home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / VSCPPv8.zip / VACPP / IBMCPP / samples / TOOLKIT / CREXX / REXXCALC / REXXCALC.C < prev    next >
C/C++ Source or Header  |  1994-11-17  |  69KB  |  1,285 lines

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