From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- support/spelchek/ascii.inf | 10 + support/spelchek/english.inf | 32 ++ support/spelchek/german.inf | 59 ++++ support/spelchek/heap.c | 72 ++++ support/spelchek/heap.h | 18 + support/spelchek/library.c | 262 ++++++++++++++ support/spelchek/library.h | 19 ++ support/spelchek/main.c | 321 ++++++++++++++++++ support/spelchek/parse.c | 769 ++++++++++++++++++++++++++++++++++++++++++ support/spelchek/parse.h | 18 + support/spelchek/texortho.map | 28 ++ support/spelchek/texortho.tex | 308 +++++++++++++++++ 12 files changed, 1916 insertions(+) create mode 100644 support/spelchek/ascii.inf create mode 100644 support/spelchek/english.inf create mode 100644 support/spelchek/german.inf create mode 100644 support/spelchek/heap.c create mode 100644 support/spelchek/heap.h create mode 100644 support/spelchek/library.c create mode 100644 support/spelchek/library.h create mode 100644 support/spelchek/main.c create mode 100644 support/spelchek/parse.c create mode 100644 support/spelchek/parse.h create mode 100644 support/spelchek/texortho.map create mode 100644 support/spelchek/texortho.tex (limited to 'support/spelchek') 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 +#include +#include + +#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 +#include +#include +#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 + +#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 +#include +#include + +#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 +#include +#include +#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 + = + = 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} + +\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 + +. . . + +\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 + +. . . + +\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} -- cgit v1.2.3