/*
 * Conversion Calculator   (C) 1994 Software Sculptors
 *                             All Rights Under Copyright Reserved
 *
 * Version 2.0
 *
 * Written using SAS/C 6.51
 * Using Magic User Interface (MUI) by Stefan Stuntz
 *
 * By John M. Haubrich, Jr.
 *
 *
 * Version~ Date~~~~~~~ Comments~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * -------  ----        --------
 *    1.0   MAR 24 1994 First MUI version.
 *    2.0   OCT 24 1994 Now has user-definable conversions and precision.
 *             ;
 *
 */

#include "common.h"


struct NewMenu Menu_MainMenu[] = {
   NM_TITLE, (STRPTR)"Project",                        NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"New",                      (STRPTR)"N", 0, 0L, (APTR)ID_MENU_NEW,
   NM_ITEM, (STRPTR)NM_BARLABEL,                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Open...",                  (STRPTR)"O", 0, 0L, (APTR)ID_MENU_OPEN,
   NM_ITEM, (STRPTR)"Save",                     (STRPTR)"S", 0, 0L, (APTR)ID_MENU_SAVE,
   NM_ITEM, (STRPTR)"Save As...",               (STRPTR)"A", 0, 0L, (APTR)ID_MENU_SAVEAS,
   NM_ITEM, (STRPTR)NM_BARLABEL,                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"About...",                 (STRPTR)"?", 0, 0L, (APTR)ID_MENU_ABOUT,
   NM_ITEM, (STRPTR)NM_BARLABEL,                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Quit",                     (STRPTR)"Q", 0, 0L, (APTR)ID_MENU_QUIT,
   NM_TITLE, (STRPTR)"Edit",                           NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Cut",                      (STRPTR)"X", 0, 0L, (APTR)ID_MENU_EDITCOPY,
   NM_ITEM, (STRPTR)"Copy",                     (STRPTR)"C", 0, 0L, (APTR)ID_MENU_EDITCOPY,
   NM_ITEM, (STRPTR)"Paste",                    (STRPTR)"V", 0, 0L, (APTR)ID_MENU_EDITPASTE,
//   NM_TITLE, (STRPTR)"Macros",                         NULL, 0, 0L, NULL,
//   NM_ITEM, (STRPTR)"Run Macro...",             (STRPTR)"M", 0, 0L, (APTR)ID_MENU_RUNMACRO,
   NM_TITLE, (STRPTR)"Settings",                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Verify clears?",                  NULL, CHECKIT | MENUTOGGLE, 0L, (APTR)ID_MENU_PREFSCLRVERIFY,
   NM_ITEM, (STRPTR)NM_BARLABEL,                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Units Definition...",             NULL, 0, 0L, (APTR)ID_MENU_SETUNITDEFNS,
   NM_ITEM, (STRPTR)"Precision",                       NULL, 0, 0L, (APTR)ID_MENU_SETPRECISION,
   	NM_SUB, (STRPTR)"1",                      (STRPTR)"1", CHECKIT|MENUTOGGLE        ,  2|4|8|16|32|64,(APTR)ID_MENU_PREC1,
	   NM_SUB, (STRPTR)"2",                      (STRPTR)"2", CHECKIT|MENUTOGGLE        ,1|  4|8|16|32|64,(APTR)ID_MENU_PREC2,
   	NM_SUB, (STRPTR)"3",                      (STRPTR)"3", CHECKIT|MENUTOGGLE        ,1|2|  8|16|32|64,(APTR)ID_MENU_PREC3,
	   NM_SUB, (STRPTR)"4",                      (STRPTR)"4", CHECKIT|MENUTOGGLE|CHECKED,1|2|4|  16|32|64,(APTR)ID_MENU_PREC4,
   	NM_SUB, (STRPTR)"5",                      (STRPTR)"5", CHECKIT|MENUTOGGLE        ,1|2|4|8|   32|64,(APTR)ID_MENU_PREC5,
	   NM_SUB, (STRPTR)"6",                      (STRPTR)"6", CHECKIT|MENUTOGGLE        ,1|2|4|8|16|   64,(APTR)ID_MENU_PREC6,
   	NM_SUB, (STRPTR)"7",                      (STRPTR)"7", CHECKIT|MENUTOGGLE        ,1|2|4|8|16|32   ,(APTR)ID_MENU_PREC7,
   NM_ITEM, (STRPTR)NM_BARLABEL,                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Save Settings",                   NULL, 0, 0L, (APTR)ID_MENU_PREFSSAVE,
   NM_END, NULL, NULL, 0, 0L, NULL
};


/*
 * GLOBAL VARIABLES ---------------------------------
 */
struct MyGlobals        MG;
struct MainWindow       MAIN;
struct UnitDefnsWindow  UDFN;

UWORD   uwTokenIndex = 0;
double  TList[ 50 ]; // TOKENS: -1.0 = '+'
                     // TOKENS: -2.0 = '-'
                     // TOKENS: -3.0 = '*'
                     // TOKENS: -4.0 = '/'
                     // TOKENS: -5.0 = '='
                     // TOKENS: -6.0 = 'T'

char  GL_szFault[ 512 ];
char  GL_szBuf[ 256 ];
char  GL_szInput[ 30+1 ];  // I'll declare 30 in the buffer but limit
                           // the user to 20 for input!!!
char  GL_szOutput[ 30+1 ];

// for disk write routine...
USHORT chip ImageData1[] =
{
   0x0018,0x03FF,0xE01A,0xAAAA,0xBA00,0x001C,0x03FF,0xE000,
   0x0000,0x3200,0x002A,0x03FF,0xE000,0x0000,0x2A00,0x006A,
   0x03FF,0xE001,0xFFFE,0x2600,0x002A,0x0BFF,0xE000,0x0000,
   0x3E00,0x00AA,0x17FF,0xE001,0xFE00,0x1E00,0x00AA,0x2BFF,
   0xE000,0x0000,0x0600,0x01AA,0x2BFF,0xE001,0xFFE0,0x0E00,
   0x02A9,0x4BFF,0xE000,0x0000,0x1A00,0x02AA,0xABFF,0xE001,
   0xFFFE,0x3E00,0x3EAA,0x2BFF,0xE000,0x2000,0x7E00,0x42AA,
   0xAFFF,0xE546,0x796C,0xEE00,0xBF6D,0xB7FF,0xE00C,0xE801,
   0xFE00,0xC555,0x53FF,0xE519,0xE803,0xBE00,0x3954,0x4BFF,
   0xE033,0x7FFF,0xFE00,0x0555,0x53FF,0xF466,0x700E,0xFE00,
   0x0255,0x53FF,0xE0CC,0x701F,0xFE00,0x0152,0xA3FF,0xF118,
   0x703B,0xDE00,0x0154,0x43FF,0xE2F0,0x707F,0xD600,0x0094,
   0x03FF,0xFBE0,0x70EF,0x2E00,0x2AC2,0xABFF,0xEDC0,0x71FC,
   0xDE00,0x5FED,0xFBFF,0xE700,0x73BF,0x7E00,0x5018,0x03FF,
   0xEE00,0x77FD,0xAE00,0x6955,0x03FF,0xFC00,0x6EFE,0x5600,
   0x595A,0x8BFF,0xF800,0x5FD7,0x2E00,0x61DA,0xC3FF,0xE000,
   0x3BEB,0xFE00,0x594A,0xABFF,0xE000,0x7FD5,0xFA00,0x6156,
   0xD3FF,0xE000,0xEEAE,0xFE00,0x5AA0,0x2BFF,0xFFFD,0xFEBF,
   0xFE00,0x6000,0x57FF,0xFFFB,0xBF5D,0xEE00,0x5800,0xABFF,
   0xE007,0xFFBF,0xFE00,0x6011,0x43FF,0xE00E,0xF3DF,0xBA00,
   0x580A,0xABFF,0xE01F,0xF5FF,0xF200,0x6C00,0x03FF,0xEABB,
   0xEBFE,0xE200,0x5602,0x03FF,0xF77F,0xB7FF,0xC600,0x6AAA,
   0xABFF,0xFEEF,0x7D7B,0x8E00,0x5FFF,0xFFFF,0xFDFF,0xEAFF,
   0x1E00,0x7FFF,0xFFFF,0xFBBF,0xF5EE,0x3E00,0x7FFF,0xFFFF,
   0xFFFF,0xFFFF,0xFE00,0xFFEF,0xFFFF,0xFFE5,0x5555,0x6400,
   0x8014,0x03FF,0xE00F,0xFFFF,0xD000,0x803E,0x03FF,0xE00F,
   0xFFFF,0xD800,0x805E,0x03FF,0xE00F,0x8A29,0xD800,0x807E,
   0x0BC3,0x600F,0xFFFF,0xFC00,0x80FE,0x1FDF,0x600F,0x23FF,
   0xE400,0x80F6,0x3FDF,0x600F,0xFFFF,0xF800,0x8176,0x3FFF,
   0x600F,0x8A3F,0xF000,0x83D7,0x7FFE,0x600F,0xFFFF,0xE000,
   0x8357,0xFF80,0xE00F,0x128B,0xC400,0xBD57,0xF7FF,0xFFFF,
   0xFFFF,0x8800,0xFD55,0x57FF,0xE2BB,0x8803,0x0000,0xF7FF,
   0xDBFF,0xE7F7,0x47FE,0x2000,0x7BAA,0xAFFF,0xEAEE,0xC7FC,
   0x0400,0xBFAF,0xFFDF,0xFFDD,0x4000,0x8C00,0x87AF,0xF7FF,
   0x6BBA,0x5010,0x0400,0x83FF,0xF7FF,0x7F74,0xD022,0x0000,
   0x81FE,0xE7C3,0x6E89,0x5040,0x0000,0x81FC,0x47DF,0x7CD2,
   0xD088,0x5000,0x80FC,0x079E,0x6365,0x5100,0x2C00,0xAAEA,
   0xAFFF,0xECCA,0xD220,0xD800,0xC03C,0x07FF,0xE715,0x5403,
   0x7C00,0xFFF7,0xFFFF,0x6A2A,0x5881,0x8800,0xD6AA,0xAFF8,
   0x7855,0x5000,0x5000,0xE6A5,0x57FB,0xE8A8,0x6200,0x2000,
   0xD7F5,0xAFFB,0xE154,0x4028,0x6000,0xE7AD,0x97FB,0xE2A0,
   0x8854,0x0000,0xD6A9,0x2FFB,0xF551,0x00AE,0x0400,0xE555,
   0x57FB,0xFFFE,0x20BF,0x0800,0xD6AA,0xABF3,0xE004,0x015C,
   0x0000,0xE555,0x5FFF,0xE008,0x80BC,0x2400,0xD6AA,0xFFFF,
   0xE010,0x0058,0x0800,0xE555,0x57FF,0xE022,0x1430,0x9000,
   0xD000,0x03FF,0xE040,0x2A00,0x2000,0xEC00,0x03DF,0xE088,
   0xB782,0x4000,0xDAAA,0xABFF,0x6100,0x7500,0x8000,0xDFFF,
   0xFFC3,0x6220,0xEA09,0x0000,0xEAAA,0xABDF,0x6406,0x7402,
   0x0000,0x8000,0x03FF,0xE000,0x0000,0x0000,0x0018,0x0000,
   0x001A,0xAAAA,0x9A00,0x7FFF,0xFC00,0x1FF0,0x0000,0x2C00,
   0x7FE3,0xFCFE,0x1FF0,0x0000,0x2400,0x7FE3,0xFCFF,0x1FF0,
   0x75D6,0x2000,0x6E82,0xECC3,0x0EF0,0x0000,0x0000,0x7F83,
   0xF4C3,0x1FF0,0xDC00,0x1800,0x2A82,0xA0C3,0x0AB0,0x0000,
   0x0000,0x7783,0x60FF,0x1770,0x75C0,0x0000,0x2A01,0xC0FE,
   0x0AB0,0x0000,0x0400,0x5600,0x8000,0x1550,0xED74,0x0000,
   0x3E00,0x0000,0x0000,0x0000,0x1000,0x4000,0x0018,0x07FB,
   0x87FC,0x1000,0x8000,0x003C,0x07F7,0x0800,0x4000,0xC000,
   0x007E,0x0FEE,0x0800,0x4000,0x3800,0x08C3,0x1FDC,0x8009,
   0x0000,0x0401,0x10FF,0x1FB9,0x8801,0x0000,0x2201,0x10FF,
   0x1F73,0x8804,0x0000,0x0102,0xA0C3,0x1E67,0x8804,0x7000,
   0x0104,0x40C3,0x1D0F,0x8810,0xA800,0x0084,0x0000,0x1C1F,
   0x8811,0xD000,0x1555,0x5000,0x123F,0x8841,0x2000,0x1FE9,
   0xF8FF,0x18FF,0x8840,0x8000,0x1018,0x00FF,0x11FF,0x8102,
   0x5000,0x2955,0x0018,0x03FF,0x8101,0xA800,0x1818,0x8818,
   0x07FF,0x8438,0xD000,0x2800,0x0018,0x1FFF,0x8454,0x0000,
   0x1810,0x6818,0x1FFF,0x10AA,0x0400,0x2956,0x5018,0x1FFE,
   0x1151,0x0000,0x1AA0,0x2818,0x0000,0x4140,0x1000,0x2940,
   0x5400,0x0000,0x40A2,0x1000,0x1A80,0xA800,0x1FF1,0x0040,
   0x4000,0x2911,0x4018,0x1FE1,0x1C20,0x4400,0x1A0A,0xA83C,
   0x0004,0x2A01,0x0C00,0x2FFF,0xFC7E,0x0A84,0x5501,0x1800,
   0x1B57,0x54C3,0x1710,0x4804,0x3400,0x3000,0x00FF,0x1E10,
   0x8284,0x6C00,0x2000,0x00C3,0x1C40,0x1510,0xDC00,0x0000,
   0x00C3,0x1840,0x0A11,0xBC00,0x0000,0x0000,0x0000,0x0000,
   0x0000
};
struct Image Image1 =
{
   0,
   0,
   71,
   39,
   3,
   ImageData1,
   0x07,
   0x00,
   NULL
};

USHORT chip ImageData2[] =
{
   0x0018,0x01FF,0xF01A,0xAAAA,0xBA00,0x001C,0x01FF,0xF000,
   0x0000,0x3200,0x002A,0x01FF,0xF000,0x0000,0x2A00,0x006A,
   0x01FF,0xF001,0xFFFE,0x2600,0x002A,0x09FF,0xF000,0x0000,
   0x3E00,0x00AA,0x15FF,0xF001,0xFE00,0x1E00,0x00AA,0x2BFF,
   0xF000,0x0000,0x0600,0x01AA,0x2BFF,0xF001,0xFFE0,0x0E00,
   0x02A9,0x4BFF,0xF000,0x0000,0x1A00,0x02AA,0xABFF,0xF001,
   0xFFFE,0x3E00,0x3EAA,0x2BFF,0xF000,0x2000,0x7E00,0x42AA,
   0xADFF,0xF446,0x796C,0xEE00,0xBF6D,0xB7FF,0xFA0C,0xE801,
   0xFE00,0xC555,0x51FF,0xF119,0xE803,0xBE00,0x3954,0x49FF,
   0xF033,0x7FFF,0xFE00,0x0555,0x51FF,0xF066,0x700E,0xFE00,
   0x0255,0x51FF,0xF2CC,0x701F,0xFE00,0x0152,0xA1FF,0xF318,
   0x703B,0xDE00,0x0154,0x41FF,0xF6F0,0x707F,0xD600,0x0094,
   0x01FF,0xFFE0,0x70EF,0x2E00,0x2AC2,0xA9FF,0xFFC0,0x71FC,
   0xDE00,0x5FED,0xF9FF,0xFF00,0x73BF,0x7E00,0x5018,0x01FF,
   0xFE00,0x77FD,0xAE00,0x6955,0x01FF,0xFC00,0x6EFE,0x5600,
   0x595A,0x89FF,0xF800,0x5FD7,0x2E00,0x61DA,0xC1FF,0xF000,
   0x3BEB,0xFE00,0x594A,0xA9FF,0xF000,0x7FD5,0xFA00,0x6156,
   0xD1FF,0xF000,0xEEAE,0xFE00,0x5AA0,0x2BFF,0xFFFD,0xFEBF,
   0xFE00,0x6000,0x57FF,0xFFFB,0xBF5D,0xEE00,0x5800,0xA9FF,
   0xF007,0xFFBF,0xFE00,0x6011,0x41FF,0xF00E,0xF3DF,0xBA00,
   0x580A,0xABFF,0xF01F,0xF5FF,0xF200,0x6C00,0x01FF,0xF0BB,
   0xEBFE,0xE200,0x5602,0x03FF,0xF17F,0xB7FF,0xC600,0x6AAA,
   0xABFF,0xF0EF,0x7D7B,0x8E00,0x5FFF,0xFFFF,0xF1FF,0xEAFF,
   0x1E00,0x7FFF,0xFFFF,0xFBBF,0xF5EE,0x3E00,0x7FFF,0xFFFF,
   0xFFFF,0xFFFF,0xFE00,0xFFEF,0xFFFF,0xFFE5,0x5555,0x6400,
   0x8014,0x01FF,0xF00F,0xFFFF,0xD000,0x803E,0x0180,0xF00F,
   0xFFFF,0xD800,0x805E,0x0180,0x700F,0x8A29,0xD800,0x807E,
   0x099E,0x700F,0xFFFF,0xFC00,0x80FE,0x1D9E,0x700F,0x23FF,
   0xE400,0x80F6,0x3F9E,0x700F,0xFFFF,0xF800,0x8176,0x3F80,
   0x700F,0x8A3F,0xF000,0x83D7,0x7F80,0xF00F,0xFFFF,0xE000,
   0x8357,0xFFFF,0xF00F,0x128B,0xC400,0xBD57,0xF7FF,0xFFFF,
   0xFFFF,0x8800,0xFD55,0x57F3,0xFFBB,0x8803,0x0000,0xF7FF,
   0xDBE1,0xFFF7,0x47FE,0x2000,0x7BAA,0xAFC0,0xFEEE,0xC7FC,
   0x0400,0xBFAF,0xFF9E,0x7FDD,0x4000,0x8C00,0x87AF,0xF780,
   0x7FBA,0x5010,0x0400,0x83FF,0xF780,0x7F74,0xD022,0x0000,
   0x81FE,0xE79E,0x7E89,0x5040,0x0000,0x81FC,0x479E,0x7CD2,
   0xD088,0x5000,0x80FC,0x07FF,0xFB65,0x5100,0x2C00,0xAAEA,
   0xAFFF,0xF6CA,0xD220,0xD800,0xC03C,0x0780,0x7D15,0x5403,
   0x7C00,0xFFF7,0xFF80,0x7A2A,0x5881,0x8800,0xD6AA,0xAFF3,
   0xF455,0x5000,0x5000,0xE6A5,0x57F3,0xF8A8,0x6200,0x2000,
   0xD7F5,0xAFF3,0xF154,0x4028,0x6000,0xE7AD,0x97F3,0xF2A0,
   0x8854,0x0000,0xD6A9,0x2FF3,0xF151,0x00AE,0x0400,0xE555,
   0x55FF,0xFFFE,0x20BF,0x0800,0xD6AA,0xA9FF,0xF004,0x015C,
   0x0000,0xE555,0x5FF3,0xF008,0x80BC,0x2400,0xD6AA,0xFFE1,
   0xF010,0x0058,0x0800,0xE555,0x55C0,0xF022,0x1430,0x9000,
   0xD000,0x019E,0x7040,0x2A00,0x2000,0xEC00,0x0180,0x7088,
   0xB782,0x4000,0xDAAA,0xAB80,0x7100,0x7500,0x8000,0xDFFF,
   0xFF9E,0x7220,0xEA09,0x0000,0xEAAA,0xABFF,0xF406,0x7402,
   0x0000,0x8000,0x01FF,0xF000,0x0000,0x0000,0x0018,0x0000,
   0x001A,0xAAAA,0x9A00,0x7FFF,0xFE00,0x0FF0,0x0000,0x2C00,
   0x7FE3,0xFE00,0x0FF0,0x0000,0x2400,0x7FE3,0xFE00,0x0FF0,
   0x75D6,0x2000,0x6E82,0xEE00,0x0EF0,0x0000,0x0000,0x7F83,
   0xF600,0x0FF0,0xDC00,0x1800,0x2A82,0xA200,0x08B0,0x0000,
   0x0000,0x7783,0x6200,0x0370,0x75C0,0x0000,0x2A01,0xC200,
   0x0EB0,0x0000,0x0400,0x5600,0x8200,0x0550,0xED74,0x0000,
   0x3E00,0x0200,0x0000,0x0000,0x1000,0x4000,0x0000,0x0FFB,
   0x87FC,0x1000,0x8000,0x0000,0x0FF7,0x0800,0x4000,0xC000,
   0x0000,0x0FEE,0x0800,0x4000,0x3800,0x0800,0x0FDC,0x8009,
   0x0000,0x0401,0x1000,0x0FB9,0x8801,0x0000,0x2201,0x1000,
   0x0F73,0x8804,0x0000,0x0102,0xA000,0x0E67,0x8804,0x7000,
   0x0104,0x4000,0x0D0F,0x8810,0xA800,0x0084,0x0000,0x081F,
   0x8811,0xD000,0x1555,0x5000,0x003F,0x8841,0x2000,0x1FE9,
   0xF800,0x00FF,0x8840,0x8000,0x1018,0x0000,0x01FF,0x8102,
   0x5000,0x2955,0x0000,0x03FF,0x8101,0xA800,0x1818,0x8800,
   0x07FF,0x8438,0xD000,0x2800,0x0000,0x0FFF,0x8454,0x0000,
   0x1810,0x6800,0x0FFF,0x10AA,0x0400,0x2956,0x5000,0x0FFE,
   0x1151,0x0000,0x1AA0,0x2A00,0x0000,0x4140,0x1000,0x2940,
   0x5400,0x0000,0x40A2,0x1000,0x1A80,0xA800,0x0FF1,0x0040,
   0x4000,0x2911,0x4000,0x0FE1,0x1C20,0x4400,0x1A0A,0xAA00,
   0x0C04,0x2A01,0x0C00,0x2FFF,0xFE00,0x0884,0x5501,0x1800,
   0x1B57,0x5600,0x0910,0x4804,0x3400,0x3000,0x0000,0x0A10,
   0x8284,0x6C00,0x2000,0x0000,0x0040,0x1510,0xDC00,0x0000,
   0x0000,0x0040,0x0A11,0xBC00,0x0000,0x0000,0x0000,0x0000,
   0x0000
};
struct Image Image2 =
{
   0,
   0,
   71,
   39,
   3,
   ImageData2,
   0x07,
   0x00,
   NULL
};

struct DiskObject diskobj = {
   WB_DISKMAGIC, WB_DISKVERSION,
   {
      NULL,
      0, 0, 71, 39,
      GADGIMAGE | GFLG_GADGHIMAGE,
      GADGIMMEDIATE | RELVERIFY,
      BOOLGADGET,
      (APTR)&Image1,
      (APTR)&Image2,
      NULL,
      NULL,
      NULL,
      0,
      NULL
   },
   WBPROJECT,
   "ConvCalc",
   NULL,
   NO_ICON_POSITION,
   NO_ICON_POSITION,
   NULL,
   NULL,
   8192
};


/*
 * DEFINES ------------------------------------------
 */
#define NUM_ARGS        0
//#define ARG_SETTINGS    1

#define KeyButtonNoBar(name,key)\
	TextObject,\
		ButtonFrame,\
		MUIA_Text_Contents, name,\
		MUIA_Text_PreParse, "\33c\33b",\
		MUIA_ControlChar  , key,\
		MUIA_InputMode    , MUIV_InputMode_RelVerify,\
		MUIA_Background   , MUII_ButtonBack,\
		End

#define TOKEN_PLUS      -1.0
#define TOKEN_MINUS     -2.0
#define TOKEN_MULTIPLY  -3.0
#define TOKEN_DIVIDE    -4.0
#define TOKEN_EQUAL     -5.0


/*
 * ARRAYS --------------------------------------------
 */
struct UnitDefnNode {
   UBYTE  szUnitName[20+1];
   UBYTE  szUnitFactor[12+1];
};


/*
 * LIBRARY VARIABLES ---------------------------------
 */
struct Library       *DosBase          = NULL;
struct IntuitionBase *IntuitionBase    = NULL;
struct GfxBase       *GfxBase          = NULL;
struct Library       *GadToolsBase     = NULL;
struct Library       *AslBase          = NULL;
struct Library       *UtilityBase      = NULL;
struct Library       *MUIMasterBase    = NULL;

#ifdef LATTICE
int CXBRK(void) { return(0); }
void __regargs __chkabort(void) { return; }
#endif


/*
 * APP MESSAGE HOOK FUNCTIONS -----------------------
 */
SAVEDS ASM LONG AppMsgFunc( REG(a2)APTR obj, REG(a1)struct AppMessage **appmsg )
{
   struct WBArg      *ap;
   struct AppMessage *amsg = *appmsg;
   static char        buf[256];
   LONG               lItems;
   BOOL               fSure = TRUE;    // sure you want to load this?


   ap = amsg->am_ArgList;
   NameFromLock( ap->wa_Lock, buf, sizeof( buf ) );
   AddPart( buf, ap->wa_Name, sizeof( buf ) );

   // if there are items in the listview, ask before loading!
   get( MAIN.LIS_FromUnits, MUIA_List_Entries, &lItems );
   if ( lItems > 0 )
   {
      fSure = MUI_Request( MG.App, MG.WIN_Main, 0, NULL, "OK|*Cancel",
                           "Data is currently loaded.\nAre you sure you want to load the new file?", NULL );
   }
   if ( fSure == TRUE )
   {
      // load data file
      strcpy( MG.szProjectSpec, buf );
      DoMethod( UDFN.LIS_PopList , MUIM_List_Clear, TRUE );
      DoMethod( MAIN.LIS_PopUnits, MUIM_List_Clear, TRUE );
      fnReadData( MG.szProjectSpec );
      set( MAIN.LIS_PopUnits, MUIA_List_Active, 1 );
      set( MAIN.LIS_PopUnits, MUIA_List_Active, 0 );
   }

   return( 0 );
}

static const struct Hook AppMsgHook = { { NULL,NULL }, (VOID *)AppMsgFunc, NULL, NULL };


/*
 * SUBROUTINES ---------------------------------------
 */
void fnNew( void )
{
   LONG  lStat;


   fnFreeData();
   memset( (char *)&TList, 0, sizeof( double ) * 50 );
   MG.ubPrecision = 4;
   DoMethod( MG.menustrip, MUIM_SetUData, ID_MENU_PREC4, MUIA_Menuitem_Checked, TRUE );
   DoMethod( UDFN.LIS_PopList , MUIM_List_Clear, TRUE );
   DoMethod( UDFN.LIS_UnitList, MUIM_List_Clear, TRUE );
   DoMethod( MAIN.LIS_PopUnits, MUIM_List_Clear, TRUE );
   set( MAIN.TXT_Input,  MUIA_Text_Contents, NULL );
   set( MAIN.TXT_Output, MUIA_Text_Contents, NULL );
   strcpy( MG.szProjectSpec, "" );

   //
   // init bases
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   for ( lStat = 0; lStat < MAX_BASE_COUNT; lStat++ )
   {
      strcpy( (MG.pBaseBase+lStat)->szBaseName, "Unused" );
      strcpy( (MG.pBaseBase+lStat)->szBaseUnit, "Undefined" );
      (MG.pBaseBase+lStat)->uwNumUnits = 0;
      (MG.pBaseBase+lStat)->pUnitBase  = NULL;
   }
   MG.uwNumBases = MAX_BASE_COUNT - 1;
   fnFillListWithBases( UDFN.LIS_PopList );
   fnFillListWithBases( MAIN.LIS_PopUnits );

   set( MAIN.TXT_PopText, MUIA_Text_Contents, (MG.pBaseBase)->szBaseName );
   set( MAIN.LIS_PopUnits, MUIA_List_Active, 0 );
}

void fnFreeData( void )    // units/bases/arrays/etc...
{
   UWORD  bi;


   if ( MG.pBaseBase )
   {
      for ( bi = 0; bi < MG.uwNumBases; bi++ )
      {
         if ( (MG.pBaseBase+bi)->pUnitBase )
         {
            FreeVec( (MG.pBaseBase+bi)->pUnitBase );
            (MG.pBaseBase+bi)->pUnitBase = NULL;
         }
      }

      MG.uwNumBases = 0;
      memset( MG.pBaseBase, 0, sizeof( struct Base ) * MAX_BASE_COUNT );
   }
}

void fnFillListWithBases( Object *pList )
{
   UWORD  uw;
   UBYTE  szBuf[50];


   for ( uw = 0; uw < MG.uwNumBases; uw++ )
   {
      sprintf( szBuf, "%s", (MG.pBaseBase+uw)->szBaseName );
      DoMethod( pList, MUIM_List_InsertSingle, szBuf, MUIV_List_Insert_Bottom );
   }
}

void fnFillListWithUnits( Object *pList, UWORD uwIndex )
{
   UWORD        uw, uwNumUnits;
   UBYTE        szBuf[50];
   struct Unit *pUnits = NULL;


   pUnits     = (MG.pBaseBase + uwIndex)->pUnitBase;
   uwNumUnits = (MG.pBaseBase + uwIndex)->uwNumUnits;

   if ( pUnits )
   {
      for ( uw = 0; uw < uwNumUnits; uw++ )
      {
         sprintf( szBuf, "%s", (pUnits+uw)->szUnitName );
         DoMethod( pList, MUIM_List_InsertSingle, szBuf, MUIV_List_Insert_Bottom );
      }
   }
}

BOOL fnReallocList( Object *pList, UWORD uwBaseIndex )
{
   BOOL   rc;         // return error
   UWORD  uw;
   ULONG  ulNE;

   struct UnitDefnNode *pUDFNNode;
   struct Unit         *pNewUnits = NULL;


   get( pList, MUIA_List_Entries, &ulNE );
   pNewUnits = AllocVec( sizeof( struct Unit ) * ulNE, MEMF_PUBLIC | MEMF_CLEAR );
   if ( pNewUnits )
   {
      for ( uw = 0; uw < ulNE; uw++ )
      {
         DoMethod( pList, MUIM_List_GetEntry, uw, &pUDFNNode );
         strcpy( (pNewUnits+uw)->szUnitName, pUDFNNode->szUnitName );
         (pNewUnits+uw)->dblFactor = atof( pUDFNNode->szUnitFactor );
      }

      if ( (MG.pBaseBase+uwBaseIndex)->pUnitBase )
      {
         FreeVec( (MG.pBaseBase+uwBaseIndex)->pUnitBase );
      }
      (MG.pBaseBase+uwBaseIndex)->pUnitBase  = pNewUnits;
      (MG.pBaseBase+uwBaseIndex)->uwNumUnits = (UWORD)ulNE;
      rc = TRUE;
   }
   else
   {
      rc = FALSE;    // return error so we can complain and retry...
   }

   return( rc );
}

void fnFillUDfnList( Object *pList, UWORD uwBaseIndex )
{
   UWORD  uw;
   struct Unit    *pUB;
   UBYTE           szBuf[100];


   for ( uw = 0; uw < (MG.pBaseBase+uwBaseIndex)->uwNumUnits; uw++ )
   {
      pUB = (MG.pBaseBase+uwBaseIndex)->pUnitBase;
      sprintf( szBuf, "%s%c%f", (pUB+uw)->szUnitName, 255, (pUB+uw)->dblFactor );
      DoMethod( pList, MUIM_List_InsertSingle, szBuf, MUIV_List_Insert_Bottom );
   }
}

ULONG fnReadData( char *pszFile )
{
   char   szBuf[100];
   BPTR   fh = NULL;
   char   szPathPart[ FMSIZE+1 ], szFilePart[ FMSIZE+1 ], *psz, sz;
   char  *pszFileError = 0;

   struct Window        *pWindow = NULL;
   struct FileRequester *pFReq   = NULL;


   if ( !pszFile )
   {
      get( MG.WIN_Main, MUIA_Window , &pWindow );
      if ( pFReq = MUI_AllocAslRequestTags( ASL_FileRequest, TAG_DONE ) )
      {
         strcpy( szPathPart, MG.szProjectSpec );
         psz = PathPart( szPathPart );
         if ( psz )
         {
            sz = *psz;
            *psz = 0;
            sprintf( szFilePart, "%c%s", sz, psz+1 );
         }
         else
         {
            strcpy( szPathPart, "" );
            strcpy( szFilePart, MG.szProjectSpec );
         }

         if ( MUI_AslRequestTags( pFReq,
                                  ASLFR_Window         , pWindow,
                                  ASLFR_PrivateIDCMP   , TRUE,
                                  ASLFR_TitleText      , "Open ConvCalc file",
                                  ASLFR_InitialDrawer  , szPathPart,
                                  ASLFR_InitialFile    , szFilePart,
                                  TAG_DONE ) )
         {
            // set the new contents for our string gadget
            memset( MG.szProjectSpec, 0, sizeof( MG.szProjectSpec ) );
            strncpy( MG.szProjectSpec, pFReq->fr_Drawer, sizeof( MG.szProjectSpec )-1 );
            AddPart( MG.szProjectSpec, pFReq->fr_File,   sizeof( MG.szProjectSpec )-1 );
         }
         else
         {
            return( FALSE );
         }

         MUI_FreeAslRequest( pFReq );
      }
   }
   else
   {
      strcpy( MG.szProjectSpec, pszFile );
   }

   fh = Open( MG.szProjectSpec, MODE_OLDFILE );
   if ( !fh )
   {
      Fault( IoErr(), "File open error!\n", GL_szFault, sizeof( GL_szFault ) );
      JMH_Error( GL_szFault, NULL, "PROGDIR:convcalc.guide", "errors", 0 );
      return( RETURN_ERROR );
   }

   //
   // we got the file open... now let's verify that it's one of ours...
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   FGets( fh, szBuf, 80 );
   if ( strncmp( szBuf, FILEID_HEADER, strlen( FILEID_HEADER ) ) )
   {
      Fault( IoErr(), "Disk read error!\n", GL_szFault, sizeof( GL_szFault ) );
      JMH_Error( GL_szFault, NULL, "PROGDIR:convcalc.guide", "errors", 0 );
      Close( fh );
      return( RETURN_ERROR );
   }

   //
   // ok, read the file into memory...
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   fnFreeData();

   set( MG.App, MUIA_Application_Sleep, TRUE );

   pszFileError = FGets( fh, szBuf, 10 );    // read number of bases...
   if ( pszFileError )
   {
      UWORD  bi, ui;
      UBYTE *psz;


      MG.uwNumBases = atoi( szBuf );
      for ( bi = 0; bi < MG.uwNumBases; bi++ )
      {
         pszFileError = FGets( fh, szBuf, 40 );       JMH_Trim( szBuf, "\n", 1 );
         if ( pszFileError == 0 ) break;
         strcpy( (MG.pBaseBase+bi)->szBaseName, szBuf );
         pszFileError = FGets( fh, szBuf, 40 );       JMH_Trim( szBuf, "\n", 1 );
         if ( pszFileError == 0 ) break;
         strcpy( (MG.pBaseBase+bi)->szBaseUnit, szBuf );
         pszFileError = FGets( fh, szBuf, 40 );       JMH_Trim( szBuf, "\n", 1 );
         if ( pszFileError == 0 ) break;
         (MG.pBaseBase+bi)->uwNumUnits = atoi( szBuf );

         (MG.pBaseBase+bi)->pUnitBase = AllocVec( sizeof( struct Unit ) * (MG.pBaseBase+bi)->uwNumUnits, MEMF_PUBLIC | MEMF_CLEAR );
         if ( (MG.pBaseBase+bi)->pUnitBase )
         {
            for ( ui = 0; ui < ( (MG.pBaseBase+bi)->uwNumUnits ); )
            {
               if ( pszFileError = FGets( fh, szBuf, 50 ) )
               {
                  JMH_Trim( szBuf, "\n", 1 );
                  psz = strchr( szBuf, 255 );
                  if ( psz )
                  {
                     *psz = 0;
                     strcpy( (((MG.pBaseBase+bi)->pUnitBase)+ui)->szUnitName, szBuf );
                     (((MG.pBaseBase+bi)->pUnitBase)+ui)->dblFactor = atof( psz+1 );
                     ui++;
                  }
               }
               else
               {
                  break;
               }
            }
         }
         else
         {
            MG.uwNumBases = bi;
            break;
         }
      }
      for ( bi = MG.uwNumBases; bi < MAX_BASE_COUNT; bi++ )
      {
         strcpy( (MG.pBaseBase+bi)->szBaseName, "Unused" );
         strcpy( (MG.pBaseBase+bi)->szBaseUnit, "Undefined" );
         (MG.pBaseBase+bi)->uwNumUnits = 0;
         (MG.pBaseBase+bi)->pUnitBase  = NULL;
      }
   }

   if ( pszFileError == 0 )
   {
      sprintf( GL_szFault, "File error #%ld reading base/unit data.", IoErr() );
      JMH_Error( GL_szFault, NULL, "PROGDIR:Convcalc.guide", "errors", 0 );

      MG.uwNumBases = 0;
      memset( MG.pBaseBase, 0, sizeof( struct Base ) * MAX_BASE_COUNT );
   }

   MG.uwNumBases = MAX_BASE_COUNT - 1;
   fnFillListWithBases( UDFN.LIS_PopList );
   fnFillListWithBases( MAIN.LIS_PopUnits );

   Close( fh );
   set( MG.App, MUIA_Application_Sleep, FALSE );
   return( RETURN_OK );
}

BOOL fnWriteData( BOOL fPopupFReq )
{
   BOOL   rc = FALSE;      // assume FAILURE

   char   szBuf[100];
   UWORD  bi, ui;
   BPTR   fh = NULL;
   char   szPathPart[ FMSIZE+1 ], szFilePart[ FMSIZE+1 ], *psz, sz;
   LONG   lFileError = 0;

   struct Unit *pUnits;

   struct Window        *pWindow = NULL;
   struct FileRequester *pFReq   = NULL;
   struct DiskObject    *pDObj   = NULL;


   if ( ( fPopupFReq ) || ( strcmp( MG.szProjectSpec, "" ) == 0 ) )
   {
      get( MG.WIN_Main, MUIA_Window , &pWindow );
      if ( pFReq = MUI_AllocAslRequestTags( ASL_FileRequest, TAG_DONE ) )
      {
         strcpy( szPathPart, MG.szProjectSpec );
         psz = PathPart( szPathPart );
         if ( psz )
         {
            sz = *psz;
            *psz = 0;
            sprintf( szFilePart, "%c%s", sz, psz+1 );
         }
         else
         {
            strcpy( szPathPart, "" );
            strcpy( szFilePart, MG.szProjectSpec );
         }

         if ( MUI_AslRequestTags( pFReq,
               ASLFR_Window         , pWindow,
               ASLFR_PrivateIDCMP   , TRUE,
               ASLFR_TitleText      , "Save ConvCalc file",
               ASLFR_DoSaveMode     , TRUE,
               ASLFR_InitialDrawer  , szPathPart,
               ASLFR_InitialFile    , szFilePart,
               TAG_DONE ) )
         {
            // set the new contents for our string gadget
            memset( MG.szProjectSpec, 0, sizeof( MG.szProjectSpec ) );
            strncpy( MG.szProjectSpec, pFReq->fr_Drawer, sizeof( MG.szProjectSpec )-1 );
            AddPart( MG.szProjectSpec, pFReq->fr_File,   sizeof( MG.szProjectSpec )-1 );
         }
         else
         {
            return( FALSE );
         }

         MUI_FreeAslRequest( pFReq );
      }
   }

   fh = Open( MG.szProjectSpec, MODE_NEWFILE );
   if ( fh )
   {
      set( MG.App, MUIA_Application_Sleep, TRUE );

      //
      // Here's a clever idea:
      //    Put a while loop here and if any errors occur in writing data
      //    to disk, simply issue a 'break' which will take us outside
      //    the loop!  Note, of course, that the loop itself is bogus;
      //    we don't want to write the data more than once!!!
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      lFileError = 0;
      while ( 1 )
      {
         sprintf( szBuf, "%s\n", FILEID_HEADER );
         if ( lFileError = FPuts( fh, szBuf ) )   break;

         sprintf( szBuf, "%u\n", MG.uwNumBases );
         if ( lFileError = FPuts( fh, szBuf ) )   break;

         for ( bi = 0; ( ( bi < MG.uwNumBases) && ( lFileError == 0 ) ); bi++ )
         {
            sprintf( szBuf, "%s\n", (MG.pBaseBase+bi)->szBaseName );
            if ( lFileError = FPuts( fh, szBuf ) )  break;

            sprintf( szBuf, "%s\n", (MG.pBaseBase+bi)->szBaseUnit );
            if ( lFileError = FPuts( fh, szBuf ) )  break;

            sprintf( szBuf, "%u\n", (MG.pBaseBase+bi)->uwNumUnits );
            if ( lFileError = FPuts( fh, szBuf ) )  break;

            for ( ui = 0; ( ( ui < (MG.pBaseBase+bi)->uwNumUnits ) && ( lFileError == 0 ) ); ui++ )
            {
               pUnits = (MG.pBaseBase+bi)->pUnitBase;
               sprintf( szBuf, "%s%c%f\n", (pUnits+ui)->szUnitName, 255, (pUnits+ui)->dblFactor );
               if ( lFileError = FPuts( fh, szBuf ) ) break;
            }
         }

         break;   // don't actually loop... see note above!
      }

      if ( lFileError )
      {
         sprintf( GL_szFault, "File error #%ld writing base/unit data.", IoErr() );
         JMH_Error( GL_szFault, NULL, "PROGDIR:Convcalc.guide", "errors", 0 );
      }
      else
      {
         // write icon here
         pDObj = GetDiskObject( MG.szProjectSpec );
         if ( !pDObj )
         {
            // don't write an icon if one already exists...
            PutDiskObject( MG.szProjectSpec, &diskobj );
         }
         else
         {
            FreeDiskObject( pDObj );
         }
      }
      Close( fh );
      set( MG.App, MUIA_Application_Sleep, FALSE );
   }
   else
   {
      Fault( IoErr(),
             "Cannot open data file because",
             GL_szFault,
             sizeof( GL_szFault ) );
      JMH_Error( GL_szFault, NULL, "PROGDIR:convcalc.guide", "errors", 0 );
      rc = RETURN_ERROR;
   }

   return( rc );
}

void fnAddFraction( double fVal )
{
   double  fInputVal;
   char   *psz;


   if ( MG.fStartNewNumber )
   {
      sprintf( GL_szInput, "%f", fVal );
   }
   else
   {
      get( MAIN.TXT_Input, MUIA_Text_Contents, &psz );
      fInputVal = atof( psz );
      fInputVal += fVal;
      sprintf( GL_szInput, "%f", fInputVal );
   }

   JMH_Trim( GL_szInput, "0", 1 );
   set( MAIN.TXT_Input, MUIA_Text_Contents, GL_szInput );
}
void fnAddDigit( char *pszDigit )
{
   double  dblInputVal;
   char   *psz;


   get( MAIN.TXT_Input, MUIA_Text_Contents, &psz );
   dblInputVal = atof( psz );

   // check max length!!!
   if ( strlen( GL_szInput ) >= 20 )
   {
      DisplayBeep(0);
   }
   else
   {
      if ( MG.fStartNewNumber )
      {
         strcpy( GL_szInput, pszDigit );
      }
      else
      {
         strcat( GL_szInput, pszDigit );
      }
      set( MAIN.TXT_Input, MUIA_Text_Contents, GL_szInput );
   }
}
void fnClear()
{
   set( MAIN.TXT_Input,  MUIA_Text_Contents, NULL );
   set( MAIN.TXT_Output, MUIA_Text_Contents, NULL );
   memset( (char *)&TList, 0, sizeof( double ) * 50 );
   uwTokenIndex = 0;
   MG.fStartNewNumber = TRUE;
   MG.fDecimalTyped = FALSE;
}
LONG fnClipCopy()
{
   char   szBuf[ 255+1 ];
   UWORD  uwLen;


   uwLen = strlen( GL_szOutput );
   if ( uwLen )
   {
      if ( strlen( GL_szOutput ) & 1 )    uwLen++;

      memset( szBuf, 0, sizeof( szBuf ) );
      sprintf( szBuf, "FORM    FTXTCHRS    %s", GL_szOutput );
      *( (ULONG *)&szBuf[4] ) = 12+uwLen;
      *( (ULONG *)&szBuf[16] ) = uwLen;
      MG.pClipIO->io_Offset = 0;
      MG.pClipIO->io_Error  = 0;
      MG.pClipIO->io_ClipID = 0;
      MG.pClipIO->io_Data    = (STRPTR)szBuf;
      MG.pClipIO->io_Length  = 8+12+uwLen;
      MG.pClipIO->io_Command = CMD_WRITE;
      DoIO( (struct IORequest *)MG.pClipIO );

      // tell clipboard we are done writing
      MG.pClipIO->io_Command = CMD_UPDATE;
      DoIO( (struct IORequest *)MG.pClipIO );

      return( RETURN_OK );
   }

   return( RETURN_ERROR );
}
LONG fnClipPaste()
{
   LONG   rc = RETURN_ERROR;    // assume failure
   char   szBuf[ 255+1 ];


   MG.pClipIO->io_Offset = 0;
   MG.pClipIO->io_Error  = 0;
   MG.pClipIO->io_ClipID = 0;
   MG.pClipIO->io_Data    = (STRPTR)szBuf;
   MG.pClipIO->io_Length  = 12;
   MG.pClipIO->io_Command = CMD_READ;
   DoIO( (struct IORequest *)MG.pClipIO );

   if ( MG.pClipIO->io_Actual == 12L )
   {
      if ( ( strncmp( &szBuf[0], "FORM", 4 ) == 0 ) &&
           ( strncmp( &szBuf[8], "FTXT", 4 ) == 0 ) )
      {
         ULONG  ulSize;
         BOOL   fLooking = TRUE;


         while ( fLooking )
         {
            fLooking = FALSE;

            MG.pClipIO->io_Data    = (STRPTR)szBuf;
            MG.pClipIO->io_Length  = 4;
            MG.pClipIO->io_Command = CMD_READ;
            DoIO( (struct IORequest *)MG.pClipIO );
            if ( MG.pClipIO->io_Actual == 4L )
            {
               if ( strncmp( szBuf, "CHRS", 4 ) == 0 )
               {
                  // read size of data that follows
                  MG.pClipIO->io_Data    = (STRPTR)szBuf;
                  MG.pClipIO->io_Length  = 4;
                  MG.pClipIO->io_Command = CMD_READ;
                  DoIO( (struct IORequest *)MG.pClipIO );
                  if ( MG.pClipIO->io_Actual == 4L )
                  {
                     // if more than 20, cutoff at 20...
                     ulSize = *( (ULONG *)szBuf );
                     if ( ulSize > 20 )   ulSize = 20;

                     memset( (char *)&szBuf, 0, sizeof( szBuf ) );

                     // read data from clipboard
                     MG.pClipIO->io_Data    = (STRPTR)szBuf;
                     MG.pClipIO->io_Length  = ulSize;
                     MG.pClipIO->io_Command = CMD_READ;
                     DoIO( (struct IORequest *)MG.pClipIO );
                     if ( MG.pClipIO->io_Actual == ulSize )
                     {
                        sprintf( GL_szInput, "%f", atof( szBuf ) );
                        JMH_Trim( GL_szInput, "0", 1 );
                        set( MAIN.TXT_Input, MUIA_Text_Contents, GL_szInput );
                        rc = RETURN_OK;
                     }
                  }
               }
               else
               {
                  // skip this chunk... move to next
                  // read size of data that follows
                  MG.pClipIO->io_Data    = (STRPTR)szBuf;
                  MG.pClipIO->io_Length  = 4;
                  MG.pClipIO->io_Command = CMD_READ;
                  DoIO( (struct IORequest *)MG.pClipIO );
                  if ( MG.pClipIO->io_Actual == 4L )
                  {
                     ulSize = *( (ULONG *)szBuf );
                     if ( ulSize & 1 ) ulSize++;

                     MG.pClipIO->io_Offset += ulSize;
                     fLooking = TRUE;
                  }
               }
            }
         }
      }
   }

   // read past end of data to tell clipboard we are done
   MG.pClipIO->io_Data    = (STRPTR)szBuf;
   MG.pClipIO->io_Length  = 254;
   MG.pClipIO->io_Command = CMD_READ;
   while ( MG.pClipIO->io_Actual )
      DoIO( (struct IORequest *)MG.pClipIO );

   return( rc );
}
void fnConvert()
{
   LONG    lFrom, lTo, lStat;
   double  dblFromFactor, dblToFactor, dblResult;
   char   *pszStat;


   get( MAIN.LIS_PopUnits, MUIA_List_Active, &lStat );
   get( MAIN.LIS_FromUnits, MUIA_List_Active, &lFrom );
   get( MAIN.LIS_ToUnits, MUIA_List_Active, &lTo );

   if ( ( lFrom != MUIV_List_Active_Off ) && ( lTo != MUIV_List_Active_Off ) )
   {
      dblFromFactor = (((MG.pBaseBase+lStat)->pUnitBase)+lFrom)->dblFactor;
      dblToFactor   = (((MG.pBaseBase+lStat)->pUnitBase)+lTo)->dblFactor;

      get( MAIN.TXT_Input, MUIA_Text_Contents, &pszStat );
      dblResult = atof( pszStat ) * dblToFactor / dblFromFactor;
      sprintf( GL_szOutput, "%.*f", MG.ubPrecision, dblResult );
      JMH_Trim( GL_szOutput, "0", 1 );
      set( MAIN.TXT_Output, MUIA_Text_Contents, GL_szOutput );
   }
}
void fnTokenizeValue( double dblTokenArray[], UWORD *puwTokenIndex )
{
   char *psz;


   // tokenize input value
   if ( *puwTokenIndex < 48 )
   {
      get( MAIN.TXT_Input, MUIA_Text_Contents, &psz );
      dblTokenArray[ (*puwTokenIndex)++ ] = atof( psz );
   }
   else
   {
      JMH_Error( "Expression too complex.", MG.WIN_Main,
                 "PROGDIR:convcalc.guide", "errors", 0 );
   }
}
void fnTokenizeToken( double dblToken, double dblTokenArray[], UWORD *puwTokenIndex )
{
   if ( *puwTokenIndex < 48 )
   {
      dblTokenArray[ (*puwTokenIndex)++ ] = dblToken;
   }
   else
   {
      JMH_Error( "Expression too complex.", MG.WIN_Main,
                 "PROGDIR:convcalc.guide", "errors", 0 );
   }
}
void fnRecalc( double dblTokenArray[], UWORD *puwTokenIndex )
{
   double  dblOpR[ 50 ],   // operators
           dblOpN[ 50 ];   // operands
   UWORD   uwOpRIndex = 0,
           uwOpNIndex = 0,
           uw;
   BOOL    fCont = TRUE;
   char   *pszDecimal = NULL;


   for ( uw = 0; uw < *puwTokenIndex; uw++ )
   {
      if ( dblTokenArray[ uw ] >= 0.0 )
      {
         dblOpN[ uwOpNIndex++ ] = dblTokenArray[ uw ];
      }
      else
      {
         if ( ( dblTokenArray[ uw ] == TOKEN_PLUS ) ||
              ( dblTokenArray[ uw ] == TOKEN_MINUS ) )
         {
            dblOpR[ uwOpRIndex++ ] = dblTokenArray[ uw ];
         }
         else if ( ( dblTokenArray[ uw ] == TOKEN_MULTIPLY ) ||
                   ( dblTokenArray[ uw ] == TOKEN_DIVIDE ) ||
                   ( dblTokenArray[ uw ] == TOKEN_EQUAL ) )
         {
            if ( ( dblTokenArray[ uw ] == TOKEN_EQUAL ) ||
                 ( ( uwOpRIndex > 0 ) &&
                   ( ( dblTokenArray[ uw-1 ] == TOKEN_PLUS ) ||
                     ( dblTokenArray[ uw-1 ] == TOKEN_MINUS )
                   )
                 )
               )
            {
               // take all previous stuff from stack and calculate
               // then put result back on OpN stack; reset indexes
               fCont = TRUE;

               do
               {
                  uwOpRIndex--;
                  if ( uwOpNIndex < 2 )
                  {
                     // stack error!
                     JMH_Error( "OpN Stack underflow!", NULL,
                                "PROGDIR:convcalc.guide", "errors", 0 );
                     fCont = FALSE;
                  }
                  if      ( dblOpR[ uwOpRIndex ] == TOKEN_PLUS )
                  {
                     dblOpN[ uwOpNIndex-2 ] = ( dblOpN[ uwOpNIndex-2 ] + dblOpN[ uwOpNIndex-1 ] );
                     uwOpNIndex--;
                  }
                  else if ( dblOpR[ uwOpRIndex ] == TOKEN_MINUS )
                  {
                     dblOpN[ uwOpNIndex-2 ] = ( dblOpN[ uwOpNIndex-2 ] - dblOpN[ uwOpNIndex-1 ] );
                     uwOpNIndex--;
                  }
                  else if ( dblOpR[ uwOpRIndex ] == TOKEN_MULTIPLY )
                  {
                     dblOpN[ uwOpNIndex-2 ] = ( dblOpN[ uwOpNIndex-2 ] * dblOpN[ uwOpNIndex-1 ] );
                     uwOpNIndex--;
                  }
                  else if ( dblOpR[ uwOpRIndex ] == TOKEN_DIVIDE )
                  {
                     if ( dblOpN[ uwOpNIndex-1 ] == 0.0 )
                     {
                        set( MAIN.TXT_Input, MUIA_Text_Contents, "*** DIV BY ZERO ***" );
                        fCont = FALSE;
                     }
                     else
                     {
                        dblOpN[ uwOpNIndex-2 ] = ( dblOpN[ uwOpNIndex-2 ] / dblOpN[ uwOpNIndex-1 ] );
                        uwOpNIndex--;
                     }
                  }
               }
               while ( ( uwOpRIndex > 0 ) && ( fCont ) );
            }
            else
            {
               // put the operator on the OpR stack for later...
               dblOpR[ uwOpRIndex++ ] = dblTokenArray[ uw ];
            }
         }
      }
   }

   if ( dblOpN[0] < 0.0 )
   {
      JMH_Error( "Negative result!", MG.WIN_Main,
                 "PROGDIR:convcalc.guide", "errors", 0 );
      set( MAIN.TXT_Input,  MUIA_Text_Contents, NULL );
      set( MAIN.TXT_Output, MUIA_Text_Contents, NULL );
      memset( (char *)&dblTokenArray, 0, sizeof( double ) * 50 );
      *puwTokenIndex = 0;
   }
   else
   {
      sprintf( GL_szInput, "%f", dblOpN[0] );
      if ( dblOpN[0] == floor( dblOpN[0] ) )
      {
         // if the number is 'whole', strip off the floating part
         pszDecimal = strchr( GL_szInput, '.' );
         if ( pszDecimal )    *pszDecimal = 0;
      }
   }
   if ( MG.fDecimalTyped == FALSE ) JMH_Trim( GL_szInput, "0", 1 );
   set( MAIN.TXT_Input, MUIA_Text_Contents, GL_szInput );
}


// ***********************************************************************
//
//    MAIN WINDOW
//
// ***********************************************************************
BOOL fnConstructMainWindow( void )
{
   APTR  menuptr;


   MG.WIN_Main = WindowObject,
      MUIA_Window_ID, MAKE_ID('M','A','I','N'),
      MUIA_Window_Title, "Conversion Calculator",
      MUIA_Window_AppWindow, TRUE,
      MUIA_Window_Menustrip, MG.menustrip = MUI_MakeObject( MUIO_MenustripNM, Menu_MainMenu, 0 ),
      MUIA_HelpNode, "mainwdw",
      WindowContents, VGroup,
         Child, HGroup,
            Child, KeyLabel1("Unit Category",'u'),
            Child, MAIN.POP_Units = PopobjectObject,
               MUIA_ControlChar, 'u',
               MUIA_Popstring_String, MAIN.TXT_PopText = TextObject, TextFrame,
                  End,
               MUIA_Popstring_Button, PopButton(MUII_PopUp),
               MUIA_Popobject_Object, MAIN.LIS_PopUnits = ListviewObject,
                  MUIA_Listview_List, ListObject, InputListFrame,
                     MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
                     MUIA_List_DestructHook,  MUIV_List_DestructHook_String,
                     End,
                  End,
               End,
            End,
         Child, ColGroup(2),
            Child, Label1("\33lInput"),
            Child, Label1("\33lOutput"),
            Child, MAIN.TXT_Input  = TextObject, TextFrame,
               MUIA_Background, MUII_TextBack,
               End,
            Child, MAIN.TXT_Output = TextObject, TextFrame,
               MUIA_Background, MUII_TextBack,
               End,
            Child, MAIN.LIS_FromUnits = ListviewObject,
               MUIA_Listview_MultiSelect, FALSE,
               MUIA_Listview_Input, TRUE,
               MUIA_Listview_List, ListObject,
                  InputListFrame,
                  MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
                  MUIA_List_DestructHook,  MUIV_List_DestructHook_String,
                  End,
               End,
            Child, MAIN.LIS_ToUnits = ListviewObject,
               MUIA_Listview_MultiSelect, FALSE,
               MUIA_Listview_Input, TRUE,
               MUIA_Listview_List, ListObject,
                  InputListFrame,
                  MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
                  MUIA_List_DestructHook,  MUIV_List_DestructHook_String,
                  End,
               End,
            End,
         Child, HGroup,
            Child, VGroup, GroupFrameT("Fractions"),
               MUIA_Group_SameSize, TRUE,
               Child, MAIN.BUT_Frac1_2  = SimpleButton("1/2"),
               Child, MAIN.BUT_Frac1_3  = SimpleButton("1/3"),
               Child, MAIN.BUT_Frac1_4  = SimpleButton("1/4"),
               Child, MAIN.BUT_Frac1_8  = SimpleButton("1/8"),
               Child, MAIN.BUT_Frac1_16 = SimpleButton("1/16"),
               End,
            Child, HSpace(0),
            Child, ColGroup(4), GroupFrameT("Keypad"),
               MUIA_Group_SameSize, TRUE,
               Child, MAIN.BUT_C        = KeyButton("C",'c'),
               Child, MAIN.BUT_CE       = KeyButton("CE",'e'),
               Child, MAIN.BUT_Divide   = KeyButtonNoBar("/",'/'),
               Child, MAIN.BUT_Multiply = KeyButtonNoBar("*",'*'),
               Child, MAIN.BUT_7        = KeyButtonNoBar("7",'7'),
               Child, MAIN.BUT_8        = KeyButtonNoBar("8",'8'),
               Child, MAIN.BUT_9        = KeyButtonNoBar("9",'9'),
               Child, MAIN.BUT_Minus    = KeyButtonNoBar("-",'-'),
               Child, MAIN.BUT_4        = KeyButtonNoBar("4",'4'),
               Child, MAIN.BUT_5        = KeyButtonNoBar("5",'5'),
               Child, MAIN.BUT_6        = KeyButtonNoBar("6",'6'),
               Child, MAIN.BUT_Plus     = KeyButtonNoBar("+",'+'),
               Child, MAIN.BUT_1        = KeyButtonNoBar("1",'1'),
               Child, MAIN.BUT_2        = KeyButtonNoBar("2",'2'),
               Child, MAIN.BUT_3        = KeyButtonNoBar("3",'3'),
               Child, HSpace(0),
               Child, MAIN.BUT_0        = KeyButtonNoBar("0",'0'),
               Child, HSpace(0),
               Child, MAIN.BUT_Decimal  = KeyButtonNoBar(".",'.'),
               Child, MAIN.BUT_Enter    = KeyButtonNoBar("=",'='),
               End,
            End,
         Child, HGroup,
            Child, HSpace(0),
            Child, MAIN.BUT_Calculate = KeyButton("Convert",'t'),
            Child, HSpace(0),
            End,
         End,
      End;

   // window failed?
   if ( !MG.WIN_Main )
   {
      return( FAILURE );
   }
   else
   {
      // make menu connections for ENV:
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREFSCLRVERIFY );
      set( menuptr, MUIA_ExportID, 101 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC1 );
      set( menuptr, MUIA_ExportID, 201 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC2 );
      set( menuptr, MUIA_ExportID, 202 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC3 );
      set( menuptr, MUIA_ExportID, 203 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC4 );
      set( menuptr, MUIA_ExportID, 204 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC5 );
      set( menuptr, MUIA_ExportID, 205 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC6 );
      set( menuptr, MUIA_ExportID, 206 );
      menuptr = (APTR)DoMethod( MG.menustrip, MUIM_FindUData, ID_MENU_PREC7 );
      set( menuptr, MUIA_ExportID, 207 );

      // make gadget connections
      DoMethod( MAIN.LIS_PopUnits, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
                MAIN.POP_Units, 2, MUIM_Popstring_Close, TRUE );

      DoMethod( MG.WIN_Main, MUIM_Notify, MUIA_AppMessage, MUIV_EveryTime,
                MG.App, 3, MUIM_CallHook, &AppMsgHook, MUIV_TriggerValue );

      DoMethod( MG.WIN_Main, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
                MG.App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit );

      DoMethod( MAIN.LIS_PopUnits, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_POP_UNITS );

      // setup menus to return state of precision MutEx items...
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC1, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC1 );
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC2, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC2 );
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC3, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC3 );
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC4, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC4 );
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC5, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC5 );
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC6, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC6 );
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuAction, ID_MENU_PREC7, MG.App, 2, MUIM_Application_ReturnID, ID_MENU_PREC7 );

      DoMethod( MAIN.BUT_Frac1_2,   MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_FRAC1_2 );
      DoMethod( MAIN.BUT_Frac1_3,   MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_FRAC1_3 );
      DoMethod( MAIN.BUT_Frac1_4,   MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_FRAC1_4 );
      DoMethod( MAIN.BUT_Frac1_8,   MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_FRAC1_8 );
      DoMethod( MAIN.BUT_Frac1_16,  MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_FRAC1_16 );
      DoMethod( MAIN.BUT_C,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_C );
      DoMethod( MAIN.BUT_CE,        MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_CE );
      DoMethod( MAIN.BUT_Divide,    MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_DIVIDE );
      DoMethod( MAIN.BUT_Multiply,  MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_MULTIPLY );
      DoMethod( MAIN.BUT_7,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_7 );
      DoMethod( MAIN.BUT_8,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_8 );
      DoMethod( MAIN.BUT_9,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_9 );
      DoMethod( MAIN.BUT_Minus,     MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_MINUS );
      DoMethod( MAIN.BUT_4,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_4 );
      DoMethod( MAIN.BUT_5,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_5 );
      DoMethod( MAIN.BUT_6,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_6 );
      DoMethod( MAIN.BUT_Plus,      MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_Plus );
      DoMethod( MAIN.BUT_1,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_1 );
      DoMethod( MAIN.BUT_2,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_2 );
      DoMethod( MAIN.BUT_3,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_3 );
      DoMethod( MAIN.BUT_0,         MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_0 );
      DoMethod( MAIN.BUT_Decimal,   MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_DECIMAL );
      DoMethod( MAIN.BUT_Enter, MUIM_Notify, MUIA_Pressed, FALSE,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_EQUAL );
      DoMethod( MAIN.LIS_ToUnits, MUIM_Notify, MUIA_Listview_DoubleClick, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_LIS_CALCULATE );
      DoMethod( MAIN.BUT_Calculate, MUIM_Notify, MUIA_Pressed, FALSE,
                MG.App, 2, MUIM_Application_ReturnID, ID_LIS_CALCULATE );

      // set up help for menus
      DoMethod( MG.App, MUIM_Notify, MUIA_Application_MenuHelp, MUIV_EveryTime,
                MG.App, 5, MUIM_Application_ShowHelp, MG.WIN_Main, "PROGDIR:convcalc.guide", "mainmenus", 0 );

      // set tab cycle chain
      DoMethod( MG.WIN_Main, MUIM_Window_SetCycleChain,
                MAIN.LIS_FromUnits,
                MAIN.LIS_ToUnits,
                MAIN.BUT_Calculate,
                NULL );

      // add window to Application object
      DoMethod( MG.App, OM_ADDMEMBER, MG.WIN_Main );

      return( SUCCESS );
   }
}


/*
 * LIST HOOK FUNCTIONS ------------------------------
 */
SAVEDS ASM APTR fnUDfnConstructFunc(REG(a0) struct Hook *hook, REG(a2) APTR mempool, REG(a1) char *pszText )
{
   struct UnitDefnNode *pNew;
   char          *psz;


   if ( pNew = AllocVec( sizeof( struct UnitDefnNode ), MEMF_ANY | MEMF_CLEAR ) )
   {
      psz = strchr( pszText, 255 );
      if ( psz )
      {
         *psz = 0;
         strcpy( pNew->szUnitName  , pszText );
         strcpy( pNew->szUnitFactor, psz+1   );
      }

      return( pNew );
   }
   else
   {
      return( NULL );
   }
}
static struct Hook hUDfnConstructHook =
{
   {NULL, NULL},
   (void *)fnUDfnConstructFunc,
   NULL, NULL
};

SAVEDS ASM VOID fnUDfnDestructFunc(REG(a0) struct Hook *hook, REG(a2) APTR mempool, REG(a1) struct UnitDefnNode *pNode )
{
   FreeVec( pNode );
}
static struct Hook hUDfnDestructHook = {
   {NULL, NULL},
   (void *)fnUDfnDestructFunc,
   NULL, NULL
};

SAVEDS ASM LONG fnUDfnCompareFunc( REG(a0) struct Hook *hook, REG(a1) struct UnitDefnNode *pUDNode1, REG(a2) struct UnitDefnNode *pUDNode2 )
{
   LONG   rc = NULL;


   if ( pUDNode1 && pUDNode2 )
   {
      rc = strcmp( pUDNode1->szUnitName, pUDNode2->szUnitName );
      if ( rc == 0 )
      {
         rc = strcmp( pUDNode1->szUnitFactor, pUDNode2->szUnitFactor );
      }
   }
   else
   {
      rc = 0;
   }

   return( rc );
}
static struct Hook hUDfnCompareHook = {
   {NULL, NULL},
   (void *)fnUDfnCompareFunc,
   NULL, NULL
};

SAVEDS ASM LONG fnUDfnDisplayFunc(REG(a0) struct Hook *hook,REG(a2) char **array,REG(a1) struct UnitDefnNode *pUDNode )
{
   if ( pUDNode )
   {
      //
      // display data
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      *array++ = pUDNode->szUnitName;
      *array   = pUDNode->szUnitFactor;
   }
   else
   {
      //
      // display list title
      // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      *array++ = "\33bName";
      *array   = "\33bFactor";
   }

   return(0);
}
static struct Hook hUDfnDisplayHook = {
   {NULL, NULL},
   (void *)fnUDfnDisplayFunc,
   NULL, NULL
};


//
// UNIT DEFINITION WINDOW ------------------------------------------------
//
BOOL fnConstructUDfnWindow( void )
{
   MG.WIN_UDfn = WindowObject,
      MUIA_Window_ID, MAKE_ID('U','D','F','N'),
      MUIA_Window_Title, "Unit Definition",
      MUIA_Window_Menu, (APTR)Menu_MainMenu,
      MUIA_HelpNode, "unitdefnwdw",
      WindowContents, VGroup,
         Child, ColGroup(2),
            Child, KeyLabel1("Base Unit",'b'),
            Child, UDFN.STR_BaseUnit = StringObject, StringFrame,
               MUIA_String_AttachedList, UDFN.LIS_PopList,
               MUIA_ControlChar, 'b',
               MUIA_String_Format, MUIV_String_Format_Left,
               MUIA_String_MaxLen, 20+1,
               MUIA_String_Contents, NULL,
               End,
            Child, Label1("Base Name"),
            Child, UDFN.POP_BasePopper = PopobjectObject,
               MUIA_Popstring_String, UDFN.STR_BaseName = StringObject, StringFrame,
                  MUIA_String_AttachedList, UDFN.LIS_PopList,
                  MUIA_String_Format, MUIV_String_Format_Left,
                  MUIA_String_MaxLen, 20+1,
                  MUIA_String_Contents, NULL,
                  End,
               MUIA_Popstring_Button, PopButton(MUII_PopUp),
               MUIA_Popobject_Object, VGroup,
                  Child, UDFN.LIS_PopList = ListviewObject,
                     MUIA_Listview_List, ListObject, InputListFrame,
                        MUIA_List_ConstructHook, MUIV_List_ConstructHook_String,
                        MUIA_List_DestructHook,  MUIV_List_DestructHook_String,
                        End,
                     End,
                  End,
               End,
            End,
         Child, UDFN.LIS_UnitList = ListviewObject,
            MUIA_Listview_Input, TRUE,
            MUIA_Listview_List, ListObject,
               InputListFrame,
               MUIA_List_CompareHook,   &hUDfnCompareHook,
               MUIA_List_ConstructHook, &hUDfnConstructHook,
               MUIA_List_DestructHook,  &hUDfnDestructHook,
               MUIA_List_DisplayHook,   &hUDfnDisplayHook,
               MUIA_List_Format, "D=10 COL=0,D=10 COL=1",
               MUIA_List_Title, TRUE,
               End,
            End,
         Child, HGroup,
            Child, UDFN.BUT_UnitsNew = KeyButton("New",'n'),
            Child, UDFN.BUT_UnitsDel = KeyButton("Del",'d'),
            Child, HSpace(0),
            End,
         Child, VSpace(0),
         Child, HGroup,
            Child, Label1("Name"),
            Child, UDFN.STR_UnitName = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Left,
               MUIA_String_MaxLen, 20+1,
               MUIA_String_Contents, NULL,
               MUIA_String_AttachedList, UDFN.LIS_UnitList,
               End,
            Child, HSpace(0),
            Child, Label1("Factor"),
            Child, UDFN.STR_UnitFactor = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Left,
               MUIA_String_MaxLen, 12+1,
               MUIA_String_Contents, NULL,
               MUIA_String_AttachedList, UDFN.LIS_UnitList,
               End,
            End,
         Child, VSpace(0),
         Child, HGroup,
            Child, UDFN.BUT_OK     = KeyButton("OK",'o'),
            Child, HSpace(0),
            Child, UDFN.BUT_Cancel = SimpleButton("Cancel"),
            End,
         End,
      End;

   // window failed?
   if ( !MG.WIN_UDfn )
   {
      return( FAILURE );
   }
   else
   {
      // make gadget connections
      DoMethod( UDFN.LIS_PopList, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE,
                UDFN.POP_BasePopper, 2, MUIM_Popstring_Close, TRUE );

      DoMethod( MG.WIN_UDfn, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
                MG.App, 2, MUIM_Application_ReturnID, ID_UDFN_CLOSEWINDOW );

      DoMethod( UDFN.BUT_UnitsNew, MUIM_Notify, MUIA_Pressed, FALSE,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNUNITSNEW );
      DoMethod( UDFN.BUT_UnitsDel, MUIM_Notify, MUIA_Pressed, FALSE,
                UDFN.LIS_UnitList, 2, MUIM_List_Remove, MUIV_List_Remove_Active );
      DoMethod( UDFN.LIS_UnitList, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_LIS_UDFNUPDATE );
      DoMethod( UDFN.LIS_PopList, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_LIS_UDFNPOPUPDATE );

      DoMethod( UDFN.STR_BaseName, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNBASENAMEACK );
      DoMethod( UDFN.STR_BaseUnit, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNBASEACK );
      DoMethod( UDFN.STR_UnitName, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNNAMEACK );
      DoMethod( UDFN.STR_UnitFactor, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNFACTORACK );

      DoMethod( UDFN.BUT_OK    , MUIM_Notify, MUIA_Pressed, FALSE, MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNOK );
      DoMethod( UDFN.BUT_Cancel, MUIM_Notify, MUIA_Pressed, FALSE, MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UDFNCANCEL  );

      // set tab cycle chain
      DoMethod( MG.WIN_UDfn, MUIM_Window_SetCycleChain,
                UDFN.STR_BaseUnit,
                UDFN.STR_BaseName,
                UDFN.LIS_PopList,
                UDFN.LIS_UnitList,
                UDFN.BUT_UnitsNew,
                UDFN.BUT_UnitsDel,
                UDFN.STR_UnitName,
                UDFN.STR_UnitFactor,
                UDFN.BUT_OK,
                UDFN.BUT_Cancel,
                NULL );

      // add window to Application object
      DoMethod( MG.App, OM_ADDMEMBER, MG.WIN_UDfn );

      return( SUCCESS );
   }
}


/**
 ** M A I N   P R O G R A M -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 **/
void main( int argc, char *argv[] )
{
   ULONG   signals = 0;
   ULONG   ulInputEvent;
   ULONG   ulVerify;
   LONG    lOldPopActive = 0;
   BPTR    tmplock;

   struct WBStartup    *WBenchMsg = NULL;
   struct WBArg        *pWBArg    = NULL;

   struct UnitDefnNode *pUDFNNode;

   // generic status vars...
   LONG    lStat;
   UBYTE  *pszStat, *pszStat2;


   //
   // setup variables, read startup params, etc...
   // also create application object
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   JMH_Startup( argc, argv );
   memset( (char *)&TList, 0, sizeof( double ) * 50 );
   MG.ubPrecision = 4;

   //
   // construct all windows
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( fnConstructMainWindow() == FAILURE )
   {
      JMH_Quit( "Failed to create Main window." );
   }
   if ( fnConstructUDfnWindow() == FAILURE )
   {
      JMH_Quit( "Failed to create Unit Definition window." );
   }

   //
   // read settings
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   DoMethod( MG.App, MUIM_Application_Load, MUIV_Application_Load_ENV );

   //
   // init bases
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   for ( lStat = 0; lStat < MAX_BASE_COUNT; lStat++ )
   {
      strcpy( (MG.pBaseBase+lStat)->szBaseName, "Unused" );
      strcpy( (MG.pBaseBase+lStat)->szBaseUnit, "Undefined" );
      (MG.pBaseBase+lStat)->uwNumUnits = 0;
      (MG.pBaseBase+lStat)->pUnitBase  = NULL;
   }
   MG.uwNumBases = MAX_BASE_COUNT - 1;
   fnFillListWithBases( UDFN.LIS_PopList );
   fnFillListWithBases( MAIN.LIS_PopUnits );

   strcpy( MG.szProjectSpec, "" );

   //
   // setup then open main window
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   set( MG.WIN_Main, MUIA_Window_ActiveObject,  MAIN.LIS_FromUnits );
   set( MG.WIN_Main, MUIA_Window_DefaultObject, MAIN.LIS_FromUnits );

   set( MAIN.TXT_Input,  MUIA_Text_Contents, NULL );
   set( MAIN.TXT_Output, MUIA_Text_Contents, NULL );

   set( MAIN.LIS_FromUnits, MUIA_List_Active, 0 );
   set( MAIN.LIS_ToUnits  , MUIA_List_Active, 0 );
   set( MAIN.LIS_PopUnits , MUIA_List_Active, 0 );

   set( MG.WIN_Main, MUIA_Window_Open, TRUE );

   pszStat = FindToolType( MG.dobj_App->do_ToolTypes, "CLEARVERIFY" );
   if ( strcmpi( pszStat, "TRUE" ) == 0 )
   {
      DoMethod( MG.App, MUIM_Application_SetMenuCheck, ID_MENU_PREFSCLRVERIFY, TRUE );
   }

   //
   // if we're passed a data file, load it
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( argc > 1 )
   {
      fnReadData( argv[1] );

      set( MAIN.TXT_PopText, MUIA_Text_Contents, (MG.pBaseBase+0)->szBaseName );
      set( MAIN.LIS_FromUnits, MUIA_List_Quiet, TRUE );
      set( MAIN.LIS_ToUnits,   MUIA_List_Quiet, TRUE );
      DoMethod( MAIN.LIS_FromUnits, MUIM_List_Clear, TRUE );
      DoMethod( MAIN.LIS_ToUnits,   MUIM_List_Clear, TRUE );
      fnFillListWithUnits( MAIN.LIS_FromUnits, 0 );
      fnFillListWithUnits( MAIN.LIS_ToUnits  , 0 );
      set( MAIN.LIS_FromUnits, MUIA_List_Active, 0 );
      set( MAIN.LIS_ToUnits,   MUIA_List_Active, 0 );
      set( MAIN.LIS_FromUnits, MUIA_List_Quiet, FALSE );
      set( MAIN.LIS_ToUnits,   MUIA_List_Quiet, FALSE );

      set( MAIN.LIS_PopUnits,  MUIA_List_Active, 0 );
   }
   else
   {
      WBenchMsg   = (struct WBStartup *)argv;
      pWBArg      = WBenchMsg->sm_ArgList;

      pWBArg++;   // get first parameter

      if ( pWBArg )
      {
         if ( ( pWBArg->wa_Lock ) && ( *pWBArg->wa_Name ) )
         {
            tmplock  = Lock( pWBArg->wa_Name, ACCESS_READ );
            NameFromLock( tmplock, GL_szBuf, FMSIZE );
            fnReadData( GL_szBuf );
            UnLock( tmplock );

            set( MAIN.TXT_PopText, MUIA_Text_Contents, (MG.pBaseBase+0)->szBaseName );
            set( MAIN.LIS_FromUnits, MUIA_List_Quiet, TRUE );
            set( MAIN.LIS_ToUnits,   MUIA_List_Quiet, TRUE );
            DoMethod( MAIN.LIS_FromUnits, MUIM_List_Clear, TRUE );
            DoMethod( MAIN.LIS_ToUnits,   MUIM_List_Clear, TRUE );
            fnFillListWithUnits( MAIN.LIS_FromUnits, 0 );
            fnFillListWithUnits( MAIN.LIS_ToUnits  , 0 );
            set( MAIN.LIS_FromUnits, MUIA_List_Active, 0 );
            set( MAIN.LIS_ToUnits,   MUIA_List_Active, 0 );
            set( MAIN.LIS_FromUnits, MUIA_List_Quiet, FALSE );
            set( MAIN.LIS_ToUnits,   MUIA_List_Quiet, FALSE );

            set( MAIN.LIS_PopUnits,  MUIA_List_Active, 0 );
         }
      }
   }

   set( MAIN.TXT_PopText, MUIA_Text_Contents, (MG.pBaseBase)->szBaseName );

   //
   // show 'em what it's all 'About'
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   JMH_About();

   MG.running = TRUE;

   //
   //   MAIN LOOP          MAIN LOOP         MAIN LOOP         MAIN LOOP
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   while ( MG.running )
   {
      ulInputEvent = DoMethod( MG.App, MUIM_Application_Input, &signals );
      switch ( ulInputEvent )
      {
         case MUIV_Application_ReturnID_Quit:
         case ID_MENU_QUIT:
            if ( MUI_Request( MG.App, MG.WIN_Main, 0, NULL, "Yes|*No",
                              "Are you sure you want to quit?", NULL ) == 1 )
            {
               MG.running = FALSE;
            }
            break;

         // MENUS ---------------------------------------------
            case ID_MENU_NEW:
               fnClear();
               break;
            case ID_MENU_OPEN:
               DoMethod( UDFN.LIS_PopList , MUIM_List_Clear, TRUE );
               DoMethod( MAIN.LIS_PopUnits, MUIM_List_Clear, TRUE );
               fnReadData( NULL );
               set( MAIN.LIS_PopUnits, MUIA_List_Active, 1 );
               set( MAIN.LIS_PopUnits, MUIA_List_Active, 0 );
               break;
            case ID_MENU_SAVE:
               fnWriteData( FALSE );
               break;
            case ID_MENU_SAVEAS:
               fnWriteData( TRUE );
               break;
            case ID_MENU_ABOUT:
               JMH_About();
               break;
            case ID_MENU_EDITCOPY:
               fnClipCopy();
               break;
            case ID_MENU_EDITPASTE:
               fnClipPaste();
               break;
//            case ID_MENU_RUNMACRO:
//MUI_Request( MG.App, MG.WIN_Main, 0, NULL, "*OK", "MAIN:RunMacro", NULL );
//               break;
            case ID_MENU_PREFSSAVE:
               DoMethod( MG.App, MUIM_Application_Save, MUIV_Application_Save_ENVARC );
               break;
            case ID_MENU_SETUNITDEFNS:
               get( UDFN.LIS_PopList, MUIA_List_Active, &lStat );
               if ( lStat == MUIV_List_Active_Off )
               {
                  set( UDFN.LIS_PopList, MUIA_List_Active, 0 );
               }
               set( MG.WIN_Main, MUIA_Window_Sleep, TRUE );
               set( MG.WIN_UDfn, MUIA_Window_Open, TRUE );
               break;
            case ID_MENU_PREC1:  MG.ubPrecision = 1;  break;
            case ID_MENU_PREC2:  MG.ubPrecision = 2;  break;
            case ID_MENU_PREC3:  MG.ubPrecision = 3;  break;
            case ID_MENU_PREC4:  MG.ubPrecision = 4;  break;
            case ID_MENU_PREC5:  MG.ubPrecision = 5;  break;
            case ID_MENU_PREC6:  MG.ubPrecision = 6;  break;
            case ID_MENU_PREC7:  MG.ubPrecision = 7;  break;

         // GADGETS -------------------------------------------
            case ID_BUT_FRAC1_2:    fnAddFraction( 0.5      ); break;
            case ID_BUT_FRAC1_3:    fnAddFraction( 0.333333 ); break;
            case ID_BUT_FRAC1_4:    fnAddFraction( 0.25     ); break;
            case ID_BUT_FRAC1_8:    fnAddFraction( 0.125    ); break;
            case ID_BUT_FRAC1_16:   fnAddFraction( 0.0625   ); break;
            case ID_BUT_C:
               ulVerify = (ULONG)DoMethod( MG.App, MUIM_Application_GetMenuCheck, ID_MENU_PREFSCLRVERIFY );
               if ( ulVerify )
               {
                  if ( MUI_Request( MG.App, MG.WIN_Main, 0, NULL, "Yes|*No",
                                   "Are you sure you want to clear?", NULL ) == 1 )
                  {
                     fnClear();
                  }
               }
               else
               {
                  fnClear();
               }
               break;
            case ID_BUT_CE:
               set( MAIN.TXT_Input,  MUIA_Text_Contents, NULL );
               MG.fStartNewNumber = TRUE;
               MG.fDecimalTyped = FALSE;
               break;
            case ID_BUT_DIVIDE:
               fnTokenizeValue( TList, &uwTokenIndex );
               fnTokenizeToken( TOKEN_DIVIDE, TList, &uwTokenIndex );
               fnRecalc( TList, &uwTokenIndex );
               MG.fStartNewNumber = TRUE;
               MG.fDecimalTyped = FALSE;
               break;
            case ID_BUT_MULTIPLY:
               fnTokenizeValue( TList, &uwTokenIndex );
               fnTokenizeToken( TOKEN_MULTIPLY, TList, &uwTokenIndex );
               fnRecalc( TList, &uwTokenIndex );
               MG.fStartNewNumber = TRUE;
               MG.fDecimalTyped = FALSE;
               break;
            case ID_BUT_MINUS:
               fnTokenizeValue( TList, &uwTokenIndex );
               fnTokenizeToken( TOKEN_MINUS, TList, &uwTokenIndex );
               fnRecalc( TList, &uwTokenIndex );
               MG.fStartNewNumber = TRUE;
               MG.fDecimalTyped = FALSE;
               break;
            case ID_BUT_Plus:
               fnTokenizeValue( TList, &uwTokenIndex );
               fnTokenizeToken( TOKEN_PLUS, TList, &uwTokenIndex );
               fnRecalc( TList, &uwTokenIndex );
               MG.fStartNewNumber = TRUE;
               MG.fDecimalTyped = FALSE;
               break;
            case ID_BUT_EQUAL:
               fnTokenizeValue( TList, &uwTokenIndex );
               fnTokenizeToken( TOKEN_EQUAL, TList, &uwTokenIndex );
               fnRecalc( TList, &uwTokenIndex );
               TList[0] = atof( GL_szInput );
               uwTokenIndex = 0;
               MG.fStartNewNumber = TRUE;
               MG.fDecimalTyped = FALSE;
               break;

            case ID_BUT_7:       fnAddDigit( "7" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_8:       fnAddDigit( "8" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_9:       fnAddDigit( "9" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_4:       fnAddDigit( "4" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_5:       fnAddDigit( "5" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_6:       fnAddDigit( "6" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_1:       fnAddDigit( "1" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_2:       fnAddDigit( "2" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_3:       fnAddDigit( "3" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_0:       fnAddDigit( "0" );   MG.fStartNewNumber = FALSE;   break;
            case ID_BUT_DECIMAL:
               if ( MG.fDecimalTyped == FALSE )
               {
                  MG.fDecimalTyped = TRUE;
                  if ( MG.fStartNewNumber )
                  {
                     strcpy( GL_szInput, "." );
                  }
                  else
                  {
                     strcat( GL_szInput, "." );
                  }
                  set( MAIN.TXT_Input, MUIA_Text_Contents, GL_szInput );
                  MG.fStartNewNumber = FALSE;
               }
               break;

            case ID_LIS_CALCULATE:
               fnConvert();
               break;

            case ID_POP_UNITS:
               get( MAIN.LIS_PopUnits, MUIA_List_Active, &lStat );
               set( MAIN.TXT_PopText, MUIA_Text_Contents, (MG.pBaseBase+lStat)->szBaseName );
               set( MAIN.LIS_FromUnits, MUIA_List_Quiet, TRUE );
               set( MAIN.LIS_ToUnits,   MUIA_List_Quiet, TRUE );
               DoMethod( MAIN.LIS_FromUnits, MUIM_List_Clear, TRUE );
               DoMethod( MAIN.LIS_ToUnits,   MUIM_List_Clear, TRUE );
               fnFillListWithUnits( MAIN.LIS_FromUnits, lStat );
               fnFillListWithUnits( MAIN.LIS_ToUnits  , lStat );
               set( MAIN.LIS_FromUnits, MUIA_List_Active, 0 );
               set( MAIN.LIS_ToUnits,   MUIA_List_Active, 0 );
               set( MAIN.LIS_FromUnits, MUIA_List_Quiet, FALSE );
               set( MAIN.LIS_ToUnits,   MUIA_List_Quiet, FALSE );
               break;

         // UDFN WINDOW ---------------------------------------
            case ID_UDFN_CLOSEWINDOW:
            case ID_BUT_UDFNCANCEL:
               set( MG.WIN_UDfn, MUIA_Window_Open, FALSE );
               set( MG.WIN_Main, MUIA_Window_Sleep, FALSE );
               break;
            case ID_LIS_UDFNUPDATE:
               get( UDFN.LIS_UnitList, MUIA_List_Active, &lStat );
               if ( lStat != MUIV_List_Active_Off )
               {
                  DoMethod( UDFN.LIS_UnitList, MUIM_List_GetEntry, lStat, &pUDFNNode );
                  set( UDFN.STR_UnitName  , MUIA_String_Contents, pUDFNNode->szUnitName   );
                  set( UDFN.STR_UnitFactor, MUIA_String_Contents, pUDFNNode->szUnitFactor );
               }
               else
               {
                  set( UDFN.STR_UnitName  , MUIA_String_Contents, NULL );
                  set( UDFN.STR_UnitFactor, MUIA_String_Contents, NULL );
               }
               break;
            case ID_LIS_UDFNPOPUPDATE:
               get( UDFN.LIS_PopList, MUIA_List_Active, &lStat );
               set( UDFN.STR_BaseName, MUIA_String_Contents, (MG.pBaseBase+lStat)->szBaseName );
               set( UDFN.STR_BaseUnit, MUIA_String_Contents, (MG.pBaseBase+lStat)->szBaseUnit );

               // store old units back in data struct
               fnReallocList( UDFN.LIS_UnitList, lOldPopActive );
               DoMethod( UDFN.LIS_UnitList, MUIM_List_Clear, TRUE );
               fnFillUDfnList( UDFN.LIS_UnitList, (UWORD)lStat );

               lOldPopActive = lStat;
               break;
            case ID_BUT_UDFNUNITSNEW:
               sprintf( GL_szBuf, "( new )%c", 255 );
               DoMethod( UDFN.LIS_UnitList, MUIM_List_InsertSingle, GL_szBuf, MUIV_List_Insert_Bottom );
               set( UDFN.LIS_UnitList, MUIA_List_Active, MUIV_List_Active_Bottom );
               set( MG.WIN_UDfn, MUIA_Window_ActiveObject, UDFN.STR_UnitName );
               break;
            case ID_BUT_UDFNNAMEACK:
            case ID_BUT_UDFNFACTORACK:
               get( UDFN.LIS_UnitList, MUIA_List_Active, &lStat );
               get( UDFN.STR_UnitName, MUIA_String_Contents, &pszStat );
               get( UDFN.STR_UnitFactor, MUIA_String_Contents, &pszStat2 );
               DoMethod( UDFN.LIS_UnitList, MUIM_List_Remove, lStat );
               sprintf( GL_szBuf, "%s%c%s", pszStat, 255, pszStat2 );
               DoMethod( UDFN.LIS_UnitList, MUIM_List_InsertSingle, GL_szBuf, lStat );
               break;
            case ID_BUT_UDFNBASEACK:
            case ID_BUT_UDFNBASENAMEACK:
               get( UDFN.LIS_PopList, MUIA_List_Active, &lStat );
               get( UDFN.STR_BaseUnit, MUIA_String_Contents, &pszStat );
               strcpy( (MG.pBaseBase+lStat)->szBaseUnit, pszStat );

               get( UDFN.LIS_PopList, MUIA_List_Active, &lStat );
               get( UDFN.STR_BaseName, MUIA_String_Contents, &pszStat );
               strcpy( (MG.pBaseBase+lStat)->szBaseName, pszStat );
               DoMethod( UDFN.LIS_PopList, MUIM_List_Remove, lStat );
               DoMethod( UDFN.LIS_PopList, MUIM_List_InsertSingle, pszStat, lStat );
               set( UDFN.LIS_PopList, MUIA_List_Active, lStat );
               break;
            case ID_BUT_UDFNOK:
               get( UDFN.LIS_PopList, MUIA_List_Active, &lStat );
               fnReallocList( UDFN.LIS_UnitList, lStat );
               set( MG.WIN_UDfn, MUIA_Window_Open, FALSE );
               set( MG.WIN_Main, MUIA_Window_Sleep, FALSE );
               DoMethod( MAIN.LIS_PopUnits, MUIM_List_Clear, TRUE );
               fnFillListWithBases( MAIN.LIS_PopUnits );
               set( MAIN.LIS_PopUnits, MUIA_List_Active, 1 );
               set( MAIN.LIS_PopUnits, MUIA_List_Active, 0 );
               break;
      }
      if ( MG.running && signals ) Wait(signals);
   }

   set( MG.WIN_Main, MUIA_Window_Open, FALSE );
   JMH_Quit(NULL);
}
