Category : C Source Code
Archive   : TENKEY.ZIP
Filename : TENKEY.C
* TENKEY+ *
* A WINDOW PRO demonstration program. *
* *
* Seabreeze Software *
* *
* Copyright (c) 1987, 1988 *
* *
* All rights reserved *
* *
***************************************************************************
Note: To compile the TENKEY+ source code requires The WINDOW PRO library.
The WINDOW PRO is available as shareware on most bulletin boards. Or
you can order it directly from Seabreeze Software. For more information
on The WINDOW PRO, The WINDOW PRO license agreements, TENKEY+ license
agreements, and other Seabreeze Software products and services call
Kenneth Stott, (214) 437-2729.
If you are using The WINDOW PRO version 1.2 or lower -- TENKEY+ will
compile and operate properly from the keyboard, but the mouse will not
activate the scroll bars properly. In addition, there will be a brief
flash during the setup phase of TENKEY. If you do not have version 1.21
or higher contact Seabreeze Software for an update.
TENKEY+ source has been tested under the MSC C version 4 compiler
(must define MSC = TRUE to compile) and TURBO C version 1.
MODIFICATIONS:
5/18/88 -- made minor changes to the mouse oriented routines for
upgrading to The WINDOW PRO 1.31 version of the windowing library
routines. Also, you may have noticed that the
mouse cursor is not visible at all times when using an MDA. The
original was written so that the color scheme would look OK on
any type of display. However, it did not take into account
the visibility/invisibility of the mouse cursor. A good project
would be to check the adapter type first and then change the
color scheme (You can globally change the values that the
colors map to using the arrays ibm_fcolor_table[16] &
ibm_bcolor_table[16].) Good luck.
*/
#include "pro.h"
#include "xglobals.h"
#include "mouse.h"
#include "keyboard.h"
#include "kernel.h"
#include "vs.h"
#include "colors.h"
#include
#include
/* These are some extended keyboard codes returned from kb_getxc */
#define XUP 18432
#define XDOWN 20480
#define XRIGHT 19712
#define XLEFT 19200
#define XENTER 7181
#define XHOME 18176
#define XEND 20224
#define XPGUP 18688
#define XPGDN 20736
#define XF1 15104
#define XF2 15360
#define XF3 15616
#define XF4 15872
#define XF5 16128
#define XF6 16384
#define XF7 16640
#define XF8 16896
#define XF9 17152
#define XF0 17408
#define XPLUS 20011
#define XMINUS 18989
#define XT 5236
#define XC 11875
#define XASTERISK 14122
#define XDIVIDE 13615
#define XDELETE 21248
/* These are the op-codes used by the calculator */
#define ADD 0
#define MINUS 1
#define MULTIPLY 2
#define DIVIDE 3
#define EQUALS 4
#define MEMPLUS 5
#define MEMMINUS 6
#define MEMRECALL 7
#define NO_OP 255
#define MEMCLEAR 8
#define CLEARALL 9
#define SUBTOTAL 10
#define GRANDTOTAL 11
#define MEMO 12
#define HELP 14
#define END_IT 15
#define GO_UP 16
#define GO_DOWN 17
#define GO_HOME 18
#define GO_END 19
#define GO_PGUP 20
#define COMMENT 13
#define GO_PGDN 21
#define INSERT 22
#define DELETE 23
#define TEAR 28
#define GO_LEFT 29
#define GO_RIGHT 30
/* keys, added 128 to avoid conflict with some ASCII codes used for commands*/
#define ENTER 13
#define F1 59+128
#define F2 60+128
#define F3 61+128
#define F4 62+128
#define F5 63+128
#define F6 64+128
#define F7 65+128
#define F8 66+128
#define F9 67+128
#define F0 68+128
#define UP 72+128
#define DOWN 80+128
#define HOME 71+128
#define END 79+128
#define PGUP 73+128
#define PGDN 81+128
#define DEL 83+128
#define LEFT 75+128
#define RIGHT 77+128
#define CTRL_A 1
#define CTRL_B 2
#define CTRL_C 3
#define CTRL_D 4
/*
'entry' is the basic record type for each item on the tape.
forward pointer to the next item on the tape
backward pointer to the previous item on the tape
value value to be displayed on tape
accum value of the accumulator at that point on the tape
popreg value of the pending operation (* and /) register
at that point on the tape
memreg value of the memory register at that point on the tape
op the operation (range 1 to 22) for currenty entry
p_op the pending operation (2 or 3) for current entry
deflt FALSE = value entered from keyboard for this entry
TRUE = value of previous entry used
*/
typedef struct {
void *forward, *backward;
float value, accum, popreg, memreg;
unsigned char deflt, op, p_op;
char *comment;
} entry;
/*
'command_rec' is a subset of record type 'entry'. Temporarily stores
commands entered from the keyboard.
*/
typedef struct {
unsigned char op,deflt;
float value;
char *comment;
} command_rec;
/* global variables */
/*
* key codes for the tenkey commands, their position in the array
* relates to the tenkey op-codes, i.e. the keycode in position 0
* relates to op-code 0 (or ADD).
*/
unsigned char cmds[] = {
'+', '-', '*', '/', '=', F1, F2, F3, F4, F5, F6, F7,
254, F8, F9, F0, UP, DOWN, HOME, END, PGDN, PGUP, ENTER,
DEL, CTRL_A, CTRL_B, CTRL_C, CTRL_D, 'T', LEFT, RIGHT},
/*
* the op-codes which output to the tape, put these strings to the
* right of the output value.
*/
*cmd_str[15] = {
" +", " -", " *", " /", " =", "M+",
"M-", "MR", "MC", "CA","ST","GT"," "," :","XX"};
/*
* There are 36 keycaps, numbered 0 to 35 -- starting in the upper
* left corner and progressing for towards the right and then down.
* Each op-code makes a key 'flash' on the display -- like it had been
* pressed. The keycap flashed is determined by this array. For example,
* op-code 0 (position 0 in this array) flashes keycap 17.
*/
int caps[] = {
17, 23, 11, 5, 29, 0, 1, 6, 7, 12, 13, 18, 19,
26, 24, 25, 26, 26, 26, 26, 26, 26, 35, 28, 26,
26, 26, 26, 33, 26, 26, 26};
/*
* These characters represent the legal commands while entering a
* number
*/
char digits[] = {'0','1','2','3','4','5','6','7','8','9','.','C'};
/*
* Similar to the op-codes, the digit presses also flash a key. The
* keycap flashed is determined by the offest in this array, relative
* to the offset in the array digits[]. For example, pressing '0', in
* the 0 position above, flashes the keycap 21, in the 0 position below.
*/
int dig_caps[] = {21, 14, 15, 16, 8, 9, 10, 2, 3, 4, 22, 34};
/*
* Each keycap has a label in it, this array determines the label
* used by each keycap. A label of NULL, forces the keycap to
* not be shown
*/
char *msg[] ={
" M+", " M-", " 7 ", " 8 ", " 9 ", " / ",
" MR", " MC", " 4 ", " 5 ", " 6 ", " * ",
" CA", " ST", " 1 ", " 2 ", " 3 ", " + ",
" GT", "CMT", NULL, " 0 ", " . ", " - ",
"HELP","EXIT",NULL, NULL, "del", "=",
"ins","scr","num", "Tear","Clr", "entr"};
/*
* This array determines the foreground color for each
* keycap
*/
char cap_f[] = {
GREEN, GREEN, YELLOW, YELLOW, YELLOW, RED,
GREEN, GREEN, YELLOW, YELLOW, YELLOW, RED,
GREEN, GREEN, YELLOW, YELLOW, YELLOW, RED,
GREEN, GREEN, 0, YELLOW, YELLOW, RED,
GREEN, GREEN, 0, 0, RED, RED,
WHITE, WHITE, WHITE, RED, RED, RED};
/*
* This array sets the background color for each keycap
*/
char cap_b[] = {
BLACK, BLACK, BLUE, BLUE, BLUE, BLACK,
BLACK, BLACK, BLUE, BLUE, BLUE, BLACK,
BLACK, BLACK, BLUE, BLUE, BLUE, BLACK,
BLACK, BLACK, 0, BLUE, BLUE, BLACK,
BLACK, BLACK, 0, 0, GREEN, BLACK,
BLACK, BLACK, BLACK, GREEN, GREEN, BLACK};
char *keybox[3] = {
"IMMMM;",
": :",
"HMMMM<"
};
/*
* These represent the extended keyboard values returned when the
* mouse 'presses' a keycap.
*/
int ctox[] = {
XF1, XF2, '7', '8', '9', '/',
XF3, XF4, '4', '5', '6', '*',
XF5, XF6, '1', '2', '3', '+',
XF7, XF8, 0, '0', '.', '-',
XF9, XF0, 0, 0 , XDELETE, '=',
0, 0, 0, 'T', 'C', XENTER};
entry *first; /* the first entry on the tape */
entry *last; /* the last entry on the tape */
entry *curr; /* the entry being edited */
int comment_wdw, /* a window handle used for entering comments */
tape_wdw, /* the window use for tape */
comm_wdw, /* the window used to display the keycaps */
count,
scr_test = TRUE, /* current state of the scroll lock, ..*/
num_test = TRUE, /* numlock, ..*/
ins_test = TRUE, /* and insert indicators. */
update = TRUE, /* suspends output to the tape if TRUE */
wdw_width = 20, /* width of the tape window */
wdw_length = 15, /* length of the tape window */
wdw_x = 39, /* location of the upper left corner .. */
wdw_y = 2, /* of the tape window. */
mouse_timeout = 15; /* initial mouse click sensitivity */
command_rec *command; /* used to get a command */
char line_buffer[100]; /* stores formatted string to output to tape */
/* function declarations */
int scroll_lock();
int num_lock();
int insert_on();
void size(int);
void no_op(entry *);
void update_scroll_lock();
void update_insert();
void update_num_lock();
void tear_tape();
unsigned char upcase(unsigned char);
void start_tape();
void disp_machine();
entry *add(entry *);
entry *subtract(entry *);
void memrecall(entry *);
void memclear(entry *);
void multiply(entry *);
void scroll(int, int);
void divide(entry *);
void clearall(entry *);
void subtotal(entry *);
void grandtotal(entry *);
void memplus(entry *);
void memminus(entry *);
entry *equals(entry *);
entry *del_spurious(entry *);
entry *delete_entry(entry *);
void get_command(float *);
void calc(entry *);
entry *insert_entry(entry *);
void to_tape(entry *);
void scroll_up();
void scroll_down();
/* prototypes end */
void main()
{
/* initialize memory for the first command record */
command = k_malloc(sizeof(command_rec));
/* initialize The WINDOW PRO */
wn_init();
/* set the mouse to the software cursor */
if (mouse_installed) kb_settextcursor(0, 0x77FF, 0x7700);
/* turn off the cursor */
wn_hidecur();
/* set the window border colors */
active_attr = WHITE + (BLACK << 4);
inactive_attr = WHITE + (BLACK << 4);
/* set up the windows we'll use */
thumbwheels_on = NO_BARS;
comm_wdw = wn_createw(22,75,1,1,1,1,22,60,FALSE,HEAD_ON,
"Seabreeze Software, TENKEY+",NULL);
vs_fillattr(comm_wdw, 0, 1, 1, 75, 22, WHITE, BLUE);
default_box = box2;
comment_wdw = wn_createw(2,30,1,1,1,1,1,30,FALSE,HEAD_ON,
"Enter your comment","press ENTER to terminate");
tape_wdw = wn_createw(wdw_length+5,wdw_width+10,wdw_x,wdw_y,
1,1,wdw_length,wdw_width,FALSE,HEAD_ON,"TAPE",NULL);
wn_createt(tape_wdw,"registers",wdw_width+10,4,1,1);
/* set up the help screen */
genhelp();
/* set up the register tile in the tape window */
wn_opent(tape_wdw,1);
/* get them to their respective sizes */
wn_sizet(tape_wdw,0,0,5);
wn_sizet(tape_wdw,1,0,5);
wn_sizet(tape_wdw,0,0,5);
wn_sizet(tape_wdw,1,0,5);
wn_sizet(tape_wdw,0,0,2);
wn_sizet(tape_wdw,1,0,2);
/* put the keycap displays in the command window */
printkeys();
/* and some other stuff */
vs_puts(comm_wdw, 0, 1, 19, 60, WHITE, BLUE, "------ Default Register -------->");
vs_puts(comm_wdw, 0, 1, 21, 60, WHITE, BLUE, "------ Subtotal Register -------->");
vs_puts(comm_wdw, 0, 1, 20, 60, WHITE, BLUE, "------ Memory Register -------->");
/* turn off the scroll bars on these tiles */
wn_togscroll(comm_wdw,0,FALSE);
wn_togscroll(tape_wdw,1,FALSE);
/* display the calculator */
wn_freeze();
wn_openw(comm_wdw);
wn_openw(tape_wdw);
wn_defrost(1,1,physical_columns,physical_rows);
/* initialize the tape */
start_tape();
/* the main command loop -- EXIT on END_IT */
while (command->op != END_IT) {
/* if a numeric type operation output the number & operation */
if (curr->op < 15) sprintf(line_buffer,"%*.2f %s",window[tape_wdw]->port_columns - 3,curr->value,cmd_str[curr->op]);
/* if the operation used the default value indicate it */
if (curr->deflt) line_buffer[0] = '|';
/*
* If the operation is a no-op then make sure and not
* indicate the use of the default marker
*/
if (curr->op == 255) line_buffer[0] = 0x00;
/* If the operation is a comment, display the comment string */
if (curr->op == COMMENT) sprintf(line_buffer,"%s",curr->comment);
/*
* If this isn't the last spot then output the spot on the tape
* to the command window
*/
if (curr != last)
vs_puts(tape_wdw,1,1,1,window[tape_wdw]->port_columns,BLACK, GREEN,line_buffer);
/* otherwise display the end of tape message */
else vs_puts(tape_wdw,1,1,1,window[tape_wdw]->port_columns,0,7,"END OF TAPE -->");
/* update the memory register display */
sprintf(line_buffer,"%*.2f ",window[tape_wdw]->port_columns - 3,
((entry *)(curr->backward))->memreg);
line_buffer[0] = 'M';line_buffer[1] = 'R';
/* update the accumulator display */
vs_puts(tape_wdw,1,1,3,window[tape_wdw]->port_columns,BLACK, GREEN, line_buffer);
sprintf(line_buffer,"%*.2f ",window[tape_wdw]->port_columns - 3,
((entry *)(curr->backward))->accum);
line_buffer[0] = 'S';line_buffer[1] = 'T';
vs_puts(tape_wdw,1,1,4,window[tape_wdw]->port_columns,BLACK,GREEN,line_buffer);
/* get the next command */
get_command(&((entry *)curr->backward)->value);
/*
* if a number oriented command then reset all the registers
* and recalculate the tape.
*/
if (command->op < 14) {
if ((insert_on()) && (curr->backward != first)) curr = insert_entry(curr->backward);
curr->accum = ((entry *)(curr->backward))->accum;
curr->popreg = ((entry *)(curr->backward))->popreg;
curr->p_op = ((entry *)(curr->backward))->p_op;
curr->memreg = ((entry *)(curr->backward))->memreg;
curr->op = command->op;
curr->value = command->value;
curr->deflt = command->deflt;
curr->comment = command->comment;
calc(curr);
}
else {
switch (command->op) {
case GO_UP: if (!scroll_lock()) scroll_up();
else scroll(0,-1);
break;
case GO_DOWN: if (!scroll_lock()) scroll_down();
else scroll(0,1);
break;
case GO_LEFT: if (scroll_lock()) scroll(-1,0);
else size(-1);
break;
case GO_RIGHT: if (scroll_lock()) scroll(1,0);
else size(1);
break;
case GO_HOME: while(curr != last) {
scroll_down();
}
break;
case GO_END: while(curr->backward != first) {
scroll_up();
}
break;
case GO_PGUP: for(count=0;count
scroll_down();
}
break;
case GO_PGDN: for(count=0;count
scroll_up();
}
break;
case INSERT: insert_entry(curr->backward);
/* carryforward the registers */
((entry *)(curr->backward))->memreg =
((entry *)((entry *)(curr->backward))->backward)->memreg;
((entry *)(curr->backward))->accum =
((entry *)(((entry *)(curr->backward))->backward))->accum;
((entry *)(curr->backward))->popreg =
((entry *)(((entry *)(curr->backward))->backward))->popreg;
((entry *)(curr->backward))->p_op =
((entry *)(((entry *)(curr->backward))->backward))->p_op;
((entry *)(curr->backward))->deflt =
((entry *)(((entry *)(curr->backward))->backward))->deflt;
((entry *)(curr->backward))->value =
((entry *)(((entry *)(curr->backward))->backward))->value;
/* make it a no-op */
((entry *)(curr->backward))->op = 255;
/* output it to tape */
to_tape(curr->backward);
break;
case DELETE: delete_entry(curr);
if (curr != last) calc(curr);
scroll_up();
break;
case TEAR: tear_tape();
start_tape();
break;
case HELP: helpsystem();
break;
}
}
}
/* turn off the mouse cursor */
if (mouse_installed) kb_hidemouse();
/* restore the characters to the original screen */
wn_restorescr();
/* restore the cursor position */
v_gotoxy(oldx,oldy);
/* restore the cursor shape */
v_curshape(oldb, olde);
}
/* returns TRUE if a keystroke is a tenkey command */
int is_op(xcode)
int *xcode;
{
unsigned char asc_code, scan_code;
asc_code = (*xcode % 256);
scan_code = (*xcode / 256) + 128;
if ( (asc_code == '+') ||
(asc_code == '/') ||
(asc_code == ENTER) ||
(asc_code == 'T') ||
(asc_code == '*') ||
(asc_code == '-') ||
(asc_code == '=')) {
*xcode = asc_code;
return(TRUE);
}
if ((scan_code == (F1)) ||
(scan_code == (F2)) ||
(scan_code == (F3)) ||
(scan_code == (F4)) ||
(scan_code == (F5)) ||
(scan_code == (F6)) ||
(scan_code == (F7)) ||
(scan_code == (F8)) ||
(scan_code == (F9)) ||
(scan_code == (F0)) ||
(scan_code == (UP)) ||
(scan_code == (LEFT)) ||
(scan_code == (RIGHT)) ||
(scan_code == (DEL)) ||
(scan_code == (PGUP)) ||
(scan_code == (PGDN)) ||
(scan_code == (HOME)) ||
(scan_code == (END)) ||
(scan_code == (DOWN))) {
*xcode = scan_code;
return(TRUE);
}
return(FALSE);
}
/* translates a keystroke into an operator value */
int opval(op)
unsigned char op;
{
unsigned char count;
for(count = 0; count < 31; count++) if (op == cmds[count]) return(count);
return(13);
}
/* recalculates a tape from 'location' forward */
void calc(location)
entry * location;
{
entry *next_comm;
/*
* If item is the the last item then setup a new record to hold it
* and output it to the tape
*/
if (location == last) {
curr = insert_entry(location);
update = TRUE;
}
else update = FALSE;
/* repeat this loop until it reaches the end of the tape */
while (location != last) {
/*
* get rid of '=' not preceded by a * or a / and get rid of
* all memo entries
*/
location = del_spurious(location);
/*
* if del_spurious changed the 'location' pointer, check to see
* if while_loop should be terminated early
*/
if (location == last) break;
/* determine if record should use entered value or a default value */
if (location->deflt) location->value =
((entry *)(location->backward))->value;
/* select the operation to perform */
switch (location->op) {
case ADD: location = add(location);
break;
case MINUS: location = subtract(location);
break;
case MULTIPLY: multiply(location);
break;
case DIVIDE: divide(location);
break;
case EQUALS: location = equals(location);
break;
case MEMPLUS: memplus(location);
break;
case MEMMINUS: memminus(location);
break;
case MEMRECALL: memrecall(location);
break;
case MEMCLEAR: memclear(location);
break;
case CLEARALL: clearall(location);
break;
case SUBTOTAL: subtotal(location);
break;
case GRANDTOTAL:grandtotal(location);
break;
case NO_OP: no_op(location);
break;
case COMMENT: no_op(location);
break;
}
if (update) to_tape(location);
/* set location = to next item on the list and start over */
if (location != last) location = location->forward;
else break;
}
if (update) curr = location;
else scroll_down();
}
entry *insert_entry(after)
entry *after;
{
entry *new_entry, *hold_it;
/* get memory for new record */
new_entry = k_malloc(sizeof(entry));
/* give it a bogus op code */
new_entry->op = 255;
/* set all the registers to 0 */
new_entry->accum =
new_entry->popreg =
new_entry->memreg =
new_entry->value = 0.0;
/* set pending op-code to nothing */
new_entry->p_op = 0;
/* don't link it into the list */
new_entry->forward = NULL;
new_entry->backward = NULL;
/* set comment string pointer to NULL */
new_entry->comment = NULL;
/* link in the new record into the list */
if (after != NULL) {
hold_it = after->forward;
after->forward = new_entry;
new_entry->backward = after;
new_entry->forward = hold_it;
hold_it->backward = new_entry;
if (after == last) last = new_entry;
}
else first = last = new_entry;
/* return a pointer to the new entry */
return(new_entry);
}
/* output an entry to the tape */
void to_tape(location)
entry *location;
{
/* if number oriented op output value */
if (location->op < 15) sprintf(line_buffer,"%*.2f %s",
window[tape_wdw]->port_columns - 3,location->value,cmd_str[location->op]);
/* make room for it */
vs_delrow(tape_wdw,0,1,1,wdw_width+10,wdw_length,1,BLACK,LIGHTGRAY);
/* set the default value indicator */
if (location->deflt) line_buffer[0] = '|';
/* if a no-op, clear the default value indicator */
if (location->op == 255) line_buffer[0] = 0x00;
/* if a comment op-code output the comment string */
if (location->op == COMMENT) sprintf(line_buffer, "%s",
location->comment);
/* output the string to the tape */
vs_puts(tape_wdw, 0, 1, wdw_length, window[tape_wdw]->port_columns,
BLACK, LIGHTGRAY, line_buffer);
}
/* scroll the tape up one entry */
void scroll_up()
{
int a,b;
entry *location;
/*
* set location equal to the item which will be the next
* bottom of the tape
*/
location = ((entry *)(curr->backward))->backward;
/* if it is an item -- continue */
if (location != NULL) {
/* make the item in the edit area the previous item */
curr = curr->backward;
/* find the top of the tape */
for (a = wdw_length - 1; a > 0; a--) {
location = location->backward;
if (location == NULL) break;
}
/* if there is a new top of the tape -- output it */
if (!a) {
if (location->op < 15) sprintf(line_buffer,
"%*.2f %s", window[tape_wdw]->port_columns - 3,
location->value, cmd_str[location->op]);
if (location->deflt) line_buffer[0] = '|';
if (location->op == 255) line_buffer[0] = 0x00;
if (location->op == COMMENT) sprintf(line_buffer, "%s",
location->comment);
vs_insrow(tape_wdw, 0, 1, 1, wdw_width + 10,
wdw_length, 1, BLACK, LIGHTGRAY);
vs_puts(tape_wdw, 0, 1, 1, window[tape_wdw]->port_columns,
BLACK, LIGHTGRAY, line_buffer);
}
/* otherwise output a blank */
else vs_insrow(tape_wdw, 0, 1, 1, wdw_width + 10,
wdw_length, 1, BLACK, BLACK);
}
}
void scroll_down()
{
int a,b;
entry *location;
location = curr;
if (location != last) {
curr = curr->forward;
vs_delrow(tape_wdw, 0, 1, 1, wdw_width + 10, wdw_length, 1,
BLACK, LIGHTGRAY);
if (location->op < 15) sprintf(line_buffer, "%*.2f %s",
window[tape_wdw]->port_columns - 3,
location->value, cmd_str[location->op]);
if (location->deflt) line_buffer[0] = '|';
if (location->op == 255) line_buffer[0] = 0x00;
if (location->op == COMMENT) sprintf(line_buffer, "%s",
location->comment);
vs_puts(tape_wdw, 0, 1, wdw_length,
window[tape_wdw]->port_columns,
BLACK, LIGHTGRAY, line_buffer);
}
}
void get_command(d)
float *d;
{
unsigned char len = 0, /* length of value string */
count, /* general */
decpoint = FALSE, /* a decimal point has been entered if TRUE */
valstr[50], /* holds the value string */
asc_code; /* ascii code of current keypress */
float display; /* floating point value of value string */
int mouse_clicks = 0, /* click value of mouse */
xcode; /* most recent extended kyeboard code */
unsigned int mousex, mousey; /* coordinate of mouse at most recent click */
/* erase the value string */
for(count = 0; count < 50; count++) valstr[count]=0x00;
/* initialize value to display in edit window */
display = *d;
/* keep getting keypresses until a command is entered */
while(TRUE) {
/* output the current value of the kyepresses */
sprintf(line_buffer, "%*g",
window[tape_wdw]->port_columns - 3, display);
vs_puts(tape_wdw,1,1,2,window[tape_wdw]->port_columns,0,2,line_buffer);
/*
* if a mouse is installed display the mouse cursor and
* wait for some mouse key action and/or keyboard action.
*/
if (mouse_installed) kb_showmouse();
while ((!kbhit()) && (!mouse_clicks)) {
update_scroll_lock();
update_num_lock();
update_insert();
if (mouse_installed)
mouse_clicks =
kb_mouseclicks(1, mouse_timeout,
&mousex, &mousey);
}
/*
* turn off the mouse while we executed the command --
* otherwise it messes up the redrawing
*/
if (mouse_installed) kb_hidemouse();
/*
* if it was mouse action translate it into an extended
* keyboard code
*/
if (mouse_clicks) {
xcode = interp_mouseclick(mouse_clicks, mousex, mousey);
mouse_clicks = FALSE;
}
/* otherwise get the keypress from the keyboard */
else xcode = kb_getxc();
/* calc the ascii code from the extended kyeboard code */
asc_code = upcase(xcode % 256);
/* it it was a digit key cap -- flash the key */
for (count = 0; count < 12; count++) {
if (digits[count] == asc_code) {
printcmdkey(dig_caps[count], BLACK, LIGHTGRAY);
printcmdkey(dig_caps[count],
cap_f[dig_caps[count]],
cap_b[dig_caps[count]]);
}
}
/* if it was a real digit add it to the value string */
if ((isdigit(asc_code)) && (len < 20)) {
valstr[len++] = asc_code;
}
/*
* if it is a decimal point -- & we don't already have a
* decimal point add it to the string
*/
else if ((asc_code == '.') && (!decpoint)) {
decpoint = TRUE;
valstr[len++] = asc_code;
}
/* If it is the clear command zero out the value string */
else if (asc_code =='C') {
for(count=0;count<50;count++) valstr[count]=0x00;
decpoint = FALSE;
len = 0;
}
/*
* if it is a backspace then get rid of the last
* entered character from the string
*/
else if ((asc_code == 8) && (len)) {
if (valstr[len-1] == '.') decpoint = FALSE;
valstr[--len] = 0x00;
}
/* otherwise see if it is a command */
else if (is_op(&xcode)) break;
/*
* if it is not a command the loop back through --
* and up date the display
*/
if (len) display = atof(valstr);
else display=*d;
}
/* If it was a command the convert the command to an op-code */
command->op = opval(xcode);
/* and flash the keycap on the display */
printcmdkey(caps[command->op],BLACK, LIGHTGRAY);
printcmdkey(caps[command->op],cap_f[caps[command->op]],
cap_b[caps[command->op]]);
/* if we entered a value then don't use the default value */
command->deflt = (!len);
/* and set the explicit value to the amount collected above */
command->value = display;
/* set the pointer to the comment string to NULL */
command->comment = NULL;
/* If a comment op-code was requested get the string from the user */
if (command->op == COMMENT) {
command->comment = k_malloc(30);
wn_openw(comment_wdw);
vs_locatecur(comment_wdw,0,1,1);
wn_locatevs(comment_wdw,0,1,1);
vs_gets(comment_wdw, 0, TRUE, command->comment, WHITE, BLACK, 29);
wn_closew(comment_wdw);
}
}
entry *delete_entry(location)
entry *location;
{
entry *temp;
/* can't delete the first and last items */
if ((location != last) && (location != first)) {
/* set temp to the item to be deleted */
temp = location;
/* link around the item */
((entry *)(location->backward))->forward =
location->forward;
((entry *)(location->forward))->backward =
location->backward;
location = location->forward;
/*
* if it is the item in the display that got
* deleted then reset the pointer to the current item
*/
if (temp == curr) curr = location;
/* get rid of the memory allocated to the comment */
if(temp->comment != NULL) {
k_free(temp->comment);
}
/* get rid of the memory allocated to the item */
k_free(temp);
temp = location;
/* return a pointer to the next item */
return(temp);
}
else return(location);
}
entry *del_spurious(temp)
entry *temp;
{
while ((temp->op == MEMO) ||
((temp->op == EQUALS) &&
(!((entry *)(temp->backward))->p_op))) {
temp = delete_entry(temp);
}
return(temp);
}
entry *equals(location)
entry *location;
{
entry *next_comm;
location->popreg = location->p_op = 0;
location->accum = ((entry *)(location->backward))->accum;
location->memreg = ((entry *)(location->backward))->memreg;
if (((entry *)(location->backward))->p_op != 0) {
if (((entry *)(location->backward))->p_op == 2) location->popreg =
((entry *)(location->backward))->popreg *
location->value;
if (((entry *)(location->backward))->p_op == 3) location->popreg =
((entry *)(location->backward))->popreg /
location->value;
}
if (update) to_tape(location);
next_comm = insert_entry(location);
next_comm->op = MEMO;
next_comm->value = location->popreg;
next_comm->p_op = 0;
next_comm->accum = location->accum;
next_comm->memreg = location->memreg;
location = next_comm;
return(location);
}
entry *add(location)
entry *location;
{
entry *next_comm;
location->popreg = 0.0;
location->p_op = 0;
location->memreg = ((entry *)(location->backward))->memreg;
location->accum = ((entry *)(location->backward))->accum +
location->value;
if (((entry *)(location->backward))->p_op != 0) {
if (((entry *)(location->backward))->p_op == 2) location->popreg =
((entry *)(location->backward))->popreg * location->value;
if (((entry *)(location->backward))->p_op == 3) location->popreg =
((entry *)(location->backward))->popreg / location->value;
location->op = EQUALS;
location->p_op = 0;
location->accum = ((entry *)(location->backward))->accum;
if(update) to_tape(location);
next_comm = insert_entry(location);
next_comm->op = MEMO;
next_comm->p_op = next_comm->popreg = 0;
next_comm->deflt = FALSE;
next_comm->memreg = location->memreg;
next_comm->value = location->popreg;
next_comm->accum = location->accum;
location = next_comm;
next_comm = insert_entry(location);
next_comm->op = next_comm->p_op = next_comm->popreg = 0;
next_comm->deflt = TRUE;
next_comm->memreg = location->memreg;
next_comm->value = location->popreg;
next_comm->accum = location->accum + location->popreg;
}
return(location);
}
entry *subtract(location)
entry *location;
{
entry *next_comm;
location->popreg = 0.0;
location->p_op = 0;
location->memreg = ((entry *)(location->backward))->memreg;
location->accum = ((entry *)(location->backward))->accum -
location->value;
if (((entry *)(location->backward))->p_op != 0) {
if (((entry *)(location->backward))->p_op == 2) location->popreg =
((entry *)(location->backward))->popreg * location->value;
if (((entry *)(location->backward))->p_op == 3) location->popreg =
((entry *)(location->backward))->popreg / location->value;
location->op = EQUALS;
location->p_op = 0;
location->accum = ((entry *)(location->backward))->accum;
if(update) to_tape(location);
next_comm = insert_entry(location);
next_comm->op = MEMO;
next_comm->p_op = next_comm->popreg = 0;
next_comm->deflt = FALSE;
next_comm->value = location->popreg;
next_comm->memreg = location->memreg;
next_comm->accum = location->accum;
location = next_comm;
next_comm = insert_entry(location);
next_comm->op = 1;
next_comm->p_op = next_comm->popreg = 0;
next_comm->deflt = TRUE;
next_comm->value = location->popreg;
next_comm->memreg = location->memreg;
next_comm->accum = location->accum - location->popreg;
}
return(location);
}
void multiply(location)
entry *location;
{
location->accum = ((entry *)(location->backward))->accum;
location->memreg = ((entry *)(location->backward))->memreg;
if (((entry *)(location->backward))->p_op != 0) {
if (((entry *)(location->backward))->p_op == 2) location->popreg =
((entry *)(location->backward))->popreg * location->value;
if (((entry *)(location->backward))->p_op == 3) location->popreg =
((entry *)(location->backward))->popreg / location->value;
}
else location->popreg = location->value;
location->p_op = 2;
}
void divide(location)
entry *location;
{
location->accum = ((entry *)(location->backward))->accum;
location->memreg = ((entry *)(location->backward))->memreg;
if (((entry *)(location->backward))->p_op != 0) {
if (((entry *)(location->backward))->p_op == 2) location->popreg =
((entry *)(location->backward))->popreg * location->value;
if (((entry *)(location->backward))->p_op == 3) location->popreg =
((entry *)(location->backward))->popreg / location->value;
}
else location->popreg = location->value;
location->p_op = 3;
}
void memplus(location)
entry *location;
{
location->memreg = ((entry *)(location->backward))->memreg + location->value;
location->accum = ((entry *)(location->backward))->accum;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
}
void memminus(location)
entry *location;
{
location->memreg = ((entry *)(location->backward))->memreg - location->value;
location->accum = ((entry *)(location->backward))->accum;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
}
void memrecall(location)
entry *location;
{
location->value =
location->memreg = ((entry *)(location->backward))->memreg;
location->accum = ((entry *)(location->backward))->accum;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
}
void memclear(location)
entry *location;
{
location->value = ((entry *)(location->backward))->memreg;
location->memreg = 0.0;
location->accum = ((entry *)(location->backward))->accum;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
}
void clearall(location)
entry *location;
{
location->value = location->accum = 0;
location->memreg = ((entry *)(location->backward))->memreg;
}
void subtotal(location)
entry *location;
{
location->accum =
location->value = ((entry *)(location->backward))->accum;
location->memreg = ((entry *)(location->backward))->memreg;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
}
void grandtotal(location)
entry *location;
{
location->accum = 0;
location->value = ((entry *)(location->backward))->accum;
location->memreg = ((entry *)(location->backward))->memreg;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
}
void scroll(x, y)
int x, y;
{
unsigned int handle;
signed int new_x1, new_y1, new_x2, new_y2;
/*
* Normally, The WINDOW PRO handles all of the range checking
* on range moves -- but it does it individually. Since, we
* need to keep the windows in synch I do the range checking
* here.
*/
handle = comm_wdw;
new_x1 = WDW->physical_x + x;
new_y1 = WDW->physical_y + y;
new_x2 = new_x1 + WDW->port_columns + 1;
new_y2 = new_y1 + WDW->port_rows + 1;
if ((new_x1 > 0) && (new_y1 > 0) && (new_x2 <= physical_columns) &&
(new_y2 <= physical_rows)) {
wn_moverng(comm_wdw, tape_wdw, x, y);
}
}
void size(x)
int x;
{
signed int new_columns, new_x;
unsigned int handle;
handle = tape_wdw;
new_columns = x + WDW->port_columns;
handle = comm_wdw;
new_x = x + WDW->physical_x + WDW->port_columns + 1;
if ((new_columns <= wdw_width+10) && (new_x <= physical_columns) &&
(new_columns > 0)) {
wn_sizerng(comm_wdw,tape_wdw,x,0);
}
}
void start_tape()
{
curr = insert_entry(NULL);
curr->op = CLEARALL;
curr->deflt = FALSE;
curr->accum = curr->memreg = curr->p_op = curr->popreg = 0;
to_tape(curr);
curr = insert_entry(curr);
command->op = 0;
}
void tear_tape()
{
int count;
entry *temp1, *temp2;
vs_clrvs(tape_wdw, 0, BLACK, BLACK);
temp1 = first;
while(temp1 != NULL) {
temp2 = temp1->forward;
if (temp1->comment != NULL) free(temp1->comment);
free(temp1);
temp1 = temp2;
}
}
unsigned char upcase(ch)
unsigned char ch;
{
if ((ch >=97) && (ch <= 122)) return(ch-32);
else return(ch);
}
int scroll_lock()
{
char *shift_status;
shift_status = 0x00000417;
return(*shift_status & 16);
}
int num_lock()
{
char *shift_status;
shift_status = 0x00000417;
return(*shift_status & 32);
}
int insert_on()
{
unsigned char *shift_status;
shift_status = 0x00000417;
return(*shift_status & 128);
}
void update_scroll_lock()
{
if (scroll_lock() != scr_test) {
scr_test = scroll_lock();
if (scroll_lock()) printcmdkey(31, BLACK, LIGHTGRAY);
else printcmdkey(31, WHITE, BLACK);
}
}
void update_num_lock()
{
if (num_lock() != num_test) {
num_test = num_lock();
if (num_lock()) printcmdkey(32, BLACK, LIGHTGRAY);
else printcmdkey(32, WHITE, BLACK);
}
}
void update_insert()
{
if (insert_on() != ins_test) {
ins_test = insert_on();
if (insert_on()) printcmdkey(30, BLACK, LIGHTGRAY);
else printcmdkey(30, WHITE, BLACK);
}
}
void no_op(location)
entry* location;
{
location->accum = ((entry *)(location->backward))->accum;
location->popreg = ((entry *)(location->backward))->popreg;
location->p_op = ((entry *)(location->backward))->p_op;
location->memreg = ((entry *)(location->backward))->memreg;
}
int printbox(handle, tile_handle, x, y, fg, bg, cap)
unsigned int handle, x, y;
unsigned char fg, bg, *cap, tile_handle;
{
int count,y1;
if (cap == NULL) return;
y1 = y;
for (count = 0; count < 3; count++) {
vs_puts(handle,tile_handle,x,y1++,6,fg,bg,keybox[count]);
}
vs_puts(handle,tile_handle,x+1,y+1,4,fg,bg,cap);
}
int printkeys()
{
int count;
for (count = 0; count < 36; count++) printcmdkey(count,
cap_f[count], cap_b[count]);
}
int printcmdkey(num,fg,bg)
int num;
unsigned char fg, bg;
{
int x, y;
y = num / 6;
x = (num % 6);
printbox(comm_wdw, 0, (x * 6) + 1, (y * 3) + 1, fg, bg, msg[num]);
}
int getcap(x,y)
{
int cap;
x--;
y--;
cap = x / 6;
if (cap > 5) return(37);
cap += (y / 3) * 6;
return(cap);
}
int interp_mouseclick(clicks, mousex, mousey)
int clicks, mousex, mousey;
{
int xdiff, ydiff, result, iclicks, cap;
unsigned int x, y;
unsigned int handle;
unsigned char tile_handle;
if (clicks == HOLDING) mouse_timeout = -1;
if (clicks == RELEASE) mouse_timeout = 15;
if (clicks == PRESS) mouse_timeout = 15;
scr_test = FALSE;
x = (mousex/(640/physical_columns)) + 1;
y = (mousey/(200/physical_rows)) + 1;
result = wn_whereon(&handle, &tile_handle, &x, &y);
if (command->op != HELP) {
if ((handle == comm_wdw) && (!tile_handle) && (result == 17)) {
if ((clicks == CLICK) || (clicks == RELEASE)
|| clicks == DOUBLECLICK) {
cap = getcap(x,y);
if (cap <= 36) return(ctox[cap]);
}
}
if ((handle == tape_wdw) && (!tile_handle) &&
((clicks == CLICK) || (clicks == HOLDING))) {
if(result == 11) return(XDOWN);
if(result == 12) return(XUP);
if(result == 13) return(XDOWN);
if(result == 14) return(XUP);
}
if ((handle == tape_wdw) && (!tile_handle) &&
(clicks == DOUBLECLICK)) {
if(result == 11) return(XPGUP);
if(result == 12) return(XPGDN);
if(result == 13) return(XPGUP);
if(result == 14) return(XPGDN);
}
if ((handle == comm_wdw) && (result == 1) && (clicks == PRESS)) {
iclicks = kb_mouseclicks(1,-1,&x,&y);
while(iclicks == HOLDING) {
x = (x/(640/physical_columns)) + 1;
y = (y/(200/physical_rows)) + 1;
xdiff = x - window[comm_wdw]->physical_x;
ydiff = y - window[comm_wdw]->physical_y;
scroll(xdiff,ydiff);
iclicks = kb_mouseclicks(1,-1,&x,&y);
}
}
if ((handle == comm_wdw) && (result == 3) && (clicks == PRESS)) {
iclicks = kb_mouseclicks(1,-1,&x,&y);
while(iclicks == HOLDING) {
x = (x/(640/physical_columns)) + 1;
xdiff = x - (window[comm_wdw]->physical_x +
window[comm_wdw]->port_columns + 1);
size(xdiff);
iclicks = kb_mouseclicks(1,-1,&x,&y);
}
}
}
else if ((handle == comm_wdw) && (!tile_handle) &&
((clicks == CLICK) || (clicks == HOLDING))) {
if(result == 11) return(XDOWN);
if(result == 12) return(XUP);
if(result == 13) return(XDOWN);
if(result == 14) return(XUP);
}
return(0);
}
int helpsystem()
{
int clicks, count;
unsigned int x, y;
wn_swapt(comm_wdw,0,comm_wdw,1);
wn_actw(comm_wdw);
clicks = FALSE;
count = TRUE;
while (count) {
if (mouse_installed) {
kb_showmouse();
clicks = kb_mouseclicks(1,mouse_timeout,&x,&y);
}
if (clicks) {
if (clicks == DOUBLECLICK) count = 2;
else count = interp_mouseclick(clicks, x, y);
if (!count) count = 1;
}
else if (kbhit()) count = kb_getxc();
else count = 1;
if (mouse_installed) kb_hidemouse();
switch (count) {
case XUP : wn_scrollvs(comm_wdw,0,0,-1);
break;
case XDOWN : wn_scrollvs(comm_wdw,0,0,1);
break;
case XRIGHT : wn_scrollvs(comm_wdw,0,1,0);
break;
case XLEFT : wn_scrollvs(comm_wdw,0,-1,0);
break;
case XHOME : wn_locatevs(comm_wdw,0,1,1);
break;
case XEND : wn_locatevs(comm_wdw,0,1,100);
break;
case XPGUP : wn_scrollvs(comm_wdw,0,0,-22);
break;
case XPGDN : wn_scrollvs(comm_wdw,0,0,22);
break;
case 1 : break;
default : count = FALSE;
}
}
wn_swapt(comm_wdw,0,comm_wdw,1);
wn_actw(tape_wdw);
command->op = 0;
}
int genhelp()
{
wn_createt(comm_wdw,"Cursor keys to scroll -- any other key to return",75,105,1,1);
/*
* this string is split up into several pieces because MSC 4 can't
* handle long strings
*/
vs_format(comm_wdw, 1, WHITE, BLACK,
"TENKEY+ is a programmable tenkey calculator written in C\n\
using The WINDOW PRO, the professional programmer's C\n\
windowing library. The WINDOW PRO is available from\n\
Seabreeze Software, (214) 437-2729. TENKEY+ is\n\
copyrighted (c) 1987, 1988 by Kenneth Stott. You\n\
may not sell TENKEY+, or remove this notice.\n\
\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"TENKEY+ operates just like the accountant's tenkey\n\
calculator, except that if you make a mistake you can\n\
go back and change the tape. Changing the tape\n\
automatically recalculates the entire tape. To edit\n\
an item position it in the edit area just below the\n\
tape and reenter the operation. Thats it!\n\
\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"If you are unfamiliar with adding machines you should\n\
note that it operates quite differently than a\n\
calculator. Also, TENKEY+ is meant principally to\n\
demonstrate The WINDOW PRO although it is useful, to\n\
make it a truly useful product would require the addition\n\
of IO (printing, and saving and loading tapes from disk)\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"and perhaps memory residency. These things aren't\n\
horrendously difficult -- so I've left the challenge to\n\
you. If you do modify TENKEY+ you must still incorporate\n\
the original copyright notice, you must indicate that\n\
it has been modified, and you may still not sell the\n\
program. -- although you are encouraged to share it.\n\
\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"Cursor keys -- vertical movement scrolls the tape.\n\
horizontal movement resizes the tape window. With\n\
scroll lock on cursor keys move the calculator.\n\
\n\
Insert -- with insert off all operations overwrite\n\
the operation in the edit area. While insert is on\n\
new operations are inserted above the item in the\n\
edit area.\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"\n\
Subtotal Register -- displays the value of the\n\
subtotal accumulator.\n\
\n\
Memory Register -- displays the value of the memory\n\
register.\n\
\n\
Default Register -- displays the value used by an\n\
operation if no value is explicitly entered.\n\
Operations which used the default register have a\n\
| displayed to the left. The default register is\n\
always equal to the value used by the operation\n\
above it.\n\
\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"MR -- outputs the value of the memory register to\n\
the tape.\n\
\n\
M+/M- -- adds/subtracts a value to/from the memory\n\
register.\n\
\n\
MC -- outputs the value of the memory register and\n\
clears the memory register.\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"ST -- outputs the value of the subtotal register.\n\
\n\
GT -- outputs the value of the subtotal register\n\
and clears it.\n\
\n\
+/- -- outputs a value and adds/subtracts it\n\
to/from the subtotal accumulator\n\
\n\
* & / -- multiplies or divides the value by the\n\
value of the next operation. If the next operation\n\
is + or - the result of the * or / is added to or\n\
subtracted from the subtotal accumulator\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"\n\
= -- complets a * or / operation.\n\
\n\
Del -- deletes the operation in the edit area.\n\
\n\
ENTER -- outputs a blank line.\n\
\n\
HELP -- view this screen.\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"\n\
(T)ear -- deletes the entire tape.\n\
\n\
(C)lear -- clears a number being entered in the\n\
edit area.\n\
\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"CMT -- lets you enter a 29 character alpha string\n\
to output on the tape.\n\
\n\
EXIT -- exit TENKEY+.\n\
\n\
Using the Mouse -- If you have a mouse installed\n\
clicking on the picture of the calculator keys\n\
works the same as pressing the keys on the\n\
keyboard.\n\
\n");
vs_format(comm_wdw, 1, WHITE, BLACK,
"To move the calculator around the screen grab it\n\
in the upper left corner and move the mouse cursor.\n\
\n\
To resize the tape window grab the calculator in the\n\
lower right corner and move the mouse cursor.\n\
\n\
To scroll the tape press on the scroll bar indicators.\n\
\n\
You can exit HELP by double clicking anywhere.");
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/