/* --------------------- HyperCreate.c -------------------------- */

#include "hardware/blit.h"
#include "exec/execbase.h"
#include "intuition/intuitionbase.h"

#include "workbench/startup.h"
#include "workbench/workbench.h"

#include "exec/memory.h"
#include "exec/io.h"
#include <exec/ports.h>
#include "devices/printer.h"
#include <libraries/dosextens.h>

#include "functions.h"

#define UCHAR   unsigned char
#define USHORT  unsigned short
#define ULONG   unsigned long

#define BUFSIZE         4096L
#define HYPERWORDSIZE   17                /* max size of hyper word/phrase */

struct HTENTRY {                            /* hyper table entry structure */
    UCHAR   word[18];                             /* the hyper word/phrase */
    short   level;               /* Adam is level 0, children level 1, etc */
    ULONG   offset;         /* byte offset of this hyper word sect in file */
    USHORT  parent;                /* parent hyper word of this hyper word */
    USHORT  child;                                    /* child of this one */
    USHORT  nextSibling;               /* next sibling of this one, if any */
    USHORT  lastSibling;                           /* last sibling, if any */
};

long            bufindex,bufsize,offset;
long            entries;
struct HTENTRY  *table;
UCHAR           *fdf,*fdt;
UCHAR           *tablename,*filename;
ULONG           filesize,tablesize;
ULONG           errorline;
UCHAR           word[18],buffer[BUFSIZE];

USHORT          findparent();

main(argc,argv)
int     argc;
UCHAR   **argv;
{
long j;

    table = NULL;
    fdf = NULL;
    fdt = NULL;

    if (argc<3) {
        puts("  Uedit HyperCreate (C) 1989 Rick Stiles.  All rights reserved.");
        puts("      Creates a lookup table for a valid hyper text file.");
        puts("      See doc for formatting of hyper text files.");
        puts(" ");
        puts("      Usage:  UHC  HyperTextFile HyperTableFile");
        exit(0);
    }
    filename = argv[1];
    tablename = argv[2];

    fdf = (UCHAR *)Open(filename,(long)MODE_OLDFILE);
    if (fdf==NULL) {
        puts("Can't open hyper text file");
        quit(10);
    }

    fdt = (UCHAR *)Open(tablename,(long)MODE_NEWFILE);
    if (fdt==NULL) {
        puts("Can't create table file");
        quit(10);
    }

    /* get the size of the hyper text file */
    tablesize = bufindex = offset = entries = 0L;
    bufsize = Read((BPTR)fdf,buffer,BUFSIZE);
    while (nextsection(&j)) {
            entries++;
            printf(" Hyper Words:  %5ld\r",entries);
            tablesize += sizeof(struct HTENTRY);
    }
    printf(" Hyper Words:  %5ld\n",entries);
    
    filesize = Seek((BPTR)fdf,0L,(long)OFFSET_END);
    table = (struct HTENTRY *)AllocMem(tablesize,(long)MEMF_CLEAR);
    if (table==NULL) {
        puts("Can't allocate memory for table");
        quit(10);
    }

    if (Write((BPTR)fdt,&tablesize,4L)!=4L || Write((BPTR)fdt,&filesize,4L)!=4L) {
        puts("Error writing to table file");
        quit(10);
    }

    bufindex = offset = entries = 0L;
    Seek((BPTR)fdf,0L,(long)OFFSET_BEGINNING);
    bufsize = Read((BPTR)fdf,buffer,BUFSIZE);
    errorline = 1L;
    while (hyperentry()) printf(" %17s\r",word);
    printf(" %17s\n","finished          ");

    if (entries==0L) {
        puts("No hyper words (sections) to process.");
        puts("Put a formfeed before each section.");
        quit(10);
    }
    if (Write((BPTR)fdt,table,tablesize)!=tablesize) {
        puts("Error writing lookup table");
        quit(10);
    }
    quit(0);
}


linemsg()
{
    printf("Line %ld:  ",errorline);
}


quit(flag)
short   flag;
{
        if (fdf) Close((BPTR)fdf);
        if (fdt) Close((BPTR)fdt);
        if (flag) DeleteFile(tablename);
        if (table) FreeMem(table,tablesize);
        exit(flag);
}


nextsection(j)
long        *j;
{
register short  ch;

    while (1) {                                  /* find the next formfeed */
        ch = nextchar();
        if (ch==0) return(FALSE);
        if (ch==12) {
            *j = offset - 1L;
            return(TRUE);
        }
    }
}


nextchar()
{
register short ch;

    if (bufindex>=bufsize) {
        bufsize = Read((BPTR)fdf,buffer,BUFSIZE);
        bufindex = 0L;
        if (bufsize<=0L) return(0);
    }
    ch = buffer[bufindex];
    if (ch==10 || ch==12) errorline++;
    bufindex++;
    offset++;
    return(ch);
}


hyperword(x)
register UCHAR   *x;
{
register short i,ch;

    *x = 0x00;
    ch = nextchar();                                   /* just before '<' */
    if (ch!='<' || ch==0) return(FALSE);
    ch = nextchar();
    i = 0;
    while (ch!='>') {
        *(x++) = ch;
        ch = nextchar();
        if (++i>=17) break;
    }
    *x = 0x00;
    while (ch!='>') ch = nextchar();
    while (ch!=10) ch = nextchar();
    return(TRUE);
}


hyperentry()
{
struct HTENTRY  *p,*t;
long            j;
short           level;
USHORT          pindex,windex,child;
UCHAR           ch,lastch;
UCHAR           parent[18];

    if (!nextsection(&j)) return(FALSE);
                            /* cursor now on char AFTER formfeed */
    if (entries>65535L) {
        linemsg();
        puts("Too many hyper words (sections) - max allowed is 65535");
        quit(10);
    }
    parent[0] = 0x00;
    if (entries==0) {
        ch = nextchar();    /* cursor now AFTER empty parent line eol */
        while (ch!=10) ch = nextchar();
    } else if (!hyperword(parent)) {
        linemsg();
        puts("Missing Parent Line hyper word");
        quit(10);
    }

    if (!hyperword(word)) {
        linemsg();
        puts("Missing Word Line hyper word");
        quit(10);
    }

    toLower(parent);
    toLower(word);

    /* find the parent index & make a ptr to its entry */
    pindex = 0;                                         /* find the parent */
    if (*parent) pindex = findparent(parent,word);
    p = table + pindex;                           /* ptr to parent's entry */

    /* make a ptr to the new entry & update the fields in the new entry */
    t = table + entries;
    strcpy(t->word,word);                /* the new hyper word, <=17 bytes */
    if (*parent) t->level = p->level + 1;              /* parent level + 1 */
    else t->level = 0;              /* first entry, level 0, has no parent */
    t->offset = j;
    t->parent = pindex;                 /* is 0 if this is the first entry */

    /* if this isn't the first entry, take care of sibling links */
    if (entries) {
        if (p->child!=0) {
            /* find last sibling & link to it */
            child = p->child;
            while (1) {
                t = table + child;
                if (t->nextSibling==0) {
                    t->nextSibling = entries;
                    t = table + entries;
                    t->lastSibling = child;
                    break;
                }
                child = t->nextSibling;
            }
        } else p->child = entries;
    }
    entries++;
    return(TRUE);
}


USHORT findparent(parent,word)
UCHAR           *parent;
register UCHAR  *word;
{
register struct HTENTRY  *t;
register USHORT          pindex;
register short           minlevel;

    if (strcmp(word,parent)==0) {
        linemsg();
        printf("Child can't use same name as parent:  %s\n",word);
        quit(10);
    }
    pindex = entries - 1;               /* highest existing index in table */
    t = table + pindex;                                /* last table entry */
    minlevel = t->level;
    while (1) {
        if (t->level<=minlevel) {
            minlevel = t->level;
            if (strcmp(t->word,parent)==0) return(pindex);
        }
        if (pindex-- == 0) break;
        t = table + pindex;
    }
    linemsg();
    printf("Can't find parent of:  %s\n",word);
    quit(10);
}


toLower(x)
register UCHAR *x;
{
    while (*x) {
        if (*x>='A' && *x<='Z') *x |= 32;
        x++;
    }
}
