/*
 * MUILabeler   (C) 1994 Software Sculptors
 *                  All Rights Under Copyright Reserved
 *
 * Version 1.3
 *
 * Written using SAS/C 6.51
 * Using Magic User Interface (MUI) by Stefan Stuntz
 *
 * By John M. Haubrich, Jr.
 *
 *
 * Version~ Date~~~~~~~ Comments~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * -------  ----        --------
 *    0.0   JUL 04 1994 First MUI version.
 *    1.3   MAY 28 1995 Added a Test button and printer settings.
 *             ;
 *
 */

#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)"Print",                    (STRPTR)"P", 0, 0L, (APTR)ID_MENU_PRINT,
   NM_ITEM, (STRPTR)"Printer Setup...",                NULL, 0, 0L, (APTR)ID_MENU_PRINTERSETUP,
   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_CUT,
   NM_ITEM, (STRPTR)"Copy",                     (STRPTR)"C", 0, 0L, (APTR)ID_MENU_COPY,
   NM_ITEM, (STRPTR)"Paste",                    (STRPTR)"V", 0, 0L, (APTR)ID_MENU_PASTE,
   NM_TITLE, (STRPTR)"Settings",                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Device settings...",              NULL, 0, 0L, (APTR)ID_MENU_SETCON,
   NM_ITEM, (STRPTR)NM_BARLABEL,                       NULL, 0, 0L, NULL,
   NM_ITEM, (STRPTR)"Load Settings",                   NULL, 0, 0L, (APTR)ID_MENU_SETLOAD,
   NM_ITEM, (STRPTR)"Save Settings",                   NULL, 0, 0L, (APTR)ID_MENU_SETSAVE,
   NM_ITEM, (STRPTR)"Save Settings As...",             NULL, 0, 0L, (APTR)ID_MENU_SETSAVEAS,
   NM_END, NULL, NULL, 0, 0L, NULL };


/*
 * GLOBAL VARIABLES ---------------------------------
 */
struct MyGlobals       MG;
struct MainWindow      MAIN;
struct SettingsWindow  SETT;

char  GL_szBuf[ 256 ];
char  GL_szFault[ 512 ];


// for disk write routine...
USHORT chip ImageData1[] =
{
	0x0000,0x0000,0x0000,0x0400,0x7FFF,0xFFFF,0xFFFF,0xFC00,
	0x7FFF,0x0000,0x0FFF,0xFC00,0x7FFF,0x4000,0x03FF,0xFC00,
	0x5000,0x0000,0x0000,0x5400,0x77FF,0xFFFF,0xFFFF,0xFC00,
	0x560F,0xE1F8,0x0FC3,0xD400,0x6667,0xCCF8,0x0F99,0xEC00,
	0x5667,0xC0FE,0x3F81,0xD400,0x2667,0xCCFE,0x3F99,0xEC00,
	0x560F,0xCCFE,0x3F99,0xD400,0x07FF,0xFFFF,0xFFFF,0xC400,
	0x47FF,0xFFFF,0xFFFF,0xC400,0x0001,0x4FB0,0x0100,0x0400,
	0x0015,0x0000,0x0554,0x0400,0x002C,0x4000,0x012A,0x4400,
	0x0059,0x2492,0x4915,0x4400,0x02C9,0x2492,0x4920,0xC400,
	0x0000,0x0000,0x003F,0x8400,0x00AA,0xAAAA,0xAAAA,0x8400,
	0x0055,0x57FF,0xFFD5,0x8400,0x00BC,0xAB20,0x9249,0x8400,
	0x0055,0x5761,0xBE54,0x8400,0x00AA,0xAA00,0x000B,0x0400,
	0x03FF,0xFFFF,0xFFFD,0x0400,0x0155,0x5555,0x5556,0x0400,
	0x00FF,0xFFFF,0xFFFE,0x0400,0x007F,0xFFFF,0xFFFC,0x0400,
	0xFFFF,0xFFFF,0xFFFF,0xFC00,0xFFFF,0xFFFF,0xFFFF,0xF800,
	0x8000,0x0000,0x0000,0x0000,0x8000,0xFFFF,0xF000,0x0000,
	0x8000,0xFFFF,0xFC00,0x0000,0x8FFF,0xFFFF,0xFFFF,0x8000,
	0x8FFF,0xFFFF,0xFFFF,0x8000,0x8FFF,0xFFFF,0xFFFF,0x8000,
	0x8FFF,0xFFFF,0xFFFF,0x8000,0x8FFF,0xFFFF,0xFFFF,0x8000,
	0x8FFF,0xFFFF,0xFFFF,0x8000,0x8FFF,0xFFFF,0xFFFF,0x8000,
	0x8FFF,0xFFFF,0xFFFF,0x8000,0x8000,0x0000,0x0000,0x0000,
	0x803F,0xF04F,0xFFF0,0x0000,0x806B,0xFFFF,0xFFA8,0x0000,
	0x80D4,0xFFFF,0xFF15,0xC000,0x81A9,0x2492,0x490A,0xC000,
	0x8120,0x0000,0x001F,0xC000,0x83FF,0xFFFF,0xFFC0,0x8000,
	0x8355,0x5555,0x5555,0x8000,0x83BA,0xA9FF,0xFFAA,0x8000,
	0x835B,0x5541,0xA436,0x0000,0x83AA,0xA901,0x802A,0x8000,
	0x8355,0x55FF,0xFFF4,0x0000,0x8000,0x0000,0x0001,0x0000,
	0x80AA,0xAAAA,0xAAA8,0x0000,0x80AA,0xAAAA,0xAAAA,0x0000,
	0x807F,0xFFFF,0xFFFC,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0000,0x0400,0x7FFF,0xFFFF,0xFFFF,0xF800,
	0x7FFF,0x0000,0x0FFF,0xF800,0x7FFF,0x0000,0x03FF,0xF800,
	0x5000,0x0000,0x0000,0x5000,0x7000,0x0000,0x0000,0x3800,
	0x5000,0x0000,0x0000,0x1000,0x6000,0x0000,0x0000,0x2800,
	0x5000,0x0000,0x0000,0x1000,0x2000,0x0000,0x0000,0x2800,
	0x5000,0x0000,0x0000,0x1000,0x0000,0x0000,0x0000,0x0000,
	0x4800,0x0000,0x0000,0x0000,0x0000,0x0000,0x0008,0x0000,
	0x0014,0x0000,0x0050,0x0000,0x002B,0x0000,0x00E8,0x0000,
	0x0854,0x8828,0x82F4,0x0800,0x02C2,0x9800,0x00C0,0x0000,
	0x2800,0x0000,0x003F,0x6800,0x10AA,0xAAAA,0xAAAA,0x1000,
	0x284D,0x5600,0x0055,0x2800,0x54BC,0xAA34,0xD349,0x5000,
	0x2855,0x56CB,0x6CD5,0x2800,0x5CAA,0xAA00,0x000A,0xD800,
	0x3BFF,0xFFFF,0xFFFE,0xB800,0x7F55,0x5555,0x5555,0xF800,
	0x7F00,0x0000,0x0000,0xF800,0x7F80,0x0000,0x0003,0xF800,
	0x8000,0x0000,0x0000,0x0000
};
struct Image Image1 =
{
	0,
	0,
	54,
	29,
	3,
	ImageData1,
	0x07,
	0x00,
	NULL
};

USHORT chip ImageData2[] =
{
	0xFFFF,0xFFFF,0xFFFF,0xF800,0xFFFF,0x0000,0x0FFF,0xF800,
	0xFFFF,0x4000,0x03FF,0xF800,0xFFFF,0x0000,0x05FF,0xF800,
	0xDFFF,0xFFFF,0xFFFF,0xD000,0xEFFF,0xFFFF,0xFFFF,0xB800,
	0xDFFF,0xFFFF,0xFFFF,0x9000,0xEFFF,0xFFFF,0xFFFF,0xA800,
	0xDFFF,0xFFFF,0xFFFF,0x9000,0xAFFF,0xFFFF,0xFFFF,0xA800,
	0xCFFF,0xFFFF,0xFFFF,0x9000,0x8FFF,0xFFFF,0xFFFF,0x8000,
	0xC000,0x0000,0x0000,0x0000,0x8001,0x0F98,0x0500,0x0000,
	0x8015,0x4000,0x0154,0x0000,0x802C,0x0000,0x052A,0x4000,
	0x8059,0x2492,0x4915,0x4000,0x82C9,0x2492,0x4920,0xC000,
	0x8000,0x0000,0x003F,0x8000,0x80AA,0xAAAA,0xAAAA,0x8000,
	0x8055,0x57FF,0xFFD5,0x8000,0x80BC,0xAB20,0x9249,0x8000,
	0x8055,0x5761,0xBE54,0x8000,0x80AA,0xAA00,0x000B,0x0000,
	0x83FF,0xFFFF,0xFFFD,0x0000,0x8155,0x5555,0x5556,0x0000,
	0x80FF,0xFFFF,0xFFFE,0x0000,0x807F,0xFFFF,0xFFFC,0x0000,
	0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
	0x0000,0xFFFF,0xF000,0x0400,0x0000,0xFFFF,0xFC00,0x0400,
	0x0000,0xFFFF,0xFE00,0x0400,0x0000,0x0000,0x0000,0x0400,
	0x07FF,0xFFFF,0xFFFF,0xC400,0x060F,0xE1F8,0x0FC3,0xC400,
	0x0667,0xCCF8,0x0F99,0xC400,0x0667,0xC0FE,0x3F81,0xC400,
	0x0667,0xCCFE,0x3F99,0xC400,0x060F,0xCCFE,0x3F99,0xC400,
	0x07FF,0xFFFF,0xFFFF,0xC400,0x0FFF,0xFFFF,0xFFFF,0xC400,
	0x003F,0xF067,0xFFF0,0x0400,0x006B,0xFFFF,0xFFA8,0x0400,
	0x00D4,0xFFFF,0xFF15,0xC400,0x01A9,0x2492,0x490A,0xC400,
	0x0120,0x0000,0x001F,0xC400,0x03FF,0xFFFF,0xFFC0,0x8400,
	0x0355,0x5555,0x5555,0x8400,0x03BA,0xA9FF,0xFFAA,0x8400,
	0x035B,0x5541,0xA436,0x0400,0x03AA,0xA901,0x802A,0x8400,
	0x0355,0x55FF,0xFFF4,0x0400,0x0000,0x0000,0x0001,0x0400,
	0x00AA,0xAAAA,0xAAA8,0x0400,0x00AA,0xAAAA,0xAAAA,0x0400,
	0x007F,0xFFFF,0xFFFC,0x0400,0x7FFF,0xFFFF,0xFFFF,0xFC00,
	0x0000,0x0000,0x0000,0x0400,0x7FFF,0x0000,0x0FFF,0xF800,
	0x7FFF,0x0000,0x03FF,0xF800,0x7FFF,0x0000,0x01FF,0xF800,
	0x5000,0x0000,0x0000,0x1000,0x7000,0x0000,0x0000,0x3800,
	0x5000,0x0000,0x0000,0x1000,0x7000,0x0000,0x0000,0x2800,
	0x5000,0x0000,0x0000,0x1000,0x3000,0x0000,0x0000,0x2800,
	0x5000,0x0000,0x0000,0x1000,0x1000,0x0000,0x0000,0x0000,
	0x4000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0008,0x0000,
	0x0014,0x0000,0x0050,0x0000,0x002B,0x0000,0x00E8,0x0000,
	0x0854,0x8828,0x82F4,0x0800,0x02C2,0x9800,0x00C0,0x0000,
	0x2800,0x0000,0x003F,0x6800,0x10AA,0xAAAA,0xAAAA,0x1000,
	0x284D,0x5600,0x0055,0x2800,0x54BC,0xAA34,0xD349,0x5000,
	0x2855,0x56CB,0x6CD5,0x2800,0x5CAA,0xAA00,0x000A,0xD800,
	0x3BFF,0xFFFF,0xFFFE,0xB800,0x7F55,0x5555,0x5555,0xF800,
	0x7F00,0x0000,0x0000,0xF800,0x7F80,0x0000,0x0003,0xF800,
	0x8000,0x0000,0x0000,0x0000
};
struct Image Image2 =
{
	0,
	0,
	54,
	29,
	3,
	ImageData2,
	0x07,
	0x00,
	NULL
};

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


/*
 * DEFINES ------------------------------------------
 */
#define RESET           "\033[0m"
#define BOLD_ON         "\033[1m"
#define BOLD_OFF        "\033[22m"
#define ITALIC_ON       "\033[3m"
#define ITALIC_OFF      "\033[23m"
#define UNDERLINE_ON    "\033[4m"
#define UNDERLINE_OFF   "\033[24m"


/*
 * 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_List, 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 );
      fnReadDataFromDisk( MG.szProjectSpec, MAIN.LIS_List, MUIV_List_Insert_Bottom );
   }

   return( 0 );
}

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

/*
 * SUBROUTINES ---------------------------------------
 */
LONG fnClipCopy( char *psz )
{
   char   szBuf[ 255+1 ];
   UWORD  uwLen;


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

      memset( szBuf, 0, sizeof( szBuf ) );
      sprintf( szBuf, "FORM    FTXTCHRS    %s", psz );
      *( (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
   LONG   lStat;
   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 75, cutoff at 75...
                     ulSize = *( (ULONG *)szBuf );
                     if ( ulSize > 75 )   ulSize = 75;

                     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 )
                     {
                        get( MAIN.LIS_List, MUIA_List_Active, &lStat );
                        if ( lStat == MUIV_List_Active_Off )
                        {
                           lStat = MUIV_List_Insert_Bottom;
                        }
                        DoMethod( MAIN.LIS_List, MUIM_List_InsertSingle, szBuf, lStat );
                        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 );
}

//
// fnReadDataFromDisk()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL fnReadDataFromDisk( char *pszFile, APTR pListObject, ULONG ulSortControl )
{
   BPTR                  bpFile;
   struct FileInfoBlock *pFIB = NULL;
   BOOL                  rc = FAILURE;
   char                 *pszSave;
   ULONG                 ul, ulLine;
   char                 *pTextPool;


   if ( pFIB = AllocDosObject( DOS_FIB, NULL ) )
   {
      if ( bpFile = Open( pszFile, MODE_OLDFILE ) )
      {
         if ( ExamineFH( bpFile, pFIB ) )
         {
            if ( pTextPool = (char *)AllocVec( pFIB->fib_Size, 0 ) )
            {
               if ( Read( bpFile, pTextPool, pFIB->fib_Size ) ==
                        pFIB->fib_Size )
               {
                  set( pListObject, MUIA_List_Quiet, TRUE );
                  DoMethod( pListObject, MUIM_List_Clear, TRUE );

                  rc = SUCCESS;
                  // ...then read label text lines
                  pszSave = pTextPool;
                  for ( ul=0, ulLine=0; ul < pFIB->fib_Size; ul++ )
                  {
                     if ( *( pTextPool+ul ) == '\n' )
                     {
                        *( pTextPool+ul ) = 0;

                        // settings are stored in the first five lines!
                        switch( ulLine )
                        {
                           case 0:  set( MAIN.STR_ColsPerLabel    , MUIA_String_Contents, pszSave );  break;
                           case 1:  set( MAIN.STR_LinesPerLabel   , MUIA_String_Contents, pszSave );  break;
                           case 2:  set( MAIN.STR_LinesTweenLabels, MUIA_String_Contents, pszSave );  break;
                           case 3:  set( MAIN.STR_LabelsUp        , MUIA_String_Contents, pszSave );  break;
                           case 4:  set( MAIN.STR_NumLabels       , MUIA_String_Contents, pszSave );  break;
                           default:
                              DoMethod( pListObject, MUIM_List_Insert, &pszSave, 1, ulSortControl );
                              break;
                        }
                        pszSave = pTextPool+ul+1;
                        ulLine++;
                     }
                  }
                  set( pListObject, MUIA_List_Quiet, FALSE );
               }
               else
               {
                  Fault( IoErr(), "Disk read error!\n", GL_szFault, sizeof( GL_szFault ) );
                  JMH_Error( GL_szFault, NULL, NULL, NULL, 0 );
               }
               FreeVec( pTextPool );
            }
            else
            {
               JMH_Error( "Memory Error!\nNo memory for buffer.", NULL, NULL, NULL, 0 );
            }
         }
         else
         {
            Fault( IoErr(), "Disk examine error!\n", GL_szFault, sizeof( GL_szFault ) );
            JMH_Error( GL_szFault, NULL, NULL, NULL, 0 );
         }
         Close( bpFile );
      }
      else
      {
         Fault( IoErr(), "File error!\n", GL_szFault, sizeof( GL_szFault ) );
         sprintf( GL_szBuf, "\nFile: %s", pszFile );
         strcat( GL_szFault, GL_szBuf );
         JMH_Error( GL_szFault, NULL, NULL, NULL, 0 );
      }
      FreeDosObject( DOS_FIB, pFIB );
   }
   else
   {
      JMH_Error( "Memory Error!\nCannot allocate DOS FIB.", NULL, NULL, NULL, 0 );
   }

   return( rc );
}


//
// fnWriteDataToDisk()
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL fnWriteDataToDisk( char *pszFile, APTR pListObject )
{
   BOOL   rc = SUCCESS;

   FILE  *fp;
   ULONG  ulStat;
   LONG   lStat;
   char  *pszStat;

   struct DiskObject    *pDObj;


   if ( fp = fopen( pszFile, "w" ) )
   {
      get( MAIN.STR_ColsPerLabel, MUIA_String_Contents, &pszStat );
      sprintf( GL_szBuf, "%s\n", pszStat );
      fputs( GL_szBuf, fp );

      get( MAIN.STR_LinesPerLabel, MUIA_String_Contents, &pszStat );
      sprintf( GL_szBuf, "%s\n", pszStat );
      fputs( GL_szBuf, fp );

      get( MAIN.STR_LinesTweenLabels, MUIA_String_Contents, &pszStat );
      sprintf( GL_szBuf, "%s\n", pszStat );
      fputs( GL_szBuf, fp );

      get( MAIN.STR_LabelsUp, MUIA_String_Contents, &pszStat );
      sprintf( GL_szBuf, "%s\n", pszStat );
      fputs( GL_szBuf, fp );

      get( MAIN.STR_NumLabels, MUIA_String_Contents, &pszStat );
      sprintf( GL_szBuf, "%s\n", pszStat );
      fputs( GL_szBuf, fp );

      get( pListObject, MUIA_List_Entries, &ulStat );
      for ( lStat = 0; ( (lStat < ulStat) && (!ferror(fp)) ); lStat++ )
      {
         DoMethod( pListObject, MUIM_List_GetEntry, lStat, &pszStat );
         sprintf( GL_szBuf, "%s\n", pszStat );
         fputs( GL_szBuf, fp );
      }

      if ( ferror(fp) )
      {
         sprintf( GL_szFault, "Disk Error!\nFile may be corrupt." );
         JMH_Error( GL_szFault, MG.WIN_Main, NULL, NULL, 0 );
         rc = FAILURE;
      }
      fclose( fp );

      // write icon here
      if ( rc == SUCCESS )
      {
         pDObj = GetDiskObject( MG.szProjectSpec );
         if ( !pDObj )
         {
            // don't write an icon if one already exists...
            PutDiskObject( MG.szProjectSpec, &diskobj );
         }
         else
         {
            FreeDiskObject( pDObj );
         }
      }
   }
   else
   {
      Fault( IoErr(), "File error!\n", GL_szFault, sizeof( GL_szFault ) );
      JMH_Error( GL_szFault, NULL, NULL, NULL, 0 );
      rc = FAILURE;
   }

   return( rc );
}


//
// fnFileReq(): Pop up a file requester...
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL fnFileReq( APTR pWindowObj, char *pszFreqHail, BOOL fSaveMode, char *pszSaveBuf, UWORD uwSaveBufSize )
{
   char  *psz;
   static char  szPathPart[ FMSIZE+1 ], szFilePart[ FMSIZE+1 ];

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


   get( pWindowObj, MUIA_Window , &pWindow );
   if ( pFReq = MUI_AllocAslRequestTags( ASL_FileRequest, TAG_DONE ) )
   {
      strcpy( szPathPart, pszSaveBuf );
      psz = FilePart( szPathPart );
      if ( psz )
      {
         strcpy( szFilePart, psz );
         *psz = 0;
      }
      else
      {
         strcpy( szFilePart, "" );
      }

      if ( MUI_AslRequestTags( pFReq,
                               ASLFR_Window        , pWindow,
                               ASLFR_PrivateIDCMP  , TRUE,
                               ASLFR_TitleText     , pszFreqHail,
                               ASLFR_InitialDrawer , szPathPart,
                               ASLFR_InitialFile   , szFilePart,
                               ASLFR_DoSaveMode    , fSaveMode,
                               TAG_DONE ) )
      {
         // set the new contents for our string gadget
         *pszSaveBuf = 0;
         strncpy( pszSaveBuf, pFReq->fr_Drawer, uwSaveBufSize-1 );
         AddPart( pszSaveBuf, pFReq->fr_File,   uwSaveBufSize-1 );
      }
      else
      {
         MUI_FreeAslRequest( pFReq );
         return( FALSE );
      }

      MUI_FreeAslRequest( pFReq );
   }
   else
   {
      return( FALSE );
   }

   return( TRUE );
}

//
// fnPrintALabelRow(): print one line of labels to output device
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void fnPrintALabelRow( char *pszOutputDevice )
{
   FILE        *fp;
   ULONG        ulCols, ulLines, ulLinesTween, ulLabelsUp, ulNumLabels;
   ULONG        ul2;
   static char  szBuf[ 256 ];
   LONG         lStat, lNE;
   UBYTE       *pszStat;
   UBYTE       *pszNew, *pszStartOld, *pszOld;
   USHORT       usColDiff;
   SHORT        sJustify;


   fp = fopen( pszOutputDevice, "w" );
   if ( fp )
   {
      set( MG.App, MUIA_Application_Sleep, TRUE );

      get( MAIN.STR_ColsPerLabel    , MUIA_String_Contents, &pszStat );    ulCols       = atol( pszStat );
      get( MAIN.STR_LinesPerLabel   , MUIA_String_Contents, &pszStat );    ulLines      = atol( pszStat );
      get( MAIN.STR_LinesTweenLabels, MUIA_String_Contents, &pszStat );    ulLinesTween = atol( pszStat );
      get( MAIN.STR_LabelsUp        , MUIA_String_Contents, &pszStat );    ulLabelsUp   = atol( pszStat );
      get( MAIN.STR_NumLabels       , MUIA_String_Contents, &pszStat );    ulNumLabels  = atol( pszStat );
      get( MAIN.LIS_List, MUIA_List_Entries, &lNE );
      for ( lStat = 0; ( (lStat < ulLines) && (!ferror(fp)) ); lStat++ )
      {
         DoMethod( MAIN.LIS_List, MUIM_List_GetEntry, lStat, &pszStat );
         if ( pszStat )
         {
            sJustify = -1;
            pszNew = szBuf;
            pszStartOld = pszStat;
            usColDiff = 0;
            memset( szBuf, 0, sizeof( szBuf ) );
            for ( pszOld = strchr( pszStartOld, '\\' );
                  pszOld;
                  pszOld = strchr( pszStartOld, '\\' ) )
            {
               strncpy( pszNew, pszStartOld, (pszOld - pszStartOld) );
               pszNew += (pszOld - pszStartOld);
               pszStartOld += (pszOld - pszStartOld);
               switch( *( pszOld+1 ) )
               {
                  case 'c':
                  case 'C':   sJustify =  0;    break;
                  case 'l':
                  case 'L':   sJustify = -1;    break;
                  case 'r':
                  case 'R':   sJustify = +1;    break;

                  case 'p':
                  case 'P':
                     strcpy( pszNew, RESET );
                     pszNew += strlen( RESET );
                     usColDiff += strlen( RESET );
                     break;
                  case 'B':
                     strcpy( pszNew, BOLD_ON );
                     pszNew += strlen( BOLD_ON );
                     usColDiff += strlen( BOLD_ON );
                     break;
                  case 'b':
                     strcpy( pszNew, BOLD_OFF );
                     pszNew += strlen( BOLD_OFF );
                     usColDiff += strlen( BOLD_OFF );
                     break;
                  case 'I':
                     strcpy( pszNew, ITALIC_ON );
                     pszNew += strlen( ITALIC_ON );
                     usColDiff += strlen( ITALIC_ON );
                     break;
                  case 'i':
                     strcpy( pszNew, ITALIC_OFF );
                     pszNew += strlen( ITALIC_OFF );
                     usColDiff += strlen( ITALIC_OFF );
                     break;
                  case 'U':
                     strcpy( pszNew, UNDERLINE_ON );
                     pszNew += strlen( UNDERLINE_ON );
                     usColDiff += strlen( UNDERLINE_ON );
                     break;
                  case 'u':
                     strcpy( pszNew, UNDERLINE_OFF );
                     pszNew += strlen( UNDERLINE_OFF );
                     usColDiff += strlen( UNDERLINE_OFF );
                     break;
               }
               pszStartOld += 2;
            }
            strcpy( pszNew, pszStartOld );
            switch( sJustify )
            {
            char szsz[256];
               case +1:
                  ul2 = ulCols - ( strlen( szBuf )-usColDiff );
                  sprintf( szsz, "%*s%s", (int)ul2, " ", szBuf );
                  strcpy( szBuf, szsz );
                  break;
               case  0:
                  ul2 = ulCols - ( strlen( szBuf )-usColDiff );
                  sprintf( szsz, "%*s%s%-75.75s", (int)(ul2/2), " ", szBuf, " " );
                  strcpy( szBuf, szsz );
                  break;
               case -1:
               default:
                  sprintf( szBuf, "%-75.75s", szBuf );
                  break;
            }
         }
         else
            sprintf( szBuf, "%-75.75s", "" );

         szBuf[ ulCols+usColDiff ] = 0;
         strcpy( GL_szBuf, "" );
         for ( ul2 = 0; ul2 < ulLabelsUp; ul2++ )
         {
            strcat( GL_szBuf, szBuf );
            strcat( GL_szBuf, RESET );
            strcat( GL_szBuf, " "   );
         }
         GL_szBuf[ strlen(GL_szBuf)-1 ] = '\n';
         fputs( RESET, fp );
         fputs( GL_szBuf, fp );
      }
      if ( ferror(fp) )
      {
         sprintf( GL_szFault, "File error # %lu.\nConsult your AmigaDOS manual.", ferror(fp) );
         JMH_Error( GL_szBuf, MG.WIN_Main, NULL, NULL, 0 );
      }
      else
      {
         for ( ul2 = 0; ul2 < ulLinesTween; ul2++ )
            fputs( "\n", fp );
      }
      fclose( fp );

      set( MG.App, MUIA_Application_Sleep, FALSE );
   }
   else
   {
      JMH_Error( "Couldn't open device for preview.", MG.WIN_Main, NULL, NULL, 0 );
   }
}


// ***********************************************************************
//
//    MAIN WINDOW
//
// ***********************************************************************
BOOL fnConstructMainWindow( void )
{
   MG.WIN_Main = WindowObject,
      MUIA_Window_ID, MAKE_ID('M','A','I','N'),
      MUIA_Window_Title, "MUILabeler",
      MUIA_Window_Menu, (APTR)Menu_MainMenu,
      MUIA_Window_AppWindow, TRUE,
      MUIA_HelpNode, "mainwdw",
      WindowContents, VGroup,
         Child, ColGroup(4), GroupFrameT("Settings"),
            Child, HSpace(0),
            Child, KeyLabel1("Columns per Label",'c'),
            Child, MAIN.STR_ColsPerLabel = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Right,
               MUIA_String_Accept, "0123456789",
               MUIA_String_MaxLen, 2+1,
               MUIA_ControlChar  , 'c',
               End,
            Child, HSpace(0),
            Child, HSpace(0),
            Child, KeyLabel1("Lines per Label",'l'),
            Child, MAIN.STR_LinesPerLabel = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Right,
               MUIA_String_Accept, "0123456789",
               MUIA_String_MaxLen, 2+1,
               MUIA_ControlChar  , 'l',
               End,
            Child, HSpace(0),
            Child, HSpace(0),
            Child, KeyLabel1("Lines between labels",'b'),
            Child, MAIN.STR_LinesTweenLabels = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Right,
               MUIA_String_Accept, "0123456789",
               MUIA_String_MaxLen, 2+1,
               MUIA_ControlChar  , 'b',
               End,
            Child, HSpace(0),
            Child, HSpace(0),
            Child, KeyLabel1("Labels Up",'a'),
            Child, MAIN.STR_LabelsUp = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Right,
               MUIA_String_Accept, "0123456789",
               MUIA_String_MaxLen, 2+1,
               MUIA_ControlChar  , 'a',
               End,
            Child, HSpace(0),
            Child, HSpace(0),
            Child, KeyLabel1("Number to print",'n'),
            Child, MAIN.STR_NumLabels = StringObject, StringFrame,
               MUIA_String_Format, MUIV_String_Format_Right,
               MUIA_String_Accept, "0123456789",
               MUIA_String_MaxLen, 4+1,
               MUIA_ControlChar  , 'n',
               End,
            Child, HSpace(0),
            End,
         Child, HGroup,
            Child, VGroup, MUIA_HorizWeight, 500,
               Child, MAIN.LIS_List = 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.STR_List = StringObject, StringFrame,
                  MUIA_String_AttachedList, MAIN.LIS_List,
                  MUIA_String_Format, MUIV_String_Format_Left,
                  MUIA_String_MaxLen, 75+1,
                  End,
               End,
            Child, VGroup, MUIA_Group_SameSize, TRUE,
               Child, MAIN.BUT_ClearSelection = KeyButton("Clear",'l'),
               Child, MAIN.BUT_Erase          = KeyButton("Erase",'e'),
               Child, VSpace(0),
               Child, MAIN.BUT_Up    = KeyButton("Up",'u'),
               Child, MAIN.BUT_Down  = KeyButton("Down",'d'),
               End,
            End,
         Child, HGroup,
            Child, MAIN.BUT_Print = KeyButton("Print",'p'),
            Child, HSpace(0),
            Child, MAIN.BUT_Test  = KeyButton("Test",'t'),
            Child, HSpace(0),
            Child, MAIN.BUT_View  = KeyButton("View",'v'),
            End,
         End,
      End;

   // window failed?
   if ( !MG.WIN_Main )
   {
      return( FAILURE );
   }
   else
   {
      // make gadget connections
      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.STR_List, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_STR_LIST_ACK );

      DoMethod( MAIN.BUT_Up,    MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_UP );
      DoMethod( MAIN.BUT_Down,  MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_DOWN );
      DoMethod( MAIN.BUT_Erase, MUIM_Notify, MUIA_Pressed, FALSE,
                MAIN.LIS_List, 2, MUIM_List_Remove, MUIV_List_Remove_Active );
      DoMethod( MAIN.BUT_Print, MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_PRINT );
      DoMethod( MAIN.BUT_Test,  MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_TEST );
      DoMethod( MAIN.BUT_View,  MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_VIEW );
      DoMethod( MAIN.BUT_ClearSelection,  MUIM_Notify, MUIA_Pressed, FALSE,   MG.App, 2, MUIM_Application_ReturnID, ID_BUT_CLEARSELECTION );

      // 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:MUILabeler.guide", "mainmenus", 0 );

      // tie the list string to the active item
      DoMethod( MAIN.LIS_List, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
                MG.App, 2, MUIM_Application_ReturnID, ID_LIS_LISTCHANGED );

      // set tab cycle chain
      DoMethod( MG.WIN_Main, MUIM_Window_SetCycleChain,
                MAIN.STR_ColsPerLabel,
                MAIN.STR_LinesPerLabel,
                MAIN.STR_LinesTweenLabels,
                MAIN.STR_LabelsUp,
                MAIN.STR_NumLabels,
                MAIN.STR_List,
                MAIN.BUT_ClearSelection,
                MAIN.BUT_Erase,
                MAIN.BUT_Up,
                MAIN.BUT_Down,
                MAIN.BUT_Print,
                MAIN.BUT_Test,
                MAIN.BUT_View,
                NULL );

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

      return( SUCCESS );
   }
}

// ***********************************************************************
//
//    SETTINGS WINDOW
//
// ***********************************************************************
BOOL fnConstructSettingsWindow( void )
{
   MG.WIN_Settings = WindowObject,
      MUIA_Window_ID, MAKE_ID('S','E','T','T'),
      MUIA_Window_Title, "MUILabeler Settings",
      MUIA_HelpNode, "settings",
      WindowContents, VGroup,
         Child, ColGroup(2),
            Child, KeyLabel1("CON: string",'c'),
            Child, SETT.STR_CONString = StringObject, StringFrame,
               MUIA_ExportID, MAKE_ID('C','O','N','S'),
               MUIA_String_MaxLen, 255+1,
               MUIA_ControlChar  , 'c',
               End,
            Child, KeyLabel1("Printer device",'p'),
            Child, SETT.STR_Printer = StringObject, StringFrame,
               MUIA_ExportID, MAKE_ID('P','R','I','N'),
               MUIA_String_MaxLen, 255+1,
               MUIA_ControlChar  , 'p',
               End,
            End,
         Child, VSpace(0),
         Child, HGroup,
            Child, SETT.BUT_Save   = KeyButton("Save",'s'),
            Child, HSpace(0),
            Child, SETT.BUT_Use    = KeyButton("Use",'u'),
            Child, HSpace(0),
            Child, SETT.BUT_Cancel = SimpleButton("Cancel"),
            End,
         End,
      End;

   // window failed?
   if ( !MG.WIN_Settings )
   {
      return( FAILURE );
   }
   else
   {
      // make gadget connections
      DoMethod( MG.WIN_Settings, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_SETTCANCEL );

      DoMethod( SETT.BUT_Save  ,  MUIM_Notify, MUIA_Pressed, FALSE,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_SETTSAVE );
      DoMethod( SETT.BUT_Use   ,  MUIM_Notify, MUIA_Pressed, FALSE,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_SETTUSE );
      DoMethod( SETT.BUT_Cancel,  MUIM_Notify, MUIA_Pressed, FALSE,
                MG.App, 2, MUIM_Application_ReturnID, ID_BUT_SETTCANCEL );
      DoMethod( SETT.STR_CONString, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.WIN_Settings, 3, MUIM_Set, MUIA_Window_ActiveObject, SETT.STR_Printer );
      DoMethod( SETT.STR_Printer, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime,
                MG.WIN_Settings, 3, MUIM_Set, MUIA_Window_ActiveObject, SETT.BUT_Save );

      // set tab cycle chain
      DoMethod( MG.WIN_Settings, MUIM_Window_SetCycleChain,
                SETT.STR_CONString,
                SETT.STR_Printer,
                SETT.BUT_Save,
                SETT.BUT_Use,
                SETT.BUT_Cancel,
                NULL );

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

      return( SUCCESS );
   }
}


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

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

   static char  szBuf[ 256 ];
   static char  szCONOutput[ FMSIZE+20 ];

   UBYTE  *pszNew, *pszStartOld, *pszOld;
   USHORT  usColDiff;
   SHORT   sJustify;

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


   //
   // setup variables, read startup params, etc...
   // also create application object
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   JMH_Startup( argc, argv );

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

   //
   // read settings
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   DoMethod( MG.App, MUIM_Application_Load, MUIV_Application_Load_ENV );
   strcpy( MG.szSettingsSpec, "ENV:" );

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

   //
   // if we're passed a data file, load it
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   if ( argc > 1 )
   {
      fnReadDataFromDisk( MG.szProjectSpec, MAIN.LIS_List, MUIV_List_Insert_Bottom );
   }
   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, MG.szProjectSpec, FMSIZE );

            UnLock( tmplock );
         }
      }
      if ( strcmp( MG.szProjectSpec, "" ) )
      {
         fnReadDataFromDisk( MG.szProjectSpec, MAIN.LIS_List,
                             MUIV_List_Insert_Bottom );
      }
   }

   //
   // show 'em what it's all 'About'
   // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   set( MG.WIN_Main, MUIA_Window_Open, TRUE );
   JMH_About();

   set( MAIN.LIS_List, MUIA_List_Active, 0 );
   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:
               if ( MUI_Request( MG.App, MG.WIN_Main, 0, NULL, "Yes|*No",
                                 "Are you sure you want to clear everything?", NULL ) == 1 )
               {
                  DoMethod( MAIN.LIS_List, MUIM_List_Clear, TRUE );
                  set( MAIN.STR_List            , MUIA_String_Contents, NULL );
                  set( MAIN.STR_ColsPerLabel    , MUIA_String_Contents, NULL );
                  set( MAIN.STR_LinesPerLabel   , MUIA_String_Contents, NULL );
                  set( MAIN.STR_LinesTweenLabels, MUIA_String_Contents, NULL );
                  set( MAIN.STR_LabelsUp        , MUIA_String_Contents, NULL );
                  set( MAIN.STR_NumLabels       , MUIA_String_Contents, NULL );
                  set( MG.WIN_Main, MUIA_Window_ActiveObject, MAIN.STR_ColsPerLabel );
               }
               break;
            case ID_MENU_OPEN:
               if ( fnFileReq( MG.WIN_Main, "Open a MUILabeler List", FALSE,
                               MG.szProjectSpec, sizeof( MG.szProjectSpec ) ) == TRUE )
               {
                  fnReadDataFromDisk( MG.szProjectSpec,
                                      MAIN.LIS_List,
                                      MUIV_List_Insert_Bottom );
                  set( MAIN.LIS_List, MUIA_List_Active, 0 );
               }
               break;
            case ID_MENU_SAVE:
               if ( strcmp( MG.szProjectSpec, "" ) == 0 )
               {
                  if ( fnFileReq( MG.WIN_Main, "Save a MUILabeler List", TRUE,
                                  MG.szProjectSpec, sizeof( MG.szProjectSpec ) ) == TRUE )
                  {
                     fnWriteDataToDisk( MG.szProjectSpec, MAIN.LIS_List );
                  }
               }
               else
               {
                  fnWriteDataToDisk( MG.szProjectSpec, MAIN.LIS_List );
               }
               break;
            case ID_MENU_SAVEAS:
               if ( fnFileReq( MG.WIN_Main, "Save a MUILabeler List", TRUE,
                               MG.szProjectSpec, sizeof( MG.szProjectSpec ) ) == TRUE )
               {
                  fnWriteDataToDisk( MG.szProjectSpec, MAIN.LIS_List );
               }
               break;
            case ID_MENU_PRINTERSETUP:
               set( MG.App, MUIA_Application_Sleep, TRUE );
               lStat = SystemTags( "SYS:Prefs/Printer", SYS_Asynch, FALSE, TAG_DONE, TAG_DONE );
               if ( lStat != 0 )
               {
                  if ( lStat > 0 )
                     Fault( IoErr(),
                            "Cannot launch Printer Preferences tool because",
                            GL_szFault,
                            sizeof( GL_szFault ) );
                  else
                     strcpy( GL_szFault, "Unable to launch Printer Preferences tool!" );

                  JMH_Error( GL_szFault, MG.WIN_Main, NULL, NULL, 0 );
               }
               set( MG.App, MUIA_Application_Sleep, FALSE );
               break;
            case ID_MENU_ABOUT:
               JMH_About();
               break;
            case ID_MENU_CUT:
               get( MAIN.LIS_List, MUIA_List_Active, &lStat );
               if ( lStat != MUIV_List_Active_Off )
               {
                  DoMethod( MAIN.STR_List, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pszStat );
                  fnClipCopy( pszStat );
                  DoMethod( MAIN.LIS_List, MUIM_List_Remove, MUIV_List_Remove_Active );
               }
               break;
            case ID_MENU_COPY:
               get( MAIN.LIS_List, MUIA_List_Active, &lStat );
               if ( lStat != MUIV_List_Active_Off )
               {
                  DoMethod( MAIN.STR_List, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pszStat );
                  fnClipCopy( pszStat );
               }
               break;
            case ID_MENU_PASTE:
               fnClipPaste();
               break;
            case ID_MENU_SETCON:
               set( MG.WIN_Main,     MUIA_Window_Sleep, TRUE );
               set( MG.WIN_Settings, MUIA_Window_Open,  TRUE );
               set( MG.WIN_Settings, MUIA_Window_ActiveObject, SETT.STR_CONString );
               break;
            case ID_MENU_SETLOAD:
               if ( fnFileReq( MG.WIN_Main, "Load MUILabeler Settings", FALSE,
                               MG.szSettingsSpec, sizeof( MG.szSettingsSpec ) ) == TRUE )
               {
      				DoMethod( MG.App, MUIM_Application_Load, MG.szSettingsSpec );
               }
   				break;
            case ID_MENU_SETSAVE:
               DoMethod( MG.App, MUIM_Application_Save, MUIV_Application_Save_ENVARC );
   				break;
            case ID_MENU_SETSAVEAS:
               if ( fnFileReq( MG.WIN_Main, "Save a MUILabeler List", TRUE,
                               MG.szSettingsSpec, sizeof( MG.szSettingsSpec ) ) == TRUE )
               {
                  DoMethod( MG.App, MUIM_Application_Save, MG.szSettingsSpec );
               }
   				break;

         // SETTINGS GADGETS ----------------------------------
            case ID_BUT_SETTSAVE:
               DoMethod( MG.App, MUIM_Application_Save, MUIV_Application_Save_ENVARC );
               set( MG.WIN_Settings, MUIA_Window_Open, FALSE );
               set( MG.WIN_Main, MUIA_Window_Sleep, FALSE );
               break;
            case ID_BUT_SETTUSE:
               DoMethod( MG.App, MUIM_Application_Save, MUIV_Application_Save_ENV    );
               set( MG.WIN_Settings, MUIA_Window_Open, FALSE );
               set( MG.WIN_Main, MUIA_Window_Sleep, FALSE );
               break;
            case ID_BUT_SETTCANCEL:
               set( MG.WIN_Settings, MUIA_Window_Open, FALSE );
               set( MG.WIN_Main, MUIA_Window_Sleep, FALSE );
               break;

         // GADGETS -------------------------------------------
            case ID_LIS_LISTCHANGED:
               DoMethod( MAIN.LIS_List, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pszStat );
               set( MAIN.STR_List, MUIA_String_Contents, pszStat );
               break;
            case ID_STR_LIST_ACK:
               get( MAIN.LIS_List, MUIA_List_Active, &lStat );
               if ( lStat == MUIV_List_Active_Off )
               {
                  lStat = MUIV_List_Insert_Bottom;
               }
               else
               {
                  DoMethod( MAIN.LIS_List, MUIM_List_Remove, MUIV_List_Remove_Active );
               }
               get( MAIN.STR_List, MUIA_String_Contents, &pszStat );
               DoMethod( MAIN.LIS_List, MUIM_List_InsertSingle, pszStat, lStat );
               set( MAIN.STR_List, MUIA_String_Contents, NULL );
               set( MG.WIN_Main, MUIA_Window_ActiveObject,  MAIN.STR_List );
               break;
            case ID_BUT_UP:
               get( MAIN.LIS_List, MUIA_List_Active, &lStat );
               if ( ( lStat != MUIV_List_Active_Off ) && ( lStat > 0 ) )
               {
                  DoMethod( MAIN.LIS_List, MUIM_List_GetEntry, lStat, &pszStat );
                  strcpy( GL_szBuf, pszStat );
                  DoMethod( MAIN.LIS_List, MUIM_List_Remove, lStat );
                  DoMethod( MAIN.LIS_List, MUIM_List_InsertSingle, GL_szBuf, lStat-1 );
                  set( MAIN.LIS_List, MUIA_List_Active, lStat-1 );
               }
               break;
            case ID_BUT_DOWN:
               get( MAIN.LIS_List, MUIA_List_Active, &lStat );
               get( MAIN.LIS_List, MUIA_List_Entries, &lNE );
               if ( ( lStat != MUIV_List_Active_Off ) && ( lStat < lNE-1 ) )
               {
                  DoMethod( MAIN.LIS_List, MUIM_List_GetEntry, lStat, &pszStat );
                  strcpy( GL_szBuf, pszStat );
                  DoMethod( MAIN.LIS_List, MUIM_List_Remove, lStat );
                  DoMethod( MAIN.LIS_List, MUIM_List_InsertSingle, GL_szBuf, lStat+1 );
                  set( MAIN.LIS_List, MUIA_List_Active, lStat+1 );
               }
               break;
            case ID_BUT_CLEARSELECTION:
               set( MAIN.LIS_List, MUIA_List_Active, MUIV_List_Active_Off );
               break;
            case ID_BUT_VIEW:
               get( SETT.STR_CONString, MUIA_String_Contents, &pszStat );
               sprintf( szCONOutput, "%s/AUTO/CLOSE/WAIT", pszStat );
               fnPrintALabelRow( szCONOutput );
               break;
            case ID_BUT_TEST:
               get( SETT.STR_Printer, MUIA_String_Contents, &pszStat );
               strcpy( szCONOutput, pszStat );
               if ( strcmp( pszStat, "" ) == 0 )
               {
                  strcpy( szCONOutput, "PRT:" );
               }
               fnPrintALabelRow( pszStat );
               break;
            case ID_MENU_PRINT:
            case ID_BUT_PRINT:
            {
               FILE  *fp;
               ULONG  ulCols, ulLines, ulLinesTween, ulLabelsUp, ulNumLabels;
               ULONG  ul, ul2;


               get( SETT.STR_Printer, MUIA_String_Contents, &pszStat );
               strcpy( szCONOutput, pszStat );
               if ( strcmp( pszStat, "" ) == 0 )
               {
                  strcpy( szCONOutput, "PRT:" );
               }
               fp = fopen( szCONOutput, "w" );
               if ( fp )
               {
                  set( MG.App, MUIA_Application_Sleep, TRUE );

                  get( MAIN.STR_ColsPerLabel    , MUIA_String_Contents, &pszStat );    ulCols       = atol( pszStat );
                  get( MAIN.STR_LinesPerLabel   , MUIA_String_Contents, &pszStat );    ulLines      = atol( pszStat );
                  get( MAIN.STR_LinesTweenLabels, MUIA_String_Contents, &pszStat );    ulLinesTween = atol( pszStat );
                  get( MAIN.STR_LabelsUp        , MUIA_String_Contents, &pszStat );    ulLabelsUp   = atol( pszStat );
                  get( MAIN.STR_NumLabels       , MUIA_String_Contents, &pszStat );    ulNumLabels  = atol( pszStat );
                  get( MAIN.LIS_List, MUIA_List_Entries, &lNE );
                  for ( ul = 0; ul < ulNumLabels; ul += ulLabelsUp )
                  {
                     for ( lStat = 0; ( (lStat < ulLines) && (!ferror(fp)) ); lStat++ )
                     {
                        DoMethod( MAIN.LIS_List, MUIM_List_GetEntry, lStat, &pszStat );
                        if ( pszStat )
                        {
                           sJustify = -1;
                           pszNew = szBuf;
                           pszStartOld = pszStat;
                           usColDiff = 0;
                           memset( szBuf, 0, sizeof( szBuf ) );
                           for ( pszOld = strchr( pszStartOld, '\\' );
                                 pszOld;
                                 pszOld = strchr( pszStartOld, '\\' ) )
                           {
                              strncpy( pszNew, pszStartOld, (pszOld - pszStartOld) );
                              pszNew += (pszOld - pszStartOld);
                              pszStartOld += (pszOld - pszStartOld);
                              switch( *( pszOld+1 ) )
                              {
                                 case 'c':
                                 case 'C':   sJustify =  0;    break;
                                 case 'l':
                                 case 'L':   sJustify = -1;    break;
                                 case 'r':
                                 case 'R':   sJustify = +1;    break;

                                 case 'p':
                                 case 'P':
                                    strcpy( pszNew, RESET );
                                    pszNew += strlen( RESET );
                                    usColDiff += strlen( RESET );
                                    break;
                                 case 'B':
                                    strcpy( pszNew, BOLD_ON );
                                    pszNew += strlen( BOLD_ON );
                                    usColDiff += strlen( BOLD_ON );
                                    break;
                                 case 'b':
                                    strcpy( pszNew, BOLD_OFF );
                                    pszNew += strlen( BOLD_OFF );
                                    usColDiff += strlen( BOLD_OFF );
                                    break;
                                 case 'I':
                                    strcpy( pszNew, ITALIC_ON );
                                    pszNew += strlen( ITALIC_ON );
                                    usColDiff += strlen( ITALIC_ON );
                                    break;
                                 case 'i':
                                    strcpy( pszNew, ITALIC_OFF );
                                    pszNew += strlen( ITALIC_OFF );
                                    usColDiff += strlen( ITALIC_OFF );
                                    break;
                                 case 'U':
                                    strcpy( pszNew, UNDERLINE_ON );
                                    pszNew += strlen( UNDERLINE_ON );
                                    usColDiff += strlen( UNDERLINE_ON );
                                    break;
                                 case 'u':
                                    strcpy( pszNew, UNDERLINE_OFF );
                                    pszNew += strlen( UNDERLINE_OFF );
                                    usColDiff += strlen( UNDERLINE_OFF );
                                    break;
                              }
                              pszStartOld += 2;
                           }
                           strcpy( pszNew, pszStartOld );
                           switch( sJustify )
                           {
                           char szsz[256];
                              case +1:
                                 ul2 = ulCols - ( strlen( szBuf )-usColDiff );
                                 sprintf( szsz, "%*s%s", (int)ul2, " ", szBuf );
                                 strcpy( szBuf, szsz );
                                 break;
                              case  0:
                                 ul2 = ulCols - ( strlen( szBuf )-usColDiff );
                                 sprintf( szsz, "%*s%s%-75.75s", (int)(ul2/2), " ", szBuf, " " );
                                 strcpy( szBuf, szsz );
                                 break;
                              case -1:
                              default:
                                 sprintf( szBuf, "%-75.75s", szBuf );
                                 break;
                           }
                        }
                        else
                           sprintf( szBuf, "%-75.75s", "" );

                        szBuf[ ulCols+usColDiff ] = 0;
                        strcpy( GL_szBuf, "" );
                        for ( ul2 = 0; ul2 < ulLabelsUp; ul2++ )
                        {
                           strcat( GL_szBuf, szBuf );
                           strcat( GL_szBuf, " "   );
                        }
                        GL_szBuf[ strlen(GL_szBuf)-1 ] = '\n';
                        fputs( RESET, fp );
                        fputs( GL_szBuf, fp );
                     }
                     if ( ferror(fp) )
                     {
                        sprintf( GL_szFault, "Printer error # %lu.\nConsult your AmigaDOS manual.", ferror(fp) );
                        JMH_Error( GL_szBuf, MG.WIN_Main, NULL, NULL, 0 );
                        break;
                     }
                     else
                     {
                        for ( ul2 = 0; ul2 < ulLinesTween; ul2++ )
                           fputs( "\n", fp );
                     }
                  }
                  fclose( fp );

                  set( MG.App, MUIA_Application_Sleep, FALSE );
               }
               else
               {
                  JMH_Error( "Couldn't open printer.  Labels not printed.", MG.WIN_Main, NULL, NULL, 0 );
               }
               break;
            }
      }
      if ( MG.running && signals ) Wait(signals);
   }

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