/********************************************/
/*   ShowFont 3.2 - by Arthur Johnson Jr.   */
/* ======================================== */
/* Usage: ShowFont [font_name] [font_size]  */
/* ======================================== */
/*      Last modifications - 12/20/88       */
/********************************************/

#include "intuition/intuition.h" /* this one includes heaps o' stuff */
#include "exec/memory.h"
#include "libraries/diskfont.h"

#define XAREA       20      /* no characters beyond (screenwidth - XAREA) */
#define FONTBUFFER  5000    /* hopefully enough for most people */
#define FONTNAMELEN 30      /* maximum font name length */
#define MAXFLAGS    9       /* total of nine style flags so far */

#define MAXDISPLAY  7       /* max names, sizes, and styles to display */
#define NAMELEN     13      /* maximum chars of name displayed */
#define NAMEXPOS    13
#define SIZEXPOS    145
#define STYLXPOS    197
#define TOPYPOS     7

#define BASELINE    6   /* for Topaz-8 font */
#define YINCR       8

/* these are short little macro expanders to save me some typing effort */
#define SIZES       fonts[namesel].sizes
#define SIZESEL     fonts[namesel].sizesel
#define STYLES      fonts[namesel].size[SIZESEL].styles
#define STYLE       fonts[namesel].size[SIZESEL].style
#define STYLESEL    fonts[namesel].size[SIZESEL].stylesel

extern struct NewScreen newscreen;
extern struct Gadget W_Prop;
extern struct Menu Menu1;
extern struct NewWindow newwindow;
extern struct Requester requester1;
extern struct Requester requester2;
extern struct PropInfo W_PropSInfo;
extern struct PropInfo R_FontSInfo;
extern struct PropInfo R_SizeSInfo;
extern struct PropInfo R_StyleSInfo;
extern struct Gadget R_Font;
extern struct Gadget R_Size;
extern struct Gadget R_Style;
extern struct Border Outline1;

struct Screen *screen;
struct Window *window;
struct RastPort *rp;
struct Gadget *whichgad;
struct IntuiMessage *message;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct DiskfontBase *DiskfontBase;

struct sizenode {
    UWORD ysize;
    int   styles;
    UBYTE style[MAXFLAGS];
    UBYTE flags;
    int   stylesel;
};

struct tempsizenode {
    UWORD ysize;
    int   styles;
    UBYTE style[MAXFLAGS];
    UBYTE flags;
    struct tempsizenode *prev;
    struct tempsizenode *next;
};

struct fontinfo {
    char    name[FONTNAMELEN + 1];
    int     sizes;
    struct  sizenode *size;
    int     sizesel;
};
struct fontinfo *fonts;

struct tempfontinfo {
    char    name[FONTNAMELEN + 1];
    int     sizes;
    struct  tempsizenode *size;
    struct  tempfontinfo *prev;
    struct  tempfontinfo *next;
};
struct tempfontinfo *tempfonts;

char fontname[FONTNAMELEN + 6]; /* include space for '.font\0' */
struct TextAttr myfont = { /* necessary structure for fonts */
    &fontname[0],   /* default is Topaz-8 fault */
    8,
    FS_NORMAL,
    FPF_ROMFONT };
struct TextFont *font;

struct {
    UBYTE *string;
    int length;
} fontline[256];    /* maximum of 256 lines (one char/line) */

/* I just don't want to pass the following values around */

int numfonts;

int screenwidth, screenheight;

int nameline, sizeline, styleline,
    namesel,
    rfontlastline, rsizelastline, rstylelastline;

USHORT fontpropsize, fontproppos, sizepropsize, sizeproppos,
        stylepropsize, styleproppos;

void clearfonts()
{

    register i;

    for (i = 0; i < numfonts; i++)
        FreeMem(fonts[i].size, fonts[i].sizes * sizeof(struct sizenode));
    FreeMem(fonts, numfonts * sizeof(struct fontinfo));

    numfonts = 0;   /* there are no fonts */

}

void clearfontlines()
{

    register i = 0;

    while (fontline[i].length != 0) {
        FreeMem(fontline[i].string, fontline[i].length);
        fontline[i].length = 0;
        ++i;
    }

}

void cleanup(text)
char *text;
{

    clearfontlines();
    clearfonts();
    if (font)
        CloseFont(font);
    if (window) {
        ClearMenuStrip(window);
        CloseWindow(window);
    }
    if (screen)
        CloseScreen(screen);
    if (DiskfontBase)
        CloseLibrary(DiskfontBase);
    if (IntuitionBase)
        CloseLibrary(IntuitionBase);
    if (GfxBase)
        CloseLibrary(GfxBase);

    if (text)
        puts(text);

    exit(0);

}

void cleartempsize(font)
struct tempfontinfo *font;
{

    struct tempsizenode *erase;

    while (font->size != NULL) {
        erase = font->size;
        font->size = font->size->next;
        FreeMem(erase, sizeof(struct tempsizenode));
    }

}

void cleartempfonts()
{

    struct tempfontinfo *erase;

    while (tempfonts != NULL) {
        erase = tempfonts;
        tempfonts = tempfonts->next;
        cleartempsize(erase);
        FreeMem(erase, sizeof(struct tempfontinfo));
    }

}

int stylenum(style)
UBYTE style;
{

    if (style == FS_NORMAL)
        return(0);
    if (style & FSF_UNDERLINED)
        return(1);
    if (style & FSF_BOLD)
        return(2);
    if (style & FSF_ITALIC)
        return(4);
    if (style & FSF_EXTENDED)
        return(8);

}

void addsizenode(font, ysize, style, flags)
struct tempfontinfo *font;
UWORD ysize;
UBYTE style;
UBYTE flags;
{

    struct tempsizenode *search, *prev, *newnode;

    int foundit = FALSE;

    prev = NULL;
    search = font->size;
    while (search != NULL) {
        if ((search->ysize == ysize) && (search->flags == flags)) {
            search->style[search->styles] = stylenum(style);
            ++(search->styles);
            foundit = TRUE;
            break;
        }
        else {
            if (search->ysize >= ysize) /* should go before this size */
                break;
            else {
                prev = search;
                search = search->next;
            }
        }
    }
    if (!foundit) {
        newnode = (struct tempsizenode *)AllocMem(sizeof(struct tempsizenode), MEMF_CLEAR);
        if (newnode == NULL)
            cleanup("ShowFont: couldn't allocate enough memory!");
        newnode->ysize = ysize;
        newnode->styles = 0;
        newnode->flags = flags;
        newnode->style[newnode->styles] = stylenum(style);
        ++(newnode->styles);
        ++(font->sizes);
        if (font->size == NULL) {   /* list is empty */
            newnode->prev = NULL;
            newnode->next = NULL;
            font->size = newnode;
        }
        else {
            if (search == NULL) {   /* add at end o' list */
                prev->next = newnode;
                newnode->prev = prev;
                newnode->next = NULL;
            }
            else {
                if (search->prev == NULL) { /* add at beginning o' list */
                    newnode->prev = NULL;
                    newnode->next = search;
                    search->prev = newnode;
                    font->size = newnode;
                }
                else {  /* add in the middle o' the list */
                    search->prev->next = newnode;
                    newnode->prev = search->prev;
                    newnode->next = search;
                    search->prev = newnode;
                }
            }
        }
    }

}

void readfonts()
{

    struct AvailFontsHeader *afh;
    struct AvailFonts *af;

    struct tempfontinfo *search, *prev, *newnode;
    struct tempsizenode *sizenode;

    int foundit;

    int mem = FONTBUFFER,
        moremem;

    register i, j, k;

    clearfonts();

    do {
        afh = (struct AvailFontsHeader *)AllocMem(mem, MEMF_CLEAR);
        if (afh == NULL)
            cleanup("ShowFont: couldn't allocate enough memory!");
        moremem = AvailFonts(afh, mem, 0xFF);
        if (moremem != 0) {
            FreeMem(afh, mem);
            mem += moremem;
            printf("ShowFont: allocating %d bytes of memory for the FONTS: info.\n", mem);
        }
    } while (moremem != 0);

    if (afh->afh_NumEntries == 0) {
        FreeMem(afh, mem);
        cleanup("ShowFont: couldn't find any fonts! (Is FONTS: set correctly?)");
    }

    tempfonts = NULL;

    af = (struct AvailFonts *)&afh[1];
    for (i = 0; i < afh->afh_NumEntries; i++) {
        if (!((af->af_Attr.ta_Flags & FPF_REMOVED) ||
            (af->af_Attr.ta_Flags & FPF_REVPATH) ||
            ((af->af_Type & AFF_MEMORY) &&
             (af->af_Attr.ta_Flags & FPF_DISKFONT)))) {

            prev = NULL;
            search = tempfonts;
            foundit = FALSE;
            while (search != NULL) {
                if (strnicmp(af->af_Attr.ta_Name, search->name, (strlen(af->af_Attr.ta_Name) - 5)) == NULL) {
                    addsizenode(search, af->af_Attr.ta_YSize, af->af_Attr.ta_Style, af->af_Attr.ta_Flags);
                    foundit = TRUE;
                    break;
                }
                else {
                    if (strnicmp(af->af_Attr.ta_Name, search->name, (strlen(af->af_Attr.ta_Name) - 5)) < NULL)
                        break;  /* should go before here */
                    else {
                        prev = search;
                        search = search->next;
                    }
                }
            }
            if (!foundit) {
                newnode = (struct tempfontinfo *)AllocMem(sizeof(struct tempfontinfo), MEMF_CLEAR);
                if (newnode == NULL)
                    cleanup("ShowFont: couldn't allocate enough memory!");
                stccpy(newnode->name, af->af_Attr.ta_Name, (strlen(af->af_Attr.ta_Name) - 4));
                newnode->sizes = 0;
                newnode->size = NULL;
                addsizenode(newnode, af->af_Attr.ta_YSize, af->af_Attr.ta_Style, af->af_Attr.ta_Flags);
                ++numfonts;
                if (tempfonts == NULL) { /* list is empty */
                    newnode->prev = NULL;
                    newnode->next = NULL;
                    tempfonts = newnode;
                }
                else {
                    if (search == NULL) {   /* should add at end */
                        prev->next = newnode;
                        newnode->prev = prev;
                        newnode->next = NULL;
                    }
                    else {
                        if (search->prev == NULL) { /* add at beginning */
                            newnode->prev = NULL;
                            newnode->next = search;
                            search->prev = newnode;
                            tempfonts = newnode;
                        }
                        else { /* add in the middle o' the list */
                            search->prev->next = newnode;
                            newnode->prev = search->prev;
                            newnode->next = search;
                            search->prev = newnode;
                        }
                    }
                }
            }
        }
        af++;
    }

    FreeMem(afh, mem);

    if ((fonts = (struct fontinfo *)AllocMem(numfonts * sizeof(struct fontinfo), MEMF_CLEAR)) == NULL)
        cleanup("ShowFont: couldn't allocate secondary memory!");

    search = tempfonts;

    for (i = 0; i < numfonts; i++) {
        strcpy(fonts[i].name, search->name);
        fonts[i].sizes = search->sizes;
        if ((fonts[i].size = (struct sizenode *)AllocMem(fonts[i].sizes * sizeof(struct sizenode), MEMF_CLEAR)) == NULL)
            cleanup("ShowFont: couldn't allocate tertiary memory!");
        sizenode = search->size;
        for (j = 0; j < fonts[i].sizes; j++) {
            fonts[i].size[j].ysize = sizenode->ysize;
            fonts[i].size[j].styles = sizenode->styles;
            for (k = 0; k < fonts[i].size[j].styles; k++)
                fonts[i].size[j].style[k] = sizenode->style[k];
            fonts[i].size[j].stylesel = 0;
            fonts[i].size[j].flags = sizenode->flags;
            sizenode = sizenode->next;
        }
        fonts[i].sizesel = 0;
        search = search->next;
    }

    cleartempfonts();

}

void setupscreen()
{

    if (window) {
        ClearMenuStrip(window);
        CloseWindow(window);
    }
    if (screen)
        CloseScreen(screen);

    newscreen.Width = screenwidth;
    newscreen.Height = screenheight;
    if (screenwidth == 320)
        if (screenheight == 200)
            newscreen.ViewModes = NULL;
        else
            newscreen.ViewModes = LACE;
    else
        if (screenheight == 200)
            newscreen.ViewModes = HIRES;
        else
            newscreen.ViewModes = HIRES | LACE;

    newwindow.Width = screenwidth;
    newwindow.Height = screenheight;

    if (screenwidth == 320) {
        requester1.LeftEdge = 0;
        requester2.LeftEdge = 56;
    }
    else {
        requester1.LeftEdge = 160;
        requester2.LeftEdge = 216;
    }

    if (screenheight == 200) {
        requester1.TopEdge = 50;
        requester2.TopEdge = 50;
    }
    else {
        requester1.TopEdge = 150;
        requester2.TopEdge = 150;
    }

    if ((screen = (struct Screen *)OpenScreen(&newscreen)) == NULL)
        cleanup("ShowFont: couldn't open the screen.");
    newwindow.Screen = screen;

    if ((window = (struct Window *)OpenWindow(&newwindow)) == NULL)
        cleanup("ShowFont: couldn't open the window.");
    rp = window->RPort;

    SetMenuStrip(window, &Menu1);

}

int findfont()
{

    int low, mid, high;

    low = 0;
    high = numfonts - 1;
    while (low <= high) {
        mid = (low + high) / 2;
        if (strnicmp(fontname, fonts[mid].name, (strlen(fontname) - 5)) < 0)
            high = mid - 1;
        else
            if (strnicmp(fontname, fonts[mid].name, (strlen(fontname) - 5)) > 0)
                low = mid + 1;
            else
                return(mid);
    }

    return(-1);

}

USHORT proppos(line, maxline)
int line;
int maxline;
{

    if (maxline == 1)
        return((USHORT)MAXBODY);
    else
        return((USHORT)((MAXBODY * (line - 1)) / (maxline - 1)));

}

USHORT propsize(display, maxdisplay)
int display;
int maxdisplay;
{

    if (display >= maxdisplay)
        return((USHORT)MAXPOT);
    else
        return((USHORT)((MAXPOT * display) / maxdisplay));

}

int propline(proppos, maxline)
USHORT proppos;
int maxline;
{

    return((proppos * maxline) / MAXPOT);

}

void refresh1(rp)
struct RastPort *rp;
{

    register loop,
             x = NAMEXPOS,
             y = TOPYPOS + BASELINE;

    char namestring[NAMELEN + 1];

    SetDrMd(rp, JAM2);
    SetAPen(rp, 1);

    for (loop = 0; loop < MAXDISPLAY; loop++) {
        Move(rp, x, y);
        SetBPen(rp, 0);
        if ((nameline + loop) < numfonts) {
            if ((nameline + loop) == namesel)
                SetBPen(rp, 2);
            sprintf(namestring, "%-13s", fonts[nameline + loop].name);
            Text(rp, namestring, NAMELEN);
        }
        else
            Text(rp, "             ", NAMELEN);
        y += YINCR;
    }

}

void refresh2(rp)
struct RastPort *rp;
{

    register loop,
             x = SIZEXPOS,
             y = TOPYPOS + BASELINE;

    char sizestring[3 + 1];

    SetDrMd(rp, JAM2);

    for (loop = 0; loop < MAXDISPLAY; loop++) {
        Move(rp, x, y);
        SetBPen(rp, 0);
        if ((sizeline + loop) < SIZES) {
            SetAPen(rp, 1);
            if (fonts[namesel].size[sizeline + loop].flags & FPF_PROPORTIONAL)
                SetAPen(rp, 3);
            if ((sizeline + loop) == SIZESEL)
                SetBPen(rp, 2);
            sprintf(sizestring, "%3d", fonts[namesel].size[sizeline + loop].ysize);
            Text(rp, sizestring, 3);
        }
        else
            Text(rp, "   ", 3);
        y += YINCR;
    }

}

void refresh3(rp)
struct RastPort *rp;
{

    register x = STYLXPOS,
             y = TOPYPOS + BASELINE,
             loop;

    SetDrMd(rp, JAM2);
    SetAPen(rp, 1);

    for (loop = 0; loop < MAXDISPLAY; loop++) {
        Move(rp, x, y);
        if ((loop + styleline) == STYLESEL)
            SetBPen(rp, 2);
        else
            SetBPen(rp, 0);
        if ((loop + styleline) < STYLES) {
            switch(STYLE[(loop + styleline)]) {
                case 0: Text(rp, "Normal      ", 12);
                        break;
                case 1: Text(rp, "Underlined  ", 12);
                        break;
                case 2: Text(rp, "Bold        ", 12);
                        break;
                case 4: Text(rp, "Italic      ", 12);
                        break;
                case 8: Text(rp, "Extended    ", 12);
                        break;
            }
        }
        else
            Text(rp, "            ", 12);
        y += YINCR;
    }

}

void updateprop(prop, requester, proppos, propsize)
struct Gadget *prop;
struct Requester *requester;
USHORT proppos;
USHORT propsize;
{

    NewModifyProp(prop, window, requester, AUTOKNOB | FREEVERT, -1, proppos, -1, propsize, 1);

}

/* updatetype =  1 : refresh 1      */
/*                   update 2, 3    */
/*                   refresh 2, 3   */
/*               2 : refresh 2      */
/*                   update 3       */
/*                   refresh 3      */
/*               3 : refresh 3      */
/*              10 : arrow 1, u/r 1 */
/*              20 : arrow 2, u/r 2 */
/*              30 : arrow 3, u/r 3 */
void duhprop(rp, updatetype)
struct RastPort *rp;
int updatetype;
{

    if (updatetype == 1) {
        rsizelastline = (SIZES - MAXDISPLAY) + 1;
        if (rsizelastline < 1)
            rsizelastline = 1;
        sizeline = SIZESEL;
        if ((sizeline + 1) >= rsizelastline)
            sizeline = rsizelastline - 1;
        sizepropsize = propsize(MAXDISPLAY, SIZES);
        sizeproppos = proppos((sizeline + 1), rsizelastline);
    }
    if (updatetype <= 3) {
        rstylelastline = (STYLES - MAXDISPLAY) + 1;
        if (rstylelastline < 1)
            rstylelastline = 1;
        styleline = STYLESEL;
        if ((styleline + 1) >= rstylelastline)
            styleline = rstylelastline - 1;
        stylepropsize = propsize(MAXDISPLAY, STYLES);
        styleproppos = proppos((styleline + 1), rstylelastline);
    }

    switch (updatetype) {
         case 10: fontproppos = proppos((nameline + 1), rfontlastline);
                  break;
         case 20: sizeproppos = proppos((sizeline + 1), rsizelastline);
                  break;
         case 30: styleproppos = proppos((styleline + 1), rstylelastline);
                  break;
    }

    switch (updatetype) {
        case  1: refresh1(rp);
                 updateprop(&R_Size, &requester1, sizeproppos, sizepropsize);
                 updateprop(&R_Style, &requester1, styleproppos, stylepropsize);
                 refresh2(rp);
                 refresh3(rp);
                 break;
        case  2: refresh2(rp);
                 updateprop(&R_Style, &requester1, styleproppos, stylepropsize);
                 refresh3(rp);
                 break;
        case  3: refresh3(rp);
                 break;
        case 10: updateprop(&R_Font, &requester1, fontproppos, fontpropsize);
                 refresh1(rp);
                 break;
        case 20: updateprop(&R_Size, &requester1, sizeproppos, sizepropsize);
                 refresh2(rp);
                 break;
        case 30: updateprop(&R_Style, &requester1, styleproppos, stylepropsize);
                 refresh3(rp);
                 break;
    }

}

int selectfont()
{

    struct RastPort *rp;

    int returnvalue,
        refreshhow,
        x, y;

    ULONG  class;

    Request(&requester1, window);
    rp = requester1.ReqLayer->rp;

    namesel = findfont();

    rfontlastline = numfonts - MAXDISPLAY + 1;
    if (rfontlastline < 1)
        rfontlastline = 1;
    fontpropsize = propsize(MAXDISPLAY, numfonts);

    nameline = namesel;
    if ((nameline + 1) >= rfontlastline)
        nameline = rfontlastline - 1;

    duhprop(rp, 1);
    duhprop(rp, 10);

    DrawBorder(rp, &Outline1, 0, 0);

    refreshhow = 0;
    returnvalue = 0;

    while (returnvalue == 0) {
        switch (refreshhow) {
            case  1: if (nameline > 0)
                         --nameline;
                     duhprop(rp, 10);
                     break;
            case  2: nameline = propline(R_FontSInfo.VertPot, rfontlastline);
                     if ((nameline + 1) >= rfontlastline)
                         nameline = rfontlastline - 1;
                     refresh1(rp);
                     break;
            case  3: if ((nameline + 1) < rfontlastline)
                         ++nameline;
                     duhprop(rp, 10);
                     break;
            case  4: if (sizeline > 0)
                         --sizeline;
                     duhprop(rp, 20);
                     break;
            case  5: sizeline = propline(R_SizeSInfo.VertPot, rsizelastline);
                     if ((sizeline + 1) >= rsizelastline)
                         sizeline = rsizelastline - 1;
                     refresh2(rp);
                     break;
            case  6: if ((sizeline + 1) < rsizelastline)
                         ++sizeline;
                     duhprop(rp, 20);
                     break;
            case  7: if (styleline > 0)
                         --styleline;
                     duhprop(rp, 30);
                     break;
            case  8: styleline = propline(R_StyleSInfo.VertPot, rstylelastline);
                     if ((styleline + 1) >= rstylelastline)
                         styleline = rstylelastline - 1;
                     refresh3(rp);
                     break;
            case  9: if ((styleline + 1) < rstylelastline)
                         ++styleline;
                     duhprop(rp, 30);
                     break;
        }

        message = (struct IntuiMessage *)GetMsg(window->UserPort);
        if (message != 0) {
            class = message->Class;
            x = message->MouseX - requester1.LeftEdge;
            y = message->MouseY - requester1.TopEdge;
            whichgad = (struct Gadget *)message->IAddress;
            ReplyMsg(message);

            if (class == GADGETDOWN) {
                refreshhow = whichgad->GadgetID;
            }
            if (class == GADGETUP) {
                switch (whichgad->GadgetID) {
                    case 101: returnvalue = 1;
                              break;
                    case 102: returnvalue = -1;
                              break;
                }
                refreshhow = 0; /* no more auto-scrolling */
            }
            if (class == MOUSEBUTTONS) {
                if ((y >= 0) && (y < 100) && (x >= 0) && (x < 320)) {
                    y -= TOPYPOS;
                    y = y / YINCR;
                    if (y < MAXDISPLAY) {
                        if ((x >= NAMEXPOS) && (x < (NAMEXPOS + NAMELEN * 8))) {
                            if (namesel == (nameline + y)) {
                                returnvalue = 1;
                                EndRequest(&requester1, window);
                            }
                            else {
                                namesel = nameline + y;
                                if (namesel >= numfonts)
                                    namesel = numfonts - 1;
                                duhprop(rp, 1);
                            }
                        }
                        if ((x >= SIZEXPOS) && (x < (SIZEXPOS + 3 * 8))) {
                            if (SIZESEL == (sizeline + y)) {
                                returnvalue = 1;
                                EndRequest(&requester1, window);
                            }
                            else {
                                SIZESEL = sizeline + y;
                                if (SIZESEL >= SIZES)
                                    SIZESEL = SIZES - 1;
                                duhprop(rp, 2);
                            }
                        }
                        if ((x >= STYLXPOS) && (x < (STYLXPOS + 12 * 8))) {
                            if (STYLESEL == (styleline + y)) {
                                returnvalue = 1;
                                EndRequest(&requester1, window);
                            }
                            else {
                                STYLESEL = styleline + y;
                                if (STYLESEL >= STYLES)
                                    STYLESEL = STYLES - 1;
                                duhprop(rp, 3);
                            }
                        }
                    }
                }
            }
        }
    }

    if (returnvalue == 1) {
        strcpy(fontname, fonts[namesel].name);
        strcat(fontname, ".font");
        myfont.ta_YSize = fonts[namesel].size[SIZESEL].ysize;
        myfont.ta_Style = STYLE[STYLESEL];
        myfont.ta_Flags = fonts[namesel].size[SIZESEL].flags;
    }

    return(returnvalue);

}

void mycat(s, c)
char *s;
char c;
{

    while (*s++ != '\0') {}
    *(s - 1) = c;
    *s = '\0';

}

void main(argc,argv)
int argc;
char *argv[];
{

    int cont = TRUE,
        rethinkfont = TRUE;

    ULONG   class;
    USHORT  code;

    int line, maxline,
        yarea,
        startchar,
        len, pixels,
        whichmenu, whichitem,
        wproplastline,
        refreshhow;

    char windowtitle[81];

    USHORT numy, pos, size;

    register loop, i;

    UBYTE textline[256];

    if ((argc == 2) && (*argv[1] == '?'))
        cleanup("Usage: ShowFont [font_name] [font_size]");

    if ((IntuitionBase = (struct IntuitionBase *)
            OpenLibrary("intuition.library", 0)) == NULL)
        cleanup("ShowFont: couldn't open 'intuition.library'.");

    if ((GfxBase = (struct GfxBase *)
            OpenLibrary("graphics.library", 0)) == NULL)
        cleanup("ShowFont: couldn't open 'graphics.library'.");

    if ((DiskfontBase = (struct DiskfontBase *)
            OpenLibrary("diskfont.library", 0)) == NULL)
        cleanup("ShowFont: couldn't open 'diskfont.library'.");

    screenwidth = 640;
    screenheight = 200;
    setupscreen();

    fonts = NULL;

    if (argc == 1)
        strcpy(fontname, "Topaz.font");
    else
        sprintf(fontname, "%s.font", argv[1]);
    if (argc < 3) {
        readfonts();
        selectfont();
    }
    else
        myfont.ta_YSize = atoi(argv[2]);

    for (i = 0; i < 256; ++i)
        fontline[i].length = 0;

    while (cont) {

        if (rethinkfont) {

            if (font)
                CloseFont(font);

            if ((font = (struct TextFont *)OpenDiskFont(&myfont)) == NULL)
                cleanup("ShowFont: couldn't find the font.");

            if (myfont.ta_YSize > screenheight) {
                screenheight = 400;
                setupscreen();
            }

            SetFont(rp, font);

            clearfontlines();

            startchar = font->tf_LoChar;
            line = 0;
            len = 0;

            for (loop = font->tf_LoChar; loop <= font->tf_HiChar; ++loop) {
                textline[len++] = loop;
                pixels = TextLength(rp, textline, len) + window->BorderLeft;
                if (pixels > (screenwidth - XAREA)) {
                    --len;
                    fontline[line].string = (UBYTE *)AllocMem(len, MEMF_CLEAR);
                    if (fontline[line].string == NULL)
                        cleanup("ShowFont: couldn't allocate enough memory!");
                    for (i = startchar; i < loop; ++i)
                        fontline[line].string[i - startchar] = i;
                    fontline[line].length = len;
                    startchar = loop;
                    ++line;
                    len = 0;
                    --loop; /* must go back and insert that character */
                }
                else
                    if (loop == font->tf_HiChar) {
                        fontline[line].string = (UBYTE *)AllocMem(len, MEMF_CLEAR);
                        if (fontline[line].string == NULL)
                            cleanup("ShowFont: couldn't allocate enough memory!");
                        for (i = startchar; i <= font->tf_HiChar; ++i)
                            fontline[line].string[i - startchar] = i;
                        fontline[line].length = len;
                        ++line;
                    }
            }

            maxline = line;
            line = 0;
            yarea = screenheight - (window->BorderTop + window->BorderBottom);
            numy = yarea / font->tf_YSize;

            wproplastline = (maxline - numy) + 1;
            if (wproplastline < 1)
                wproplastline = 1;

            size = propsize(numy, maxline);

            stccpy(windowtitle, fontname, (strlen(fontname) - 4));
            sprintf(windowtitle + strlen(windowtitle), " - %d", myfont.ta_YSize);
            SetWindowTitles(window, windowtitle, -1);

            rethinkfont = FALSE;
            refreshhow = 99;    /* refresh it once only */
        }

        switch (refreshhow) {
            case  1: if (line > 0)
                         --line;
                     break;
            case  2: pos = W_PropSInfo.VertPot;
                     line = propline(pos, wproplastline);
                     if ((line + 1) > wproplastline)
                         line = wproplastline - 1;
                     break;
            case  3: if ((line + 1) < wproplastline)
                         ++line;
                     break;
        }

        if (refreshhow != 0) {

            pos = proppos((line + 1), wproplastline);

            if (refreshhow != 2)    /* don't blink the slider */
                NewModifyProp(&W_Prop, window, NULL, AUTOKNOB | FREEVERT, -1, pos, -1, size, 1);

            WaitTOF();  /* might just possibly reduce blinking */
            SetAPen(rp, 0); /* clear the screen */
            RectFill(rp, window->BorderLeft, window->BorderTop, (screenwidth - XAREA), (screenheight - window->BorderBottom));

            SetAPen(rp, 1);
            SetBPen(rp, 0);
            SetDrMd(rp, JAM2);

            for (i = line; i < (line + numy); ++i) {
                Move(rp, window->BorderLeft, ((i - line) * font->tf_YSize) + window->BorderTop + font->tf_Baseline);
                Text(rp, fontline[i].string, fontline[i].length);
            }

            if (refreshhow == 99)
                refreshhow = 0; /* for initial refreshment only */
        }

        message = (struct IntuiMessage *)GetMsg(window->UserPort);
        if (message != 0) {
            class = message->Class;
            code  = message->Code;
            whichgad = (struct Gadget *)message->IAddress;
            ReplyMsg(message);

            if (class == CLOSEWINDOW)
                cont = FALSE;
            if (class == GADGETDOWN)
                refreshhow = whichgad->GadgetID;
            if (class == GADGETUP)
                refreshhow = 0; /* stop scrolling */
            if (class == MENUPICK) {
                if (code != MENUNULL) {
                    whichmenu = MENUNUM(code);
                    whichitem = ITEMNUM(code);
                    switch (whichmenu) {
                        case 0 : switch (whichitem) {
                                    case 0: Request(&requester2, window); /* about */
                                            break;
                                    case 1: cont = FALSE; /* quit */
                                            break;
                                 }
                                 break;
                        case 1 : switch (whichitem) {
                                    case 0: if (fonts == NULL)
                                                readfonts();
                                            if (selectfont() == 1)
                                                rethinkfont = TRUE;
                                            break; /* font selection */
                                 }
                                 break;
                        case 2 : switch (whichitem) {
                                    case 0: screenwidth = 320;
                                            screenheight = 200;
                                            setupscreen();
                                            break;
                                    case 1: screenwidth = 320;
                                            screenheight = 400;
                                            setupscreen();
                                            break;
                                    case 2: screenwidth = 640;
                                            screenheight = 200;
                                            setupscreen();
                                            break;
                                    case 3: screenwidth = 640;
                                            screenheight = 400;
                                            setupscreen();
                                            break;
                                 }
                                 rethinkfont = TRUE;
                                 break;
                    }
                }
            }
        }
    }

    cleanup(NULL);

}
