/* $Filename:    ReportPlus/Source/rp.c
 * $VER:         Report+ 5.63
 * $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 <libraries/iffparse.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 <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_0_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_ST1  11
#define GIDS_0     GID_0_ST1

#define GID_A_LY1  0
#define GIDS_A     GID_A_LY1

#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/amigan.ilbm"
};
MODULE STRPTR FunctionDesc[FUNCTIONS + 2] =
{   // Edit
    "Bug report",         // 1
    "Aminet readme",      // 2
    "Battery-backed RAM", // 9
    // View
    "Manufacturer IDs",   // 5
    "IFF FORMs",          // 6
    // Process
    "Icons",              // 4
    "EOLs/tabs",          // 7
    // Report
    "Path size",          // 8
    "System files",       // 10
    // Conduct
    "ACSE test",          // 3
    // (default)
    TITLEBARTEXT
};

#define MENUENTRIES 11
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, "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 sender_loop(ULONG gid);
MODULE void about_loop(void);

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,
                                *SpaceBase       = NULL;
AGLOBAL TEXT                    asldir[PATHNAMEFIELD + 1],
                                aslresult[PATHNAMEFIELD + 1],
                                IOBuffer[LONGESTFIELD + 1],
                                string[LONGESTFIELD + 1],
                                weekdaystring[LEN_DATSTRING],
                                datestring[LEN_DATSTRING],
                                timestring[LEN_DATSTRING],
                                cpuline[VLONGFIELD + 1];
AGLOBAL WORD                    xsize;
AGLOBAL SBYTE                   page             = 0,
                                closer           = 0;
AGLOBAL ULONG                   increment,
                                offset,
                                wbval,
                                aboutsignal,
                                signal;
AGLOBAL ABOOL                   BattBuffer[96],
                                done             = 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 TextFont*        FontPtr          = NULL;
AGLOBAL struct VisualInfo*      VisualInfoPtr    = NULL;
AGLOBAL struct ExAllData*       EADataPtr        = 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 IconStruct    icon;
IMPORT struct Gadget*       icon_gadgets[GIDS_4 + 1];
IMPORT ABOOL                quit;
// from f6.c
IMPORT struct IFFStruct     iff;
// from f7.c
IMPORT struct Gadget*       eol_gadgets[GIDS_7 + 1];
// from f8.c
IMPORT struct SizeStruct    size;
// from f9.c
IMPORT struct Library*      BattMemBase;
// from f10.c
IMPORT struct FilesStruct   files;

AGLOBAL       Object*          WinObject[FUNCTIONS + 1]; // note that WindowObject is a reserved macro
AGLOBAL struct TextAttr        Topaz8 =
{	(STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
}; // "topaz.font" is case-sensitive

MODULE BPTR                    NilHandle         = NULL;
MODULE TEXT                    pubscreen[256 + 1];
MODULE ABOOL                   logo              = TRUE;
MODULE        Object*          AboutWinObject    = NULL;
MODULE struct Gadget          *gadgets[GIDS_0 + 1],
                              *sender_gadgets[GIDS_S + 1];
MODULE struct RDArgs*          ArgsPtr           = NULL;
MODULE struct WBArg*           WBArg             = NULL;
MODULE struct WBStartup*       WBMsg             = NULL;
MODULE struct ASLBase*         ASLBase           = NULL;
MODULE struct GadToolsBase*    GadToolsBase      = NULL;
MODULE struct IFFParseBase*    IFFParseBase      = NULL;
MODULE struct IntuitionBase*   IntuitionBase     = NULL;
MODULE struct Library*         VersionBase       = NULL;
MODULE struct EasyStruct       EasyStruct =
{   sizeof(struct EasyStruct),
    0,
    "Report+: Error",
    NULL,
    "Quit"
};

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

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

    /* Start of program.

    version embedding into executable */

    if (0) /* that is, never */
        Printf("$VER: Report+ 5.63 (21.10.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 (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 ASLBase *) 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 (!(IFFParseBase = (struct IFFParseBase *) OpenLibrary("iffparse.library", 0L)))
        rq("Can't open IFFParse.library!");
    // it would be better to disable only the IFF viewer rather than abort
    // the entire program.
    if (!(FontPtr = OpenFont(&Topaz8)))
    {   rq("Can't open Topaz 8 font!");
    }

    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 (!(SpaceBase       = OpenLibrary("gadgets/space.gadget", 44)))
                       rq("OpenLibrary(\"gadgets/space.gadget\") (V44) 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:. */

    NilHandle = Open("NIL:", MODE_NEWFILE);
    if (NilHandle)
    {   if (!SystemTags("C:Copy C:Version RAM: >NIL:", SYS_Output, NilHandle, TAG_DONE))
        {   ram = TRUE;
        }
        if (!SystemTags("C:CPU >T:ReportPlus.temp", SYS_Output, NilHandle, TAG_DONE))
        {   readordie("T:ReportPlus.temp");
            DeleteFile("T:ReportPlus.temp"); /* returns FALSE for failure */

            for (i = 0; i <= VLONGFIELD; i++)
            {   if (IOBuffer[i] == LF)
                {   IOBuffer[i] = 0;
                    break;
            }   }
            strcpy(cpuline, IOBuffer);
        } else
        {   strcpy(cpuline, "?");
        }
        Close(NilHandle);
        NilHandle = NULL;
    } else
    {   strcpy(cpuline, "?");
    }

    report_init();     // f1  list init, var init
    aminet_init();     // f2  list init: memory loss?
    iff_init();        // f6  var init
    size_init();       // f8  list init
    files_init();      // f10  pen init, list init
    /* those must be done before we handle CLI arguments */

    if (argc) /* started from CLI */
    {   if (!(ArgsPtr = ReadArgs
        (   "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 [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])
        {   strcpy(pubscreen, (STRPTR) args[0]);
        }
        if (args[1])
        {   logo = FALSE;
        }
        if (args[2])
        {   number = (SLONG) (*((SLONG *) args[2]));
            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[3])
        {   if (number != 4)
            {   Printf("%s: <function> must be 4 for this!\n", argv[0]);
                cleanexit(EXIT_FAILURE);
            }
            if (!stricmp((STRPTR) args[3], "DISK"))
            {   icon.type = WBDISK;
            } elif (!stricmp((STRPTR) args[3], "DRAWER"))
            {   icon.type = WBDRAWER;
            } elif (!stricmp((STRPTR) args[3], "TOOL"))
            {   icon.type = WBTOOL;
            } elif (!stricmp((STRPTR) args[3], "PROJECT"))
            {   icon.type = WBPROJECT;
            } elif (!stricmp((STRPTR) args[3], "TRASHCAN"))
            {   icon.type = WBGARBAGE;
            } elif (!stricmp((STRPTR) args[3], "DEVICE"))
            {   icon.type = WBDEVICE;
            } elif (!stricmp((STRPTR) args[3], "KICKSTART"))
            {   icon.type = WBKICK;
            } elif (!stricmp((STRPTR) args[3], "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[4] || args[5] || args[6] || args[7] || args[8] || args[9] || args[10])
        {   if (number != 9)
            {   Printf("%s: <function> must be 9 for this!\n", argv[0]);
                cleanexit(EXIT_FAILURE);
            }
            if (!args[4])
            {   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[5])
            {   BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR]       = TRUE;
            } else BattBuffer[BATTMEM_SCSI_TIMEOUT_ADDR]    = FALSE;
            if (args[6])
            {   BattBuffer[BATTMEM_SCSI_LUNS_ADDR]          = TRUE;
            } else BattBuffer[BATTMEM_SCSI_LUNS_ADDR]       = FALSE;
            if (args[7])
            {   BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR]     = TRUE;
            } else BattBuffer[BATTMEM_SCSI_SYNC_XFER_ADDR]  = FALSE;
            if (args[8])
            {   BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR]     = TRUE;
            } else BattBuffer[BATTMEM_SCSI_FAST_SYNC_ADDR]  = FALSE;
            if (args[9])
            {   BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR]    = TRUE;
            } else BattBuffer[BATTMEM_SCSI_TAG_QUEUES_ADDR] = FALSE;
            if (args[10]) // these bits are inverted
            {   hostid = (SLONG) (*((SLONG *) args[10]));
                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[11])
        {   switch(number)
            {
            case 1:
                strcpy(report.output, (STRPTR) args[11]);
                loadreport();
            break;
            case 2:
                strcpy(aminet.output, (STRPTR) args[11]);
                loadaminet();
            break;
            case 4:
                strcpy(shared.pathname, (STRPTR) args[11]);
                if (convert(FALSE))
                {   Printf("All done.\n");
                } else
                {   Printf("No matches!\n");
                }
                cleanexit(EXIT_SUCCESS);
            break;
            case 6:
                strcpy(iff.pathname, (STRPTR) args[11]);
            break;
            case 7:
                strcpy(shared.pathname, (STRPTR) args[11]);
                if (convert(FALSE))
                {   Printf("All done.\n");
                } else
                {   Printf("No matches!\n");
                }
                cleanexit(EXIT_SUCCESS);
            break;
            case 8:
                strcpy(size.path, (STRPTR) args[11]);
            break;
            case 10:
                strcpy(files.basepath, (STRPTR) args[11]);
            break;
            default:
                Printf("Report+: <function> must be 1-2, 4, 6-8, or 10 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;
    if (!(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!");
    }

    if (ConfigHandle = (BPTR) Open("PROGDIR:ReportPlus.config", MODE_OLDFILE))
    {   if (Read(ConfigHandle, IOBuffer, 25) != -1)
        {   manuf_config(); //                                         20
            icon_config();  //                                 161718
            iff_config();   //                                       19
            eol_config();   //   0102030405
            size_config();  // 00          06                15          2122  24
            files_config(); //               0708091011121314                23
        }
        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)
            icon1();
        elif (page == 51)
            manuf1();
        elif (page == 61)
            iff1();
        elif (page == 71)
            eol1();
        elif (page == 81)
            size1();
        elif (page == 91)
            batt1();
        elif (page == 101)
            files1();
        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;

    /* Each of these calls to NewObject() loses 32 bytes, for a loss of
       388 bytes. */

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

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

    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_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_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_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",
                    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[9 - 1],
                        BITMAP_Width,        35,
                        BITMAP_Height,       32,
                        TAG_DONE
                    ),
                    BUTTON_BackgroundPen,    bgpen,
                    BUTTON_FillPen,          bgpen,
                TAG_END),
            TAG_END),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         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_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU4] =
                        NewObject
                        (   NULL,                  "button.gadget",
                            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[5 - 1],
                                BITMAP_Width,        35,
                                BITMAP_Height,       32,
                                TAG_DONE
                            ),
                            BUTTON_BackgroundPen,    bgpen,
                            BUTTON_FillPen,          bgpen,
                            TAG_DONE
                        ),
                        LAYOUT_AddChild,           gadgets[GID_0_BU5] =
                        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[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_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         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_END),
                    CHILD_WeightedHeight,      0,
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_HorizAlignment,     LALIGN_CENTER,
                        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_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_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[7 - 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_DeferLayout,        TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),       NULL,
                         // layout tags
                         LAYOUT_Orientation,      LAYOUT_ORIENT_HORIZ,
                         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_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[8 - 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[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_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         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_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[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;

    /* The Amiga loses 24 bytes each time ReportPlus is run...

    ASL requesters are assumed to be already closed. */

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

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

    if (MenuPtr)
    {   FreeMenus(MenuPtr);
        MenuPtr = NULL;
    }
    if (VisualInfoPtr)
    {   FreeVisualInfo(VisualInfoPtr);
        VisualInfoPtr = NULL;
    }

    /* You can't fool around with attached lists, so we close the window
    before calling these next routines. */

    report_die();  // f1  clear list
    aminet_exit(); // f2  clear subdir list
    aminet_die();  // f2  clear maindir list
    acse_exit();   // f3  close timer
    icon_die();    // f4  config data
    manuf_die();   // f5  config data
    iff_exit();    // f6  free memory, clear lists, close iffhandles
    iff_die();     // f6  config data
    eol_die();     // f7  config data
    size_exit();   // f8  close filehandles/locks, clear full lists
    size_die();    // f8  clear empty lists
    files_exit();  // f10 clear full list, close filehandle
    files_die();   // f10 clear empty list, config data

    if (NilHandle)
    {   Close(NilHandle);
        NilHandle = NULL;
    }
    if (ram && (NilHandle = Open("NIL:", MODE_NEWFILE)))
    {   if (!SystemTags("Delete RAM:Version", SYS_Output, NilHandle, TAG_DONE))
        {   ram = FALSE;
        }
        Close(NilHandle);
        NilHandle = NULL;
    }

    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, 25);
            Close(ConfigHandle);
            // ConfigHandle = NULL;
    }   }

    /* ReAction */
    if (WindowBase)
    {   CloseLibrary(WindowBase);
    }
    if (TextEditorBase)
    {   CloseLibrary(TextEditorBase);
    }
    if (StringBase)
    {   CloseLibrary(StringBase);
    }
    if (SpaceBase)
    {   CloseLibrary(SpaceBase);
    }
    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 (IFFParseBase)
        CloseLibrary((struct Library *) IFFParseBase);
    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;
    }
    NewList(ListPtr);
}
AGLOBAL void FreePathnameNodes(struct List* ListPtr)
{   struct PathnameNode *WorkNodePtr, *NextNodePtr;
	
    WorkNodePtr = (struct PathnameNode *) (ListPtr->lh_Head); /* first node */
    while (NextNodePtr = (struct PathnameNode *) (WorkNodePtr->Node.ln_Succ))
    {   FreeMem(WorkNodePtr, sizeof(struct PathnameNode));
        WorkNodePtr = NextNodePtr;
    }
    NewList(ListPtr);
}
AGLOBAL void helpabout(void)
{   PERSIST ABOOL       first = TRUE;

    if (AboutWindowPtr)
    {   return;
    }

    lockscreen();
    if (first)
    {   if (!(image[FUNCTIONS] = NewObject
        (   BITMAP_GetClass(), NULL,
            BITMAP_SourceFile, imagename[FUNCTIONS],
            BITMAP_Width,      44,
            BITMAP_Height,     38,
            BITMAP_Screen,     ScreenPtr,
        TAG_DONE)
        ))
        {   rq("Can't create ReAction image!");
        }
        GetAttr(BITMAP_BitMap, image[FUNCTIONS], (ULONG *) &bitmap[FUNCTIONS]);
        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,
        NewObject
        (   LAYOUT_GetClass(),         NULL,
            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[FUNCTIONS],
                    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_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_Orientation,      LAYOUT_ORIENT_HORIZ,
                    LAYOUT_DeferLayout,      TRUE,
                    LAYOUT_AddImage,
                    NewObject
                    (   LABEL_GetClass(),    NULL,
                        LABEL_Justification, LJ_CENTRE,
                        LABEL_Text,          "Monday 21 October 2002",
                    TAG_END),
                TAG_END),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),       NULL,
                    LAYOUT_Orientation,      LAYOUT_ORIENT_HORIZ,
                    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_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_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));

    // Obtain the window wait signal mask.
    GetAttr(WINDOW_SigMask, AboutWinObject, &aboutsignal);
}

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

        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
        OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));

        /* 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;
}   }

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, PATHNAMEFIELD))
        {   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)
{   SWORD oldpage = page;
    UWORD code;
    ULONG result;

    closer = page;
    done = FALSE;
    while (page == oldpage && !done)
    {   if (AboutWindowPtr)
        {   about_loop();
        } else
        {   if ((Wait(signal | SIGBREAKF_CTRL_C)) & SIGBREAKF_CTRL_C)
            {   done = TRUE;
                /* should we clear the Ctrl-C signal? */
        }   }
        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 == 31)
                {   acse_closewindow();
                } elif (page == 0)
                {   cleanexit(EXIT_SUCCESS);
                } elif (page == 1)
                {   if (shared.function == 1)
                    {   page = 11;
                    } else
                    {   assert(shared.function == 3);
                        page = 32;
                }   }
                else page = 0;
            break;
            case WMHI_GADGETUP:
                if (page == 1)
                {   sender_loop(result & WMHI_GADGETMASK);
                } else
                {   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 3:
                        acse_loop(result & WMHI_GADGETMASK);
                    break;
                    case 4:
                        icon_loop(result & WMHI_GADGETMASK);
                    break;
                    case 5:
                        manuf_loop(result & WMHI_GADGETMASK);
                    break;
                    case 6:
                        iff_loop(result & WMHI_GADGETMASK);
                    break;
                    case 7:
                        eol_loop(result & WMHI_GADGETMASK);
                    break;
                    case 8:
                        size_loop(result & WMHI_GADGETMASK);
                    break;
                    case 9:
                        batt_loop(result & WMHI_GADGETMASK);
                    break;
                    case 10:
                        files_loop(result & WMHI_GADGETMASK);
                    break;
                    default:
                        assert(0);
                    break;
                }   }
            break;
            default:
            break;
}   }   }   }

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 LocalFileHandle;

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

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, "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;
        }
        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);
}
AGLOBAL void AddPathnameNode(struct List* ListPtr, STRPTR name)
{   struct PathnameNode* PathnameNodePtr;

    if (!(PathnameNodePtr = AllocMem(sizeof(struct PathnameNode), MEMF_CLEAR)))
        rq("Out of memory!");
    strcpy(PathnameNodePtr->pathname, name);
    PathnameNodePtr->Node.ln_Name = NULL;
    PathnameNodePtr->Node.ln_Type = NT_USER;
    PathnameNodePtr->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!");
}

MODULE void about_loop(void)
{   UWORD code;
    ULONG result;
    ABOOL localdone = FALSE;

    // Processes any messages for the About... window.

    if ((Wait(aboutsignal | SIGBREAKF_CTRL_C)) & SIGBREAKF_CTRL_C)
    {   localdone = TRUE;
        /* should we clear the Ctrl-C signal? */
    }
    while ((result = DoMethod(AboutWinObject, WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
    {   switch (result & WMHI_CLASSMASK)
        {
        case WMHI_MENUPICK:
            ; // handlemenus(code);
        break;
        case WMHI_CLOSEWINDOW:
            localdone = TRUE;
        break;
        default:
        break;
    }   }

    if (localdone)
    {   DisposeObject(AboutWinObject);
        AboutWindowPtr = AboutWinObject = NULL;
        OnMenu(MainWindowPtr, FULLMENUNUM(MN_HELP, IN_ABOUT, NOSUB));
}   }

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, PATHNAMEFIELD))
        {   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; */

    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);
            break;
            case IN_OPEN:
                if (shared.function == 1)
                    openreport();
                elif (shared.function == 2)
                    openaminet();
                elif (shared.function == 9)
                    batt_open();
            break;
            case IN_SAVE:
                if (shared.function == 1)
                    savereport(FALSE);
                elif (shared.function == 2)
                    saveaminet(FALSE);
                elif (shared.function == 9)
                    batt_save(FALSE);
            break;
            case IN_SAVEAS:
                if (shared.function == 1)
                    savereport(TRUE);
                elif (shared.function == 2)
                    saveaminet(TRUE);
                elif (shared.function == 9)
                    batt_save(TRUE);
            break;
            case IN_QUIT:
                cleanexit(EXIT_SUCCESS);
            break;
            default:
            break;
            }
        break;
        case MN_HELP:
            switch (ITEMNUM(code))
            {
            case IN_ABOUT:
                helpabout();
            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;
}   }   }

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, PATHNAMEFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        if (!AddPart(shared.thisfile, AnchorPathPtr->ap_Info.fib_FileName, PATHNAMEFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        CurrentDir(OldDir);
        AddPathnameNode(&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, PATHNAMEFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            if (!AddPart(shared.thisfile, AnchorPathPtr->ap_Info.fib_FileName, PATHNAMEFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            CurrentDir(OldDir);
            AddPathnameNode(&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, PATHNAMEFIELD))
            {   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, PATHNAMEFIELD))
                   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, PATHNAMEFIELD))
            {   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 == 4);
                SetGadgetAttrs
                (   icon_gadgets[GID_4_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 == 4 && gid == GID_4_BU4)
             || (shared.function == 7 && gid == GID_7_BU4)
            )
            {   stop = TRUE;
            }
        break;
        default:
        break;
}   }   }

AGLOBAL ABOOL 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 PathnameNode* 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);
    }

    if ((FileList.lh_Head)->ln_Succ) // if the list is non-empty
    {   // Walk the list
        for
        (   NodePtr = FileList.lh_Head;
            NodePtr->Node.ln_Succ;
            NodePtr = NodePtr->Node.ln_Succ
        )
        {   if (!stop)
            {   strcpy(shared.thisfile, NodePtr->pathname);
                if (shared.function == 7)
                {   eolconvert(gui);
                } else
                {   /* assert(shared.function == 4); */
                    iconconvert(gui);
        }   }   }
        if (FileList.lh_Head->ln_Succ) // if list is non-empty
        {   FreePathnameNodes(&FileList);
        }
        return(TRUE);
    } else
    {   return(FALSE);
}   }

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 = 91;  // battery RAM
    break;
    case GID_0_BU4:
        page = 51;  // ID database
    break;
    case GID_0_BU5:
        page = 61;  // IFF FORMs
    break;
    case GID_0_BU6:
        page = 41;  // icons
    break;
    case GID_0_BU7:
        page = 71;  // EOL/tabs
    break;
    case GID_0_BU8:
        page = 81;  // path size
    break;
    case GID_0_BU9:
        page = 101; // system files
    break;
    case GID_0_BU10:
        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
}

// 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);

    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_NEW,    NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_OPEN,   NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVE,   NOSUB));
    OffMenu(MainWindowPtr, FULLMENUNUM(MN_PROJECT, IN_SAVEAS, NOSUB));
}

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)
{   struct Hook SenderHookStruct;
    STRPTR      stringptr;

    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);
    }

    InitHook(&SenderHookStruct, SenderHookFunc, NULL);

    /* Create the window object. */
    lockscreen();

if (!(WinObject[shared.function] =
NewObject
(
    WINDOW_GetClass(),                    NULL,
    WA_PubScreen,                         ScreenPtr,
    WA_ScreenTitle,                       "Report+",
    WA_Title,                             "Report+: Sender Details",
    WA_Activate,                          TRUE,
    WA_DepthGadget,                       TRUE,
    WA_DragBar,                           TRUE,
    WA_CloseGadget,                       TRUE,
    WA_SizeGadget,                        TRUE,
    WA_IDCMP,                             IDCMP_RAWKEY,
    WINDOW_IDCMPHook,                     &SenderHookStruct,
    WINDOW_IDCMPHookBits,                 IDCMP_RAWKEY,
    WINDOW_MenuStrip,                     MenuPtr,
    WINDOW_Position,                      WPOS_CENTERSCREEN,
    WINDOW_ParentGroup,                   sender_gadgets[GID_S_LY1] =
    NewObject
    (   LAYOUT_GetClass(),                NULL,
        LAYOUT_Orientation,               LAYOUT_ORIENT_HORIZ,
        LAYOUT_SpaceOuter,                TRUE,
        LAYOUT_DeferLayout,               TRUE,
        LAYOUT_AddChild,                  NewObject(LAYOUT_GetClass(), NULL,
            LAYOUT_Orientation,           LAYOUT_ORIENT_VERT,
            LAYOUT_VertAlignment,         LALIGN_CENTER,
            LAYOUT_BevelStyle,            BVS_NONE,
            LAYOUT_AddChild,              NewObject
            (   LAYOUT_GetClass(),        NULL,
                LAYOUT_Orientation,       LAYOUT_ORIENT_HORIZ,
                LAYOUT_HorizAlignment,    LALIGN_RIGHT,
                LAYOUT_BevelStyle,        BVS_NONE,
                LAYOUT_AddImage,          NewObject
                (   LABEL_GetClass(),     NULL,
                    // label
                    LABEL_Text,           "_First name:",
                    LABEL_Justification,  LJ_RIGHT,
                    TAG_END
                ),
                TAG_END
            ),
            CHILD_WeightedHeight,         0,
            LAYOUT_AddChild,              NewObject(LAYOUT_GetClass(), NULL,
                // layout
                LAYOUT_Orientation,       LAYOUT_ORIENT_HORIZ,
                LAYOUT_HorizAlignment,    LALIGN_RIGHT,
                LAYOUT_BevelStyle,        BVS_NONE,
                LAYOUT_AddImage,          NewObject
                (   LABEL_GetClass(),     NULL,
                    // label
                    LABEL_Text,           "_Last name:",
                    LABEL_Justification,  LJ_RIGHT,
                    TAG_END
                ),
            TAG_END),
            CHILD_WeightedHeight,         0,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),        NULL,
                LAYOUT_Orientation,       LAYOUT_ORIENT_HORIZ,
                LAYOUT_HorizAlignment,    LALIGN_RIGHT,
                LAYOUT_BevelStyle,        BVS_NONE,
                LAYOUT_AddImage,          NewObject
                (   LABEL_GetClass(),     NULL,
                    // label
                    LABEL_Text,           "_Company:",
                    LABEL_Justification,  LJ_RIGHT,
                    TAG_END
                ),
                TAG_END
            ),
            CHILD_WeightedHeight,         0,
            LAYOUT_AddChild,              NewObject(LAYOUT_GetClass(), NULL,
                // layout
                LAYOUT_Orientation,       LAYOUT_ORIENT_HORIZ,
                LAYOUT_HorizAlignment,    LALIGN_RIGHT,
                LAYOUT_BevelStyle,        BVS_NONE,
                LAYOUT_AddImage,          NewObject
                (   LABEL_GetClass(),     NULL,
                    // label
                    LABEL_Text,           "_Phone number:",
                    LABEL_Justification,  LJ_RIGHT,
                    TAG_END
                ),
                TAG_END
            ),
            CHILD_WeightedHeight,         0,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),        NULL,
                LAYOUT_Orientation,       LAYOUT_ORIENT_HORIZ,
                LAYOUT_HorizAlignment,    LALIGN_RIGHT,
                LAYOUT_BevelStyle,        BVS_NONE,
                LAYOUT_AddImage,          NewObject
                (   LABEL_GetClass(),     NULL,
                    // label
                    LABEL_Text,           "_Developer number:",
                    LABEL_Justification,  LJ_RIGHT,
                    TAG_END
                ),
                TAG_END
            ),
            CHILD_WeightedHeight,         0,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),        NULL,
                LAYOUT_Orientation,       LAYOUT_ORIENT_HORIZ,
                LAYOUT_HorizAlignment,    LALIGN_RIGHT,
                LAYOUT_BevelStyle,        BVS_NONE,
                LAYOUT_AddImage,          NewObject
                (   LABEL_GetClass(),     NULL,
                    // label
                    LABEL_Text,           "_Email:",
                    LABEL_Justification,  LJ_RIGHT,
                TAG_END),
            TAG_END),
            CHILD_WeightedHeight,         0,
        TAG_END),
        CHILD_WeightedWidth,              0,
        LAYOUT_AddChild,
        NewObject
        (   LAYOUT_GetClass(),        NULL,
            LAYOUT_Orientation,       LAYOUT_ORIENT_VERT,
            LAYOUT_VertAlignment,     LALIGN_CENTER,
            LAYOUT_HorizAlignment,    LALIGN_CENTER,
            LAYOUT_BevelStyle,        BVS_NONE,
            LAYOUT_AddChild,          sender_gadgets[GID_S_ST1] =
            NewObject
            (   STRING_GetClass(),    NULL,
                GA_ID,                GID_S_ST1,
                STRINGA_TextVal,      report.firstname,
                STRINGA_MinVisible,   20,
                STRINGA_MaxChars,     MEDFIELD,
                GA_TabCycle,          TRUE,
            TAG_END),
            LAYOUT_AddChild,          sender_gadgets[GID_S_ST2] =
            NewObject
            (   STRING_GetClass(),    NULL,
                GA_ID,                GID_S_ST2,
                STRINGA_TextVal,      report.lastname,
                STRINGA_MinVisible,   20,
                STRINGA_MaxChars,     MEDFIELD,
                GA_TabCycle,          TRUE,
            TAG_END),
            LAYOUT_AddChild,          sender_gadgets[GID_S_ST3] =
            NewObject
            (   STRING_GetClass(),    NULL,
                GA_ID,                GID_S_ST3,
                STRINGA_TextVal,      report.company,
                STRINGA_MinVisible,   20,
                STRINGA_MaxChars,     MEDFIELD,
                GA_TabCycle,          TRUE,
            TAG_END),
            LAYOUT_AddChild,          sender_gadgets[GID_S_ST4] =
            NewObject
            (   STRING_GetClass(),    NULL,
                GA_ID,                GID_S_ST4,
                STRINGA_TextVal,      report.phone,
                STRINGA_MinVisible,   20,
                STRINGA_MaxChars,     MEDFIELD,
                GA_TabCycle,          TRUE,
            TAG_END),
            LAYOUT_AddChild,          sender_gadgets[GID_S_ST5] =
            NewObject
            (   STRING_GetClass(),    NULL,
                GA_ID,                GID_S_ST5,
                STRINGA_TextVal,      report.developer,
                STRINGA_MinVisible,   20,
                STRINGA_MaxChars,     MEDFIELD,
                GA_TabCycle,          TRUE,
            TAG_END),
            LAYOUT_AddChild,          sender_gadgets[GID_S_ST6] =
            NewObject
            (   STRING_GetClass(),    NULL,
                GA_ID,                GID_S_ST6,
                STRINGA_TextVal,      report.email,
                STRINGA_MinVisible,   20,
                STRINGA_MaxChars,     MEDFIELD,
                GA_TabCycle,          TRUE,
            TAG_END),
        TAG_END),
        CHILD_WeightedHeight,     0,
    TAG_END)
)))
{   rq("Can't create ReAction gadgets!");
}
unlockscreen();
openwindow();

    ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST1]);
    loop();

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

    strcpy(report.refer, "# Refer: ");
    if (!(GetAttr
    (   STRINGA_TextVal, sender_gadgets[GID_S_ST2], (ULONG *) &stringptr
    )))
    {   rq("Unsupported inquiry!"); // should never happen
    }
    strcat(report.refer, stringptr);
    strcat(report.refer, ",");
    if (!(GetAttr
    (   STRINGA_TextVal, sender_gadgets[GID_S_ST1], (ULONG *) &stringptr
    )))
    {   rq("Unsupported inquiry!"); // should never happen
    }
    strcat(report.refer, stringptr);
    strcat(report.refer, " (");
    if (!(GetAttr
    (   STRINGA_TextVal, sender_gadgets[GID_S_ST3], (ULONG *) &stringptr
    )))
    {   rq("Unsupported inquiry!"); // should never happen
    }
    strcat(report.refer, stringptr);
    strcat(report.refer, " ,phone ");
    if (!(GetAttr
    (   STRINGA_TextVal, sender_gadgets[GID_S_ST4], (ULONG *) &stringptr
    )))
    {   rq("Unsupported inquiry!"); // should never happen
    }
    strcat(report.refer, stringptr);
    strcat(report.refer, ")\n");

    if (!(GetAttr
    (   STRINGA_TextVal, sender_gadgets[GID_S_ST6], (ULONG *) &stringptr
    )))
    {   rq("Unsupported inquiry!"); // should never happen
    }
    strcpy(report.path, "# Path: ");
    strcat(report.path, stringptr);
    strcat(report.path, "\n");

    if (!(GetAttr
    (   STRINGA_TextVal, sender_gadgets[GID_S_ST5], (ULONG *) &stringptr
    )))
    {   rq("Unsupported inquiry!"); // should never happen
    }
    strcpy(report.referid, "# ReferID: ");
    strcat(report.referid, stringptr);
    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 gid)
{   ;
}

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

    /* If you have any lock on the file or its directory, this function
    will fail (returning "?"). */

    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;
}   }

AGLOBAL ABOOL dirasl(void)
{   struct FileRequester* ASLRqPtr;
    ABOOL                 success;

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "#?", ASL_Window, MainWindowPtr, ASL_ExtFlags1, FIL1F_NOFILES, TAG_DONE)))
    {   rq("Can't create ASL request!");
    }
    if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ path selector", ASL_FuncFlags, FILF_PATGAD, TAG_DONE))
    {   strcpy(aslresult, ASLRqPtr->rf_Dir);
        success = TRUE;
    } else success = FALSE;
    FreeAslRequest(ASLRqPtr);
    return(success);
}

AGLOBAL void comma(ULONG value, STRPTR commastring)
{   ABOOL yes = FALSE;
    TEXT  valuestring[11];

    strcpy(commastring, " ,   ,   ,   ");
    //                    1   5   9

    valuestring[ 0] = '0' + (value / 1000000000);
    value %= 1000000000;
    if (valuestring[ 0] != '0')
    {   commastring[0] = valuestring[0];
        yes = TRUE;
    } else
    {   commastring[ 0] = ' ';
        commastring[ 1] = ' ';
    }

    valuestring[ 1] = '0' + (value /  100000000);
    value %=  100000000;
    if (yes || valuestring[1] != '0')
    {   commastring[2] = valuestring[1];
        yes = TRUE;
    } else commastring[2] = ' ';

    valuestring[ 2] = '0' + (value /   10000000);
    value %=   10000000;
    if (yes || valuestring[2] != '0')
    {   commastring[3] = valuestring[2];
        yes = TRUE;
    } else commastring[3] = ' ';

    valuestring[ 3] = '0' + (value /    1000000);
    value %=    1000000;
    if (yes || valuestring[3] != '0')
    {   commastring[4] = valuestring[3];
        yes = TRUE;
    } else
    {   commastring[4] = ' ';
        commastring[5] = ' ';
    }

    valuestring[ 4] = '0' + (value /     100000);
    value %=     100000;
    if (yes || valuestring[4] != '0')
    {   commastring[6] = valuestring[4];
        yes = TRUE;
    } else commastring[6] = ' ';

    valuestring[ 5] = '0' + (value /      10000);
    value %=      10000;
    if (yes || valuestring[5] != '0')
    {   commastring[7] = valuestring[5];
        yes = TRUE;
    } else commastring[7] = ' ';

    valuestring[ 6] = '0' + (value /       1000);
    value %=       1000;
    if (yes || valuestring[6] != '0')
    {   commastring[8] = valuestring[6];
        yes = TRUE;
    } else
    {   commastring[8] = ' ';
        commastring[9] = ' ';
    }

    valuestring[ 7] = '0' + (value /        100);
    value %=        100;
    if (yes || valuestring[7] != '0')
    {   commastring[10] = valuestring[7];
        yes = TRUE;
    } else commastring[10] = ' ';

    valuestring[ 8] = '0' + (value /         10);
    value %=         10;
    if (yes || valuestring[8] != '0')
    {   commastring[11] = valuestring[8];
        // yes = TRUE;
    } else commastring[11] = ' ';

    valuestring[ 9] = '0' +  value              ;
    commastring[12] = valuestring[9];
}

AGLOBAL ULONG SenderHookFunc(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." */

    UWORD code, qual;

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

    code = ((struct IntuiMessage *) msg)->Code;
    qual = ((struct IntuiMessage *) msg)->Qualifier;

    switch(code)
    {
    case SCAN_HELP:
        helpabout();
    break;
    case SCAN_ESCAPE:
        if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
        {   cleanexit(EXIT_SUCCESS);
        } else
        {   if (shared.function == 1)
            {   page = 11;
            } else
            {   assert(shared.function == 3);
                page = 32;
        }   }
    break;
    case SCAN_F:
        ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST1]);
    break;
    case SCAN_L:
        ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST2]);
    break;
    case SCAN_C:
        ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST3]);
    break;
    case SCAN_P:
        ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST4]);
    break;
    case SCAN_D:
        ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST5]);
    break;
    case SCAN_E:
        ActivateLayoutGadget(sender_gadgets[GID_S_LY1], MainWindowPtr, NULL, (Object) sender_gadgets[GID_S_ST6]);
    break;
    default:
    break;
    }

    return(1);
}

AGLOBAL void addreactionnode(struct List* ListPtr, STRPTR text)
{   // This is only for single-column lists.

    struct ListBrowserNode* ListBrowserNodePtr;

    if (!(ListBrowserNodePtr = AllocListBrowserNode
    (   1,                   // columns,
        LBNCA_CopyText,      TRUE,
        LBNCA_Text,          text,
        TAG_END
    )))
    {   rq("Can't create ReAction listbrowser.gadget node(s)!");
    }
    AddTail(ListPtr, (struct Node *) ListBrowserNodePtr); // AddTail() has no return code
}
