/****h* MyCalc/MyCalc.c [1.0] ****************************************
*
* NAME
*    MyCalc.c
*
* DESCRIPTION
*    A Commoditized Calculator for programmers.
*
* NOTES
*    ToolTypes are as follows:
*        TEMPFILE    = "T:CalcTemp"  (Default) 
*        HELPFILE    = "Help:english/MyCalc.guide" (Default)
*        HOTKEY      = rawkey alt c  (Default)
*        CX_PRIORITY = 0             (Default)
*        DONOTWAIT
*
*    Source machine generated by GadToolsBox V2.0b
*    which is (c) Copyright 1991-1993 Jaba Development
*
*    GUI Designed by : Jim Steichen
*
*    $VER: MyCalc.c 1.0 (04-May-2002) by J.T. Steichen
**********************************************************************
*
*/

#include <stdio.h>
#include <string.h>

#include <exec/types.h>

#include <AmigaDOSErrs.h>

#include <intuition/intuition.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/gadgetclass.h>

#include <devices/inputevent.h> // For RawKey stuff (NOT working!!).

#include <libraries/commodities.h>
#include <libraries/gadtools.h>

#include <graphics/displayinfo.h>
#include <graphics/gfxbase.h>

#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <workbench/icon.h>

#include <clib/commodities_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>

#include "CPGM:GlobalObjects/CommonFuncs.h"

#define   ALLOCATE   // Added for V1.8 
# include <Author.h> // My name & EMail address.
#undef    ALLOCATE 

#define StrBfPtr( g ) (((struct StringInfo *) g->SpecialInfo)->Buffer)

#define ExprStr      0
#define DecTxt       1
#define HexTxt       2
#define Mem1Txt      3
#define Mem2Txt      4
#define Mem3Txt      5

#define Key0         6
#define Key1         7
#define Key2         8
#define Key3         9
#define Key4         10
#define Key5         11
#define Key6         12
#define Key7         13
#define Key8         14
#define Key9         15
#define KeyA         16
#define KeyB         17
#define KeyC         18
#define KeyD         19
#define KeyE         20
#define KeyF         21
#define KeyPlus      22
#define KeyMinus     23
#define KeyStar      24
#define KeySlash     25
#define KeyLParen    26
#define KeyRParen    27
#define KeyPeriod    28
#define KeyAND       29
#define KeyOR        30
#define KeyNOT       31
#define KeyXOR       32
#define KeyLShift    33
#define KeyRShift    34
#define KeyModulo    35
#define KeyEqual     36
#define KeyAllClear  37
#define KeyMemClear  38
#define Mem1In       39
#define Mem2In       40
#define Mem3In       41
#define Mem1Recall   42
#define Mem2Recall   43
#define Mem3Recall   44
#define KeyDollar    45
#define HelpKey      46

#define PC_CNT       47

#define ExprGadget   PCGadgets[ ExprStr ]
#define EXPRESSION   StrBfPtr( ExprGadget )

#define MEM1Gadget   PCGadgets[ Mem1Txt ]
#define MEM2Gadget   PCGadgets[ Mem2Txt ]
#define MEM3Gadget   PCGadgets[ Mem3Txt ]

#define DecGadget    PCGadgets[ DecTxt ]
#define HexGadget    PCGadgets[ HexTxt ]

#define HEXRESULT    StrBfPtr( HexGadget )

#define EXPRSIZE     256

// -----------------------------------------------------------------

IMPORT struct WBStartup *_WBenchMsg;

// -----------------------------------------------------------------

struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
struct Library       *GadToolsBase;
struct Library       *IconBase = NULL;
struct Library       *CxBase   = NULL;

PRIVATE char v[] = "\0$VER: 1.0 " __AMIGADATE__ " by J.T. Steichen\0";

PRIVATE char ErrMsg[256]     = "";
PRIVATE char ProgramName[80] = ""; // In case the User renames us.
PRIVATE char lastResult[64]  = ""; // Temporary storage for HexaDecimal Text Gadget.
PRIVATE char memory[3 * 64]  = ""; // Temporary storage for the memory Text Gadgets.

PRIVATE struct Screen *Scr     = NULL;
PRIVATE struct Window *PCWnd   = NULL;
PRIVATE struct Gadget *PCGList = NULL;
PRIVATE struct Gadget *PCGadgets[ PC_CNT ] = { 0, };

PRIVATE UBYTE  *PubScreenName = "Workbench";
PRIVATE APTR    VisualInfo    = NULL;

PRIVATE struct IntuiMessage  PCMsg;

PRIVATE UWORD  PCLeft   = 168;
PRIVATE UWORD  PCTop    = 18;
PRIVATE UWORD  PCWidth  = 470;
PRIVATE UWORD  PCHeight = 350;
PRIVATE UBYTE *PCWdt    = "Programmer's Calculator ©2002 by J.T. Steichen";

// Replace later with a ToolType???:

PRIVATE struct TextAttr topaz11 = { "topaz.font", 11, 0x00, 0x62 };

PRIVATE UWORD PCGTypes[] = {

   STRING_KIND, TEXT_KIND,   TEXT_KIND,   TEXT_KIND,   TEXT_KIND,   TEXT_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND,
   BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND, BUTTON_KIND
};

PRIVATE int ExprStrClicked(     void );
PRIVATE int Key0Clicked(        void );
PRIVATE int Key1Clicked(        void );
PRIVATE int Key2Clicked(        void );
PRIVATE int Key3Clicked(        void );
PRIVATE int Key4Clicked(        void );
PRIVATE int Key5Clicked(        void );
PRIVATE int Key6Clicked(        void );
PRIVATE int Key7Clicked(        void );
PRIVATE int Key8Clicked(        void );
PRIVATE int Key9Clicked(        void );
PRIVATE int KeyAClicked(        void );
PRIVATE int KeyBClicked(        void );
PRIVATE int KeyCClicked(        void );
PRIVATE int KeyDClicked(        void );
PRIVATE int KeyEClicked(        void );
PRIVATE int KeyFClicked(        void );
PRIVATE int KeyPlusClicked(     void );
PRIVATE int KeyMinusClicked(    void );
PRIVATE int KeyStarClicked(     void );
PRIVATE int KeySlashClicked(    void );
PRIVATE int KeyLParenClicked(   void );
PRIVATE int KeyRParenClicked(   void );
PRIVATE int KeyPeriodClicked(   void );
PRIVATE int KeyDollarClicked(   void );
PRIVATE int KeyANDClicked(      void );
PRIVATE int KeyORClicked(       void );
PRIVATE int KeyNOTClicked(      void );
PRIVATE int KeyXORClicked(      void );
PRIVATE int KeyLShiftClicked(   void );
PRIVATE int KeyRShiftClicked(   void );
PRIVATE int KeyModuloClicked(   void );
PRIVATE int KeyEqualClicked(    void );
PRIVATE int KeyAllClearClicked( void );
PRIVATE int KeyMemClearClicked( void );
PRIVATE int Mem1InClicked(      void );
PRIVATE int Mem2InClicked(      void );
PRIVATE int Mem3InClicked(      void );
PRIVATE int Mem1RecallClicked(  void );
PRIVATE int Mem2RecallClicked(  void );
PRIVATE int Mem3RecallClicked(  void );
PRIVATE int HelpKeyClicked(     void );

PRIVATE struct NewGadget PCNGad[] = {

     7,   6, 430, 21, NULL, NULL, ExprStr, 0, NULL, (APTR) ExprStrClicked,

    40, 206, 171, 21, "Result (Decimal): ", NULL, DecTxt, PLACETEXT_ABOVE, NULL, NULL,
    40, 259, 171, 21,     "Result (Hex): ", NULL, HexTxt, PLACETEXT_ABOVE, NULL, NULL,

   258, 206, 200, 21, "Mem 1:", NULL, Mem1Txt, PLACETEXT_ABOVE, NULL, NULL,
   258, 259, 200, 21, "Mem 2:", NULL, Mem2Txt, PLACETEXT_ABOVE, NULL, NULL,
   258, 312, 200, 21, "Mem 3:", NULL, Mem3Txt, PLACETEXT_ABOVE, NULL, NULL,

     9,  36, 20, 21, "_0", NULL, Key0, PLACETEXT_IN, NULL, (APTR) Key0Clicked,
    37,  36, 20, 21, "_1", NULL, Key1, PLACETEXT_IN, NULL, (APTR) Key1Clicked,
    66,  36, 20, 21, "_2", NULL, Key2, PLACETEXT_IN, NULL, (APTR) Key2Clicked,
    94,  36, 20, 21, "_3", NULL, Key3, PLACETEXT_IN, NULL, (APTR) Key3Clicked,

     9,  65, 20, 21, "_4", NULL, Key4, PLACETEXT_IN, NULL, (APTR) Key4Clicked,
    37,  65, 20, 21, "_5", NULL, Key5, PLACETEXT_IN, NULL, (APTR) Key5Clicked,
    66,  65, 20, 21, "_6", NULL, Key6, PLACETEXT_IN, NULL, (APTR) Key6Clicked,
    94,  65, 20, 21, "_7", NULL, Key7, PLACETEXT_IN, NULL, (APTR) Key7Clicked,

     9,  95, 20, 21, "_8", NULL, Key8, PLACETEXT_IN, NULL, (APTR) Key8Clicked,
    37,  95, 20, 21, "_9", NULL, Key9, PLACETEXT_IN, NULL, (APTR) Key9Clicked,
    66,  95, 20, 21, "_A", NULL, KeyA, PLACETEXT_IN, NULL, (APTR) KeyAClicked,
    94,  95, 20, 21, "_B", NULL, KeyB, PLACETEXT_IN, NULL, (APTR) KeyBClicked,

     9, 126, 20, 21, "_C", NULL, KeyC, PLACETEXT_IN, NULL, (APTR) KeyCClicked,
    37, 126, 20, 21, "_D", NULL, KeyD, PLACETEXT_IN, NULL, (APTR) KeyDClicked,
    66, 126, 20, 21, "_E", NULL, KeyE, PLACETEXT_IN, NULL, (APTR) KeyEClicked,
    94, 126, 20, 21, "_F", NULL, KeyF, PLACETEXT_IN, NULL, (APTR) KeyFClicked,

     9, 157, 20, 21, "_+", NULL, KeyPlus,   PLACETEXT_IN, NULL, (APTR) KeyPlusClicked,
    37, 157, 20, 21, "_-", NULL, KeyMinus,  PLACETEXT_IN, NULL, (APTR) KeyMinusClicked,
    66, 157, 20, 21, "_*", NULL, KeyStar,   PLACETEXT_IN, NULL, (APTR) KeyStarClicked,
    94, 157, 20, 21, "_/", NULL, KeySlash,  PLACETEXT_IN, NULL, (APTR) KeySlashClicked,
   122, 157, 20, 21, "_(", NULL, KeyLParen, PLACETEXT_IN, NULL, (APTR) KeyLParenClicked,
   150, 157, 20, 21, "_)", NULL, KeyRParen, PLACETEXT_IN, NULL, (APTR) KeyRParenClicked,
   178, 157, 20, 21, "_.", NULL, KeyPeriod, PLACETEXT_IN, NULL, (APTR) KeyPeriodClicked,
   206, 157, 20, 21, "_$", NULL, KeyDollar, PLACETEXT_IN, NULL, (APTR) KeyDollarClicked,

   124,  36, 69, 21, "AND _&", NULL, KeyAND, PLACETEXT_IN, NULL, (APTR) KeyANDClicked,
   124,  65, 69, 21, "OR _|",  NULL, KeyOR,  PLACETEXT_IN, NULL, (APTR) KeyORClicked,
   124,  95, 69, 21, "NOT _~", NULL, KeyNOT, PLACETEXT_IN, NULL, (APTR) KeyNOTClicked,
   124, 126, 69, 21, "XOR _^", NULL, KeyXOR, PLACETEXT_IN, NULL, (APTR) KeyXORClicked,

   212,  36, 94, 21, "_L SHIFT", NULL, KeyLShift, PLACETEXT_IN, NULL, (APTR) KeyLShiftClicked,
   212,  65, 94, 21, "_R SHIFT", NULL, KeyRShift, PLACETEXT_IN, NULL, (APTR) KeyRShiftClicked,
   212,  95, 94, 21, "_MODULO",  NULL, KeyModulo, PLACETEXT_IN, NULL, (APTR) KeyModuloClicked,
   212, 126, 94, 21, "EVAL _=",  NULL, KeyEqual,  PLACETEXT_IN, NULL, (APTR) KeyEqualClicked,

   331, 126,  94, 21, "_Help!",    NULL, HelpKey,     PLACETEXT_IN, NULL, (APTR) HelpKeyClicked,
   331,  36, 107, 21, "ALL CLEAR", NULL, KeyAllClear, PLACETEXT_IN, NULL, (APTR) KeyAllClearClicked,
   331,  65, 107, 21, "MEM CLEAR", NULL, KeyMemClear, PLACETEXT_IN, NULL, (APTR) KeyMemClearClicked,

   258, 182, 51, 21, "M in", NULL, Mem1In, PLACETEXT_IN, NULL, (APTR) Mem1InClicked,
   258, 235, 51, 21, "M in", NULL, Mem2In, PLACETEXT_IN, NULL, (APTR) Mem2InClicked,
   258, 288, 51, 21, "M in", NULL, Mem3In, PLACETEXT_IN, NULL, (APTR) Mem3InClicked,

   389, 182, 70, 21, "M out", NULL, Mem1Recall, PLACETEXT_IN, NULL, (APTR) Mem1RecallClicked,
   389, 235, 70, 21, "M out", NULL, Mem2Recall, PLACETEXT_IN, NULL, (APTR) Mem2RecallClicked,
   389, 288, 70, 21, "M out", NULL, Mem3Recall, PLACETEXT_IN, NULL, (APTR) Mem3RecallClicked,

};

PRIVATE ULONG PCGTags[] = {

   GTST_MaxChars, EXPRSIZE, STRINGA_Justification, GACT_STRINGCENTER, TAG_DONE,

   GTTX_Border, TRUE, TAG_DONE,
   GTTX_Border, TRUE, TAG_DONE,
   GTTX_Border, TRUE, TAG_DONE,
   GTTX_Border, TRUE, TAG_DONE,
   GTTX_Border, TRUE, TAG_DONE,

   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,
   GT_Underscore, '_', TAG_DONE,   GT_Underscore, '_', TAG_DONE,   
   GT_Underscore, '_', TAG_DONE
};

// TTTTTTTTT ToolTypes: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

PRIVATE char TempFile[]         = "TEMPFILE";
PRIVATE char HelpFile[]         = "HELPFILE";
PRIVATE char HotKey[]           = "HOTKEY";
PRIVATE char CXPriority[]       = "CX_PRIORITY";
PRIVATE char DoNotWait[]        = "DONOTWAIT";

PRIVATE char DefTempFile[128]   = "T:CalcTemp";
PRIVATE char DefHelpFile[128]   = "Help:english/MyCalc.guide";
PRIVATE char DefHotKey[80]      = "rawkey alt c";

PUBLIC  char *TTTempFile        = &DefTempFile[0]; // Visible to Calc.y

PRIVATE char *TTHotKey          = &DefHotKey[0];
PRIVATE char *TTHelpFile        = &DefHelpFile[0];

PRIVATE int   DefCXPriority     = 0;
PRIVATE int   TTCXPriority      = 0;

// TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT

PRIVATE char               **ToolPntr = NULL;
PRIVATE struct WBArg        *WB_Args  = NULL;
PRIVATE struct DiskObject   *DiskObj  = NULL;

// CCCCCCCCCCCCCCC COMMODITIES STUFF: CCCCCCCCCCCCCCCCCCCCCCCCCCCCC

#define EVT_HOTKEY 1L

PRIVATE struct MsgPort *broker_mp = NULL;

PRIVATE CxObj *broker    = NULL;
PRIVATE CxObj *filter    = NULL;
PRIVATE CxObj *sender    = NULL;
PRIVATE CxObj *translate = NULL;

PRIVATE struct NewBroker newbroker = {

   NB_VERSION,
   "ProgrammersCalculator",
   "Programmer's Calculator",
   "Perform HexaDecimal Calculations.",

   NBU_UNIQUE | NBU_NOTIFY, // No duplicates & send CXM_UNIQUE.
   0, 0,                    // Priority
   0, 0 
};

PRIVATE ULONG CXSignal     = 0L;
PRIVATE ULONG WindowSignal = 0L;
PRIVATE ULONG AllSignals   = 0L;

// ---------------------------------------------------------------------

PRIVATE BOOL UnlockFlag = FALSE;

PRIVATE int SetupScreen( void )
{
   struct Screen *chk = GetActiveScreen();
   
   if ((Scr = LockPubScreen( PubScreenName )) == NULL)
      return( -1 );

   if (chk != Scr)
      {
      UnlockPubScreen( NULL, Scr );
      Scr        = chk;
      UnlockFlag = FALSE;      
      }
   else
      UnlockFlag = TRUE;
   
   if ((VisualInfo = GetVisualInfo( Scr, TAG_DONE )) == NULL)
      return( -2 );

   return( 0 );
}

PRIVATE void CloseDownScreen( void )
{
   if (VisualInfo != NULL) 
      {
      FreeVisualInfo( VisualInfo );
      VisualInfo = NULL;
      }

   if ((UnlockFlag == TRUE) && (Scr != NULL))
      {
      UnlockPubScreen( NULL, Scr );
      Scr = NULL;
      }

   return;
}

PRIVATE void ClosePCWindow( void )
{
   AllSignals   &= ~WindowSignal;
   WindowSignal  = 0L;
   
   if (PCWnd != NULL) 
      {
      CloseWindow( PCWnd );
      PCWnd = NULL;
      }

   if (PCGList != NULL) 
      {
      FreeGadgets( PCGList );
      PCGList = NULL;
      }
      
   return;
}

PRIVATE int OpenPCWindow( void )
{
   struct Screen    *chk;
   struct NewGadget  ng;
   struct Gadget    *g;
   UWORD             lc, tc;
   UWORD             offx = Scr->WBorLeft;
   UWORD             offy = Scr->WBorTop + Scr->RastPort.TxHeight + 1;
   UWORD             wleft, wtop;

   chk = GetActiveScreen();

   if (Scr != chk)
      {
      if (UnlockFlag == TRUE)
         {
         UnlockPubScreen( NULL, Scr );
         
         UnlockFlag = FALSE;
         }

      Scr = chk;
      }

   // Center on the Screen:   

   wleft = (Scr->Width  -           PCWidth) / 2;
   wtop  = (Scr->Height - (PCHeight + offy)) / 2;

   // Initialize Gadgets: ----------------------------------------------

   if ((g = CreateContext( &PCGList )) == NULL)
      return( -1 );

   for (lc = 0, tc = 0; lc < PC_CNT; lc++) 
      {
      CopyMem( (char *) &PCNGad[ lc ], (char *) &ng, 
               (long) sizeof( struct NewGadget )
             );

      ng.ng_VisualInfo = VisualInfo;
      ng.ng_TextAttr   = &topaz11;
      ng.ng_LeftEdge  += offx;
      ng.ng_TopEdge   += offy;

      PCGadgets[ lc ] = g 
                      = CreateGadgetA( (ULONG) PCGTypes[ lc ], 
                                       g, 
                                       &ng, 
                                       (struct TagItem *) &PCGTags[ tc ] 
                                     );

      while (PCGTags[ tc ] != TAG_DONE)
         tc += 2;
      
      tc++;

      if (g == NULL)
         return( -2 );
      }

   // Open Window (GUI): -----------------------------------------------
   
   if ((PCWnd = OpenWindowTags( NULL,

            WA_Left,        wleft,
            WA_Top,         wtop,
            WA_Width,       PCWidth,
            WA_Height,      PCHeight + offy,

            WA_IDCMP,       STRINGIDCMP | TEXTIDCMP | BUTTONIDCMP | IDCMP_MENUPICK 
              | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY
              | IDCMP_REFRESHWINDOW, // | IDCMP_RAWKEY,

            WA_Flags,       WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET
              | WFLG_SMART_REFRESH | WFLG_ACTIVATE | WFLG_RMBTRAP,

            WA_Gadgets,     PCGList,
            WA_Title,       PCWdt,
            WA_ScreenTitle, "Programmer's Calculator:",

            TAG_DONE )
      
      ) == NULL)
      return( -4 );

   GT_RefreshWindow( PCWnd, NULL );

   // Without these, the program will simply hang!!

   WindowSignal  = 1 << PCWnd->UserPort->mp_SigBit;
   AllSignals   |= WindowSignal;

   return( 0 );
}

// ----------------------------------------------------------------------

PRIVATE int PCCloseWindow( void )
{
   ClosePCWindow();

   return( FALSE );
}

PRIVATE void ExprLimitExceeded( void )
{
   // UserInfo() in GlobalObjects/CommonFuncs.o: 

   UserInfo( "Expression length is limited to 256 characters!", 
             "Expression Limit EXCEEDED:" 
           );

   return;
}

PRIVATE BOOL ExprOkay = TRUE;

PRIVATE int EvaluateExpr( char *expr )
{
   IMPORT int Calculate( char *expr );

   char result[64] = "";   
   int  i, len, rval = 0;

   ExprOkay = TRUE; // Assume all is okay until proven otherwise.
   
   len = strlen( expr );
   i   = 0;

   // Check for invalid characters in string first:

   while (i < len)
      {
      switch (*(expr + i))
         {
         case '0': case '1': case '2': case '3': case '4': 
         case '5': case '6': case '7': case '8': case '9':

         case 'A': case 'B': case 'C': 
         case 'D': case 'E': case 'F':
         case 'a': case 'b': case 'c': 
         case 'd': case 'e': case 'f':

         case '~': case '%': case '^':
         case '&': case '*': case '(':
         case ')': case '-': case '=':
         case '+': case '|': case '/':
         case '.': case ' ': case '<':
         case '>': case '$':
            break;
                     
         default:
            ExprOkay = FALSE; // Disallowed junk in String.
         }

      i++;
      }

   if (ExprOkay == FALSE) // Keep the parser happy.
      {
      UserInfo( "Invalid character in Expression String!", "User ERROR:" );

      return( TRUE );
      }
      
   // Now, place the string in a file & call the Parser (in Calc.y):

   rval = Calculate( expr );

   // Finally, display the results:

   (void) stcl_d( result, rval );     // SAS-C function
   
   GT_SetGadgetAttrs( DecGadget, PCWnd, NULL, GTTX_Text, result, TAG_DONE );

   strcpy( result, "$" );
   
   (void) stcl_h( &result[1], rval ); // SAS-C function

   strcpy( lastResult, result );

   GT_SetGadgetAttrs( HexGadget, PCWnd, NULL, GTTX_Text, result, TAG_DONE );
              
   return( TRUE );
}

PRIVATE int ExprStrClicked( void )       // for the <RETURN> key in String Gadget
{
   return( EvaluateExpr( EXPRESSION ) );
}

PRIVATE int Key0Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "0" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key1Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "1" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key2Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "2" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key3Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "3" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key4Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "4" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key5Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "5" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key6Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "6" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key7Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "7" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key8Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "8" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int Key9Clicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "9" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyAClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "A" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyBClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "B" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyCClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "C" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyDClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "D" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyEClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "E" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyFClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "F" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyPlusClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "+ " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyMinusClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "- " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyStarClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "* " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeySlashClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "/ " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyLParenClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "(" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyRParenClicked( void )
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, ")" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyPeriodClicked( void ) // Not currently used.
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "." );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyDollarClicked( void ) // Indicates a HexaDecimal integer.
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "$" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyANDClicked( void ) // Logical AND some bits.
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "& " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyORClicked( void )  // Logical OR some bits.
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "| " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyNOTClicked( void ) // Invert (Logical) some bits.
{
   int len = strlen( EXPRESSION );
   
   if (len < EXPRSIZE)
      {
      strcat( EXPRESSION, "~" );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyXORClicked( void ) // Logical XOR some bits.
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "^ " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyLShiftClicked( void ) // Shift some bits to the left.
{
   int len = strlen( EXPRESSION );
   
   if ((len + 2) < EXPRSIZE)
      {
      strcat( EXPRESSION, "<< " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyRShiftClicked( void ) // Shift some bits to the right.
{
   int len = strlen( EXPRESSION );
   
   if ((len + 2) < EXPRSIZE)
      {
      strcat( EXPRESSION, ">> " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyModuloClicked( void ) // Return the remainder of a division
{
   int len = strlen( EXPRESSION );
   
   if ((len + 1) < EXPRSIZE)
      {
      strcat( EXPRESSION, "% " );

      GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, EXPRESSION, TAG_DONE );
      }
   else
      ExprLimitExceeded();
      
   return( TRUE );
}

PRIVATE int KeyEqualClicked( void ) // For the '=' key (or Eval Gadget)
{
   return( EvaluateExpr( EXPRESSION ) );
}

PRIVATE int KeyMemClearClicked( void ) // User pressed the Memory Clear key
{
   strcpy( memory,       "$0" );
   strcpy( &memory[64],  "$0" );
   strcpy( &memory[128], "$0" );
 
   GT_SetGadgetAttrs( MEM1Gadget, PCWnd, NULL, GTTX_Text, "$0", TAG_DONE );
   GT_SetGadgetAttrs( MEM2Gadget, PCWnd, NULL, GTTX_Text, "$0", TAG_DONE );
   GT_SetGadgetAttrs( MEM3Gadget, PCWnd, NULL, GTTX_Text, "$0", TAG_DONE );

   return( TRUE );
}


PRIVATE int KeyAllClearClicked( void ) // User pressed the All Clear key
{
   GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, GTST_String, "", TAG_DONE );

   GT_SetGadgetAttrs( DecGadget, PCWnd, NULL, GTTX_Text, "0", TAG_DONE );

   strcpy( lastResult, "$0" );

   GT_SetGadgetAttrs( HexGadget, PCWnd, NULL, GTTX_Text, "$0", TAG_DONE );
   
   return( KeyMemClearClicked() );   
}

PRIVATE int Mem1InClicked( void ) // Store the last result in memory #1
{
   strcpy( memory, lastResult );

   GT_SetGadgetAttrs( MEM1Gadget, PCWnd, NULL,
                      GTTX_Text, lastResult, TAG_DONE 
                    );
   return( TRUE );
}

PRIVATE int Mem2InClicked( void ) // Store the last result in memory #2
{
   strcpy( &memory[64], lastResult );
   
   GT_SetGadgetAttrs( MEM2Gadget, PCWnd, NULL,
                      GTTX_Text, lastResult, TAG_DONE 
                    );
   return( TRUE );
}

PRIVATE int Mem3InClicked( void ) // Store the last result in memory #3
{
   strcpy( &memory[128], lastResult );

   GT_SetGadgetAttrs( MEM3Gadget, PCWnd, NULL,
                      GTTX_Text, lastResult, TAG_DONE 
                    );
   return( TRUE );
}

PRIVATE int Mem1RecallClicked( void ) // Recall memory #1 into the Expr String Gadget
{
   GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL,
                      GTST_String, memory, TAG_DONE 
                    );
   return( TRUE );
}

PRIVATE int Mem2RecallClicked( void ) // Recall memory #2 into the Expr String Gadget
{
   GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL,
                      GTST_String, &memory[64], TAG_DONE 
                    );
   return( TRUE );
}

PRIVATE int Mem3RecallClicked( void ) // Recall memory #3 into the Expr String Gadget
{
   GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL,
                      GTST_String, &memory[128], TAG_DONE 
                    );
   return( TRUE );
}

/****i* PCInfo() ***************************************************
*
* NAME
*    PCInfo()
*
* DESCRIPTION
*    Show the user some info on the program.
********************************************************************
*
*/

PRIVATE int PCInfo( char *pgmName )
{
   char ttl[80];
   
   sprintf( ttl, "%s Info:", pgmName );

   sprintf( ErrMsg, "This GUI allows the programmer to perform some\n"
                    "simple calculations on decimal/hexadecimal numbers.\n\n"
                    "My e-mail address: %s", &authorEMail[0] 
          );
   
   UserInfo( ErrMsg, ttl );

   return( (int) TRUE );
}

PRIVATE int HelpKeyClicked( void )
{
   sprintf( ErrMsg, "Multiview %s", TTHelpFile );
   
   if (System( ErrMsg, TAG_DONE ) < 0)
      {
      sprintf( ErrMsg, "System either could NOT find Multiview or %s.\n", TTHelpFile );

      UserInfo( ErrMsg, "Did you install the Help file??" );
      }
      
   return( TRUE );
}

PRIVATE int PCVanillaKey( int whichKey ) // Process key presses.
{
   int rval = TRUE;
   
   switch (whichKey)
      {
      case 'i':
      case 'I':
         rval = PCInfo( ProgramName );
         break;
         
      case 'h':
      case 'H':
      case '?':
         rval = HelpKeyClicked();
         break;
         
      case '\n': // #*&%$&!! RawKeys!!
         rval = ExprStrClicked();
         break;

      case '$':  // Differentiate HexaDecimal numbers from base 10. 
         rval = KeyDollarClicked();
         break;
         
      case 'q':
      case 'Q':
         rval = FALSE;
         break;
          
      case '0': 
         rval = Key0Clicked();
         break;
         
      case '1': 
         rval = Key1Clicked();
         break;
         
      case '2': 
         rval = Key2Clicked();
         break;
         
      case '3': 
         rval = Key3Clicked();
         break;
         
      case '4': 
         rval = Key4Clicked();
         break;
         
      case '5':
         rval = Key5Clicked();
         break;
         
      case '6':
         rval = Key6Clicked();
         break;
         
      case '7': 
         rval = Key7Clicked();
         break;
         
      case '8': 
         rval = Key8Clicked();
         break;
         
      case '9':
         rval = Key9Clicked();
         break;
         
      case 'A': 
      case 'a':
         rval = KeyAClicked();
         break;
               
      case 'B': 
      case 'b':
         rval = KeyBClicked();
         break;
                
      case 'C': 
      case 'c':
         rval = KeyCClicked();
         break;
                
      case 'D': 
      case 'd':
         rval = KeyDClicked();
         break;
                
      case 'E':
      case 'e': 
         rval = KeyEClicked();
         break;
               
      case 'F': 
      case 'f':
         rval = KeyFClicked();
         break;
         
      case '~': 
         rval = KeyNOTClicked();
         break;
         
      case 'm':
      case 'M':
      case '%':
         rval = KeyModuloClicked();
         break;
         
      case '^':
         rval = KeyXORClicked();
         break;
         
      case '&': 
         rval = KeyANDClicked();
         break;
         
      case '+': 
         rval = KeyPlusClicked();
         break;
         
      case '*': 
         rval = KeyStarClicked();
         break;
         
      case '(':
         rval = KeyLParenClicked();
         break;
         
      case ')': 
         rval = KeyRParenClicked();
         break;
         
      case '-': 
         rval = KeyMinusClicked();
         break;
         
      case '=':
         rval = KeyEqualClicked();
         break;
         
      case '|': 
         rval = KeyORClicked();
         break;
         
      case '/':
         rval = KeySlashClicked();
         break;
         
      case '.':
         rval = KeyPeriodClicked(); // Not currently used.
         break;
         
      case ' ': // SpaceBar
         {
         int len = strlen( EXPRESSION );
   
         if (len < EXPRSIZE)
            {
            strcat( EXPRESSION, " " );
 
            GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, 
                               GTST_String, EXPRESSION, TAG_DONE 
                             );
            }
         else
            ExprLimitExceeded();
         }

         break;

      case 'l':
      case 'L':
      case '<':
         rval = KeyLShiftClicked();
         break;
         
      case 'r':
      case 'R':
      case '>':
         rval = KeyRShiftClicked();
         break;
      }
      
   return( rval );
}

/*
PRIVATE int PCRawKey( int whichKey, int qual )
{
   int rval = TRUE;

   if (qual & IEQUALIFIER_NUMERICPAD != 0)
      {
      if (whichKey == 0x43)
         {
         rval = ExprStrClicked();
         }
      }
   else if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT) != 0)
      {
      switch (whichKey)
         {
         case 0x44: // '\n':
            rval = ExprStrClicked();
            break;
   
         case 0: // '~': 
            rval = KeyNOTClicked();
            break;
            
         case 4: // '$': 
            rval = KeyDollarClicked();
            break;
            
         case 6: // '^':
            rval = KeyXORClicked();
            break;
            
         case 7: // '&': 
            rval = KeyANDClicked();
            break;
            
         case 0x0C: // '+': 
            rval = KeyPlusClicked();
            break;
            
         case 8: // '*': 
            rval = KeyStarClicked();
            break;
            
         case 9: // '(':
            rval = KeyLParenClicked();
            break;
            
         case 0x0A: // ')': 
            rval = KeyRParenClicked();
            break;
            
         case 0x0D: // '|': 
            rval = KeyORClicked();
            break;
   
         case 0x20: // 'A': 
            rval = KeyAClicked();
            break;
                  
         case 0x35: // 'B': 
            rval = KeyBClicked();
            break;
                   
         case 0x33: // 'C':
            rval = KeyCClicked();
            break;
                   
         case 0x22: // 'D':
            rval = KeyDClicked();
            break;
                   
         case 0x12: // 'E': 
            rval = KeyEClicked();
            break;
                  
         case 0x23: // 'F':
            rval = KeyFClicked();
            break;

         default:
            break;
         }         
      }
   else
      {
      switch (whichKey)
         {
         case 0x44: // '\n':
            rval = ExprStrClicked();
            break;
   
         case 0x0A: // '0': 
            rval = Key0Clicked();
            break;
         
         case 1: 
            rval = Key1Clicked();
            break;
            
         case 2: 
            rval = Key2Clicked();
            break;
            
         case 3: 
            rval = Key3Clicked();
            break;
            
         case 4: 
            rval = Key4Clicked();
            break;
            
         case 5:
            rval = Key5Clicked();
            break;
            
         case 6:
            rval = Key6Clicked();
            break;
            
         case 7: 
            rval = Key7Clicked();
            break;
            
         case 8: 
            rval = Key8Clicked();
            break;
            
         case 9:
            rval = Key9Clicked();
            break;
            
         case 0x20: // 'a': 
            rval = KeyAClicked();
            break;
                  
         case 0x35: // 'b': 
            rval = KeyBClicked();
            break;
                   
         case 0x33: // 'c':
            rval = KeyCClicked();
            break;
                   
         case 0x22: // 'd':
            rval = KeyDClicked();
            break;
                   
         case 0x12: // 'e': 
            rval = KeyEClicked();
            break;
                  
         case 0x23: // 'f':
            rval = KeyFClicked();
            break;
            
         case 0x37: // 'm':
            rval = KeyModuloClicked();
            break;
            
         case 0x0B: // '-': 
            rval = KeyMinusClicked();
            break;
            
         case 0x0C: // '=':
            rval = KeyEqualClicked();
            break;
            
         case 0x3A: // '/':
            rval = KeySlashClicked();
            break;
            
         case 0x39: // '.':
            rval = KeyPeriodClicked();
            break;
            
         case 0x40: // ' ':
            {
            int len = strlen( EXPRESSION );
      
            if (len < EXPRSIZE)
               {
               strcat( EXPRESSION, " " );
    
               GT_SetGadgetAttrs( ExprGadget, PCWnd, NULL, 
                                  GTST_String, EXPRESSION, TAG_DONE 
                                );
               }
            else
               ExprLimitExceeded();
            }
   
            break;

         case 0x28: // 'l':
            rval = KeyLShiftClicked();
            break;
            
         case 0x13: // 'r':
            rval = KeyRShiftClicked();
            break;
         }
      }

   return( rval );
}
*/

PRIVATE int ActivateProgram( void ) // User pressed the CX_HOTKEY
{
   if (OpenPCWindow() < 0)
      {
      return( -1 );
      }

   SetNotifyWindow( PCWnd );

//   (void) KeyAllClearClicked();

   return( 0 );
}

// ----------------------------------------------------------------------

PRIVATE int ProcessIDCMP( struct IntuiMessage *msg )
{
   int (*func)( void );
   int   rval = TRUE;

   switch (msg->Class) 
      {
      case   IDCMP_REFRESHWINDOW:

         GT_BeginRefresh( PCWnd );
         GT_EndRefresh(   PCWnd, TRUE );

         break;

      case   IDCMP_CLOSEWINDOW:
         rval = PCCloseWindow();
         break;

      case   IDCMP_VANILLAKEY:
         rval = PCVanillaKey( msg->Code );
         break;
/*
      case   IDCMP_RAWKEY:
         rval = PCRawKey( msg->Code, msg->Qualifier );
         break;
*/
      case   IDCMP_GADGETUP:
         func = (void *) ((struct Gadget *) msg->IAddress)->UserData;
            
         if (func != NULL)
            rval = func();
            
         break;

      case IDCMP_MENUPICK: // For later.
      default:
         break;
      }

   return( rval );
}

PRIVATE void ProcessMsg( void );

PRIVATE int HandlePCIDCMP( void )
{
   struct IntuiMessage *m;
   ULONG                sigrcvd = 0L;
   BOOL                 running = TRUE;
   
   while (running == TRUE)
      {
      sigrcvd = Wait( AllSignals );
      
      if ((sigrcvd & WindowSignal) == WindowSignal)
         {
         m = GT_GetIMsg( PCWnd->UserPort );

         if (m != NULL)
            {
            CopyMem( (char *) m, (char *) &PCMsg, 
                     (long) sizeof( struct IntuiMessage )
                   );

            GT_ReplyIMsg( m );

            running = ProcessIDCMP( &PCMsg );
            }
         }
      else
         {
         ProcessMsg();
         }
      }

   return( running );
}

PRIVATE void ShutdownProgram( void ) // User is killing the Commodity.
{
   if (PCWnd != NULL)
      {
      struct IntuiMessage *m;
      
      while ((m = GT_GetIMsg( PCWnd->UserPort )) != NULL) 
         GT_ReplyIMsg( m ); // Just in case.

      ClosePCWindow();
      }
      
   CloseDownScreen();

   if (broker_mp != NULL)
      {
      DeletePort( broker_mp );
      broker_mp = NULL;
      }

   if (IconBase != NULL)
      {
      CloseLibrary( IconBase );
      IconBase = NULL;
      }

   if (CxBase != NULL)
      {
      CloseLibrary( CxBase );
      CxBase = NULL;
      }

   CloseLibs();
   
   return;
}

PRIVATE int SetupProgram( void )
{
   if (OpenLibs() < 0)
      return( -1 );

   if ((IconBase = OpenLibrary( "icon.library", 37L )) == NULL)
      {
      CloseLibs();
      return( -3 );
      }

   if ((CxBase = OpenLibrary( "commodities.library", 37L )) == NULL)
      {
      ShutdownProgram();
      return( -4 );
      }

   if (SetupScreen() < 0)
      {
      ShutdownProgram();
      return( -5 );
      }   

   if ((broker_mp = CreateMsgPort()) == NULL) 
      {
      ShutdownProgram();
      return( -6 );
      }

   return( 0 );  
}

PRIVATE void *processToolTypes( char **ToolPntr ) // Setup some global values.
{
   if (ToolPntr == NULL)
      return( NULL );

   TTHotKey         = GetToolStr( ToolPntr, HotKey, DefHotKey );

   TTTempFile       = GetToolStr( ToolPntr, TempFile, DefTempFile );

   TTHelpFile       = GetToolStr( ToolPntr, HelpFile, DefHelpFile );

   newbroker.nb_Pri = GetToolInt( ToolPntr, CXPriority, DefCXPriority );

   TTCXPriority     = newbroker.nb_Pri;
   
   return( NULL );
}

PRIVATE BOOL HandleCXCommand( ULONG cx_command ) // Deal with Commodities Broker.
{
   struct IntuiMessage *m    = NULL;
   BOOL                 rval = TRUE;
    
   switch (cx_command) 
      {
      case CXCMD_APPEAR:
         if (PCWnd == NULL)
            {
            if (ActivateProgram() < 0)
               {
               rval = FALSE;

               break;
               }
            }

         (void) HandlePCIDCMP();

         break;
                     
      case CXCMD_DISAPPEAR:
         if (PCWnd != NULL)
            {
            while ((m = GT_GetIMsg( PCWnd->UserPort )) != NULL) 
               GT_ReplyIMsg( m ); // Just in case.

            ClosePCWindow();
            }

         break;

      case CXCMD_DISABLE:
         // printf( "CXCMD_DISABLE\n" );
         ActivateCxObj( broker, FALSE ); // DISABLE_CX );
         
         if (PCWnd != NULL)
            {         
            while ((m = GT_GetIMsg( PCWnd->UserPort )) != NULL)
               GT_ReplyIMsg( m ); // Just in case.

            ClosePCWindow();
            }

         break;

      case CXCMD_ENABLE:
         // printf( "CXCMD_ENABLE\n" );
         ActivateCxObj( broker, TRUE ); // ENABLE_CX );

         if (PCWnd == NULL)
            {
            if (ActivateProgram() < 0)
               {
               rval = FALSE;

               break;
               }
            }

         (void) HandlePCIDCMP();

         break;

      case CXCMD_KILL:
         // printf( "CXCMD_KILL\n" );
         {
         struct CxMsg *msg;
          
         rval = FALSE;

         DeleteCxObjAll( broker );

         /* Empty the port of all CxMsgs */
         while (msg = (CxMsg *) GetMsg( broker_mp ))
            ReplyMsg( (struct Message *) msg );
         
         ShutdownProgram();

         exit( RETURN_OK );
         }

         break;

      case CXCMD_UNIQUE:
         // printf( "CXCMD_UNIQUE\n" );
         {
         struct CxMsg *msg;
         
         rval = FALSE;

         DeleteCxObjAll( broker );

         /* Empty the port of all CxMsgs */
         while (msg = (CxMsg *) GetMsg( broker_mp ))
            ReplyMsg( (struct Message *) msg );
         
         ShutdownProgram();

         exit( RETURN_OK );
         }

         break;

      case CXCMD_LIST_CHG: // Someone changed the broker list.
      default:
         break;
      }

   return( rval );
}

PRIVATE void ProcessMsg( void )
{
   CxMsg *msg = NULL;

   ULONG  sigrcvd = 0L, msgid, msgtype;
   BOOL   still_running = TRUE;

   while (still_running != FALSE) 
      {
      if ((msg = (CxMsg *) GetMsg( broker_mp )) == NULL) 
         {
         sigrcvd = Wait( AllSignals ); // ( SIGBREAKF_CTRL_C | CXSignal );

         continue;
         }

      msgid   = CxMsgID(   msg );
      msgtype = CxMsgType( msg );

      ReplyMsg( (struct Message *) msg );

      if ((sigrcvd & CXSignal) == CXSignal)
         {
         switch (msgtype) 
            {
            case CXM_IEVENT: // From the input event food chain.
               // printf( "A CXM_EVENT, " );
               if (msgid == EVT_HOTKEY) 
                  {
                  if (PCWnd == NULL)
                     {
                     if (ActivateProgram() < 0)
                        {
                        still_running = FALSE;

                        break;
                        }
                     }

                  (void) HandlePCIDCMP();
                  }

               break;

            case CXM_COMMAND: // From the broker's MsgPort
               still_running = (int) HandleCXCommand( msgid ); 

               break;

            default:
               break;
            }
         }
      else if ((sigrcvd & SIGBREAKF_CTRL_C) == SIGBREAKF_CTRL_C) 
         {
         DeleteCxObjAll( broker );

         /* Empty the port of all CxMsgs */
         while ((msg = (CxMsg *) GetMsg( broker_mp )) != NULL)
            ReplyMsg( (struct Message *) msg );
         
         ShutdownProgram();

         exit( RETURN_OK );
         }
      else // this should never happen:
         {
         struct IntuiMessage *m = GT_GetIMsg( PCWnd->UserPort );

         if (m != NULL)
            {
            CopyMem( (char *) m, (char *) &PCMsg, 
                     (long) sizeof( struct IntuiMessage )
                   );

            GT_ReplyIMsg( m );

            still_running = ProcessIDCMP( &PCMsg );
            }
         }

      }  // while (still_running != FALSE) 

   return;
}

PRIVATE void ShowError( int errorval ) // Returns from CxObjError()
{
   switch (errorval)
      {
      case COERR_ISNULL:
         fprintf( stderr, "cx filter was == NULL!\n" );
         break;

      case COERR_NULLATTACH:
         fprintf( stderr, "someone attached NULL to my list!\n" );
         break;

      case COERR_BADFILTER:
         fprintf( stderr, "bad filter description!\n" );
         break;

      case COERR_BADTYPE:
         fprintf( stderr, "unmatched type-specific operation!\n" );
         break;

      case CBERR_OK:
         fprintf( stderr, "No error!\n" );
         break;
      
      default:
         fprintf( stderr, 
                  "Unknown error value from CxObjError() = %d",
                  errorval
                );
         break;
      }

   return;
}

PUBLIC int main( int argc, char **argv )
{
   CxMsg *msg     = NULL;
   int    cberror = CBERR_OK;
   
   if (SetupProgram() < 0)
      {
      // fprintf( stderr, "Couldn't set up %s!\n", argv[0] );
      return( RETURN_FAIL );
      }

   SetNotifyWindow( PCWnd ); // In GlobalObjects/CommonFuncs.o

   if (argc > 0)    // from CLI:
      {
      strcpy( ProgramName, argv[0] );

      // We prefer to use the ToolTypes: 
      (void) FindIcon( &processToolTypes, DiskObj, ProgramName );
      }
   else             // from Workbench:
      {
      WB_Args  = &(_WBenchMsg->sm_ArgList[ _WBenchMsg->sm_NumArgs - 1 ]);
      ToolPntr = FindTools( DiskObj, WB_Args->wa_Name, WB_Args->wa_Lock );

      strcpy( ProgramName, WB_Args->wa_Name );

      (void) processToolTypes( ToolPntr );
      }

   newbroker.nb_Port = broker_mp;

   CXSignal   = 1L << broker_mp->mp_SigBit;
   AllSignals = CXSignal | SIGBREAKF_CTRL_C;
   
   if ((broker = CxBroker( &newbroker, NULL )) != NULL)
      {
      if ((filter = CxFilter( TTHotKey )) != NULL) 
         {
         AttachCxObj( broker, filter );

         if ((sender = CxSender( broker_mp, EVT_HOTKEY )) != NULL) 
            {
            AttachCxObj( filter, sender );

            if ((translate = CxTranslate( NULL )) != NULL) 
               {
               AttachCxObj( filter, translate );

               if ((cberror = CxObjError( filter )) == CBERR_OK) 
                  {
                  ActivateCxObj( broker, ENABLE_CX );
                  ProcessMsg();
                  }
               else
                  ShowError( cberror );
               }
            }
         }

      DeleteCxObjAll( broker );

      // Empty the port of all CxMsgs:
      while ((msg = (CxMsg *) GetMsg( broker_mp )) != NULL)
         ReplyMsg( (struct Message *) msg );
      }

   FreeDiskObject( DiskObj );

   ShutdownProgram();

   return( RETURN_OK );
}

/* --------------------- END of MyCalc.c file! -------------------------- */
