home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,R-,S-,V+,X+}
- {$M 6144,0,655360}
- Program SpelChek;
- { SPELCHEK - A spelling checker. Copyright (c) 1990,91 by Edwin T. Floyd. }
- Uses Dos, Crt, Dict;
-
- Const
- Alphabetic = ['a'..'z','A'..'Z']; { Alphabetic characters }
- WordChar = Alphabetic+['''']; { Default WordSet }
- DefaultOutput = ''; { Default output filename (''=stdout) }
- BufSize = 4096; { I/O buffer size }
-
- Type
- SetOfChar = Set Of Char;
- FileEntryPtr = ^FileEntry;
- FileEntry = Record
- { Input file name list entry }
- NextFile : FileEntryPtr;
- FileName : PathStr;
- End;
-
- Const
- FileList : FileEntryPtr = Nil; { File name list head }
- LastFile : FileEntryPtr = Nil; { File name list tail }
- WordCount : LongInt = 0; { Total number of words examined }
- BadWords : LongInt = 0; { Total number of words not found }
- ReturnCode : Word = 0; { Return code for Halt }
- WordSet : SetOfChar = WordChar; { Words are made of these }
- HighOrder : Boolean = False; { If true, clear high-order bits }
- FullMark : Boolean = False; { If true, output full markup info }
- UserDict : Boolean = False; { If true, use a user dictionary }
- SuppressOutput : Boolean = False; { If true, do not write output file }
- Aborted : Boolean = False; { True if operator aborted }
- OutName : PathStr = DefaultOutput; { Output file name }
- UserDictName : PathStr = ''; { User dictionary name }
- DictPath : PathStr = ''; { Dictionary path }
-
- Var
- dab, dcd, deh, din, dor, dst, duz, user : Dictionary;
- TextFile : File; { Input file }
- OutFile : Text; { Output file }
- TextBuf : Array[1..BufSize] Of Char; { I/O buffer for TextFile }
-
- {$S+}
- Function ProcessParameter(s : String) : Boolean; Forward;
-
- Function ParseParamString(s : String) : Boolean;
- { Extract parameters from a string and process them; return True if all OK. }
- Var
- i, j : Word;
- ParamsOk : Boolean;
- Begin
- ParamsOk := True;
- While (s <> '') And (s[Length(s)] = ' ') Do Dec(s[0]);
- While s <> '' Do Begin
- i := 1;
- While (i <= Length(s)) And (s[i] = ' ') Do Inc(i);
- j := Succ(i);
- While (j <= Length(s)) And (s[j] <> ' ') Do Inc(j);
- If Not ProcessParameter(Copy(s, i, j - i)) Then ParamsOk := False;
- Delete(s, 1, Pred(j));
- End;
- ParseParamString := ParamsOk;
- End;
-
- Function ProcessParameter(s : String) : Boolean;
- { Process command line parameter or file name; return True if OK. }
- Var
- ThisFile : FileEntryPtr;
- IncludeFile : Text;
- ParamOk : Boolean;
- i, j : Word;
- IoRes : Integer;
-
- Procedure GetFiles(Var s : String);
- Var
- Path : PathStr;
- Dir : DirStr;
- Name : NameStr;
- Ext : ExtStr;
- Search : SearchRec;
- Begin
- Path := FExpand(s);
- FSplit(Path, Dir, Name, Ext);
- FindFirst(Path, Archive, Search);
- If DosError <> 0 Then Begin
- WriteLn('No files match ', s);
- ParamOk := False;
- End;
- While DosError = 0 Do Begin
- Path := Dir + Search.Name;
- ThisFile := FileList;
- While (ThisFile <> Nil) And (ThisFile^.FileName <> Path) Do
- ThisFile := ThisFile^.NextFile;
- If ThisFile = Nil Then Begin
- New(ThisFile);
- If ThisFile <> Nil Then Begin
- With ThisFile^ Do Begin
- NextFile := Nil;
- FileName := Path;
- End;
- If LastFile = Nil Then FileList := ThisFile
- Else LastFile^.NextFile := ThisFile;
- LastFile := ThisFile;
- End;
- End Else WriteLn('Already in list: ', Path);
- FindNext(Search);
- End;
- End;
-
- Begin
- ParamOk := True;
- If (s[1] = '-') Or (s[1] = '/') Then Case UpCase(s[2]) Of
- 'H' : If s[3] = '-' Then HighOrder := False Else HighOrder := True;
- 'M' : If s[3] = '-' Then FullMark := False Else FullMark := True;
- 'O' : Begin { Output file }
- Delete(s, 1, 2);
- For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
- If (s <> '') And ((s[1] = '-') Or (s = 'NUL')) Then Begin
- SuppressOutput := True;
- OutName := '-';
- End Else Begin
- SuppressOutput := False;
- If s = '' Then OutName := s Else OutName := FExpand(s);
- End;
- End;
- 'P' : Begin { Dictionary path }
- Delete(s, 1, 2);
- For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
- If (s <> '') Then Begin
- DictPath := FExpand(s);
- If DictPath[Length(DictPath)] <> '\' Then DictPath := DictPath + '\';
- End Else DictPath := s;
- End;
- 'U' : Begin { User dictionary }
- Delete(s, 1, 2);
- For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
- If (s <> '') And ((s[1] = '-') Or (s = 'NUL')) Then Begin
- UserDict := False;
- UserDictName := '';
- End Else Begin
- UserDict := True;
- UserDictName := FExpand(s);
- End;
- End;
- 'W' : Begin { Word character set }
- Delete(s, 1, 2);
- Case s[1] Of
- '+' : ;
- '-' : WordSet := [];
- Else Begin
- WriteLn('WordSet (-W) option must be followed by + or -.');
- ParamOk := False;
- End;
- End;
- Delete(s, 1, 1);
- For i := 1 To Length(s) Do
- WordSet := WordSet + [s[i]];
- End;
- Else Begin
- WriteLn('Unrecognized option: ', s);
- ParamOk := False;
- End;
- End Else If s[1] = '@' Then Begin
- Delete(s, 1, 1);
- For i := 1 To Length(s) Do s[i] := UpCase(s[i]);
- Assign(IncludeFile, s);
- Reset(IncludeFile);
- IoRes := IoResult;
- If IoRes = 0 Then Begin
- WriteLn('Processing include file ', s);
- Repeat
- ReadLn(IncludeFile, s);
- IoRes := IoResult;
- If IoRes = 0 Then If Not ParseParamString(s) Then ParamOk := False;
- Until Eof(IncludeFile) Or (IoRes <> 0);
- If IoRes <> 0 Then Begin
- WriteLn('Error ', IoRes, ' reading include file');
- ParamOk := False;
- End;
- Close(IncludeFile);
- IoRes := IoResult;
- End Else Begin
- WriteLn('Error ', IoRes, ' opening include file ', s);
- ParamOk := False;
- End;
- End Else GetFiles(s);
- ProcessParameter := ParamOk;
- End;
-
- Procedure ParseParams;
- { Interpret environment and command line parameters; display Help info. }
- Var
- i, j : Word;
- ParamsOk : Boolean;
- Ch : Char;
- s : String;
- Begin
- WriteLn('SPELCHEK v1.2 - A spelling checker. Copyright (c) 1990,91 by Edwin T. Floyd.');
- ParamsOk := True;
- If Not ParseParamString(GetEnv('SPELCHEK')) Then Begin
- WriteLn('Error found in SET SPELCHEK=.. environment string');
- ParamsOk := False;
- End;
- For i := 1 To ParamCount Do Begin
- FillChar(s[1], 255, ' ');
- s := ParamStr(i);
- If Not ProcessParameter(s) Then ParamsOk := False;
- End;
- If Not ParamsOk Then Begin
- WriteLn('At least one parameter was in error. Run SPELCHEK with no parameters');
- WriteLn('to see documentation.');
- Halt(1);
- End Else If FileList = Nil Then Begin
- WriteLn;
- WriteLn(' SPELCHEK filenames.. [-H] [-W[+/-]abc..] [@name] [-Oname] [-Ppath]' );
- WriteLn(' [-Uname]');
- WriteLn;
- WriteLn('All command line parameters are separated by spaces. Input text filenames');
- WriteLn('and options may be intermixed; options are distinguished by a leading hyphen:');
- WriteLn;
- WriteLn(' -H[-] Clear high-order bits on input file (i.e. WordStar, default off).');
- WriteLn(' -M[-] Output markup information for MARKDOC program');
- WriteLn(' -W-abc.. Replace the word character set with the indicated characters');
- WriteLn(' (default is all alphabetic characters, upper and lower case, apostrophe).');
- WriteLn(' -W+abc.. Add additional characters to the word character set.');
- WriteLn(' -O[name] Name the output file (default is name omitted => stdout).');
- WriteLn(' -O- Suppress output (counts are still displayed on screen).');
- WriteLn(' -Ppath Drive and directory of dictionary files.');
- WriteLn(' -Uname specifies a user dictionary.');
- WriteLn;
- WriteLn('The "@" prefixes the name of an ASCII include file which may contain');
- WriteLn('filenames, options, and nested include files, in any order.');
- Write('Press any key to continue...');
- Ch := ReadKey;
- Write(^M);
- ClrEol;
- WriteLn;
- WriteLn('You may use the DOS "SET" command to specify default parameters. Examples:');
- WriteLn;
- WriteLn(' SET SPELCHEK=-Ospell.out -W-ABCDEFGHIJKLMNOPQRSTUVWXYZ');
- WriteLn(' SET SPELCHEK=@defaults.spl -O -Pc:\spell');
- WriteLn;
- WriteLn('Command line parameters override "SET" parameters. SPELCHEK examples:');
- WriteLn;
- WriteLn(' SPELCHEK document.txt -W+- -Obadwords.lst');
- WriteLn(' SPELCHEK @filename.lst -Pc:\spell\dict -Obadwords.txt');
- WriteLn(' SPELCHEK file1.txt -H+ -M+ -Umedterm.dct -O | MARKDOC');
- WriteLn;
- WriteLn('SPELCHEK was written by:');
- WriteLn;
- WriteLn(' Edwin T. Floyd [76067,747] (CompuServe)');
- WriteLn(' #9 Adams Park Court 404/576-3305 (work)');
- WriteLn(' Columbus, GA 31909 404/322-0076 (home)');
- Halt(0);
- End Else Begin
- s := '';
- If HighOrder Then ch := '+' Else ch := '-';
- s := s + ' -H' + ch;
- If FullMark Then ch := '+' Else ch := '-';
- s := s + ' -M' + ch;
- WriteLn('Options: ', s, ', -O', OutName);
- If DictPath <> '' Then WriteLn(' -P', DictPath);
- If UserDict Then WriteLn(' -U', UserDictName);
- WriteLn('Press <Esc> to stop.');
- End;
- End;
-
- {$S-}
-
- Function FileExists(FileName : PathStr) : Boolean;
- { Return TRUE if FileName can be opened ($F parameter should be off). }
- Var
- f : File;
- Begin
- Assign(f, FileName);
- Reset(f);
- If IoResult = 0 Then Begin
- FileExists := True;
- Close(f);
- End Else FileExists := False;
- End;
-
- Procedure LoadDict;
- { Load dictionaries }
- Var
- d : DirStr;
- n : NameStr;
- e : ExtStr;
- found : Boolean;
- Begin
- If Not FileExists(DictPath+'AB.DCT') Then Begin
- found := False;
- If DictPath <> '' Then Begin
- WriteLn('Dictionary not found in directory ', DictPath);
- DictPath := '';
- If FileExists('AB.DCT') Then found := True
- Else WriteLn('Dictionary not found in current directory');
- End;
- If Not found Then Begin
- FSplit(ParamStr(0), d, n, e);
- If d[Length(d)] <> '\' Then d := d + '\';
- DictPath := d;
- If Not FileExists(DictPath+'AB.DCT') Then Begin
- WriteLn('Dictionary not found in program directory');
- WriteLn('Unable to locate master dictionary, terminating');
- Halt(1);
- End;
- End;
- End;
- WriteLn('Loading dictionary');
- dab.RestoreDictionary(DictPath+'AB.DCT');
- dcd.RestoreDictionary(DictPath+'CD.DCT');
- deh.RestoreDictionary(DictPath+'EH.DCT');
- din.RestoreDictionary(DictPath+'IN.DCT');
- dor.RestoreDictionary(DictPath+'OR.DCT');
- dst.RestoreDictionary(DictPath+'ST.DCT');
- duz.RestoreDictionary(DictPath+'UZ.DCT');
- If UserDict Then Begin
- If FileExists(UserDictName) Then Begin
- WriteLn('Loading user dictionary');
- user.RestoreDictionary(UserDictName)
- End Else Begin
- WriteLn('User dictionary not found: ', UserDictName);
- WriteLn('Processing continued without user dictionary');
- End;
- End;
- End;
-
- Function InDict(Var s : String) : Boolean;
- { Test for word in dictionary }
- Var
- IsIn : Boolean;
- Begin
- Case s[1] Of
- 'A'..'B' : IsIn := dab.StringInDictionary(s);
- 'C'..'D' : IsIn := dcd.StringInDictionary(s);
- 'E'..'H' : IsIn := deh.StringInDictionary(s);
- 'I'..'N' : IsIn := din.StringInDictionary(s);
- 'O'..'R' : IsIn := dor.StringInDictionary(s);
- 'S'..'T' : IsIn := dst.StringInDictionary(s);
- 'U'..'Z' : IsIn := duz.StringInDictionary(s);
- Else IsIn := False;
- End;
- If UserDict And Not IsIn Then IsIn := user.StringInDictionary(s);
- InDict := IsIn;
- End;
-
- Function ParseInputBlock(Block : LongInt; Len : Word) : Word;
- { Check words from input block against dictionaries }
- Var
- Words : Word;
- s : String;
- i, start : Word;
- Begin
- i := 1;
- Words := 0;
- While i <= Len Do Begin
- s := '';
- While (i <= Len) And Not (TextBuf[i] In WordSet) Do Inc(i);
- start := i;
- If i <= Len Then Begin
- Inc(Words);
- While (i <= Len) And (Length(s) < 255)
- And (TextBuf[i] In WordSet) Do Begin
- Inc(s[0]);
- s[Ord(s[0])] := UpCase(TextBuf[i]);
- Inc(i);
- End;
- While (s <> '') And Not (s[1] In Alphabetic) Do Begin
- Delete(s, 1, 1);
- Inc(start);
- End;
- While (s <> '') And Not (s[Length(s)] In Alphabetic) Do
- Dec(s[0]);
- (*
- { Check for posessive and for some contractions }
- If s = 'WON''T' Then s := ''
- Else If Length(s) > 3 Then Begin
- If Copy(s, Length(s)-1, 2) = '''S' Then
- Delete(s, Length(s)-1, 2)
- Else If Copy(s, Length(s)-1, 2) = '''M' Then
- Delete(s, Length(s)-1, 2)
- Else If Copy(s, Length(s)-2, 3) = 'N''T' Then
- Delete(s, Length(s)-2, 3)
- Else If Copy(s, Length(s)-2, 3) = '''LL' Then
- Delete(s, Length(s)-2, 3)
- Else If Copy(s, Length(s)-2, 3) = '''RE' Then
- Delete(s, Length(s)-2, 3)
- Else If Copy(s, Length(s)-2, 3) = '''VE' Then
- Delete(s, Length(s)-2, 3);
- End;
- *)
- If (Length(s) > 1) And Not InDict(s) Then Begin
- Inc(BadWords);
- If Not SuppressOutput Then Begin
- If FullMark Then Write(OutFile, Block + start, ' ');
- WriteLn(OutFile, s);
- End;
- End;
- End;
- End;
- ParseInputBlock := Words;
- End;
-
- Procedure ProcessNextFile;
- { Open and process the next input file pointed to by FileList. }
- Var
- ThisFile : FileEntryPtr;
- FileWords, BlockOfs, OldBad : LongInt;
- i, MaxLen, Len : Word;
- FileResult : Integer;
- Begin
- ThisFile := FileList;
- With ThisFile^ Do Begin
- Write(FileName, ': ');
- Assign(TextFile, FileName);
- Reset(TextFile, 1);
- FileResult := IoResult;
- If FileResult = 0 Then Begin
- If FullMark And Not SuppressOutput Then
- WriteLn(OutFile, '0 ', FileName);
- Len := 0;
- FileWords := 0;
- OldBad := BadWords;
- BlockOfs := 0;
- Repeat
- BlockRead(TextFile, TextBuf[Succ(Len)], BufSize-Len, i);
- FileResult := IoResult;
- If FileResult = 0 Then Begin
- MaxLen := Len + i;
- If HighOrder Then For i := Succ(Len) To MaxLen Do
- TextBuf[i] := Chr(Ord(TextBuf[i]) And $7F);
- Len := MaxLen;
- If Not Eof(TextFile) Then Begin
- While (Len > 0) And (TextBuf[Len] In WordSet) Do Dec(Len);
- If (Len = 0) Then Len := MaxLen;
- End;
- FileWords := FileWords + ParseInputBlock(BlockOfs, Len);
- BlockOfs := BlockOfs + Len;
- MaxLen := MaxLen - Len;
- If MaxLen > 0 Then
- Move(TextBuf[Succ(Len)], TextBuf[1], MaxLen);
- Len := MaxLen;
- Write(^M, FileName, ': ', FileWords, ' words, ',
- BadWords-OldBad, ' bad');
- While KeyPressed Do If ReadKey = ^[ Then Aborted := True;
- End;
- Until Eof(TextFile) Or (FileResult <> 0) Or Aborted;
- Close(TextFile);
- WriteLn(^M, FileName, ': ', FileWords, ' words, ',
- BadWords-OldBad, ' bad');
- WordCount := WordCount + FileWords;
- End Else WriteLn('Unable to open input file ', FileName);
- If FileResult <> 0 Then Begin
- WriteLn('Error ', FileResult);
- Inc(ReturnCode);
- End;
- FileList := NextFile;
- End;
- Dispose(ThisFile);
- End;
-
- {$F+}
- Function HandleHeapError(Size : Word) : Integer;
- Begin
- If Size > 0 Then Begin
- WriteLn('SPELCHEK ran out of memory.');
- Halt(1);
- End;
- End;
- {$F-}
-
- Begin
- HeapError := @HandleHeapError;
- FileMode := $40;
- ParseParams;
- LoadDict;
- If Not SuppressOutput Then Begin
- Assign(OutFile, OutName);
- Rewrite(OutFile);
- End;
- While (FileList <> Nil) And Not Aborted Do ProcessNextFile;
- If Aborted Then Begin
- WriteLn('File processing aborted by operator');
- If Not SuppressOutput Then WriteLn(OutFile, '***ABORTED***');
- Inc(ReturnCode);
- End;
- If Not SuppressOutput Then Close(OutFile);
- WriteLn('Final Counts: ', WordCount, ' words examined, ',
- BadWords, ' words not found in dictionary');
- WriteLn('Done!');
- Halt(ReturnCode);
- End.
-