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 / rexxcal4.c < prev    next >
C/C++ Source or Header  |  1996-11-19  |  64KB  |  1,204 lines

  1. /*********************************************************************/
  2. /*                                                                   */
  3. /* REXXCAL4 - A simple PM based pocket calculator                    */
  4. /*                                                                   */
  5. /*********************************************************************/
  6.  
  7. /* Standard C libraries */
  8.  
  9. #define  _MT
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include <string.h>
  13. #include <math.h>
  14. #include <process.h>
  15.  
  16.  /* Include specific parts of the OS/2 and presentation manager      */
  17.  /* definitions                                                      */
  18.  
  19. #define INCL_DOSSEMAPHORES
  20. #define INCL_DOSPROCESS
  21. #define INCL_WIN
  22. #include <os2.h>
  23. #define INCL_RXFUNC
  24. #define INCL_RXSUBCOM
  25. #define INCL_RXSHV
  26. #include <rexxsaa.h>
  27.  
  28. /* Include the constants file created by the Dialog Box Editor.      */
  29. /* This include file defines symbols for all elements of the         */
  30. /* calculator dialog.                                                */
  31.  
  32. #include "rexxcal4.h"
  33.  
  34. /* Declare some typedefs                                             */
  35.  
  36. typedef struct {                       /* Instorage descriptor       */
  37.   RXSTRING    source;                  /* Program source             */
  38.   RXSTRING    image;                   /* tokenized image            */
  39. } INSTORE;
  40.  
  41. typedef INSTORE *PINSTORE;             /* pointer to instore desc.   */
  42.  
  43. /* Declare prototypes for all subroutines.                           */
  44.  
  45. INT main(void);                        /* Main PM calculator program */
  46.  
  47.                                        /* Calculator dialog          */
  48. MRESULT EXPENTRY Calculator(HWND, ULONG, MPARAM, MPARAM);
  49.                                        /* Button subclass winproc    */
  50. MRESULT EXPENTRY Button(HWND, ULONG, MPARAM, MPARAM);
  51.                                        /* CalcForm external function */
  52. LONG    EXPENTRY CalcForm(PSZ, LONG, PRXSTRING, PSZ, PRXSTRING);
  53.                                        /* CalcPrecision ext function */
  54. LONG    EXPENTRY CalcPrecision(PSZ, LONG, PRXSTRING, PSZ, PRXSTRING);
  55.                                        /* subcommand handler         */
  56. APIRET  EXPENTRY CalcCommand(PRXSTRING, PUSHORT, PRXSTRING);
  57. void    CalcThread(void);              /* thread for calculations    */
  58. void    EditThread(void);              /* thread for editting        */
  59. void    ProcessArithmetic(LONG);       /* Arithmetic processor       */
  60. void    AddDigit(INT);                 /* add digit to display       */
  61. void    SetDisplay(PRXSTRING);         /* set new display            */
  62.                                        /* process a programmed key   */
  63. void    ProcessProgram(ULONG, PRXSTRING, PRXSTRING, PRXSTRING);
  64. void    ProcessMacro(ULONG, PRXSTRING, PRXSTRING, PRXSTRING, ULONG);
  65. INT     Datatype(PSZ, PSZ);            /* validate a whole number    */
  66.                                        /* read macro source          */
  67. void    ReadSourceFile(PSZ, PINSTORE);
  68. void    FreeSourceFile(PINSTORE);      /* free macro source          */
  69. INT     SetRexxVariable(PSZ, PSZ);     /* set a Rexx variable        */
  70.  
  71. /* Define some constants for the calculator dialog                   */
  72.  
  73. #define DISPLAY_WIDTH    20            /* width of display area      */
  74. #define MAX_DIGITS       18            /* maximum digits in display  */
  75. #define SCIENTIFIC        0            /* Scientific floating point  */
  76. #define ENGINEERING       1            /* Engineering floating point */
  77. #define NUMBER_MEMORIES   50           /* size of memory registers   */
  78. #define STACKSIZE         8192         /* thread execution stack     */
  79. #define YES               1            /* YES and NO constants (I    */
  80. #define NO                0            /* prefer these over TRUE and */
  81.                                        /* FALSE                      */
  82. #define WM_EDIT_DONE      WM_USER+1    /* edit completion user msg   */
  83. #define WM_MEMORY_DONE    WM_USER+2    /* calc completion user msg   */
  84. #define WM_OPERATOR_DONE  WM_USER+3    /* calc completion user msg   */
  85. #define WM_PROGRAM_DONE   WM_USER+4    /* calc completion user msg   */
  86. #define MACRO_COUNT       (sizeof(operator_names)/sizeof(PSZ))
  87.  
  88. /* Global data used for the dialog                                   */
  89.  
  90.  HAB    hab;                           /* Anchor block handle        */
  91.  HWND   hwndCalc;                      /* Handle for calculator      */
  92.                                        /*   dialog (created using    */
  93.                                        /*   the dialog editor)       */
  94.  
  95. /* Global data used for the calculator                               */
  96.  
  97.                                        /* memory registers           */
  98.  PSZ      memory_bank[NUMBER_MEMORIES + 1];
  99.  UCHAR    membuff[3];                  /* memory function selector   */
  100.  UCHAR    accbuff[DISPLAY_WIDTH + 1];  /* accumulator buffer         */
  101.  UCHAR    dispbuff[DISPLAY_WIDTH + 1]; /* display buffer             */
  102.  UCHAR    precision[MAX_DIGITS + 1];   /* current precision          */
  103.  INT      form;                        /* engineering/scientific flag*/
  104.  RXSTRING accumulator;                 /* current register value     */
  105.  RXSTRING display;                     /* current display            */
  106.  INT      oldaction;                   /* pending key action         */
  107.  INT      digits;                      /* digits in display          */
  108.  INT      hadperiod;                   /* period in number           */
  109.  INT      hadexponent;                 /* exponent in number         */
  110.  INT      memory_function;             /* memory function flag       */
  111.  INT      memory_action;               /* save memory action         */
  112.                                        /* saved window procedures    */
  113.  PFNWP    oldwindowproc[MAX_MACRO - MIN_MACRO + 1];
  114.  INT      calcdisabled;                /* calc interlock flag        */
  115.  TID      editthreadid;                /* TID of editor thread       */
  116.  TID      calcthreadid;                /* TID of calculator thread   */
  117.  HEV      calcsem;                     /* calculation semaphore      */
  118.  LONG     editted_program;             /* macro editted              */
  119.  RXSTRING global_args[2];              /* passed argument strings    */
  120.  INT      global_argc;                 /* argument count             */
  121.  PRXSTRING global_result;              /* returned result string     */
  122.  ULONG    global_completion;           /* completion message         */
  123.  ULONG    global_macro_name;           /* macro to invoke            */
  124.  HWND     global_handle;               /* handle for completion msg  */
  125.  
  126.                                        /* table of external function */
  127.                                        /* macro names                */
  128. PUCHAR     operator_names[] = {
  129.     "MULTIPLY.CAL",                    /* * key                      */
  130.     "MINUS.CAL",                       /* - key                      */
  131.     "PLUS.CAL",                        /* + key                      */
  132.     "DIVIDE.CAL",                      /* / key                      */
  133.     "INTEGER.CAL",                     /* % key                      */
  134.     "REMAIND.CAL",                     /* // key                     */
  135.     "POWER.CAL",                       /* ** key                     */
  136.     "PROGRAM1.CAL",                    /* first program key          */
  137.     "PROGRAM2.CAL",                    /* second program key         */
  138.     "PROGRAM3.CAL",                    /* third program key          */
  139.     "PROGRAM4.CAL",                    /* fourth program key         */
  140.     "MEMPLUS.CAL",                     /* memory plus key            */
  141.     "MEMMINUS.CAL",                    /* memory minus key           */
  142.     "MEMSTORE.CAL",                    /* memory recall key          */
  143.     "MEMRECAL.CAL",                    /* memory store key           */
  144.     "MEMCLEAR.CAL",                    /* memory clear key           */
  145.     "DATATYPE.CAL"};                   /* data validation program    */
  146.  
  147.                                        /* loaded program sources     */
  148. INSTORE    operator_programs[MACRO_COUNT];
  149.  
  150. /*********************************************************************/
  151. /* main() - the main calculator program entry point                  */
  152. /*********************************************************************/
  153.  
  154. INT main()
  155. {
  156.   HMQ   hmq;                           /* Message queue handle       */
  157.   QMSG  qmsg;                          /* Receive PM queue message   */
  158.  
  159.                                        /* startup PM usage           */
  160.   hab = WinInitialize(0);              /* Get the anchor block handle*/
  161.   hmq = WinCreateMsgQueue(hab, 0);     /* Create the message queue   */
  162.                                        /* register our window class  */
  163.   WinRegisterClass(hab, "RexxCalc", Calculator, 0l, 0);
  164.  
  165.   /* Load the calculator dialog.  The dialog definitions are in      */
  166.   /* rexxcalc.rc                                                     */
  167.  
  168.   hwndCalc = WinLoadDlg(HWND_DESKTOP, HWND_DESKTOP,
  169.                         NULL,
  170.                         0,
  171.                         REXXCALC,      /* Dialog ID                  */
  172.                         NULL);
  173.  
  174.   WinSendMsg(hwndCalc, WM_SETICON,     /* Set program icon           */
  175.       (MPARAM)WinLoadPointer(HWND_DESKTOP, 0, REXXCALC), NULL);
  176.  
  177.                                        /* set the window focus       */
  178.   WinSetFocus(HWND_DESKTOP,
  179.       WinWindowFromID(hwndCalc, FID_CLIENT));
  180.  
  181.   /* Process the standard Presentation Manager message loop until    */
  182.   /* we are told to terminate                                        */
  183.  
  184.                                        /* While more messages        */
  185.   while (WinGetMsg(hab, &qmsg, 0, 0, 0))
  186.      WinDispatchMsg(hab, &qmsg);       /* dispatch application       */
  187.                                        /*   message handler          */
  188.  
  189.  
  190.   /* The close option has been selected so we need to clean up       */
  191.   /* our context.                                                    */
  192.  
  193.   WinDestroyWindow(hwndCalc);          /* Destroy the dialog window  */
  194.   WinDestroyMsgQueue(hmq);             /* Destroy the message queue  */
  195.   WinTerminate(hab);                   /* Terminate PM usage         */
  196.   return (0);                          /* Indicate successful        */
  197.                                        /*   completion               */
  198. }
  199.  
  200. /*********************************************************************/
  201. /*                                                                   */
  202. /* Calculator() - the PM WinProc for handling the calculator dialog. */
  203. /* The dialog itself has been created using the dialog box editor.   */
  204. /* This seperates the actual form of the calculator from the program */
  205. /* source.                                                           */
  206. /*                                                                   */
  207. /*********************************************************************/
  208.  
  209. MRESULT EXPENTRY Calculator(
  210.   HWND    hwnd,                        /* window handle              */
  211.   ULONG   msg,                         /* dispatched message id      */
  212.   MPARAM  mp1,                         /* first message parameter    */
  213.   MPARAM  mp2 )                        /* second message parameter   */
  214. {
  215.   ULONG     action;                    /* Action to process          */
  216.   INT       i;                         /* loop index                 */
  217.   RXSTRING  memory_setting;            /* memory number              */
  218.  
  219.    switch (msg) {                      /* switch based on the message*/
  220.                                        /* received                   */
  221.  
  222.       /* The initialization message has been received.  We do some   */
  223.       /* additional fixup of the dialog to make it look a little     */
  224.       /* nicer.                                                      */
  225.  
  226.       case WM_INITDLG:
  227.  
  228.          global_handle = hwnd;         /* remember handle for thread */
  229.                                        /* register our external      */
  230.                                        /* functions                  */
  231.          RexxRegisterFunctionExe("CalcPrecision", (PFN)CalcPrecision);
  232.          RexxRegisterFunctionExe("CalcForm", (PFN)CalcForm);
  233.                                        /* register subcommand handler*/
  234.          RexxRegisterSubcomExe("Calculator", (PFN)CalcCommand, NULL);
  235.                                        /* read in the programs       */
  236.          for (i = 0; i < MACRO_COUNT; i++)
  237.            ReadSourceFile(operator_names[i],
  238.                &operator_programs[i]);
  239.  
  240.                                        /* initialize the memory bank */
  241.          for (i = 1; i <= NUMBER_MEMORIES; i++)
  242.            memory_bank[i] = NULL;      /* all null pointers          */
  243.  
  244.                                        /* subclass programmable      */
  245.                                        /* buttons so we can trap     */
  246.                                        /* BUTTON2 events             */
  247.          for (i = MIN_MACRO; i <= MAX_MACRO; i++)
  248.            oldwindowproc[i - MIN_MACRO] =
  249.                WinSubclassWindow(WinWindowFromID(hwnd, i),
  250.                (PFNWP)Button);
  251.                                        /* initialize accumulator     */
  252.          MAKERXSTRING(accumulator, accbuff, 1);
  253.          strcpy(accbuff, "0");         /* fill in a zero             */
  254.          digits = 0;                   /* no digits in number        */
  255.          hadperiod = NO;               /* no period yet              */
  256.          hadexponent = NO;             /* no exponential yet         */
  257.          oldaction = 0;                /* no pending operations      */
  258.          memory_function = NO;         /* not waiting for mem number */
  259.          strcpy(precision, "9");       /* set default precision      */
  260.          form = SCIENTIFIC;            /* set default form           */
  261.          calcdisabled = NO;            /* functions enabled          */
  262.          SetDisplay(&accumulator);     /* set initial display value  */
  263.                                        /* update the calculator      */
  264.                                        /* display                    */
  265.          WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  266.              display.strptr);
  267.          calcsem = 0;                  /* zero semaphore handle      */
  268.                                        /* create a semaphore         */
  269.          DosCreateEventSem(NULL, &calcsem, FALSE, FALSE);
  270.                                        /* create calculation thread  */
  271.          DosCreateThread(&calcthreadid, (PFNTHREAD)CalcThread, 
  272.              (ULONG)0, (ULONG)0, STACKSIZE);
  273.          return FALSE;                 /* initialization complete    */
  274.  
  275.       /* We have finished editting a key macro.  Clean up the thread */
  276.       /* and reenable the main calculator.                           */
  277.  
  278.       case WM_EDIT_DONE:
  279.  
  280.         calcdisabled = NO;             /* reenable the calculator    */
  281.         return FALSE;                  /* resume normal operations   */
  282.  
  283.       case WM_MEMORY_DONE:             /* memory command completed   */
  284.  
  285.         calcdisabled = NO;             /* reenable the calculator    */
  286.                                        /* display                    */
  287.         WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  288.             display.strptr);
  289.         return FALSE;                  /* resume normal operations   */
  290.  
  291.       case WM_OPERATOR_DONE:           /* math operator completed    */
  292.  
  293.         calcdisabled = NO;             /* reenable the calculator    */
  294.                                        /* function return an error?  */
  295.         if (!strcmp(accumulator.strptr,"Error"))
  296.           oldaction = 0;               /* cancel next on error       */
  297.                                        /* redisplay the accumlator   */
  298.         SetDisplay(&accumulator);
  299.                                        /* display                    */
  300.         WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  301.             display.strptr);
  302.  
  303.                                        /* may need to process a      */
  304.                                        /* a program key now          */
  305.         switch (oldaction) {           /* now process then new key   */
  306.  
  307.                                        /* process function keys      */
  308.                                        /* immediately                */
  309.           case BUTTON_PROGRAM1:        /* program key one            */
  310.           case BUTTON_PROGRAM2:        /* program key two            */
  311.           case BUTTON_PROGRAM3:        /* program key three          */
  312.           case BUTTON_PROGRAM4:        /* program key four           */
  313.  
  314.             oldaction = 0;             /* cancel next action         */
  315.                                        /* call the appropriate       */
  316.                                        /* Rexx operand processor     */
  317.                                        /* Process the macro          */
  318.             ProcessMacro(oldaction - MIN_MACRO, &accumulator, 
  319.                 &display, &accumulator, WM_PROGRAM_DONE);
  320.             break;
  321.  
  322.         }
  323.         return FALSE;                  /* resume normal operations   */
  324.  
  325.       case WM_PROGRAM_DONE:            /* program key completed      */
  326.  
  327.         calcdisabled = NO;             /* reenable the calculator    */
  328.                                        /* redisplay the accumlator   */
  329.         SetDisplay(&accumulator);
  330.                                        /* display                    */
  331.         WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  332.             display.strptr);
  333.         return FALSE;                  /* resume normal operations   */
  334.  
  335.       /* We are going away, time to post a quit message to the       */
  336.       /* message loop.                                               */
  337.  
  338.       case WM_CLOSE:
  339.  
  340.          if (calcdisabled)             /* currently editting?        */
  341.                                        /* suspend the thread         */
  342.            DosSuspendThread(editthreadid);
  343.                                        /* free source programs       */
  344.          for (i = 0; i < MACRO_COUNT; i++)
  345.            FreeSourceFile(&operator_programs[i]);
  346.                                        /* clear the memory bank      */
  347.          for (i = 1; i <= NUMBER_MEMORIES; i++)
  348.            if (memory_bank[i])         /* if has a value             */
  349.              free(memory_bank[i]);     /* release it                 */
  350.  
  351.                                        /* Deregister our defined     */
  352.                                        /* functions                  */
  353.          RexxDeregisterFunction("CalcPrecision");
  354.          RexxDeregisterFunction("CalcForm");
  355.                                        /* Deregister command handler */
  356.          RexxDeregisterSubcom("Calculator", NULL);
  357.  
  358.                                        /* Standard Close processing  */
  359.          WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  360.          return FALSE;                 /* Exit now                   */
  361.  
  362.       /* We've received a WM_CONTROL message.  This was              */
  363.       /* generated by the "Form" check blox.                         */
  364.  
  365.       case WM_CONTROL:                 /* change current form        */
  366.  
  367.          action = SHORT1FROMMP(mp1);   /* Extract message sub-type   */
  368.  
  369.          switch (action) {             /* process the control        */
  370.  
  371.            case BUTTON_FORM:           /* form switch button         */
  372.  
  373.              if (form == SCIENTIFIC) { /* current scientific?        */
  374.                form = ENGINEERING;     /* make it engineering        */
  375.                                        /* update label               */
  376.                WinSetWindowText(WinWindowFromID(hwnd, BUTTON_FORM),
  377.                    "Engineering");
  378.              }
  379.              else {
  380.                form = SCIENTIFIC;      /* otherwise scientfic        */
  381.                WinSetWindowText(WinWindowFromID(hwnd, BUTTON_FORM),
  382.                   "Scientific");
  383.              }
  384.              return FALSE;             /* all done                   */
  385.            default:                    /* Unknown, can't handle this */
  386.              return FALSE;
  387.          }
  388.  
  389.       /* We've received a WM_COMMAND message.  WM_COMMAND messages   */
  390.       /* are generated by "pressing" buttons on the calculator.  The */
  391.       /* additional parameters in the received message identify the  */
  392.       /* button that was pressed                                     */
  393.  
  394.       case WM_COMMAND:
  395.  
  396.          if (calcdisabled) {           /* editting a function?       */
  397.                                        /* give an error beep         */
  398.            WinAlarm(HWND_DESKTOP, WA_ERROR);
  399.            return FALSE;               /* done with message          */
  400.          }
  401.  
  402.          action = SHORT1FROMMP(mp1);   /* Extract message sub-type   */
  403.          if (memory_function) {        /* waiting for memory input?  */
  404.            switch(action) {            /* process based on type      */
  405.  
  406.              case BUTTON_0:            /* Numeric keys are the only  */
  407.              case BUTTON_1:            /* things allowed, except for */
  408.              case BUTTON_2:            /* the clear key              */
  409.              case BUTTON_3:
  410.              case BUTTON_4:
  411.              case BUTTON_5:
  412.              case BUTTON_6:
  413.              case BUTTON_7:
  414.              case BUTTON_8:
  415.              case BUTTON_9:
  416.  
  417.                                        /* store character            */
  418.                membuff[sizeof(membuff) - (memory_function + 1)] =
  419.                    (UCHAR)((action - BUTTON_0) + '0');
  420.                                        /* got last digit?            */
  421.                if (!(--memory_function)) {
  422.                                        /* get memory number in an    */
  423.                                        /* RXSTRING                   */
  424.                  MAKERXSTRING(memory_setting, membuff,
  425.                      sizeof(membuff) - 1);
  426.                                        /* process the memory key     */
  427.                  switch (memory_action) {
  428.  
  429.                                        /* memory recall              */
  430.                    case BUTTON_MEMORY_RECALL:
  431.                    case BUTTON_MEMORY_CLEAR:
  432.  
  433.                                        /* call the macro             */
  434.                      ProcessMacro(memory_action - MIN_MACRO,
  435.                          &memory_setting, NULL, NULL, WM_MEMORY_DONE);
  436.                      break;            /* finished                   */
  437.  
  438.                                        /* memory operation on display*/
  439.                    case BUTTON_MEMORY_STORE:
  440.                    case BUTTON_MEMORY_PLUS:
  441.                    case BUTTON_MEMORY_MINUS:
  442.  
  443.                                        /* call the macro             */
  444.                      ProcessMacro(memory_action - MIN_MACRO,
  445.                          &memory_setting, &accumulator,
  446.                          NULL, WM_MEMORY_DONE);
  447.                      break;            /* finished                   */
  448.                  }
  449.                }
  450.                return FALSE;           /* done with message          */
  451.  
  452.              case BUTTON_CLEAR:        /* Clear key                  */
  453.  
  454.                memory_function = 0;    /* disable memory function    */
  455.                return FALSE;           /* done with message          */
  456.  
  457.              default:                  /* disabled key               */
  458.                                        /* give an error beep         */
  459.                WinAlarm(HWND_DESKTOP, WA_ERROR);
  460.                return FALSE;           /* done with message          */
  461.            }
  462.          }
  463.  
  464.          switch (action) {
  465.  
  466.                                        /* memory operation on display*/
  467.             case BUTTON_MEMORY_STORE:  /* store to memory            */
  468.             case BUTTON_MEMORY_PLUS:   /* add to memory              */
  469.             case BUTTON_MEMORY_MINUS:  /* subtract from memory       */
  470.             case BUTTON_MEMORY_RECALL: /* recall memory to display   */
  471.             case BUTTON_MEMORY_CLEAR:  /* clear a memory             */
  472.  
  473.                                        /* copy display into accum    */
  474.               strcpy(accumulator.strptr, display.strptr);
  475.                                        /* copy the length also       */
  476.               accumulator.strlength = display.strlength;
  477.               digits = 0;              /* no digits in display       */
  478.               memory_action = action;  /* remember the key           */
  479.               memory_function = 2;     /* need two digits from pad   */
  480.               return FALSE;            /* wait for key info          */
  481.  
  482.             case BUTTON_CLEAR:         /* Clear key                  */
  483.  
  484.                                        /* initialize accumulator     */
  485.               MAKERXSTRING(accumulator, accbuff, 1);
  486.               strcpy(accbuff, "0");    /* fill in a zero             */
  487.                                        /* initialize the display     */
  488.               MAKERXSTRING(display, dispbuff, 1);
  489.               strcpy(dispbuff, "0");   /* fill in a zero display     */
  490.               digits = 0;              /* no digits yet              */
  491.               hadperiod = NO;          /* turn off number processing */
  492.               hadexponent = NO;        /* flags.                     */
  493.               oldaction = 0;           /* and any pending operations */
  494.                                        /* update the calculator      */
  495.                                        /* display                    */
  496.               WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  497.                   display.strptr);
  498.               return FALSE;            /* All done                   */
  499.  
  500.             case BUTTON_DIGITS:        /* set new digits             */
  501.                                        /* not a whole number?        */
  502.               if (!Datatype(display.strptr, "Whole"))
  503.                                        /* give an error beep         */
  504.                 WinAlarm(HWND_DESKTOP, WA_ERROR);
  505.               else {                   /* process the number         */
  506.                                        /* copy the number            */
  507.                 strcpy(precision, display.strptr);
  508.                                        /* redisplay the accumlator   */
  509.                 SetDisplay(&accumulator);
  510.                                        /* display                    */
  511.                 WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  512.                     display.strptr);
  513.               }
  514.               return FALSE;            /* All done                   */
  515.  
  516.             case BUTTON_0:             /* Numeric keys               */
  517.             case BUTTON_1:
  518.             case BUTTON_2:
  519.             case BUTTON_3:
  520.             case BUTTON_4:
  521.             case BUTTON_5:
  522.             case BUTTON_6:
  523.             case BUTTON_7:
  524.             case BUTTON_8:
  525.             case BUTTON_9:
  526.             case BUTTON_PERIOD:        /* decimal point              */
  527.             case BUTTON_EXPONENT:      /* exponent value             */
  528.             case BUTTON_SIGN:          /* sign change                */
  529.  
  530.                                        /* Add a digit to display     */
  531.               AddDigit(action);
  532.                                        /* update the accumulator     */
  533.                                        /* display                    */
  534.               WinSetWindowText(WinWindowFromID(hwnd, DISPLAY),
  535.                     display.strptr);
  536.               return FALSE;            /* All done                   */
  537.  
  538.             /* The arithmetic operation keys all have a deferred     */
  539.             /* execution.  When one of these is pressed, the previous*/
  540.             /* arithmetic operation is processed using the           */
  541.             /* accumulator and the current display.  The new operator*/
  542.             /* is saved for later execution.  If no operator exists, */
  543.             /* then the current display is moved to the accumulator  */
  544.             /* and no arithmetic is done                             */
  545.  
  546.             case BUTTON_MULTIPLY:      /* Multiply key               */
  547.             case BUTTON_DIVIDE:        /* Division key               */
  548.             case BUTTON_PLUS:          /* Addition key               */
  549.             case BUTTON_MINUS:         /* Subtraction key            */
  550.             case BUTTON_IDIV:          /* integer division           */
  551.             case BUTTON_REMAINDER:     /* remainder division         */
  552.             case BUTTON_POWER:         /* raise a number to power    */
  553.             case BUTTON_ENTER:         /* "Total" key                */
  554.             case BUTTON_PROGRAM1:      /* programmed Rexx function   */
  555.             case BUTTON_PROGRAM2:      /* programmed Rexx function   */
  556.             case BUTTON_PROGRAM3:      /* programmed Rexx function   */
  557.             case BUTTON_PROGRAM4:      /* programmed Rexx function   */
  558.  
  559.                                        /* Process pending operations */
  560.               global_handle = hwnd;    /* save window handle         */
  561.               ProcessArithmetic(action);
  562.               return FALSE;            /* All done                   */
  563.  
  564.             default:                   /* Unknown, can't handle this */
  565.                return FALSE;
  566.          }
  567.  
  568.       case WM_ERASEBACKGROUND:         /* disable background erase   */
  569.         return MRFROMLONG(TRUE);       /* don't allow this           */
  570.  
  571.       /* Message not handled by us.  PM gives us first chance at all */
  572.       /* messages.  Those we don't want to process we pass on to the */
  573.       /* default dialog procedure.                                   */
  574.  
  575.       default:
  576.          return WinDefWindowProc(hwnd, msg, mp1, mp2);
  577.  
  578.    }
  579.  
  580.    return FALSE;                       /* Should never reach here    */
  581.  }
  582.  
  583. /*********************************************************************/
  584. /*                                                                   */
  585. /* Button() -     the PM WinProc for handling actions on             */
  586. /* programmable buttons.  This only intercepts the WM_BUTTON2DOWN    */
  587. /* events for programmable keys.                                     */
  588. /*                                                                   */
  589. /*********************************************************************/
  590.  
  591. MRESULT EXPENTRY Button(
  592.   HWND    hwnd,                        /* window handle              */
  593.   ULONG   msg,                         /* dispatched message id      */
  594.   MPARAM  mp1,                         /* first message parameter    */
  595.   MPARAM  mp2 )                        /* second message parameter   */
  596. {
  597.   INT     id;                          /* id of pressed button       */
  598.  
  599.                                        /* get the button id          */
  600.   id = WinQueryWindowUShort(hwnd, QWS_ID);
  601.  
  602.   switch(msg) {                        /* process different messages */
  603.  
  604.                                        /* Button 2 pressed on a      */
  605.     case WM_BUTTON2DOWN:               /* programmed key.            */
  606.  
  607.       if (calcdisabled) {              /* already editting?          */
  608.                                        /* give an error beep         */
  609.         WinAlarm(HWND_DESKTOP, WA_ERROR);
  610.         return FALSE;                  /* done with message          */
  611.       }
  612.                                        /* save the program           */
  613.       editted_program = id - MIN_MACRO;
  614.       calcdisabled = YES;              /* disable key functions      */
  615.                                        /* spin off the thread        */
  616.       DosCreateThread(&editthreadid, (PFNTHREAD)EditThread, 
  617.           (ULONG)0, (ULONG)0, STACKSIZE);
  618.       return FALSE;                    /* wait for completion msg    */
  619.  
  620.       /* Pass all other events on to the main handlers.              */
  621.  
  622.     default:
  623.       return (*oldwindowproc[id - MIN_MACRO])(hwnd, msg, mp1, mp2);
  624.   }
  625.  
  626. }
  627. /*********************************************************************/
  628. /*                                                                   */
  629. /* AddDigit(digit) - add a digit to the calculator display           */
  630. /*                                                                   */
  631. /*********************************************************************/
  632.  
  633. void AddDigit(
  634.   INT    digit )                       /* new digit to add           */
  635. {
  636.  
  637.   if (digit == BUTTON_SIGN) {          /* negate number              */
  638.     if (!digits ||                     /* first press?               */
  639.                                        /* sign after exponent?       */
  640.         display.strptr[digits-1] == 'E') {
  641.       display.strptr[digits++] = '-';  /* add the minus sign         */
  642.       display.strptr[digits] = '\0';   /* add new string terminator  */
  643.       display.strlength = digits;      /* keep length in check       */
  644.     }
  645.     else                               /* invalid sign press         */
  646.       WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user           */
  647.   }
  648.  
  649.   else if (digit == BUTTON_PERIOD) {   /* decimal point              */
  650.     if (hadperiod ||                   /* have one already?          */
  651.         hadexponent ||                 /* or an exponent?            */
  652.         digits >= MAX_DIGITS)          /* or too big                 */
  653.       WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user           */
  654.     else {                             /* add a decimal point        */
  655.       if (!digits)                     /* have digits already?       */
  656.         display.strptr[digits++] = '0';/* no, add leading zero       */
  657.       display.strptr[digits++] = '.';  /* add the decimal point      */
  658.       display.strptr[digits] = '\0';   /* add new string terminator  */
  659.       display.strlength = digits;      /* keep length in check       */
  660.       hadperiod = YES;                 /* remember this              */
  661.     }
  662.   }
  663.  
  664.   else if (digit == BUTTON_EXPONENT) { /* use scientific             */
  665.     if (hadexponent ||                 /* have one already?          */
  666.         digits >= MAX_DIGITS)          /* or too big                 */
  667.       WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user           */
  668.     else {
  669.       if (!digits)                     /* have digits already?       */
  670.         display.strptr[digits++] = '0';/* no, add leading zero       */
  671.       display.strptr[digits++] = 'E';  /* add the exponent           */
  672.       display.strptr[digits] = '\0';   /* add new string terminator  */
  673.       display.strlength = digits;      /* keep length in check       */
  674.       hadexponent = YES;               /* remember this              */
  675.     }
  676.   }
  677.  
  678.   else {                               /* real digit                 */
  679.     digit -= BUTTON_0;                 /* make base zero             */
  680.     digit += (INT)'0';                 /* convert to character value */
  681.     if (digits >= MAX_DIGITS)          /* or too big                 */
  682.       WinAlarm(HWND_DESKTOP, WA_ERROR);/* beep at the user           */
  683.  
  684.     else {                             /* if small enough            */
  685.                                        /* add new digit to display   */
  686.       display.strptr[digits++] = (UCHAR)digit;
  687.       display.strptr[digits] = '\0';   /* add new string terminator  */
  688.       display.strlength = digits;      /* keep length in check       */
  689.     }
  690.   }
  691. }
  692.  
  693. /*********************************************************************/
  694. /*                                                                   */
  695. /* SetDisplay(newdisplay) - Set the current display string to a new  */
  696. /*                display value.                                     */
  697. /*                                                                   */
  698. /*********************************************************************/
  699.  
  700. void SetDisplay(
  701.   PRXSTRING  newdisplay )              /* new number to display      */
  702. {
  703.                                        /* copy the new value         */
  704.    memcpy(dispbuff, newdisplay->strptr, newdisplay->strlength);
  705.    display.strptr = dispbuff;          /* point at current buffer    */
  706.                                        /* update the length          */
  707.    display.strlength = newdisplay->strlength;
  708.    dispbuff[display.strlength] = '\0'; /* make into ASCII-Z          */
  709.    digits = 0;                         /* no digits in number        */
  710.    hadperiod = NO;                     /* no period yet              */
  711.    hadexponent = NO;                   /* no exponential yet         */
  712. }
  713.  
  714. /*********************************************************************/
  715. /*                                                                   */
  716. /* ProcessArithmetic(newaction)  -  Process any pending arithmetic   */
  717. /*                operation updating the accumulator and the pending */
  718. /*                operation.                                         */
  719. /*                                                                   */
  720. /*********************************************************************/
  721.  
  722. void ProcessArithmetic(
  723.   LONG  newaction )                    /* new operator key pressed   */
  724. {
  725.    LONG    action;                     /* action to take             */
  726.  
  727.    action = oldaction;                 /* remember old actiion       */
  728.  
  729.    switch(oldaction) {                 /* process prior action key   */
  730.  
  731.      case BUTTON_MULTIPLY:             /* multiplication             */
  732.      case BUTTON_DIVIDE:               /* division                   */
  733.      case BUTTON_PLUS:                 /* addition                   */
  734.      case BUTTON_MINUS:                /* subtraction                */
  735.      case BUTTON_IDIV:                 /* integer division           */
  736.      case BUTTON_REMAINDER:            /* remainder division         */
  737.      case BUTTON_POWER:                /* raise a number to power    */
  738.  
  739.        oldaction = newaction;          /* remember the new action    */
  740.                                        /* call the appropriate       */
  741.                                        /* Rexx operand processor     */
  742.        ProcessMacro(action - MIN_MACRO, &accumulator, &display, 
  743.            &accumulator, WM_OPERATOR_DONE);
  744.        break;
  745.  
  746.      default:
  747.  
  748.                                        /* copy display into accum    */
  749.        strcpy(accumulator.strptr, display.strptr);
  750.                                        /* copy the length also       */
  751.        accumulator.strlength = display.strlength;
  752.        display.strlength = 0;          /* clear out digits           */
  753.        digits = 0;                     /* no digits in display       */
  754.  
  755.        switch (newaction) {            /* now process the new key    */
  756.  
  757.                                        /* process function keys      */
  758.                                        /* immediately                */
  759.          case BUTTON_PROGRAM1:         /* program key one            */
  760.          case BUTTON_PROGRAM2:         /* program key two            */
  761.          case BUTTON_PROGRAM3:         /* program key three          */
  762.          case BUTTON_PROGRAM4:         /* program key four           */
  763.  
  764.            oldaction = 0;              /* cancel next action         */
  765.                                        /* call the appropriate       */
  766.                                        /* Rexx operand processor     */
  767.            SetDisplay(&accumulator);   /* update display             */
  768.            ProcessMacro(newaction - MIN_MACRO, &accumulator, &display, 
  769.                &accumulator, WM_PROGRAM_DONE);
  770.            break;
  771.  
  772.          default:                      /* all other operations       */
  773.            oldaction = newaction;      /* remember the new action    */
  774.        }
  775.        break;                          /* no more needed             */
  776.    }
  777. }
  778.  
  779. /*********************************************************************/
  780. /*                                                                   */
  781. /* ProcessProgram()  - Process a call to a programed Rexx function.  */
  782. /*                     The program is passed both the accumulator    */
  783. /*                     and the current display as strings.           */
  784. /*                                                                   */
  785. /*********************************************************************/
  786.  
  787. void ProcessProgram(
  788.   ULONG      macro_name,               /* macro to invoke            */
  789.   PRXSTRING  left,                     /* left operand               */
  790.   PRXSTRING  right,                    /* right operand              */
  791.   PRXSTRING  result )                  /* result location            */
  792. {
  793.   RXSTRING   args[2];                  /* passed argument strings    */
  794.   INT        argc;                     /* argument count             */
  795.   INT        rc;                       /* Rexx return code           */
  796.   SHORT      return_code;              /* function return code       */
  797.  
  798.  
  799.   args[0] = *left;                     /* set first argument         */
  800.   if (right) {                         /* two arguments provided?    */
  801.     args[1] = *right;                  /* copy RXSTRING              */
  802.     argc = 2;                          /* two arguments              */
  803.   }
  804.   else
  805.     argc = 1;                          /* only one argument          */
  806.  
  807.   rc = RexxStart(argc,                 /* two arguments              */
  808.                  args,                 /* array of arguments         */
  809.                                        /* name of the macro          */
  810.                  operator_names[macro_name],
  811.                                        /* instorage program          */
  812.                  (PRXSTRING)&operator_programs[macro_name],
  813.                  "Calculator",         /* default command address    */
  814.                  RXFUNCTION,           /* calling this a function    */
  815.                  NULL,
  816.                  &return_code,         /* numeric value of return str*/
  817.                  result);              /* returned string result     */
  818.    if (result)                         /* if result requested        */
  819.                                        /* make into an ASCII-Z string*/
  820.      result->strptr[result->strlength] = '\0';
  821. }
  822.  
  823. /*********************************************************************/
  824. /*                                                                   */
  825. /* ProcessMacro()    - Process a call to a programed Rexx function.  */
  826. /*                     The program is passed both the accumulator    */
  827. /*                     and the current display as strings and        */
  828. /*                     executed on a separate thread.                */
  829. /*                                                                   */
  830. /*********************************************************************/
  831.  
  832. void ProcessMacro(
  833.   ULONG      macro_name,               /* macro to invoke            */
  834.   PRXSTRING  left,                     /* left operand               */
  835.   PRXSTRING  right,                    /* right operand              */
  836.   PRXSTRING  result,                   /* result location            */
  837.   ULONG      completion )              /* completion message         */
  838. {
  839.   global_args[0] = *left;              /* set first argument         */
  840.   if (right) {                         /* two arguments provided?    */
  841.     global_args[1] = *right;           /* copy RXSTRING              */
  842.     global_argc = 2;                   /* two arguments              */
  843.   }
  844.   else
  845.     global_argc = 1;                   /* only one argument          */
  846.   global_macro_name = macro_name;      /* save macro name            */
  847.   global_result = result;              /* save result pointer        */
  848.   global_completion = completion;      /* save completion message    */
  849.   DosPostEventSem(calcsem);            /* kick off the thread        */
  850.  
  851. }
  852.  
  853. /*********************************************************************/
  854. /*                                                                   */
  855. /* Datatype()        - Call Rexx to validate a character string      */
  856. /*                                                                   */
  857. /*********************************************************************/
  858.  
  859. INT Datatype(
  860.   PSZ        string,                   /* string to validate         */
  861.   PSZ        operation )               /* datatype operation         */
  862. {
  863.   RXSTRING   args[2];                  /* passed argument strings    */
  864.   RXSTRING   result;                   /* returned result string     */
  865.   UCHAR      resbuf[10];               /* result buffer              */
  866.  
  867.  
  868.                                        /* set first argment          */
  869.   MAKERXSTRING(args[0], string, strlen(string));
  870.                                        /* and second argument        */
  871.   MAKERXSTRING(args[1], operation, strlen(operation));
  872.   result.strptr = resbuf;              /* point to return point      */
  873.   result.strlength = sizeof(resbuf);   /* set maximum size           */
  874.  
  875.                                        /* invoke the Rexx program    */
  876.                                        /* DATATYPE is last one in    */
  877.                                        /* the list                   */
  878.   ProcessProgram(MACRO_COUNT - 1, &args[0], &args[1], &result);
  879.  
  880.    if (resbuf[0] == '1')               /* whole number?              */
  881.      return YES;                       /* yes, this is good          */
  882.    else
  883.      return NO;                        /* nope, bad number           */
  884. }
  885.  
  886. /*********************************************************************/
  887. /*                                                                   */
  888. /* ReadSourceFile()  - Read Rexx program source off of disk.         */
  889. /*                                                                   */
  890. /*********************************************************************/
  891.  
  892. void ReadSourceFile(
  893.   PSZ        program,                  /* program to read            */
  894.   PINSTORE   descriptor )              /* saved location             */
  895. {
  896.   HFILE      handle;                   /* file handle                */
  897.   FILESTATUS status;                   /* queried file status        */
  898.   ULONG      size;                     /* program size               */
  899.   ULONG      action;                   /* DosOpen action             */
  900.   ULONG      bytes_read;               /* bytes read with DosRead    */
  901.  
  902.                                        /* zero out image holder      */
  903.   MAKERXSTRING(descriptor->image, NULL, 0);
  904.                                        /* open the file              */ 
  905.   DosOpen(program, &handle, &action, 0, 0, OPEN_ACTION_OPEN_IF_EXISTS,
  906.       OPEN_ACCESS_READONLY + OPEN_SHARE_DENYREADWRITE +
  907.       OPEN_FLAGS_FAIL_ON_ERROR + OPEN_FLAGS_WRITE_THROUGH,NULL);
  908.                                        /* retrieve the file size     */
  909.   DosQueryFileInfo(handle, 1, (PBYTE)&status, sizeof(FILESTATUS));
  910.   size = status.cbFile;                /* get the file size          */
  911.                                        /* allocate buffer for source */
  912.   descriptor->source.strptr = malloc(size);
  913.   descriptor->source.strlength = size; /* set the size               */
  914.                                        /* read in the program        */
  915.   DosRead(handle, descriptor->source.strptr, size, &bytes_read);
  916.   DosClose(handle);                    /* close the file             */
  917. }
  918.  
  919. /*********************************************************************/
  920. /*                                                                   */
  921. /* FreeSourceFile()  - Release storage for Rexx source program.      */
  922. /*                                                                   */
  923. /*********************************************************************/
  924.  
  925. void FreeSourceFile(
  926.   PINSTORE   descriptor )              /* saved location             */
  927. {
  928.   if (descriptor->source.strptr)       /* if have a source           */
  929.                                        /* release it                 */
  930.     free(descriptor->source.strptr);
  931.   if (descriptor->image.strptr)        /* if we have an image        */
  932.                                        /* release it also            */
  933.     DosFreeMem(descriptor->image.strptr);
  934.  
  935.                                        /* clear out both descriptors */
  936.   MAKERXSTRING(descriptor->source, NULL, 0);
  937.   MAKERXSTRING(descriptor->image, NULL, 0);
  938. }
  939.  
  940. /*********************************************************************/
  941. /*                                                                   */
  942. /* SetRexxVariable - Set the value of a Rexx variable                */
  943. /*                                                                   */
  944. /*********************************************************************/
  945.  
  946. INT SetRexxVariable(
  947.   PSZ        name,                     /* Rexx variable to set       */
  948.   PSZ        value )                   /* value to assign            */
  949. {
  950.   SHVBLOCK   block;                    /* variable pool control block*/
  951.  
  952.   block.shvcode = RXSHV_SYSET;         /* do a symbolic set operation*/
  953.   block.shvret=(UCHAR)0;               /* clear return code field    */
  954.   block.shvnext=(PSHVBLOCK)0;          /* no next block              */
  955.                                        /* set variable name string   */
  956.   MAKERXSTRING(block.shvname, name, strlen(name));
  957.                                        /* set value string           */
  958.   MAKERXSTRING(block.shvvalue, value, strlen(value));
  959.   block.shvnamelen=strlen(name);       /* set name length            */
  960.   block.shvvaluelen=strlen(value);     /* set value length           */
  961.   return RexxVariablePool(&block);     /* set the variable           */
  962. }
  963.  
  964. /*********************************************************************/
  965. /*                                                                   */
  966. /* CalcPrecision - External Rexx function for obtaining current      */
  967. /*                 calculator numeric precision                      */
  968. /*                                                                   */
  969. /*********************************************************************/
  970.  
  971.  
  972. LONG   EXPENTRY CalcPrecision(
  973.   PSZ        name,                     /* function name              */
  974.   LONG       argc,                     /* count of arguments         */
  975.   PRXSTRING  argv,                     /* argument RXSTRINGs         */
  976.   PSZ        queue,                    /* current Rexx queue         */
  977.   PRXSTRING  retstr )                  /* returned string value      */
  978. {
  979.   strcpy(RXSTRPTR(*retstr), (const char *)precision);/* copy over current precision*/
  980.                                        /* set new length             */
  981.   retstr->strlength = strlen((const char *)precision);
  982.   return 0;                            /* completed successfully     */
  983. }
  984.  
  985.  
  986. /*********************************************************************/
  987. /*                                                                   */
  988. /* CalcForm      - External Rexx function for obtaining current      */
  989. /*                 caculator numeric form                            */
  990. /*                                                                   */
  991. /*********************************************************************/
  992.  
  993. LONG   EXPENTRY CalcForm(
  994.   PSZ        name,                     /* function name              */
  995.   LONG       argc,                     /* count of arguments         */
  996.   PRXSTRING  argv,                     /* argument RXSTRINGs         */
  997.   PSZ        queue,                    /* current Rexx queue         */
  998.   PRXSTRING  retstr )                  /* returned string value      */
  999. {
  1000.   if (form == SCIENTIFIC) {            /* scientific precision?      */
  1001.                                        /* return that word           */
  1002.     strcpy(RXSTRPTR(*retstr), "SCIENTIFIC");
  1003.                                        /* set new length             */
  1004.     retstr->strlength = strlen("SCIENTIFIC");
  1005.   }
  1006.   else {                               /* engineering precision      */
  1007.                                        /* return that word           */
  1008.     strcpy(RXSTRPTR(*retstr), "ENGINEERING");
  1009.                                        /* set new length             */
  1010.     retstr->strlength = strlen("ENGINERRING");
  1011.   }
  1012.   return 0;                            /* completed successfully     */
  1013. }
  1014.  
  1015. /*********************************************************************/
  1016. /*                                                                   */
  1017. /* CalcCommand   - Subcommand handler for the calculator             */
  1018. /*                                                                   */
  1019. /*********************************************************************/
  1020.  
  1021.  
  1022. APIRET EXPENTRY CalcCommand(
  1023.   PRXSTRING    command,                /* command to issue           */
  1024.   PUSHORT      flags,                  /* error/failure flags        */
  1025.   PRXSTRING    retstr )                /* return code                */
  1026. {
  1027.   PSZ          scan;                   /* scan position              */
  1028.   INT          memory_number;          /* number of memory value     */
  1029.   PSZ          memory_item;            /* returned memory item       */
  1030.   RXSTRING     newdisplay;             /* new display value          */
  1031.  
  1032.                                        /* leading blanks             */
  1033.   scan = command->strptr + strspn(command->strptr, " ");
  1034.  
  1035.                                        /* set operation?             */
  1036.   if (!memicmp(scan, "SET ", strlen("SET "))) {
  1037.     scan += strlen("SET ");            /* step past command          */
  1038.     scan += strspn(scan, " ");         /* skip to next non-blank     */
  1039.     memory_number = atol(scan);        /* get memory number          */
  1040.     if (memory_number <= 0 ||          /* validate the value         */
  1041.         memory_number > NUMBER_MEMORIES) {
  1042.       *flags = RXSUBCOM_ERROR;         /* raise error condition      */
  1043.       strcpy(retstr->strptr, "2");     /* give return code of 2      */
  1044.       retstr->strlength = 1;           /* set proper length          */
  1045.       return 0;                        /* finished                   */
  1046.     }
  1047.     scan = strchr(scan, ' ');          /* step past number           */
  1048.     if (!scan) {                       /* no value?                  */
  1049.       *flags = RXSUBCOM_ERROR;         /* raise error condition      */
  1050.       strcpy(retstr->strptr, "3");     /* give return code of 3      */
  1051.       retstr->strlength = 1;           /* set proper length          */
  1052.       return 0;                        /* finished                   */
  1053.     }
  1054.     scan += strspn(scan, " ");         /* skip to next non-blank     */
  1055.     if (!Datatype(scan, "Number")) {   /* if not a valid number      */
  1056.       *flags = RXSUBCOM_ERROR;         /* raise error condition      */
  1057.       strcpy(retstr->strptr, "4");     /* give return code of 4      */
  1058.       retstr->strlength = 1;           /* set proper length          */
  1059.       return 0;                        /* finished                   */
  1060.     }
  1061.  
  1062.     if (memory_bank[memory_number])    /* have a value already?      */
  1063.       free(memory_bank[memory_number]);/* release the value          */
  1064.                                        /* set the new value          */
  1065.     memory_bank[memory_number] = strdup(scan);
  1066.   }
  1067.                                        /* get operation?             */
  1068.   else if (!memicmp(scan, "GET ", strlen("GET"))) {
  1069.     scan += strlen("GET ");            /* step past command          */
  1070.     scan += strspn(scan, " ");         /* skip to next non-blank     */
  1071.     memory_number = atol(scan);        /* get memory number          */
  1072.     if (memory_number <= 0 ||          /* validate the value         */
  1073.         memory_number > NUMBER_MEMORIES) {
  1074.       *flags = RXSUBCOM_ERROR;         /* raise error condition      */
  1075.       strcpy(retstr->strptr, "2");     /* give return code of 2      */
  1076.       retstr->strlength = 1;           /* set proper length          */
  1077.       return 0;                        /* finished                   */
  1078.     }
  1079.     scan = strchr(scan, ' ');          /* step past number           */
  1080.     if (!scan) {                       /* no value?                  */
  1081.       *flags = RXSUBCOM_ERROR;         /* raise error condition      */
  1082.       strcpy(retstr->strptr, "3");     /* give return code of 3      */
  1083.       retstr->strlength = 1;           /* set proper length          */
  1084.       return 0;                        /* finished                   */
  1085.     }
  1086.     scan += strspn(scan, " ");         /* skip to next non-blank     */
  1087.                                        /* get memory contents        */
  1088.     memory_item = memory_bank[memory_number];
  1089.     if (!memory_item)                  /* empty memory register?     */
  1090.       memory_item = "0";               /* just use a zero            */
  1091.                                        /* set the variable ok?       */
  1092.     if (SetRexxVariable(scan, memory_item) > RXSHV_NEWV) {
  1093.       *flags = RXSUBCOM_ERROR;         /* raise error condition      */
  1094.       strcpy(retstr->strptr, "5");     /* give return code of 5      */
  1095.       retstr->strlength = 1;           /* set proper length          */
  1096.       return 0;                        /* finished                   */
  1097.     }
  1098.   }
  1099.                                        /* get operation?             */
  1100.   else if (!memicmp(scan, "DISPLAY ", strlen("DISPLAY"))) {
  1101.     scan += strlen("DISPLAY");         /* step past command          */
  1102.     scan += strspn(scan, " ");         /* skip to next non-blank     */
  1103.                                        /* make an RXSTRING           */
  1104.     MAKERXSTRING(newdisplay, scan, strlen(scan));
  1105.     SetDisplay(&newdisplay);           /* set the new display        */
  1106.   }
  1107.   else {                               /* unknown command            */
  1108.     *flags = RXSUBCOM_FAILURE;         /* raise failure condition    */
  1109.     strcpy(retstr->strptr, "1");       /* give return code of 1      */
  1110.     retstr->strlength = 1;             /* set proper length          */
  1111.     return 0;                          /* finished                   */
  1112.   }
  1113.                                        /* successful completion      */
  1114.   strcpy(retstr->strptr, "0");         /* give return code of 0      */
  1115.   retstr->strlength = 1;               /* set proper length          */
  1116.   return 0;                            /* finished                   */
  1117. }
  1118.  
  1119.  
  1120. /*********************************************************************/
  1121. /*                                                                   */
  1122. /* EditThread    - Edit a macro bound to a key                       */
  1123. /*                                                                   */
  1124. /*********************************************************************/
  1125.  
  1126. void EditThread(void)
  1127. {
  1128.   RESULTCODES   returncodes;           /* result of EDITing          */
  1129.   UCHAR         loaderror[150];        /* object name buffer         */
  1130.   UCHAR         args[150];             /* argument string            */
  1131.   PSZ           argptr;                /* used to build arg string   */
  1132.  
  1133.   strcpy(args, "E");                   /* fill in command name       */
  1134.   argptr = args + sizeof("E");         /* step past name             */
  1135.                                        /* copy in file name          */
  1136.   strcpy(argptr, (const char *)operator_names[editted_program]);
  1137.                                        /* terminate arguments        */
  1138.   argptr[strlen((const char *)operator_names[editted_program]) + 1] = 0;
  1139.                                        /* invoke the system editor   */
  1140.   DosExecPgm(loaderror, sizeof(loaderror),
  1141.       EXEC_SYNC, args, NULL,
  1142.       &returncodes, "E.EXE");
  1143.                                        /* release existing source    */
  1144.   FreeSourceFile(&operator_programs[editted_program]);
  1145.                                        /* read in new source         */
  1146.   ReadSourceFile(operator_names[editted_program],
  1147.       &operator_programs[editted_program]);
  1148.  
  1149.   DosEnterCritSec();                   /* allow thread to complete   */
  1150.                                        /* send completion message    */
  1151.   WinPostMsg(hwndCalc, WM_EDIT_DONE, NULL, NULL);
  1152.   DosExit(EXIT_THREAD, 0);             /* end the thread             */
  1153. }
  1154.  
  1155. /*********************************************************************/
  1156. /*                                                                   */
  1157. /* CalcThread    - Execute a macro bound to a key                    */
  1158. /*                                                                   */
  1159. /*********************************************************************/
  1160.  
  1161.  
  1162. void CalcThread(void)
  1163. {
  1164.   LONG      rc;                        /* rexx return code           */
  1165.   SHORT     return_code;               /* numeric return code        */
  1166.   ULONG     postcount;                 /* semaphore post count       */
  1167.   RXSTRING  result;                    /* result rxstring            */
  1168.   PRXSTRING resultptr;                 /* passed result pointer      */
  1169.  
  1170.   while (TRUE) {                       /* Do Forever                 */
  1171.     DosWaitEventSem(calcsem, -1);      /* wait for work to do        */
  1172.     DosResetEventSem(calcsem,          /* clear posted event         */
  1173.         &postcount);
  1174.     if (global_result) {               /* if result needed           */
  1175.       result = *global_result;         /* make temp copy             */
  1176.       result.strlength = DISPLAY_WIDTH;/* set result size            */
  1177.       resultptr = &result;             /* set result pointer         */
  1178.     }
  1179.     else
  1180.       resultptr = NULL;                /* no result                  */
  1181.  
  1182.     rc = RexxStart(global_argc,        /* two arguments              */
  1183.                    global_args,        /* array of arguments         */
  1184.                                        /* name of the macro          */
  1185.                    operator_names[global_macro_name],
  1186.                                        /* instorage program          */
  1187.                    (PRXSTRING)&operator_programs[global_macro_name],
  1188.                    "Calculator",       /* default command address    */
  1189.                    RXFUNCTION,         /* calling this a function    */
  1190.                    NULL,
  1191.                    &return_code,       /* numeric value of return str*/
  1192.                    resultptr);         /* returned string result     */
  1193.     if (global_result) {               /* if result requested        */
  1194.                                        /* make into an ASCII-Z string*/
  1195.       global_result->strptr[result.strlength] = '\0';
  1196.                                        /* set returned length        */
  1197.       global_result->strlength = result.strlength;
  1198.     }
  1199.                                        /* signal completion          */
  1200.     WinPostMsg(hwndCalc, global_completion, NULL, NULL);
  1201.   }
  1202.   DosExit(EXIT_THREAD, 0);             /* end the thread                      */
  1203. }
  1204.