/* * A very simple 16-bit TSR (POP-UP) calculator, featuring automatic entry * of last result into DOS applications. This feature works only on AT or * higher class machines with a recent BIOS. * * Use 'calc' with no operands for NON-TSR operation. * * If HOTKEYS are specified on the command line, CALC will install * itself as a TSR (Ram-Resident) program, which can be invoked at * any time by pressing the HOTKEYS. Available HOTKEYS are: * L - Left SHIFT * R - Right SHIFT * A - ALT * C - CONTROL * S - SysRq (Caution: some systems may not like this one) * * eg: CALC LR (Install with LEFT+RIGHT SHIFT for hotkeys) * * Keys used: * + Addition * - Subtraction * * Multiply * / Divide * % Modulus * & Bitwise AND * | Bitwise OR * ^ Bitwise EXCLUSIVE OR * < Shift left * > Shift right * = Display result * 0-9 Decimal input digits * A-F Hexidecimal input digits * 'c Enter a single ASCII character value * "cc Enter a dual ASCII character value * K Clear display * R Read value from memory * S Store value in memory * BKSP Clear last digit * SPACE Toggle HEX/DECIMAL * ESC Exit, no entry * ENTER Exit, enter value to DOS application (works only on AT or higher) * UP Move display up * DOWN Move display down * RIGHT Move display right * LEFT Move display left * * Copyright 1990-1995 Dave Dunfield * All rights reserved. * * Permission granted for personal (non-commercial) use only. * * Compile command: cc calc -fop */ #include #include #include int x=33, y=10, acc = 0, acc1, memory = 0; char op, mode = 0; /* Scan codes for entered digit values */ char scans[] = { 0x0B, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x1E, 0x30, 0x2E, 0x20, 0x12, 0x21 }; /* * Main calculator program */ calc() { char c, buffer[7]; op = acc ? '=' : ' '; /* Use '=' reset mode if value left over */ redraw: wopen(x, y, 9, 4, (WSAVE|WBOX2|WCOPEN|WSCROLL)+REVERSE); wcursor_off(); for(;;) { wprintf(mode ? "\r%c $%04x" : "\r%c%6d", op, acc); switch(c = toupper(wgetc())) { case '+' : /* Record all operators */ case '-' : case '*' : case '/' : case '%' : case '&' : case '|' : case '^' : case '<' : case '>' : doeval(); wprintf(mode ? "\r $%04x\n" : "\r %6d\n", acc1); acc = 0; op = c; break; case '=' : /* Display partial result */ doeval(); wclwin(); acc = acc1; op = '='; break; case '\'' : /* Single ASCII character */ acc = wgetc(); break; case '"' : /* Double ASCII character */ acc = (wgetc() << 8) | wgetc(); break; case _KBS : /* Delete last entered digit */ acc /= mode ? 16 : 10; break; case _KUA : /* Move display up */ if(y) --y; goto move; case _KDA : /* Move display down */ if(y < 21) ++y; goto move; case _KLA : /* Move display left */ if(x) --x; goto move; case _KRA : /* Move display right */ if(x < 71) ++x; move: wclose(); goto redraw; case ' ' : /* Toggle hex/decmal mode */ mode = !mode; break; case '\n' : /* Exit and enter value */ doeval(); sprintf(buffer, mode ? "%x" : "%d", acc = acc1); for(acc1 = 0; c = buffer[acc1]; ++acc1) pushkey(c, scans[c]); wclose(); return; case '\x1B' : /* Exit and don't enter value */ doeval(); acc = acc1; wclose(); return; case 'K' : /* Clear the calculator display */ acc = acc1 = 0; op = ' '; break; case 'S' : /* Save to memory */ memory = acc; break; case 'R' : /* Restore from memory */ acc = memory; break; default: if(op == '=') { /* Previous result to clear */ acc = acc1 = 0; op = ' '; } if(mode) { /* Hex input */ if(isdigit(c)) acc = (acc * 16) + (c - '0'); else if((c >= 'A') && (c <= 'F')) acc = (acc * 16) + (c - ('A'-10)); } else if(isdigit(c)) /* Decimal input */ acc = (acc * 10) + (c - '0'); } } } /* * Evaluate the last recorded operation */ doeval() { switch(op) { case '+' : acc1 += acc; break; case '-' : acc1 -= acc; break; case '*' : acc1 *= acc; break; case '/' : if(!acc) goto dbz; acc1 /= acc; break; case '%' : if(!acc) goto dbz; acc1 %= acc; break; case '&' : acc1 &= acc; break; case '|' : acc1 |= acc; break; case '^' : acc1 ^= acc; break; case '<' : acc1 <<=acc; break; case '>' : acc1 >>=acc; break; default : acc1 = acc; break; dbz: wprintf("\n? / 0\nError"); wgetc(); } } /* * Shove a key (char & scancode) into the BIOS keyboard buffer */ pushkey(c, s) asm { MOV CH,4[BP] ; Get Scan code MOV CL,6[BP] ; Get character MOV AH,05h ; Push key... INT 16h ; Ask BIOS } /* * Main program, either TSR or execute main tty program menu */ main(int argc, char *argv[]) { int hot_keys; char *ptr; /* If RAM-resident, print startup message & TSR */ if(argc > 1) { fputs("POP-UP Calculator\n\nCopyright 1990-1995 Dave Dunfield\nAll rights reserved.", stderr); hot_keys = 0; ptr = argv[1]; while(*ptr) switch(toupper(*ptr++)) { case 'A' : hot_keys |= ALT; break; case 'C' : hot_keys |= CONTROL; break; case 'L' : hot_keys |= L_SHIFT; break; case 'R' : hot_keys |= R_SHIFT; break; case 'S' : hot_keys |= SYS_REQ; break; default: abort("\n\nInvalid HOTKEY"); } tsr(&calc, hot_keys, 2000); } /* Not RAM-resident, execute the program */ calc(); }