/* $Filename:    ReportPlus/Source/rp.c
 * $VER:         Report+ 5.4
 * $Description: Multipurpose utility
 *
 * © Copyright 1999-2002 James R. Jacobs. Freely distributable.
 *        _
 *       //      -=AMIGA=-
 *      //
 * _   //
 * \\ //
 *  \X/

#INCLUDES -------------------------------------------------------------- */

/* #include <assert.h> */

#include <exec/types.h>
#include <exec/alerts.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <proto/exec.h>
#include <intuition/intuition.h>
#include <clib/intuition_protos.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <clib/gadtools_protos.h>
#include <workbench/workbench.h> /* struct DiskObject */
#include <libraries/asl.h>
#include <proto/asl.h>
#include <dos/dos.h>
#include <dos/dostags.h>
#include <dos/dosextens.h>
#include <proto/dos.h>
#include <diskfont/diskfont.h>
#include <proto/diskfont.h>
#include <graphics/gfx.h>
#include <graphics/displayinfo.h>
#include <graphics/gels.h>
#include <clib/graphics_protos.h>
#include <utility/tagitem.h>
#include <proto/utility.h>
#include <workbench/icon.h>
#include <clib/icon_protos.h>
#include <clib/alib_protos.h>
#include <resources/battmem.h>
#include <resources/battmembitsamiga.h>
#include <resources/battmembitsshared.h>

#define ALL_REACTION_CLASSES
#define ALL_REACTION_MACROS
#include <reaction/reaction.h>
#include <clib/alib_protos.h>
#include <clib/texteditor_protos.h>
#include <gadgets/texteditor.h>
#include <pragmas/texteditor_pragmas.h>

#define GID_0_LY1   0
#define GID_0_BU1   1 // the function buttons must start from GID_O_BU1,
#define GID_0_BU2   2 // and must all be consecutive.
#define GID_0_BU3   3
#define GID_0_BU4   4
#define GID_0_BU5   5
#define GID_0_BU6   6
#define GID_0_BU7   7
#define GID_0_BU8   8
#define GID_0_BU9   9
#define GID_0_BU10 10
#define GID_0_BU11 11
#define GID_0_BU12 12
#define GID_0_ST1  13
#define GID_0_LY2  14
#define GIDS_0     GID_0_LY2

#include <ctype.h>
#include <stdio.h>          /* FILE, printf() */
#include <stdlib.h>         /* EXIT_SUCCESS, EXIT_FAILURE */
#include <string.h>
#include "rp.h"
#include "boards.h"

#ifdef __STORM__
   #pragma chip
#endif

MODULE struct Image*  image[FUNCTIONS + 1];
MODULE struct BitMap* bitmap[FUNCTIONS + 1];
MODULE STRPTR         imagename[FUNCTIONS + 1] =
{   "PROGDIR:images/f1.ilbm",
    "PROGDIR:images/f2.ilbm",
    "PROGDIR:images/f3.ilbm",
    "PROGDIR:images/f4.ilbm",
    "PROGDIR:images/f5.ilbm",
    "PROGDIR:images/f6.ilbm",
    "PROGDIR:images/f7.ilbm",
    "PROGDIR:images/f8.ilbm",
    "PROGDIR:images/f9.ilbm",
    "PROGDIR:images/f10.ilbm",
    "PROGDIR:images/f11.ilbm",
    "PROGDIR:images/f12.ilbm",
    "PROGDIR:images/amigan.ilbm"
};
MODULE STRPTR FunctionDesc[FUNCTIONS + 2] =
{   // Edit
    "Bug report",         // 1
    "Aminet readme",      // 2
    "Autodoc",            // 4
    "Battery-backed RAM", // 9
    "AGDB review",        // 1
    // View
    "Manufacturer IDs",   // 5
    "IFF FORMs",          // 6
    // Process
    "EOLs/tabs",          // 7
    "Icons",              // 12
    // Report
    "Path size",          // 8
    "System files",       // 10
    // Conduct
    "ACSE test",          // 3
    // (default)
    TITLEBARTEXT
};

AGLOBAL struct NewGadget Gadget =
{   0, 0, /* left-x, top-y */
    0, 0, /* width, height */
    0,    /* text */
    NULL, /* font */
    NULL, /* gadget ID */
    NULL, /* flags */
    NULL, /* visual info */
    NULL  /* user data */
};

#define MENUENTRIES 13
MODULE struct NewMenu NewMenu[MENUENTRIES] =
{   { NM_TITLE, "Project",       0 , 0,               0, 0},
    {  NM_ITEM, "New",          "N", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, "Open...",      "O", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, NM_BARLABEL,     0 , 0,               0, 0},
    {  NM_ITEM, "Save",         "S", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, "Save As...",   "A", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, NM_BARLABEL,     0 , 0,               0, 0},
    {  NM_ITEM, "Quit Report+", "Q", 0,               0, 0},
    { NM_TITLE, "Help",          0 , 0,               0, 0},
    {  NM_ITEM, "Manual...",    "M", 0,               0, 0},
    {  NM_ITEM, NM_BARLABEL,     0 , 0,               0, 0},
    {  NM_ITEM, "About...",     "?", 0,               0, 0},
    {   NM_END, NULL,            0 , 0,               0, 0}
};

MODULE void clearkybd(void);
MODULE void menu(void);
MODULE void parsewb(void);
MODULE void eachwildcard(STRPTR subpattern, ABOOL gui);
MODULE void menu_loop(ULONG gid);
MODULE void AddPathnameToTail(struct List* ListPtr, STRPTR name);
MODULE void clearpathlist(struct List* ListPtr);
MODULE void FreePathnameNodes(struct List* ListPtr);
MODULE void sender_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual);

int CXBRK(void) { return(0); }    /* Disable SAS/C Ctrl-C handling */
int chkabort(void) { return(0); } /* really */

MODULE  struct Window*           AboutWindowPtr  = NULL;
AGLOBAL struct Library          *WindowBase      = NULL,
                                *LayoutBase      = NULL,
                                *ButtonBase      = NULL,
                                *TextEditorBase  = NULL,
                                *LabelBase       = NULL,
                                *ListBrowserBase = NULL,
                                *ChooserBase     = NULL,
                                *StringBase      = NULL,
                                *CheckBoxBase    = NULL,
                                *BoardsBase      = NULL,
                                *BitMapBase      = NULL,
                                *FuelGaugeBase   = NULL,
                                *IntegerBase     = NULL,
                                *RadioButtonBase = NULL;
AGLOBAL TEXT                    asldir[VLONGFIELD + 1],
                                aslresult[VLONGFIELD + 1],
                                IOBuffer[LONGESTFIELD + 1],
                                globalname[VLONGFIELD + 1],
                                string[4096 + 1],
                                weekdaystring[LEN_DATSTRING],
                                datestring[LEN_DATSTRING],
                                timestring[LEN_DATSTRING];
AGLOBAL WORD                    xsize;
AGLOBAL SBYTE                   page             = 0,
                                closer           = 0;
AGLOBAL ULONG                   fillcolour,
                                increment,
                                offset,
                                wbval,
                                signal;
AGLOBAL ABOOL                   BattBuffer[96],
                                done             = FALSE,
                                fillwindows      = FALSE,
                                ram              = FALSE,
                                stop             = FALSE;
AGLOBAL struct Library*         IconBase         = NULL;
AGLOBAL struct Menu*            MenuPtr          = NULL;
AGLOBAL struct Screen*          ScreenPtr        = NULL;
AGLOBAL struct Window*          MainWindowPtr    = NULL;
AGLOBAL struct VisualInfo*      VisualInfoPtr    = NULL;
AGLOBAL struct ExAllData*       EADataPtr        = NULL;
AGLOBAL struct Gadget          *BU99_Right       = NULL,
                               *GListPtr         = NULL,
                               *PrevGadPtr       = NULL,
                               *ST1_Company      = NULL,
                               *ST1_Developer    = NULL,
                               *ST1_EMail        = NULL,
                               *ST1_FirstName    = NULL,
                               *ST1_LastName     = NULL,
                               *ST1_Phone        = NULL;
AGLOBAL struct List             EmptyList,
                                FileList;
AGLOBAL struct SharedStruct shared =
{   0,
    "", ""
};

IMPORT struct ExecBase*     SysBase;
// from f1.c
IMPORT struct ReportStruct  report;
// from f2.c
IMPORT struct AminetStruct  aminet;
// from f4.c
IMPORT struct AutodocStruct autodoc;
// from f6.c
IMPORT struct IFFStruct     iff;
// from f7.c
IMPORT struct Gadget*       eol_gadgets[GIDS_7 + 1];
// from f9.c
IMPORT struct Library*      BattMemBase;
// from f11.c
IMPORT struct AGDBStruct    agdb;
// from f12.c
IMPORT struct IconStruct    icon;
IMPORT struct Gadget*       icon_gadgets[GIDS_12 + 1];
IMPORT ABOOL                quit;

AGLOBAL       Object*          WinObject[FUNCTIONS + 1]; // note that WindowObject is a reserved macro

MODULE TEXT                    pubscreen[256 + 1];
MODULE WORD                    ysize;
MODULE ULONG                   ksval;
MODULE ABOOL                   logo   = TRUE;
MODULE        Object          *AboutWinObject = NULL;
MODULE struct Gadget*          gadgets[GIDS_0 + 1];
MODULE struct RDArgs*          ArgsPtr           = NULL;
MODULE struct TextFont*        FontPtr           = NULL;
MODULE struct WBArg*           WBArg             = NULL;
MODULE struct WBStartup*       WBMsg             = NULL;
MODULE struct ASLBase*         ASLBase         = NULL;
MODULE struct DiskFontBase*    DiskFontBase    = NULL;
MODULE struct Library*         GadToolsBase    = NULL;
MODULE struct IntuitionBase*   IntuitionBase   = NULL;
MODULE struct Library*         VersionBase     = NULL;
MODULE struct TextAttr         Topaz8 =
{	(STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
}, /* "topaz.font" is case-sensitive */ WormWars8 =
{	(STRPTR) "WormWars.font", 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
};
MODULE  struct EasyStruct       EasyStruct =
{   sizeof(struct EasyStruct),
    0,
    "Report+: Error",
    NULL,
    "Quit"
};

/* FUNCTIONS -------------------------------------------------------------- */

int main(int argc, char** argv)
{   UWORD  i;
    SLONG  args[13] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    BPTR   OldDir;
    SLONG  number = 0, hostid = 7;
//  BPTR   ConfigHandle = NULL;

    /* Start of program.

    version embedding into executable */

    if (0) /* that is, never */
        Printf("$VER: Report+ 5.4 (16.4.2002)"); /* always d.m.y format */

    for (i = 0; i <= FUNCTIONS; i++)
    {   WinObject[i] = NULL;
    }

    /* Check for OS3.9+... */
    if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 40L)))
    {   Printf("Report+: Need AmigaOS 3.9+!\n");
        cleanexit(EXIT_FAILURE);
    }
    if ((ksval = SysBase->LibNode.lib_Version) < 40L)
    {   Printf("Report+: Need AmigaOS 3.9+!\n");
        cleanexit(EXIT_FAILURE);
    }
    if (!(VersionBase = (struct Library *) OpenLibrary("version.library", 0L)))
        rq("Can't open version.library!");
    wbval = VersionBase->lib_Version;
    CloseLibrary((struct Library *) VersionBase);
    VersionBase = NULL;
    if (wbval < 45)
    {   Printf("Report+: Need AmigaOS 3.9+!\n");
        cleanexit(EXIT_FAILURE);
    }

    if (!(GadToolsBase = (struct Library *) OpenLibrary("gadtools.library", 38L)))
        rq("Can't open GadTools.library V38+!");
    if (!(ASLBase = (struct ASLBase *) OpenLibrary("asl.library", 0L)))
        rq("Can't open ASL.library!");
    if (
        (DiskFontBase = (struct DiskFontBase *) OpenLibrary("diskfont.library", 0L))
    &&  (FontPtr = OpenDiskFont(&WormWars8))
       )
    {   Gadget.ng_TextAttr = (struct TextAttr *) &WormWars8;
    } elif (!(FontPtr = OpenFont(&Topaz8)))
    {   rq("Can't open fonts!");
    } else
    {   Gadget.ng_TextAttr = (struct TextAttr *) &Topaz8;
    }

    if (!(ButtonBase      = OpenLibrary("gadgets/button.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/button.gadget\") failed!");
    if (!(CheckBoxBase    = OpenLibrary("gadgets/checkbox.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/checkbox.gadget\") failed!");
    if (!(ChooserBase     = OpenLibrary("gadgets/chooser.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/chooser.gadget\") failed!");
    if (!(LabelBase       = OpenLibrary("images/label.image", 44)))
                       rq("OpenLibrary(\"images/label.image\") failed!");
    if (!(LayoutBase      = OpenLibrary("gadgets/layout.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/layout.gadget\") failed!");
    if (!(ListBrowserBase = OpenLibrary("gadgets/listbrowser.gadget", 0)))
                       rq("OpenLibrary(\"gadgets/listbrowser.gadget\") failed!");
    if (!(StringBase      = OpenLibrary("gadgets/string.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/string.gadget\") failed!");
    if (!(TextEditorBase  = OpenLibrary("gadgets/texteditor.gadget", 0)))
                       rq("OpenLibrary(\"gadgets/texteditor.gadget\") failed!");
    if (!(WindowBase      = OpenLibrary("window.class", 44)))
                       rq("OpenLibrary(\"window.class\") failed!");
    if (!(BitMapBase      = OpenLibrary("images/bitmap.image", 44)))
                       rq("OpenLibrary(\"images/bitmap.image\") failed!");
    if (!(FuelGaugeBase   = OpenLibrary("gadgets/fuelgauge.gadget", 0)))
                       rq("OpenLibrary(\"gadgets/fuelgauge.gadget\") failed!");
    if (!(IntegerBase     = OpenLibrary("gadgets/integer.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/integer.gadget\") failed!");
    if (!(RadioButtonBase = OpenLibrary("gadgets/radiobutton.gadget", 45)))
                       rq("OpenLibrary(\"gadgets/radiobutton.gadget\") (V45) failed!");
    if (!(IconBase        = OpenLibrary("icon.library", 44)))
                       rq("Need icon.library V44+!");
          BoardsBase      = OpenLibrary("boards.library", 0);

    pubscreen[0] = 0;
    NewList(&EmptyList);
    NewList(&FileList);
    for (i = 0; i <= FUNCTIONS; i++)
    {   image[i]  =
        bitmap[i] = NULL;
    }
    if (!(EADataPtr = AllocVec(4096, MEMF_CLEAR | MEMF_PUBLIC)))
    {   rq("Out of memory!");
    }

    /* This is done for speed. Even though the Version command *might* be
    resident, or *might* fit entirely into the disk buffers, we shouldn't
    count on this being the case. So we copy the Version command into RAM:. */
    if (!SystemTags("Copy C:Version RAM:", SYS_Output, Open("NIL:", MODE_NEWFILE), TAG_DONE))
    {   ram = TRUE;
    }

    report_init();    // f1
    aminet_init();    // f2
    autodoc_init();   // f4
    size_init();      // f8
    batt_init();      // f9
    files_init();     // f10
    newagdb(FALSE);   // f11
    /* those must be done before we handle CLI arguments */

    if (argc) /* started from CLI */
    {   if (!(ArgsPtr = ReadArgs
        (   "-F=FILL/S,PUBSCREEN/K,-N=NOLOGO/S,FUNCTION/N,-I=ICONTYPE/K,"
            "RESET/S,TIMEOUT/S,LUNS/S,SYNC_XFER/S,SLOW_SYNC/S,TAG_QUEUES/S,HOST_ID/K/N,"
            "FILE/F",
            (LONG *) args,
            NULL
	)))
        {   Printf
            (   "Usage: %s [-f|FILL] [PUBSCREEN <screen>] [-n|NOLOGO] "
                "[[FUNCTION] <function> "
                "[-i|ICONTYPE DISK|DRAWER|TOOL|PROJECT|TRASHCAN|DEVICE|KICKSTART|APPICON] "
                "[RESET [TIMEOUT] [LUNS] [SYNC_XFER] [SLOW_SYNC] [TAG_QUEUES] [HOST_ID <host_id>]] "
                "[[FILE] <file(s)...>]]\n",
                argv[0]
            );
            cleanexit(EXIT_FAILURE);
	}
        if (args[0])
        {   fillwindows = TRUE;
        }
        if (args[1])
        {   strcpy(pubscreen, (STRPTR) args[1]);
        }
        if (args[2])
        {   logo = FALSE;
        }
        if (args[3])
        {   number = (SLONG) (*((SLONG *) args[3]));
            if (number >= 1 && number <= FUNCTIONS)
            {   page = closer = (number * 10) + 1;
                shared.function = number;
            } else
            {   Printf("Report+: <function> must be 1-%ld!\n", FUNCTIONS);
                cleanexit(EXIT_FAILURE);
        }   }
        if (args[4])
        {   if (number != 12)
            {   Printf("%s: <function> must be 12 for this!\n", argv[0]);
                cleanexit(EXIT_FAILURE);
            }
            if (!stricmp((STRPTR) args[4], "DISK"))
            {   icon.type = WBDISK;
            } elif (!stricmp((STRPTR) args[4], "DRAWER"))
            {   icon.type = WBDRAWER;
            } elif (!stricmp((STRPTR) args[4], "TOOL"))
            {   icon.type = WBTOOL;
            } elif (!stricmp((STRPTR) args[4], "PROJECT"))
            {   icon.type = WBPROJECT;
            } elif (!stricmp((STRPTR) args[4], "TRASHCAN"))
            {   icon.type = WBGARBAGE;
            } elif (!stricmp((STRPTR) args[4], "DEVICE"))
            {   icon.type = WBDEVICE;
            } elif (!stricmp((STRPTR) args[4], "KICKSTART"))
            {   icon.type = WBKICK;
            } elif (!stricmp((STRPTR) args[4], "APPICON"))
            {   icon.type = WBAPPICON;
            } else
            {   Printf("%s: <icontype> must be DISK, DRAWER, TOOL, PROJECT, TRASHCAN, DEVICE, KICKSTART or APPICON!\n", argv[0]);
                cleanexit(EXIT_FAILURE);
        }   }
        if (args[5] || args[6] || args[7] || args[8] || args[9] || args[10] || args[11])
        {   if (number != 9)
            {   Printf("%s: <function> must be 9 for this!\n", argv[0]);
                cleanexit(EXIT_FAILURE);
            }
            if (!args[5])
            {   Printf("%s: You need the RESET switch for this!\n", argv[0]);
                cleanexit(EXIT_FAILURE);
            }
            for (i = 0; i <= 95; i++)
            {   BattBuffer[i] = FALSE;
            }
            BattBuffer[BATTMEM_AMIGA_AMNESIA_ADDR]          =
            BattBuffer[BATTMEM_SHARED_AMNESIA_ADDR]         = TRUE; // these bits are inverted
            if (args[6])
            {   BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR]       = TRUE;
            } else BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR]    = FALSE;
            if (args[7])
            {   BattBuffer[BATTMEM_SCSI_LUNS_ADDR]          = TRUE;
            } else BattBuffer[BATTMEM_SCSI_LUNS_ADDR]       = FALSE;
            if (args[8])
            {   BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR]     = TRUE;
            } else BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR]  = FALSE;
            if (args[9])
            {   BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR]     = TRUE;
            } else BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR]  = FALSE;
            if (args[10])
            {   BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR]    = TRUE;
            } else BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR] = FALSE;
            if (args[11]) // these bits are inverted
            {   hostid = (SLONG) (*((SLONG *) args[11]));
                if (hostid < 0 || hostid > 7)
                {   Printf("%s: <host_id> must be 0-7!\n", argv[0]);
                    cleanexit(EXIT_FAILURE);
                }
                BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR]     = (hostid & 4)? 0 : 1;
                BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 1] = (hostid & 2)? 0 : 1;
                BattBuffer[BATTMEM_SCSI_HOST_ID_ADDR + 2] = (hostid & 1)? 0 : 1;
            }
            if (!BattMemBase)
            {   if (!(BattMemBase = OpenResource(BATTMEMNAME)))
                {   rq("Can't open battery RAM resource!");
            }   }
            writebatt(FALSE);
            Printf("Done.\n");
            cleanexit(EXIT_SUCCESS);
        }
        if (args[12])
        {   switch(number)
            {
            case 1:
                strcpy(report.output, (STRPTR) args[12]);
                loadreport();
            break;
            case 2:
                strcpy(aminet.output, (STRPTR) args[12]);
                loadaminet();
            break;
            case 4:
                strcpy(autodoc.output, (STRPTR) args[12]);
                loadautodoc();
            break;
            case 6:
                strcpy(iff.pathname, (STRPTR) args[12]);
            break;
            case 7:
                // strcpy(icon.pathname, (STRPTR) args[12]); no need for this
                strcpy(shared.pathname, (STRPTR) args[12]);
                convert(FALSE);
                Printf("All done.\n");
                cleanexit(EXIT_SUCCESS);
            break;
            case 11:
                strcpy(  agdb.output, (STRPTR) args[12]);
                loadagdb();
            break;
            case 12:
                // strcpy(icon.pathname, (STRPTR) args[12]); // no need for this
                strcpy(shared.pathname, (STRPTR) args[12]);
                convert(FALSE);
                Printf("All done.\n");
                cleanexit(EXIT_SUCCESS);
            break;
            default:
                Printf("Report+: <function> must be 1, 2, 6, 7, 11 or 12 for this!\n");
                cleanexit(EXIT_FAILURE);
            break;
    }   }   }
    else /* started from WB */
    {   WBMsg = (struct WBStartup *) argv;
        WBArg = WBMsg->sm_ArgList; /* head of the arg list */
        for (i = 0; i < WBMsg->sm_NumArgs; i++, WBArg++)
        {   if (WBArg->wa_Lock)
            {   /* something that does not support locks */
                parsewb();
            } else
            {   /* lock supported; change to the proper directory */
                OldDir = CurrentDir(WBArg->wa_Lock);
                parsewb();
                CurrentDir(OldDir);
            }
            if (i == 1)
            {   ; /* we were started from a project icon, which is
                currently unsupported */
    }   }   }

    strcpy(asldir, "PROGDIR:");
    /* RKM Libraries, p. 59-61: */
    lockscreen();
    if (GetVPModeID(&(ScreenPtr->ViewPort)) == INVALID_ID)
    {   rq("Invalid default public screen mode ID!");
    }
    xsize = ScreenPtr->Width;
    ysize = ScreenPtr->Height;
    unlockscreen();

/*  if (ConfigHandle = (BPTR) Open("PROGDIR:ReportPlus.config", MODE_OLDFILE))
    {   if (Read(ConfigHandle, IOBuffer, 24 != -1))
        {   manuf_config(); //                                         20
            iff_config();   //                                       19
            eol_config();   //   0102030405
            size_config();  // 00          06                            2122
            files_config(); //               0708091011                      23
            icon_config();  //                                 161718
            // spare                                   12131415
        }
        Close(ConfigHandle);
        ConfigHandle = NULL;
    } */

    while(1)
    {   if (page != 1)
        {   shared.function = page / 10;
        }
        if (page == 1)
            sender();
        elif (page == 11)
            report1();
        elif (page == 12)
            report2();
        elif (page == 21)
            aminet1();
        elif (page == 31)
            acse1();
        elif (page == 32)
            acse2();
        elif (page == 41)
            autodoc1();
        elif (page == 42)
            autodoc2();
        elif (page == 51)
            manuf1();
        elif (page == 61)
            iff1();
        elif (page == 71)
            eol1();
        elif (page == 81)
            size1();
        elif (page == 91)
            batt1();
        elif (page == 101)
            files1();
        elif (page == 111)
            agdb1();
        elif (page == 121)
        {   icon1();
        } else
        {   /* assert(page == 0); */
            menu();
}   }   }

MODULE void menu(void)
{   PERSIST ABOOL       first = TRUE;
    AUTO    struct Hook Hook0Struct;
    AUTO    ULONG       i, tag[2];
    AUTO    LONG        bgpen;

    if (first)
    {   lockscreen();
        for (i = 0; i < FUNCTIONS; i++)
        {   image[i] = BitMapObject,
                BITMAP_SourceFile, imagename[i],
                BITMAP_Width,      35,
                BITMAP_Height,     32,
                BITMAP_Screen,     ScreenPtr,
            EndImage;
            if (!image[i])
            {   rq("Can't create ReAction image(s)!");
            }
            GetAttr(BITMAP_BitMap, image[i], (ULONG *) &bitmap[i]);
        }
        unlockscreen();
        first = FALSE;
    }

    /* PAGE 0 ************************************************************* */

    gadtools(); // needed for menu strip
    InitHook(&Hook0Struct, Hook0Func, NULL);

    lockscreen();

    bgpen = FindColor
    (   ScreenPtr->ViewPort.ColorMap,
        0x96969696,
        0x96969696,
        0x96969696,
        -1
    );

    if (logo)
    {   tag[0] = LAYOUT_AddImage;
        tag[1] = NewObject
        (   BITMAP_GetClass(), NULL,
            // bitmap tags
            BITMAP_SourceFile, "PROGDIR:images/logo.ilbm",
            BITMAP_Masking,    TRUE,
            BITMAP_Screen,     ScreenPtr,
            TAG_DONE
        );
    } else
    {   tag[0] = TAG_IGNORE;
        tag[1] = NULL;
    }

    if (!(WinObject[0] = NewObject(WINDOW_GetClass(), NULL,
        // window tags
        WA_PubScreen,             ScreenPtr,
        WA_ScreenTitle,           TITLEBARTEXT,
        WA_Title,                 "Report+: Main Menu",
        WA_Activate,              TRUE,
        WA_DepthGadget,           TRUE,
        WA_DragBar,               TRUE,
        WA_CloseGadget,           TRUE,
        WA_IDCMP,                 IDCMP_RAWKEY | IDCMP_INTUITICKS,
        WINDOW_IDCMPHook,         &Hook0Struct,
        WINDOW_IDCMPHookBits,     IDCMP_RAWKEY | IDCMP_INTUITICKS,
        WINDOW_MenuStrip,         MenuPtr,
        WINDOW_Position,          WPOS_CENTERSCREEN,
        WINDOW_ParentGroup,       gadgets[GID_0_LY1] =
        NewObject
        (   LAYOUT_GetClass(),         NULL,
            // root-layout tags
            LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
            LAYOUT_SpaceOuter,         TRUE,
            LAYOUT_DeferLayout,        TRUE,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),     NULL,
                // layout tags
                LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,     TRUE,
                LAYOUT_DeferLayout,    TRUE,
                LAYOUT_HorizAlignment, LALIGN_CENTER,
                tag[0],                tag[1],
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(), NULL,
                // layout tags
                LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,     TRUE,
                LAYOUT_DeferLayout,    TRUE,
                LAYOUT_HorizAlignment, LALIGN_CENTER,
                LAYOUT_AddImage,
                NewObject
                (   LABEL_GetClass(),    NULL,
                    // label tags
                    LABEL_Justification, LJ_CENTRE,
                    LABEL_Text,          "Edit:",
                    TAG_END
                ),
                TAG_END
            ),
            CHILD_WeightedHeight,      0,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,         TRUE,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,           gadgets[GID_0_BU1] =
                NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU1,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,
                    NewObject
                    (   BITMAP_GetClass(),   NULL,
                        // bitmap tags
                        BITMAP_BitMap,       bitmap[1 - 1],
                        BITMAP_Width,        35,
                        BITMAP_Height,       32,
                        TAG_DONE
                    ),
                    BUTTON_BackgroundPen,    bgpen,
                    BUTTON_FillPen,          bgpen,
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU2] =
                NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU2,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,
                    NewObject
                    (   BITMAP_GetClass(),   NULL,
                        // bitmap tags
                        BITMAP_BitMap,       bitmap[2 - 1],
                        BITMAP_Width,        35,
                        BITMAP_Height,       32,
                        TAG_DONE
                    ),
                    BUTTON_BackgroundPen,    bgpen,
                    BUTTON_FillPen,          bgpen,
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU3] =
                NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU3,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,              NewObject
                    (   BITMAP_GetClass(),   NULL,
                        // bitmap tags
                        BITMAP_BitMap,       bitmap[4 - 1],
                        BITMAP_Width,        35,
                        BITMAP_Height,       32,
                        TAG_DONE
                    ),
                    BUTTON_BackgroundPen,    bgpen,
                    BUTTON_FillPen,          bgpen,
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU4] = NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU4,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,              NewObject
                    (   BITMAP_GetClass(),   NULL,
                        // bitmap tags
                        BITMAP_BitMap,       bitmap[9 - 1],
                        BITMAP_Width,        35,
                        BITMAP_Height,       32,
                        TAG_DONE
                    ),
                    BUTTON_BackgroundPen,    bgpen,
                    BUTTON_FillPen,          bgpen,
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU5] = (struct Gadget *) NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU5,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,              NewObject
                    (   BITMAP_GetClass(),   NULL,
                        // bitmap tags
                        BITMAP_BitMap,       bitmap[11 - 1],
                        BITMAP_Width,        35,
                        BITMAP_Height,       32,
                        TAG_DONE
                    ),
                    BUTTON_BackgroundPen,    bgpen,
                    BUTTON_FillPen,          bgpen,
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,         TRUE,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,    TRUE,
                         LAYOUT_DeferLayout,   TRUE,
                         LAYOUT_HorizAlignment, LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(), NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "View:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU6] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU6,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[5 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        LAYOUT_AddChild,           gadgets[GID_0_BU7] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU7,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[6 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,    TRUE,
                         LAYOUT_DeferLayout,   TRUE,
                         LAYOUT_HorizAlignment, LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(), NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "Process:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU8] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU8,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[7 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        LAYOUT_AddChild,           gadgets[GID_0_BU9] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU9,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[12 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,         TRUE,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),       NULL,
                         // layout tags
                         LAYOUT_Orientation,      LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,       TRUE,
                         LAYOUT_DeferLayout,      TRUE,
                         LAYOUT_HorizAlignment,   LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(),    NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "Report:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU10] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU10,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[8 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        LAYOUT_AddChild,           gadgets[GID_0_BU11] =
                        NewObject
                        (   NULL,                  "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU11,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[10 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,    TRUE,
                         LAYOUT_DeferLayout,   TRUE,
                         LAYOUT_HorizAlignment, LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(), NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "Conduct:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU12] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU12,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(),   NULL,
                                // bitmap tags
                                BITMAP_BitMap,       bitmap[3 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,  bgpen,
                            BUTTON_FillPen,        bgpen,
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,          gadgets[GID_0_ST1] =
            NewObject
            (   STRING_GetClass(),    NULL,
                // string tags
                GA_ID,                GID_0_ST1,
                GA_ReadOnly,          TRUE,
                STRINGA_TextVal,      TITLEBARTEXT,
                TAG_END
            ),
            CHILD_WeightedHeight,     0,
            TAG_DONE
        ),
        TAG_DONE
    )))
    {   rq("Can't create ReAction gadgets!");
    }
    unlockscreen();
    openwindow();
    loop();
    closewindow();
}

AGLOBAL void cleanexit(SBYTE rc)
{   // BPTR  ConfigHandle;
       ULONG i;

    /* ASL requesters are assumed to be already closed.
    iffparse.library is never opened or closed. :-O */

    /* help|about... */
    if (AboutWindowPtr)
    {   DisposeObject(AboutWinObject);
        AboutWindowPtr = NULL;
    }

    /* all */
    unlockscreen(); // in case the screen is locked
    closewindow();

    /* Remember that you can't fool around with the list whilst the
    gadget is still using it. So we close the window before calling
    these next routines. */

    report_die();  // f1: deallocates "subsystem" list
    aminet_exit(); // f2: deallocates "subdirectory" list
    aminet_die();  // f2: deallocates "main directory" list
    acse_exit();   // f3: shuts down timer
    manuf_die();
    eol_die();
    size_exit();
    size_die();    // f8: deallocates "empty" (1-node) columnar list
    files_exit();  // f10: deallocates "result" list & closes logfile handle
    files_die();
    icon_die();

    if (ram)
    {   if (!SystemTags("Delete RAM:Version", SYS_Output, Open("NIL:", MODE_NEWFILE), TAG_DONE))
        {   ram = FALSE;
    }   }
    if (EADataPtr)
    {   FreeVec(EADataPtr);
        EADataPtr = NULL;
    }
    if (FontPtr)
    {   CloseFont(FontPtr);
        FontPtr = NULL;
    }
    if (ArgsPtr)
    {   FreeArgs(ArgsPtr);
        ArgsPtr = NULL;
    }

    /* Dispose the images ourselves as button.gadget doesn't
     * do this for its GA_Image...
     */

    for (i = 0; i <= FUNCTIONS; i++)
    {   if (image[i])
        {   DisposeObject(image[i]);
            image[i] = NULL;
    }   }

/*  if (rc == EXIT_SUCCESS)
    {   if (ConfigHandle = (BPTR) Open("PROGDIR:ReportPlus.config", MODE_NEWFILE))
        {   Write(ConfigHandle, IOBuffer, 24);
            Close(ConfigHandle);
            ConfigHandle = NULL;
    }   } */

    /* ReAction */
    if (WindowBase)
    {   CloseLibrary(WindowBase);
    }
    if (TextEditorBase)
    {   CloseLibrary(TextEditorBase);
    }
    if (StringBase)
    {   CloseLibrary(StringBase);
    }
    if (ListBrowserBase)
    {   CloseLibrary(ListBrowserBase);
    }
    if (LayoutBase)
    {   CloseLibrary(LayoutBase);
    }
    if (LabelBase)
    {   CloseLibrary(LabelBase);
    }
    if (IntegerBase)
    {   CloseLibrary(IntegerBase);
    }
    if (FuelGaugeBase)
    {   CloseLibrary(FuelGaugeBase);
    }
    if (ChooserBase)
    {   CloseLibrary(ChooserBase);
    }
    if (CheckBoxBase)
    {   CloseLibrary(CheckBoxBase);
    }
    if (ButtonBase)
    {   CloseLibrary(ButtonBase);
    }
    if (BitMapBase)
    {   CloseLibrary(BitMapBase);
    }

    if (BoardsBase)
        CloseLibrary((struct Library *) BoardsBase);
    if (IconBase)
        CloseLibrary((struct Library *) IconBase);
    if (DiskFontBase)
        CloseLibrary((struct Library *) DiskFontBase);
    if (ASLBase)
        CloseLibrary((struct Library *) ASLBase);
    if (GadToolsBase)
        CloseLibrary((struct Library *) GadToolsBase);
    if (IntuitionBase)
    {   OpenWorkBench();
        CloseLibrary((struct Library *) IntuitionBase);
    }

    exit(rc); /* End of program. */
}

MODULE void clearkybd(void)
{   struct IntuiMessage* MsgPtr;

    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
        GT_ReplyIMsg(MsgPtr);
}

AGLOBAL void FreeNameNodes(struct List* ListPtr)
{   /* RKM Libraries, p. 496:
	
    "Free the entire list, including the header. The header is not
    updated as the list is freed. This function demonstrates how to
    avoid referencing freed memory when deallocating nodes." */

    struct NameNode *WorkNodePtr, *NextNodePtr;
	
    WorkNodePtr = (struct NameNode *) (ListPtr->lh_Head); /* first node */
    while (NextNodePtr = (struct NameNode *) (WorkNodePtr->nn_Node.ln_Succ))
    {   FreeMem(WorkNodePtr, sizeof(struct NameNode));
        WorkNodePtr = NextNodePtr;
}   }
MODULE void FreePathnameNodes(struct List* ListPtr)
{   struct PathnameNode *WorkNodePtr, *NextNodePtr;
	
    WorkNodePtr = (struct PathnameNode *) (ListPtr->lh_Head); /* first node */
    while (NextNodePtr = (struct PathnameNode *) (WorkNodePtr->nn_Node.ln_Succ))
    {   FreeMem(WorkNodePtr, sizeof(struct PathnameNode));
        WorkNodePtr = NextNodePtr;
}   }

AGLOBAL void gadtools(void)
{   lockscreen();
    if (!(Gadget.ng_VisualInfo = VisualInfoPtr = (struct VisualInfo *) GetVisualInfo(ScreenPtr, TAG_DONE)))
    {   rq("Can't get GadTools visual info!");
    }
    unlockscreen();

    if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
    {   rq("Can't create menus!");
    }
    if (!(LayoutMenus(MenuPtr, VisualInfoPtr, GTMN_NewLookMenus, TRUE, TAG_DONE)))
    {   rq("Can't lay out menus!");
    }
    GListPtr = NULL; /* that needs doing for the CreateContext() call */
    if (!(PrevGadPtr = (struct Gadget *) CreateContext(&GListPtr)))
    {   rq("Can't create GadTools context!");
}   }

AGLOBAL void verynewwindow(SWORD width, SWORD height, STRPTR title, ULONG idcmp)
{   // Function to open a GadTools window.

    gadtools();
    lockscreen();

    /* open the window on the public screen */
    if (!(MainWindowPtr = (struct Window*) OpenWindowTags
    (   NULL,
        WA_Left,         (xsize / 2) - (width / 2),
        WA_Top,          12 + ((ysize - 12) / 2) - (height / 2),
        WA_Width,        width,
        WA_Height,       height,
        WA_IDCMP,        IDCMP_CLOSEWINDOW | IDCMP_MENUPICK | IDCMP_REFRESHWINDOW
                         | IDCMP_MOUSEBUTTONS | IDCMP_INTUITICKS | IDCMP_VANILLAKEY
                         | IDCMP_RAWKEY | idcmp,
        WA_Gadgets,      NULL,
        WA_PubScreen,    ScreenPtr,
        WA_Activate,     TRUE,
        WA_Title,        title,
        WA_DragBar,      TRUE,
        WA_DepthGadget,  TRUE,
        WA_CloseGadget,  TRUE,
        WA_SmartRefresh, TRUE,
        WA_NewLookMenus, TRUE,
        TAG_DONE
    )))
    {   rq("Can't open window!");
    }
    unlockscreen();
    signal = 1L << MainWindowPtr->UserPort->mp_SigBit;

    SetMenuStrip(MainWindowPtr, MenuPtr);
    SetFont(MainWindowPtr->RPort, FontPtr);

    if (fillwindows)
    {   getfillcolour();
        SetAPen
        (   MainWindowPtr->RPort,
            fillcolour
        );
        RectFill
        (   MainWindowPtr->RPort,
            MainWindowPtr->BorderLeft,
            MainWindowPtr->BorderTop,
             width - 1 - MainWindowPtr->BorderRight,
            height - 1 - MainWindowPtr->BorderBottom
        );
    }

    navigate();
}

AGLOBAL void helpabout(void)
{   PERSIST ABOOL first = TRUE;

    if (AboutWindowPtr)
    {   return;
    }

    lockscreen();

    if (first)
    {   image[12] = BitMapObject,
            BITMAP_SourceFile, imagename[12],
            BITMAP_Width,      44,
            BITMAP_Height,     38,
            BITMAP_Screen,     ScreenPtr,
        EndImage;
        if (!image[12])
        {   rq("Can't create ReAction image!");
        }
        GetAttr(BITMAP_BitMap, image[12], (ULONG *) &bitmap[12]);
        unlockscreen();
        first = FALSE;
    }

    if (!(AboutWinObject = NewObject(WINDOW_GetClass(), NULL,
        // window tags
        WA_PubScreen,             ScreenPtr,
        WA_ScreenTitle,           TITLEBARTEXT,
        WA_Title,                 "About Report+",
        WA_Activate,              TRUE,
        WA_DepthGadget,           TRUE,
        WA_DragBar,               TRUE,
        WA_CloseGadget,           TRUE,
        WINDOW_Position,          WPOS_CENTERSCREEN,
        WINDOW_ParentGroup,       gadgets[GID_0_LY2] =
        NewObject
        (   LAYOUT_GetClass(),         NULL,
            // root-layout tags
            LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
            LAYOUT_SpaceOuter,         TRUE,
            LAYOUT_DeferLayout,        TRUE,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),     NULL,
                // layout tags
                LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
                LAYOUT_SpaceOuter,     TRUE,
                LAYOUT_DeferLayout,    TRUE,
                LAYOUT_VertAlignment,  LALIGN_CENTER,
                LAYOUT_AddImage,
                NewObject
                (   BITMAP_GetClass(),   NULL,
                    // bitmap tags
                    BITMAP_BitMap,       bitmap[12],
                    BITMAP_Width,        44,
                    BITMAP_Height,       38,
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(), NULL,
                // layout tags
                LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
                LAYOUT_SpaceOuter,     TRUE,
                LAYOUT_DeferLayout,    TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(), NULL,
                    // layout tags
                    LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                    LAYOUT_SpaceOuter,     FALSE,
                    LAYOUT_DeferLayout,    TRUE,
                    LAYOUT_AddImage,
                    NewObject
                    (   LABEL_GetClass(),    NULL,
                        // label tags
                        LABEL_Justification, LJ_CENTRE,
                        LABEL_Text,          TITLEBARTEXT,
                        TAG_END
                    ),
                    TAG_END
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(), NULL,
                    // layout tags
                    LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                    LAYOUT_SpaceOuter,     FALSE,
                    LAYOUT_DeferLayout,    TRUE,
                    LAYOUT_AddImage,
                    NewObject
                    (   LABEL_GetClass(),    NULL,
                        // label tags
                        LABEL_Justification, LJ_CENTRE,
                        LABEL_Text,          "Tuesday 16 April 2002",
                        TAG_END
                    ),
                    TAG_END
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(), NULL,
                    // layout tags
                    LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                    LAYOUT_SpaceOuter,     FALSE,
                    LAYOUT_DeferLayout,    TRUE,
                    LAYOUT_AddImage,
                    NewObject
                    (   LABEL_GetClass(),    NULL,
                        // label tags
                        LABEL_Justification, LJ_CENTRE,
                        LABEL_Text,          " ",
                        TAG_END
                    ),
                    TAG_END
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(), NULL,
                    // layout tags
                    LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                    LAYOUT_SpaceOuter,     FALSE,
                    LAYOUT_DeferLayout,    TRUE,
                    LAYOUT_AddImage,
                    NewObject
                    (   LABEL_GetClass(),    NULL,
                        // label tags
                        LABEL_Justification, LJ_CENTRE,
                        LABEL_Text,          "© 2002 Amigan Software",
                        TAG_END
                    ),
                    TAG_END
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(), NULL,
                    // layout tags
                    LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                    LAYOUT_SpaceOuter,     FALSE,
                    LAYOUT_DeferLayout,    TRUE,
                    LAYOUT_AddImage,
                    NewObject
                    (   LABEL_GetClass(),    NULL,
                        // label tags
                        LABEL_Justification, LJ_CENTRE,
                        LABEL_Text,          "By James R. Jacobs",
                        TAG_END
                    ),
                    TAG_END
                ),
                TAG_DONE
            ),
            TAG_DONE
        ),
        TAG_DONE
    )))
    {   rq("Can't create ReAction objects!");
    }
    unlockscreen();

    if (!(AboutWindowPtr = (struct Window *) DoMethod((Object *) AboutWinObject, WM_OPEN, NULL)))
    {   rq("Can't open ReAction window!");
    }

    OffMenu(MainWindowPtr, FULLMENUNUM(MN_HELP, IN_ABOUT, NOSUB));
}

AGLOBAL void closewindow(void)
{   if (MainWindowPtr)
    {   clearkybd();

        if
        (   page != 1
         && (shared.function == 0
             || shared.function == 2
             || shared.function == 4
             || shared.function == 5
             || shared.function == 7
             || shared.function == 8
             || shared.function == 10
             || shared.function == 11
             || shared.function == 12
        )   )
        {   /* Disposing of the window object will also close the window if it is
             * already opened, and it will dispose of the layout object attached to it.
             */
            DisposeObject(WinObject[shared.function]);
            WinObject[shared.function] = NULL;
            MainWindowPtr = NULL;
        } else
        {   ClearMenuStrip(MainWindowPtr);
            CloseWindow(MainWindowPtr);
            MainWindowPtr = NULL;
    }   }
    if (GListPtr)
    {   FreeGadgets(GListPtr);
        GListPtr = NULL;
    }
    if (MenuPtr)
    {   FreeMenus(MenuPtr);
        MenuPtr = NULL;
    }
    if (VisualInfoPtr)
    {   FreeVisualInfo(VisualInfoPtr);
        VisualInfoPtr = NULL;
}   }

AGLOBAL ABOOL asl(STRPTR pattern)
{   struct FileRequester* ASLRqPtr;
    ABOOL                 success;

    /* asldir is the directory that the ASL requester will start in. */

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, pattern, ASL_Window, MainWindowPtr, TAG_DONE)))
        rq("Can't create ASL request!");
    if
    (   AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ file selector", ASL_FuncFlags, FILF_PATGAD, TAG_DONE)
     && *(ASLRqPtr->rf_File) != 0
    )
    {   strcpy(asldir, ASLRqPtr->rf_Dir);
        strcpy(aslresult, ASLRqPtr->rf_Dir);
        if (!AddPart(aslresult, ASLRqPtr->rf_File, VLONGFIELD))
        {   FreeAslRequest(ASLRqPtr);
            rq("Can't add filename to pathname!");
        }
        success = TRUE;
    } else
    {   // either the user chose Cancel, or clicked OK with an empty filename
        strcpy(aslresult, "");
        success = FALSE;
    }
    // assert(ASLRqPtr);
    FreeAslRequest(ASLRqPtr);
    return(success);
}

AGLOBAL void loop(void)
{   AUTO SWORD                oldpage = page;
    AUTO struct Gadget*       addr;
    AUTO struct IntuiMessage* MsgPtr;
    AUTO UWORD                code, qual;
    AUTO ULONG                class, result;
    AUTO SWORD                mousex, mousey;

    closer = page;
    done = FALSE;
    while (page == oldpage && !done)
    {   if (AboutWindowPtr)
        {   if (aboutloop())
            {   DisposeObject(AboutWinObject);
                AboutWindowPtr = NULL;
                OnMenu(MainWindowPtr, FULLMENUNUM(MN_HELP, IN_ABOUT, NOSUB));
        }   }
        else
        {   if ((Wait(signal | SIGBREAKF_CTRL_C)) & SIGBREAKF_CTRL_C)
            {  done = TRUE;
               /* should we clear the Ctrl-C signal? */
        }   }
        if
        (   shared.function ==  0
         || (shared.function == 1 && page == 12)
         || shared.function ==  2
         || shared.function ==  4
         || shared.function ==  5
         || shared.function ==  7
         || shared.function ==  8
         || shared.function == 10
         || shared.function == 11
         || shared.function == 12
        ) // handle ReAction windows
        {   while ((result = DoMethod(WinObject[shared.function], WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
            {   switch (result & WMHI_CLASSMASK)
                {
                case WMHI_MENUPICK:
                    handlemenus(code);
                break;
                case WMHI_CLOSEWINDOW:
                    if (page == 0)
                    {   cleanexit(EXIT_SUCCESS);
                    } else page = 0;
                break;
                case WMHI_GADGETUP:
                    switch(shared.function)
                    {
                    case 0:
                        menu_loop(result & WMHI_GADGETMASK);
                    break;
                    case 1:
                        report_ra_loop(result & WMHI_GADGETMASK);
                    break;
                    case 2:
                        aminet_loop(result & WMHI_GADGETMASK);
                    break;
                    case 4:
                        autodoc_loop(result & WMHI_GADGETMASK);
                    break;
                    case 5:
                        manuf_loop(result & WMHI_GADGETMASK);
                    break;
                    case 7:
                        eol_loop(result & WMHI_GADGETMASK);
                    break;
                    case 8:
                        size_loop(result & WMHI_GADGETMASK);
                    break;
                    case 10:
                        files_loop(result & WMHI_GADGETMASK);
                    break;
                    case 11:
                        agdb_loop(result & WMHI_GADGETMASK);
                    break;
                    case 12:
                        icon_loop(result & WMHI_GADGETMASK);
                    break;
                    default:
                        ; // assert(0);
                    break;
                    }
                break;
                default:
                break;
        }   }   }
        else // handle GadTools windows
        {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
            {   class  = MsgPtr->Class;                       
                code   = MsgPtr->Code;
                addr   = MsgPtr->IAddress;
                qual   = MsgPtr->Qualifier;
                mousex = MsgPtr->MouseX;
                mousey = MsgPtr->MouseY;
                GT_ReplyIMsg(MsgPtr);
                if (class == IDCMP_CLOSEWINDOW && page == 31)
                {   acse_loop(IDCMP_CLOSEWINDOW, addr, code);
                } else
                {   switch(class)
                    {
                    case IDCMP_MENUPICK:
                        handlemenus(code);
                    break;
                    case IDCMP_CLOSEWINDOW:
                        if (page == 1)
                        {   if (shared.function == 1)
                            {   page = 11;
                            } else
                            {   // assert(shared.function == 3);
                                page = 32;
                        }   }
                        else page = 0;
                    break;
                    case IDCMP_REFRESHWINDOW:
                        GT_BeginRefresh(MainWindowPtr);
                        GT_EndRefresh(MainWindowPtr, TRUE);
                    break;
                    default:
                        if (class == IDCMP_RAWKEY && code == SCAN_HELP)
                            helpabout();
                        elif (class == IDCMP_VANILLAKEY && code == ESCAPE && ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT)))
                            cleanexit(EXIT_SUCCESS);
                        elif (page == 1)
                            sender_loop(class, addr, code, qual);
                        elif (page == 11)
                            report_gt_loop(class, addr, code, qual);
                        elif (page >= 31 && page <= 32)
                            acse_loop(class, addr, code);
                        elif (page == 61)
                            iff_loop(class, addr, code, qual);
                        elif (page == 91)
                            batt_loop(class, addr, code, qual, mousex, mousey);
                    break;
}   }   }   }   }   }

AGLOBAL void navigate(void)
{   gadtools();

    /* BU99_Right is created first, as all windows use it. Therefore all
    windows can safely call AddGList(), etc. with the BU99_Right argument.
    This is the only purpose of its existence. */

    setgadget(0, 0, 0, 0, "", NULL);
    BU99_Right = PrevGadPtr = (struct Gadget *) CreateGadget
    (   GENERIC_KIND,
        PrevGadPtr,
        &Gadget,
        TAG_DONE
    );
}

AGLOBAL void setgadget(WORD leftx, WORD topy, WORD width, WORD height,
STRPTR text, ULONG flags)
{   Gadget.ng_LeftEdge   = leftx;
    Gadget.ng_TopEdge    = topy;
    Gadget.ng_Width      = width;
    Gadget.ng_Height     = height;
    Gadget.ng_GadgetText = text;
    Gadget.ng_Flags      = flags;
}

AGLOBAL ABOOL readin(STRPTR pathname)
{   BPTR FileHandle;

    if (!(FileHandle = (BPTR) Open(pathname, MODE_OLDFILE)))
        return FALSE;
    if (Read(FileHandle, IOBuffer, LONGESTFIELD) == -1)
    /* Limitation: the whole file must be < 16K */
    {   Close(FileHandle);
        return FALSE;
    }
    Close(FileHandle);
    return TRUE;
}

AGLOBAL void writeout(STRPTR pathname)
{   BPTR FileHandle;

    if (!(FileHandle = (BPTR) Open(pathname, MODE_NEWFILE)))
        rq("Can't open file for writing!");
    if (Write(FileHandle, IOBuffer, strlen(IOBuffer)) == -1)
    {   Close(FileHandle);
        rq("Can't write to file!");
    }
    Close(FileHandle);
}

AGLOBAL void rq(STRPTR text)
{   EasyStruct.es_TextFormat = text;
    EasyRequest(MainWindowPtr, &EasyStruct, NULL);

    cleanexit(EXIT_FAILURE);
}

AGLOBAL void readordie(STRPTR pathname)
{   BPTR FileHandle;

    if (!(FileHandle = (BPTR) Open(pathname, MODE_OLDFILE)))
        rq("Can't open file for reading!");
    if (Read(FileHandle, IOBuffer, LONGESTFIELD) == -1)
    {   Close(FileHandle);
        rq("Can't read file!");
    }
    if (!Close(FileHandle))
        rq("Can't close file for reading!");
}

MODULE void parsewb(void)
{   struct DiskObject* DiskObject;
    STRPTR*            ToolArray;
    STRPTR             s;

    if ((*WBArg->wa_Name) && (DiskObject = GetDiskObject(WBArg->wa_Name)))
    {   ToolArray = (STRPTR *) DiskObject->do_ToolTypes;

        if (s = FindToolType((CONST_STRPTR *) ToolArray, "FILL"))
            fillwindows = TRUE;
        if (s = FindToolType((CONST_STRPTR *) ToolArray, "PUBSCREEN"))
            strcpy(pubscreen, s);
        if (s = FindToolType((CONST_STRPTR *) ToolArray, "NOLOGO"))
            logo = FALSE;
        if (s = FindToolType((CONST_STRPTR *) ToolArray, "ICONTYPE"))
        {   if (MatchToolValue(s, "DISK"))
            {   icon.type = WBDISK - 1;
            } elif (MatchToolValue(s, "DRAWER"))
            {   icon.type = WBDRAWER - 1;
            } elif (MatchToolValue(s, "TOOL"))
            {   icon.type = WBTOOL - 1;
            } elif (MatchToolValue(s, "PROJECT"))
            {   icon.type = WBPROJECT - 1;
            } elif (MatchToolValue(s, "TRASHCAN"))
            {   icon.type = WBGARBAGE - 1;
            } elif (MatchToolValue(s, "DEVICE"))
            {   icon.type = WBDEVICE - 1;
            } elif (MatchToolValue(s, "KICKSTART"))
            {   icon.type = WBKICK - 1;
            } elif (MatchToolValue(s, "APPICON"))
            {   icon.type = WBAPPICON - 1;
        }   }
        if (s = FindToolType((CONST_STRPTR *) ToolArray, "FUNCTION"))
        {   if (MatchToolValue(s, "1"))
                page = 11;
            elif (MatchToolValue(s, "2"))
                page = 21;
            elif (MatchToolValue(s, "3"))
                page = 31;
            elif (MatchToolValue(s, "4"))
                page = 41;
            elif (MatchToolValue(s, "5"))
                page = 51;
            elif (MatchToolValue(s, "6"))
                page = 61;
            elif (MatchToolValue(s, "7"))
                page = 71;
            elif (MatchToolValue(s, "8"))
                page = 81;
            elif (MatchToolValue(s, "9"))
                page = 91;
            elif (MatchToolValue(s, "10"))
                page = 101;
            elif (MatchToolValue(s, "11"))
            {   page = 111;
            } elif (MatchToolValue(s, "12"))
            {   page = 121;
        }   }
        FreeDiskObject(DiskObject);
}   }

AGLOBAL void getdate(void)
{   struct DateTime DateTime;

    DateTime.dat_Format  = FORMAT_DOS;
    DateTime.dat_Flags   = NULL;
    DateTime.dat_StrDay  = weekdaystring;
    DateTime.dat_StrDate = datestring;
    DateTime.dat_StrTime = timestring;

    DateStamp(&(DateTime.dat_Stamp));
    if (!DateToStr(&DateTime))
        rq("Can't convert date!");
}

AGLOBAL void AddNameToTail(struct List* ListPtr, STRPTR name)
{   /* RKM Libraries, p. 496:
	
    "Allocate a NameNode structure, copy the given name into the
    structure, then add it [to] the...list." */

    struct NameNode* NameNodePtr;

    if (!(NameNodePtr = AllocMem(sizeof(struct NameNode), MEMF_CLEAR)))
        rq("Out of memory!");
    strcpy(NameNodePtr->nn_Data, name);
    NameNodePtr->nn_Node.ln_Name = NameNodePtr->nn_Data;
    NameNodePtr->nn_Node.ln_Type = NT_USER;
    NameNodePtr->nn_Node.ln_Pri  = 0;
    AddTail((struct List *) ListPtr, (struct Node *) NameNodePtr);
}
MODULE void AddPathnameToTail(struct List* ListPtr, STRPTR name)
{   struct PathnameNode* PathnameNodePtr;

    if (!(PathnameNodePtr = AllocMem(sizeof(struct PathnameNode), MEMF_CLEAR)))
        rq("Out of memory!");
    strcpy(PathnameNodePtr->nn_Data, name);
    PathnameNodePtr->nn_Node.ln_Name = PathnameNodePtr->nn_Data;
    PathnameNodePtr->nn_Node.ln_Type = NT_USER;
    PathnameNodePtr->nn_Node.ln_Pri  = 0;
    AddTail((struct List *) ListPtr, (struct Node *) PathnameNodePtr);
}

AGLOBAL void append(STRPTR pathname)
{   BPTR FileHandle;

    if (!(FileHandle = (BPTR) Open(pathname, MODE_READWRITE)))
        rq("Can't open file for appending!");
    Seek(FileHandle, 0, OFFSET_END);
    if (Write(FileHandle, IOBuffer, strlen(IOBuffer)) == -1)
    {   Close(FileHandle);
        rq("Can't append to file!");
    }
    if (!Close(FileHandle))
        rq("Can't close appended file!");
}

AGLOBAL ABOOL aboutloop(void)
{   struct IntuiMessage* MsgPtr;
    ABOOL                done = FALSE;
    UWORD                code, qual;
    ULONG                class;

    /* Processes any outstanding messages for the About... window.
       Returns TRUE if user wants to exit, FALSE otherwise.
       This should probably be done using ReAction, since it *is* a
       ReAction window, but this seems to work fine... */

    while (MsgPtr = (struct IntuiMessage *) GetMsg(AboutWindowPtr->UserPort))
    {   class = MsgPtr->Class;
        code  = MsgPtr->Code;
        qual  = MsgPtr->Qualifier;
        ReplyMsg((struct Message *) MsgPtr);

        if (class == CLOSEWINDOW)
            done = TRUE;
        elif (class == IDCMP_RAWKEY)
        {   if ((!(qual & IEQUALIFIER_REPEAT)) && code < KEYUP && (code < FIRSTQUALIFIER || code > LASTQUALIFIER))
                done = TRUE;
    }   }
    return(done);
}

AGLOBAL void drawgadgets(WORD gadgets)
{   if (!PrevGadPtr)
        rq("Can't create GadTools gadgets!");
    AddGList(MainWindowPtr, BU99_Right, (UWORD) ~0, gadgets, NULL);
    RefreshGList(BU99_Right, MainWindowPtr, NULL, -1);
    GT_RefreshWindow(MainWindowPtr, NULL);
}

AGLOBAL void parse(STRPTR terminator)
{   ABOOL done = FALSE;
    ULONG dest = 0; // index in destination string

    while (!done)
    {   if (IOBuffer[offset] != CR)
        {   string[dest] = IOBuffer[offset];
        }
        if (!strncmp(&IOBuffer[offset], terminator, strlen(terminator)))
        {   string[dest] = 0;
            done = TRUE;
            offset += strlen(terminator);
        } elif (offset > strlen(IOBuffer)) // we are past the end of the buffer
        {   string[0] = 0;
            done = TRUE;
        } else
        {   offset++;
            if (IOBuffer[offset] != CR)
            {   dest++;
}   }   }   }

AGLOBAL void parsetoend(void)
{   ABOOL done      = FALSE;
    ULONG suboffset = 0;

    while (!done)
    {   string[suboffset] = IOBuffer[offset];
        if (offset > strlen(IOBuffer))
        {   /* EOF */
            string[suboffset] = 0;
            done = TRUE;
        } else
        {   offset++;
            suboffset++;
}   }   }

AGLOBAL ABOOL saveasl(STRPTR message, STRPTR pattern)
{   struct FileRequester* ASLRqPtr;
    TEXT                  tempstring[VLONGFIELD + 1];
    ABOOL                 success;

    strcpy(tempstring, "Report+: ");
    strcat(tempstring, message);

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "~(#?.info)", ASL_Window, MainWindowPtr, TAG_DONE)))
        rq("Can't create ASL request!");
    if
    (   AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, tempstring, ASL_FuncFlags, FILF_PATGAD | FILF_SAVE, TAG_DONE)
     && *(ASLRqPtr->rf_File) != 0
    )
    {   strcpy(asldir, ASLRqPtr->rf_Dir);
        strcpy(aslresult, ASLRqPtr->rf_Dir);
        if (!AddPart(aslresult, ASLRqPtr->rf_File, VLONGFIELD))
        {   FreeAslRequest(ASLRqPtr);
            rq("Can't add filename to pathname!");
        }
        success = TRUE;
    } else
    {   strcpy(aslresult, "");
        success = FALSE;
    }
    // assert(ASLRqPtr);
    FreeAslRequest(ASLRqPtr);
    return(success);
}

AGLOBAL void handlemenus(UWORD code)
{   /* struct MenuItem* ItemPtr; */
       BPTR             LockPtr;

    if (code != MENUNULL) /* while (code != MENUNULL) */
    {   /* ItemPtr = ItemAddress(MenuPtr, code); */
        switch (MENUNUM(code))
        {
        case MN_PROJECT:
            switch (ITEMNUM(code))
            {
            case IN_NEW:
                if (shared.function == 1)
                    newreport(TRUE);
                elif (shared.function == 2)
                    newaminet(TRUE);
                elif (shared.function == 4)
                    newautodoc(TRUE);
                elif (page == 111)
                    newagdb(TRUE);
            break;
            case IN_OPEN:
                if (shared.function == 1)
                    openreport();
                elif (shared.function == 2)
                    openaminet();
                elif (shared.function == 4)
                    openautodoc();
                elif (page == 91)
                {   batt_open();
                } elif (page == 111)
                    openagdb();
            break;
            case IN_SAVE:
                if (shared.function == 1)
                    savereport(FALSE);
                elif (shared.function == 2)
                    saveaminet(FALSE);
                elif (shared.function == 4)
                    saveautodoc(FALSE);
                elif (page == 91)
                {   batt_save(FALSE);
                } elif (page == 111)
                    saveagdb(FALSE);
            break;
            case IN_SAVEAS:
                if (shared.function == 1)
                    savereport(TRUE);
                elif (shared.function == 2)
                    saveaminet(TRUE);
                elif (shared.function == 4)
                    saveautodoc(TRUE);
                elif (page == 91)
                {   batt_save(TRUE);
                } elif (page == 111)
                    saveagdb(TRUE);
            break;
            case IN_QUIT:
                cleanexit(EXIT_SUCCESS);
            break;
            default:
            break;
            }
        break;
        case MN_HELP:
            switch (ITEMNUM(code))
            {
            case IN_ABOUT:
                helpabout();
            break;
            case IN_MANUAL:
                LockPtr = Lock("CON:", ACCESS_READ);
                if (SystemTags
                (   "MultiView ReportPlus.guide",
                    SYS_Input,  (ULONG) LockPtr,
                    SYS_Output, NULL,
                    SYS_Asynch, TRUE,
                    TAG_DONE
                ) == -1)
                {   DisplayBeep(ScreenPtr);
                }
                UnLock(LockPtr);
            break;
            default:
            break;
            }
        break;
        default:
        break;
        }
        /* Doing things the above way disables multi-selection,
        but prevents `endless selection'.
        code = ItemPtr->NextSelect; */
}   }

AGLOBAL void lockscreen(void)
{   if (pubscreen[0])
    {   if (!(ScreenPtr = LockPubScreen(pubscreen)))
        {   rq("Can't lock specified public screen!");
    }   }
    else
    {   if (!(ScreenPtr = LockPubScreen(NULL)))
        {   rq("Can't lock default public screen!");
}   }   }
AGLOBAL void unlockscreen(void)
{   if (ScreenPtr)
    {   if (pubscreen[0])
        {   UnlockPubScreen(pubscreen, ScreenPtr);
            ScreenPtr = NULL;
        } else
        {   UnlockPubScreen(NULL, ScreenPtr);
            ScreenPtr = NULL;
}   }   }

AGLOBAL void getfillcolour(void)
{   if (fillwindows)
    {   lockscreen();
        fillcolour = FindColor
        (   ScreenPtr->ViewPort.ColorMap,
            0x99999999, /* red */
            0x99999999, /* green */
            0xFFFFFFFF, /* blue */
           -1
        );
        unlockscreen();
    } else fillcolour = 0;
}

MODULE void eachwildcard(STRPTR subpattern, ABOOL gui)
{   struct AnchorPath* AnchorPathPtr;
    BPTR               OldDir;
    BOOL               result;
    ABOOL              done;

    shared.thisfile[0] = 0;
    // AnchorPathPtr must be longword aligned
    if (!(AnchorPathPtr = AllocMem(sizeof(struct AnchorPath), MEMF_ANY | MEMF_PUBLIC)))
    {   return;
    }

    /* We can't do the processing of the files until we have finished
    all of the Match...() calls, due to lock problems. So we build a
    list of the pathnames. */

    AnchorPathPtr->ap_BreakBits = NULL;
    AnchorPathPtr->ap_Flags     = NULL;
    AnchorPathPtr->ap_Strlen    = 0;
    result = MatchFirst(subpattern, AnchorPathPtr);
    if (result == 0) // 0 means success
    {   OldDir = CurrentDir(AnchorPathPtr->ap_Current->an_Lock);
        if (!NameFromLock(AnchorPathPtr->ap_Current->an_Lock, shared.thisfile, VLONGFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        if (!AddPart(shared.thisfile, AnchorPathPtr->ap_Info.fib_FileName, VLONGFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        CurrentDir(OldDir);
        AddPathnameToTail(&FileList, shared.thisfile);
    } elif (result != ERROR_NO_MORE_ENTRIES)
    {   MatchEnd(AnchorPathPtr);
        return;
    }

    done = FALSE;
    while (!done)
    {   result = MatchNext(AnchorPathPtr);
        if (result == 0)
        {   OldDir = CurrentDir(AnchorPathPtr->ap_Current->an_Lock);
            if (!NameFromLock(AnchorPathPtr->ap_Current->an_Lock, shared.thisfile, VLONGFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            if (!AddPart(shared.thisfile, AnchorPathPtr->ap_Info.fib_FileName, VLONGFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            CurrentDir(OldDir);
            AddPathnameToTail(&FileList, shared.thisfile);
        } elif (result != ERROR_NO_MORE_ENTRIES)
        {   MatchEnd(AnchorPathPtr);
            return;
        } else done = TRUE;
    }
    MatchEnd(AnchorPathPtr);
    FreeMem(AnchorPathPtr, sizeof(struct AnchorPath));
}

AGLOBAL void multiasl(STRPTR pattern)
{   struct FileRequester* ASLRqPtr;
    ULONG                 i;
    TEXT                  quotestring[2];

    quotestring[0] = QUOTE;
    quotestring[1] = 0;

    /* It would also be good to correctly
    handle selection of directories. */

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, pattern, ASL_Window, MainWindowPtr, TAG_DONE)))
        rq("Can't create ASL request!");
    if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ file multiselector", ASL_FuncFlags, FILF_PATGAD | FILF_MULTISELECT, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
    {   if (ASLRqPtr->rf_NumArgs)
        {   /* rf_ArgList is an array of WBArg structures. Each entry in
            this array corresponds to one of the files the user selected
            (in alphabetical order). The user multiselected; step through
            the list of selected files. */
            strcpy(asldir, ASLRqPtr->rf_Dir);
            strcpy(shared.pathname, quotestring);
            strcat(shared.pathname, ASLRqPtr->rf_Dir);
            if (!AddPart(shared.pathname, (ASLRqPtr->rf_ArgList)[0].wa_Name, VLONGFIELD))
            {   FreeAslRequest(ASLRqPtr);
                rq("Can't add filename to pathname!");
            }
            strcat(shared.pathname, quotestring);
            strcat(shared.pathname, " ");
            for (i = 1; i < ASLRqPtr->rf_NumArgs; i++)
            {   strcat(shared.pathname, quotestring);
                strcat(shared.pathname, ASLRqPtr->rf_Dir);
                if (!AddPart(shared.pathname, (ASLRqPtr->rf_ArgList)[i].wa_Name, VLONGFIELD))
                   rq("Can't add filename to pathname!");
                strcat(shared.pathname, quotestring);
                if (i < ASLRqPtr->rf_NumArgs - 1)
                    strcat(shared.pathname, " ");
        }   }
        else
        {   /* The user didn't multiselect; use the normal way to get the
            filename. */

            strcpy(asldir, ASLRqPtr->rf_Dir);
            strcpy(shared.pathname, quotestring);
            strcat(shared.pathname, ASLRqPtr->rf_Dir);
            if (!AddPart(shared.pathname, ASLRqPtr->rf_File, VLONGFIELD))
            {   FreeAslRequest(ASLRqPtr);
                rq("Can't add filename to pathname!");
            }
            strcat(shared.pathname, quotestring);
    }   }
    else
    {   ; // the user chose Cancel
    }
    // assert(ASLRqPtr);
    FreeAslRequest(ASLRqPtr);
}

AGLOBAL void checkabort(ABOOL gui)
{   ULONG signals, gid, result;
    UWORD code;

    /* OK, we've just finished operating on that file. Now before we */
    /* start on the next one, check whether the user still wants to... */
    signals = SetSignal(0L, 0L);
    if (signals & SIGBREAKF_CTRL_C)
    {   stop = TRUE;
        SetSignal(0L, SIGBREAKF_CTRL_C); /* clear the Ctrl-C signal */
        if (gui)
        {   if (shared.function == 7)
            {   SetGadgetAttrs
                (   eol_gadgets[GID_7_ST2], MainWindowPtr, NULL,
                    STRINGA_TextVal, "Aborted by user!",
                TAG_DONE);
            } else
            {   // assert(shared.function == 12);
                SetGadgetAttrs
                (   icon_gadgets[GID_12_ST2], MainWindowPtr, NULL,
                    STRINGA_TextVal, "Aborted by user!",
                TAG_DONE);
        }   }
        else
        {   Printf("Aborted by user!\n");
            Flush(Output());
    }   }

    while ((result = DoMethod(WinObject[shared.function], WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
    {   switch (result & WMHI_CLASSMASK)
        {
        case WMHI_MENUPICK:
            ; /* handlemenus(code); */
        break;
        case WMHI_CLOSEWINDOW:
            done = quit = TRUE;
        break;
        case WMHI_GADGETUP:
            gid = result & WMHI_GADGETMASK;
            if
            (   (shared.function ==  7 && gid == GID_7_BU4)
             || (shared.function == 12 && gid == GID_12_BU4)
            )
            {   stop = TRUE;
            }
        break;
        default:
        break;
}   }   }

AGLOBAL void convert(ABOOL gui)
{   ULONG        i, j, length;
    ABOOL        letters, /* are we in letters (TRUE) or whitespace (FALSE)? */
                 quoted;  /* are we quoted (TRUE) or unquoted (FALSE)? */
    struct Node* NodePtr;

    /* At this point we have a list of pathnames, separated by spaces and
    NULL-terminated. If they came from ASL, they will be quoted, otherwise,
    they may not. This is the raw input; it can contain anything,
    including wildcards.

    shared.pathname: the actual contents of the string gadget.
    shared.thatfile: each file that we pass to eachwildcard().
    shared.thisfile: each file that we pass for conversion. */

    stop = letters = quoted = FALSE;
    length = strlen(shared.pathname);
    j = 0;

    for (i = 0; i < length; i++)
    {   if (!stop)
        {   if (shared.pathname[i] == ' ' && letters && !quoted)
            {   /* if we're unquoted and have a space */
                shared.thatfile[j] = 0; /* then NULL-terminate the pathname */
                eachwildcard(shared.thatfile, gui);
                j = 0;
                letters = FALSE;
            } elif (shared.pathname[i] == QUOTE)
            {   if (!letters && !quoted)
                {   letters = TRUE; /* we're in letters */
                    quoted = TRUE; /* it's a quote */
                } elif (letters && quoted)
                {   quoted = FALSE; /* it's an unquote */
            }   }
            else
            {   shared.thatfile[j++] = shared.pathname[i];
                letters = TRUE; /* we're in letters */
    }   }   }
    /* Now we are at the end. */
    if (!stop && letters) /* if we're in letters */
    {   shared.thatfile[j] = 0;
        /* then it is ended, quoted or not. Although we could */
        /* report an error condition if there are an odd */
        /* number of quotes (ie. a missing quote). */
        eachwildcard(shared.thatfile, gui);
    }
    // Walk the list
    for
    (   NodePtr = FileList.lh_Head;
        NodePtr->ln_Succ;
        NodePtr = NodePtr->ln_Succ
    )
    {   if (!stop)
        {   strcpy(shared.thisfile, NodePtr->ln_Name);
            if (shared.function == 7)
            {   eolconvert(gui);
            } else
            {   /* assert(shared.function == 12); */
                iconconvert(gui);
    }   }   }
    clearpathlist(&FileList);
}

MODULE void menu_loop(ULONG gid)
{   switch (gid)
    {
    case GID_0_BU1:
        page = 11;  // bug report
    break;
    case GID_0_BU2:
        page = 21;  // Aminet readme
    break;
    case GID_0_BU3:
        page = 41;  // autodoc
    break;
    case GID_0_BU4:
        page = 91;  // battery RAM
    break;
    case GID_0_BU5:
        page = 111; // AGDB review
    break;
    case GID_0_BU6:
        page = 51;  // ID database
    break;
    case GID_0_BU7:
        page = 61;  // IFF FORMs
    break;
    case GID_0_BU8:
        page = 71;  // EOL/tabs
    break;
    case GID_0_BU9:
        page = 121; // icons
    break;
    case GID_0_BU10:
        page = 81;  // path size
    break;
    case GID_0_BU11:
        page = 101; // system files
    break;
    case GID_0_BU12:
        page = 31;  // ACSE
    break;
    default:
        ; // assert(0);
    break;
}   }

AGLOBAL ULONG Hook0Func(struct Hook *h, VOID *o, VOID *msg)
{   /* "When the hook is called, the data argument points to the 
    window object and message argument to the IntuiMessage."

    These IntuiMessages do not need to be replied to by the appliprog. */

    AUTO    UWORD code, qual;
    AUTO    ULONG class, i;
    AUTO    SWORD mousex, mousey;
    AUTO    SLONG newover;
    PERSIST ULONG over = FUNCTIONS;

    geta4(); // wait till here before doing anything

    class  = ((struct IntuiMessage *) msg)->Class;
    code   = ((struct IntuiMessage *) msg)->Code;
    qual   = ((struct IntuiMessage *) msg)->Qualifier;
    mousex = ((struct IntuiMessage *) msg)->MouseX;
    mousey = ((struct IntuiMessage *) msg)->MouseY;

    switch(class)
    {
    case IDCMP_RAWKEY:
        switch(code)
        {
        case SCAN_HELP:
            helpabout();
        break;
        case SCAN_ESCAPE:
            cleanexit(EXIT_SUCCESS);
        break;
        case SCAN_GRAVE:
            if (qual & IEQUALIFIER_CONTROL)
            {   decrypt();
            }
        break;
        default:
        break;
        }
    break;
    case IDCMP_INTUITICKS:
    {   newover = FUNCTIONS;
        for (i = 0; i < FUNCTIONS; i++)
        {   if
            (   mousex >= gadgets[GID_0_BU1 + i]->LeftEdge
             && mousex <= gadgets[GID_0_BU1 + i]->LeftEdge + gadgets[GID_0_BU1 + i]->Width  - 1
             && mousey >= gadgets[GID_0_BU1 + i]->TopEdge
             && mousey <= gadgets[GID_0_BU1 + i]->TopEdge  + gadgets[GID_0_BU1 + i]->Height - 1
            )
            {   newover = i;
                break;
        }   }
        if (newover != over)
        {   over = newover;
            SetGadgetAttrs
            (   gadgets[GID_0_ST1], MainWindowPtr, NULL,
                STRINGA_TextVal, FunctionDesc[over],
                TAG_DONE
            );
    }   }
    break;
    default:
    break;
    }

    return(1);
}

/* This function converts register-parameter Hook calling convention into
standard C conventions. It requires a C compiler that supports
registerized parameters, such as SAS/C 5.x or greater. */

AGLOBAL ULONG ASM hookEntry(REG(a0) struct Hook *h, REG(a2) VOID *o, REG(a1) VOID *msg)
{   // This is the stub function that converts the register-parameters
    // to stack parameters.

    return ((*(ULONG (*)(struct Hook *, VOID *, VOID *))(*h->h_SubEntry))(h, o, msg));
}

AGLOBAL void InitHook(struct Hook* hook, ULONG (*func)(), void* data)
{   // Make sure a pointer was passed

    if (hook)
    {   // Fill in the Hook fields
        hook->h_Entry    = (ULONG (*)()) hookEntry;
        hook->h_SubEntry = func;
        hook->h_Data     = data;
    } else
    {   Printf("Report+: Can't initialize hook (NULL pointer)!");
        cleanexit(EXIT_FAILURE);
}   }

AGLOBAL void clearlist(struct List* ListPtr)
{   if (ListPtr->lh_Head->ln_Succ) // if list is non-empty
    {   FreeNameNodes(ListPtr);
    }
    NewList(ListPtr); // prepare for reuse
}
MODULE void clearpathlist(struct List* ListPtr)
{   if (ListPtr->lh_Head->ln_Succ) // if list is non-empty
    {   FreePathnameNodes(ListPtr);
    }
    NewList(ListPtr); // prepare for reuse
}

// Function to free an Exec List of ReAction ListBrowser nodes.
AGLOBAL void clearreactionlist(struct List* ListPtr)
{   /* Requirements: listbrowser class must be already open, and list
    must be detached from gadget*/

    if (ListPtr->lh_Head->ln_Succ) // if list is non-empty
    {   FreeListBrowserList(ListPtr);
    }
    NewList(ListPtr); // prepare for reuse
}

AGLOBAL void openwindow(void)
{   // Opens a ReAction window.

    if (!(MainWindowPtr = (struct Window *) DoMethod(WinObject[shared.function], WM_OPEN, NULL)))
    {   rq("Can't open ReAction window!");        
    }

    // Obtain the window wait signal mask.
    GetAttr(WINDOW_SigMask, WinObject[shared.function], &signal);
}

AGLOBAL ABOOL ra_checkbreak(void)
{   ULONG result;
    UWORD code;

    while ((result = DoMethod(WinObject[shared.function], WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
    {   switch (result & WMHI_CLASSMASK)
        {
        case IDCMP_RAWKEY:
            if (code == SCAN_ESCAPE)
                return(1);
        break;
        case WMHI_CLOSEWINDOW:
             return(2);
        break;
        case WMHI_GADGETUP:
             if (shared.function == 8)
             {   if ((result & (WMHI_GADGETMASK)) == GID_8_BU5) // these parentheses are needed!
                 {   return(1);
             }   }
             else
             {   // assert(shared.function == 10);
                 if ((result & (WMHI_GADGETMASK)) == GID_10_BU3) // these parentheses are needed!
                 {   return(1);
             }   }
        break;
        default:
        break;
    }   }
    return(0);
}

AGLOBAL void sender(void)
{   verynewwindow
    (   SENDERWIDTH, SENDERHEIGHT,
        "Report+: Sender Details",
        BUTTONIDCMP | STRINGIDCMP
    );

    if (readin("S:Report.sender"))
    {   /* # Refer: <last>,<first> (<company> ,phone <phone>)<LF>
           # Path: <email><LF>
           # ReferID: <developer><LF> */

        offset = 0;
        parse("# Refer: ");
        parse(",");
        strcpy(report.lastname,  string);
        parse(" (");
        strcpy(report.firstname, string);
        parse(" ,phone ");
        strcpy(report.company,   string);
        parse(")\n# Path: ");
        strcpy(report.phone,     string);
        parse("\n# ReferID: ");
        strcpy(report.email,     string);
        parse("\n");
        strcpy(report.developer, string);
    }

    /* first name */
    setgadget(166, 22, 256, 12, "_First name:", NULL);
    ST1_FirstName = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.firstname),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* last name */
    setgadget(166, 34, 256, 12, "_Last name:", NULL);
    ST1_LastName = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.lastname),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* company name */
    setgadget(166, 46, 256, 12, "_Company:", NULL);
    ST1_Company = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.company),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* phone */
    setgadget(166, 58, 256, 12, "_Phone number:", NULL);
    ST1_Phone = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.phone),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* developer number */
    setgadget(166, 70, 256, 12, "_Developer number:", NULL);
    ST1_Developer = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
	PrevGadPtr,
	&Gadget,
        GTST_String, &(report.developer),
        GTST_MaxChars, LONGFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    /* email */
    setgadget(166, 82, 256, 12, "_EMail:", NULL);
    ST1_EMail = PrevGadPtr = (struct Gadget *) CreateGadget
    (	STRING_KIND,
	PrevGadPtr,
	&Gadget,
	GTST_String, &(report.email),
	GTST_MaxChars, MEDFIELD,
	GA_TabCycle, TRUE,
        GT_Underscore, '_',
	TAG_DONE
    );

    drawgadgets((UWORD) ~0);
    ActivateGadget(ST1_FirstName, MainWindowPtr, NULL);
    loop();

        /* write out S:Report.sender
        # Refer: <last>,<first> (<company> ,phone <phone>)<LF>
        # Path: <email><LF>
        # ReferID: <developer><LF> */

        strcpy(report.refer, "# Refer: ");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST1_LastName->SpecialInfo)->Buffer
        );
        strcat(report.refer, ",");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST1_FirstName->SpecialInfo)->Buffer
        );
        strcat(report.refer, " (");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST1_Company->SpecialInfo)->Buffer
        );
        strcat(report.refer, " ,phone ");
        strcat
        (   report.refer,
            ((struct StringInfo *) ST1_Phone->SpecialInfo)->Buffer
        );
        strcat(report.refer, ")\n");

        strcpy(report.path, "# Path: ");
        strcat
        (	report.path,
            ((struct StringInfo *) ST1_EMail->SpecialInfo)->Buffer
        );
        strcat(report.path, "\n");

        strcpy(report.referid, "# ReferID: ");
        strcat
        (   report.referid,
            ((struct StringInfo *) ST1_Developer->SpecialInfo)->Buffer
        );
        strcat(report.referid, "\n");

        strcpy(IOBuffer, report.refer);
        strcat(IOBuffer, report.path);
        strcat(IOBuffer, report.referid);
    
        writeout("S:Report.sender");
        closewindow();
}

MODULE void sender_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual)
    {   if (class == IDCMP_VANILLAKEY)
        {   code = toupper(code);
            if (code == ESCAPE)
            {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
                {   cleanexit(EXIT_SUCCESS);
                } elif (shared.function == 1)
                {   page = 11;
                } else
                {   // assert(shared.function == 3);
                    page = 32;
            }   }
            elif (code == 'F')
            {   ActivateGadget(ST1_FirstName, MainWindowPtr, NULL);
            } elif (code == 'L')
            {   ActivateGadget(ST1_LastName,  MainWindowPtr, NULL);
            } elif (code == 'C')
            {   ActivateGadget(ST1_Company,   MainWindowPtr, NULL);
            } elif (code == 'D')
            {   ActivateGadget(ST1_Developer, MainWindowPtr, NULL);
            } elif (code == 'P')
            {   ActivateGadget(ST1_Phone,     MainWindowPtr, NULL);
            } elif (code == 'E')
            {   ActivateGadget(ST1_EMail,     MainWindowPtr, NULL);
    }   }   }

AGLOBAL void getversion(STRPTR filename, STRPTR output)
{   ULONG i;
    TEXT  commandstring[VLONGFIELD + 1];

    if (ram)
    {   strcpy(commandstring, "RAM:Version ");
    } else
    {   strcpy(commandstring, "Version ");
    }
    strcat(commandstring, filename);
    strcat(commandstring, " >T:ReportPlus.temp");
    if (!SystemTags(commandstring, SYS_Output, Open("NIL:", MODE_NEWFILE), TAG_DONE))
    {   readordie("T:ReportPlus.temp");
        for (i = 0; i <= VLONGFIELD; i++)
        {   if (IOBuffer[i] == LF)
            {   IOBuffer[i] = 0;
                break;
        }   }
        strcpy(output, IOBuffer);
    } else
    {   strcpy(output, "?");
}   }

AGLOBAL void setbar(ULONG max)
{   // Ensure we do no more than BARUPDATES updates of the progress bar.

    increment = max / BARUPDATES;
    if (increment == 0)
    {   increment = 1;
}   }

