/* ======================================================================= */
/* AUI-SPELL: Spelling Check Program (CLI/Shell test version 0.10)         */
/*                                                                         */
/* Programmer:    Paul Overaa                                              */
/*                                                                         */
/* Date:          2nd March 91                                             */
/* ----------------------------------------------------------------------- */
/* Info: This is the first intermediate (test) release of the AUI-SPELL    */  
/*       program. In its current state it provides a line-by-line scan    */ 
/*       of the specified text file with high-lighting of all unknown      */
/*       words. At the moment the program just provides a rapid scan       */
/*       mode without any correction or dictionary addition facilities.    */
/*       The display can however be stopped and started by using the       */
/*       space-bar and return key.                                         */ 
/*                                                                         */
/*       There are good reasons for the current limitations: Firstly,I     */
/*       wanted this stage to be fairly Intuition/Amiga independent - this */  
/*       ensures a straightforward port to other 68000 machines. Secondly, */
/*       I wanted to see and use some kind of visible version (to see if   */ 
/*       there are any problems with the routines to-date) before adding   */
/*       further code and/or producing an Intuition based version.         */
/*                                                                         */
/*       Dictionary additions? In my early notes I said that my initial    */
/*       dictionary scheme was going to be a simple list of words. This    */
/*       WILL change in the next release to an ADT-dictionary orientated   */
/*       form which eliminates the need to compare every word in the       */ 
/*       dictionary whilst checking a textfile. Quite simply I did not     */
/*       want to waste time writing dictionary addition/deletion code for  */
/*       handling a dictionary structure that I know is only temporary!    */
/*                                                                         */
/*       If you want to modify the sorted list of words which constitutes  */ 
/*       the dictionary write your own insertion routines or (if you have  */
/*       enough memory) use a text editor. Current dictionary incidentally */
/*       has about 12,500 words in it.                                     */
/*                                                                         */
/*       The program identifies all of the words in a specified textfile   */
/*       using a binary word tree with duplicates list-tied to their       */
/*       respective tree nodes. Here is a brief summary of how the program */
/*       works...                                                          */
/*                                                                         */
/*       Files are opened and a scan is made to count words and linefeeds. */
/*       Descriptor space is allocated and then an assembly language patch */ 
/*       does all the tree and list orientated descriptor building. Once   */ 
/*       descriptors are available a simple binary tree routine scans the  */
/*       tree and checks words against a sequential sorted-list dictionary */ 
/*       file. Characters of all unidentifed words are marked (bit7 high)  */
/*       and the print routine uses these flags to high-light unknowns.    */
/*                                                                         */
/*       Useage:  aui-spell <text filename> <dictionary filename>          */
/* ----------------------------------------------------------------------- */

/* some defines... */

#define  FIB_SIZE      (LONG) (sizeof(struct FileInfoBlock))

#define  TREENODE_SIZE (LONG) (sizeof(struct TreeNode))

#define  SIGN_ON       0 

#define  USEAGE        1

#define  PROBLEM       2

#define  WAIT          3

#define  CLEAR_CLI     4

#define  HIGHLIGHT_ON  5

#define  HIGHLIGHT_OFF 6

#define  MAXWORD_SIZE  80

#define  FORMAT_STRING "%80s"

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

/* some includes... */

#include <exec/types.h>

#include <exec/memory.h>

#include <libraries/dos.h>

#include <stdio.h>

#include <string.h>

#include <ram:stack_adt.h>

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

/* some structures... */

struct ListNode {

struct ListNode *next_node; 

TEXT   *duplicate;

void   *unused1;

void   *unused2;

void   *unused3;

};

struct TreeNode {

        ULONG count; /* number of characters in word */

        TEXT  *word; /* pointer to word */ 

        struct TreeNode *left_descendant;

        struct TreeNode *right_descendant;

        struct ListNode *head;

};

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

/* some prototypes... */

void   InorderTreePrint(struct TreeNode *g_node_memory_p);

struct TreeNode *FindNext(struct TreeNode *node_p);

struct TreeNode *RightExists(struct TreeNode *node_p);

struct TreeNode *TestForRoot(struct TreeNode *node_p);

struct TreeNode *FindLowest(struct TreeNode *node_p); 

void   PrintLine(TEXT *start_p, TEXT *end_p);

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

/* some globals... */

ULONG g_filesize, g_line_count, g_word_count;

UBYTE g_path, LEFT=1, RIGHT=2; 

TEXT *g_text_p, **g_line_memory_p, g_dictionary_word[MAXWORD_SIZE+1]={NULL},
     *g_buffer_p;

FILE *g_dictionary_file_p;

struct TreeNode *g_node_memory_p;

STACK *g_parent_stack_p, *g_path_stack_p;

TEXT *message[] = {

"AUI-SPELL CLI/Shell version 0.10 Paul Overaa (C) Feb 91\n\n", /* SIGN_ON */

"Usage: aui-spell <text file> <dictionary file>\n\n", /* USEAGE */

"Cannot complete - no source files or no memory \n\n", /* PROBLEM */

"Please wait...\n\n", /* WAIT */

"\x9b" "H" "\x9b" "J", /* CLEAR_CLI */

"\x9b" "33" "\x6d", /* HIGHLIGHT_ON */

"\x9b" "31" "\x6d" /* HIGHLIGHT_OFF */

};

/* ======================================================================= */

main(int argc, char *argv[])

{

BOOL error_flag=TRUE;

ULONG i; 

TEXT *current_line_start_p;

TEXT *current_line_end_p, **current_line_end_descriptor_p;

struct FileHandle *fh;

struct FileLock *filelock_p;

struct FileInfoBlock *fib_p;

g_text_p=message[CLEAR_CLI];while(*g_text_p) putchar(*g_text_p++);

g_text_p=message[SIGN_ON];while(*g_text_p) putchar(*g_text_p++);

if(argc!=3) {g_text_p=message[USEAGE];while(*g_text_p) putchar(*g_text_p++);}

else

 { /* first try to open specified dictionary file */

 if(g_dictionary_file_p=fopen(argv[2],"r"))

  { /* dictionary file open OK - now check if specified text file exists */

   if (filelock_p=(struct FileLock *)Lock(argv[1],ACCESS_READ))

   { /* textfile does exist so dynamically allocate file info block */

       if(fib_p=(struct FileInfoBlock *)AllocMem(FIB_SIZE,MEMF_PUBLIC))

     { /* allocation OK */

      if(Examine(filelock_p, fib_p))

      {

       g_filesize=fib_p->fib_Size; /* get size and allocate buffer */

       if(g_buffer_p=(TEXT *)AllocMem(g_filesize,MEMF_PUBLIC))

        { /* all OK so open properly and read into buffer */

         if((fh=(struct FileHandle *)Open(argv[1], MODE_OLDFILE))!=NULL) 

              {

               g_text_p=message[WAIT];while(*g_text_p) putchar(*g_text_p++);

               fflush(stdout);

               g_filesize=Read(fh,g_buffer_p,g_filesize);

               Close(fh);

               WordCount(); /* preliminary scan to count words and lines */
                 
               if (g_node_memory_p=(struct TreeNode *)
                   AllocMem((g_word_count+1)*TREENODE_SIZE, MEMF_CLEAR))

                 { /* have just sucessfully allocated word descriptor memory */
                       
                  if (g_line_memory_p=(TEXT **)
                      AllocMem((g_line_count+1)*sizeof(TEXT **), MEMF_CLEAR))
   
                   { /* ditto space for linefeed addresses */   
       
                   error_flag=FALSE; /* clear... everything worked O.K. */

                   SeparateWords(); /* build tree descriptor etc. */

                   g_node_memory_p++; /* move past first NULL node */            
        
                   InorderTreePrint(g_node_memory_p);

                   g_node_memory_p--; /* back to real start for deallocation */             

                   current_line_start_p=g_buffer_p;

                   current_line_end_descriptor_p=g_line_memory_p;

                   current_line_end_p=*current_line_end_descriptor_p;
   
                   for (i=0;i<g_line_count;i++)   
                        
                      { 

                      PrintLine(current_line_start_p, current_line_end_p);
                      current_line_start_p=current_line_end_p;
                      current_line_start_p++;     
                      current_line_end_descriptor_p++;
                      current_line_end_p=*current_line_end_descriptor_p;

                      }

                   PrintLine(current_line_start_p, (TEXT *)
                            ((ULONG)g_buffer_p+g_filesize-1));

                   FreeMem(g_line_memory_p, (g_line_count+1)*sizeof(TEXT **));

                   }

                  FreeMem(g_node_memory_p, (g_word_count+1)*TREENODE_SIZE);

                 }

              }

          FreeMem(g_buffer_p, g_filesize);

         } /* end of if AllocMem() for buffer... */

       } /* end of if Examine()... */

     FreeMem(fib_p,FIB_SIZE);

     } /* end of if (fib_p... */

   UnLock(filelock_p);

   } /* end of if (filelock... */

  fclose(g_dictionary_file_p); 

  } /* end of if (g_dictionary_file... */

 } /* end of if(argc==3)... */

 if (error_flag) {g_text_p=message[PROBLEM];while(*g_text_p) putchar(*g_text_p++);}

g_text_p=message[HIGHLIGHT_OFF]; while(*g_text_p) putchar(*g_text_p++);

}/* end of main()... */

/* ----------------------------------------------------------------------- */
void PrintLine(TEXT *start_p, TEXT *end_p)

{

BOOL highlight_on_flag=FALSE;

while(start_p<=end_p)
   
   {

       if(!highlight_on_flag)

           {         
       
            if (*start_p&0x80)

                 {

                 g_text_p=message[HIGHLIGHT_ON];
                 while(*g_text_p) putchar(*g_text_p++);   
                 highlight_on_flag=TRUE;

                 }

            }
                           
      else { 
                                
            if(!(*start_p&0x80))
 
                {

                 g_text_p=message[HIGHLIGHT_OFF];      
                 while(*g_text_p) putchar(*g_text_p++); 
                 highlight_on_flag=FALSE;

                 }

            }

     putchar(*start_p&0x7F); start_p++;

     }

fflush(stdout);

}

/* ======================================================================= */
/*                B I N A R Y - T R E E - R O U T I N E S                  */
/* ----------------------------------------------------------------------- */

void InorderTreePrint(struct TreeNode *node_p)

{

COUNT i, x; TEXT *byte_p;

struct ListNode *duplicate_p;

BOOL exit_compare_flag=FALSE;

g_parent_stack_p=CreateStack(struct TreeNode *);

g_path_stack_p=CreateStack(UBYTE);

node_p=FindLowest(node_p);

   do { 
        
      /* identify node words present in dictionary file */  
 
      x=strnicmp(node_p->word, g_dictionary_word, node_p->count);

      if (x==0) {if(node_p->count<strlen(g_dictionary_word)) x=-1;}
  
      if(x<0)
 
            { /* node word is less than dictionary word */

            /* set bit7 high for node word and duplicates... */

             byte_p=node_p->word;
 
             for (i=0;i<node_p->count;i++) {*byte_p=(*byte_p|=0x80);byte_p++;}
             
             duplicate_p=node_p->head;

             while(duplicate_p)

                {
                        
                byte_p=duplicate_p->duplicate;
               
                for (i=0;i<node_p->count;i++) {*byte_p=(*byte_p|=0x80);byte_p++;}
   
                duplicate_p=duplicate_p->next_node;                        
                        
                }
                
             if(!(node_p=FindNext(node_p))) exit_compare_flag=TRUE; 

            }
 
       else {
 
            if(x==0)
      
                  { 
                        
                  /* if words same we CANNOT be at dictionary end 

                     because dictionary file has a sentinel word */ 
         
                  if(!(node_p=FindNext(node_p))) exit_compare_flag=TRUE; 
                
                  else fscanf(g_dictionary_file_p,FORMAT_STRING,g_dictionary_word);
                        
                  }      
      
             else fscanf(g_dictionary_file_p, FORMAT_STRING, g_dictionary_word);
             
            }
 
      }while(!exit_compare_flag);
   
KillStack(g_parent_stack_p); 

KillStack(g_path_stack_p);

}

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

struct TreeNode *FindNext(struct TreeNode *node_p)

{

if(node_p->right_descendant) return(RightExists(node_p));

else return(TestForRoot(node_p));  

}

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

struct TreeNode *RightExists(struct TreeNode *node_p)

{

PushStack(g_parent_stack_p, node_p); PushStack(g_path_stack_p, RIGHT);

return(FindLowest(node_p->right_descendant));

}
/* ----------------------------------------------------------------------- */

struct TreeNode *TestForRoot(struct TreeNode *node_p)

{

BOOL exit_flag=FALSE;
        
do {

    if (StackEmpty(g_parent_stack_p)) {node_p=NULL; exit_flag=TRUE;}

    else { 
        
          PopStack(g_parent_stack_p, node_p);

          PopStack(g_path_stack_p, g_path);

          if (g_path==LEFT) exit_flag=TRUE;
         
         }

   }while (!exit_flag);     
        
return(node_p);

}

/* ----------------------------------------------------------------------- */
/* If node supplied does NOT have a left descendant then 
   following routine returns the unchanged node address */
   
struct TreeNode *FindLowest(struct TreeNode *node_p)

{

while (node_p->left_descendant)

     { 

      PushStack(g_parent_stack_p, node_p);
  
      PushStack(g_path_stack_p, LEFT); 
      
      node_p=node_p->left_descendant;
 
     }

return(node_p);

}

/* ======================================================================= */










