/*
   IndexAG 
   AmigaGuide context index creator
   By Sebastien Boisvert
   Version 2 revision 0
   
   Description:
   
   Purpose: To create an 'Index' node for all words/links on an
            AmigaGuide document in their context(s)
            
   Options:
        Wordfile: list of words to ignore; one word per line,
                  semi-conlon (;) as first chararcter are comments
        
        NOLINKS:  do not include internal/external links in Index node
        
        NOWORDS: do not incluce words in Index nodes
        
        Threshold: maximum times a word is allowed to repeat in a node
                   before it is too repetitive and omitted
        
        COMMENT: for words that exceed the threshold, comment them so
                 the author can decide to include it or not later
        
        GroupStart/GroupEnd: sequence of characters that determine the
                             start/end of word groups
   
   General Operation: Reads the word list (if NOWORDS is not set). Opens
        the document and proceeds to scan words/links within set parameters
        and catalogs them. As they are catalogued, it is added to the list
        for the node they are in, unless already present. Once done, 
        produces the index in alphabetical order, check that the links are
        valid as it goes along.
        
*/

#define DEBUG 0

/* debug 1 = see each word/node/link as we go along */
/* debug 2 = see each deallocation */
/* debug >2 make a memory report */

#include <exec/memory.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <exec/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include <proto/dos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>
#include <clib/exec_protos.h>

#include "strip.h"

#if DEBUG ==3
# define MWDEBUG 1
# include "sc:extras/memlib/memwatch.h"
#endif

#define VERSIONNUMBER "2.1"

long __oslibversion = 37;

char VersionString[] = "$VER: IndexAG "VERSIONNUMBER" ©1998 by Sébastien Boisvert ("__DATE__")";

struct MinList *nodelist=NULL;  /* Points to the nodes list */
struct MinList *linklist=NULL;  /* Points to the links list */
struct MinList *exwords=NULL;   /* Points to the excluded words list */

struct treenode         /* tree structure */
{
        struct treenode *leftptr;   /* pointer to left */
        struct word *text;                 /* contains pointer to direct name of link/word */
        BOOL type;                  /* identifies it as a word (TRUE) or link (FALSE) */
        struct treenode *rightptr;
};

struct word     /* Word structure */
{
        struct MinNode nextword;
        char    *name;          /* the string */
        struct node *node;      /* the node it belongs to */
        WORD   linenumber;    /* its linenumber in the node */
        WORD   count;         /* the count */
        
        
        
};

struct node      /* Node structure */
{
        struct MinNode nextnode;
        WORD   words;            /* number of words in node */
        char   *title;             /* Node title string */
        char  *name;             /* Node name string */
        struct MinList *wordlist; /* pointer to its words */   
};

struct link      /* Link structure */
{
        struct MinNode nextlink;
        char *name;    /* the name */
        char  *node;   /* the name of the node it references */
        WORD   linenumber;    /* the line number associated with the link, if any */

        

};

struct xword
{
   struct MinNode nextxword;
   char *word;
};

UBYTE currentline;
UBYTE currentnode;
char buffer[513]="";
UBYTE threshold;
BOOL nowords,nolinks,comment;
char groupstart[5]="";
char groupend[5]="";
char GuideName[80];
char WordFile[80];
BPTR masterfile;
BPTR outfile;
int spacing;
int lines;
struct treenode *treeptr = NULL;
char alpha = 64;

void Freexwords(void);
int readwords(void);
int readarguments(void);
int scannode(void);
int scanword(char *, const struct node *);
void cleanup(void);
int doublex(const struct node*, char *);


void __regargs __chkabort(void)   /* disables CTRL_C */
{}

int readwords(void)
{
   void SortMinList(struct MinList *mlh);
   BPTR wordfilehandle;
   struct xword *word1;
   void *temp;
   
   if(!(wordfilehandle=Open(WordFile,MODE_OLDFILE)))       /* Open our word file */
   {
     printf("Could not open word file '%s'!\n", WordFile);
     return 0;
   }
   else
   {
      if (!(exwords=AllocMem(sizeof(struct MinList), MEMF_CLEAR)))      /* Allocate memory for the list header */
        printf("Not enough mem for wordlist\n");
      else
      {
        
        NewList((struct List *)exwords);
      
        /* We start adding words here */
      
      FGets(wordfilehandle, buffer, 513);      /* Prime loop */
      do
      {
         if (buffer[0] != ';')  /* If it's not a comment line */
         {
           if (!(word1=AllocMem(sizeof(struct xword),MEMF_CLEAR)))  /* Allocate space for the node */
              printf("Not enough memory for newword structure\n");
           else
           {
              if (!(temp=AllocMem(strlen(buffer), MEMF_CLEAR)))  /* Allocate for the word - buffer has extra \n !! */
                 printf("Not enough memory to store word\n");
              else
              {
                  word1->word = temp;                         /* point our word pointer to the memory allocated */
                  buffer[(strlen(buffer)-1)] = '\0';               /* we change the \n to a NULL */
                  strncpy(word1->word, buffer, strlen(buffer));
                  AddTail((struct List *)exwords, (struct Node *)word1);  /* add it to the list */
              }
           }
         }
          /* get next word */
      }while(FGets(wordfilehandle, buffer, 513));        /* repeat until done reading */
      }
   }
   Close(wordfilehandle);

   SortMinList(exwords);
   
   return 1;
}

/*------------------------------------------------------------------------*/
/*                                                                        *
 *  $Id: sortminlist.c 1.1 1996/09/15 07:42:23 heinz Exp $
 *                                                                        */
/*------------------------------------------------------------------------*/

/*------------------------------------------------------------------------*/
/*
 * A simple Insertion Sort based MinList sort function with a test case
 * (C)1996 by Heinz Wrobel, <heinz@hwg.muc.de>
 *
 * Based on SAS/C 6.56. Use a command line like this to check this out:
 *  SC $*.c LINK DEF=TEST
 */
/*------------------------------------------------------------------------*/

/*------------------------------------------------------------------------*/
void SortMinList(struct MinList *mlh)
{
    struct xword *mn1, *mn2, *mnnext;

    /* We are doing a simple insertion like sort here, working our way
     * sequentially through the list. The runtime should be acceptable
     * for smaller lists. MinLists are used because this is the lowest
     * common denominator for all lists. I always felt that it is better
     * to cast something down than to cast it upwards.
     */

    /* This makes sense only if we have more than one node in the list! */
    mn1 = (struct xword *)mlh->mlh_Head;
    if(mn1->nextxword.mln_Succ)
    {
        /* While there is still a current node to sort in, sort it in.
         * We stash the next pointer right away to avoid losing it on
         * node removal. Note how we also skip the very first node!
         */
        for(mn1 = (struct xword *)mn1->nextxword.mln_Succ;
            mnnext = (struct xword *)mn1->nextxword.mln_Succ;
            mn1 = mnnext)
        {
            /* Work our way backwards to find
             * the correct insertion point
             */
            for(mn2 = (struct xword *)mn1->nextxword.mln_Pred;
                mn2->nextxword.mln_Pred;
                mn2 =(struct xword *) mn2->nextxword.mln_Pred)
            {
                /* Our callback must return the same values
                 * strcmp would return:
                 *      <0  : mn1 <  mn2
                 *      =0  : mn1 == mn2
                 *      >0  : mn1 >  mn2
                 * We stop when we find a node that is smaller than the
                 * current one and insert our node after it
                 */
                if(stricmp(mn1->word, mn2->word) > 0)
                {
                    break;
                } /* if */
            } /* for */

            /* Only do something, if we are not at
             * the correct position yet
             */
            if(mn2->nextxword.mln_Succ != (struct MinNode *)mn1)
            {
                /* Remember how we stashed the next pointer to continue! */
                Remove((struct Node *)mn1);
                Insert((struct List *)mlh,
                       (struct Node *)mn1, (struct Node *)mn2);
            } /* if */
        } /* while */
    } /* if */

} /* SortMinList */

/*------------------------------------------------------------------------*/

      
void cleanup(void)   /* Here we free the entire xwords list */
{
   struct xword *new;
   struct node *newnode;
   struct word *newwrd;
   struct link *newlink;
   void *temp;
   void freetree(struct treenode *);

   if(exwords)
   {
#if DEBUG ==2
  printf("Freeing exwords\n");
#endif      
     for (new= (struct xword *)exwords->mlh_Head; new->nextxword.mln_Succ; new=(struct xword *)exwords->mlh_Head)
     { 
#if DEBUG ==2
 printf(" Clearing word '%s' from exwords\n",new->word);
#endif
         if(new->word)
          FreeMem(new->word, strlen(new->word)+1);   /* release size of word + the NULL */
         temp=RemHead((struct List *)exwords);             /* remove node from list */
         FreeMem(temp, sizeof(struct xword));              /* release memory */
     }
#if DEBUG ==2
 printf("Freed exwords list\n\n");
#endif
     FreeMem(exwords, sizeof(struct MinList));  /* release the list */
   }
   
  if(nodelist)  /* If there's a node list */
  {
#if DEBUG ==2
 printf("Freeing nodelist\n");
#endif
   for(newnode =(struct node *)nodelist->mlh_Head; newnode->nextnode.mln_Succ; newnode=(struct node *)nodelist->mlh_Head)
   {
#if DEBUG ==2
 printf(" Clearing node:title '%s' & nodename '%s'\n", newnode->title, newnode->name);
#endif
      if(newnode->title)
       FreeMem(newnode->title, strlen(newnode->title)+1);  /* free its name and title */
      if(newnode->name)
       FreeMem(newnode->name, strlen(newnode->name)+1);
      if(newnode->wordlist)   /* check for wordlist */
      {
#if DEBUG ==2
 printf("  Freeing node's wordlist\n");
#endif         
         for(newwrd= (struct word *)newnode->wordlist->mlh_Head; newwrd->nextword.mln_Succ; newwrd= (struct word *)newnode->wordlist->mlh_Head)
         {
#if DEBUG ==2
  printf("   Freeing word '%s' in node's wordlist with count %d, threshold is %d\n", newwrd->name, newwrd->count, threshold);
#endif
            if(newwrd->name)
             FreeMem(newwrd->name, strlen(newwrd->name)+1);   /* clear each word node */
            temp=RemHead((struct List *)newnode->wordlist);
            FreeMem(temp, sizeof(struct word));
         }
#if DEBUG ==2
 printf("   Freed node's wordlist\n");
#endif      
          FreeMem(newnode->wordlist, sizeof(struct MinList));  /* free wordlist */
      }
#if DEBUG ==2
 printf("  Freed node\n");
 #endif
      temp=RemHead((struct List *)nodelist);  /* free the node */
      FreeMem(temp, sizeof(struct node));
   }
#if DEBUG ==2
 printf("Freed nodelist\n\n");
#endif
   FreeMem(nodelist, sizeof(struct MinList));   /* finally free the node list */
  }
   
   if(linklist) /* check for link list */
   {
#if DEBUG ==2
 printf("Freeing linklist\n");
#endif
      for(newlink = (struct link *)linklist->mlh_Head; newlink->nextlink.mln_Succ; newlink=(struct link *)linklist->mlh_Head)
      {
#if DEBUG ==2
 printf("  Freeing link node name '%s' from linklist %d\n", newlink->name, newlink->linenumber);        
#endif
         if (newlink->name)
             FreeMem(newlink->name, strlen(newlink->name)+1);  /* free the link name */
         if(newlink->node)
             FreeMem(newlink->node, strlen(newlink->node)+1); /* free the node name and finally the node */
         temp=RemHead((struct List *)linklist);
#if DEBUG ==2
  printf(" Freeing node from linklist\n");
#endif
         FreeMem(temp, sizeof(struct link));
      }
#if DEBUG ==2
 printf("Freed linklist\n");
#endif      
      FreeMem(linklist, sizeof(struct MinList));   /* free the list */
   }
   
   if(treeptr)
        freetree(treeptr);      /* free the tree */
         
}

void freetree(struct treenode *treeptr)  /* this recursively clears the tree */
{
        freetree(treeptr->leftptr);
        freetree(treeptr->rightptr);
        FreeMem(treeptr, sizeof(struct treenode));
}

int readarguments(void)      /* read in arguments form CLI */
{
   int result=0;
   struct RDArgs *rda;
   LONG options[8];
   
   printf("IndexAG "VERSIONNUMBER" by Sébastien Boisvert\n");

     if ((rda = AllocDosObject(DOS_RDARGS, NULL)) != NULL)
     {
         rda->RDA_ExtHelp = "\nFILENAME/A   name of the AmigaGuide database\n"
                            "WORDFILE/K   alternate word file to use\n"
                            "THRESHOLD/N  maximum number of times a word can repeat in a node\n"
                            "NOWORDS/S    do not index words, only links\n"
                            "NOLINKS/S    do not index links, only words. Overrides NOWORDS if both are set\n"
                            "COMMENT/S    comment words that cross threshold\n"
                            "GROUPSTART/K the sequence of character(s) that indicate the start of a group\n"
                            "GROUPEND/K   the sequence of character(s) that indicate the end of a group\n"
                            " (Both GROUPSTART and GROUPEND must be no more than 4 characters)\n"
                            "Enter arguments";
      
      
        options[0] = (LONG)"";                 /* defaults */
        options[1] = (LONG)"IndexAG.words";
        options[2] = NULL;
        options[3] = 0;
        options[4] = 0;
        options[5] = 0;
        options[6] = (LONG)"<";
        options[7] = (LONG)">";
      
         if (ReadArgs("FILENAME/A,WF=WORDFILE/K,TH=THRESHOLD/N,NW=NOWORDS/S,NL=NOLINKS/S,C=COMMENT/S,GS=GROUPSTART/K,GE=GROUPEND/K", options, rda) != NULL)
        {
           strcpy(GuideName,(char *)options[0]);
           strcpy(WordFile, (char *)options[1]);
           if (options[2] != NULL)
             threshold = *(LONG *)options[2];
           else
              threshold = 10;
           nowords = options[3];
           nolinks = options[4];      
           comment= options[5]; 
           
           if (nowords && nolinks)
              nowords =0;
           
           strncpy(groupstart,(char *)options[6], 4);
           strncpy(groupend,(char *)options[7], 4);
           FreeArgs(rda);
           FreeDosObject(DOS_RDARGS, rda);
           
           result =1;  /* success */
        }
        else
           PrintFault(IoErr(), "IndexAG");
           
     return result;
  }
}  

int scannode()
{
   char temptitle[80]="";
   char tempname[80]="";
   char *temp;
      char scannodebuffer[100]="";
   char *tempbuffer=scannodebuffer;
   char mid[5]="";
   struct node *tempnode;
   struct word *tempword, *searchdouble;
   long i;
   
   strcpy(tempname, strtok(NULL, " \""));       /* get the name of the node */
   
   if(!(strncmp(tempname, "\"", 1)))            /* if it's in strings extract untill next quote */
   {
      strcpy(tempname, tempname+1);
      strcat(tempname, " ");
      strcat(tempname,(strtok(NULL, "\"")));
   }
   
   if(!(strnicmp(tempname,"INDEX", 5)))         /* check if it's the INDEX node */
     return 1;                                  /* and return (skip it) if so */
   
   strcpy(temptitle, strtok(NULL, "\n"));       /* get the title */
   
   strip(tempname, " \"\n", 'B');      
   strip(temptitle, " \"", 'B');
#if DEBUG ==1
 printf("Found node:'%s'   '%s'\n", tempname, temptitle);
#endif   
         
      if(!(tempnode=AllocMem(sizeof(struct node), MEMF_CLEAR)))
      {
        printf("Not enough memory to add node to the list!\n");
        return 0;
      }
      else
      {
         AddTail((struct List *)nodelist, (struct Node *)tempnode);  /* add new node */
         tempnode->name = NULL;
         tempnode->title=NULL;
         
         if(!(temp=AllocMem(strlen(temptitle)+1, MEMF_CLEAR)))
         {
           printf("Can't allocate memory for node title!\n");
           return 0;
         }
         else
         {
            #if DEBUG ==1
              printf("Allocated node title\n");                 /* add title */
            #endif
            tempnode->title=temp;
            strcpy(temp, temptitle);
            
            if(!(temp=AllocMem(strlen(tempname)+1, MEMF_CLEAR)))
            {
               printf("Can't allocate memory for node name!\n");
               return 0;
            }
            else
            {
               #if DEBUG ==1
                 printf("Allocated node name\n");       /* add name */
               #endif
               tempnode->name = temp;
               strcpy(temp, tempname);
               
               tempnode->words=0;
               tempnode->wordlist = NULL;       /* initialise its wordlist to NULL */
               
               
               if (!nowords)
               {
                  if(!(temp=AllocMem(sizeof(struct MinList), MEMF_CLEAR)))
                  {
                     printf("Can't allocate words list for node!\n");
                     return 0;
                  }
                  else
                  {
                     #if DEBUG ==1
                       printf("Allocated wordlist for node\n");         /* create word list */
                     #endif
                     tempnode->wordlist=(struct MinList *)temp;
                     
                     NewList((struct List *)tempnode->wordlist);        /* initialise list */
                  }
               }
                               
               lines=0;
                   
               do
               {
                  FGets(masterfile, buffer, 513);       /* read next line */
                  if(!(strnicmp(buffer, "@ENDNODE", 7)))        /* if end of node */
                     return 1;                                  /* return for next */
                        
                  strip(buffer, "\n", 'E');
                  for(i=0; buffer[i] != NULL; i++)      /* make sure each character is printable */
                    if(!(isprint(buffer[i])))           /* to validate scanning w/ strtok() */
                       buffer[i]=' ';
                  
                  strip(tempbuffer, " ", 'B');
                                
                  lines++;
                     
                  temp=strtok(buffer, " ");
                  
                        
                  do
                  {
                    if(temp)    
                    {
                     strcpy(tempbuffer, temp);
                                          
                     /* Check for group word */
                                                               
                     if(!nowords && strlen(groupstart) && strlen(groupend) )
                     {
                       strmid(tempbuffer,mid,1,strlen(groupstart));
                       if(!(stricmp(mid, groupstart)))
                       {
                         strmid(tempbuffer,mid,strlen(tempbuffer)-strlen(groupend),strlen(groupend));
                         if(stricmp(mid,groupend))
                         {
                             strcat(tempbuffer, " ");   /* get full group of words */
                             strcat(tempbuffer, strtok(NULL,groupend));
                         }
                       }  
                             
                       strip(tempbuffer,groupstart, 'S');
                       strip(tempbuffer,groupend, 'E');
                     }
                           
                     if(!(strncmp(tempbuffer,"@", 1)))
                      if(!(scanword(tempbuffer, tempnode)))  /* check if it's a command */
                          return 0;     /* return to caller if failure for cleanup() */
                             
                     if(temp=strchr(tempbuffer, '@'))  /* if there's a tag left over */
                       if(*(++temp) == '{')             /* strip it */
                          *(--temp)='\0';
                     
                     /* get rid of extraneous characters */
                           
                     strip(tempbuffer,"!#$%^&*()[]{}|,<>?;=\"`~", 'A');
                     strip(tempbuffer,".'+-_:/\\ ", 'B');
#if DEBUG ==1
                     printf("Current buffer is:'%s' %d\n", tempbuffer, strlen(tempbuffer));
#endif
                     /* if we want to add words */
                     
                     if (!nowords && strlen(tempbuffer)!=0)
                     {
                        if(!(doublex(tempnode, tempbuffer))) /* check if in exclude list */
                        {
                                /* check if already in current wordlist */
                          for(searchdouble= (struct word *)tempnode->wordlist->mlh_Head; searchdouble ; searchdouble= (struct word *)searchdouble->nextword.mln_Succ)
                              if (searchdouble->name)
                              {
      
                                if(!(stricmp(tempbuffer, searchdouble->name)))
                                   break; 
                                   
                              }
                          
                          
                          /* if not add it to list */    
                          if (!searchdouble)
                          {
                             if(!(tempword=AllocMem(sizeof(struct word), MEMF_CLEAR)))
                             {
                                printf("Not enough memory to add word node to node's list\n");
                                return 0;
                             }
                             else
                             {
                                tempword->name = NULL;
                                AddTail((struct List *)tempnode->wordlist, (struct Node *)tempword);

                                if(!(temp=AllocMem(strlen(tempbuffer)+1, MEMF_CLEAR)))
                                {
                                   printf("Not enough memory to add word to node's list!\n");
                                   return 0;
                                }
                                else
                                {
                                   tempword->name = temp;
                                   strcpy(tempword->name,tempbuffer);
                                   tempword->node = tempnode;
                                   tempword->linenumber=lines;
                                   tempword->count=1;
                                   
                                   if (spacing < strlen(tempword->name))
                                        spacing = strlen(tempword->name);
#if DEBUG==1
  printf(" Added word '%s' to node's wordlist\n", tempword->name);
#endif
                                }
                             }
                          }
                          else
                             ++(searchdouble->count);   /* otherwise increase its count */
                        } 
                     }
                   }
                  }
                  while (temp=strtok(NULL, " "));  /* loop back with next token */
                 }
                     while(1);  /* loop until EOF */
                  }
            }
         }
   return 1;
}

int doublex(const struct node *node, char *string)   /* checks if word is in exclude list  */
{
   struct xword *xword;
   for(xword=(struct xword *)exwords->mlh_Head; xword->nextxword.mln_Succ; xword= (struct xword *)xword->nextxword.mln_Succ)
      if(!(stricmp(xword->word, string)))
        return 1;
  
   return 0;
}                       


int scanword(char *tempbuffer, const struct node *node)
{
   char linkname[80]="";
   char command[80]="";
   char nodelink[80]="";
   struct link *newlink;
   void *temp;
   char *ptr;
   int tempnum;
   
   
   if(!(strncmp(tempbuffer, "@{\"",3))) /* check if it's a link */
   {
      
      strcpy(linkname, tempbuffer+3);           /* yes, get link name */
      if(linkname[strlen(linkname)-1]!='"')
      {
        strcat(linkname, " ");
        strcat(linkname, strtok(NULL,"\""));
      }
      
      strcpy(command, strtok(NULL, " "));  /* get link where it points to */
      strcpy(nodelink, strtok(NULL, "}"));
      strip(nodelink, " ", 'E');
      
      ptr=strrchr(nodelink, ' ');       /* find the last space character */
      
      tempnum=atoi(ptr);
      
      if(tempnum != 0)  /* check if there's a number at the end */
        *ptr='\0';
         
      strip(linkname, " \"", 'B');
      strip(nodelink, " \"", 'B');

#if DEBUG ==1
 printf("\nLink found for string '%s' to node '%s' lineref: %d\n", linkname, nodelink, tempnum);
#endif      

      if(!(stricmp(command,"link")) && !nolinks)  /* if it's a link */
      {
        int match=0;
        for(newlink= (struct link *)linklist->mlh_Head; newlink->nextlink.mln_Succ && !match; newlink = (struct link *)newlink->nextlink.mln_Succ)
        {
           if(!(stricmp(newlink->name, linkname)))  /* see if it's in list */
              match=1;
        }

        if(!match)      /* if not in list add it to links list */
        {
           if(!(newlink=AllocMem(sizeof(struct link), MEMF_CLEAR)))
           {
              printf("Can't allocate memory to add link node!\n");
              return 0;
           }
           else
           {
              AddTail((struct List *)linklist, (struct Node *)newlink);
              newlink->name = NULL;
              newlink->node = NULL;
              
              if(!(temp=AllocMem(strlen(linkname)+1, MEMF_CLEAR)))
              {
                 printf("Can't allocate memory for link name!\n");
                 return 0;
              }
              else
              {
                 strcpy(temp, linkname);
                 newlink->name = temp;
                 
                 if (spacing < strlen(linkname))
                        spacing = strlen(linkname);
                        
                 if(!(temp=AllocMem(strlen(nodelink)+1, MEMF_CLEAR)))
                 {
                     printf("Can't allocate memory for link node!\n");
                     return 0;
                 }
                 else
                 {
                        strcpy(temp, nodelink);
                        newlink->node = temp;
                        newlink->linenumber = tempnum;
                 }
              }
           }
        }
      }
     else   /* it's not an internal link, but a command; index as word (by returning to caller with name in buffer */
      {
        if(!nowords)
        {
                strcpy(tempbuffer, linkname);
                return 1;
        }
      } 
   }
   else
   {
     if(!(strncmp(tempbuffer,"@{", 2)))  /* check if it's a tag */
     {
        char *temp;
        
        if(temp=strchr(tempbuffer,'}')) /* skip it and see if there's anything after it */
          strcpy(tempbuffer, temp+1);
          
        if (strlen(tempbuffer) !=0 && tempbuffer[strlen(tempbuffer)-1] == '}')
          *(strchr(tempbuffer, '@')) = '\0'; /* if there's something and it contains another */
                                     /* command, stip that command */
           
     }
     else
     {
        *tempbuffer='\0';  /* otherwise it's a command so skip entire line */
        strtok(NULL,"\n");
        lines--;                /* command lines are not counted in linking */
     } 
   }
   
   return 1;  /* success */
}

int createindex(void)
{
        int insertnode (struct treenode **, struct word *, BOOL);
        int writeindex(struct treenode *);
                
        struct node *currentnode;
        struct word *current;
        struct link *currentlink;

        printf("\nCreating index node...\n");
        
         if(!nowords)
          for(currentnode = (struct node *)nodelist->mlh_Head; currentnode->nextnode.mln_Succ ; currentnode = (struct node *)currentnode->nextnode.mln_Succ)
                for(current = (struct word *)currentnode->wordlist->mlh_Head; current->nextword.mln_Succ != NULL ; current = (struct word *)current->nextword.mln_Succ)
                        if(!(insertnode(&treeptr, current,  TRUE)))
                                return 0;

         if(!nolinks)
          for(currentlink = (struct link *)linklist->mlh_Head; currentlink->name ; currentlink = (struct link *)currentlink->nextlink.mln_Succ)
                if(!(insertnode(&treeptr, (struct word *)currentlink, FALSE)))
                        return 0;
                
         if(!(writeindex(treeptr)))
                return 0;             
                
 return 1;       
        
}

int writeindex(struct treenode *tree)
{
        struct node *node;
        int i, match;
        
             if (tree != NULL)
             {
                    if(!(writeindex(tree->leftptr)))
                        return 0;

                    switch(tree->type)
                    {
                        case TRUE:
                                if(!nowords)
                                if(tree->text->count < threshold || comment)
                                {
                                        if(toupper(tree->text->name[0]) > alpha)
                                        {
                                                while(toupper(tree->text->name[0]) != alpha)
                                                        alpha++;
                                                
                                                sprintf(buffer, "\n %c\n\n", alpha);
                                                FPuts(outfile, buffer);
                                        }               

                                        FPutC(outfile, (tree->text->count < threshold ? ' ' : '*'));
                                        sprintf(buffer, "@{\" %s \" link \"%s\" %d}", tree->text->name, tree->text->node->name, tree->text->linenumber);
                                        FPuts(outfile, buffer);
                                        for (i=0; i<(spacing-strlen(tree->text->name)); i++)
                                                FPutC(outfile, ' ');
                                        sprintf(buffer, "%s\n",tree->text->node->title);
                                        FPuts(outfile, buffer);
                                }
                                break;
                        case FALSE:
                        
                                if(!nolinks)
                                {       
                                        if(toupper(tree->text->name[0]) > alpha)
                                        {
                                                while(toupper(tree->text->name[0]) != alpha)
                                                        alpha++;
                                                
                                                sprintf(buffer, "\n %c\n\n", alpha);
                                                FPuts(outfile, buffer);
                                        }
                                                       
                                        for(node = (struct node *)nodelist->mlh_Head, match=0; node->nextnode.mln_Succ; node = (struct node *)node->nextnode.mln_Succ)
                                                if(!(stricmp(node->name, (char *)tree->text->node)))
                                                {
                                                        match =1;
                                                        break;
                                                }
                                                
                                        if(match)       
                                        {
                                                sprintf(buffer," @{\" %s \" link \"%s\" %d}", tree->text->name, node->name, (struct link *)tree->text->linenumber);
                                                FPuts(outfile, buffer);
                                                for (i=0; i<(spacing-(strlen(tree->text->name))); i++)
                                                        FPutC(outfile, ' ');
                                                sprintf(buffer, "%s\n", node->title);
                                                FPuts(outfile,buffer);
                                         }
                                         else
                                         {
                                                printf("  Can't find node for link \"%s\" - please double check reference.\n", tree->text->name); 
                                                sprintf(buffer, "?@{\" %s \" link \"%s\" %d}\n", tree->text->name, (char *)tree->text->node, tree->text->linenumber);
                                                FPuts(outfile, buffer);
                                         }
                                }
                                break;
                     }
                     
                if(!(writeindex(tree->rightptr)))
                        return 0;
                FreeMem(tree, sizeof(struct treenode));
                }
   return 1;             
}

int insertnode(struct treenode **tree, struct word *current, BOOL Type)
{
        if(*tree == NULL)
        {
                *tree = AllocMem(sizeof(struct treenode), MEMF_CLEAR);
                
                if (*tree != NULL)
                {
                        (*tree)->text = current;
                        (*tree)->type = Type;
                        (*tree)->leftptr = NULL;
                        (*tree)->rightptr = NULL;
                }
                else
                {
                        printf("Could not allocate memory to insert word in tree!\n");
                        return 0;
                }
        }
        else
        {
#if DEBUG ==1   
/*        printf("Comparing '%s' with '%s'\n", (*tree)->text->name, current->name); */
#endif             
                if(stricmp((*tree)->text->name, current->name) >= 0)
                        insertnode(&((*tree)->leftptr), current, Type);
                else
                        insertnode(&((*tree)->rightptr), current, Type);
        }                
        return 1;
}
      
void main(int argc, char *argv[])
{
    
     char *tempword;
     __aligned struct FileInfoBlock Fileinfo;
     long filepos, filesize;
     BPTR Filelock;
     
     if (argc == 0)
        printf("This program must be run from the Shell.\n");
     else
     if(readarguments())
     {
        if (!(masterfile=Open(GuideName, MODE_OLDFILE)))
            printf("Could not open file '%s'!\n", GuideName);
        else
        {
           Filelock=Lock(GuideName,SHARED_LOCK);
           Examine(Filelock, &Fileinfo);
           UnLock(Filelock);
           FGets(masterfile, buffer, 513);
           filesize = Fileinfo.fib_Size;
        
           if (strnicmp(buffer, "@DATABASE", 9))
              printf("Not an AmigaGuide Database!\n");
           else
           {
              if (!nowords)
                 readwords();
                 
              if(!nolinks)
              {
                  if(!(linklist=AllocMem(sizeof(struct MinList), MEMF_CLEAR)))
                  {
                    printf("Can't allocate node list structure!\n");
                       goto exit;
                  }
                  else
                    NewList((struct List *)linklist);
               } 

              
              if (!(nodelist=AllocMem(sizeof(struct MinList), MEMF_CLEAR)))
                 printf("Not enough memory to create new nodelist!\n");
              else
              {
                 NewList((struct List *)nodelist);

                 printf("\nScanning document...   ");                 
                 FGets(masterfile, buffer, 513);
                 
                 do
                 {
                    tempword=strtok(buffer, " ");
                    if (!(strnicmp(tempword, "@NODE", 5)))
                    {
                      if(!scannode())
                          goto exit;
                          
                      filepos=Seek(masterfile,0,OFFSET_CURRENT);
                      printf("\b\b\b%2.0f%", (float)filepos / filesize * 100);
                      fflush(stdout);

                    }
                 }
                 while(FGets(masterfile, buffer, 513));    
                 
                 printf("\b\b\b   \n");
              }
              if(!(outfile = Open("index.node", MODE_NEWFILE)))
                        printf("Can't create \"index.guide\" for output!\n");
               else
               {
                    spacing+=3;
                    FPuts(outfile, "@NODE Index\n@REMARK This index created with IndexAG "VERSIONNUMBER" by Sébastien Boisvert\n\n");
                    if(!(createindex()))
                        printf("Could not create index!\n");
                    else
                    {
                        treeptr=NULL;
                        printf("\nDone!\n");
                    }
                    FPuts(outfile, "@ENDNODE\n");
                    Close(outfile);
               }
               
              exit:
                 cleanup();                 
           }
           Close(masterfile);
        }
        
      }
     
#if DEBUG >=3
    MWReport("IndexAG memory report", MWR_FULL);
#endif    

}

