home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-07-13 | 54.5 KB | 2,255 lines |
- ;
- ; SPELL version 2.0 December 22, 1982
- ;
- ; written by Michael C. Adler
- ;
- ; History of SPELL's dictionary:
- ; The first SPELL using this dictionary was probably written
- ; by Ralph Gorin at Stanford. It was transported to MIT by
- ; Wayne Mattson. Both the program at MIT and the dictionary
- ; were most recently revised by William Ackerman.
- ;
- ; Thanks to all for the effort spent desigining
- ; the dictionary!
- ; -Michael
- ;
- ;
- .Z80
- TITLE SPELL
- ; JMP START <--Include this line if assembled under anything
- ; but M80.
-
- DB '(C) 1982 Michael C. Adler. '
- DB 'This program has been released into the public domain '
- DB 'by the author. It may neither be sold for profit nor '
- DB 'included in a sold software package without permission '
- DB 'of the author.'
- ;
- ; SPELL will compare words in a document to a dictionary
- ; and mark any words that are not found. It is intended for use
- ; with WordStar's ^QL (Find Misspelling) command. Words are marked
- ; with a preceding null if they are not found.
- ;
- ; WARNING: SPELL requires a Z80 processor.
- ;
- ; MODIFICATION HISTORY:
- ;
- ; 2.0 - December 22, 1982 Michael Adler
- ; -Bug fix: modified to rename files correctly at end of
- ; run if output drive is different from input drive.
- ; -Bug fix: modified to recognize hyphenated words in indented
- ; text.
- ; -Enhanced to allow user specified dictionaries on command
- ; line.
- ; 1.3 - October 10, 1982 Michael Adler
- ; -Bug fix: crashed if number of unique words was multiple
- ; of 256.
- ; 1.2 - October 8, 1982 Michael Adler
- ; -Modified MEMWRD routine to store words backwards in
- ; memory starting just below the BDOS. Thus, maximum
- ; memory is utilized since pointers to words and the words
- ; grow toward each other.
- ; -FILE.UDC is now deleted if it is empty.
- ; -Added messages displaying number of words, number of
- ; unique words, and number of words not found.
- ; 1.1 - August 28, 1982 Michael Adler
- ; -Crashed if file.ADD had a zero length word. Fixed.
- ; -Fixed bug in AUXDIC: stopped reading from .ADD file
- ; when 0 encountered.
- ; -Fixed compatability with WS R(un program). WS initializes
- ; byte at 6CH with default drive instead of 0. Caused output
- ; to be directed to wrong drive sometimes.
- ; -Set SPELL to ignore lines starting with . because WS can't
- ; handle misspelling markers in dot command lines.
- ; -SPELL did not find hyphenated words if LF had parity bit
- ; set. Fixed.
- ;
- ; 1.0 - August 16, 1982 Michael Adler
- ; -Released
- ;
-
-
- INCLUDE SPELL0.MAC
-
- ERRCHR EQU 0 ;THIS IS THE CHARACTER THAT MARKS
- ;UNFOUND WORDS. FOR WordStar, IT
- ;MUST BE 0. IF YOU ARE USING ANOTHER
- ;EDITOR, SET ERRCHR TO THE ASCII
- ;EQUIVALENT OF THE CHARACTER THAT
- ;SHOULD MARK MISSPELLED WORDS.
-
-
- BOOT EQU 0000H
- BDOS EQU BOOT+0005H
- IFCB EQU BOOT+005CH
- TPA EQU BOOT+0100H
- CONOUT EQU 2
- STROUT EQU 9
- OPEN EQU 15
- CLOSE EQU 16
- DELETE EQU 19
- READ EQU 20
- WRITE EQU 21
- MAKE EQU 22
- RENAME EQU 23
- CURDSK EQU 25
- SETDMA EQU 26 ;SET DMA ADDRESS
- RANREA EQU 33 ;READ RANDOM
-
- LF EQU 10
- CR EQU 13
- EOF EQU 01AH ;END OF FILE CHARACTER
- ;
- ; The following are bit flags for the dictionary
- ;
- ZFLAG EQU 1
- YFLAG EQU 2
- RFLAG EQU 4
- GFLAG EQU 8
- DFLAG EQU 16
- MFLAG EQU 32
- SFLAG EQU 64
- HFLAG EQU 256
- VFLAG EQU 512
- JFLAG EQU 1024
- XFLAG EQU 2048
- TFLAG EQU 4096
- NFLAG EQU 8192
- PFLAG EQU 16384
-
- ;
- ; Macros
- ;
- JISIT MACRO CHAR, JMPLOC ;JUMP TO JMPLOC IF (HL) .EQ. CHAR
- LD A,CHAR
- CP (HL)
- JP Z,JMPLOC
- ENDM
-
- QISIT MACRO CHAR, JMPLOC ;QUICK FORM OF JISIT. CHARACTER
- ;TO COMPARE IS ALREADY IN A
- CP CHAR
- JP Z,JMPLOC
- ENDM
-
- ISIT MACRO CHAR ;JUMP TO WRDNOT IF (HL) .NE. CHAR
- LD A,CHAR
- CP (HL)
- JP NZ,WRDNOT
- ENDM
-
-
- START: LD SP,STACK ;CREATE A STACK
- LD A,0C9H ;RETURN INSTRUCTION
- LD (TPA),A ;DON'T ALLOW SECOND RUN OF PROGRAM
- LD DE,WELCOM ;PRINT SIGNON MESSAGE
- LD C,STROUT
- CALL BDOS
- JR START0
- WELCOM: DB 'SPELL V2.0 -- December 22, 1982',CR,LF
- DB '(C) 1982 Michael C. Adler',CR,LF,'$'
-
- START0: LD A,(BOOT+6CH) ;GET OUTPUT DRIVE
- PUSH PSW ;SAVE IT
- LD C,OPEN ;OPEN THE DICTIONARY FILE
- LD DE,DICFCB
- CALL BDOS
- CP 0FFH ;FOUND?
- JP NZ,SETUP ;JUMP IF FOUND
- LD A,1 ;TRY DRIVE A IF NOT ON DEFAULT DRIVE
- LD (DICFCB),A
- LD C,OPEN
- LD DE,DICFCB
- CALL BDOS
- CP 0FFH ;FOUND?
- JP NZ,SETUP
- LD C,STROUT ;OUTPUT: "CAN'T FIND DICTIONARY..."
- LD DE,DICERR
- CALL BDOS
- CALL 0
- DICERR: DB 'Can''t find dictionary file DICT.DIC',CR,LF,'$'
-
- SETUP: LD DE,OFCB ;COPY INPUT FILENAME TO OUTPUT
- LD HL,IFCB
- LD BC,9
- LDIR
- LD DE,P2FCB ;COPY INPUT FILENAME TO PASS 2 FCB
- LD HL,IFCB ; (THIS FCB IS FOR INPUT ON PASS 2)
- LD BC,12
- LDIR
- LD DE,FILDIC ;COPY INPUT FILENAME TO FILE.DIC FCB
- LD HL,IFCB
- LD BC,9
- LDIR
- LD DE,FILADD ;COPY INPUT FILENAME TO FILE.ADD FCB
- LD HL,IFCB
- LD BC,9
- LDIR
- LD DE,FILD$$ ;COPY INPUT FILENAME TO FILE.D$$ FCB
- LD HL,IFCB
- LD BC,9
- LDIR
- POP PSW ;GET OUTPUT DRIVE, IF SPECIFIED (FROM
- ;6CH)
- CP 0
- JR Z,NODRV
- LD HL,BOOT+81H ;SEARCH FOR DRIVE SPECIFICATION IN
- ;COMMAND LINE
- LD A,(BOOT+80H) ;NUMBER OF CHARACTERS IN COMMAND LINE
- LD B,0
- LD C,A ;COUNTER
- ADD HL,BC ;HL POINTS TO LAST CHARACTER
- DEC BC ;DON'T TEST FIRST BYTE OF INPUT
- LD A,':' ;SEARCHING FOR ":"
- CPDR
- JR NZ,NODRV ;IF NO DRIVE SPECIFIED, THEN USE
- ;DEFAULT
- LD A,(HL) ;GET DRIVE NAME
- AND 5FH ;MAKE UPPER CASE
- SUB 40H ;MAKE A=1
- LD (OFCB),A ;MAKE OUTPUT FILES ON OUTPUT DRIVE
- LD (FILD$$),A
- NODRV: LD C,OPEN ;OPEN THE INPUT FILE
- LD DE,IFCB
- CALL BDOS
- LD C,OPEN ;WITH PASS 1 AND PASS 2 FCB'S
- LD DE,P2FCB
- CALL BDOS
- CP 0FFH
- JP NZ,SETUP0 ;JUMP IF FOUND
- LD C,STROUT ;OUTPUT: "CAN'T FIND INPUT FILE"
- LD DE,NOINPT
- CALL BDOS
- CALL BOOT
- NOINPT: DB 'Can''t find input file',CR,LF,'$'
-
- SETUP0: LD C,DELETE ;DELETE OUTPUT FILE (FILE.$$$)
- LD DE,OFCB
- CALL BDOS
- LD C,MAKE ;MAKE A NEW OUTPUT FILE
- LD DE,OFCB
- CALL BDOS
- CP 0FFH
- JP NZ,SETUP1 ;JUMP IF SUCCESSFUL
- LD C,STROUT ;OUTPUT: "DIRECTORY FULL"
- LD DE,NODIR
- CALL BDOS
- CALL BOOT
- NODIR: DB 'Directory full',CR,LF,'$'
-
- SETUP1: CALL CTRLZ ;FILL OUTPUT BUFFER WITH EOF
- LD A,EOF ;MARK END OF OUTPUT BUFFER
- LD (OBUFF+512),A
- LD A,0 ;MARK END OF DICTIONARY BUFFER
- LD (DICBUF+256),A
- LD (DICBUF+257),A
- LD A,(PUTCHR) ;GET THE NORMAL FIRST INSTRUCTION
- ;AT PUTCHR
- LD (SAVPUT),A ;STORE IT FOR LATER
- LD A,0C9H ;RETURN INSTRUCTION
- LD (PUTCHR),A ;DISABLE OUTPUT
- CALL AUXDIC ;LOAD "SPELL.DIC", FILE.DIC AND
- ; FILE.ADD
- LD HL,IFCB ;INPUT FILE FCB
- LD (FILPAT),HL ;PATCH GETWRD: TO READ FROM IT
-
-
- ;
- ; SRTFIL -- Sort the file in memory, alphabetically. Duplicate words are
- ; discarded. This will save a lot of time during dictionary lookups
- ; since the words will have to be located only once.
-
- SRTFIL: CALL GETWRD ;GET A WORD INTO SRCWRD:
- JP Z,CHECK ;IF EOF THEN START CHECKING
- LD HL,(TOTWRD) ;KEEP TRACK OF TOTAL # OF WORDS
- INC HL
- LD (TOTWRD),HL
- CALL CREWRD ;CREATE WORD FROM SRCWRD:
- LD A,0 ;IS IT AT LEAST 2 CHARS LONG?
- CP C
- JR Z,SRTFIL ;FORGET IT IF NOT
- LD A,41 ;IF LONGER THAN 40, ALSO FORGET IT
- CP C
- JR Z,SRTFIL
- CALL MEMWRD ;PUT WORD IN MEMORY
- AND A ;FULL?
- JR Z,SRTFIL ;GET ANOTHER WORD IF NOT
- LD HL,(INPTR) ;GET OLD INPUT BUFFER POINTER
- LD (OLDPTR),HL ;SAVE IT
- LD A,1 ;MARK PASS 1 INCOMPLETE
- LD (STOPED),A
- LD (MLTPAS),A ;RECORD PERMANENTLY THAT >1 PASS
- LD C,36 ;GET RECORD NUMBER OF INPUT FILE
- LD DE,IFCB
- CALL BDOS
-
-
- ;
- ; CHECK -- Compare the entries in the sorted table to the dictionary.
- ; Words that are found are marked.
- ;
- CHECK: LD A,(STOPED) ;IS READ OF SOURCE COMPLETE?
- CP 0
- JR NZ,CHEC01 ;IF NOT, NO MESSAGE
- LD DE,TOTMSG ;OUTPUT: "TOTAL # OF WORDS"
- LD C,STROUT
- CALL BDOS
- LD HL,(TOTWRD) ;PRINT NUMBER
- CALL DECOUT
- CHEC01: LD HL,(SRTTOP) ;TOP ENTRY IN POINTER TABLE
- LD DE,(SRTBOT) ;BOTTOM
- XOR A ;CLEAR CARRY
- DEC HL ;POINT TO TRUE END, NOT DUMMY RECORD
- DEC HL
- SBC HL,DE ;HL=NUMBER OF WORDS TIMES 2
- JP Z,MAIN ;IF EMPTY, WRITE OUT FILE
- RRC L ;DIVIDE HL BY 2
- LD A,L
- AND 07FH
- LD L,A
- LD A,0
- RRC H
- ADC A,0
- RRC A
- OR L
- LD L,A
- LD A,H
- AND 07FH
- LD H,A
- LD B,H ;PUT COUNTER IN BC
- LD C,L
- INC B ;MAKE B WORD WITH DEC B AND JNZ
- ;COMBINATION
- LD A,0
- CP C ;IF C 0?
- JR NZ,CHEC02
- DEC B ;IF C=0 THEN READJUST B BECAUSE
- ;IT WOULD LOOP 256 TOO MANY TIMES
- CHEC02: LD HL,(SRTBOT) ;GET ADDRESS OF FIRST ENTRY
- INC HL ;BYPASS DUMMY ENTRY AT BEGINNING
- INC HL
- CHECK0: LD E,(HL) ;GET ADDRESS OF WORD IN MEMORY
- INC HL
- LD D,(HL)
- INC HL
- PUSH BC
- PUSH HL
- LD HL,WORD
- LD C,0FEH ;CHARACTER COUNTER
- ;AT THE END, C=CHARS-1. START OF WITH
- ;-2 SO THAT 0 AND 1 CHARACTER NOT
- ;COUNTED
- CHECK1: LD A,(DE) ;GET A CHARACTER
- LD (HL),A ;PUT IT IN WORD:
- INC C
- DEC DE
- INC HL
- CP 0 ;END OF WORD?
- JR NZ,CHECK1 ;LOOP UNTIL END
- LD A,C
- LD (LASTC),A ;NUMBER OF CHARACTERS
- LD HL,(UNQWRD) ;RECORD # OF UNIQUE WORDS
- INC HL
- LD (UNQWRD),HL
- CALL WRDTST ;SEARCH DICTIONARY FOR WORD
- CP 1 ;FOUND?
- JR NZ,CHECK2 ;LEAVE UNMARKED IF NOT FOUND
- INC DE ;POINT TO END MARKER OF WORD
- LD A,080H
- LD (DE),A ;MARK WORD AS FOUND
- JR CHECK3
- CHECK2: LD HL,(MISWRD) ;INCREMENT MISSED WORDS COUNTER
- INC HL
- LD (MISWRD),HL
- CHECK3: POP HL
- POP BC
- DEC C
- JP NZ,CHECK0 ;LOOP
- DEC B
- JP NZ,CHECK0 ;16 BIT LOOP INDEX
- LD HL,P2FCB ;SET TO INPUT FROM PASS 2 FCB
- LD (FILPAT),HL
- LD HL,(P2OPTR) ;SET PASS 2 INPUT POINTER
- LD (INPTR),HL
- LD A,(SAVPUT) ;GET THE NORMAL FIRST INSTRUCTION
- ;AT PUTCHR
- LD (PUTCHR),A ;PATCH IT INTO THE WRITE ROUTINE
- LD HL,P2BUF+512 ;PATCH NEW BUFFER INTO GETCHR
- LD (BUFPAT),HL
- LD HL,P2BUF
- LD (BUFPA0),HL
- LD (BUFPA1),HL
- INC HL
- LD (BUFPA2),HL
- LD A,(LASTCH) ;SAVE LAST CHARACTER READ
- LD B,A
- LD A,(OLSTCH) ;PUT OLD LASTCH BACK
- LD (LASTCH),A
- LD A,B
- LD (OLSTCH),A ;SAVE CURRENT LASTCH
- JR MAIN
- TOTMSG: DB CR,LF,LF,'Total number of words in document: $'
-
- ;
- ; MAIN -- Do a second pass through the input file. Compare each word to
- ; the memory buffer to determine whether the words were found.
- ; If a word was not found, mark it with the ERRCHR.
-
- MAIN: CALL GETWRD ;GET A WORD INTO SRCWRD:
- JP Z,DONE ;IF EOF THEN STOP
- CALL CREWRD ;CREATE WORD FROM SRCWRD:
- LD A,0 ;IS WORD AT LEAST 2 CHARS LONG?
- CP C
- JR Z,MAIN0 ;ACCEPT IF NOT
- LD A,41 ;IF LONGER THAN 40, ALSO ACCEPT
- CP C
- JR Z,MAIN0
- CALL MEMWRD ;SEARCH FOR WORD IN MEMORY
- LD A,(DE) ;GET MARKER FOR WORD
- CP 080H ;WORD SPELLED CORRECTLY?
- JR Z,MAIN0
- LD A,ERRCHR ;IF NOT, MARK WORD
- CALL PUTCHR
- MAIN0: LD HL,SRCWRD ;OUTPUT THE ORIGINAL WORD
- MAIN1: LD A,(HL)
- CP 0 ;END OF WORD?
- JR Z,MAIN2
- CALL PUTCHR ;OUTPUT CHARACTER
- INC HL ;POINT TO NEXT CHARACTER
- JR MAIN1 ;LOOP
- MAIN2: LD A,(STOPED) ;WAS PASS 1 INCOMPLETE
- AND A
- JR Z,MAIN ;GET NEXT WORD IF NOT
- LD DE,P2FCB ;COMPUTE CURRENT RECORD NUMBER
- LD C,36
- CALL BDOS
- LD DE,(P2FCB+21H)
- LD HL,(IFCB+21H) ;COMPARE STOPPED RECORD NUMBER TO
- ;CURRENT
- XOR A ;CLEAR CARRY
- SBC HL,DE
- JP NZ,MAIN ;GET NEXT WORD IF NOT THE SAME
- LD HL,(OLDPTR) ;GET POSITION IN RECORD
- LD DE,P2BUF-INBUF ;OFFSET IT TO COMPARE WITH PASS 2 BUFF
- ADD HL,DE
- LD DE,(INPTR)
- XOR A
- SBC HL,DE ;COMPARE STOPPED POS TO CURRENT
- JP NZ,MAIN ;GET NEXT WORD IF NOT THE SAME
- LD A,0 ;UNMARK PASS 1 INCOMPLETE
- LD (STOPED),A
- LD HL,(INPTR) ;SAVE PASS 2 INPUT POINTER
- LD (P2OPTR),HL
- LD HL,(OLDPTR) ;GET OLD POINTER TO BUFFER
- LD (INPTR),HL ;RESET BUFFER POINTER
- LD HL,IFCB ;PATCH GETCHR: ROUTINE TO READ FROM
- ;PASS 1 FCB
- LD (FILPAT),HL
- LD HL,INBUF+512 ;PATCH THE CORRECT BUFFER INTO GETCHR
- LD (BUFPAT),HL
- LD HL,INBUF
- LD (BUFPA0),HL
- LD (BUFPA1),HL
- INC HL
- LD (BUFPA2),HL
- LD A,0C9H ;MAKE PUTCHR NOT WORK
- LD (PUTCHR),A
- LD HL,(SRTBOT) ;RESET MEMORY BUFFER POINTERS
- INC HL
- INC HL
- LD (SRTTOP),HL
- LD HL,(BDOS+1) ;GET BDOS VECTOR
- DEC HL ;POINT TO FREE MEMORY
- LD (FREE),HL ;POINTER TO FREE MEMORY
- LD A,(LASTCH) ;SAVE LAST CHARACTER READ
- LD B,A
- LD A,(OLSTCH) ;PUT OLD LASTCH BACK
- LD (LASTCH),A
- LD A,B
- LD (OLSTCH),A ;SAVE CURRENT LASTCH
- JP SRTFIL ;FILL BUFFER AGAIN
-
- ;
- ; DONE -- Write out the rest of the output buffer and then close and rename
- ; output files.
-
- DONE: LD HL,OBUFF ;WRITE OUT REMAINING DATA IN BUFFER
- LD DE,128
- DONE1: LD A,EOF ;DONE?
- CP (HL)
- JR Z,DONE3
- PUSH DE
- PUSH HL
- LD D,H ;SET UP DMA ADDRESS
- LD E,L
- LD C,SETDMA
- CALL BDOS
- LD DE,OFCB ;WRITE 128 BYTES TO FILE
- LD C,WRITE
- CALL BDOS
- POP HL
- POP DE
- CP 0 ;ERROR?
- JR NZ,DONE2 ;DISK FULL --> BRANCH
- ADD HL,DE ;POINT TO NEXT RECORD
- JR DONE1
- DONE2: LD C,STROUT ;DISK FULL
- LD DE,DSKFUL ;DISK FULL MESSAGE (SEE PUTCHR)
- CALL BDOS
- CALL BOOT
-
- DONE3: LD DE,OFCB ;CLOSE OUTPUT FILE
- LD C,CLOSE
- CALL BDOS
- LD A,'B'
- LD (OFCB+9),A
- LD A,'A'
- LD (OFCB+10),A
- LD A,'K'
- LD (OFCB+11),A
- LD A,(OFCB) ;REMEMBER OUTPUT DRIVE NAME
- PUSH PSW
- LD A,(IFCB) ;GET THE DRIVE ON WHICH INPUT WAS DONE
- LD (OFCB),A ;TRY TO DELETE .BAK ON IT ONLY
- LD DE,OFCB
- LD C,DELETE
- CALL BDOS
- LD DE,IFCB+16 ;RENAME SOURCE TO SOURCE.BAK
- LD HL,OFCB
- LD BC,12 ;COPY FILENAME FOR RENAME
- LDIR
- LD DE,IFCB
- LD C,RENAME
- CALL BDOS
- LD HL,IFCB+9 ;RENAME .$$$ TO SOURCE
- LD DE,IFCB+25
- LD BC,3
- LDIR
- LD A,'$'
- LD (IFCB+9),A
- LD (IFCB+10),A
- LD (IFCB+11),A
- POP PSW ;RESTORE OUTPUT DRIVE NAME
- LD (IFCB),A ;AND PUT IT IN FCB
- LD DE,IFCB
- LD C,RENAME
- CALL BDOS
- ;NOW TAKE CARE OF USER DICTIONARIES
- LD DE,FILADD ;DELETE FILE.ADD
- LD C,DELETE
- CALL BDOS
- LD DE,FILDIC ;DELETE FILE.UDC
- LD C,DELETE
- CALL BDOS
- LD A,(MLTPAS) ;WAS MORE THAN 1 PASS REQUIRED?
- CP 0
- JR Z,DONE30 ;NO MESSAGE IF NOT
- LD DE,NOTOUT ;OUTPUT: NO TOTALS PRINTED
- LD C,STROUT
- CALL BDOS
- JR DONE31
- DONE30: LD DE,UNQMSG ;OUTPUT: # OF UNIQUE WORDS
- LD C,STROUT
- CALL BDOS
- LD HL,(UNQWRD) ;PRINT # OF WORDS
- CALL DECOUT
- LD DE,MISMSG ;OUTPUT: # OF "MISSPELLED" WORDS
- LD C,STROUT
- CALL BDOS
- LD HL,(MISWRD) ;PRINT #
- CALL DECOUT
- DONE31: LD HL,(FILUDC) ;DELETE FILE.D$$ IF IT HAS NO WORDS
- LD A,0
- CP H
- JR NZ,DONE4 ;RENAME IT TO FILE.UDC IF >0 WORDS
- CP L
- JR NZ,DONE4
- LD DE,FILD$$ ;DELETE IT
- LD C,DELETE
- CALL BDOS
- CALL BOOT
-
- DONE4: LD HL,FILDIC ;RENAME FILE.D$$ TO FILE.UDC
- LD DE,FILD$$+16
- LD BC,12
- LDIR
- LD DE,FILD$$
- LD C,RENAME
- CALL BDOS
- CALL BOOT
- NOTOUT: DB CR,LF,'No subtotals available due to size of document.$'
- UNQMSG: DB CR,LF,' Number of unique words: $'
- MISMSG: DB CR,LF,' Unique "misspelled" words: $'
-
- ;
- ; GETWRD -- Read a word from an input file. Words are any series of
- ; alphabetic characters (with or without parity set) and
- ; apostrophes.
- ;
- ; Returns: C <-- number of characters in word
- ; Z flag set if EOF
-
- GETWRD: CALL GETCHR ;GET A CHARACTER
- CP EOF ;END OF FILE?
- RET Z
- CALL LEGAL ;TEST IF LEGAL
- LD (LASTCH),A ;SAVE LAST CHARACTER
- JR Z,KILPER ;EXIT LOOP IF LEGAL
- CALL PUTCHR ;SEND CHARACTER DIRECTLY OUT
- JR GETWRD ;LOOP UNTIL LEGAL
- KILPER: LD C,A
- AND 07FH ;MASK PARITY
- CP '.' ;IS IT A DOT COMMAND?
- LD A,C
- JR NZ,GETWR0 ;GET WORD IF NOT
- CALL PUTCHR
- KILPE0: CALL GETCHR ;ERADICATE THIS LINE
- CP EOF ;END OF FILE?
- RET Z
- CALL PUTCHR ;OUTPUT IT
- LD (LASTCH),A
- AND 07FH ;MASK PARITY
- CP LF ;IS IT A LINE TERMINATOR?
- JR NZ,KILPE0 ;LOOP THROUGH WHOLE LINE
- JR GETWRD ;GET A TEXT WORD NOW
- GETWR0: LD C,1 ;ZERO CHARACTER COUNTER
- LD HL,SRCWRD+1 ;INITIALIZE POINTER TO SRCWRD:
- LD (SRCWRD),A ;STORE FIRST CHARACTER
- GETWR1: CALL GETCHR
- HYPTST: CP 1FH ;SOFT HYPHEN?
- JP Z,ISHYP
- CP 1EH ;UNUSED SOFT HYPHEN?
- JP NZ,NOTHYP
- ISHYP: LD (LASTCH),A ;UPDATE LAST CHARACTER POINTER
- LD (HL),A ;STORE HYPHEN
- INC HL
- INC C
- CALL GETCHR
- ISHYP0: CP CR OR 80H ;SOFT RETURN AFTER HYPHEN?
- JR NZ,HYPTST ;TEST FOR ANOTHER HYPHEN
- LD (LASTCH),A ;UPDATE LAST CHARACTER POINTER
- LD (HL),A ;STORE RETURN
- INC HL
- INC C
- CALL GETCHR
- LD B,A ;SAVE THE CHAR
- AND 07FH ;KILL PARITY BIT
- CP LF ;SOFT LINE FEED?
- LD A,B ;RESTORE CHAR
- JR NZ,HYPTST ;TEST FOR ANOTHER HYPHEN
- LD (LASTCH),A ;UPDATE LAST CHARACTER POINTER
- LD (HL),A ;STORE LF
- INC HL
- INC C
- CALL GETCHR
- ISHYP1: CP ' ' OR 80H ;ELIMINATE SOFT SPACES AT START OF LINE
- JR NZ,ISHYP0 ;TEST FOR REST OF WORD
- LD (LASTCH),A ;UPDATE LAST CHARACTER POINTER
- LD (HL),A ;STORE SPACE
- INC HL
- INC C
- CALL GETCHR
- JR ISHYP1 ;TEST FOR MORE SPACES
- NOTHYP: CALL LEGAL
- JR NZ,GETWR2 ;EXIT LOOP WHEN NOT WORD CHARACTER
- LD (LASTCH),A
- LD (HL),A
- INC HL
- INC C
- JR GETWR1
- GETWR2: LD (HL),0 ;MARK END OF WORD
- LD HL,(INPTR) ;DECREMENT POINT FOR INPUT BUFFER
- ;SO FIRST CHAR AFTER WORD IS KEPT
- DEC HL
- LD (INPTR),HL
- RET
-
- ;
- ; LEGAL -- Determines whether character is alphabetic, an apostrophe,
- ; or period for a dot command.
- ;
- ; Returns: Z flag set <-- characters was one of the above
- ; Z flag clear <-- was not one of the above
-
- LEGAL: LD B,A
- AND 05FH ;KILL PARITY AND LOWER CASE
- CP 'A' ;MUST BE GREATER THAN "A"
- JP C,LEGAL0
- CP 'Z'+1 ;GREATER THAN "Z"
- JP NC,LEGAL0
- LD A,B
- CP A ;SET ZERO FLAG
- RET
- LEGAL0: LD A,B
- AND 07FH ;KILL ONLY PARITY
- CP 27H ;"'"
- JR Z,LEGAL1
- LD A,(LASTCH) ;WAS LAST CHARACTER A LF?
- AND 7FH ;MASK PARITY
- CP LF
- JR NZ,LEGAL1
- LD A,B
- CP '.' ;ACCEPT PERIODS SO DOT COMMAND ACCEPTED
- LEGAL1: LD A,B
- RET
-
- ;
- ; GETCHR -- Read a character from an input file into a buffer. This routine
- ; is used for a number of different purposes. The file from which
- ; to read is patched into FILPAT. The buffer to which writes should
- ; occur is patched into BUFPAT-BUFPA2.
- ;
- ; Returns: A <-- next character from input file
-
- GETCHR: PUSH BC
- PUSH DE
- PUSH HL
- LD HL,(INPTR) ;POINTER FOR INPUT
- LD DE,INBUF+512 ;END OF INPUT BUFFER
- BUFPAT EQU $-2 ;PATCH FOR INPUT BUFFER
- XOR A ;CLEAR CARRY
- PUSH HL
- SBC HL,DE ;AT END OF BUFFER?
- POP HL
- JP Z,GETCH0 ;REFILL BUFFER
- LD A,(HL) ;GET THE CHARACTER
- INC HL ;INCREMENTED POINTER
- LD (INPTR),HL
- GETRET: POP HL
- POP DE
- POP BC
- RET
- GETCH0: LD HL,INBUF
- BUFPA0 EQU $-2 ;PATCH FOR INPUT BUFFER
- LD DE,128
- LD C,4
- GETCH2: PUSH BC
- PUSH DE
- PUSH HL
- LD A,EOF ;MARK WITH EOF IN CASE NO RECORD
- LD (HL),A
- LD D,H ;SET UP DMA ADDRESS FOR READ
- LD E,L
- LD C,SETDMA
- CALL BDOS ;SET DMA ADDRESS
- LD DE,IFCB
- FILPAT EQU $-2 ;FCB PATCH ADDRESS
- LD C,READ ;READ 128 BYTES OF INPUT FILE
- CALL BDOS
- POP HL
- POP DE
- POP BC
- CP 0 ;SUCCESS?
- JR NZ,GETCH3 ;JUMP IF EOF
- ADD HL,DE ;POINT TO NEXT RECORD ADDRESS
- DEC C
- JP NZ,GETCH2 ;LOOP FOR 4 RECORDS
- GETCH3: LD A,(INBUF) ;GET FIRST CHARACTER
- BUFPA1 EQU $-2 ;ANOTHER BUFFER PATCH
- LD (HL),EOF ;PUT EOF AT BEGINNING OF FIRST UNUSED
- ;RECORD IN MEMORY
- LD HL,INBUF+1
- BUFPA2 EQU $-2 ;AND YET ANOTHER BUFFER PATCH
- LD (INPTR),HL ;SET UP POINTER TO RECORDS
- JP GETRET
-
- ;
- ; CREWRD -- Converts the word in SRCWRD to a word in WORD. Parity bits
- ; are cleared, lower case is converted to upper case, and apostrophes
- ; that are not imbedded in words are discarded.
-
- CREWRD: LD HL,WORD ;POINTER TO DESINATION BUFFER
- LD DE,SRCWRD ;SOURCE BUFFER
- LD C,0
- CREWR0: LD A,(DE) ;GET A CHARACTER
- CP 0 ;END OF WORD?
- JP Z,CREWR2
- AND 07FH ;MASK PARITY
- CP 027H ;"'" CHARACTER?
- JR Z,CREWR3
- AND 05FH ;MASK PARITY AND CONVERT TO UPPER CASE
- CP 'A' ;IS IT ONLY A HYPHEN?
- JR C,CREWR1 ;IF SO, SKIP IT
- CREADD: INC C
- LD (HL),A ;PUT CHARACTER IN WORD BUFFER
- LD A,41 ;MAXIMUM OF 40 CHARACTERS IN WORD
- CP C
- RET Z ;WORD TOO LONG. ACCEPT IT
- INC HL
- CREWR1: INC DE
- JP CREWR0
- CREWR2: LD (HL),0 ;MARK END OF WORD
- LD HL,LASTC ;PUT NUMBER OF CHARACTERS IN LASTC
- DEC C ;C=NUMBER OF CHARACTERS - 1
- JP P,CREWS2 ;JUMP IF C WASN'T ALREADY 0
- INC C
- CREWS2: LD (HL),C
- RET
- CREWR3: LD A,0 ;IF FIRST CHARACTER IN WORD, IGNORE
- ;"'"
- CP C
- JR Z,CREWR1
- INC DE
- LD A,(DE) ;IF LAST CHAR IN WORD, IGNORE
- CP 0
- DEC DE
- JR Z,CREWR1
- LD A,27H ;OTHERWISE, KEEP "'"
- JR CREADD
-
- ;
- ; PUTCHR -- write a character to output file
- ;
- ; Input: A --> character to output
-
- PUTCHR: PUSH PSW
- PUSH BC
- PUSH DE
- PUSH HL
- LD HL,(OPOSS) ;GET CURRENT POSITION IN OBUFF
- LD (HL),A ;PUT CHARACTER IN BUFFER
- INC HL
- LD (OPOSS),HL ;UPDATE POINTER
- LD DE,OBUFF+512 ;AT END OF BUFFER?
- XOR A ;CLEAR CARRY
- SBC HL,DE
- JR Z,PUTCH0 ;WRITE OUT DATA IF END OF BUFFER
- PUTRET: POP HL
- POP DE
- POP BC
- POP PSW
- RET
- PUTCH0: LD C,4 ;LOOP COUNTER
- LD HL,OBUFF ;ADDRESS OF DATA
- LD DE,128 ;LENGTH OF EACH RECORD
- PUTCH1: PUSH BC
- PUSH DE
- PUSH HL
- LD D,H ;SET UP DMA ADDRESS
- LD E,L
- LD C,SETDMA
- CALL BDOS
- LD DE,OFCB ;WRITE RECORD TO OUTPUT FILE
- OUTPAT EQU $-2 ;PATCH ADDRESS FOR OUTPUT FILE FCB
- LD C,WRITE
- CALL BDOS
- CP 0 ;SUCCESS?
- JR NZ,PUTCH2 ;JUMP IF DISK FULL
- POP HL
- POP DE
- POP BC
- ADD HL,DE ;POINT TO NEXT RECORD
- DEC C
- JP NZ,PUTCH1 ;LOOP FOR 512 BYTE BUFFER
- LD HL,OBUFF ;RESET POINTER
- LD (OPOSS),HL
- CALL CTRLZ ;FILL BUFFER WITH EOF CHARACTER
- JP PUTRET ;RETURN
- PUTCH2: LD C,STROUT ;DISK FULL ERROR
- LD DE,DSKFUL
- CALL BDOS
- CALL BOOT ;GIVE UP
- DSKFUL: DB CR,LF,'Disk full -- aborting',CR,LF,'$'
-
- ;
- ; CTRLZ -- Fill the output buffer with EOF characters to prepare it for
- ; writing
-
- CTRLZ: LD HL,OBUFF ;BUFFER ADDRESS
- LD B,2 ;LOOP 256 BYTES 2 TIMES
- LD C,0
- CTRLZ0: LD (HL),EOF ;PUT EOF IN BUFFER
- INC HL
- DEC C ;FAST COUNTER
- JR NZ,CTRLZ0
- DEC B ;SLOW COUNTER
- JR NZ,CTRLZ0
- RET
-
- ;
- ; MEMWRD -- put word in WORD into memory. If word already exists in memory
- ; then its the address of its status byte is returned in DE. If the
- ; word is not found, the word is placed in memory and the pointers
- ; that alphabetize the words are updated. If memory is full, a
- ; 1 is returned in A. Otherwise 0 is returned in A.
-
- MEMWRD: LD BC,(SRTBOT) ;GET ADDRESS OF BOTTOM OF WORD POINTER
- LD DE,(SRTTOP) ;TOP OF WORD POINTER
- JR MEMSKP
- MEMWR0: POP HL
- POP DE
- POP BC
- JP M,MEMW00
- LD D,H ;MOVE HIGH POINTER DOWN
- LD E,L
- JR MEMSKP
- MEMW00: LD B,H ;MOVE LOW POINTER UP
- LD C,L
- MEMSKP: LD H,D ;HL IS POINTER TO RECORD BETWEEN DE AND
- LD L,E ;BC
- XOR A ;CLEAR CARRY
- SBC HL,BC
- LD A,0 ;IS BC+1=HL?
- CP H
- JP NZ,MEMWR1
- LD A,2
- CP L
- JP NZ,MEMWR1
- LD HL,(SRTTOP) ;UPDATE SRTTOP=SRTTOP+2
- INC HL
- INC HL
- LD (SRTTOP),HL
- XOR A ;CLEAR CARRY
- PUSH HL
- SBC HL,DE ;NUMBER OF BYTES IN TABLE TO MOVE
- LD B,H ;PUT NUMBER OF COUNTER FOR LDDR
- LD C,L
- POP HL
- PUSH DE ;SAVE THE ADDRESS FOR NEW WORD
- LD D,H ;PUT DESTINATION ADDRESS IN DE
- LD E,L
- DEC HL ;SOURCE IN HL
- DEC HL
- LDDR ;PUT A SPACE FOR NEW POINTER IN TABLE
- POP DE
- LD HL,(FREE) ;ADDRESS TO STORE NEW WORD
- EX DE,HL
- LD (HL),E ;STORE ADDRESS OF WORD IN TABLE
- INC HL
- LD (HL),D
- LD HL,WORD
- LD A,(LASTC) ;GET NUMBER OF CHARACTERS
- LD B,A
- INC B ;B = NUMBER OF CHARACTERS IN WORD + 1
- INC B
- MEMW01: LD A,(HL) ;GET A CHARACTER
- LD (DE),A ;PUT IT IN MEMORY
- DEC DE ;STORE WORD BACKWARDS
- INC HL ;NEXT CHAR IN WORD
- DJNZ MEMW01
- LD (FREE),DE ;UPDATE FREE MEMORY POINTER
- EX DE,HL
- LD DE,45 ;ALLOW ROOM FOR ANOTHER WORD
- XOR A ;CLEAR CARRY
- SBC HL,DE
- LD DE,(SRTTOP) ;POINTER TO TOP OF POINTER TABLE
- XOR A
- SBC HL,DE ;IS ANY MEMORY LEFT?
- JR C,MEMFUL ;IF NOT, NO MORE MEMORY
- LD A,0 ;INDICATE MEMORY LEFT
- RET
- MEMFUL: LD A,1 ;NO MEMORY LEFT
- RET
- MEMWR1: RRC L ;DIVIDE HL BY 2
- LD A,L
- AND 07EH ;MAKE IT EVEN
- LD L,A
- LD A,0
- RRC H
- ADC A,0 ;IF BIT 0 OF H SET, THEN C SET
- RRC A
- OR L
- LD L,A
- LD A,H
- AND 07FH
- LD H,A
- ADD HL,BC ;HL POINTS TO RECORD BETWEEN BC AND
- ;DE
- PUSH BC
- PUSH DE
- PUSH HL
- LD E,(HL) ;DE= ADDRESS OF COMPARISON WORD IN BUFF
- INC HL
- LD D,(HL)
- LD HL,WORD ;HL= ADDRESS OF NEW WORD BUFFER
- MEMWR2: LD A,(DE) ;GET A CHARACTER
- AND 07FH ;KILL CARRY (FOR 0 BYTE OF CORRECTED
- ;WORDS)
- CP (HL) ;COMPARE THEM
- JP NZ,MEMWR0 ;IF .NE. THEN TRY ANOTHER WORD
- LD A,0
- CP (HL) ;END OF WORD?
- DEC DE ;DECREMENT WORD TABLE POINTER (WORDS
- ;ARE STORED BACKWARDS
- INC HL ;INCREMENT POINTER (DON'T AFFECT
- ;FLAGS)
- JR NZ,MEMWR2
- POP HL
- POP BC ;TRASH OLD DE
- POP BC
- INC DE ;POINT TO 0 OR 080H AT END OF WORD
- ; (80H IS CORRECTED AND WORD FOUND)
- RET ;DON'T BOTHER TO BUFFER THE SAME WORD
-
- ;
- ; AUXDIC -- Open SPELL.DIC and load it into memory. Open FILE.UDC and load
- ; it as well. If FILE.ADD exists (wordstar dictionary addition file),
- ; load it and put its contents in FILE.UDC.
-
- AUXDIC: LD HL,NEXT ;ZERO THE MEMORY DICTIONARY
- LD A,0
- LD (HL),A
-
- AUXDI2: LD DE,FILD$$ ;MAKE TEMPORARY .DIC OUTPUT FILE
- LD C,DELETE
- CALL BDOS
- LD DE,FILD$$
- LD C,MAKE
- CALL BDOS
- LD HL,FILD$$ ;PATCH THIS FCB INTO OUTPUT ROUTINE
- LD (OUTPAT),HL
- LD A,(SAVPUT) ;MAKE PUTCHR: WRITE TO A FILE
- LD (PUTCHR),A
- LD DE,FILDIC ;TRY TO OPEN FILE.UDC
- LD C,OPEN
- CALL BDOS
- CP 0FFH ;FOUND?
- JP Z,AUXDI4 ;JUMP IF NOT
- LD HL,FILDIC ;PATCH GETCHR: TO READ FROM THIS FILE
- LD (FILPAT),HL
- LD HL,INBUF+512 ;PATCH INPTR TO READ ON FIRST CALL
- LD (INPTR),HL
- AUXDI3: CALL GETWRD ;GET A WORD INTO SRCWRD:
- JP Z,AUXDI4 ;IF EOF THEN START CHECKING
- CALL CREWRD ;CREATE WORD FROM SRCWRD:
- LD A,0 ;IS IT AT LEAST 2 CHARS LONG?
- CP C
- JR Z,AUXDI3 ;FORGET IT IF NOT
- LD A,41 ;IF LONGER THAN 40, ALSO FORGET IT
- CP C
- JR Z,AUXDI3
- PUSH HL
- LD HL,(FILUDC) ;INCREMENT COUNTER FOR WORDS OUTPUT
- INC HL ; TO FILE.UDC
- LD (FILUDC),HL
- POP HL
- CALL SAVWRD ;PUT WORD IN MEMORY
- LD HL,WORD ;PUT WORD IN OUTPUT FILE
- AUXDH3: LD A,(HL) ;GET A CHARACTER
- CP 0 ;END OF WORD?
- JR Z,AUXDI3 ;QUIT OUTPUT IF END
- CALL PUTCHR ;OUTPUT CHARACTER
- INC HL
- JR AUXDH3
-
- AUXDI4: LD DE,FILADD ;TRY TO OPEN FILE.ADD
- LD C,OPEN
- CALL BDOS
- CP 0FFH ;FOUND?
- JP Z,AUXDI7 ;RETURN IF NOT
- LD HL,FILADD ;PATCH GETCHR: TO READ FROM FILE.ADD
- LD (FILPAT),HL
- LD HL,INBUF+512 ;SET INPTR TO READ ON FIRST CALL
- LD (INPTR),HL
- LD A,CR ;PUT CR LF IN OUTPUT FILE
- CALL PUTCHR
- LD A,LF
- CALL PUTCHR
- AUXDI5: CALL GETCHR ;GET A CHARACTER FROM FILE.ADD
- ;IGNORE ALL WORD TYPES EXCEPT 0FFH
- ;(EOF)
- CP 0FFH ;END OF WORDS IN CURRENT RECORD?
- JR Z,AUXDI5 ;IF YES, LOOP THROUGH RECORD
- CP 0 ;ZERO USED AS FILLER CHARACTER?
- JP Z,AUXDI5
- CP EOF ;EOF?
- JP Z,AUXDI7
- CALL GETCHR ;THIS CHARACTER IS LENGTH OF WORD
- CP 0 ;NO CHARACTERS?
- JR Z,AUXDI5
- LD B,A
- LD HL,WORD ;BUFFER IT IN WORD
- AUXDI6: CALL GETCHR ;GET A CHARACTER
- LD (HL),A ;SAVE IT IN WORD:
- INC HL
- DJNZ AUXDI6 ;GET WHOLE WORD
- LD A,0 ;MARK END OF WORD
- LD (HL),A
- CALL SAVWRD ;PUT WORD IN MEMORY
- JP Z,AUXDI5 ;IF WORD ALREADY IN MEMORY THEN DON'T
- ;OUTPUT TO FILE.UDC
- PUSH HL
- LD HL,(FILUDC) ;INCREMENT COUNTER FOR WORDS OUTPUT
- INC HL ; TO FILE.UDC
- LD (FILUDC),HL
- POP HL
- LD HL,WORD ;OUTPUT WORD
- AUXDH6: LD A,(HL) ;GET A CHARACTER
- INC HL
- CP 0 ;END?
- JR Z,AUXDK6
- CALL PUTCHR
- JR AUXDH6
- AUXDK6: LD A,CR ;PUT CR LF IN OUTPUT FILE
- CALL PUTCHR
- LD A,LF
- CALL PUTCHR
- JP AUXDI5 ;GET ANOTHER CHARACTER
-
- AUXDI7: LD HL,OBUFF ;WRITE OUT REMAINING DATA IN BUFFER
- LD DE,128
- AUXDI8: LD A,EOF ;DONE?
- CP (HL)
- JR Z,AUXDJ0
- PUSH DE
- PUSH HL
- LD D,H ;SET UP DMA ADDRESS
- LD E,L
- LD C,SETDMA
- CALL BDOS
- LD DE,FILD$$ ;WRITE 128 BYTES TO FILE
- LD C,WRITE
- CALL BDOS
- POP HL
- POP DE
- CP 0 ;ERROR?
- JR NZ,AUXDI9 ;DISK FULL --> BRANCH
- ADD HL,DE ;POINT TO NEXT RECORD
- JR AUXDI8
- AUXDI9: LD C,STROUT ;DISK FULL
- LD DE,DSKFUL ;DISK FULL MESSAGE (SEE PUTCHR)
- CALL BDOS
- CALL BOOT
-
- AUXDJ0: CALL RDICT ;READ SPELL.DIC
- LD HL,BOOT+81H ;POINT TO INPUT LINE BUFFER
- LD A,(BOOT+80H) ;NUMBER OF CHARACTERS
- LD B,A
- LD A,' ' ;LOOK FOR A SPACE TO INDICATE END OF
- ;INPUT FILE NAME
- AUXDJ1: CP (HL)
- JR Z,AUXDJ2 ;EXIT LOOP IF SPACE
- INC HL ;NEXT CHARACTER
- DJNZ AUXDJ1 ;LOOP WHILE CHARACTERS LEFT
- JR AUXRET ;NOTHING AFTER FILE. JUST RETURN.
- AUXDJ2: LD A,'$' ;NOW LOOK FOR $ TO INDICATE MORE DICTS.
- AUXDJ3: CP (HL)
- JR Z,AUXDJ4 ;EXIT LOOP IF FOUND
- INC HL
- DJNZ AUXDJ3 ;CONTINUE WHILE CHARACTERS LEFT
- JR AUXRET ;NOT FOUND
- AUXDJ4: LD A,' ' ;ELMINATE SPACES
- INC HL ;SKIP '$'
- DJNZ AUXDJ5 ;CONTINUE IF CHAR LEFT
- JR AUXRET
- AUXDJ5: CP (HL)
- JR NZ,AUXDJ6 ;STOP IF NOT SPACE
- INC HL
- DJNZ AUXDJ5
- JR AUXRET ;DONE IF JUST SPACES
- AUXDJ6: LD A,0
- LD (SPLDIC),A ;USE DEFAULT DRIVE
- LD DE,SPLDIC+1 ;FCB BUFFER TO USE
- LD A,' ' ;NULL FILE NAME (SPACES)
- PUSH BC
- LD B,8 ;FIRST DO FILENAME, NOT EXTENSION
- AUXDJ7: LD (DE),A
- INC DE ;CLEAR ENTIRE FILENAME
- DJNZ AUXDJ7
- LD DE,SPLDIC+12 ;GET REST OF FCB
- LD B,24
- LD A,0 ;ZERO REST OF FCB
- AUXDJ8: LD (DE),A
- INC DE
- DJNZ AUXDJ8
- POP BC
- LD DE,SPLDIC+1 ;POINT TO FCB
- LD C,0 ;NO CHARACTERS WRITTEN TO FCB YET
- LD A,2 ;ARE AT LEAST 3 CHAR LEFT?
- CP B
- JP NC,AUXDJ9 ;IF NOT, CAN'T BE A DRIVE SPECIFIED
- INC HL
- LD A,(HL) ;SEE IF NEXT CHAR IS A ':'
- DEC HL
- CP ':'
- JR NZ,AUXDJ9 ;JUMP IF NO DRIVE SPECIFIED
- LD A,(HL) ;GET THE DRIVE
- INC HL ;POINT TO NEXT CHAR AFTER :
- INC HL
- DEC B
- DEC B
- AND 11011111B ;MAKE SURE IT'S UPPER CASE
- SUB 'A'-1 ;MAKE DRIVE NUMBER BASED AT 0
- LD (SPLDIC),A ;STORE IT IN FCB
- AUXDJ9: LD A,(HL) ;GET A CHARACTER
- CP ' ' ;END OF FILENAME?
- JR Z,AUXDK2 ;READ THE FILE
- CP '.' ;PERIOD? DISCARD EXTENSION IF YES.
- JR Z,AUXDK0
- LD (DE),A ;FCB IT
- INC DE
- INC C
- LD A,8 ;8 CHARACTERS WRITTEN YET?
- CP C
- JR Z,AUXDK0
- INC HL
- DJNZ AUXDJ9
- JR AUXDK2 ;READ THE FILE
- AUXDK0: LD A,' ' ;SEARCH FOR SPACE TO END FILENAME
- ;DISCARD EXTRA CHARACTERS
- AUXDK1: CP (HL)
- JR Z,AUXDK2
- INC HL ;TRY NEXT CHAR
- DJNZ AUXDK1
- AUXDK2: DEC HL ;POINT TO CHAR BEFORE END OR SPACE
- INC B ;1 MORE LEFT NOW
- CALL RDICT ;READ FROM THE DICTIONARY
- JP AUXDJ4 ;TRY FOR ANOTHER DICTIONARY
-
- AUXRET: LD DE,FILD$$ ;CLOSE TEMPORARY FILE
- LD C,CLOSE
- CALL BDOS
- LD HL,OFCB ;PATCH PUTCHR: TO OUTPUT TO FILE.$$$
- LD (OUTPAT),HL
- LD A,0C9H ;RETURN OPCODE
- LD (PUTCHR),A ;MAKE PUTCHR: DO NOT OUTPUT
- CALL CTRLZ ;CLEAR OUTPUT BUFFER
- LD HL,OBUFF ;CLEAR OUTPUT BUFFER POSITION
- LD (OPOSS),HL
- LD HL,(FREE) ;GET ADDRESS OF NEXT FREE BYTE
- INC HL
- LD (SRTBOT),HL ;POINT TO TABLE FOR INPUT FILE INDEX
- INC HL
- INC HL
- LD (SRTTOP),HL ;TOP OF TABLE
- LD HL,(BDOS+1) ;GET ADDRESS OF BDOS
- DEC HL ;POINT TO FREE MEMORY
- LD (FREE),HL
- LD HL,INBUF+512
- LD (INPTR),HL ;SET INPUT FILE POINTER TO READ RECORD
- ;ON NEXT GETCHR: CALL
- CALL CTRLZ ;CLEAN OUTPUT FILE BUFFER
- LD A,LF ;RESET LASTCH FOR INPUT
- LD (LASTCH),A
- LD DE,UDCMSG ;OUTPUT: "Words read from...FILE.UDC"
- LD C,STROUT
- CALL BDOS
- LD HL,(FILUDC) ;NUMBER OF WORDS WRITTEN
- LD B,H ;GOES IN BC
- LD C,L
- LD HL,FILD$$ ;FCB ADDRESS IN HL
- LD A,'U' ;CHANGE 'FILENAME.D$$' TO '.UDC'
- LD (FILD$$+9),A
- LD A,'D'
- LD (FILD$$+10),A
- LD A,'C'
- LD (FILD$$+11),A
- CALL TYPFIL ;WRITE FILENAME AND # TO CONSOLE
- LD A,'D' ;CHANGE IT BACK TO '.D$$'
- LD (FILD$$+9),A
- LD A,'$'
- LD (FILD$$+10),A
- LD (FILD$$+11),A
- RET
- UDCMSG: DB CR,LF,'Words written to dictionary $'
-
- ;
- ; RDICT - Read dictionary in SPLDIC FCB
- ;
- RDICT: PUSH PSW
- PUSH BC
- PUSH DE
- PUSH HL
- LD HL,INBUF+512
- LD (INPTR),HL ;SET INPUT FILE POINTER TO READ RECORD
- ;ON NEXT GETCHR CALL
- LD HL,0
- LD (SPLDC),HL ;RESET # WORDS READ
- LD DE,SPLDIC ;FCB FOR SPELL.DIC
- LD C,OPEN
- CALL BDOS
- PUSH PSW
- LD C,CURDSK ;GET THE DEFAULT DRIVE BEFORE ITS
- CALL BDOS ; TOO LATE
- INC A
- LD (DEFDRV),A
- POP PSW
- CP 0FFH ;FOUND?
- JR NZ,RDICT0 ;YES, READ FROM IT
- LD A,(SPLDIC) ;WAS DEFAULT DRIVE TESTED?
- CP 0
- JR NZ,RDICT2 ;IF SPECIFIC DRIVE TESTED AND NOT
- ;FOUND THEN GIVE UP
- LD A,1 ;TRY DRIVE "A"
- LD (SPLDIC),A
- LD DE,SPLDIC
- LD C,OPEN
- CALL BDOS
- CP 0FFH ;FOUND?
- JP Z,RDICT2 ;IF NOT, GIVE UP
- RDICT0: LD HL,SPLDIC ;PATCH FCB ADDRESS INTO GETWRD
- LD (FILPAT),HL
- RDICT1: CALL GETWRD ;GET A WORD INTO SRCWRD:
- JP Z,RDICT3 ;IF EOF THEN START CHECKING
- CALL CREWRD ;CREATE WORD FROM SRCWRD:
- LD A,0 ;IS IT AT LEAST 2 CHARS LONG?
- CP C
- JR Z,RDICT1 ;FORGET IT IF NOT
- LD A,41 ;IF LONGER THAN 40, ALSO FORGET IT
- CP C
- JR Z,RDICT1
- PUSH HL
- LD HL,(SPLDC) ;INCREMENT COUNTER FOR WORDS IN
- INC HL ; SPELL.DIC
- LD (SPLDC),HL
- POP HL
- CALL SAVWRD ;PUT WORD IN MEMORY
- JR RDICT1
-
- RDICT2: LD DE,RNT ;PRINT CR,LF
- LD C,STROUT
- CALL BDOS
- LD A,(SPLDIC) ;DEFAULT DRIVE USED?
- CP 0
- JR NZ,RDICU0 ;JUMP IF NOT
- LD A,(DEFDRV) ;GET DEFAULT DRIVE
- LD (SPLDIC),A ;AND PUT IT IN FCB
- RDICU0: LD A,(SPLDIC) ;GET DRIVE
- ADD A,'A'-1 ;MAKE IT A LETTER
- LD C,CONOUT
- LD E,A
- CALL BDOS ;PRINT DRIVE NAME
- LD E,':'
- LD C,CONOUT
- CALL BDOS ;AND A COLON
- LD DE,SPLDIC+1 ;POINT TO FILENAME
- LD HL,SPLDIC+12 ;POINT TO FIRST BYTE AFTER NAME
- LD A,'$'
- LD (SPLDIC+12),A ;MARK END FOR OUPTUT
- LD C,STROUT
- CALL BDOS ;PRINT THE FILE NAME
-
- LD DE,RNT0 ;PRINT NOT FOUND
- LD C,STROUT
- CALL BDOS
- JR RDICTR
- RNT: DB CR,LF,'$'
- RNT0: DB ' not found$'
-
- RDICT3: LD DE,RDIWRD ;FOUND MESSAGE
- LD C,STROUT
- CALL BDOS
- LD HL,(SPLDC) ;STORE # WORDS READ IN BC
- LD B,H
- LD C,L
- LD HL,SPLDIC ;FCB ADDRESS
- CALL TYPFIL ;TYPE FILE NAME AND # WORDS IN IT
- JR RDICTR
- RDIWRD: DB CR,LF,'Words read from dictionary $'
-
- RDICTR: POP HL
- POP DE
- POP BC
- POP PSW
- RET
-
- ;
- ; TYPFIL -- print name of dictionary file being read and words found in it
- ;
- ; Input: BC --> Number of words found in file
- ; HL --> Address of file's FCB
- ;
- TYPFIL: PUSH PSW
- PUSH BC
- PUSH DE
- PUSH HL
- LD A,(HL) ;DEFAULT DRIVE USED?
- CP 0
- JR NZ,TYPFI0 ;JUMP IF NOT
- LD A,(DEFDRV) ;GET DEFAULT DRIVE
- LD (HL),A ;AND PUT IT IN FCB
- TYPFI0: LD A,(HL) ;GET DRIVE
- ADD A,'A'-1 ;MAKE IT A LETTER
- PUSH BC
- PUSH HL
- LD C,CONOUT
- LD E,A
- CALL BDOS ;PRINT DRIVE NAME
- LD E,':'
- LD C,CONOUT
- CALL BDOS ;AND A COLON
- POP HL
- LD D,H
- LD E,L
- INC DE ;POINT TO FILENAME
- LD BC,12
- ADD HL,BC ;HL POINTS TO END OF FILENAME
- LD A,'$'
- LD (HL),A ;MARK END FOR OUPTUT
- LD C,STROUT
- CALL BDOS ;PRINT THE FILE NAME
- LD DE,TYPSPA ;PRINT SPACES AFTER NAME
- LD C,STROUT
- CALL BDOS
- POP BC
- LD H,B ;NUMBER OF WORDS FOUND
- LD L,C
- CALL DECOUT ;PRINT NUMBER
- POP HL
- POP DE
- POP BC
- POP PSW
- RET
- TYPSPA: DB ': $'
-
- ;
- ; SAVWRD -- put WORD in memory dictionary
- ;
-
- SAVWRD: CALL USRTST ;WAS WORD ALREADY MARKED?
- CP 1
- RET Z ;RETURN WITH Z SET IF ALREADY MARKED
- LD HL,(FREE) ;GET NEXT AVAILABLE BYTE
- LD DE,WORD ;POINT TO WORD
- SAVWR0: LD A,(DE) ;GET A CHARACTER
- LD (HL),A ;STORE IT IN BUFFER
- INC DE ;INCREMENT POINTERS
- INC HL
- CP 0 ;END OF WORD?
- JR NZ,SAVWR0
- LD (HL),A ;MARK END OF TABLE WITH 0
- LD (FREE),HL ;UPDATE FREE MEMORY POINTER
- LD A,1
- AND A ;MAKE FOR Z NOT SET
- RET
-
- ;
- ; WRDTST -- Search for WORD in dictionary. If it is not found, try
- ; stripping of suffixes and looking for new word with a flag set.
- ;
- ; Returns in A: 0 <-- WORD not found
- ; 1 <-- WORD found
- ; 2 <-- root word found but necessary
- ; suffix flag not set. Returned
- ; only if suffixes were stripped.
-
- WRDTST: PUSH BC
- PUSH DE
- PUSH HL
- LD HL,0
- LD (FLAG),HL ;NO FLAGS FOR FIRST LOOKUP
- CALL FINDIT ;LOOK FOR WORD IN DICTIONARY
- PUSH PSW
- LD A,1 ;ASSUME THAT WORD WAS FOUND AND
- ;INDICATE WORKING IN ALPHABETICAL ORDER
- ;STILL (DECODING OF CURRENT RECORD
- ;BY LOOKUP ROUTINE CAN CONTINUE FROM
- ;CURRENT POSITION)
- LD (ALPHA),A
- POP PSW
- CP 0 ;NOT FOUND?
- JP Z,WRDTS0 ;KEEP TRYING IF NOT FOUND
- WRDRET: POP HL
- POP DE
- POP BC
- RET
-
- WRDTS0: CALL USRTST ;TEST USER DICTIONARY
- CP 1 ;FOUND?
- JP Z,WRDRET
- LD A,0 ;NOT WORKING IN ALPHABETICAL ORDER
- ;ANY MORE
- LD (ALPHA),A
- LD HL,LASTC ;PUT NUMBER OF CHARACTERS -1 IN C
- LD C,(HL)
- LD B,0 ;MAKE BC AN OFFSET TO LAST CHAR
- LD HL,WORD ;POINT TO WORD
- ADD HL,BC ;POINT TO LAST CHARACTER IN WORD
- LD A,(HL)
- QISIT 'E',FLGV ;WORD ENDS IN "E"
- QISIT 'H',FLGH ;"H"
- QISIT 'Y',FLGY ;"LY"
- QISIT 'G',FLGG ;"ING"
- QISIT 'N',FLGN ;"TION, "EN"
- QISIT 'D',FLGD ;"ED", "IED"
- QISIT 'T',FLGT ;"EST", "IEST"
- QISIT 'R',FLGR ;"ER", "IER"
- QISIT 'S',FLGS ;LOTS OF WORDS ENDING IN "S"
- LD A,0
- JP WRDRET ;NO FLAGS FIT
-
- FLGV: LD A,2 ;WORD MUST BE 4 CHARS LONG
- CP C
- JP P,WRDNOT ;NOT FOUND IF TOO SHORT
- LD DE,VFLAG ;LOOKING FOR V FLAG
- LD (FLAG),DE
- DEC HL ;CHARACTER BEFORE
- ISIT 'V'
- DEC HL
- ISIT 'I'
- LD (HL),'E' ;GET "CREATIVE"
- INC HL
- LD (HL),0
- CALL FINDIT
- CP 0 ;FOUND?
- JP NZ,WRDRET ;BRANCH IF FOUND
- DEC HL ;POINT TO CHAR BEFORE NEW "E"
- DEC HL
- JISIT 'E',WRDNOT ;KILL "CREATEIVE"
- INC HL
- LD (HL),0
- CALL FINDIT
- JP WRDRET
-
- FLGH: LD A,2 ;MUST BE 4 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,HFLAG ;SEEKING WORD WITH H FLAG SET
- LD (FLAG),DE
- DEC HL
- ISIT 'T'
- DEC HL
- JISIT 'Y',WRDNOT ;KILL "TWENTYTH"
- INC HL
- LD (HL),0 ;NEW END OF WORD
- CALL FINDIT ;GET "HUNDREDTH"
- CP 0 ;FOUND?
- JP NZ,WRDRET ;RETURN IS FOUND
- LD A,4 ;WORDS WITH "IETH" MUST BE 6 CHARS LONG
- CP C
- JP P,WRDNOT
- DEC HL
- ISIT 'E'
- DEC HL
- ISIT 'I'
- LD (HL),'Y' ;MODIFY WORD TO END IN "Y"
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "TWENTIETH"
- JP WRDRET
-
- FLGY: LD A,2 ;MUST BE 4 CHARACTERS LONG (AT LEAST)
- CP C
- JP P,WRDNOT
- LD DE,YFLAG ;WORDS MUST HAVE Y FLAG SET
- LD (FLAG),DE
- DEC HL
- ISIT 'L'
- LD (HL),0 ;MARK NEW END OF WORD
- CALL FINDIT ;GET "QUICKLY"
- JP WRDRET
-
- FLGG: LD A,2 ;MUST BE AT LEAST 4 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,GFLAG ;SET G FLAG
- LD (FLAG),DE
- FLGGE: DEC HL
- ISIT 'N'
- DEC HL
- ISIT 'I'
- LD (HL),'E'
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "FILING"
- CP 0
- JP NZ,WRDRET ;RETURN IF FOUND
- DEC HL
- DEC HL
- JISIT 'E',WRDNOT ;KILL "FILEING"
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "CROSSING"
- JP WRDRET
-
- FLGN: LD A,2 ;MUST BE 4 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,NFLAG ;SET N FLAG
- LD (FLAG),DE
- FLGNEE: DEC HL
- JISIT 'O',FLGNO ;WORD WITH "TION"
- ISIT 'E' ;IF .EQ. "TION" THEN .EQ. "EN"
- DEC HL
- JISIT 'E',WRDNOT ;KILL "CREATEEN"
- JISIT 'Y',WRDNOT ;KILL "MULTIPLYEN"
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "FALLEN"
- JP WRDRET
- FLGNO: LD A,3 ;MUST BE 4 CHARS LONG
- CP C
- JP P,WRDNOT
- DEC HL
- ISIT 'I'
- LD (HL),'E'
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "CREATION"
- CP 0
- JP NZ,WRDRET ;RETURN IF FOUND
- LD A,7 ;MUST BE AT LEAST 9 CHARS LONG
- CP C
- JP P,WRDNOT
- DEC HL
- DEC HL
- ISIT 'T'
- DEC HL
- ISIT 'A'
- DEC HL
- ISIT 'C'
- DEC HL
- ISIT 'I'
- LD (HL),'Y'
- INC HL
- LD (HL),0
- CALL FINDIT
- JP WRDRET
-
- FLGD: LD A,2 ;MUST BE 4 CHARACTERS LONG
- CP C
- JP P,WRDRET
- LD DE,DFLAG ;SET D FLAG
- LD (FLAG),DE
- FLGDE: DEC HL
- ISIT 'E'
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "CREATED"
- CP 0
- JP NZ,WRDRET
- DEC HL
- DEC HL
- JISIT 'E',WRDNOT ;KILL "CREATEED"
- LD A,(HL)
- CP 'Y' ;IF .NE. "Y" TRY OTHER SUFFIXES
- JP NZ,FLGD5
- DEC HL
- CALL VOWEL ;VOWEL MUST BE BEFORE "Y"
- JP NZ,WRDNOT
- INC HL
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "CONVEYED"
- JP WRDRET
- FLGD5: INC HL
- LD (HL),0
- CALL FINDIT ;GET "CROSSED"
- CP 0
- JP NZ,WRDRET ;RETURN IF FOUND
- DEC HL
- ISIT 'I'
- DEC HL
- CALL VOWEL ;CAN'T BE A VOWEL
- JP Z,WRDNOT
- INC HL
- LD (HL),'Y'
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "IMPLIED"
- JP WRDRET
-
- FLGT: LD A,2 ;MUST BE AT LEAST 4 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,TFLAG ;T FLAG MUST BE SET
- LD (FLAG),DE
- DEC HL
- JISIT 'S',FLGDE ;SAME RULES AS 'D' FLAG IF ENDS
- ;IN "ST"
- JP WRDNOT ;NOT FOUND IF NOT "ST"
-
- FLGR: LD A,2 ;MUST BE AT LEAST 4 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,RFLAG ;SET R FLAG
- LD (FLAG),DE
- FLGRE: JP FLGDE ;SAME RULES AS D FLAG
-
- FLGS: LD A,2 ;MUST BE 4 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,SFLAG ;TRY PURE "S" FLAG FIRST
- LD (FLAG),DE
- DEC HL
- JISIT 'S',FLGP ;"NESS", "INESS"
- JISIT 27H,FLGM ;"'S"
- CALL SXZH ;IS IT S, X, Z OR H?
- JP Z,WRDNOT ;IF YES, THEN ILLEGAL WORD
- LD A,(HL) ;PURE "S" LEGAL IF .NE. "Y"
- CP 'Y'
- JR NZ,FLGS2
- DEC HL
- CALL VOWEL
- JP NZ,WRDNOT ;ILLEGAL WORD IF NOT A VOWEL
- INC HL
- FLGS2: INC HL
- LD (HL),0
- CALL FINDIT ;GET "CONVEYS", "BATS"
- CP 0
- JP NZ,WRDRET ;RETURN IF FOUND
- DEC HL
- LD A,(HL)
- QISIT 'R',FLGZ ;"ERS", "IERS"
- QISIT 'N',FLGX ;"IONS", "ICATIONS", "ENS"
- QISIT 'G',FLGJ ;"INGS"
- ISIT 'E'
- DEC HL
- CALL SXZH
- JP NZ,FLGS5 ;IF LETTER NOT S,X,Z OR H TRY "IES"
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "FIXES"
- JP WRDRET
- FLGS5: ISIT 'I'
- DEC HL
- CALL VOWEL
- JP Z,WRDNOT ;CAN'T BE A VOWEL
- INC HL
- LD (HL),'Y'
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "IMPLIES"
- JP WRDRET
-
- FLGX: LD DE,XFLAG ;SET X FLAG
- LD (FLAG),DE
- JP FLGNEE ;SAVE AS "N" FLAG NOW
-
- FLGJ: LD DE,JFLAG ;SET J FLAG
- LD (FLAG),DE
- JP FLGGE ;SAVE AS "G" FLAG NOW
-
- FLGZ: LD DE,ZFLAG ;SET Z FLAG
- LD (FLAG),DE
- JP FLGRE ;SAVE AS "R" FLAG NOW
-
- FLGP: LD A,3 ;MUST BE 5 CHARS LONG
- CP C
- JP P,WRDNOT
- LD DE,PFLAG ;SET P FLAG
- LD (FLAG),DE
- DEC HL
- ISIT 'E'
- DEC HL
- ISIT 'N'
- DEC HL
- LD A,(HL)
- CP 'Y'
- JP NZ,FLGP4 ;LEGAL IF .NE. "Y"
- DEC HL
- CALL VOWEL
- JP NZ,WRDNOT ;ILLEGAL IF "Y" AND NO VOWEL
- INC HL
- FLGP4: INC HL
- LD (HL),0
- CALL FINDIT ;GET "LATENESS", "GRAYNESS"
- CP 0
- JP NZ,WRDRET ;RETURN IF FOUND
- DEC HL
- ISIT 'I'
- DEC HL
- CALL VOWEL
- JP Z,WRDNOT ;CAN'T BE A VOWEL
- INC HL
- LD (HL),'Y'
- INC HL
- LD (HL),0
- CALL FINDIT ;GET "CLOUDINESS"
- JP WRDRET
-
- FLGM: LD DE,MFLAG ;SET M FLAG
- LD (FLAG),DE
- LD (HL),0
- CALL FINDIT ;GET "DOG'S"
- JP WRDRET
-
- WRDNOT: LD A,0 ;NOT FOUND
- JP WRDRET
- ;
- ; VOWEL -- determine whether character in (HL) is a vowel.
- ;
- ; Returns: Z flag SET <-- is a vowel
- ; Z flag CLEAR <-- is not a vowel
-
- VOWEL: PUSH BC
- PUSH HL
- LD A,(HL) ;GET CHARACTER
- LD HL,VOWELS ;POINTER TO VOWELS
- LD BC,5 ;5 VOWELS
- CPIR ;TEST AGAINST ALL VOWELS
- ;SET STATUS BITS TO BE USED AFTER RET
- POP HL
- POP BC
- RET
- VOWELS: DB 'AEIOU'
-
- ;
- ; SXZH -- same as VOWEL put for the characters S, X, Z and H
-
- SXZH: PUSH BC
- PUSH HL
- LD A,(HL) ;GET CHARACTER
- LD HL,SXZH0 ;POINTER TO CHARACTER LIST
- LD BC,4 ;4 POTENTIAL MATCHES
- CPIR ;TEST AGAINST S, X, Z, H
- POP HL
- POP BC
- RET
- SXZH0: DB 'SXZH'
-
- ;
- ; Determine which record of dictionary would contain WORD. Puts record in
- ; BC
-
- FINDIT: PUSH BC
- PUSH DE
- PUSH HL
- LD A,(ALPHA) ;STILL IN ALPHABETICAL ORDER?
- AND A
- JP NZ,FINLO5 ;DON'T DECREMENT POINTERS IF YES
-
- LD HL,(LSTADR) ;GET ADDRESS OF LAST DICTIONARY POINTER
- ;USED
- FINLOW: LD DE,WORD
- EX DE,HL
- LD BC,4
- FINLO1: LD A,(DE) ;MAKE SURE THAT CURRENT RECORD IS
- ;BEFORE WORD
- INC DE
- CPI
- JP M,FINLO5 ;IF EARLIER, JUMP
- JR NZ,FINLO2 ;IF LATER, THEN DECREMENT
- JP PE,FINLO1 ;LOOP WHILE BC-1 .NE. 0
- FINLO2: LD BC,(LSTREC) ;DECREMENT THE POINTERS
- DEC BC
- LD HL,0 ;IS IT TOO LOW?
- XOR A
- SBC HL,BC
- JR Z,FINLO5 ;IF SO, THEN FORGET IT
- LD (LSTREC),BC
- LD HL,(LSTADR)
- LD DE,4
- XOR A ;CLEAR CARRY
- SBC HL,DE
- LD (LSTADR),HL
- JP FINLOW ;TRY AGAIN
-
- FINLO5: LD BC,(LSTREC) ;GET LAST RECORD NUMBER READ
- LD HL,(LSTADR) ;GET ADDRESS OF LAST DICTIONARY POINTER
- ;USED
- FINDI0: PUSH BC
- PUSH HL
- LD DE,WORD
- EX DE,HL
- LD BC,4 ;COMPARING UP TO 4 CHARACTERS
- FINDI1: LD A,(DE) ;GET A CHARACTER FROM POINTER TABLE
- INC DE
- CPI ;COMPARE TO WORD:
- JR NZ,FINDI2 ;JUMP IF DIFFERENT
- JP PO,FINDI3 ;JUMP IF ALL 4 CHARACTERS EQUAL
- JR FINDI1 ;TRY ANOTHER
- FINDI2: JP P,FINDI3 ;TOO FAR IN DICTIONARY
- LD DE,4
- POP HL
- POP BC
- ADD HL,DE ;POINT TO NEXT RECORD INDEX
- INC BC
- JP FINDI0
- FINDI3: POP HL
- POP BC
- FINDI4: DEC BC
- LD DE,4
- XOR A ;CLEAR CARRY
- SBC HL,DE
- LD (LSTREC),BC ;UPDATE POINTERS
- LD (LSTADR),HL
-
- ;
- ; LOOKUP -- loop through as many records as it takes to be sure that word is
- ; not in dictionary
-
- LOOKUP: CALL DICFND
- CP 0FFH ;IF RETURN STATUS=0FFH THEN WORD COULD
- ;BE IN NEXT RECORD
- JR NZ,LOOKU0 ;RETURN IF NOT IN NEXT RECORD
- INC BC
- LD HL,0+(TABBOT-TABTOP)/4 ;MAKE SURE NOT PAST LAST RECORD
- XOR A ;CLEAR THE CARRY BIT
- SBC HL,BC
- JR NZ,LOOKUP ;TRY NEXT RECORD IF NOT AT END
- LD A,0
- LOOKU0: POP HL ;RESTORE THE STACK
- POP DE
- POP BC
- RET
-
- ;
- ; DICFND -- read record in BC from dictionary. Determine whether WORD is
- ; in it.
- ;
- ; Returns in A: 0 <-- word not found
- ; 1 <-- word found
- ; 2 <-- word found but flag not set
- ; 0FFH<-- word not found but it may be in next
- ; record
-
- DICFND: PUSH HL
- PUSH DE
- PUSH BC
- RLC B ;MULTIPLY BC BY 2 SO IT POINTS TO
- ;256 BYTE RECORD
- RLC C
- LD A,0
- ADC A,B ;GET THE CARRY FROM RLC C
- LD B,A
- LD A,C
- AND 0FEH ;KILL BIT 0
- LD C,A
- LD HL,(DICREC) ;GET THE CURRENT RECORD IN RAM
- DEC HL ;POINT TO FIRST 128 BYTES OF 256
- ;BYTE DICTIONARY RECORDS
- XOR A ;CLEAR CARRY BIT
- SBC HL,BC ;ATTEMPT TO READ THE SAME RECORD?
- JR NZ,DICDSK ;IF NO, READ FROM DISK
- LD A,(ALPHA) ;WORKING IN APHABETICAL ORDER?
- AND A
- JP NZ,DICFO1 ;JUST GET ANOTHER WORD IF YES
- LD A,(CURBIT) ;ROTATE CURRENT BYTE SO IT IS THE RIGHT
- ;POSITION IN CASE SAME RECORD USED
- AND 0111B ;IS IT ON CORRECT ROTATION NOW?
- JR Z,DICFN0
- LD HL,(CURBYT) ;ADDRESS OF CURRENT BYTE
- LD B,A
- LD A,8 ;MUST COMPLETE 8 ROTATIONS, TOTAL
- SUB B ;SUBTRACT NUMBER ALREADY DONE
- LD B,A
- ROTATE: RLC (HL)
- DJNZ ROTATE
- JP DICFN0 ;START TESTING WORDS
- DICDSK: PUSH BC
- LD (DICREC),BC ;NEW RECORD TO READ
- LD C,SETDMA ;SET DMA TO DICTIONARY BUFFER
- LD DE,DICBUF ;DICIONARY BUFFER IN RAM
- CALL BDOS
- LD C,RANREA ;BDOS RANDOM READ CODE
- LD DE,DICFCB ;FCB OF DICTIONARY
- CALL BDOS
- POP BC
- INC BC ;GET 256 BYTES
- LD (DICREC),BC ;NEXT RECORD NUMBER
- LD C,SETDMA ;DMA ADDRESS 256 BYTES HIGHER
- LD DE,DICBUF+128
- CALL BDOS
- LD C,RANREA
- LD DE,DICFCB
- CALL BDOS ;READ NEXT RECORD
-
- DICFN0: LD HL,DICBUF-1 ;INITIALIZE POINTER TO DICTIONARY
- ;BUFFER
- LD (CURBYT),HL
- LD A,0 ;CURRENT BIT=0
- LD (CURBIT),A
- DICFN1: CALL MOVWRD ;GET A WORD
- DICFO1: LD HL,WORD ;POINT TO WORD
- LD BC,DICWRD ;POINTER TO DICTIONARY WORD
- DICFN2: LD A,(BC) ;GET A LETTER FROM DICTIONARY WORD
- CP (HL) ;THE SAME?
- INC HL ;POINT TO NEXT CHARACTER
- INC BC
- JR NZ,DICFN4 ;IF NOT, TRY SOME MORE OR END
- CP 0 ;END OF WORD?
- JR NZ,DICFN2 ;TRY ANOTHER CHARACTER
- LD C,1 ;INDICATE WORD FOUND
- LD HL,(DICFL)
- LD A,(FLAG) ;GET FIRST FLAG
- CP 0 ;NO FLAG WANTED?
- JR Z,DICFN3 ;TRY NEXT BYTE OF FLAG IF NONE
- AND L
- CP 0 ;INDICATE WORD FOUND IF .NE. 0
- JR NZ,DICRET
- LD C,2 ;INDICATE MAIN WORD FOUND/NO FLAG
- JR DICRET
- DICFN3: LD A,(FLAG+1) ;TRY NEXT FLAG BYTE
- CP 0 ;NO FLAG WANTED?
- JR Z,DICRET ;IF NONE WANTED THEN WORD FOUND
- AND H
- CP 0 ;FOUND IF .NE. 0
- JR NZ,DICRET
- LD C,2 ;INDICATE MAIN WORD FOUND/NO FLAG
- JR DICRET
-
- DICFN4: JP M,DICFN1 ;IF TEST WORD IS EARLIER IN ALPHABET,
- ;TRY NEXT DICTIONARY WORD
- LD C,0 ;NOT FOUND
- ; JP DICRET
-
- DICRET: LD A,C ;PUT STATUS BYTE IN A
- POP BC
- POP DE
- POP HL
- RET
-
- ;
- ; MOVWRD -- read a word from the dictionary by decoding the flags.
- ;
- ; Returns: DICWRD <-- word from dictionary
-
- MOVWRD: LD A,0
- LD B,4
- CALL GETBIT ;GET 4 BITS INTO A
- LD HL,DICWRD ;POINT TO DICTIONARY WORD BUFFER
- LD B,0
- LD C,A ;NUMBER OF CHARACTERS TO KEEP
- ADD HL,BC
- MOVWR1: LD A,0
- LD B,3 ;GET FIRST 3 OF 5 BITS FOR CHARACTER
- CALL GETBIT ;BITS IN A
- CP 0111B ;IS IT AN END OF WORD MARK?
- JR Z,GETFLG ;GET THE FLAGS NOW
- LD B,2 ;GET REMAINING 2 BITS
- CALL GETBIT
- CP 0 ;IF ZERO THEN END OF RECORD
- JP Z,MOVMOR ;INDICATE MAY BE IN NEXT RECORD
- ADD A,40H ;MAKE IT ASCII
- CP 'Z'+1 ;IS IT AN ENCODED "'"?
- JR NZ,MOVWR4 ;JUMP IF NOT
- LD A,027H ;MAKE IT A "'"
- MOVWR4: LD (HL),A ;BUFFER THE CHARACTER
- INC HL
- JR MOVWR1 ;GET ANOTHER CHARACTER
- MOVMOR: LD C,0FFH ;INDICATE MAY BE IN NEXT RECORD
- POP DE ;GET USELESS RETURN WORD
- JP DICRET ;RETURN
-
- ;
- ; GETFLG -- read suffix flags from buffer.
- ;
- ; Returns: DICFL <-- 16 byte flag word
-
- GETFLG: LD A,0
- LD (HL),A ;MARK THE END OF THE WORD
- LD B,4 ;GET 4 BITS FOR NUMBER OF FLAGS VALUE
- CALL GETBIT
- LD B,A ;NUMBER OF BITS IN B
- LD HL,0
- CP 0 ;ARE ANY BITS THERE TO COPY?
- JP Z,GETFL8 ;RETURN IF NONE
- PUSH BC
- CP 8 ;MORE THAN 8 BITS?
- JP M,GETFL1 ;JUMP IF NOT
- LD B,7 ;GET 7 BITS FOR FIRST BYTE
- GETFL1: LD A,0
- CALL GETBIT
- POP BC
- LD L,A ;THIS IS THE LOW BYTE OF FLAGS
- LD A,B
- CP 8 ;GET MORE IF GREATER THAN 8 BITS
- JP P,GETFL4
- LD A,7 ;COMPUTE NUMBER OF ROTATIONS NECESSARY
- ;TO PUT IT IN THE RIGHT PLACE
- SUB B
- JP Z,GETFL8 ;IF EXACTLY 7 THEN DONE
- LD B,A ;COUNTER
- GETFL3: RLC L
- DJNZ GETFL3
- JP GETFL8 ;NO RETURN
- GETFL4: SUB 7 ;GET NUMBER OF BITS NEEDED FOR BYTE 2
- LD B,A
- LD A,0
- PUSH BC
- CALL GETBIT ;GET BIT FOR HIGH BYTE OF STATUS FLAG
- POP BC
- LD H,A ;SAVE HIGH BYTE
- LD A,7 ;COMPUTE NUMBER OF ROTATIONS LEFT
- SUB B
- JR Z,GETFL8 ;RETURN IF NONE
- LD B,A
- GETFL6: RLC H
- DJNZ GETFL6
- GETFL8: LD (DICFL),HL ;SAVE THE FLAG
- RET
-
- ;
- ; GETBIT -- read number of bits in B from dictionary buffer.
- ;
- ; Returns: A <-- byte value of B bits
-
- GETBIT: PUSH DE
- PUSH HL
- EX AF,AF' ;A HOLDS DESIRED DECODED BYTE.
- ;A' HOLD CURRENT BIT VALUE
-
- LD A,(CURBIT)
- LD HL,(CURBYT) ;ADDRESS OF CURRENT BYTE FOR OUTPUT
- LD D,(HL) ;D = CURRENT BYTE VALUE
- EX AF,AF'
- GETBI0: EX AF,AF' ;GET CURRENT BIT VALUE
- AND 0111B ;MASK 1ST THREE BITS
- JR NZ,GETBI1 ;IF .NE. 0 THEN NOT TIME TO INC CURBYT
- LD (HL),D ;RESTORE OLD BYTE TO ORIGINAL VALUE
- INC HL
- LD (CURBYT),HL
- LD D,(HL) ;UPDATE D = CURRENT BYTE VALUE
- GETBI1: INC A
- EX AF,AF' ;BACK TO DECODED BYTE
- RLC D ;MOVE BYTE SO NEXT BIT IN RIGHT PLACE
- RLC A ;MAKE A READY TO RECEIVE
- BIT 0,D ;IS THE BIT ON?
- JR Z,GETBI2 ;DON'T SET A IF IT ISN'T
- OR 1 ;SET BIT 1 OF A
- GETBI2: DJNZ GETBI0 ;LOOP THROUGH DESIRED NUMBER OF BITS
- EX AF,AF' ;GET CURRENT BIT
- LD (CURBIT),A ;UPDATE IT
- EX AF,AF'
- LD (HL),D ;UPDATE BYTE FOR NEXT CALL
- POP HL
- POP DE
- RET
-
- ;
- ; USRTST -- test user dictionary in memory for WORD.
- ;
- ; Returns in A: 0 <-- word not found
- ; 1 <-- word found
-
- USRTST: LD HL,NEXT ;BEGINNING OF USER DICTIONARY BUFFER
- LD A,0
- CP (HL) ;DOES ONE EXIST?
- RET Z ;CAN'T FIND ELEMENT OF AN EMPTY SET!
- LD DE,WORD ;ADDRESS OF WORD FOR COMPARING
- USRTS1: LD A,(DE) ;GET A CHARACTER
- CP (HL) ;ARE THEY THE SAME?
- JR NZ,USRTS2 ;IF NOT SAME, TRY ANOTHER WORD
- INC DE
- INC HL
- CP 0 ;END OF WORD?
- JR NZ,USRTS1 ;LOOP THROUGH WHOLE WORD
- LD A,1 ;FOUND IT!
- RET
- USRTS2: LD A,0
- USRTS3: CP (HL) ;LOOK FOR END OF WORD
- INC HL
- JR NZ,USRTS3
- CP (HL) ;IF NEXT BYTE ALSO 0 THEN END OF TABLE
- RET Z
- LD DE,WORD
- JR USRTS1 ;TEST ANOTHER WORD
-
- ;
- ; DECOUT - Output number in HL to console in decimal
- ;
-
- DECOUT: PUSH PSW
- PUSH BC
- PUSH DE
- PUSH HL
- LD B,0 ;B WILL BE 1 ONCE NON-ZERO CHAR OUTPUT
- LD DE,10000 ;START BY TRYING 10,000'S
- CALL NUMOUT ;OUTPUT A NUMBER
- LD DE,1000 ;1000'S
- CALL NUMOUT
- LD DE,100
- CALL NUMOUT
- LD DE,10
- CALL NUMOUT
- LD B,1 ;GUARANTEE THAT 0 WILL PRINT
- LD DE,1
- CALL NUMOUT
- POP HL
- POP DE
- POP BC
- POP PSW
- RET
-
- NUMOUT: LD C,0 ;COUNTER FOR NUMBER OF SUBTRACTIONS
- NUMOU0: INC C ;COUNT LOOPS THROUGH SUBTRACTION
- XOR A ;CLEAR CARRY
- SBC HL,DE ;SUBTRACT UNITS UNTIL CARRY
- JP NC,NUMOU0
- ADD HL,DE ;RESET TO LAST POSITIVE VALUE
- DEC C ;DON'T COUNT LAST SUBRTRACTION
- JR NZ,NUMOU1 ;IF NOT ZERO, THEN OUTPUT
- CP B ;ANYTHING OUTPUT YET?
- RET Z ;IF NOT, THEN DON'T PRINT A 0
- NUMOU1: LD B,1 ;INDICATE OUTPUT SENT
- LD A,C
- ADD A,'0' ;CONVERT TO ASCII
- LD E,A ;OUTPUT TO CONSOLE
- LD C,CONOUT ;CONSOLE OUTPUT CODE
- PUSH BC
- PUSH HL
- CALL BDOS
- POP HL
- POP BC
- RET
-
-
-
- INPTR: DW INBUF+512 ;POINTER TO CURRENT BYTE IN INPUT BUFF
- OPOSS: DW OBUFF ;POINTER TO CURRENT BYTE IN OUTPUT BUFF
- SRTBOT: DW NEXT ;POINTER TO BEGINNING OF MEMORY POINTER
- ;TABLE OF ALPHABETIZED WORDS FROM INPUT
- ;FILE
- SRTTOP: DW NEXT+2 ;POINTER TO TOP OF MEMORY POINTER TABLE
- FREE: DW NEXT ;POINTER TO NEXT FREE BYTE IN TPA
- LASTCH: DB LF ;LAST CHARACTER INDICATOR
- OLSTCH: DB LF ;BUFFER FOR OLD LAST CHARACTER WHEN
- ;MULTIPLE INPUT FCB'S IN USE
- SAVPUT: DS 1 ;BUFFER FOR NORMAL FIRST INSTRUCTION
- ;AT PUTCHR. USED WHILE OUTPUT IS
- ;DISABLED
- DICFL: DW 0 ;DICTIONARY FLAG FOR COMPARE
- CURBYT: DW DICBUF-1 ;CURRENT BYTE OF DICBUF (FOR GETBIT)
- CURBIT: DB 0 ;CURRENT BIT OF BYTE (FOR GETBIT)
- ALPHA: DB 0 ;0 IF NOT WORKING IN ALPHABETICAL
- ;ORDER (DID FLAG SEEK). 1 IF IN ORDER
- LSTREC: DW 1 ;RECORD NUMBER OF LAST DICTIONARY
- ;RECORD READ
- LSTADR: DW TABTOP+4 ;POINTER TO TABLE WHERE FIRST 4 BYTES
- ;OF LAST RECORD READ ARE FOUND
- OLDPTR: DW 0 ;POINTER FOR PASS 1 OF INPUT FILE IS
- ;SAVED HERE DURING PASS 2 IF ALL OF
- ;FILE DID NOT FIT IN MEMORY
- P2OPTR: DW P2BUF+512 ;POINTER FOR PASS2 OF INPUT FILE IS
- ;SAVED HERE DURING PASS 1 IF ALL OF
- ;FILE DID NOT FIT IN MEMORY
- STOPED: DB 0 ;IS 1 IF ALL OF FILE DID NOT FIT IN
- ;MEMORY
- MLTPAS: DB 0 ;SAME AS STOPED BUT NEVER RESET ONCE
- ;SET
- DEFDRV: DB 0 ;RECEIVES DEFAULT DRIVE VALUE
- SPLDC: DW 0 ;STORES NUMBER OF WORDS IN SPELL.DIC
- FILUDC: DW 0 ;STORES NUMBER OF WORDS WRITTEN TO
- ;FILE.UDC
- TOTWRD: DW 0 ;RECORDS TOTAL NUMBER OF WORDS IN DOC
- UNQWRD: DW 0 ;NUMBER OF UNIQUE WORDS IN DOC
- MISWRD: DW 0 ;NUMBER OF MISSPELLED WORDS
-
- OFCB: DB 0,' $$$' ;FCB FOR OUTPUT FILE
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- P2FCB: DB 0,' ' ;FCB FOR PASS 2 OF INPUT FILE
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- FILDIC: DB 0,' UDC' ;FCB FILE FILE.UDC
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- FILADD: DB 0,' ADD' ;FCB FOR FILE.ADD
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- FILD$$: DB 0,' D$$' ;FCB FOR TEMPORARY FILE FILE.D$$
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- SPLDIC: DB 0,'SPELL DIC' ;FCB FOR SPELL.DIC
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0,0,0,0
- DICFCB: DB 0,'DICT DIC' ;FCB FOR DICTIONARY FILE
- DB 0,0,0,0,0,0,0,0,0,0,0,0,0
- DB 0,0,0,0,0,0,0,0
- DICREC: DB 0,0,0 ;RECORD NUMBER FOR RANDOM READ
- ;(STILL PART OF FCB)
-
- STACK EQU $+50 ;STACK
- SRCWRD EQU STACK ;BUFFER FOR UNFIXED WORD
- WORD EQU SRCWRD+100 ;BUFFER FOR FIXED WORD
- DICWRD EQU WORD+41 ;BUFFER FOR WORDS READ FROM DICTIONARY
- FLAG EQU DICWRD+41 ;BUFFER FOR DESIRED DICTIONARY FLAG
- LASTC EQU FLAG+2 ;BUFFER FOR LAST CHARACTER READ
- DICBUF EQU LASTC+1 ;BUFFER FOR DICTIONARY RECORD
- INBUF EQU DICBUF+258 ;INPUT BUFFER FOR PASS 1
- P2BUF EQU INBUF+513 ;INPUT BUFFER FOR PASS 2
- OBUFF EQU P2BUF+513 ;OUTPUT BUFFER
- NEXT EQU OBUFF+513 ;ADDRESS OF NEXT FREE BYTE
- END START