summaryrefslogtreecommitdiff
path: root/support/spelchek
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/spelchek
Initial commit
Diffstat (limited to 'support/spelchek')
-rw-r--r--support/spelchek/ascii.inf10
-rw-r--r--support/spelchek/english.inf32
-rw-r--r--support/spelchek/german.inf59
-rw-r--r--support/spelchek/heap.c72
-rw-r--r--support/spelchek/heap.h18
-rw-r--r--support/spelchek/library.c262
-rw-r--r--support/spelchek/library.h19
-rw-r--r--support/spelchek/main.c321
-rw-r--r--support/spelchek/parse.c769
-rw-r--r--support/spelchek/parse.h18
-rw-r--r--support/spelchek/texortho.map28
-rw-r--r--support/spelchek/texortho.tex308
12 files changed, 1916 insertions, 0 deletions
diff --git a/support/spelchek/ascii.inf b/support/spelchek/ascii.inf
new file mode 100644
index 0000000000..3c1973f4b5
--- /dev/null
+++ b/support/spelchek/ascii.inf
@@ -0,0 +1,10 @@
+other \
+other {
+other }
+other $
+other %
+other &
+end_of_file
+
+
+
diff --git a/support/spelchek/english.inf b/support/spelchek/english.inf
new file mode 100644
index 0000000000..80c711c730
--- /dev/null
+++ b/support/spelchek/english.inf
@@ -0,0 +1,32 @@
+escape_def 2
+- \-@
+/ \quad@
+capital \L@
+capital \AE@
+skipped_command \-
+delimiter_command \quad
+skipped_command \documentstyle
+skipped_command \Huge
+delimiter_command \item
+delimiter_command \footnote
+skipped_environment equation
+skipped_environment picture
+skipped_environment table
+skipped_environment figure
+skipped_command \bf
+skipped_command \tt
+skipped_command \ref
+skipped_command \cite
+skipped_command \em
+skipped_command \it
+skipped_command \sc
+delimiter_command \section
+delimiter_command \subsection
+delimiter_command \subsubsection
+delimiter_command \index
+skipped_command \protect
+skipped_command \mbox
+end_of_file
+
+
+
diff --git a/support/spelchek/german.inf b/support/spelchek/german.inf
new file mode 100644
index 0000000000..59fd2d26c5
--- /dev/null
+++ b/support/spelchek/german.inf
@@ -0,0 +1,59 @@
+letter á
+active "12
+a \"a
+o \"o
+u \"u
+A \"A
+O \"O
+U \"U
+s \ss@
+' \grqq@
+` \glqq@
+< \frqq@
+> \frqq@
+- \-@
+escape_def 3
+3 \ss@
+- \-@
+/ \quad@
+capital \L@
+capital \AE@
+skipped_command \grqq
+skipped_command \glqq
+skipped_command \-
+delimiter_command \quad
+skipped_command \documentstyle
+skipped_command \Huge
+delimiter_command \item
+delimiter_command \footnote
+skipped_environment equation
+skipped_environment picture
+skipped_environment table
+skipped_environment figure
+skipped_command \bf
+skipped_command \tt
+skipped_command \ref
+skipped_command \cite
+skipped_command \em
+skipped_command \it
+skipped_command \sc
+delimiter_command \section
+delimiter_command \subsection
+delimiter_command \subsubsection
+delimiter_command \index
+skipped_command \protect
+skipped_command \mbox
+delimiter_command \paragraph
+delimiter_command \title
+delimiter_command \author
+delimiter_command \cite
+delimiter_command \ref
+delimiter_command \label
+delimiter_command \addcontentsline
+delimiter_command \noindent
+delimiter_command \indent
+delimiter_command \underline
+end_of_file
+
+
+
diff --git a/support/spelchek/heap.c b/support/spelchek/heap.c
new file mode 100644
index 0000000000..2d12e52df4
--- /dev/null
+++ b/support/spelchek/heap.c
@@ -0,0 +1,72 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<stddef.h>
+
+#define align(d) (((d)+(sizeof(void*)-1))&(~(sizeof(void*)-1)))
+
+#define HEAPIMPLEMENTATION
+
+typedef struct{
+ struct heap_block *first;
+ struct heap_block *last;
+ long blocksize;
+ char *top_of_heap;
+}heap;
+
+struct heap_block{
+ struct heap_block *next;
+ long free;
+};
+
+#include"heap.h"
+
+heap *heap_create( long block_size ) /* allocates memory for heap */
+{
+ heap *HEAP;
+ HEAP = ( heap * )malloc( align( block_size) + sizeof(heap)+sizeof(struct heap_block));
+ if(NULL == HEAP)return(NULL);
+ HEAP->first = (struct heap_block*)(HEAP+1);
+ HEAP->last = HEAP->first;
+ HEAP->blocksize = align( block_size );
+ HEAP->top_of_heap = (char *)(HEAP->last+1); /* next free entry */
+ HEAP->first->next = NULL;
+ HEAP->first->free = block_size;
+ return(HEAP);
+} /* heap_create() */
+
+
+void *heap_allocate( heap *HEAP, long size ) /* allocates on heap */
+{
+ void *help;
+ if ( HEAP->last->free < size )
+ {
+ if( NULL ==(HEAP->last->next = ( struct heap_block * )malloc( HEAP->blocksize+sizeof(struct heap_block))))return(NULL);
+ HEAP->last = HEAP->last->next;
+ HEAP->last->next = NULL;
+ HEAP->last->free = HEAP->blocksize;
+ HEAP->top_of_heap = (void *)(HEAP->last+1); /* next free entry */
+ }
+ help = HEAP->top_of_heap;
+ HEAP->top_of_heap += (align(size) + sizeof(char) -1) / sizeof(char);
+ HEAP->last->free -= align(size);
+ return(help);
+} /* heap_allocate() */
+void heap_resize( heap *HEAP, void *entry, long size )
+{
+ HEAP->last->free += HEAP->top_of_heap - ( (char *)entry + align( size ) );
+ HEAP->top_of_heap = (char *)entry + align( size );
+} /* heap_resize() */
+
+void heap_delete( heap *HEAP )
+{
+ struct heap_block *this, *next;
+ this = HEAP->first;
+ free(HEAP);
+ while(this)
+ {
+ next = this->next;
+ free(this);
+ this = next;
+ } /* of while(this) */
+} /* of heap_delete() */
+
diff --git a/support/spelchek/heap.h b/support/spelchek/heap.h
new file mode 100644
index 0000000000..8e9cd2cf9e
--- /dev/null
+++ b/support/spelchek/heap.h
@@ -0,0 +1,18 @@
+#ifndef HEAP_H
+#define HEAP_H
+
+#ifndef HEAPIMPLEMENTATION
+typedef struct {char VAXDUMMY;} heap;
+#endif
+
+heap *heap_create( long block_size ); /* allocates memory for heap */
+void *heap_allocate( heap *HEAP, long size ); /* allocates on heap */
+void heap_resize( heap *HEAP, void *entry, long size );
+void heap_delete( heap *HEAP );
+
+#endif
+
+
+
+
+
diff --git a/support/spelchek/library.c b/support/spelchek/library.c
new file mode 100644
index 0000000000..45b7673403
--- /dev/null
+++ b/support/spelchek/library.c
@@ -0,0 +1,262 @@
+#include"heap.h"
+#include<stdlib.h>
+#include<string.h>
+#include<stddef.h>
+#define LIBRARYIMPLEMENTATION
+
+typedef struct{
+ heap *lib_on_which_heap;
+ struct libnode *root;
+ long number_of_entries;
+}library;
+
+struct libnode{
+ struct libnode *left;
+ struct libnode *right;
+ long how_often_occurred;
+ unsigned char *string;
+};
+
+#include "library.h"
+
+static void fill_nodelist( struct libnode *node, struct libnode ***nodelist );
+static int compare( struct libnode **first, struct libnode **second );
+static void fill_tree_hist(struct libnode *node,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch,int depth);
+static struct libnode *reorder(struct libnode *node, long *depth,long level);
+
+
+library *library_create( long blocksize )
+{
+ library *lib;
+ heap *lib_heap;
+ if( NULL == ( lib_heap = heap_create( blocksize ))) return(NULL);
+ if( NULL == ( lib = heap_allocate( lib_heap, sizeof( library )))) return(NULL);
+ lib->lib_on_which_heap = lib_heap;
+ lib->root = NULL;
+ lib->number_of_entries = 0;
+ return(lib);
+} /* library_create */
+
+void library_delete( library *lib )
+{
+ heap_delete( lib->lib_on_which_heap );
+}
+
+
+int library_read( library *lib, FILE *libfile ) /* reads library */
+{
+ long occurrences;
+ unsigned char string[256];
+
+ while(!feof(libfile))
+ {
+ if (!fscanf(libfile,"%s\t%ld\n", string, &occurrences)) break;
+ if ( occurrences <= 0 ) break;
+ if (!library_enter_entry( lib, string, occurrences ))
+ return(0); /* eintragen hat nicht geklappt */
+
+ } /* while !feof() */
+ return(1);
+}
+
+
+int library_write( library *lib, FILE *libfile )
+{
+ long i;
+ struct libnode **localptr;
+ struct libnode **nodelist;
+ if ( NULL == (nodelist = (struct libnode **)malloc( sizeof(struct libnode *)*lib->number_of_entries))) return(0);
+ localptr = nodelist;
+ fill_nodelist( lib->root, &localptr );
+ qsort( nodelist, lib->number_of_entries, sizeof( struct libnode *), (int (*)(const void *, const void *)) compare );
+/* the qsort is buggy in some libraries, to have a look at the result!! */
+ for(i = 0; i < lib->number_of_entries; i++ )
+ fprintf( libfile, "%s\t%ld\n", nodelist[i]->string, nodelist[i]->how_often_occurred);
+ fprintf( libfile, "end-of-file\t-1\n");
+ free(nodelist);
+ return(1);
+} /* library_write */
+
+static void fill_nodelist( struct libnode *node, struct libnode ***nodelist )
+{
+ if( node )
+ {
+ *((*nodelist)++) = node;
+ fill_nodelist( node->left, nodelist );
+ fill_nodelist( node->right, nodelist );
+ }
+} /* fill_nodelist */
+
+static int compare( struct libnode **first, struct libnode **second )
+{
+ long local;
+
+ local =(*first)->how_often_occurred - (*second)->how_often_occurred;
+ if (local < 0 ) return( 1 );
+ if (local > 0 ) return( -1 );
+ return( 0 );
+}
+
+
+int library_enter_entry( library *lib, const unsigned char *string, long occurrences_so_far )
+{
+ int comp = 1;
+ struct libnode *node;
+ struct libnode **dest;
+
+ if( lib->root == NULL ) /* leere lib */
+ dest = &(lib->root);
+ else
+ {
+ node = lib->root;
+ while( 0 != ( comp = strcmp(node->string,string)))
+ {
+ if ( comp > 0 )
+ {
+ if ( node->left )
+ {
+ node = node->left;
+ continue;
+ }
+ else
+ {
+ dest = &(node->left);
+ break;
+ }
+ }
+ else if( comp < 0 )
+ {
+ if ( node->right )
+ {
+ node = node->right;
+ continue;
+ }
+ else
+ {
+ dest = &(node->right);
+ break;
+ }
+ }
+ }
+ }
+ if ( comp == 0 )
+ {
+ node->how_often_occurred += occurrences_so_far;
+ return( 1 );
+ }
+
+ *dest = heap_allocate( lib->lib_on_which_heap, sizeof(struct libnode)+ strlen(string)+1 );
+ if(!*dest ) return( 0 );
+ (*dest)->left = NULL;
+ (*dest)->right = NULL;
+ (*dest)->string = (unsigned char *)( *dest + 1 ); /* da soll der string hin (hinter libnode) */
+ (*dest)->how_often_occurred = occurrences_so_far;
+ strcpy((*dest)->string, string );
+ lib->number_of_entries++;
+ return( 1 );
+} /* library_enter_entry */
+
+int library_find_entry( library *lib, const unsigned char *string )
+{
+ struct libnode *node;
+ int comp;
+
+ if ( lib->root == NULL ) return( 0 );
+ node = lib->root;
+ while( 0 != ( comp = strcmp(node->string,string)))
+ {
+ if (( comp > 0 )&&(node->left))
+ {
+ node = node->left;
+ continue;
+ }
+ else if(( comp < 0 )&&( node->right ))
+ {
+ node = node->right;
+ continue;
+ }
+ return( 0 );
+ }
+ return( 1 );
+} /* find_entry liefert pointer auf libnode */
+
+
+void library_fill_hist(library *lib,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch)
+{
+
+ fill_tree_hist( lib->root,tree_hist,weight_hist,histlenght,deepest_branch,0);
+}
+
+static void fill_tree_hist(struct libnode *node,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch,int depth)
+
+{
+ if (node)
+ {
+ fill_tree_hist(node->left,tree_hist,weight_hist,histlenght,deepest_branch,depth+1);
+ if (depth < histlenght)
+ {
+ tree_hist[depth]++;
+ weight_hist[depth] += node->how_often_occurred;
+ }
+ else
+ tree_hist[histlenght]++;
+ if (depth > *deepest_branch) *deepest_branch = depth;
+ fill_tree_hist(node->right,tree_hist,weight_hist,histlenght,deepest_branch,depth+1);
+ }
+}
+
+int library_reorganize(library *lib)
+{
+ long depth = 0;
+
+ lib->root = reorder(lib->root,&depth,0);
+return((int)lib->root);
+}
+
+static struct libnode *reorder(struct libnode *node, long *depth, long level)
+{
+ if (node)
+ {
+ long left_depth;
+ long right_depth;
+ long newdepth;
+ struct libnode *help;
+
+ help = node;
+ newdepth = *depth;
+ node->left = reorder(node->left, depth, level + 1);
+ left_depth = *depth;
+ *depth = newdepth;
+ node->right = reorder(node->right, depth, level + 1);
+ right_depth = *depth;
+ *depth = right_depth > left_depth ? right_depth : left_depth;
+
+ if (right_depth > left_depth)
+ { /* rechts rotieren */
+ if (node->right)
+ {
+ if (node->right->how_often_occurred == node->how_often_occurred)
+ {
+ help = node->right;
+ node->right = help->left;
+ help->left = node;
+ };
+ };
+ } /* links rotieren */
+ else if (left_depth > right_depth)
+ {
+ if (node->left)
+ {
+ if (node->left->how_often_occurred == node->how_often_occurred)
+ {
+ help = node->left;
+ node->left = help->right;
+ help->right = node;
+ };
+ };
+ };
+ return(help);
+ };
+ if (level > *depth) *depth = level;
+ return(node);
+}
diff --git a/support/spelchek/library.h b/support/spelchek/library.h
new file mode 100644
index 0000000000..751f9ff90e
--- /dev/null
+++ b/support/spelchek/library.h
@@ -0,0 +1,19 @@
+#ifndef LIBRARYHEADER
+#define LIBRARYHEADER
+#include<stdio.h>
+
+#ifndef LIBRARYIMPLEMENTATION
+typedef struct {unsigned char VAXDUMMY;} library;
+#endif
+
+library *library_create( long blocksize );
+void library_delete( library *lib );
+int library_read( library *lib, FILE *libfile ); /* reads library */
+int library_enter_entry( library *lib, const unsigned char *string, long occurrences_so_far );
+int library_find_entry( library *lib, const unsigned char *string );
+int library_write( library *lib, FILE *libfile );
+void library_fill_hist( library *lib,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch);
+int library_reorganize(library *lib);
+#endif
+
+
diff --git a/support/spelchek/main.c b/support/spelchek/main.c
new file mode 100644
index 0000000000..c737ebc5c8
--- /dev/null
+++ b/support/spelchek/main.c
@@ -0,0 +1,321 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+
+#include"library.h"
+#include"parse.h"
+
+/* returnwerte:
+-1: option error
+-2: file error
+-3: out of memory */
+#define tolower(c) (('A'<=(c))&&((c)<='Z')? (c)^0x20 : (c))
+#define islower(c) (('a'<=(c))&&((c)<='z'))
+
+int checking = 0, merging = 0, case_sensitive = 0;
+int first_checking = 1;
+int newlibcreate = 1;
+int library_statistics = 0;
+
+
+void print_help(void);
+void lowercase(unsigned char *string);
+void write_statistics( library *mainlib );
+
+
+int main(int argc, const unsigned char *argv[])
+{
+ unsigned char *wort;
+ FILE *texfile, *outfile, *infofile, *newlibfile;
+ library *mainlib, *newlib;
+ const unsigned char *newlibname=NULL, *outputname=NULL, *texfilename = NULL, *infofilename = NULL;
+ unsigned char libnamespace[80], infofilenamespace[] = "TeXortho.inf";
+
+ printf("This is TeXortho, version 1.0, by J.Hannappel and E.Werner \n");
+ printf("written with GNU C, 1991\n\n");
+
+ if ( argc < 3 )
+ {
+ print_help();
+ return(-1);
+ }
+ punctuation_check = 1;
+ new_sentence = 1; /* 1.11.91 */
+ infofilename = infofilenamespace;
+ outfile = stdout;
+ mainlib = library_create( 30000 );
+ /********** parsen der command line */
+
+ {
+ int i;
+ int inputfilefound = 0;
+ int optionfound = 0 , libfilefound = 0;
+ for ( i = 1; i < argc; i++ )
+ {
+ if ( argv[i][0] == '-') /* wir haben eine option */
+ {
+
+ switch( argv[i][1])
+ {
+ case 'h': /* libhist schreiben */
+ library_statistics = 1;
+ break;
+ case 'i':
+ infofilename = argv[++i];
+ break;
+ case 'l': /* name des erzeugten libfiles, default *.lib */
+ newlibname = argv[++i];
+ break;
+ case 'o': /* name des outfiles, default *.out */
+ outputname = argv[++i];
+ break;
+ case 'C': /* case sensitive search */
+ case_sensitive = 1;
+ break;
+ case 'm': /* merge file with lib */
+ optionfound = 1;
+ merging = 1;
+ break;
+ case 'c': /* check file for spelling errors */
+ checking = 1;
+ optionfound = 1;
+ break;
+ case 'p': /* supress check of isolated punctuation chars */
+ punctuation_check = 0;
+ break;
+ case 'n': /* don't create libfile */
+ newlibcreate = 0;
+ break;
+ case 'P': /* supress check of capital letters at the beginnings of sentences */
+ first_checking = 0;
+ break;
+ default:
+ printf("invalid option! aborting...\n" );
+ return(-1);
+ }
+ }
+ else /* wir haben keine option */
+ {
+ if (inputfilefound)
+ {
+ FILE *libfile;
+ libfilefound = 1;
+ if(!(libfile = fopen( argv[i],"r")))
+ {
+ printf("could not open word list %s \n",argv[i]);
+ return(-2);
+ }
+ printf("(%s",argv[i]);
+ if(!library_read( mainlib, libfile ))
+ {
+ printf("could not read word list %s \n",argv[i]);
+ return(-3);
+ }
+ fclose( libfile );
+ printf(")");
+ } /* if inputfilefound */
+ else /* dann isses das texfile */
+ {
+ texfilename = argv[i];
+ inputfilefound = 1;
+ if( newlibname == NULL )
+ {
+ strcpy(libnamespace,argv[i]);
+ newlibname = libnamespace;
+ strcpy(strrchr(newlibname,'.'), ".twl");
+ } /* if newlibname == NULL */
+ }
+ } /* else no option */
+ } /* for i < argc */
+ if( !optionfound || !inputfilefound)
+ {
+ printf("something's missing; aborting...\n");
+ return(-1);
+ }
+ } /* lokale klammer */
+ if( merging && checking )
+ {
+ printf("-c and -m are incompatible options !\n");
+ return(-1);
+ }
+ if( !merging )
+ {
+ if(!( texfile = fopen( texfilename,"r")))
+ {
+ printf("could not open textfile %s \n",texfilename);
+ return(-2);
+ }
+ printf("(%s",texfilename);
+ if ( outputname )
+ {
+ if(!( outfile = fopen( outputname,"w")))
+ {
+ printf("could not open outputfile %s \n",outputname);
+ return(-2);
+ }
+ printf("(%s",outputname);
+ }
+ if(!( infofile = fopen( infofilename,"r")))
+ {
+ printf("could not open infofile %s \n",infofilename);
+ return(-2);
+ }
+ printf( "(%s", infofilename);
+ init_parser( infofile, texfile, outfile ,texfilename);
+ fclose(infofile);
+ printf(")");
+ }
+ if( newlibcreate && !merging ) if( NULL == ( newlib = library_create( 30000 )))
+ {
+ printf("could not create a new word list, probably out of memory...\n");
+ return( -2 );
+ }
+ if( merging )
+ {
+ FILE *newlibfile;
+
+ printf("merging %s to %s ...\n", texfilename, newlibname );
+ if (!(newlibfile = fopen( texfilename, "r")))
+ {
+ printf("could not open word list file %s \n",texfilename);
+ return(-2);
+ }
+ printf("(%s",texfilename);
+ library_read(mainlib, newlibfile );
+ fclose( newlibfile );
+ printf(")");
+ if (!(newlibfile = fopen( newlibname, "w")))
+ {
+ printf("could not open otput library %s \n",newlibname);
+ return(-2);
+ }
+ printf("(%s",newlibname);
+ printf(" reorganizing...\n");
+ library_reorganize(mainlib);
+ printf(" writing...\n");
+ library_write( mainlib, newlibfile );
+ fclose(newlibfile);
+ printf(")\n");
+ if ( library_statistics ) write_statistics( mainlib );
+
+ library_delete( mainlib );
+ return(0);
+ }
+ /*************************** nun bis zum TeXfileende ******************/
+ printf("start parsing...\n");
+
+ while ( wort = next_word( &new_sentence ))
+ {
+ if ( first_checking )
+ if ( new_sentence )
+ {
+ new_sentence = 0;
+ if ( !check_first_char( wort) )
+ fprintf( outfile,"%s:%d: capital letter expected after presumed end of sentence\n",
+ texfilename, zeilennummer );
+ }
+ if( !case_sensitive )lowercase( wort );
+ if(library_find_entry( mainlib, wort ));
+ else
+ {
+ if (newlibcreate) library_enter_entry( newlib, wort, 1 );
+ fprintf(outfile, "%s:%d: unknown %s\n", texfilename, zeilennummer, wort);
+ }
+ }
+ if ( library_statistics ) write_statistics( mainlib );
+ library_delete( mainlib );
+ if (outfile != stdout)
+ {
+ fclose( outfile );
+ printf(")\n");
+ }
+ fclose( texfile );
+ printf(")\n");
+ if( newlibcreate )
+ {
+ if (!(newlibfile = fopen( newlibname, "w")))
+ {
+ printf("could not open output word list %s \n",newlibname);
+ return(-2);
+ }
+ printf("(%s",newlibname);
+ library_write( newlib, newlibfile );
+ fclose(newlibfile);
+ printf(")\n");
+ library_delete( newlib );
+ }
+ return(0);
+} /* end of main */
+
+
+void print_help(void)
+{
+ printf("possible options:\n");
+ printf(" -c\tcheck textfile for errors\n");
+ printf(" -m\tmerge word lists\n");
+ printf("exactly one of the above options is required\n");
+ printf(" -i\tnext parameter is the info file name; default: TeXortho.inf\n");
+ printf(" -l\tnext parameter is the output word list name; default: jobname.twl\n");
+ printf(" -o\tnext parameter is the output file name; default: jobname.out\n");
+ printf(" -C\tcase sensitive search; be sure your library is made for that!\n");
+ printf(" -p\tsupress punctuation check\n");
+ printf(" -P\tsupress check for capital letters at the beginnings of sentences\n");
+ printf(" -n\tdon't create output word list\n");
+ printf(" -h\tdo write a library histogram libhist\n");
+ printf("\nfirst file name is TeX(t) file, the others are word lists\n");
+ printf("for additional help, check the manual\n");
+}
+
+void lowercase( unsigned char *string )
+{
+ while ( *string = tolower(*string) )string++;
+} /* lowercase() */
+
+
+
+void write_statistics( library *mainlib )
+{
+ FILE *newlibfile;
+ if ((newlibfile = fopen( "libhist", "w")))
+ {
+ long tree_hist[250];
+ long weight_hist[250];
+ long deepest_branch;
+ int i;
+ long oldnodes;
+ float treespace;
+
+ printf("writing library statistics on LIBHIST\n");
+ for (i=0;i<250;i++) tree_hist[i] = weight_hist[i] = 0;
+ deepest_branch = 0;
+
+ library_fill_hist( mainlib,tree_hist,weight_hist,249,&deepest_branch );
+
+ fprintf(newlibfile,"deepest branch is %d deep!\n",deepest_branch);
+
+ oldnodes = 0;
+ treespace = 1.0;
+ for ( i = 0; i < (deepest_branch < 249? deepest_branch+1: 250); i++ )
+ {
+ fprintf(newlibfile,"%2d %10d %10d %10d %10.6f %10.3f\n"
+ ,i,tree_hist[i],weight_hist[i],oldnodes - tree_hist[i],
+ (float)tree_hist[i]/treespace,
+ (float)weight_hist[i]/(float)tree_hist[i]);
+ oldnodes = tree_hist[i] * 2;
+ treespace *= 2.0;
+ }
+ fclose(newlibfile);
+ }
+ else
+ printf("could not open word list statistics file....\n");
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/support/spelchek/parse.c b/support/spelchek/parse.c
new file mode 100644
index 0000000000..8c21edc94f
--- /dev/null
+++ b/support/spelchek/parse.c
@@ -0,0 +1,769 @@
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include"heap.h"
+#include"library.h"
+
+#define PARSERIMPLEMENTATION
+#include"parse.h"
+
+#define RINGSIZE 15
+#define MAXSTRING 256
+#define MAXWORT 1022
+#define MODESTACK 100
+#define MINDESTLAENGE 1
+
+#ifdef DEBUG
+#define storemode( mode ) { ringindex++; ringindex %= RINGSIZE; modering[ringindex] = mode; printf("%d ",modering[ringindex]);}
+#else
+#define storemode( mode ) { ringindex++; ringindex %= RINGSIZE; modering[ringindex] = mode;}
+#endif
+
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define is_a_letter(c) ((('A'<=(c))&&((c)<='Z'))||(('a'<=(c))&&((c)<='z')))
+#define islower( c ) ( ('a'<= ( c ))&&(( c ) <= 'z') )
+#define isdigit( c ) ( ('0'<= ( c ))&&(( c ) <= '9') )
+#define isupper( c ) ( ('A'<= ( c ))&&(( c ) <= 'Z') )
+#define preprevious_mode ( modering[ ringindex > 0 ? ringindex-1 : RINGSIZE-1 ] )
+#define previous_mode ( modering[ ringindex ] )
+#define old_mode( age ) ( modering[ ringindex - age => 0 ? ringindex-age : RINGSIZE + ringindex - age ] )
+
+enum catcode {
+ catcode_escape,
+ catcode_begingroup,
+ catcode_endgroup,
+ catcode_mathshift,
+ catcode_alignmenttab,
+ catcode_endofline,
+ catcode_space,
+ catcode_letter,
+ catcode_other,
+ catcode_active,
+ catcode_comment,
+ catcode_ignored,
+ catcode_eof
+};
+
+enum parsemode {
+ no_mode, /* kein mode im mode-ring */
+ common_mode, /* normale buchstaben */
+ escape_mode, /* befehle */
+ parameter_mode, /* untersuchung von environment-parametern */
+ space_mode, /* skippen von leerzeichen */
+ digit_mode, /* behandeln von zahlen (mit dezimalpunkt) */
+ other_mode, /* skippen von others ( z.b. '(' ) */
+ skip_mode, /* $$ werden geskipt und aehnliches */
+ comment_mode, /* behandeln von kommentaren */
+ active_mode, /* untersuchen von active-characters */
+ end_deletion_mode /* skippen der parameter von \end */
+};
+
+struct token {
+ enum catcode catcode;
+ unsigned char token;
+};
+
+
+struct active_expansion{
+ unsigned char of_what;
+ unsigned char *what;
+};
+
+
+struct active_definition{
+ struct active_definition *next;
+ unsigned char character;
+ int anzahl;
+ struct active_expansion expansion[1];
+};
+
+
+/* Modulglobale variablen */
+
+static enum parsemode modering[RINGSIZE];
+static int ringindex;
+static unsigned char punctuation_chars[50] = ".,:;!?"; /* characters, die hinter sich, aber nicht vor sich ein space wollen */
+static unsigned char textbegingroup_chars[20] = "("; /* characters, die vor sich, aber nicht hinter sich ein space wollen */
+static unsigned char textendgroup_chars[20] = ")"; /* characters, die vor sich, aber nicht hinter sich ein space wollen */
+static unsigned char sentenceend_chars[20]=".!?";
+static int zeilenoffset;
+static struct active_expansion default_expansion;
+static struct active_definition *active_defs;
+static struct active_definition *escape_def;
+static struct active_definition escape_default;
+static heap *active_heap;
+static enum parsemode mode_stack[MODESTACK];
+static enum parsemode *mode; /* pointer auf den mode_stack */
+static struct token actualtoken;
+static FILE *source;
+static FILE *outputfile;
+static const unsigned char *texname;
+static struct token catcodes[256];
+static library *skipped_env, *skipped_com, *delimiter_com;
+static library *weird_capital;
+
+/* prototypen */
+
+static struct token next_token(void);
+static void exit_parser( void );
+
+/* code */
+
+void init_parser(FILE *infofile, FILE *sourcefile, FILE *outfile, const unsigned char *sourcename )
+{
+
+ unsigned char zeile[MAXSTRING];
+ unsigned char keyword[MAXSTRING];
+ outputfile = outfile;
+ source = sourcefile;
+ texname = sourcename;
+ zeilennummer = 1;
+ zeilenoffset = 0;
+
+
+ /* initialisierung des mode-rings auf den jeweils die alten modes kommen */
+
+ for ( ringindex = 0; ringindex < RINGSIZE; ringindex++ )
+ modering[ringindex] = no_mode;
+ ringindex = 0;
+
+ escape_default.anzahl = 1;
+ escape_default.next = NULL;
+ default_expansion.of_what = '-';
+ default_expansion.what = "\\-@";
+ escape_default.expansion[0] = default_expansion;
+
+ skipped_env = library_create( 500 );
+ skipped_com = library_create( 500 );
+ delimiter_com = library_create( 500 );
+ weird_capital = library_create( 500 ); /* 1.11.91 */
+ active_heap = heap_create( 500 );
+ atexit( exit_parser );
+ escape_def = &escape_default;
+ active_defs = NULL;
+ { /* init catcodes */
+ unsigned char c;
+ for ( c = 255; c >= ' '; c-- )
+ {
+ catcodes[c].catcode = catcode_other;
+ catcodes[c].token = c;
+ }
+ for ( c = 1; c < ' '; c++ )
+ catcodes[c].catcode = catcode_ignored;
+
+ catcodes['\\'].catcode = catcode_escape;
+ catcodes['{'].catcode = catcode_begingroup;
+ catcodes['}'].catcode = catcode_endgroup;
+ catcodes['$'].catcode = catcode_mathshift;
+ catcodes['&'].catcode = catcode_alignmenttab;
+ catcodes['\n'].catcode = catcode_endofline;
+ catcodes['\n'].token = '\n';
+ catcodes[' '].catcode = catcode_space;
+ catcodes['\t'].catcode = catcode_space;
+ catcodes['%'].catcode = catcode_comment;
+ for ( c = 'A'; c <= 'Z'; c++ )
+ catcodes[c].catcode = catcode_letter;
+ for ( c = 'a'; c <= 'z'; c++ )
+ catcodes[c].catcode = catcode_letter;
+ catcodes[0].catcode = catcode_eof;
+ } /* init catcodes */
+
+ /* infofile-syntax
+ <keyword>=<string>
+ <keyword> = catcodes / skipped_environment / skipped_commands */
+
+ while( fscanf( infofile, "%s\t%s\n", keyword, zeile ))
+ {
+ unsigned char *zeilepointer;
+ zeilepointer = zeile;
+
+ if (!strcmp(keyword,"escape"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_escape;
+ else if (!strcmp(keyword,"begingroup"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_begingroup;
+ else if (!strcmp(keyword,"endgroup"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_endgroup;
+ else if (!strcmp(keyword,"mathshift"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_mathshift;
+ else if (!strcmp(keyword,"alignmenttab"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_alignmenttab;
+ else if (!strcmp(keyword,"endofline"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_endofline;
+ else if (!strcmp(keyword,"space"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_space;
+ else if (!strcmp(keyword,"letter"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_letter;
+ else if (!strcmp(keyword,"active"))
+ {
+ int i,anzahl;
+ struct active_definition *ad;
+ unsigned char expansion[80];
+ catcodes[*zeilepointer++].catcode = catcode_active;
+ anzahl = atoi( zeilepointer );
+ ad = heap_allocate( active_heap, sizeof( struct active_definition ) + sizeof( struct active_expansion ) * ( anzahl - 1 ));
+ ad->character = *zeile;
+ ad->anzahl = anzahl;
+ ad->next = active_defs;
+ active_defs = ad;
+
+ for ( i = 0; i < anzahl; i++ )
+ {
+ fscanf( infofile, "%c\t%s\n", &( ((ad->expansion)[i]).of_what), expansion );
+ ((ad->expansion)[i]).what = heap_allocate( active_heap, strlen( expansion ) + 1 );
+ strcpy( ((ad->expansion)[i]).what, expansion );
+ } /* for i < anzahl */
+ }
+ else if (!strcmp(keyword,"escape_def"))
+ {
+ int i,anzahl;
+ unsigned char expansion[80];
+ anzahl = atoi( zeilepointer );
+ escape_def = heap_allocate( active_heap, sizeof( struct active_definition ) + sizeof( struct active_expansion ) * ( anzahl - 1 ));
+ escape_def->character = *zeile;
+ escape_def->anzahl = anzahl;
+ escape_def->next = NULL;
+
+ for ( i = 0; i < anzahl; i++ )
+ {
+ fscanf( infofile, "%c\t%s\n", &( ((escape_def->expansion)[i]).of_what), expansion );
+ ((escape_def->expansion)[i]).what = heap_allocate( active_heap, strlen( expansion ) + 1 );
+ strcpy( ((escape_def->expansion)[i]).what, expansion );
+ } /* for i < anzahl */
+ }
+ else if (!strcmp(keyword,"other"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_other;
+ else if (!strcmp(keyword,"ignored"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_ignored;
+ else if (!strcmp(keyword,"comment"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_comment;
+ else if (!strcmp(keyword,"escape"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_escape;
+ else if (!strcmp(keyword,"skipped_command"))
+ library_enter_entry( skipped_com, &zeile[1], 1 );
+ else if (!strcmp(keyword,"punctuation"))
+ strcpy( punctuation_chars, zeile );
+ else if (!strcmp(keyword,"sentenceend"))
+ strcpy( sentenceend_chars, zeile );
+ else if (!strcmp(keyword,"text_begingroup"))
+ strcpy( textbegingroup_chars, zeile );
+ else if (!strcmp(keyword,"text_endgroup"))
+ strcpy( textendgroup_chars, zeile );
+ else if (!strcmp(keyword,"capital")) /* 1.11.91 */
+ library_enter_entry( weird_capital, zeile, 1 );
+ else if (!strcmp(keyword,"skipped_environment"))
+ library_enter_entry( skipped_env, zeile, 1 );
+ else if (!strcmp(keyword,"delimiter_command"))
+ library_enter_entry( delimiter_com, &zeile[1], 1 );
+ else if (!strcmp(keyword,"end_of_file"))break;
+ else
+ printf( "Invalid command %s ignored; check infofile\n\b", keyword);
+ } /* while fgets */
+ actualtoken = next_token();
+ mode = mode_stack+1;
+ *mode = common_mode;
+} /* init_parser */
+
+static struct token next_token(void)
+{
+ unsigned char zeichen;
+ for (;;)
+ {
+ zeichen = getc( source );
+ if (feof(source)) break;
+ if ( zeichen == '\n' ) zeilenoffset++;
+ if (catcodes[zeichen].catcode != catcode_ignored ) return ( catcodes[zeichen] );
+ } /* while zeichen != EOF */
+ return( catcodes[0] );
+} /* next_token */
+
+
+
+unsigned char *next_word( int *end_of_sentence )
+{
+ static unsigned char wortbuffer[MAXWORT + 2];
+ unsigned char *wort;
+ unsigned char *wortzeiger;
+ unsigned char escapebuffer[MAXSTRING];
+ unsigned char *escapezeiger;
+ unsigned char parameterbuffer[MAXSTRING];
+ unsigned char *parameterzeiger;
+ unsigned char endbuffer[MAXSTRING];
+ unsigned char *endzeiger;
+ int wortlaenge = 0;
+
+ escapezeiger = escapebuffer;
+ end_of_sentence = &new_sentence;
+ wort = &wortbuffer[2];
+ wortzeiger = wort;
+ wortlaenge = 0;
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+
+ while( 1 )
+ {
+ if ( wortzeiger < wort)
+ {
+ wortzeiger = wort;
+ printf("%s:%d:wortunderflow\n",texname, zeilennummer );
+ }
+ if ( wortzeiger >= &wort[MAXWORT-1])
+ {
+ printf("%s:%d:wortoverflow\n",texname, zeilennummer );
+ return(wort);
+ }
+ if ( mode <= mode_stack ) /* stack underflow verhindern */
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ fprintf( outputfile, "%s:%d: stack underflow\n",
+ texname, zeilennummer );
+ mode = mode_stack + 1;
+ *mode = common_mode;
+ };
+ if ( mode >= &mode_stack[ MODESTACK - 1] ) /* stack overflow */
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ fprintf( outputfile, "%s:%d: stack overflow\n",
+ texname, zeilennummer );
+ mode = mode_stack + 1;
+ *mode = common_mode;
+ };
+
+
+ switch( *mode )
+ {
+ case common_mode: /* normale buchstaben */
+ while( actualtoken.catcode == catcode_letter )
+ {
+ if (wortzeiger - wort >= MAXWORT) return(wort);
+ *wortzeiger++ = actualtoken.token;
+ wortlaenge++;
+ actualtoken = next_token();
+ }
+ switch( actualtoken.catcode )
+ {
+ case catcode_escape:
+ storemode( *mode );
+ *++mode = escape_mode; /* mode auf den stack */
+ if (wortzeiger - wort >= MAXWORT) return(wort);
+ *wortzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ escapezeiger = escapebuffer; /* initialisierung des escapebuffers */
+ break;
+ case catcode_begingroup:
+ storemode( *mode );
+ *++mode = common_mode;
+ actualtoken = next_token();
+ break;
+ case catcode_endgroup:
+ storemode( *mode );
+ --mode;
+ actualtoken = next_token();
+ break;
+ case catcode_mathshift:
+ /* *wortzeiger++ = actualtoken.token; */ /* mshift nicht an wort dran */
+ actualtoken = next_token();
+ break;
+ case catcode_endofline:
+ case catcode_space:
+ storemode( *mode );
+ *++mode = space_mode;
+ *wortzeiger = 0;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ if ( actualtoken.token == '\n' )
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ }
+ wortzeiger = wort; wortlaenge = 0;
+ break;
+ case catcode_alignmenttab:
+ case catcode_other:
+ storemode( *mode );
+ *++mode = other_mode;
+ *wortzeiger = 0;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ break;
+ case catcode_active:
+ storemode( *mode );
+ *++mode = active_mode;
+ break;
+ case catcode_comment:
+ storemode( *mode );
+ *++mode = comment_mode;
+ break;
+ case catcode_ignored:
+ ;
+ break;
+ case catcode_eof:
+ return( NULL );
+
+ } /* local switch */
+ break;
+
+
+ case escape_mode: /* befehle */
+ switch( actualtoken.catcode )
+ {
+ case catcode_space:
+ *--wortzeiger = 0; /* \\ = \n wortzeiger eins runter, um alten backslash zu tilgen */
+ storemode( *mode );
+ *mode = space_mode;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0; /* neues wort anfangen */
+ break;
+ case catcode_escape:
+ *--wortzeiger = 0; /* \\ = \n wortzeiger eins runter, um alten backslash zu tilgen */
+ actualtoken = next_token(); /* naechstes token holen */
+ storemode( *mode );
+ mode--; /* alten mode vom stack holen */
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0; /* neues wort anfangen */
+ break;
+ case catcode_other:
+ {
+ int i = 0;
+ while ( (((escape_def->expansion)[i]).of_what != actualtoken.token ) && ( i < escape_def->anzahl )) i++;
+
+ /* jetzt haben wir die makroexpansion und schauen ob sie geskippt werden muss */
+
+ if ( i == escape_def->anzahl ) ;
+ else
+ {
+ unsigned char string[80];
+ storemode( *mode );
+ mode--;
+ actualtoken = next_token();
+ strcpy( string,&(((escape_def->expansion)[i]).what[1])); /* kopieren ohne backslash */
+ string[strlen( string )-1] = 0;
+ if( library_find_entry( delimiter_com, string ))
+ {
+ *--wortzeiger = 0; /* eingefuegt 14.11.91 */
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ break;
+ }
+ if ( library_find_entry( skipped_com, string ))
+ {
+ *--wortzeiger = 0; /* backslash wegwerfen */
+ }
+ else
+ {
+ wortzeiger--;
+ strcpy (wortzeiger, (( escape_def->expansion)[i] ).what);
+ wortzeiger += strlen((( escape_def->expansion)[i] ).what);
+ wortlaenge++;
+ }
+
+ break;
+ }
+ }
+ case catcode_begingroup: /* zeichen fuer geschweifte klammer auf */
+ case catcode_endgroup: /* zeichen fuer geschweifte klammer zu */
+ case catcode_mathshift: /* dollarzeichen */
+ case catcode_alignmenttab: /* ampersand */
+ case catcode_active:
+ case catcode_comment:
+ *wortzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ storemode( *mode );
+ mode--;
+ break;
+ case catcode_endofline:
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ *wortzeiger = 0;
+ actualtoken = next_token();
+ break;
+ case catcode_letter:
+ escapezeiger = escapebuffer;
+ do{
+ *escapezeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ }while( actualtoken.catcode == catcode_letter );
+ *escapezeiger = 0;
+ if(!strcmp(escapebuffer,"begin"))
+ {
+ storemode( *mode );
+ *mode = parameter_mode;
+ if( actualtoken.catcode == catcode_comment )
+ {
+ storemode(*mode);
+ *++mode = comment_mode;
+ }
+ break;
+ }
+ if(!strcmp(escapebuffer,"end"))
+ {
+ storemode( *mode );
+ *mode = end_deletion_mode;
+ if( actualtoken.catcode == catcode_comment )
+ {
+ storemode( *mode );
+ *++mode = comment_mode;
+ }
+ break;
+ }
+ if(library_find_entry( delimiter_com, escapebuffer )) /* escapesequenz wortdelimiter (wie \quad)*/
+ {
+ storemode( *mode );
+ mode--;
+ *--wortzeiger = 0;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ }
+ else if ( library_find_entry( skipped_com, escapebuffer ))
+ {
+ storemode( *mode );
+ *mode = space_mode; /* damit der delimiting space ueberlesen wird, eingeb. 20.11.91 */
+ *--wortzeiger = 0;
+ }
+ else
+ {
+ strcpy( wortzeiger,escapebuffer );
+ wortzeiger += ( escapezeiger - escapebuffer );
+ *wortzeiger++ = '@'; /* statt eines leerzeichens in der library fuer z.B. stra\ss e */
+ storemode( *mode );
+ mode--;
+ while ( actualtoken.catcode == catcode_space ) actualtoken = next_token();
+ }
+ break;
+
+ case catcode_ignored:
+ ;
+ break;
+ case catcode_eof:
+ return( NULL );
+
+ } /* local switch */
+
+ break;
+
+ case parameter_mode: /* untersuchung von environment-parametern */
+ parameterzeiger = parameterbuffer;
+ while ( actualtoken.token == '[' )
+ while ( actualtoken.token != ']' )
+ {
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ }
+ while ( actualtoken.catcode == catcode_begingroup )
+ actualtoken = next_token();
+ while ( actualtoken.catcode == catcode_letter )
+ {
+ *parameterzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ }
+ *parameterzeiger = 0;
+ if( library_find_entry( skipped_env, parameterbuffer ))
+ {
+ storemode( *mode );
+ *mode = skip_mode;
+ break;
+ }
+ else if ( actualtoken.token == '*' ) actualtoken = next_token();
+ while ( actualtoken.catcode == catcode_endgroup ) actualtoken = next_token();
+ storemode( *mode );
+ mode--;
+ break;
+
+ case other_mode: /* behandlung von others, insbes. interpunktion */
+ if ( punctuation_check )
+ {
+ if ( strchr( punctuation_chars, actualtoken.token ))
+ {
+ unsigned char mishandled_token = actualtoken.token;
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ if ( strchr(sentenceend_chars, mishandled_token) &&
+ !isdigit( actualtoken.token )) *end_of_sentence = 1;
+ if ( ( actualtoken.catcode != catcode_space )&&
+ ( actualtoken.catcode != catcode_endofline )&&
+ !isdigit( actualtoken.token )&&
+ ( actualtoken.catcode != catcode_alignmenttab)&&
+ ( actualtoken.catcode != catcode_endgroup ))
+ {
+ fprintf(outputfile , "%s:%d: missing space after %c\n",
+ texname, zeilennummer, mishandled_token );
+ }
+ }
+ else /* if actualtoken.token is punctuation_char */
+ {
+ actualtoken = next_token();
+ }
+ }
+ else actualtoken = next_token(); /* if punctuation_check */
+ storemode( *mode );
+ mode--;
+ break;
+
+ case space_mode: /* skippen von leerzeichen */
+ while (( actualtoken.catcode == catcode_space )||( actualtoken.catcode == catcode_endofline))
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ if ( punctuation_check )
+ if ( strchr( punctuation_chars, actualtoken.token ))
+ fprintf( outputfile , "%s:%d: extra space before %c\n", texname, zeilennummer, actualtoken.token );
+ storemode( *mode );
+ mode--;
+ break;
+ case skip_mode: /* environments{parameterbuffer} werden geskipt */
+ do {
+ do {
+ do {
+ do {
+ do {
+ if( actualtoken.catcode == catcode_eof ) return( NULL );
+ while ( actualtoken.catcode != catcode_escape )actualtoken = next_token();
+ if( actualtoken.catcode == catcode_eof ) return( NULL );
+ actualtoken = next_token();
+ }while( actualtoken.token != 'e' );
+ actualtoken = next_token();
+ }while( actualtoken.token != 'n' );
+ actualtoken = next_token();
+ }while( actualtoken.token != 'd' );
+ actualtoken = next_token();
+ }while( actualtoken.catcode != catcode_begingroup );
+ actualtoken = next_token();
+ endzeiger = endbuffer;
+ while( actualtoken.catcode == catcode_letter )
+ {
+ *endzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ }
+ *endzeiger = 0;
+ }while( 0 != strcmp( endbuffer,parameterbuffer ));
+ actualtoken = next_token();
+ if( actualtoken.catcode == catcode_eof ) return( NULL );
+ storemode( *mode );
+ mode--;
+ break;
+ case comment_mode: /* behandeln von kommentaren */
+ while ( actualtoken.catcode != catcode_endofline )
+ {
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ }
+ if ( actualtoken.token == '\n' )
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ }
+ storemode( *mode ); /* 1.11.91 */
+ mode--; /* 1.11.91 */
+ actualtoken = next_token();
+ break;
+
+
+ case active_mode: /* untersuchen von active-characters */
+ {
+ unsigned char wrong_token;
+ struct active_definition *def;
+ int i=0;
+
+ storemode( *mode );
+ mode--;
+ def = active_defs;
+ while ( def->character != actualtoken.token ) def = def->next;
+ actualtoken = next_token();
+ while ( (((def->expansion)[i]).of_what != actualtoken.token ) && ( i < def->anzahl )) i++;
+
+ /* jetzt haben wir die makroexpansion und schauen ob sie geskippt werden muss */
+
+ wrong_token = actualtoken.token;
+ actualtoken = next_token();
+ if ( i == def->anzahl )
+ {
+ fprintf( outputfile, "%s:%d: active %c with unknown parameter %c\n",
+ texname, zeilennummer, def->character,wrong_token );
+ }
+ else
+ {
+ unsigned char string[80];
+ strcpy( string,&(((def->expansion)[i]).what[1])); /* kopieren ohne backslash */
+ string[strlen( string )-1] = 0;
+ if( library_find_entry( delimiter_com, string ))
+ {
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ }
+ if ( library_find_entry( skipped_com, string ))
+ {
+ ;
+ }
+ else
+ {
+ strcpy (wortzeiger, ((def->expansion)[i]).what);
+ wortzeiger += strlen(((def->expansion)[i]).what);
+ wortlaenge++;
+ }
+ }
+ }
+ break;
+
+
+ case end_deletion_mode:
+ storemode( *mode );
+ mode--;
+ if ( actualtoken.catcode == catcode_begingroup )
+ while ( actualtoken.catcode != catcode_endgroup )
+ {
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return ( NULL );
+ }
+ actualtoken = next_token();
+ break;
+ default:
+ ;
+ break;
+ } /* switch */
+ } /* while 1 */
+} /* next_word */
+
+static void exit_parser( void ) /* wirft die nebemlibraries weg */
+{
+ library_delete( skipped_com );
+ library_delete( skipped_env );
+ library_delete( delimiter_com );
+ library_delete( weird_capital );
+ heap_delete( active_heap );
+}
+
+
+int check_first_char( unsigned char *word ) /* prueft den ersten buchstaben */
+{ /* 1 = gross, 0 = klein */
+ unsigned char *hilfspointer;
+ while(word)
+ {
+ unsigned char string[MAXSTRING];
+ while( !is_a_letter( *word ))
+ {
+ if( *word == '\\' )
+ break;
+ word++;
+ }
+ if ( islower( *word ) ) return( 0 );
+ if ( isupper( *word ) ) return( 1 );
+
+ /* wir brauchen noch weird_capital fuer \L@ \AE@ etc. */
+
+ hilfspointer = word;
+ while( ( word )&&( *word != '@' )) /* bis zum @ kopieren */
+ word++; /* von hilfspointer bis word */
+ /* ist der bereich als capital definiert? 1 : continue; */
+ word++; /* affenschwanz mitnehmen */
+ strncpy( string, hilfspointer, min(word - hilfspointer,MAXSTRING) );
+ string[ min(word-hilfspointer,MAXSTRING-1) ] = 0;
+ if ( library_find_entry( weird_capital, string )) return( 1 );
+ }
+ return(0);
+}
diff --git a/support/spelchek/parse.h b/support/spelchek/parse.h
new file mode 100644
index 0000000000..e566d32513
--- /dev/null
+++ b/support/spelchek/parse.h
@@ -0,0 +1,18 @@
+unsigned char *next_word( int *end_of_sentence );
+void init_parser(FILE *infofile, FILE *sourcefile, FILE *outfile, const unsigned char *sourcename );
+int check_first_char( unsigned char *word ); /* 1.11.91 */
+
+#ifndef PARSERIMPLEMENTATION
+extern volatile
+#endif
+int zeilennummer;
+
+#ifndef PARSERIMPLEMENTATION
+extern
+#endif
+int punctuation_check;
+
+#ifndef PARSERIMPLEMENTATION
+extern
+#endif
+int new_sentence;
diff --git a/support/spelchek/texortho.map b/support/spelchek/texortho.map
new file mode 100644
index 0000000000..76e11c6cf1
--- /dev/null
+++ b/support/spelchek/texortho.map
@@ -0,0 +1,28 @@
+
+ Start Stop Length Name Class
+ 00000H 03365H 03366H _TEXT CODE
+ 03366H 03DFFH 00A9AH MAIN_TEXT CODE
+ 03E00H 04034H 00235H HEAP_TEXT CODE
+ 04035H 0481BH 007E7H LIBRARY_TEXT CODE
+ 0481CH 0645DH 01C42H PARSE_TEXT CODE
+ 06460H 06A04H 005A5H E87_PROG CODE
+ 06A10H 06A10H 00000H _FARDATA FAR_DATA
+ 06A10H 06A10H 00000H _OVERLAY_ OVRINFO
+ 06A10H 06A21H 00012H _INIT_ INITDATA
+ 06A22H 06A22H 00000H _INITEND_ INITDATA
+ 06A22H 06A27H 00006H _EXIT_ EXITDATA
+ 06A28H 06A28H 00000H _EXITEND_ EXITDATA
+ 06A30H 06A30H 00000H _1STUB_ STUBSEG
+ 06A30H 07921H 00EF2H _DATA DATA
+ 07922H 07925H 00004H _CVTSEG DATA
+ 07926H 0792BH 00006H _SCNSEG DATA
+ 0792CH 081F5H 008CAH _BSS BSS
+ 081F6H 081F6H 00000H _BSSEND ENDBSS
+ 08200H 0830FH 00110H _STACK STACK
+
+ Origin Group
+ 06A3:0 DGROUP
+ 06A2:0 EGROUP
+ 06A1:0 IGROUP
+
+Program entry point at 0000:0000
diff --git a/support/spelchek/texortho.tex b/support/spelchek/texortho.tex
new file mode 100644
index 0000000000..39bb925dc8
--- /dev/null
+++ b/support/spelchek/texortho.tex
@@ -0,0 +1,308 @@
+\documentstyle{article}
+\def\TeXorTho{T\kern-.1667em\lower.5ex\hbox{E}\kern-.1667emX\kern-.4667em\lower1.1667ex\hbox{or}\kern-.5334em\raise.5ex\hbox{T}\kern-.1667em\lower.5ex\hbox{ho}}
+\def\TeXortho{T\kern-.1667em\lower.5ex\hbox{E}\kern-.1667emX\kern-.1667em\hbox{or}\kern-.3334em\raise.5ex\hbox{T}\kern-.2em\hbox{ho}}
+
+
+
+\begin{document}
+\section*{Correcting \TeX{}ts with \TeXorTho }
+\TeXortho\ is a program designed for correcting \TeX~files. But with the
+right info file it can be made apt for almost any text file. It was written
+with GNU C by J\"urgen Hannappel and Eduard Werner, Bonn 1991.
+
+{\sc Disclaimer:} You are using this program at your own risk. It's your
+problem if it crashes your system (and most probably your fault) or writes
+over something important on your hard disk etc.
+
+\TeXortho~is able of checking spelling, correct white space around punctuation
+characters and produces output ready to be digested by an EMACS. We've
+tried hard to make it as flexible as possible so that active characters
+and user-defined macros can be checked as well.
+
+
+
+\section{Concepts}
+To use \TeXortho{} it is neccesary to understand the basic concepts underlying
+ its operation.
+\TeXortho{} parses a \TeX{}-file into words,
+ which are sequences of letters seperated by white space or other characters.
+These words are then looked up in a word list,
+ and an error-message is printed into the log-file if the word cannot be found.
+So we see that \TeXortho{} has two central parts:
+ the parser, which parses the \TeX-file into words
+ and the word list, which contains all knowledge about the spelling of words.
+
+The \TeXortho{} parser is not only applicable to texts in \TeX{} or \LaTeX{}
+ format,
+ but also to almost any other ASCII represented text format.
+It can be adapted to your special text format by means of a special
+ {\em info-file},
+ which contains information about which characters are allowed in words,
+ what sequences of characters are to be considered as commands etc.
+The info-file is discussed later on in a special chapter,
+ but a full understanding will require some knowledge about the \TeX-interna
+ such as character catcodes or active characters.
+Luckily you will not have to alter the info-file at all,
+ or at most you will have to add the definitions of some rather
+ seldom occurring commands to it.
+
+Currently the word list is organized as a binary search tree,
+ with the frequent words close to the tree root,
+ so that they can be found as fast as possible
+To insure the optimal ordering of words it is neccesary to keep track of
+ every occurence of every word in as many texts as possible,
+ which means,
+ that every time you have produced a text you should check it by the help
+ of \TeXortho{} and add the new correct spelled words to the standard word
+ list and update its word frequency information.
+
+The word lists are kept in files with a default extension of {\tt .twl}
+ (which stands for {\tt t}ex {\tt w}ord {\tt l}ist).
+They are (or should be) sorted in a way which insures an optimal search tree:
+ sorted by frequency of occurence in descending order,
+ while groups of equally frequent words are sorted in a way which insures
+ a good balance of the search tree
+ (it is not even impossible that for the sake of balance the ordering by
+ frequency is violated a bit).
+
+To keep the standard word lists in a proper state the usual usage of
+ \TeXortho{} should happen in the following steps:
+
+\begin{enumerate}
+\item Process your file (in the accompanying example it will be called
+ {\tt example.tex}) with the standard word list and infofile.\\
+ \verb/TeXortho example.tex -c english.twl -i english.inf/ \\
+ This will produce a word list {\tt example.twl} which contains
+ all the words in your file which are not in the standard word list.
+
+\item Edit the word list {\tt example.twl} and kill all words that are
+ misspelled or to strange to be put into the standard library.
+
+\item Process your file with both the standard word list and your new list of
+ correct words:\\
+ \verb/TeXortho example.tex -c english.twl example.twl -i english.inf -n/ \\
+ This will show you most errors in your file, which you should correct
+ by now.
+
+\item Process your corrected file with both the standard and the new word list
+ in order to produce a list of the words which occur in your text
+ but shall not become part of the standard library:\\
+ \verb/TeXortho example.tex -c english.twl example.twl -i english.inf -l spurious.twl/ \\
+ This produces a word list {\tt spurious.twl} with all the unwanted words.
+
+\item Process your file with the word list {\tt spurious.twl} to get a word
+ list with the common words of your file and correct information
+ about their frequency:\\
+ \verb/TeXortho example.tex -c spurious.twl -i english.inf/ \\
+ This will produce a word list {\tt example.twl} consisting of all
+ words in your file.
+
+\item Merge the information of your new word list {\tt example.twl} with the
+ standard word list:\\
+ \verb/TeXortho english.twl example.twl -m/ \\
+ This will merge the two libraries into a new version of the standard
+ library,
+ containing both the new words and the updated frequency information.
+\end{enumerate}
+
+
+
+\section{Usage and Options}
+
+\TeXortho{} is invoced both with parameters an with options;
+ the parameters are the names of the files to be processed or produced.
+\TeXortho{} takes any number of filenames as parameters,
+ their meaning depends on the option \verb/-c/ or \verb/-m/:
+With \verb/-m/ you merge word lists and thus all filenames not preceeded by
+ one of the options \verb/-i/, \verb/-l/ or \verb/-o/ will be interpreted as
+ one of the word lists to be merged,
+ while \verb/-c/ tells \TeXortho{} to check the \TeX{}t signified by the first
+ filename against the word lists contained in the other files.
+
+Some files of special importance are denoted after one of the options
+ \verb/-i/, \verb/-l/ and \verb/-o/: after any one of these options a filename
+ seperated by a blank is exspected.
+
+
+\subsection{{\protect \tt -m} merge word lists}
+This option merges word lists together. You must use either -m or -c.
+
+\subsection{{\protect \tt -c} check text}
+The first file name is taken as the input file to be checked, all other
+files are word lists.
+
+\subsection{{\protect \tt -i} info file name}
+This option must be followed be an info file name. Default is \verb/TeXortho.inf/ (check the use of uppercase characters on unix systems!).
+
+\subsection{{\protect \tt -l} output word list name}
+This option must be followed by the name of the new word list,
+ seperated by a blank.
+Use this option if you don't like {\tt jobname.twl} as output file name,
+ which is the default;
+ jobname is the name of the first file specified,
+ without extension.
+
+\subsection{{\protect \tt -o} name}
+This option must be followed by the name of a log file,
+ which will contain all the error messages produced by \TeXortho.
+Normally all output goes to stdout.
+On unix systems you may use this option to suppress the generation of errormessages by using \verb?/dev/null? as output file.
+
+\subsection{{\protect \tt -C} case sensitive search}
+By default \TeXortho{} converts all the words found in a \TeX{}t into lowercase
+ prior to looking them up in the word list,
+ a feature which can be supressed with this option.
+It does {\em not} influence the check for capital letters at the beginnings of
+ new sentences.
+
+If you want to check case-sensitive,
+ make sure your library is apt for this.
+
+\subsection{{\protect \tt -p} supress punctuation check}
+This option supresses checking of correct white space around punctuation
+characters.
+
+\subsection{{\protect \tt -P} supress firstcheck}
+This option supresses checking of capital letters at the beginnings of sentences.
+
+\subsection{{\protect \tt -n} don't write output word list}
+This supresses the generation of the output word list.
+
+\subsection{{\protect \tt -h} generate word list histogram}
+A file called \verb/libhist/ is generated,
+ containing some information about the generated word list,
+ i.e. the depth of the deepest branch of the binary search tree,
+ and for each level of that tree the number of nodes in it,
+ the number of nodes weighted by the frequency of occurence of the word,
+ the number of branches ending there,
+ the ratio between capacity and filling of that level
+ and the mean frequency of the words of that level.
+
+\section{info file}
+\subsection{overview}
+\subsection{Escape code keywords}
+The following keywords affect the handling of \TeX-catcodes.
+Normally you won't need them because the \TeX-defaults are already set.
+ If you use them,
+\TeXortho{} will think them handled equally by your TeX-version.
+If you don't know anything about them, read the \TeX-book before using these
+commands. You can assign values as follows:
+\begin{verbatim}
+<keyword> <character>
+\end{verbatim}
+for instance,
+\begin{verbatim}
+begingroup [
+\end{verbatim}
+will force \TeXortho{} to treat a {\tt [} as begin-group character.
+(This option defaults to {\tt \{ \} }.)
+
+Interesting is the keyword {\tt active} which has a different syntax.
+Settings should be made as follows:
+\begin{verbatim}
+active <char><number of possible parameters>
+<first parameter> <expansion>
+. . .
+<last parameter> <expansion>
+\end{verbatim}
+The usual setting for the german documentstyle shall serve for an example:
+\begin{verbatim}
+active "12
+a \"a
+o \"o
+u \"u
+A \"A
+O \"O
+U \"U
+s \ss@
+` \glqq@
+' \grqq@
+- \-@
+< \flqq@
+> \frqq@
+\end{verbatim}
+
+The keyword {\tt escape\_def} has a similar syntax, i.e.
+\begin{verbatim}
+escape_def <number of different escaped characters>
+<first char> <expansion>
+. . .
+<last char> <expansion>
+\end{verbatim}
+Again, the usual setting for the german style is used as example:
+\begin{verbatim}
+escape_def 3
+3 \ss@
+- \-@
+/ \quad@
+\end{verbatim}
+
+
+Possible keywords to assign catcodes are:
+\begin{itemize}
+\item {\tt escape}
+\item {\tt begingroup}
+\item {\tt endgroup}
+\item {\tt mathshift}
+\item {\tt alignmenttab}
+\item {\tt endofline}
+\item {\tt space}
+\item {\tt letter}
+\item {\tt active}
+\item {\tt other}
+\item {\tt ignored}
+\item {\tt comment}
+\end{itemize}
+
+\subsection{Making special commands known to \TeXortho}
+There is a lot of commands which usually don't occur within words or even
+can't occur within words (like \verb/\quad /). Other commands don't make
+sense written isolated, like \verb/\v/. Some environments would better
+be skipped, since they don't contain words to be checked, like {\tt equation}.
+You may want to tell \TeXortho~how each command behaves:
+
+\begin{itemize}
+
+\item {\tt skipped\_command} says that the command following will be
+ skipped over in the \TeX-file,
+ typicaly commands such as \verb/\protect/ or \verb/\tt/.
+
+\item {\tt punctuation} is followed by a string consisting of the punctuation
+ characters; default is \verb",.;:!?". You should not put a blank before such
+ characters in ordinary text.
+ \TeXortho{} will also complain if you don't leave white space behind them.
+
+\item {\tt sentenceend} is followed by a string consisting of the characters
+ after which you should start with a capital letter. Default is \verb".!?"
+
+\item {\tt text\_begingroup} is followed by a string of characters before
+ which a white space should be found and after which there should be none.
+ Default is \verb"(".
+
+\item {\tt text\_endgroup} is followed by a string of characters after
+ which a white space should be found and before which there should be none.
+ Default is \verb")".
+
+\item {\tt capital} is followed by a control sequence standing for one capital
+ letter e.g. \verb/\L@/.
+ If this sequence requires a delimiter, it must be terminated by @.
+ Default is none.
+
+\item {\tt skipped\_environment} is followed by an environment name.
+ The environment will be skipped by \TeXortho. Default: none.
+
+\item {\tt delimiter\_command} is followed by a control sequence.
+ The command will than be taken as a word delimiter like \verb/\quad/.
+\item {\tt end\_of\_file} is the terminating line of the info file.
+\end{itemize}
+
+\section{Known bugs and limitations}
+\begin{itemize}
+\item In the present version it is not possible to process more
+ than one \TeX-file at once.
+\item After a full stop a command like {\tt quad} with no space in front will
+cause an error message {\tt missing space after presumed end of sentence}.
+\item An erroneous info file might crash the program or even the OS.
+ So try to set up properly.
+\end{itemize}
+\end{document}