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

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

/* #include <assert.h> */

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

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

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

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

#define FUNCTIONS  12

#define SCAN_GRAVE  0

#define ABOUTXPIXEL     312
#define ABOUTYPIXEL      98

#ifdef __STORM__
   #pragma chip
#endif

enum
{   GID_MAIN = 0,
    GID_TEXTEDITOR1,
    GID_TEXTEDITOR2,
    GID_TEXTEDITOR3,
    GID_TEXTEDITOR4,
    GID_TEXTEDITOR5,
    GID_TEXTEDITOR6,
    GID_TEXTEDITOR7,
    GID_TEXTEDITOR8,
    GID_TEXTEDITOR9,
    GID_TEXTEDITOR10,
    GID_TEXTEDITOR11,
    GID_TEXTEDITOR12,
    GID_TEXTEDITOR13,
    GID_TEXTEDITOR14,
    GID_DOWN,
    GID_UP,
    GID_OK,
    GID_LAST
};

MODULE UWORD chip PubAboutData[132] =
{   0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFBFF,0x8FFF,0xFFE0,
    0xFBFF,0x8FFF,0xFFE0,
    0xCA7F,0x07FF,0xFFE0,
    0xCA7F,0x07FF,0xFFE0,
    0xF1FE,0x03FF,0xFFE0,
    0xF1FE,0x03FF,0xFFE0,
    0xCA7C,0x21FF,0xF7E0,
    0xCA7C,0x21FF,0xF7E0,
    0xFBF8,0x70FF,0x3660,
    0xFBF8,0x70FF,0x3660,
    0xFFF0,0xF87F,0xC1E0,
    0xFFF0,0xF87F,0xC1E0,
    0x87E0,0x0000,0x0020,
    0x87E0,0x0000,0x0020,
    0xC3C0,0x3E1F,0xC1E0,
    0xC3C0,0x3E1F,0xC1E0,
    0xE187,0xC70F,0x3660,
    0xE187,0xC70F,0x3660,
    0xF00F,0xF887,0xF7E0,
    0xF00F,0xF887,0xF7E0,
    0xF81F,0xFF03,0xFFE0,
    0xF81F,0xFF03,0xFFE0,
    0xFC3F,0xFFE1,0xFFE0,
    0xFC3F,0xFFE1,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xE1C8,0xDC38,0x6EE0,
    0xE1C8,0xDC38,0x6EE0,
    0xDDB6,0xDBF7,0x66E0,
    0xDDB6,0xDBF7,0x66E0,
    0xC1B6,0xDB30,0x6AE0,
    0xC1B6,0xDB30,0x6AE0,
    0xDDBE,0xDBB7,0x6CE0,
    0xDDBE,0xDBB7,0x6CE0,
    0xDDBE,0xD877,0x6EE0,
    0xDDBE,0xD877,0x6EE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0,
    0xFFFF,0xFFFF,0xFFE0
};
#ifdef __STORM__
   #pragma chip
#endif

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

#define ABOUTLINES      5
#define ABOUTSHADOW BLACK
#define ABOUTSHINE  WHITE

MODULE STRPTR FunctionDesc[FUNCTIONS + 2] =
{   // Edit
    "Bug report",         // 1
    "Aminet readme",      // 2
    "Autodoc",            // 4
    "Battery-backed RAM", // 9
    "AGDB review",        // 1
    // View
    "Manufacturer IDs",   // 5
    "IFF FORMs",          // 6
    // Process
    "EOLs/tabs",          // 7
    "Icons",              // 12
    // Report
    "Path size",          // 8
    "System files",       // 10
    // Conduct
    "ACSE test",          // 3
    // (default)
    TITLEBARTEXT
};

MODULE struct
{   WORD   x, y;
    STRPTR text;
} about[ABOUTLINES + 1] =
{   {80,  27, TITLEBARTEXT,           },
    {80,  35, "Tuesday 21 August 2001"},
    {80,  43, "© 2001 Amigan Software"},
    {80,  59, "By James R. Jacobs"    },
    {80,  75, "Kickstart: "           },
    {80,  83, "Workbench: "           }
};
#define MENUENTRIES 13
MODULE struct NewMenu NewMenu[MENUENTRIES] =
{   { NM_TITLE, "Project",       0 , 0,               0, 0},
    {  NM_ITEM, "New",          "N", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, "Open...",      "O", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, NM_BARLABEL,     0 , 0,               0, 0},
    {  NM_ITEM, "Save",         "S", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, "Save As...",   "O", NM_ITEMDISABLED, 0, 0},
    {  NM_ITEM, NM_BARLABEL,     0 , 0,               0, 0},
    {  NM_ITEM, "Quit Report+", "Q", 0,               0, 0},
    { NM_TITLE, "Help",          0 , 0,               0, 0},
    {  NM_ITEM, "Manual...",    "M", 0,               0, 0},
    {  NM_ITEM, NM_BARLABEL,     0 , 0,               0, 0},
    {  NM_ITEM, "About...",     "?", 0,               0, 0},
    {   NM_END, NULL,            0 , 0,               0, 0}
};

MODULE void clearkybd(void);
MODULE void menu(void);
MODULE void parsewb(void);
MODULE void eachwildcard(STRPTR subpattern);
MODULE void menu_loop(ULONG gid);

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;
AGLOBAL ABOOL                   done             = FALSE,
                                fillwindows      = FALSE,
                                stop             = FALSE;
AGLOBAL TEXT                    asldir[VLONGFIELD + 1],
                                aslresult[VLONGFIELD + 1],
                                IOBuffer[LONGESTFIELD + 1],
                                globalname[VLONGFIELD + 1],
                                string[4096 + 1],
                                weekdaystring[LEN_DATSTRING],
                                datestring[LEN_DATSTRING],
                                timestring[LEN_DATSTRING];
AGLOBAL SBYTE                   page             = 0,
                                closer           = 0;
AGLOBAL ULONG                   fillcolour,
                                offset,
                                wbval,
                                signal;
AGLOBAL ABOOL                   BattBuffer[96];
AGLOBAL struct Library*         IconBase         = NULL;
AGLOBAL struct Menu*            MenuPtr          = NULL;
AGLOBAL struct Screen*          ScreenPtr        = NULL;
AGLOBAL struct Window*          MainWindowPtr    = NULL;
AGLOBAL struct VisualInfo*      VisualInfoPtr    = NULL;
AGLOBAL struct ExAllData*       EADataPtr        = NULL;
AGLOBAL struct Gadget          *BU99_Right       = NULL,
                               *ST99_Output      = NULL,
                               *BU99_OutputASL   = NULL,
                               *CB99_Log         = NULL,
                               *BU99_Update      = NULL,
                               *BU99_Stop        = NULL,
                               *BU99_TextEditor  = NULL,
                               *GListPtr         = NULL,
                               *PrevGadPtr       = NULL;
AGLOBAL struct List             EmptyList;
AGLOBAL struct SharedStruct shared =
{   TRUE, 0,
    "", "", "", "", "", ""
};

IMPORT struct ExecBase*     SysBase;
// from f1.c
IMPORT struct ReportStruct  report;
// from f2.c
IMPORT struct AminetStruct  aminet;
IMPORT        Object*       Window2Object;
// from f3.c
IMPORT ABOOL                certified;
// from f4.c
IMPORT struct AutodocStruct autodoc;
IMPORT UBYTE*               StarBufferPtr[MAXELEMENTS + 1];
IMPORT ULONG                StarBufferSize[MAXELEMENTS + 1],
                            returncode,
                            inputs;
// from f6.c
IMPORT struct IFFStruct     iff;
// from f7.c
IMPORT struct Gadget*       TE71_Status;
// from f9.c
IMPORT struct Library*      BattMemBase;
// from f11.c
IMPORT struct AGDBStruct    agdb;
// from f12.c
IMPORT struct IconStruct    icon;
IMPORT struct Gadget*       icon_gadgets[GIDS_12 + 1];
IMPORT        Object*       Window12Object;
IMPORT ABOOL                quit;

MODULE struct Gadget*          te_gadgets[MAXELEMENTS + 1];
MODULE STRPTR                  textBuffer[MAXELEMENTS + 1];
MODULE WORD                    windowx[FUNCTIONS + 1],
                               windowy[FUNCTIONS + 1];
MODULE TEXT                    pubscreen[256 + 1];
MODULE WORD                    xsize,
                               ysize;
MODULE ULONG                   elements,
                               ksval;
MODULE        Object*          Window0Object;
MODULE struct Gadget*          gadgets[GIDS_0 + 1];
MODULE struct RDArgs*          ArgsPtr           = NULL;
MODULE struct TextFont*        FontPtr           = NULL;
MODULE struct WBArg*           WBArg             = NULL;
MODULE struct WBStartup*       WBMsg             = NULL;
MODULE struct ASLBase*         ASLBase         = NULL;
MODULE struct DiskFontBase*    DiskFontBase    = NULL;
MODULE struct Library*         GadToolsBase    = NULL;
MODULE struct IntuitionBase*   IntuitionBase   = NULL;
MODULE struct Library*         VersionBase     = NULL;
MODULE struct TextAttr         Topaz8 =
{	(STRPTR) "topaz.font", 8, FS_NORMAL, FPF_ROMFONT | FPF_DESIGNED
}, /* "topaz.font" is case-sensitive */ WormWars8 =
{	(STRPTR) "WormWars.font", 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
};
MODULE struct Image
PubAbout =
{   0, 0,
    43, 44, 1,
    PubAboutData,
    0x1, 3,
    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] = { 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L };
    BPTR   OldDir;
    SLONG  number = 0, hostid = 7;
    BPTR   ConfigHandle = NULL;

    /* Start of program.

    version embedding into executable */

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

    /* Check for OS3.5+... */
    if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 40L)))
    {   Printf("Report+: Need AmigaOS 3.5+!\n");
        cleanexit(EXIT_FAILURE);
    }
    if ((ksval = SysBase->LibNode.lib_Version) < 40L)
    {   Printf("Report+: Need AmigaOS 3.5+!\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 < 44)
    {   Printf("Report+: Need AmigaOS 3.5+!\n");
        cleanexit(EXIT_FAILURE);
    }

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

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

    pubscreen[0] = 0;
    NewList(&EmptyList);
    if (!(EADataPtr = AllocVec(2048, MEMF_CLEAR | MEMF_PUBLIC)))
    {   rq("Out of memory!");
    }

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

    if (argc) /* started from CLI */
    {   if (!(ArgsPtr = ReadArgs
        (   "-F=FILL/S,PUBSCREEN/K,FUNCTION/N,ICONTYPE/K,"
            "RESET/S,TIMEOUT/S,LUNS/S,SYNC_XFER/S,SLOW_SYNC/S,TAG_QUEUES/S,HOST_ID/K/N,"
            "FILE/F",
            (LONG *) args,
            NULL
	)))
        {   Printf
            (   "Usage: %s [-f=FILL] [PUBSCREEN <screen>]"
                "[[FUNCTION] <function> "
                "[ICONTYPE DISK|DRAWER|TOOL|PROJECT|TRASHCAN|DEVICE|KICKSTART|APPICON] "
                "[RESET [TIMEOUT] [LUNS] [SYNC_XFER] [SLOW_SYNC] [TAG_QUEUES] [HOST_ID <host_id>]] "
                "[[FILE] <file(s)...>]]\n",
                argv[0]
            );
            cleanexit(EXIT_FAILURE);
	}
        if (args[0])
        {   fillwindows = TRUE;
        }
        if (args[1])
        {   strcpy(pubscreen, (STRPTR) args[1]);
        }
        if (args[2])
        {   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 != 12)
            {   Printf("%s: <function> must be 12 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[9]));
                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]);
                report.loaded = TRUE;
                loadreport();
            break;
            case 2:
                strcpy(aminet.output, (STRPTR) args[11]);
                aminet.loaded = TRUE;
                loadaminet();
            break;
            case 6:
                strcpy(iff.pathname, (STRPTR) args[11]);
            break;
            case 7:
                strcpy(shared.pathname, (STRPTR) args[11]);
                convert(FALSE);
                Printf("All done.\n");
                cleanexit(EXIT_SUCCESS);
            break;
            case 11:
                strcpy(  agdb.output, (STRPTR) args[11]);
                agdb.loaded = TRUE;
                loadagdb();
            break;
            case 12:
                strcpy(shared.pathname, (STRPTR) args[11]);
                convert(FALSE);
                Printf("All done.\n");
                cleanexit(EXIT_SUCCESS);
            break;
            default:
                Printf("Report+: <function> must be 1, 2, 6, 7, 11 or 12 for this!\n");
                cleanexit(EXIT_FAILURE);
            break;
    }   }   }
    else /* started from WB */
    {   WBMsg = (struct WBStartup *) argv;
        WBArg = WBMsg->sm_ArgList; /* head of the arg list */
        for (i = 0; i < WBMsg->sm_NumArgs; i++, WBArg++)
        {   if (WBArg->wa_Lock)
            {   /* something that does not support locks */
                parsewb();
            } else
            {   /* lock supported; change to the proper directory */
                OldDir = CurrentDir(WBArg->wa_Lock);
                parsewb();
                CurrentDir(OldDir);
            }
            if (i == 1)
            {   ; /* we were started from a project icon, which is
                currently unsupported */
    }   }   }

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

    for (i = 0; i <= FUNCTIONS; i++)
    {   windowx[i] = windowy[i] = -1;
    }

    if (ConfigHandle = (BPTR) Open("PROGDIR:ReportPlus.config", MODE_OLDFILE))
    {   if (Read(ConfigHandle, IOBuffer, 19) != -1)
        {   shared.log = IOBuffer[0];
            eol_config();
            size_config();
            files_config();
            icon_config();
        }
        Close(ConfigHandle);
        ConfigHandle = NULL;
    }

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

MODULE void menu(void)
{   /* PAGE 0 ************************************************************* */

    struct Hook Hook0Struct;

    certified = FALSE;

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

    lockscreen();
    if (!(Window0Object = NewObject(WINDOW_GetClass(), NULL,
        // window tags
        WA_PubScreen,             ScreenPtr,
        WA_ScreenTitle,           TITLEBARTEXT,
        WA_Title,                 "Report+: Main Menu",
        WA_Activate,              TRUE,
        WA_DepthGadget,           TRUE,
        WA_DragBar,               TRUE,
        WA_CloseGadget,           TRUE,
        WA_IDCMP,                 IDCMP_RAWKEY | IDCMP_INTUITICKS,
        WINDOW_IDCMPHook,         &Hook0Struct,
        WINDOW_IDCMPHookBits,     IDCMP_RAWKEY | IDCMP_INTUITICKS,
        WINDOW_MenuStrip,         MenuPtr,
        WINDOW_Position,          WPOS_CENTERSCREEN,
        WINDOW_ParentGroup,       gadgets[GID_0_LY1] =
        NewObject
        (   LAYOUT_GetClass(),         NULL,
            // root-layout tags
            LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
            LAYOUT_SpaceOuter,         TRUE,
            LAYOUT_DeferLayout,        TRUE,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),     NULL,
                // layout tags
                LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,     TRUE,
                LAYOUT_DeferLayout,    TRUE,
                LAYOUT_HorizAlignment, LALIGN_CENTER,
                LAYOUT_AddImage,
                NewObject
                (   BITMAP_GetClass(), NULL,
                    // bitmap tags
                    BITMAP_SourceFile, "PROGDIR:images/logo.ilbm",
                    BITMAP_Masking,    TRUE,
                    BITMAP_Screen,     ScreenPtr,
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(), NULL,
                // layout tags
                LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,     TRUE,
                LAYOUT_DeferLayout,    TRUE,
                LAYOUT_HorizAlignment, LALIGN_CENTER,
                LAYOUT_AddImage,
                NewObject
                (   LABEL_GetClass(),    NULL,
                    // label tags
                    LABEL_Justification, LJ_CENTRE,
                    LABEL_Text,          "Edit:",
                    TAG_END
                ),
                TAG_END
            ),
            CHILD_WeightedHeight,      0,
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,         TRUE,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,           gadgets[GID_0_BU1] =
                NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU1,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,
                    NewObject
                    (   BITMAP_GetClass(), NULL,
                        // bitmap tags
                        BITMAP_SourceFile, "PROGDIR:images/f1.ilbm",
                        BITMAP_Screen,     ScreenPtr,
                        TAG_DONE
                    ),
                    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_SourceFile, "PROGDIR:images/f2.ilbm",
                        BITMAP_Screen,     ScreenPtr,
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU3] =
                NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU3,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,              NewObject
                    (   BITMAP_GetClass(), NULL,
                        // bitmap tags
                        BITMAP_SourceFile, "PROGDIR:images/f4.ilbm",
                        BITMAP_Screen,     ScreenPtr,
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU4] = NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU4,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,              NewObject
                    (   BITMAP_GetClass(), NULL,
                        // bitmap tags
                        BITMAP_SourceFile, "PROGDIR:images/f9.ilbm",
                        BITMAP_Screen,     ScreenPtr,
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,           gadgets[GID_0_BU5] = (struct Gadget *) NewObject
                (   NULL, "button.gadget",
                    // button tags
                    GA_ID,                 GID_0_BU5,
                    GA_Left,               20,
                    GA_Top,                20,
                    GA_Width,              41,
                    GA_Height,             40,
                    GA_RelVerify,          TRUE,
                    GA_Image,              NewObject
                    (   BITMAP_GetClass(), NULL,
                        // bitmap tags
                        BITMAP_SourceFile, "PROGDIR:images/f11.ilbm",
                        BITMAP_Screen,     ScreenPtr,
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,         TRUE,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,    TRUE,
                         LAYOUT_DeferLayout,   TRUE,
                         LAYOUT_HorizAlignment, LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(), NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "View:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU6] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU6,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(), NULL,
                                // bitmap tags
                                BITMAP_SourceFile, "PROGDIR:images/f5.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            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_SourceFile, "PROGDIR:images/f6.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,    TRUE,
                         LAYOUT_DeferLayout,   TRUE,
                         LAYOUT_HorizAlignment, LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(), NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "Process:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU8] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU8,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(), NULL,
                                // bitmap tags
                                BITMAP_SourceFile, "PROGDIR:images/f7.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            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_SourceFile, "PROGDIR:images/f12.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                TAG_DONE
            ),
            LAYOUT_AddChild,
            NewObject
            (   LAYOUT_GetClass(),         NULL,
                // layout tags
                LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceOuter,         TRUE,
                LAYOUT_DeferLayout,        TRUE,
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),       NULL,
                         // layout tags
                         LAYOUT_Orientation,      LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,       TRUE,
                         LAYOUT_DeferLayout,      TRUE,
                         LAYOUT_HorizAlignment,   LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(),    NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "Report:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU10] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU10,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(), NULL,
                                // bitmap tags
                                BITMAP_SourceFile, "PROGDIR:images/f8.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            TAG_DONE
                        ),
                        LAYOUT_AddChild,           gadgets[GID_0_BU11] =
                        NewObject
                        (   NULL,                  "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU11,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(), NULL,
                                // bitmap tags
                                BITMAP_SourceFile, "PROGDIR:images/f10.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            TAG_DONE
                        ),
                        TAG_DONE
                    ),
                    TAG_DONE
                ),
                LAYOUT_AddChild,
                NewObject
                (   LAYOUT_GetClass(),         NULL,
                    // layout tags
                    LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
                    LAYOUT_SpaceOuter,         TRUE,
                    LAYOUT_DeferLayout,        TRUE,
                    LAYOUT_AddChild,
                    NewObject
                    (    LAYOUT_GetClass(),    NULL,
                         // layout tags
                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
                         LAYOUT_SpaceOuter,    TRUE,
                         LAYOUT_DeferLayout,   TRUE,
                         LAYOUT_HorizAlignment, LALIGN_CENTER,
                         LAYOUT_AddImage,
                         NewObject
                         (   LABEL_GetClass(), NULL,
                             // label tags
                             LABEL_Justification, LJ_CENTRE,
                             LABEL_Text,          "Conduct:",
                             TAG_END
                         ),
                         TAG_DONE
                    ),
                    LAYOUT_AddChild,
                    NewObject
                    (   LAYOUT_GetClass(),         NULL,
                        // layout tags
                        LAYOUT_Orientation,        LAYOUT_ORIENT_HORIZ,
                        LAYOUT_SpaceOuter,         TRUE,
                        LAYOUT_DeferLayout,        TRUE,
                        LAYOUT_AddChild,           gadgets[GID_0_BU12] =
                        NewObject
                        (   NULL, "button.gadget",
                            // button tags
                            GA_ID,                 GID_0_BU12,
                            GA_Left,               20,
                            GA_Top,                20,
                            GA_Width,              41,
                            GA_Height,             40,
                            GA_RelVerify,          TRUE,
                            GA_Image,              NewObject
                            (   BITMAP_GetClass(), NULL,
                                // bitmap tags
                                BITMAP_SourceFile, "PROGDIR:images/f3.ilbm",
                                BITMAP_Screen,     ScreenPtr,
                                TAG_DONE
                            ),
                            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();

    if (!(MainWindowPtr = (struct Window *) DoMethod((Object *) Window0Object, WM_OPEN, NULL)))
    {   rq("Can't open ReAction window!");
    }
    // Obtain the window wait signal mask.
    GetAttr(WINDOW_SigMask, Window0Object, &signal);

    loop();
    closewindow();
}

AGLOBAL void cleanexit(SBYTE rc)
{   BPTR ConfigHandle;

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

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

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

    IOBuffer[0] = shared.log;

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

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

    if (EADataPtr)
    {   FreeVec(EADataPtr);
        EADataPtr = NULL;
    }
    if (FontPtr)
    {   CloseFont(FontPtr);
        FontPtr = NULL;
    }
    if (ArgsPtr)
    {   FreeArgs(ArgsPtr);
        ArgsPtr = NULL;
    }

    /* Reaction */
    CloseLibrary(ButtonBase);
    CloseLibrary(CheckBoxBase);
    CloseLibrary(ChooserBase);
    CloseLibrary(LabelBase);
    CloseLibrary(LayoutBase);
    CloseLibrary(StringBase);
    CloseLibrary(TextEditorBase);
    CloseLibrary(BitMapBase);
    CloseLibrary(ListBrowserBase);
    CloseLibrary(WindowBase);

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

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

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

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

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

AGLOBAL void verynewwindow(SWORD width, SWORD height, STRPTR title, ULONG idcmp)
{   WORD thewindowx, thewindowy;

    gadtools();
    lockscreen();

    if (page == 32 || page == 33)
    {   thewindowx = (xsize / 2) - (width / 2);
        thewindowy = 12 + ((ysize - 12) / 2) - (height / 2);
    } else
    {   if (windowx[page / 10] == -1)
        {   windowx[page / 10] = (xsize / 2) - (width / 2);
            windowy[page / 10] = 12 + ((ysize - 12) / 2) - (height / 2);
        }
        thewindowx = windowx[page / 10];
        thewindowy = windowy[page / 10];
    }

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

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

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

    navigate();
}

AGLOBAL void helpabout(void)
{   SBYTE line;
    TEXT  ks[5], wb[5];

    OffMenu(MainWindowPtr, FULLMENUNUM(MN_HELP, IN_ABOUT, NOSUB));
    switch(ksval)
    {
    case 40:
        strcpy(ks, "3.1 ");
    break;
    default:
        strcpy(ks, "4.0+");
    break;
    }
    switch(wbval)
    {
    break;
    case 44:
        strcpy(wb, "3.5 ");
    break;
    case 45:
        strcpy(wb, "3.9 ");
    break;
    default:
        strcpy(wb, "4.0+");
    break;
    }

    lockscreen();
    if (!(AboutWindowPtr = (struct Window *) OpenWindowTags
    (   NULL,
        WA_Left,          (xsize / 2) - (ABOUTXPIXEL / 2),
        WA_Top,           12 + ((ysize - 12) / 2) - (ABOUTYPIXEL / 2),
        WA_Width,         ABOUTXPIXEL,
        WA_Height,        ABOUTYPIXEL,
        WA_IDCMP,         IDCMP_CLOSEWINDOW | IDCMP_RAWKEY,
        WA_Title,         "About Report+",
        WA_Gadgets,       NULL,
        WA_PubScreen,     ScreenPtr,
        WA_DragBar,       TRUE,
        WA_DepthGadget,   TRUE,
        WA_CloseGadget,   TRUE,
        WA_NoCareRefresh, TRUE,
        WA_Activate,      TRUE,
        TAG_DONE
    )))
    {   rq("Can't open About... window!");
    }
    unlockscreen();

    SetFont(AboutWindowPtr->RPort, FontPtr);
    SetDrMd(AboutWindowPtr->RPort, JAM1);
    SetAPen(AboutWindowPtr->RPort, BLACK);
    for (line = 0; line <= ABOUTLINES; line++)
    {   Move(AboutWindowPtr->RPort, about[line].x, about[line].y);
        Text(AboutWindowPtr->RPort, about[line].text, (SBYTE) strlen(about[line].text));
        if (line == 4)
        {   Text(AboutWindowPtr->RPort, ks, 4);
        } elif (line == 5)
        {   Text(AboutWindowPtr->RPort, wb, 4);
    }   }

    DrawBevelBox(AboutWindowPtr->RPort, 19, 21, 45, 46, GT_VisualInfo, VisualInfoPtr, GTBB_Recessed, TRUE, TAG_DONE);
    DrawImage(AboutWindowPtr->RPort, &PubAbout, 20, 22);
}

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

        if (closer != 32 && closer != 33)
        {    // memorize the position of the window, for next time
             windowx[closer / 10] = MainWindowPtr->LeftEdge;
             windowy[closer / 10] = MainWindowPtr->TopEdge;
        }
        if (closer == 0 || closer == 121)
        {   /* 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.
             */
            if (closer == 0)
            {   DisposeObject(Window0Object);
            } else
            {   assert(closer == 121);
                DisposeObject(Window12Object);
            }
            MainWindowPtr = NULL;
        } else
        {   ClearMenuStrip(MainWindowPtr);
            CloseWindow(MainWindowPtr);
            MainWindowPtr = NULL;
    }   }
    if (GListPtr)
    {   FreeGadgets(GListPtr);
        GListPtr = NULL;
    }
    if (MenuPtr)
    {   FreeMenus(MenuPtr);
        MenuPtr = NULL;
    }
    if (VisualInfoPtr)
    {   FreeVisualInfo(VisualInfoPtr);
        VisualInfoPtr = NULL;
}   }

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

    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, "Report+ file selector", ASL_FuncFlags, FILF_PATGAD, TAG_DONE)
     && *(ASLRqPtr->rf_File) != 0
    )
    {   strcpy(asldir, ASLRqPtr->rf_Dir);
        strcpy(aslresult, ASLRqPtr->rf_Dir);
        if (!AddPart(aslresult, ASLRqPtr->rf_File, VLONGFIELD))
            rq("Can't add filename to pathname!");
        success = TRUE;
    } else
    {   strcpy(asldir, "");
        strcpy(aslresult, "");
        success = FALSE;
    }
    FreeAslRequest(ASLRqPtr);
    return(success);
}

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

    closer = page;
    done = FALSE;
    while (page == oldpage && !done)
    {   if (AboutWindowPtr)
        {   signals = SetSignal(0L, 0L);
            if (signals & SIGBREAKF_CTRL_C)
            {   done = TRUE;
                SetSignal(0L, SIGBREAKF_CTRL_C); /* clear the Ctrl-C signal */
            }
            if (aboutloop())
            {   CloseWindow(AboutWindowPtr);
                AboutWindowPtr = NULL;
                OnMenu(MainWindowPtr, FULLMENUNUM(MN_HELP, IN_ABOUT, NOSUB));
        }   }
        else
        {   if ((Wait(signal | SIGBREAKF_CTRL_C)) & SIGBREAKF_CTRL_C)
            {  done = TRUE;
               /* should we clear the Ctrl-C signal? */
        }   }
        if (page == 0)
        {   while ((result = DoMethod(Window0Object, WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
            {   switch (result & WMHI_CLASSMASK)
                {
                case WMHI_MENUPICK:
                    handlemenus(code);
                break;
                case WMHI_CLOSEWINDOW:
                    cleanexit(EXIT_SUCCESS);
                break;
                case WMHI_GADGETUP:
                    menu_loop(result & WMHI_GADGETMASK);
                break;
                default:
                break;
        }   }   }
        elif (page == 121)
        {   while ((result = DoMethod(Window12Object, WM_HANDLEINPUT, &code)) != WMHI_LASTMSG)
            {   switch (result & WMHI_CLASSMASK)
                {
                case WMHI_MENUPICK:
                    handlemenus(code);
                break;
                case WMHI_CLOSEWINDOW:
                    page = 0;
                break;
                case WMHI_GADGETUP:
                    icon_loop(result & WMHI_GADGETMASK);
                break;
                default:
                break;
        }   }   }
        else
        {   while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
            {   class  = MsgPtr->Class;                       
                code   = MsgPtr->Code;
                addr   = MsgPtr->IAddress;
                qual   = MsgPtr->Qualifier;
                mousex = MsgPtr->MouseX;
                mousey = MsgPtr->MouseY;
                GT_ReplyIMsg(MsgPtr);
                switch(class)
                {
                case IDCMP_MENUPICK:
                    handlemenus(code);
                break;
                case IDCMP_CLOSEWINDOW:
                    page = 0;
                break;
                case IDCMP_REFRESHWINDOW:
                    GT_BeginRefresh(MainWindowPtr);
                    GT_EndRefresh(MainWindowPtr, TRUE);
                break;
                default:
                    if (class == IDCMP_RAWKEY && code == SCAN_HELP)
                        helpabout();
                    elif (class == IDCMP_VANILLAKEY && code == ESCAPE && ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT)))
                        cleanexit(EXIT_SUCCESS);
                    elif (page >= 11 && page <= 14)
                        report_loop(class, addr, code, qual);
                    elif (page == 21)
                        aminet_loop(class, addr, code, qual);
                    elif (page >= 31 && page <= 33)
                        acse_loop(class, addr, code);
                    elif (page == 41)
                        autodoc_loop(class, addr, code);
                    elif (page == 51)
                        manuf_loop(class, addr, code);
                    elif (page == 61)
                        iff_loop(class, addr, code, qual);
                    elif (page == 71)
                        eol_loop(class, addr, code, qual);
                    elif (page == 81)
                        size_loop(class, addr, code, qual);
                    elif (page == 91)
                        batt_loop(class, addr, code, qual, mousex, mousey);
                    elif (page == 101)
                        files_loop(class, addr, code, qual);
                    elif (page == 111)
                    {   agdb_loop(class, addr, code);
                    }
                break;
}   }   }   }   }

AGLOBAL void navigate(void)
{   gadtools();

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

    /* next */
    switch(page)
    {
    case 11:
        setgadget(            10,  REPORTHEIGHT - 16,      REPORTWIDTH - 20, 12, "Menu",     NULL);
    break;
    case 12:
        setgadget(            10,  SENDERHEIGHT - 16,      SENDERWIDTH - 20, 12, "OK",     NULL);
    break;
    case 13:
        setgadget(            10,  CONFIGHEIGHT - 16,      CONFIGWIDTH - 20, 12, "OK",     NULL);
    break;
    case 21:
        setgadget(            10,  AMINETHEIGHT - 16,      AMINETWIDTH - 20, 12, "Menu",     NULL);
    break;
    case 31:
        setgadget(            10,   ACSE1HEIGHT - 16,       ACSE1WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 32:
        if (certified)
            setgadget(        10,   ACSE2HEIGHT - 16,       ACSE2WIDTH - 20, 12, "OK",       NULL);
        else                                                                                 
            setgadget(        10,   ACSE2HEIGHT - 16,       ACSE2WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 33:
        setgadget(            10,   ACSE3HEIGHT - 16,       ACSE3WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 41:
        setgadget(            10, AUTODOCHEIGHT - 16,     AUTODOCWIDTH - 20, 12, "Menu",     NULL);
    break;
    case 51:
        setgadget(            10,  MANUF1HEIGHT - 16,      MANUF1WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 61:
        setgadget(            10,    IFF1HEIGHT - 16,        IFF1WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 71:
        setgadget(            10,    EOL1HEIGHT - 16,        EOL1WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 81:
        if (ysize >= 512)
        {   setgadget(        10,           512 - 16,       SIZE1WIDTH - 20, 12, "Menu",     NULL);
        } else
        {   setgadget(        10,   SIZE1HEIGHT - 16,       SIZE1WIDTH - 20, 12, "Menu",     NULL);
        }
    break;
    case 91:
        setgadget(            10,   BATT1HEIGHT - 16,       BATT1WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 101:
        setgadget(            10,  FILES1HEIGHT - 16,      FILES1WIDTH - 20, 12, "Menu",     NULL);
    break;
    case 111:
        setgadget(            10,    AGDBHEIGHT - 16,        AGDBWIDTH - 20, 12, "Menu",     NULL);
    break;
    default:
    break;
    }
    BU99_Right = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
}

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

AGLOBAL ABOOL readin(STRPTR pathname)
{   BPTR FileHandle;

    if (!(FileHandle = (BPTR) Open(pathname, MODE_OLDFILE)))
        return FALSE;
    if (Read(FileHandle, IOBuffer, 4096) == -1)
    /* the whole bug report must be < 4K */
    {   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 launcheditor(STRPTR pathname)
{   GT_SetGadgetAttrs
    (   BU99_Right,
        MainWindowPtr, NULL,
        GA_Disabled, TRUE,
        TAG_DONE
    );
    textedit();
    GT_SetGadgetAttrs
    (   BU99_Right,
        MainWindowPtr, NULL,
        GA_Disabled, FALSE,
        TAG_DONE
    );
}

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

    cleanexit(EXIT_FAILURE);
}

AGLOBAL void readordie(STRPTR pathname)
{   BPTR FileHandle;

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

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

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

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

AGLOBAL ULONG checkbreak(void)
{   struct IntuiMessage* MsgPtr;
    struct Gadget*       addr;
    ULONG                class;
    UWORD                code;

    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
    {   class  = MsgPtr->Class;
        code   = MsgPtr->Code;
        addr   = MsgPtr->IAddress;
        GT_ReplyIMsg((struct IntuiMessage *) MsgPtr);
        switch(class)
        {
        case IDCMP_CLOSEWINDOW:
            return(2);
        break;
        case IDCMP_GADGETUP:
            if (addr == BU99_Stop)
                return(1);
        break;
        case IDCMP_VANILLAKEY:
            if (code == ESCAPE)
                return(1);
        break;
        case IDCMP_REFRESHWINDOW:
            GT_BeginRefresh(MainWindowPtr);
            GT_EndRefresh(MainWindowPtr, TRUE);
        break;
        default:
        break;
    }   }
    return(0);
}

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 append(STRPTR pathname)
{   BPTR FileHandle;

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

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

    /* processes any outstanding messages for the About... window. */
    /* returns TRUE if user wants to exit, FALSE otherwise. */

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

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

AGLOBAL void fliplog(ABOOL keyboard)
{   if (keyboard)
    {   if (CB99_Log->Flags & GFLG_SELECTED)
        {   shared.log = FALSE;
        } else
        {   shared.log = TRUE;
    }   }
    else
    {   if (CB99_Log->Flags & GFLG_SELECTED)
        {   shared.log = TRUE;
        } else
        {   shared.log = FALSE;
    }   }

    if (!shared.log)
    {   GT_SetGadgetAttrs
        (   ST99_Output,
            MainWindowPtr, NULL,
            GA_Disabled, TRUE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   BU99_OutputASL,
            MainWindowPtr, NULL,
            GA_Disabled, TRUE,
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   ST99_Output,
            MainWindowPtr, NULL,
            GA_Disabled, FALSE,
            TAG_DONE
        );
        GT_SetGadgetAttrs
        (   BU99_OutputASL,
            MainWindowPtr, NULL,
            GA_Disabled, FALSE,
            TAG_DONE
        );
    }
    GT_SetGadgetAttrs
    (   CB99_Log,
        MainWindowPtr, NULL,
        GTCB_Checked, shared.log,
        TAG_DONE
    );
}

AGLOBAL void outputasl(void)
{   asl();
    GT_SetGadgetAttrs
    (   ST99_Output,
        MainWindowPtr,
        NULL,
        GTST_String, aslresult,
        TAG_DONE
    );
}
AGLOBAL void outputstring(void)
{   strcpy
    (   shared.output,
        ((struct StringInfo *) ST99_Output->SpecialInfo)->Buffer
    );
}
AGLOBAL void drawgadgets(WORD gadgets)
{   if (!PrevGadPtr)
        rq("Can't create GadTools gadgets!");
    AddGList(MainWindowPtr, BU99_Right, (UWORD) ~0, gadgets, NULL);
    RefreshGList(BU99_Right, MainWindowPtr, NULL, -1);
    GT_RefreshWindow(MainWindowPtr, NULL);
}

AGLOBAL void parse(STRPTR terminator)
{   ABOOL done = FALSE;
    ULONG suboffset;

    suboffset = offset;
    while (!done)
    {   string[offset - suboffset] = IOBuffer[offset];
        if (!(strncmp(&(IOBuffer[offset]), terminator, strlen(terminator))))
        {   string[offset - suboffset] = 0;
            offset += strlen(terminator);
            done = TRUE;
        } elif (offset > strlen(IOBuffer))
        {   /* failure */
            string[0] = 0;
            done = TRUE;
        } else offset++;
}   }

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)
{   struct FileRequester* ASLRqPtr;
    TEXT                  tempstring[VLONGFIELD + 1];
    ABOOL                 success;

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

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

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

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

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

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

MODULE void eachwildcard(STRPTR subpattern)
{   struct AnchorPath* AnchorPathPtr;
    BPTR               OldDir;
    TEXT               dirbuffer[VLONGFIELD + 1];
    BOOL               result;
    ABOOL              done;

    dirbuffer[0] = NULL;
    if (!(AnchorPathPtr = AllocMem(sizeof(struct AnchorPath), MEMF_ANY | MEMF_PUBLIC)))
        return;

    AnchorPathPtr->ap_BreakBits = NULL;
    AnchorPathPtr->ap_Flags = NULL;
    AnchorPathPtr->ap_Strlen = 0;
    result = MatchFirst(subpattern, AnchorPathPtr);
    if (result == 0)
    {   OldDir = CurrentDir(AnchorPathPtr->ap_Current->an_Lock);
        if (!NameFromLock(AnchorPathPtr->ap_Current->an_Lock, dirbuffer, VLONGFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        if (!AddPart(dirbuffer, AnchorPathPtr->ap_Info.fib_FileName, VLONGFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        CurrentDir(OldDir);
        strcat(shared.finallist, "\"");
        strcat(shared.finallist, dirbuffer);
        strcat(shared.finallist, "\" ");
    } 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, dirbuffer, VLONGFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            if (!AddPart(dirbuffer, AnchorPathPtr->ap_Info.fib_FileName, VLONGFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            CurrentDir(OldDir);
            strcat(shared.finallist, "\"");
            strcat(shared.finallist, dirbuffer);
            strcat(shared.finallist, "\" ");
        } elif (result != ERROR_NO_MORE_ENTRIES)
        {   MatchEnd(AnchorPathPtr);
            return;
        } else done = TRUE;
    }
    MatchEnd(AnchorPathPtr);
    FreeMem(AnchorPathPtr, sizeof(struct AnchorPath));
}

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

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

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

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, pattern, ASL_Window, MainWindowPtr, TAG_DONE)))
        rq("Can't create ASL request!");
    if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ file multiselector", ASL_FuncFlags, FILF_PATGAD | FILF_MULTISELECT, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
    {   if (ASLRqPtr->rf_NumArgs)
        {   /* rf_ArgList is an array of WBArg structures. Each entry in
            this array corresponds to one of the files the user selected
            (in alphabetical order). The user multiselected; step through
            the list of selected files. */

            strcpy(asldir, ASLRqPtr->rf_Dir);
            strcpy(shared.pathname, quotestring);
            strcat(shared.pathname, ASLRqPtr->rf_Dir);
            if (!AddPart(shared.pathname, (ASLRqPtr->rf_ArgList)[0].wa_Name, VLONGFIELD))
                rq("Can't add filename to pathname!");
            strcat(shared.pathname, quotestring);
            strcat(shared.pathname, " ");
            for (i = 1; i < ASLRqPtr->rf_NumArgs; i++)
            {   strcat(shared.pathname, quotestring);
                strcat(shared.pathname, ASLRqPtr->rf_Dir);
                if (!AddPart(shared.pathname, (ASLRqPtr->rf_ArgList)[i].wa_Name, VLONGFIELD))
                   rq("Can't add filename to pathname!");
                strcat(shared.pathname, quotestring);
                if (i < ASLRqPtr->rf_NumArgs - 1)
                    strcat(shared.pathname, " ");
        }   }
        else
        {   /* The user didn't multiselect; use the normal way to get the
            filename. */

            strcpy(shared.pathname, quotestring);
            strcat(shared.pathname, ASLRqPtr->rf_Dir);
            if (!AddPart(shared.pathname, ASLRqPtr->rf_File, VLONGFIELD))
                rq("Can't add filename to pathname!");
            strcat(shared.pathname, quotestring);
    }   }
    if (ASLRqPtr)
        FreeAslRequest(ASLRqPtr);
}

AGLOBAL void checkabort(ABOOL gui)
{   struct Gadget*       addr;
    struct IntuiMessage* MsgPtr;
    ULONG                class, 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 (page == 71)
            {   GT_SetGadgetAttrs
                (   TE71_Status,
                    MainWindowPtr, NULL,
                    GTTX_Text, "Aborted by user!",
                    TAG_DONE
                );
            } else
            {   /* assert(page == 121); */
                SetGadgetAttrs
                (   icon_gadgets[GID_12_ST2], MainWindowPtr, NULL,
                    STRINGA_TextVal, "Aborted by user!",
                    TAG_DONE
                );
        }   }
        else
        {   Printf("Aborted by user!\n");
            Flush(Output());
    }   }

    if (page == 71)
    {
    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
    {   class  = MsgPtr->Class;                       
        addr   = MsgPtr->IAddress;
        GT_ReplyIMsg(MsgPtr);
        switch(class)
        {
        case IDCMP_CLOSEWINDOW:
            cleanexit(EXIT_SUCCESS);
        break;
        case IDCMP_GADGETUP:
            /* assert(gui); */
            if (addr == BU99_Stop)
            {   GT_SetGadgetAttrs
                (   TE71_Status,
                    MainWindowPtr, NULL,
                    GTTX_Text, "Aborted by user!",
                    TAG_DONE
                );
                stop = TRUE;
            }
        break;
        default:
        break;
    }   }
    } else
    {   /* assert(page == 121); */
        while ((result = DoMethod(Window12Object, 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 (gid == GID_12_BU4)
                {   stop = TRUE;
                }
            break;
            default:
            break;
}   }   }   }

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

    /* 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.

    shared.pathname: the actual contents of the string gadget.
    shared.thatfile: each file that we pass to eachwildcard().
    shared.finallist: the final list produced, containing all pathnames.
    shared.thisfile: each file that we pass for conversion. */

    stop = flag = quoted = FALSE;
    length = strlen(shared.pathname);
    j = shared.finallist[0] = 0;
    for (i = 0; i < length; i++)
    {   if (shared.pathname[i] == ' ' && flag && !quoted)
        {   /* if we're unquoted and have a space */
            shared.thatfile[j] = 0; /* then NULL-terminate the pathname */
            eachwildcard(shared.thatfile);
            j = 0;
            flag = FALSE;
        } elif (shared.pathname[i] == QUOTE)
        {   if (!flag && !quoted)
            {   flag = TRUE; /* we're in letters */
                quoted = TRUE; /* it's a quote */
            } elif (flag && quoted)
            {   quoted = FALSE; /* it's an unquote */
        }   }
        else
        {   shared.thatfile[j++] = shared.pathname[i];
            flag = TRUE; /* we're in letters */
    }   }
    /* Now we are at the end. */
    if (flag) /* 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);
    }

    flag = quoted = FALSE;
    length = strlen(shared.finallist);
    j = 0;
    for (i = 0; i < length; i++)
    {   if (shared.finallist[i] == ' ' && flag && !quoted)
        {   /* if we're unquoted and have a space */
            shared.thisfile[j] = 0; /* then NULL-terminate the pathname */
            if (!stop)
            {   if (shared.function == 7)
                {   eolconvert(gui);
                } else
                {   /* assert(shared.function == 12); */
                    iconconvert(gui);
            }   }
            j = 0;
            flag = FALSE;
        } elif (shared.finallist[i] == QUOTE)
        {   if (!flag && !quoted)
            {   flag = TRUE; /* we're in letters */
                quoted = TRUE; /* it's a quote */
            } elif (flag && quoted)
            {   quoted = FALSE; /* it's an unquote */
        }   }
        else
        {   shared.thisfile[j++] = shared.finallist[i];
            flag = TRUE; /* we're in letters */
        }
        if (stop)
        {   return;
    }   }
    /* Now we are at the end. */
    if (flag) /* if we're in letters */
    {   shared.thisfile[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). */
        if (shared.function == 7)
        {   eolconvert(gui);
        } else
        {   /* assert(shared.function == 12); */
            iconconvert(gui);
}   }   }

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

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

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

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

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

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

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

    return(1);
}

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

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

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

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

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

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

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

AGLOBAL void textedit(void)
{   struct MsgPort* AppPort        = NULL;
    struct Window*  TEWindowPtr    = NULL;
    Object*         TEWindowObject = NULL;
    TEXT            GadTitle[MAXELEMENTS + 1][VLONGFIELD + 1];
    ULONG           i, theindex, wrapsize;
    struct TagItem  windowtag[12],
                    rootlayouttag[7],
                    bothlayouttag[8],
                    supercaptiontag[8],
                    subcaptiontag[3],
                    texteditortag[4],
                    buttontag[4],
                     leftlayouttag[4 + (3 * (MAXELEMENTS + 1))],
                    rightlayouttag[4 + (3 * (MAXELEMENTS + 1))];

    if (page == 11)
    {   wrapsize = 75;
        switch(report.type)
        {
        case BUG:
            strcpy(GadTitle[0], "Brief bug description:");
            strcpy(GadTitle[1], "Bug generation procedure or example:");
            strcpy(GadTitle[2], "If this works differently on other versions or hardware, explain:");
            strcpy(GadTitle[3], "Related problems:");
            elements = 3;
        break;
        case COM:
            if (report.severity == 3)
            {   strcpy(GadTitle[0], "If this works differently on other versions or hardware, explain:");
                elements = 0;
            } else
            {   strcpy(GadTitle[0], "Brief bug description:");
                strcpy(GadTitle[1], "Bug generation procedure or example:");
                strcpy(GadTitle[2], "If this works differently on other versions or hardware, explain:");
                strcpy(GadTitle[3], "What developer is doing in that area of software or hardware:");
                strcpy(GadTitle[4], "Related problems:");
                elements = 4;
            }
        break;
        case ENH:
            strcpy(GadTitle[0], "Enhancement request:");
            elements = 0;
        break;
        default:
        break;
    }   }
    else
    {   // assert(page == 41);
        strcpy(GadTitle[0], "Function:");

        if (inputs)
        {   for (i = 1; i <= inputs; i++)
            {   strcpy(GadTitle[i], autodoc.var[i].name);
                strcat(GadTitle[i], ":");
        }   }
        if (returncode)
        {   strcpy(GadTitle[inputs + 1], "Result:");
        }
        strcpy(GadTitle[inputs + 1 + returncode], "Example:");
        strcpy(GadTitle[inputs + 2 + returncode], "Notes:");
        strcpy(GadTitle[inputs + 3 + returncode], "Bugs:");
        strcpy(GadTitle[inputs + 4 + returncode], "See Also:");
        elements =      inputs + 4 + returncode;
        wrapsize = 72;
    }

    /* window
        root-layout
         both-layout
          left-layout
           super-caption
            sub-caption
           texteditor
          [right-layout
           super-caption
            sub-caption
           texteditor]
         button */

    if (AppPort = CreateMsgPort())
    {   /* Create the window object. */

        subcaptiontag[0].ti_Tag     = LABEL_Text;
        // subcaptiontag[0].ti_Data filled later
        subcaptiontag[1].ti_Tag     = LABEL_Justification;
        subcaptiontag[1].ti_Data    = LJ_CENTRE;
        subcaptiontag[2].ti_Tag     = TAG_END;

       texteditortag[0].ti_Tag  = GA_ID;
       // texteditortag[0].ti_Data filled later
       texteditortag[1].ti_Tag  = GA_RelVerify;
       texteditortag[1].ti_Data = TRUE;
       texteditortag[2].ti_Tag  = GA_TEXTEDITOR_ExportWrap;
       texteditortag[2].ti_Data = wrapsize;
       texteditortag[3].ti_Tag  = TAG_END;

     buttontag[0].ti_Tag      = GA_ID;
     buttontag[0].ti_Data     = GID_OK;
     buttontag[1].ti_Tag      = GA_RelVerify;
     buttontag[1].ti_Data     = TRUE;
     buttontag[2].ti_Tag      = GA_Text;
     buttontag[2].ti_Data     = (ULONG) "_OK";
     buttontag[3].ti_Tag      = TAG_END;

       supercaptiontag[0].ti_Tag  = LAYOUT_Orientation;
       supercaptiontag[0].ti_Data = LAYOUT_ORIENT_VERT;
       supercaptiontag[1].ti_Tag  = GA_BackFill;
       supercaptiontag[1].ti_Data = NULL;
       supercaptiontag[2].ti_Tag  = LAYOUT_SpaceOuter;
       supercaptiontag[2].ti_Data = TRUE;
       supercaptiontag[3].ti_Tag  = LAYOUT_VertAlignment;
       supercaptiontag[3].ti_Data = LALIGN_CENTER;
       supercaptiontag[4].ti_Tag  = LAYOUT_HorizAlignment;
       supercaptiontag[4].ti_Data = LALIGN_CENTER;
       supercaptiontag[5].ti_Tag  = LAYOUT_BevelStyle;
       supercaptiontag[5].ti_Data = BVS_FIELD;
       supercaptiontag[6].ti_Tag  = LAYOUT_AddImage;
       // supercaptiontag[6].ti_Data filled later
       supercaptiontag[7].ti_Tag  = TAG_END;

    leftlayouttag[0].ti_Tag  = LAYOUT_Orientation;
    leftlayouttag[0].ti_Data = LAYOUT_ORIENT_VERT;
    leftlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
    leftlayouttag[1].ti_Data = TRUE;
    leftlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
    leftlayouttag[2].ti_Data = TRUE;
    theindex = 3;

    if (page == 41)
    {   for (i = 0; i <= elements / 2; i++)
        {   subcaptiontag[0].ti_Data          = (ULONG) GadTitle[i];
            texteditortag[0].ti_Data          = GID_TEXTEDITOR1 + i;
            supercaptiontag[6].ti_Data        = (ULONG) NewObjectA(LABEL_GetClass(), NULL, subcaptiontag);
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            leftlayouttag[theindex++].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, supercaptiontag);
            leftlayouttag[theindex].ti_Tag    = CHILD_WeightedHeight;
            leftlayouttag[theindex++].ti_Data = 0;
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            te_gadgets[GID_TEXTEDITOR1 + i]      = NewObjectA(TEXTEDITOR_GetClass(), NULL, texteditortag);
            leftlayouttag[theindex++].ti_Data = (ULONG) te_gadgets[GID_TEXTEDITOR1 + i];
        }
        leftlayouttag[theindex].ti_Tag        = TAG_END;

        rightlayouttag[0].ti_Tag  = LAYOUT_Orientation;
        rightlayouttag[0].ti_Data = LAYOUT_ORIENT_VERT;
        rightlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
        rightlayouttag[1].ti_Data = TRUE;
        rightlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
        rightlayouttag[2].ti_Data = TRUE;
        theindex = 3;
        for (i = (elements / 2) + 1; i <= elements; i++)
        {   subcaptiontag[0].ti_Data           = (ULONG) GadTitle[i];
            texteditortag[0].ti_Data           = GID_TEXTEDITOR1 + i;
            supercaptiontag[6].ti_Data         = (ULONG) NewObjectA(LABEL_GetClass(), NULL, subcaptiontag);
            rightlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            rightlayouttag[theindex++].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, supercaptiontag);
            rightlayouttag[theindex].ti_Tag    = CHILD_WeightedHeight;
            rightlayouttag[theindex++].ti_Data = 0;
            rightlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            te_gadgets[GID_TEXTEDITOR1 + i]       = NewObjectA(TEXTEDITOR_GetClass(), NULL, texteditortag);
            rightlayouttag[theindex++].ti_Data = (ULONG) te_gadgets[GID_TEXTEDITOR1 + i];
        }
        rightlayouttag[theindex].ti_Tag        = TAG_END;
    } else
    {   for (i = 0; i <= elements; i++)
        {   subcaptiontag[0].ti_Data          = (ULONG) GadTitle[i];
            texteditortag[0].ti_Data          = GID_TEXTEDITOR1 + i;
            supercaptiontag[6].ti_Data        = (ULONG) NewObjectA(LABEL_GetClass(), NULL, subcaptiontag);
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            leftlayouttag[theindex++].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, supercaptiontag);
            leftlayouttag[theindex].ti_Tag    = CHILD_WeightedHeight;
            leftlayouttag[theindex++].ti_Data = 0;
            leftlayouttag[theindex].ti_Tag    = LAYOUT_AddChild;
            te_gadgets[GID_TEXTEDITOR1 + i]      = NewObjectA(TEXTEDITOR_GetClass(), NULL, texteditortag);
            leftlayouttag[theindex++].ti_Data = (ULONG) te_gadgets[GID_TEXTEDITOR1 + i];
        }
        leftlayouttag[theindex].ti_Tag        = TAG_END;
    }

    /* The captions are as wide as required to hold the entire caption on
    one line. In many cases this means that `double-column' mode cannot be
    used, as the right column would be pushed out too far to the right,
    and partially offscreen. */

    bothlayouttag[0].ti_Tag  = LAYOUT_Orientation;
    bothlayouttag[0].ti_Data = LAYOUT_ORIENT_HORIZ;
    bothlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
    bothlayouttag[1].ti_Data = TRUE;
    bothlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
    bothlayouttag[2].ti_Data = TRUE;

    bothlayouttag[3].ti_Tag  = LAYOUT_AddChild;
    bothlayouttag[3].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, leftlayouttag);
    bothlayouttag[4].ti_Tag  = CHILD_WeightedWidth;
    bothlayouttag[4].ti_Data = 50;
    if (page == 41)
    {   bothlayouttag[5].ti_Tag  = LAYOUT_AddChild;
        bothlayouttag[5].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, rightlayouttag);
        bothlayouttag[6].ti_Tag  = CHILD_WeightedWidth;
        bothlayouttag[6].ti_Data = 50;
        bothlayouttag[7].ti_Tag  = TAG_END;
    } else
        bothlayouttag[5].ti_Tag  = TAG_END;

        rootlayouttag[0].ti_Tag  = LAYOUT_Orientation;
        rootlayouttag[0].ti_Data = LAYOUT_ORIENT_VERT;
        rootlayouttag[1].ti_Tag  = LAYOUT_SpaceOuter;
        rootlayouttag[1].ti_Data = TRUE;
        rootlayouttag[2].ti_Tag  = LAYOUT_DeferLayout;
        rootlayouttag[2].ti_Data = TRUE;
        rootlayouttag[3].ti_Tag  = LAYOUT_AddChild;
        rootlayouttag[3].ti_Data = (ULONG) NewObjectA(LAYOUT_GetClass(), NULL, bothlayouttag);
        rootlayouttag[4].ti_Tag  = LAYOUT_AddChild;
        rootlayouttag[4].ti_Data = (ULONG) NewObjectA(NULL, "button.gadget", buttontag);
        rootlayouttag[5].ti_Tag  = CHILD_WeightedHeight;
        rootlayouttag[5].ti_Data = 0;
        rootlayouttag[6].ti_Tag  = TAG_END;

        lockscreen();
        windowtag[0].ti_Tag   = WA_PubScreen;
        windowtag[0].ti_Data  = (ULONG) ScreenPtr;
        windowtag[1].ti_Tag   = WA_ScreenTitle;
        windowtag[1].ti_Data  = (ULONG) "Report+";
        windowtag[2].ti_Tag   = WA_Title;
        windowtag[2].ti_Data  = (ULONG) "Report+: Text Editor";
        windowtag[3].ti_Tag   = WA_Activate;
        windowtag[3].ti_Data  = TRUE;
        windowtag[4].ti_Tag   = WA_DepthGadget;
        windowtag[4].ti_Data  = TRUE;
        windowtag[5].ti_Tag   = WA_DragBar;
        windowtag[5].ti_Data  = TRUE;
        windowtag[6].ti_Tag   = WA_CloseGadget;
        windowtag[6].ti_Data  = TRUE;
        windowtag[7].ti_Tag   = WA_SizeGadget;
        windowtag[7].ti_Data  = TRUE;
        windowtag[8].ti_Tag   = WINDOW_AppPort;
        windowtag[8].ti_Data  = (ULONG) AppPort;
        windowtag[9].ti_Tag   = WINDOW_Position;
        windowtag[9].ti_Data  = WPOS_FULLSCREEN;
        windowtag[10].ti_Tag  = WINDOW_ParentGroup;
        te_gadgets[GID_MAIN]     = NewObjectA(LAYOUT_GetClass(), NULL, rootlayouttag);
        windowtag[10].ti_Data = (ULONG) te_gadgets[GID_MAIN];
        windowtag[11].ti_Tag  = TAG_END;

        TEWindowObject = NewObjectA(WINDOW_GetClass(), NULL, windowtag);
        unlockscreen();

        // Object creation successful?
        if (TEWindowObject)
        {   // Open the window.
            if (TEWindowPtr = (struct Window *) DoMethod(TEWindowObject, WM_OPEN, NULL))
            {   ULONG wait, signal, app = (1L << AppPort->mp_SigBit);
                ULONG result;
                UWORD code;

                done = FALSE;

                // Obtain the window wait signal mask.
                GetAttr(WINDOW_SigMask, TEWindowObject, &signal);

                // Do any necessary imports.
                if (page == 11)
                {   switch(report.type)
                    {
                    case BUG:
                        SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1],       TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[0]
                        ); // brief bug description
                        SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1 + 1],   TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[1]
                        ); // bug generation procedure or example
                        SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1 + 2],   TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[2]
                        ); // if this works differently...
                        SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1 + 3],   TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[3]
                        ); // related problems
                    break;
                    case COM:
                        if (report.severity == 0)
                        {   SetGadgetAttrs
                            (   te_gadgets[GID_TEXTEDITOR1],   TEWindowPtr, NULL,
                                GA_TEXTEDITOR_Contents,     report.textfield[2]
                            ); // if this works differently...
                        } else
                        {   for (i = 0; i <= 4; i++)
                            {   SetGadgetAttrs
                                (   te_gadgets[GID_TEXTEDITOR1 + i], TEWindowPtr, NULL,
                                    GA_TEXTEDITOR_Contents,       report.textfield[i]
                                );
                        }   }
                        /* brief bug description
                           bug generation procedure or example
                           if this works differently...
                           what developer is doing...
                           related problems */
                    break;
                    case ENH:
                        SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1],       TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,         report.textfield[5]
                        ); // enhancement request
                    break;
                    default:
                        ; // assert(0);
                    break;
                }   }
                else
                {   // assert(page == 41);
                    /* Autodoc text fields are as follows:
                     0 Function
                     1 Example
                     2 Notes
                     3 Bugs
                     4 See also
                     5 Result   (mirrors autodoc.var[0].desc)
                  6-13 Inputs   (

                    Whereas the te_gadgets go Function, inputs, Result, others

                    */

                    SetGadgetAttrs
                    (   te_gadgets[GID_TEXTEDITOR1],       TEWindowPtr, NULL,
                        GA_TEXTEDITOR_Contents,         autodoc.textfield[0]
                    );

                    if (inputs)
                    {   for (i = 1; i < inputs; i++)
                        {   SetGadgetAttrs
                            (   te_gadgets[GID_TEXTEDITOR1 + i], TEWindowPtr, NULL,
                                GA_TEXTEDITOR_Contents, autodoc.var[i].desc
                            );
                    }   }
                    if (returncode)
                    {   SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1 + inputs + 1], TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,     autodoc.var[0].desc
                        ); // return code
                    }
                    for (i = 1; i <= 4; i++)
                    {   SetGadgetAttrs
                        (   te_gadgets[GID_TEXTEDITOR1 + inputs + returncode + i], TEWindowPtr, NULL,
                            GA_TEXTEDITOR_Contents,     autodoc.textfield[i]
                        );
                }   }

                // Activate the first texteditor gadget.
                ActivateLayoutGadget(te_gadgets[GID_MAIN], TEWindowPtr, NULL, (Object) te_gadgets[GID_TEXTEDITOR1]);

                // Input Event Loop
                while (!done)
                {   wait = Wait( signal | SIGBREAKF_CTRL_C | app );

                    if ( wait & SIGBREAKF_CTRL_C )
                        done = TRUE;
                    else
                    {   while ( (result = RA_HandleInput(TEWindowObject, &code) ) != WMHI_LASTMSG )
                        {   switch (result & WMHI_CLASSMASK)
                            {
                            case WMHI_CLOSEWINDOW:
                                TEWindowPtr = NULL;
                                done = TRUE;
                            break;
                            case WMHI_GADGETUP:
                                switch (result & WMHI_GADGETMASK)
                                {
                                case GID_OK:
                                    done = TRUE;
                                break;
                                default:
                                break;
                                }
                            break;
                            default:
                            break;
            }   }   }   }   }

            for (i = 0; i <= elements; i++)
                textBuffer[i] = (STRPTR) DoGadgetMethod(te_gadgets[GID_TEXTEDITOR1 + i], TEWindowPtr, NULL, GM_TEXTEDITOR_ExportText, NULL);

            if (page == 11)
            {   switch(report.type)
                {
                case BUG:
                    strcpy(report.textfield[0], textBuffer[0]); // brief bug description
                    strcpy(report.textfield[1], textBuffer[1]); // bug generation procedure or example
                    strcpy(report.textfield[2], textBuffer[2]); // if this works differently...
                    strcpy(report.textfield[4], textBuffer[3]); // related problems
                break;
                case COM:
                    if (report.severity == 0)
                    {   strcpy(report.textfield[2], textBuffer[0]); // if this works differently...
                    } else
                    {   strcpy(report.textfield[0], textBuffer[0]); // brief bug description
                        strcpy(report.textfield[1], textBuffer[1]); // bug generation procedure or example
                        strcpy(report.textfield[2], textBuffer[2]); // if this works differently...
                        strcpy(report.textfield[3], textBuffer[3]); // what developer is doing...
                        strcpy(report.textfield[4], textBuffer[4]); // related problems
                    }
                break;
                case ENH:
                    strcpy(report.textfield[5], textBuffer[0]); // enhancement request
                break;
                default:
                    ; // assert(0);
                break;
            }   }
            else
            {   // assert(page == 41);
                strcpy(autodoc.textfield[0], textBuffer[0]); // function
                if (inputs)
                {   for (i = 1; i <= inputs; i++)
                    {   strcpy(autodoc.var[i].desc, textBuffer[i]);
                }   }
                if (returncode)
                {   strcpy(autodoc.var[0].desc, textBuffer[inputs + 1]);
                }
                for (i = 1; i <= 4; i++)
                {   strcpy(autodoc.textfield[i], textBuffer[inputs + returncode + i]);
                }

                /* Qty  Field type
                     1  Function field
                   0-8  Input # fields
                0 or 1  Return code field
                     1  Example field
                     1  Notes field
                     1  Bugs field
                     1  See also field */
            }

            for (i = 0; i <= elements; i++)
            {   FreeVec((APTR) textBuffer[i]);
                textBuffer[i] = NULL;
            }
    
            /* 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(TEWindowObject);
        } else rq("Report+: Can't create ReAction objects!");
        DeleteMsgPort(AppPort);
    } else rq("Report+: Can't create window message port!");

    return;
}

