diff options
Diffstat (limited to 'input.c')
-rw-r--r-- | input.c | 517 |
1 files changed, 517 insertions, 0 deletions
@@ -0,0 +1,517 @@ +/* Copyright 1998 DJ Delorie <dj@delorie.com> + Distributed under the terms of the GNU GPL + http://www.delorie.com/store/hcalc/ + Revisions copyright 2007, + Theodore Kilgore <kilgota@auburn.edu> + More revisions copyright 2023, B. Watson <urchlay@slackware.uk> +*/ +#include "hcalc.h" +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +char pending_op = 0; +int making_number = 0; +int base = 10; +int quiet = 0; + +#define MAXIN 40 + +char input_buf[MAXIN]; +int iptr; +double value, saved, stored=0; + +void paste(); +void copy(); + +void bell(void) { + if(!quiet) + XBell(display, 0); +} + +void +convert_number() +{ + char *ip = input_buf; + double scale = 1; + int sign = +1; + + if (*ip == '-') + sign = -1; + value = 0; + while (*++ip) + { + if (*ip == '.') + break; + if (*ip >= '0' && *ip <= '9') + { + value *= base; + value += *ip-'0'; + } + if (*ip >= 'a' && *ip <= 'f') + { + value *= base; + value += *ip-'a'+10; + } + } + if (*ip) + while (*++ip) + { + if (*ip >= '0' && *ip <= '9') + { + scale *= base; + value += (*ip-'0')/scale; + } + if (*ip >= 'a' && *ip <= 'f') + { + scale *= base; + value += (*ip-'a'+10)/scale; + } + } + value *= sign; +} + +void +show_value() +{ + char tmp[25], *tp; + char commas[40], *cp, *dp; + double v = value; + + if (base == 2) + { + int q = (long long)v & 0xffffffffL; + set_bits(q); + return; + } + + tmp[0] = ' '; + if (v < 0) + { + tmp[0] = '-'; + v = -v; + } + + if (base == 10) + { + sprintf(tmp+1, "%.14G", v); + if (strchr(tmp+1, 'E')) + sprintf(tmp+1, "%.9G", v); + if (tmp[14] == '.') + tmp[14] = 0; + } + else + { + static char tohex[] = "0123456789ABCDEF"; + long long ll = (long long)v; + char *revptr; + tp = tmp+1; + if (base == 16) + { + *tp++ = '0'; + *tp++ = 'x'; + } + else if (base == 8) + *tp++ = '0'; + + revptr = tp; + do { + *tp++ = tohex[ll%base]; + ll /= base; + } while (ll); + *tp-- = 0; + while (revptr < tp) { + char t = *revptr; + *revptr = *tp; + *tp = t; + tp--; + revptr++; + } + } + + cp = commas+40; + tp = tmp+strlen(tmp); + dp = strchr(tmp, '.'); + if (dp == 0) + dp = tp; + + *--cp = 0; + while (tp>=tmp) + { + *--cp = *tp--; + switch (base) + { + case 10: + if (isdigit(cp[0]) && isdigit(cp[1]) && isdigit(cp[2]) && tp<dp + && tp>=tmp && isdigit(*tp)) + *--cp = ','; + break; + case 16: + if (isxdigit(cp[0]) && isxdigit(cp[1]) + && isxdigit(cp[2]) && isxdigit(cp[3]) + && tp>=tmp && isxdigit(*tp)) + *--cp = ','; + break; + } + } + + if (strlen(cp) > 15) + set_string(tmp); + else + set_string(cp); +} + +void +end_number() +{ + if (!making_number) + return; + making_number = 0; + iptr = 0; + + switch (pending_op) + { + case '+': + value = saved + value; + break; + case '-': + value = saved - value; + break; + case '*': + value = saved * value; + break; + case '/': + value = saved / value; + break; + case '%': + value = (long long)saved % (long long)value; + break; + case '&': + value = (long long)saved & (long long)value; + break; + case '|': + value = (long long)saved | (long long)value; + break; + case '^': + value = (long long)saved ^ (long long)value; + break; + case 'S': /* Shift. Positive means <<, negative means >> */ + if (value < 0) + value = (long long)saved >> (long long)(-value); + else + value = (long long)saved << (long long)value; + break; + } + saved = value; + pending_op = 0; + show_value(); +} + +void +start_number() +{ + if (making_number) + return; + + iptr = 1; + input_buf[0] = ' '; + input_buf[1] = 0; + making_number = 1; +} + +void +key(char c) +{ + int v = c; + /* printf("key_number 0x%x\n", v); */ + + switch (c) + { + case 27: + case 'C': + making_number = 0; + iptr = 0; + pending_op = 0; + value = saved = 0; + set_string(""); + show_value(); + break; + case 'u': + if (making_number) + { + making_number = 0; + set_string(""); + } + break; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + v = c - 38; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + v -= '0'; + if (v >= base || iptr == MAXIN-1) + bell(); + else + { + start_number(); + input_buf[iptr++] = c; + input_buf[iptr] = 0; + convert_number(); + show_value(); + } + break; + case '.': + if (strchr(input_buf, '.')) + { + bell(); + break; + } + case ',': + if (iptr == 1 || iptr == MAXIN-1) + bell(); + else + { + start_number(); + input_buf[iptr++] = c; + input_buf[iptr] = 0; + convert_number(); + show_value(); + } + break; + + case 8: + case 127: + if (iptr <= 1) + bell(); + else + { + input_buf[--iptr] = 0; + convert_number(); + show_value(); + } + break; + + case '_': /* The +/- key */ + if (making_number) + { + if (input_buf[0] == '-') + input_buf[0] = ' '; + else + input_buf[0] = '-'; + convert_number(); + show_value(); + } + else + { + value *= -1.0; + saved *= -1.0; + show_value(); + } + break; + + case 'D': + end_number(); + base = 10; + show_value(); + break; + case 'H': + end_number(); + base = 16; + show_value(); + break; + case 'O': + end_number(); + base = 8; + show_value(); + break; + case 'B': + end_number(); + base = 2; + show_value(); + break; + + case 'x': /* Allow 'x' on keyboard to be used to enter '*' */ + c = '*'; + case '+': + case '-': + case '*': + case '/': + case '%': + case '^': + case '&': + case '|': + case 'S': + case '=': + end_number(); + pending_op = c; + break; + + case 13: + case 10: + end_number(); + break; + + case '~': /* Invert bits (one's complement) */ + end_number(); + value = ~ (long long)value; + saved = value; + show_value(); + break; + + case '<': /* SHL by one bit only */ +/* Modified by Keith Meehl to fix bit shift bug*/ + end_number(); + value = (long long)value << 1; + saved = value; + pending_op = 0; + show_value(); + break; + + case '>': /* SHR by one bit only */ +/* Modified by Keith Meehl to fix bit shift bug*/ + end_number(); + value = (long long)value >> 1; + saved = value; + pending_op = 0; + show_value(); + break; + + case '[': /* STO */ + stored = value; + break; + case ']': /* RCL */ + value = stored; + show_value(); + making_number = 1; + iptr = 1; + input_buf[0] = ' '; + break; + case '}': /* SUM */ + stored += value; + break; + + case 'P': /* click on the display itself */ + break; + + case 3: /* ^C */ + copy(); + break; + + case 22: /* ^V */ + paste(); + break; + + case 'q': + quiet = !quiet; + break; + + case 'Q': + case 17: + exit(0); + + case 'z': + { + /* dirty hack method of changing window size: + re-execute ourselves with appropriate argument. + TODO: see if this leaks memory, fds, etc */ + extern char *self; + char *args[4]; + + args[0] = self; + + switch(winsize) { + case 0: + args[1] = "-medium"; + break; + case 1: + args[1] = "-large"; + break; + case 2: + args[1] = "-small"; + break; + } + + args[2] = NULL; + + /* note that atexit() functions do NOT get called on execv() */ + save_config(); + + XCloseDisplay(display); + + execv(self, args); + } + } +} + +static char *bmap[] = { + "PPPP\033", /* mouse copy and paste, CLR */ + "DHOB\010", /* DEC, HEX, OCT, BIN, DEL */ + "[]}<>", /* STO, RCL, SUM, <<, >> */ + "Sdef/", /* SHF, D E F / */ + "~abc*", /* INV, */ + "|789-", /* OR, */ + "&456+", /* AND, */ + "^123=", /* XOR, */ + "u0._=" /* CE, 0, . , +/-, = */ +}; + +void +copy() +{ + XSetSelectionOwner(display, XA_PRIMARY, window, event.xbutton.time); +} + +void +paste() +{ + XConvertSelection(display, XA_PRIMARY, XA_STRING, paste_atom, window, + event.xbutton.time); +} + +void +complete_paste(unsigned char *s, int n) +{ + int i; + for (i=0; i<n; i++) + key(s[i]); + +} + +void +button(int b, int x, int y) +{ + x = (x-2)/(24 * scale_factor); + if (x < 0) x = 0; + if (x > 4) x = 4; + y = (y-1)/(16 * scale_factor); + if (y < 0) y = 0; + if (y > 8) y = 8; + + if (bmap[y][x] == 27 && b == 3) + exit(0); + + if (bmap[y][x] == 'P' && b == 1) + copy(); + if (bmap[y][x] == 'P' && b != 1) + paste(); + + if(bmap[y][x] == '/' && b != 1) + key('%'); + else + key(bmap[y][x]); + /* printf("bmap[%i][%i] and b=%i\n", y, x, b); */ +} |