home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
viscobv6.zip
/
vac22os2
/
ibmcobol
/
samples
/
toolkit
/
rexx
/
api
/
rexxcalc
/
rexxcal3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-19
|
32KB
|
615 lines
/*********************************************************************/
/* */
/* REXXCAL3 - A simple PM based pocket calculator */
/* */
/*********************************************************************/
/* Standard C libraries */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
/* Include specific parts of the OS/2 and presentation manager */
/* definitions */
#define INCL_WIN
#include <os2.h>
#define INCL_RXFUNC
#include <rexxsaa.h>
/* Include the constants file created by the Dialog Box Editor. */
/* This include file defines symbols for all elements of the */
/* calculator dialog. */
#include "rexxcal3.h"
/* Declare prototypes for all subroutines. */
INT main(VOID); /* Main PM calculator program */
/* Calculator dialog */
MRESULT EXPENTRY Calculator(HWND, ULONG, MPARAM, MPARAM);
/* CalcForm external function */
LONG APIENTRY CalcForm(PSZ, LONG, PRXSTRING, PSZ, PRXSTRING);
/* CalcPrecision ext function */
LONG APIENTRY CalcPrecision(PSZ, LONG, PRXSTRING, PSZ, PRXSTRING);
VOID ProcessArithmetic(LONG); /* Arithmetic processor */
VOID AddDigit(INT); /* add digit to display */
VOID SetDisplay(PRXSTRING); /* set new display */
INT ProcessProgram(PSZ); /* process a programmed key */
INT CheckWhole(PRXSTRING); /* validate a whole number */
/* Define some constants for the calculator dialog */
#define DISPLAY_WIDTH 20 /* width of display area */
#define MAX_DIGITS 18 /* maximum digits in display */
#define SCIENTIFIC 0 /* Scientific floating point */
#define ENGINEERING 1 /* Engineering floating point */
#define YES 1 /* YES and NO constants (I */
#define NO 0 /* prefer these over TRUE and */
/* FALSE */
/* Global data used for the dialog */
HAB hab; /* Anchor block handle */
HWND hwndCalc; /* Handle for calculator */
/* dialog (created using */
/* the dialog editor) */
/* Global data used for the calculator */
UCHAR accbuff[DISPLAY_WIDTH + 1]; /* accumulator buffer */
UCHAR dispbuff[DISPLAY_WIDTH + 1]; /* display buffer */
UCHAR precision[MAX_DIGITS + 1]; /* current precision */
INT form; /* engineering/scientific flag*/
RXSTRING accumulator; /* current register value */
RXSTRING display; /* current display */
INT oldaction; /* pending key action */
INT digits; /* digits in display */
INT hadperiod; /* period in number */
INT hadexponent; /* exponent in number */
/* table of external function */
/* macro names */
PUCHAR operator_names[] = {
"MULTIPLY.CAL", /* * key */
"MINUS.CAL", /* - key */
"PLUS.CAL", /* + key */
"DIVIDE.CAL", /* / key */
"INTEGER.CAL", /* % key */
"REMAIND.CAL", /* // key */
"POWER.CAL", /* ** key */
"PROGRAM1.CAL", /* first program key */
"PROGRAM2.CAL" }; /* second program key */
/*********************************************************************/
/* main() - the main calculator program entry point */
/*********************************************************************/
INT main()
{
HMQ hmq; /* Message queue handle */
QMSG qmsg; /* Receive PM queue message */
/* startup PM usage */
hab = WinInitialize(0); /* Get the anchor block handle*/
hmq = WinCreateMsgQueue(hab, 0); /* Create the message queue */
/* register our window class */
WinRegisterClass(hab, "RexxCalc", Calculator, 0l, 0);
/* Load the calculator dialog. The dialog definitions are in */
/* rexxcalc.rc */
hwndCalc = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP,
NULL,
0,
REXXCALC, /* Dialog ID */
NULL);
WinSendMsg(hwndCalc, WM_SETICON, /* Set program icon */
(MPARAM)WinLoadPointer(HWND_DESKTOP, 0, REXXCALC), NULL);
/* set the window focus */
WinSetFocus(HWND_DESKTOP,
WinWindowFromID(hwndCalc, FID_CLIENT));
/* Process the standard Presentation Manager message loop until */
/* we are told to terminate */
/* While more messages */
while (WinGetMsg(hab, &qmsg, 0, 0, 0))
WinDispatchMsg(hab, &qmsg); /* dispatch application */
/* message handler */
/* The close option has been selected so we need to clean up */
/* our context. */
WinDestroyWindow(hwndCalc); /* Destroy the dialog window */
WinDestroyMsgQueue(hmq); /* Destroy the message queue */
WinTerminate(hab); /* Terminate PM usage */
return (0); /* Indicate successful */
/* completion */
}
/*********************************************************************/
/* */
/* Calculator() - the PM WinProc for handling the calculator dialog. */
/* The dialog itself has been created using the dialog box editor. */
/* This seperates the actual form of the calculator from the program */
/* source. */
/* */
/*********************************************************************/
MRESULT EXPENTRY Calculator(
HWND hwnd, /* window handle */
ULONG msg, /* dispatched message id */
MPARAM mp1, /* first message parameter */
MPARAM mp2 ) /* second message parameter */
{
ULONG action; /* Action to process */
switch (msg) { /* switch based on the message*/
/* received */
/* The initialization message has been received. We do some */
/* additional fixup of the dialog to make it look a little */
/* nicer. */
case WM_INITDLG:
/* initialize accumulator */
MAKERXSTRING(accumulator, accbuff, 1);
strcpy(accbuff, "0"); /* fill in a zero */
digits = 0; /* no digits in number */
hadperiod = NO; /* no period yet */
hadexponent = NO; /* no exponential yet */
oldaction = 0; /* no pending operations */
strcpy(precision, "9"); /* set default precision */
form = SCIENTIFIC; /* set default form */
SetDisplay(&accumulator); /* set initial display value */
/* update the calculator */
/* display */
WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
display.strptr);
/* register our external */
/* functions */
RexxRegisterFunctionExe("CalcPrecision", (PFN)CalcPrecision);
RexxRegisterFunctionExe("CalcForm", (PFN)CalcForm);
return FALSE; /* initialization complete */
/* We are going away, time to post a quit message to the */
/* message loop. */
case WM_CLOSE:
/* Deregister our defined */
/* functions */
RexxDeregisterFunction("CalcPrecision");
RexxDeregisterFunction("CalcForm");
/* Standard Close processing */
WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
return FALSE; /* Exit now */
/* We've received a WM_CONTROL message. This was */
/* generated by the "Form" check blox. */
case WM_CONTROL: /* change current form */
action = SHORT1FROMMP(mp1); /* Extract message sub-type */
switch (action) { /* process the control */
case BUTTON_FORM: /* form switch button */
if (form == SCIENTIFIC) { /* current scientific? */
form = ENGINEERING; /* make it engineering */
/* update label */
WinSetWindowText(WinWindowFromID(hwnd, BUTTON_FORM),
"Engineering");
}
else {
form = SCIENTIFIC; /* otherwise scientfic */
WinSetWindowText(WinWindowFromID(hwnd, BUTTON_FORM),
"Scientific");
}
return FALSE; /* all done */
default: /* Unknown, can't handle this */
return FALSE;
}
/* We've received a WM_COMMAND message. WM_COMMAND messages */
/* are generated by "pressing" buttons on the calculator. The */
/* additional parameters in the received message identify the */
/* button that was pressed */
case WM_COMMAND:
action = SHORT1FROMMP(mp1); /* Extract message sub-type */
switch (action) {
/* The following buttons will be processed by the actual */
/* calculator routine */
case BUTTON_CLEAR: /* Clear key */
/* initialize accumulator */
MAKERXSTRING(accumulator, accbuff, 1);
strcpy(accbuff, "0"); /* fill in a zero */
/* initialize the display */
MAKERXSTRING(display, dispbuff, 1);
strcpy(dispbuff, "0"); /* fill in a zero display */
digits = 0; /* no digits yet */
hadperiod = NO; /* turn off number processing */
hadexponent = NO; /* flags. */
oldaction = 0; /* and any pending operations */
/* update the calculator */
/* display */
WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
display.strptr);
return FALSE; /* All done */
case BUTTON_DIGITS: /* set new digits */
/* not a whole number? */
if (!CheckWhole(&display))
/* give an error beep */
WinAlarm(HWND_DESKTOP, WA_ERROR);
else { /* process the number */
/* copy the number */
strcpy(precision, display.strptr);
/* redisplay the accumlator */
SetDisplay(&accumulator);
/* display */
WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
display.strptr);
}
return FALSE; /* All done */
case BUTTON_0: /* Numeric keys */
case BUTTON_1:
case BUTTON_2:
case BUTTON_3:
case BUTTON_4:
case BUTTON_5:
case BUTTON_6:
case BUTTON_7:
case BUTTON_8:
case BUTTON_9:
case BUTTON_PERIOD: /* decimal point */
case BUTTON_EXPONENT: /* exponent value */
case BUTTON_SIGN: /* sign change */
/* Add a digit to display */
AddDigit(action);
/* update the accumulator */
/* display */
WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
display.strptr);
return FALSE; /* All done */
/* The arithmetic operation keys all have a deferred */
/* execution. When one of these is pressed, the previous*/
/* arithmetic operation is processed using the */
/* accumulator and the current display. The new operator*/
/* is saved for later execution. If no operator exists, */
/* then the current display is moved to the accumulator */
/* and no arithmetic is done */
case BUTTON_MULTIPLY: /* Multiply key */
case BUTTON_DIVIDE: /* Division key */
case BUTTON_PLUS: /* Addition key */
case BUTTON_MINUS: /* Subtraction key */
case BUTTON_IDIV: /* integer division */
case BUTTON_REMAINDER: /* remainder division */
case BUTTON_POWER: /* raise a number to power */
case BUTTON_ENTER: /* "Total" key */
case BUTTON_PROGRAM1: /* programmed Rexx function */
case BUTTON_PROGRAM2: /* programmed Rexx function */
/* Process pending operations */
ProcessArithmetic(action);
SetDisplay(&accumulator);/* reset display buffer */
/* update the calculator */
/* display */
WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
accumulator.strptr);
return FALSE; /* All done */
default: /* Unknown, can't handle this */
return FALSE;
}
case WM_ERASEBACKGROUND: /* disable background erase */
return MRFROMLONG(TRUE); /* don't allow this */
/* Message not handled by us. PM gives us first chance at all */
/* messages. Those we don't want to process we pass on to the */
/* default dialog procedure. */
default:
return WinDefWindowProc(hwnd, msg, mp1, mp2);
}
return FALSE; /* Should never reach here */
}
/*********************************************************************/
/* */
/* AddDigit(digit) - add a digit to the calculator display */
/* */
/*********************************************************************/
VOID AddDigit(
INT digit ) /* new digit to add */
{
if (digit == BUTTON_SIGN) { /* negate number */
if (!digits || /* first press? */
/* sign after exponent? */
display.strptr[digits-1] == 'E') {
display.strptr[digits++] = '-'; /* add the minus sign */
display.strptr[digits] = '\0'; /* add new string terminator */
display.strlength = digits; /* keep length in check */
}
else /* invalid sign press */
WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user */
}
else if (digit == BUTTON_PERIOD) { /* decimal point */
if (hadperiod || /* have one already? */
hadexponent || /* or an exponent? */
digits >= MAX_DIGITS) /* or too big */
WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user */
else { /* add a decimal point */
if (!digits) /* have digits already? */
display.strptr[digits++] = '0';/* no, add leading zero */
display.strptr[digits++] = '.'; /* add the decimal point */
display.strptr[digits] = '\0'; /* add new string terminator */
display.strlength = digits; /* keep length in check */
hadperiod = YES; /* remember this */
}
}
else if (digit == BUTTON_EXPONENT) { /* use scientific */
if (hadexponent || /* have one already? */
digits >= MAX_DIGITS) /* or too big */
WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user */
else {
if (!digits) /* have digits already? */
display.strptr[digits++] = '0';/* no, add leading zero */
display.strptr[digits++] = 'E'; /* add the exponent */
display.strptr[digits] = '\0'; /* add new string terminator */
display.strlength = digits; /* keep length in check */
hadexponent = YES; /* remember this */
}
}
else { /* real digit */
digit -= BUTTON_0; /* make base zero */
digit += (INT)'0'; /* convert to character value */
if (digits >= MAX_DIGITS) /* or too big */
WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user */
else { /* if small enough */
/* add new digit to display */
display.strptr[digits++] = (UCHAR)digit;
display.strptr[digits] = '\0'; /* add new string terminator */
display.strlength = digits; /* keep length in check */
}
}
}
/*********************************************************************/
/* */
/* SetDisplay(newdisplay) - Set the current display string to a new */
/* display value. */
/* */
/*********************************************************************/
VOID SetDisplay(
PRXSTRING newdisplay ) /* new number to display */
{
/* copy the new value */
memcpy(dispbuff, newdisplay->strptr, newdisplay->strlength);
display.strptr = dispbuff; /* point at current buffer */
/* update the length */
display.strlength = newdisplay->strlength;
dispbuff[display.strlength] = '\0'; /* make into ASCII-Z */
digits = 0; /* no digits in number */
hadperiod = NO; /* no period yet */
hadexponent = NO; /* no exponential yet */
}
/*********************************************************************/
/* */
/* ProcessArithmetic(newaction) - Process any pending arithmetic */
/* operation updating the accumulator and the pending */
/* operation. */
/* */
/*********************************************************************/
VOID ProcessArithmetic(
LONG newaction ) /* new operator key pressed */
{
switch(oldaction) { /* process prior action key */
case BUTTON_MULTIPLY: /* multiplication */
case BUTTON_DIVIDE: /* division */
case BUTTON_PLUS: /* addition */
case BUTTON_MINUS: /* subtraction */
case BUTTON_IDIV: /* integer division */
case BUTTON_REMAINDER: /* remainder division */
case BUTTON_POWER: /* raise a number to power */
/* call the appropriate */
/* Rexx operand processor */
if (ProcessProgram(operator_names[oldaction-BUTTON_MULTIPLY]))
oldaction = 0; /* cancel next on error */
else
oldaction = newaction; /* remember the new action */
break;
default:
/* copy display into accum */
strcpy(accumulator.strptr, display.strptr);
/* copy the length also */
accumulator.strlength = display.strlength;
display.strlength = 0; /* clear out digits */
break; /* no more needed */
}
switch (newaction) { /* now process then new key */
/* process function keys */
/* immediately */
case BUTTON_PROGRAM1: /* program key one */
case BUTTON_PROGRAM2: /* program key two */
/* call the appropriate */
/* Rexx operand processor */
SetDisplay(&accumulator); /* update display */
ProcessProgram(operator_names[newaction-BUTTON_MULTIPLY]);
oldaction = 0; /* cancel next action */
break;
default: /* all other operations */
oldaction = newaction; /* remember the new action */
}
}
/*********************************************************************/
/* */
/* ProcessProgram() - Process a call to a programed Rexx function. */
/* The program is passed both the accumulator */
/* and the current display as strings. */
/* */
/*********************************************************************/
INT ProcessProgram(
PSZ macro_name ) /* macro to invoke */
{
RXSTRING args[2]; /* passed argument strings */
RXSTRING result; /* returned result string */
INT rc; /* Rexx return code */
SHORT return_code; /* function return code */
args[0] = accumulator; /* set first argument */
args[1] = display; /* set second argument */
/* ask for result in accum */
result = accumulator; /* copy accumulator data */
result.strlength = DISPLAY_WIDTH; /* set maximum size */
rc = RexxStart(2, /* two arguments */
args, /* array of arguments */
macro_name, /* name of the macro */
NULL, NULL,
RXFUNCTION, /* calling this a function */
NULL,
&return_code, /* numeric value of return str*/
&result); /* returned string result */
/* update accumulator length */
accumulator.strlength = result.strlength;
/* make into an ASCII-Z string*/
accumulator.strptr[accumulator.strlength] = '\0';
if (accumulator.strptr[0] == 'E') /* function return an error? */
return YES; /* yes, indicate so */
else
return NO; /* no errors */
}
/*********************************************************************/
/* */
/* CheckWhole() - Call Rexx to check if the digits setting is */
/* a whole number. */
/* */
/*********************************************************************/
INT CheckWhole(
PRXSTRING number ) /* number to check */
{
RXSTRING argv; /* passed argument string */
RXSTRING result; /* returned result string */
UCHAR resbuf[10]; /* result buffer */
INT rc; /* Rexx return code */
SHORT return_code; /* function return code */
argv = *number; /* set the operand */
result.strptr = resbuf; /* point to return point */
result.strlength = sizeof(resbuf); /* set maximum size */
rc = RexxStart(1, /* two arguments */
&argv, /* array of arguments */
"WHOLE.CAL", /* Whole number checker */
NULL, NULL,
RXFUNCTION, /* calling this a function */
NULL,
&return_code, /* numeric value of return str*/
&result); /* returned string result */
if (resbuf[0] == '1') /* whole number? */
return YES; /* yes, this is good */
else
return NO; /* nope, bad number */
}
/*********************************************************************/
/* */
/* CalcPrecision - External Rexx function for obtaining current */
/* calculator numeric precision */
/* */
/*********************************************************************/
LONG APIENTRY CalcPrecision(
PSZ name, /* function name */
LONG argc, /* count of arguments */
PRXSTRING argv, /* argument RXSTRINGs */
PSZ queue, /* current Rexx queue */
PRXSTRING retstr ) /* returned string value */
{
strcpy(RXSTRPTR(*retstr), (const char *)precision);/* copy over current precision*/
/* set new length */
retstr->strlength = strlen((const char *)precision);
return 0; /* completed successfully */
}
/*********************************************************************/
/* */
/* CalcForm - External Rexx function for obtaining current */
/* caculator numeric form */
/* */
/*********************************************************************/
LONG APIENTRY CalcForm(
PSZ name, /* function name */
LONG argc, /* count of arguments */
PRXSTRING argv, /* argument RXSTRINGs */
PSZ queue, /* current Rexx queue */
PRXSTRING retstr ) /* returned string value */
{
if (form == SCIENTIFIC) { /* scientific precision? */
/* return that word */
strcpy(RXSTRPTR(*retstr), "SCIENTIFIC");
/* set new length */
retstr->strlength = strlen("SCIENTIFIC");
}
else { /* engineering precision */
/* return that word */
strcpy(RXSTRPTR(*retstr), "ENGINEERING");
/* set new length */
retstr->strlength = strlen("ENGINERRING");
}
return 0; /* completed successfully */
}