home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / RXCALC.ZIP / REXXCAL6.C < prev    next >
C/C++ Source or Header  |  1992-02-17  |  68KB  |  1,274 lines

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