/*******************  parse.c  *******************
 *                                               *
 *                                               *
 *                     hyper                     *
 *                                               *
 *                  © by Koessi                  *
 *                                               *
 *              Sunday, 23 Aug 1992              *
 *                                               *
 *                                               *
 *************************************************/

/*  #define DEBUG 1 */

#include  "defs.h"
#ifdef DEBUG
Prototype void   mydebug(void);
#endif

#define TABSIZE 8

Prototype int    ParseDoc(void);

Prototype struct Remember *remkey;
Prototype struct List     *hlp_nodelist;
Prototype struct mynode   *hlp_node;

Prototype char  *database;
Prototype char  *master;


struct Remember *remkey       = NULL;
struct List     *hlp_nodelist = NULL;
struct mynode   *hlp_node     = NULL;

char  *database = NULL;
char  *master   = NULL;

/*************************************************
 *                                               *
 *                                               *
 *    FUNCTION: ParseDoc                         *
 *                                               *
 *                                               *
 *    INPUT:    char *doc                        *
 *                                               *
 *    OUTPUT:   int                              *
 *                                               *
 *    NOTE:                                      *
 *                                               *
 *************************************************/

int
ParseDoc(void)
{
  char  *ptr, *buf, *str, *lineptr, *string, **txtline;
  int   len, state = STATE_NEWLINE, linum = 0L;
  short xs = 0, xe = 0;

  struct mynode   *mn;
  struct linkgad  *lg;
  struct List     *list;
  {
    struct FileInfoBlock *fib;
    if ((fib = (char **)AllocVec(sizeof(struct FileInfoBlock), MPC)) == NULL)
    {
      cleanup();
      exit(103);
    }

    ExamineFH(DocFile, fib);
    len = fib->fib_Size;
    FreeVec(fib);
    Read(DocFile, datastr, 9);

    if (stricmp( datastr, str_database) != 0)    /*  no hyperdocname ! */
    {
      DoRequest(str_errornohyperdoc, str_resume, docname);
      cleanup();
      exit(20);
    }
    Seek(DocFile, 0, OFFSET_BEGINNING);
  }

  if (remkey)
  {
    FreeRemember(&remkey, TRUE);
    remkey = NULL;
  }

  if ((list = (char **)AllocRemember(&remkey, sizeof(struct List), MPC)) == NULL)
  {
    cleanup();
    exit(103);
  }
  list->lh_Head     = (struct Node *)&list->lh_Tail;
  list->lh_Tail     = NULL;
  list->lh_TailPred = (struct Node *)&list->lh_Head;

  hlp_nodelist = list;            /*  backup */

  if ((str = (char **)AllocRemember(&remkey, 128, MPC)) == NULL)
  {
    cleanup();
    exit(103);
  }

  string = str;                   /*  backup */

  if ((buf = AllocRemember(&remkey, len, MPC)) == NULL)
  {
    cleanup();
    exit(103);
  }

  if (Read(DocFile, buf, len) != len)
  {
    char *buf = charbuffer;
    Fault(IoErr(), str_errorread, buf, 64);
    if (hlp_win)
      DoRequest(buf, str_resume, docname);
    else
      Printf(buf, (int)docname);
    cleanup();
    exit(10);
  }


  lineptr = buf;      /*  backup */
  ptr     = buf;      /*  backup */

  for (int l = len; l; --l)
  {
    if (*ptr++ == '\n')
      ++linum;
  }

#ifdef DEBUG
    Printf("linum: %ld\n", linum);
#endif

  if ((txtline = (char **)AllocRemember(&remkey, linum << 2, MPC)) == NULL)
  {
    cleanup();
    exit(103);
  }

  linum = 0;

  ptr  =      buf;      /*  backup */
  len += (int)buf;


  while ((int)buf < len)
  {
    switch (state)
    {
    case STATE_NEWLINE:
      if (*buf == '\n')
        if ((int)++buf >= len)        /*  skip \n */
          break;


      if (*buf == '@')
      {
        if ((int)++buf >= len)
          break;

        switch ((BYTE)*buf)
        {
        case 'n':     /*  node/next found */
        case 'N':     /*  node/next found */
          switch ((BYTE)*(buf + 1))
          {
          case 'o':     /*  node found */
          case 'O':     /*  node found */
            state = STATE_NODE;
            break;
          case 'e':     /*  next found */
          case 'E':     /*  next found */
            state = STATE_NEXT;
          defaut:
            break;
          }
          break;

        case 'p':     /*  prevnode */
        case 'P':     /*  prevnode */
          state = STATE_PREV;
          break;

        case 'e':     /*  endnode */
        case 'E':     /*  endnode */
          state = STATE_ENDNODE;
          break;

        case '{':     /*  linknode */
          state = STATE_LINKNODE;
          break;

        case '#':     /*  comment found  */
          state = STATE_COMMENT;
          break;

        case 't':     /*  tableofcontents found  */
        case 'T':     /*  tableofcontents found  */
          state = STATE_TOC;
          break;

        case 'h':     /*  height found  */
        case 'H':     /*  height found  */
          state = STATE_HEIGHT;
          break;

        case 'w':     /*  widthnode */
        case 'W':     /*  widthnode */
          state = STATE_WIDTH;
          break;

        case 'm':     /*  masternode */
        case 'M':     /*  masternode */
          state = STATE_MASTER;
          break;

        case 'd':     /*  database found */
        case 'D':     /*  database found */
          state = STATE_DATABASE;
          break;

        default:
          --buf;
          state = STATE_TXTLINE;
          break;
        }
      }
      else
      {
        if (*buf == '#')
        {
          if ((int)++buf >= len)
            break;

          if (*buf == '#')
          {
            state = STATE_COMMENT;
            break;
          }
          else
            --buf;
        }
        state = STATE_TXTLINE;
      }
      break;

    case STATE_LINKINLINE:          /*  link in txtline ? */
      if ((int)++buf >= len)
        break;

      switch ((BYTE)*buf)
      {
      case '{':     /*  linknode */
        state = STATE_LINKNODE;
        break;

      default:
        --buf;
        state = STATE_TXTLINE1;
        break;
      }
      break;

    case STATE_TXTLINE:
      state = STATE_NEWLINE;
    case STATE_TXTLINE1:

      while (*buf != '\n')
      {
        if (*buf == '@' && state == STATE_NEWLINE)
        {                             /*  not yet returned from newline2 */
          state = STATE_LINKINLINE;
          break;
        }
        if (*buf == '\t')
        {
          int tab;
          tab   = xs + TABSIZE;
          tab >>= 3;
          tab <<= 3;
          tab  -= xs;
          if (((int)buf - (int)ptr) > tab)
          {
            xs += tab;
            while (tab--)
              *ptr++ = ' ';
          }
          else
          {
            *ptr++ = ' ';
            ++xs;
          }
          ++buf;
        }
        else
        {
          *ptr++ = *buf++;
          ++xs;
        }
        if ((int)buf >= len)
        {
          state = STATE_NEWLINE;
          break;
        }
      }
      if (state == STATE_LINKINLINE)    /*  linkgad found ? */
        break;

      state = STATE_NEWLINE;

      xs  = 0;                        /*  reset charcounter */
      ++linum;                        /*  one more  */

      if ((int)ptr > (int)lineptr)    /*  not only empty line */
      {
        *ptr++     = '\0';            /*  mark eos  */
#ifdef DEBUG
          Printf("%s\n", lineptr);
#endif
        *txtline++ = lineptr;         /*  char ** */
        lineptr    = ptr;             /*  next start of line */
      }
      else
      {
#ifdef DEBUG
          PutStr("\n");
#endif
        *txtline++ = NULL;
      }
      break;

    case STATE_NODE:
      str = string;
      while (*buf++ != ' ');       /*  skip 'node ' */

      char pat = '"';
      if (*buf == pat)
        ++buf;
      else
        pat = ' ';

      while (*buf != pat && *buf != '\n')
      {
        *str++ = toupper(*buf);
        buf++;                    /*  get nodename  */
      }
      *str = '\0';                /*  mark eos  */
      str  = string;

      if (mn = (struct mynode *)AllocRemember(&remkey, sizeof(struct mynode), MPC))
      {
        char *d;
        if (d = (char *)AllocRemember(&remkey, strlen(str) + 1, MPC))
        {
          mn->mn_node.ln_Name = d;
          while (*d++ = *str++);  /*  copy nodename  */

          list              = &(mn->mn_linkgads);     /*  newlist */
          list->lh_Head     = (struct Node *)&list->lh_Tail;
          list->lh_Tail     = NULL;
          list->lh_TailPred = (struct Node *)&list->lh_Head;

          mn->mn_txtline    = txtline;
          linum = 0;                /*  reset linecounter */

          if (*buf == '\n')           /*  no headline  ? */
          {
            state = STATE_NEWLINE;
            break;
          }

          while (*buf == ' ' || *buf == '"' || *buf == '\t')
            ++buf;

          while (*buf != '"' && *buf != '\n') /*  copy headline */
            *ptr++ = *buf++;

          if ((int)ptr > (int)lineptr)  /*  not only empty line */
          {
            *ptr++          = '\0';     /*  mark eos  */
            *txtline++      = lineptr;  /*  char ** */
            lineptr         = ptr;      /*  next start of line */
            mn->mn_headline = TRUE;
          }

          state = (*buf == '\n') ? STATE_NEWLINE : STATE_COMMENT;
          break;
        }
      }
      cleanup();
      exit(103);


    case STATE_LINKNODE:
      str = string;

      char pat = '"';
      while (*buf++ != pat);      /*  start at '{'  */

      xe  = xs;                   /*  start counting chars */
      *ptr++ = (BYTE)'\x9B';

      while (*buf != pat)         /*  until '"' */
      {
        *ptr = *buf;              /*  copy gadname */
        ptr++; buf++; ++xe;       /*  count on */
      }

      *ptr++ = (BYTE)'\x9B';

      while (*buf != 'k' && *buf != 'K')      /*  skip 'lin' */
        ++buf;

      ++buf;                                  /*  skip 'k' */

      while (*buf == ' ' || *buf == '\t')     /*  skip ' ' */
        ++buf;


      if (*buf == pat)
        ++buf;
      else
        pat = '}';

      while (*buf != pat)         /*  get linknodename */
      {
        *str++ = toupper(*buf);
        buf++;
      }
      if (pat == '"')             /*  skip '"}'  */
      {
        pat = '}';
        while (*buf != pat)
          ++buf;
      }
      ++buf;

      *str-- = '\0';              /*  mark eos  */
      while(*str == ' ' || *str == '\t')  /*  trunc spaces  */
        *str-- = '\0';

      str = string;               /*  goto start of string  */
      while(*str == ' ')          /*  skip  spaces  */
        ++str;

      if (lg = (struct linkgad *)AllocRemember(&remkey, sizeof(struct linkgad), MPC))
      {
        char *d;
        if (d = (char *)AllocRemember(&remkey, strlen(str) + 1, MPC))
        {
          lg->lg_linknode = d;
          while (*d = *str)
          {                     /*  copy linknodename */
            ++d; ++str;
          }

          lg->lg_line = linum;
          lg->lg_xs   = xs;         /*  start of linkgad */
          lg->lg_xe   = xs = xe;    /*  end   of linkgad & counter reset */

          AddTail(list, lg);        /*  add linkgad */
          state = STATE_TXTLINE;
          break;
        }
      }
      cleanup();
      exit(103);

    case STATE_ENDNODE:
#ifdef DEBUG

        Printf(   "----------------------------\n"
                  "Node  : %s\n", mn->mn_node.ln_Name);
        if (mn->mn_headline)
          Printf( "Head  : %s\n", *(mn->mn_txtline));

        Printf(   "lines : %ld\n", linum);

#endif

      mn->mn_linum = linum;       /*  how many lines in that node */
      AddTail(hlp_nodelist, mn);  /*  add node */

      while ((int)buf < len)
      {
        if (*buf == '@')
        {
          state = STATE_NODE;
          break;
        }
        ++buf;
      }
      break;

    case STATE_DATABASE:
    case STATE_MASTER:
    case STATE_PREV:
    case STATE_NEXT:
    case STATE_TOC:
      str = string;
      while (*buf++ != ' ');       /*  skip 'xxx ' */

      char pat = '"';
      if (*buf == pat)
        ++buf;
      else
        pat = ' ';

      while (*buf != pat && *buf != '\n')
      {
        *str++ = toupper(*buf);
        buf++;                    /*  get nodename  */
      }
      *str = '\0';                /*  mark eos  */

      char *d;
      if (d = (char *)AllocRemember(&remkey, strlen(str = string) + 1, MPC))
      {
        switch (state)
        {
        case STATE_DATABASE:
          database = d;
          break;
        case STATE_MASTER:
          master   = d;
          break;
        case STATE_PREV:
          mn->mn_prev     = d;
          mn->mn_hasprev  = TRUE;
          break;
        case STATE_NEXT:
          mn->mn_next     = d;
          mn->mn_hasnext  = TRUE;
          break;
        case STATE_TOC:
          mn->mn_toc      = d;
          mn->mn_hastoc   = TRUE;
        default:
          break;
        }
        while (*d = *str)
        {                     /*  copy name */
          ++d; ++str;
        }
        state = (*buf == '\n') ? STATE_NEWLINE : STATE_COMMENT;
        break;
      }
      cleanup();
      exit(103);

    case STATE_COMMENT:           /*  skip rest of line */
    default:
      while (*buf != '\n' && (int)++buf < len);
      state = STATE_NEWLINE;
      break;
    }
  }
/*  #define DEBUG 1 */
#ifdef DEBUG

  Printf("rest of buf: %ld\n", len - (int)ptr);
  mydebug();

#endif
  Close(DocFile);
  DocFile = NULL;

  return(TRUE);
}

/*  #define DEBUG 1 */
#ifdef DEBUG

/*************************************************
 *                                               *
 *                                               *
 *    FUNCTION: mydebug                          *
 *                                               *
 *                                               *
 *    INPUT:    void                             *
 *                                               *
 *    OUTPUT:   void                             *
 *                                               *
 *    NOTE:                                      *
 *                                               *
 *************************************************/


void
mydebug(void)
{

  char **txtline;
  int   linum;

  struct mynode  *mn;
  struct linkgad *lg;
  struct List    *list;

  for ( mn  = hlp_nodelist->lh_Head;
        mn != (struct mynode  *)&(hlp_nodelist->lh_Tail);
        mn  = mn->mn_node.ln_Succ)
  {
    linum = mn->mn_linum;

    Printf(   "----------------------------\n"
              "Node  : %s\n", mn->mn_node.ln_Name);
    if (mn->mn_headline)
      Printf( "Head  : %s\n", *(mn->mn_txtline));

    if (mn->mn_hastoc)
      Printf( "Toc   : %s\n", mn->mn_toc);
    if (mn->mn_hasprev)
      Printf( "Prev  : %s\n", mn->mn_prev);
    if (mn->mn_hasnext)
      Printf( "Next  : %s\n", mn->mn_next);

    Printf(   "lines : %ld\n", linum);

    PutStr(   "links :");

    list = &(mn->mn_linkgads);
    for ( lg  = list->lh_Head;
          lg != (struct linkgad *)&(list->lh_Tail);
          lg  = lg->lg_node.ln_Succ)
    {
      Printf("\t%s\n", lg->lg_linknode);
    }
  }
}

#endif

/*  #define DEBUG 1 */

#ifdef DEBUG
extern void _waitwbmsg(void);

void
_waitwbmsg(void)
{
  return;
}
#endif

