home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / programs / spell / spell20.mac < prev    next >
Text File  |  1994-07-13  |  56KB  |  2,255 lines

  1. ;
  2. ; SPELL version 2.0        December 22, 1982
  3. ;
  4. ;    written by Michael C. Adler
  5. ;
  6. ;    History of SPELL's dictionary:
  7. ;    The first SPELL using this dictionary was probably written
  8. ;    by Ralph Gorin at Stanford.  It was transported to MIT by
  9. ;    Wayne Mattson.  Both the program at MIT and the dictionary
  10. ;    were most recently revised by William Ackerman.
  11. ;
  12. ;        Thanks to all for the effort spent desigining
  13. ;        the dictionary!
  14. ;                        -Michael
  15. ;
  16.     .Z80
  17.     TITLE    SPELL
  18. ;    JMP    START    <--Include this line if assembled under anything
  19. ;                but M80.
  20.  
  21.     DB    '(C) 1982 Michael C. Adler. '
  22.     DB    'This program has been released into the public domain '
  23.     DB    'by the author.  It may neither be sold for profit nor '
  24.     DB    'included in a sold software package without permission '
  25.     DB    'of the author.'
  26. ;
  27. ;    SPELL will compare words in a document to a dictionary
  28. ; and mark any words that are not found.  It is intended for use
  29. ; with WordStar's ^QL (Find Misspelling) command.  Words are marked
  30. ; with a preceding null if they are not found.
  31. ;
  32. ;    WARNING:  SPELL requires a Z80 processor.
  33. ;
  34. ;    MODIFICATION HISTORY:
  35. ;
  36. ;    2.0 - December 22, 1982  Michael Adler
  37. ;          -Bug fix:  modified to rename files correctly at end of
  38. ;           run if output drive is different from input drive.
  39. ;          -Bug fix:  modified to recognize hyphenated words in indented
  40. ;           text.
  41. ;          -Enhanced to allow user specified dictionaries on command
  42. ;           line.
  43. ;    1.3 - October 10, 1982  Michael Adler
  44. ;          -Bug fix:  crashed if number of unique words was multiple
  45. ;           of 256.
  46. ;    1.2 - October 8, 1982  Michael Adler
  47. ;          -Modified MEMWRD routine to store words backwards in
  48. ;           memory starting just below the BDOS.  Thus, maximum
  49. ;           memory is utilized since pointers to words and the words
  50. ;           grow toward each other.
  51. ;          -FILE.UDC is now deleted if it is empty.
  52. ;          -Added messages displaying number of words, number of
  53. ;           unique words, and number of words not found.
  54. ;    1.1 - August 28, 1982  Michael Adler
  55. ;          -Crashed if file.ADD had a zero length word.  Fixed.
  56. ;          -Fixed bug in AUXDIC:  stopped reading from .ADD file
  57. ;           when 0 encountered.
  58. ;          -Fixed compatability with WS R(un program).  WS initializes
  59. ;           byte at 6CH with default drive instead of 0.  Caused output
  60. ;           to be directed to wrong drive sometimes.
  61. ;          -Set SPELL to ignore lines starting with . because WS can't
  62. ;           handle misspelling markers in dot command lines.
  63. ;          -SPELL did not find hyphenated words if LF had parity bit
  64. ;           set.  Fixed.
  65. ;
  66. ;    1.0 - August 16, 1982  Michael Adler
  67. ;          -Released
  68. ;
  69.  
  70.  
  71.     INCLUDE    SPELL0.MAC
  72.  
  73. ERRCHR    EQU    0            ;THIS IS THE CHARACTER THAT MARKS
  74.                     ;UNFOUND WORDS.  FOR WordStar, IT
  75.                     ;MUST BE 0.  IF YOU ARE USING ANOTHER
  76.                     ;EDITOR, SET ERRCHR TO THE ASCII
  77.                     ;EQUIVALENT OF THE CHARACTER THAT
  78.                     ;SHOULD MARK MISSPELLED WORDS.
  79.  
  80.  
  81. BOOT    EQU    0000H
  82. BDOS    EQU    BOOT+0005H
  83. IFCB    EQU    BOOT+005CH
  84. TPA    EQU    BOOT+0100H
  85. CONOUT    EQU    2
  86. STROUT    EQU    9
  87. OPEN    EQU    15
  88. CLOSE    EQU    16
  89. DELETE    EQU    19
  90. READ    EQU    20
  91. WRITE    EQU    21
  92. MAKE    EQU    22
  93. RENAME    EQU    23
  94. CURDSK    EQU    25
  95. SETDMA    EQU    26            ;SET DMA ADDRESS
  96. RANREA    EQU    33            ;READ RANDOM
  97.  
  98. LF    EQU    10
  99. CR    EQU    13
  100. EOF    EQU    01AH            ;END OF FILE CHARACTER
  101. ;
  102. ;    The following are bit flags for the dictionary
  103. ;
  104. ZFLAG    EQU    1
  105. YFLAG    EQU    2
  106. RFLAG    EQU    4
  107. GFLAG    EQU    8
  108. DFLAG    EQU    16
  109. MFLAG    EQU    32
  110. SFLAG    EQU    64
  111. HFLAG    EQU    256
  112. VFLAG    EQU    512
  113. JFLAG    EQU    1024
  114. XFLAG    EQU    2048
  115. TFLAG    EQU    4096
  116. NFLAG    EQU    8192
  117. PFLAG    EQU    16384
  118.  
  119. ;
  120. ;    Macros
  121. ;
  122. JISIT    MACRO    CHAR, JMPLOC        ;JUMP TO JMPLOC IF (HL) .EQ. CHAR
  123.     LD    A,CHAR
  124.     CP    (HL)
  125.     JP    Z,JMPLOC
  126.     ENDM
  127.  
  128. QISIT    MACRO    CHAR, JMPLOC        ;QUICK FORM OF JISIT.  CHARACTER
  129.                     ;TO COMPARE IS ALREADY IN A
  130.     CP    CHAR
  131.     JP    Z,JMPLOC
  132.     ENDM
  133.  
  134. ISIT    MACRO    CHAR            ;JUMP TO WRDNOT IF (HL) .NE. CHAR
  135.     LD    A,CHAR
  136.     CP    (HL)
  137.     JP    NZ,WRDNOT
  138.     ENDM
  139.  
  140.  
  141. START:    LD    SP,STACK        ;CREATE A STACK
  142.     LD    A,0C9H            ;RETURN INSTRUCTION
  143.     LD    (TPA),A            ;DON'T ALLOW SECOND RUN OF PROGRAM
  144.     LD    DE,WELCOM        ;PRINT SIGNON MESSAGE
  145.     LD    C,STROUT
  146.     CALL    BDOS
  147.     JR    START0
  148. WELCOM:    DB    'SPELL V2.0 -- December 22, 1982',CR,LF
  149.     DB    '(C) 1982 Michael C. Adler',CR,LF,'$'
  150.     
  151. START0:    LD    A,(BOOT+6CH)        ;GET OUTPUT DRIVE
  152.     PUSH    PSW            ;SAVE IT
  153.     LD    C,OPEN            ;OPEN THE DICTIONARY FILE
  154.     LD    DE,DICFCB
  155.     CALL    BDOS
  156.     CP    0FFH            ;FOUND?
  157.     JP    NZ,SETUP        ;JUMP IF FOUND
  158.     LD    A,1            ;TRY DRIVE A IF NOT ON DEFAULT DRIVE
  159.     LD    (DICFCB),A
  160.     LD    C,OPEN
  161.     LD    DE,DICFCB
  162.     CALL    BDOS
  163.     CP    0FFH            ;FOUND?
  164.     JP    NZ,SETUP
  165.     LD    C,STROUT        ;OUTPUT:  "CAN'T FIND DICTIONARY..."
  166.     LD    DE,DICERR
  167.     CALL    BDOS
  168.     CALL    0
  169. DICERR:    DB    'Can''t find dictionary file DICT.DIC',CR,LF,'$'
  170.  
  171. SETUP:    LD    DE,OFCB            ;COPY INPUT FILENAME TO OUTPUT
  172.     LD    HL,IFCB
  173.     LD    BC,9
  174.     LDIR
  175.     LD    DE,P2FCB        ;COPY INPUT FILENAME TO PASS 2 FCB
  176.     LD    HL,IFCB            ; (THIS FCB IS FOR INPUT ON PASS 2)
  177.     LD    BC,12
  178.     LDIR
  179.     LD    DE,FILDIC        ;COPY INPUT FILENAME TO FILE.DIC FCB
  180.     LD    HL,IFCB
  181.     LD    BC,9
  182.     LDIR
  183.     LD    DE,FILADD        ;COPY INPUT FILENAME TO FILE.ADD FCB
  184.     LD    HL,IFCB
  185.     LD    BC,9
  186.     LDIR
  187.     LD    DE,FILD$$        ;COPY INPUT FILENAME TO FILE.D$$ FCB
  188.     LD    HL,IFCB
  189.     LD    BC,9
  190.     LDIR
  191.     POP    PSW            ;GET OUTPUT DRIVE, IF SPECIFIED (FROM
  192.                     ;6CH)
  193.     CP    0
  194.     JR    Z,NODRV
  195.     LD    HL,BOOT+81H        ;SEARCH FOR DRIVE SPECIFICATION IN
  196.                     ;COMMAND LINE
  197.     LD    A,(BOOT+80H)        ;NUMBER OF CHARACTERS IN COMMAND LINE
  198.     LD    B,0
  199.     LD    C,A            ;COUNTER
  200.     ADD    HL,BC            ;HL POINTS TO LAST CHARACTER
  201.     DEC    BC            ;DON'T TEST FIRST BYTE OF INPUT
  202.     LD    A,':'            ;SEARCHING FOR ":"
  203.     CPDR
  204.     JR    NZ,NODRV        ;IF NO DRIVE SPECIFIED, THEN USE
  205.                     ;DEFAULT
  206.     LD    A,(HL)            ;GET DRIVE NAME
  207.     AND    5FH            ;MAKE UPPER CASE
  208.     SUB    40H            ;MAKE A=1
  209.     LD    (OFCB),A        ;MAKE OUTPUT FILES ON OUTPUT DRIVE
  210.     LD    (FILD$$),A
  211. NODRV:    LD    C,OPEN            ;OPEN THE INPUT FILE
  212.     LD    DE,IFCB
  213.     CALL    BDOS
  214.     LD    C,OPEN            ;WITH PASS 1 AND PASS 2 FCB'S
  215.     LD    DE,P2FCB
  216.     CALL    BDOS
  217.     CP    0FFH
  218.     JP    NZ,SETUP0        ;JUMP IF FOUND
  219.     LD    C,STROUT        ;OUTPUT:  "CAN'T FIND INPUT FILE"
  220.     LD    DE,NOINPT
  221.     CALL    BDOS
  222.     CALL    BOOT
  223. NOINPT:    DB    'Can''t find input file',CR,LF,'$'
  224.  
  225. SETUP0:    LD    C,DELETE        ;DELETE OUTPUT FILE (FILE.$$$)
  226.     LD    DE,OFCB
  227.     CALL    BDOS
  228.     LD    C,MAKE            ;MAKE A NEW OUTPUT FILE
  229.     LD    DE,OFCB
  230.     CALL    BDOS
  231.     CP    0FFH
  232.     JP    NZ,SETUP1        ;JUMP IF SUCCESSFUL
  233.     LD    C,STROUT        ;OUTPUT:  "DIRECTORY FULL"
  234.     LD    DE,NODIR
  235.     CALL    BDOS
  236.     CALL    BOOT
  237. NODIR:    DB    'Directory full',CR,LF,'$'
  238.  
  239. SETUP1:    CALL    CTRLZ            ;FILL OUTPUT BUFFER WITH EOF
  240.     LD    A,EOF            ;MARK END OF OUTPUT BUFFER
  241.     LD    (OBUFF+512),A
  242.     LD    A,0            ;MARK END OF DICTIONARY BUFFER
  243.     LD    (DICBUF+256),A
  244.     LD    (DICBUF+257),A
  245.     LD    A,(PUTCHR)        ;GET THE NORMAL FIRST INSTRUCTION
  246.                     ;AT PUTCHR
  247.     LD    (SAVPUT),A        ;STORE IT FOR LATER
  248.     LD    A,0C9H            ;RETURN INSTRUCTION
  249.     LD    (PUTCHR),A        ;DISABLE OUTPUT
  250.     CALL    AUXDIC            ;LOAD "SPELL.DIC", FILE.DIC AND
  251.                     ; FILE.ADD
  252.     LD    HL,IFCB            ;INPUT FILE FCB
  253.     LD    (FILPAT),HL        ;PATCH GETWRD: TO READ FROM IT
  254.  
  255.  
  256. ;
  257. ; SRTFIL -- Sort the file in memory, alphabetically.  Duplicate words are
  258. ;    discarded.  This will save a lot of time during dictionary lookups
  259. ;    since the words will have to be located only once.
  260.  
  261. SRTFIL:    CALL    GETWRD            ;GET A WORD INTO SRCWRD:
  262.     JP    Z,CHECK            ;IF EOF THEN START CHECKING
  263.     LD    HL,(TOTWRD)        ;KEEP TRACK OF TOTAL # OF WORDS
  264.     INC    HL
  265.     LD    (TOTWRD),HL
  266.     CALL    CREWRD            ;CREATE WORD FROM SRCWRD:
  267.     LD    A,0            ;IS IT AT LEAST 2 CHARS LONG?
  268.     CP    C
  269.     JR    Z,SRTFIL        ;FORGET IT IF NOT
  270.     LD    A,41            ;IF LONGER THAN 40, ALSO FORGET IT
  271.     CP    C
  272.     JR    Z,SRTFIL
  273.     CALL    MEMWRD            ;PUT WORD IN MEMORY
  274.     AND    A            ;FULL?
  275.     JR    Z,SRTFIL        ;GET ANOTHER WORD IF NOT
  276.     LD    HL,(INPTR)        ;GET OLD INPUT BUFFER POINTER
  277.     LD    (OLDPTR),HL        ;SAVE IT
  278.     LD    A,1            ;MARK PASS 1 INCOMPLETE
  279.     LD    (STOPED),A
  280.     LD    (MLTPAS),A        ;RECORD PERMANENTLY THAT >1 PASS
  281.     LD    C,36            ;GET RECORD NUMBER OF INPUT FILE
  282.     LD    DE,IFCB
  283.     CALL    BDOS
  284.  
  285.  
  286. ;
  287. ; CHECK -- Compare the entries in the sorted table to the dictionary.
  288. ;    Words that are found are marked.
  289. ;
  290. CHECK:    LD    A,(STOPED)        ;IS READ OF SOURCE COMPLETE?
  291.     CP    0
  292.     JR    NZ,CHEC01        ;IF NOT, NO MESSAGE
  293.     LD    DE,TOTMSG        ;OUTPUT: "TOTAL # OF WORDS"
  294.     LD    C,STROUT
  295.     CALL    BDOS
  296.     LD    HL,(TOTWRD)        ;PRINT NUMBER
  297.     CALL    DECOUT
  298. CHEC01:    LD    HL,(SRTTOP)        ;TOP ENTRY IN POINTER TABLE
  299.     LD    DE,(SRTBOT)        ;BOTTOM
  300.     XOR    A            ;CLEAR CARRY
  301.     DEC    HL            ;POINT TO TRUE END, NOT DUMMY RECORD
  302.     DEC    HL
  303.     SBC    HL,DE            ;HL=NUMBER OF WORDS TIMES 2
  304.     JP    Z,MAIN            ;IF EMPTY, WRITE OUT FILE
  305.     RRC    L            ;DIVIDE HL BY 2
  306.     LD    A,L
  307.     AND    07FH
  308.     LD    L,A
  309.     LD    A,0
  310.     RRC    H
  311.     ADC    A,0
  312.     RRC    A
  313.     OR    L
  314.     LD    L,A
  315.     LD    A,H
  316.     AND    07FH
  317.     LD    H,A
  318.     LD    B,H            ;PUT COUNTER IN BC
  319.     LD    C,L
  320.     INC    B            ;MAKE B WORD WITH DEC B AND JNZ
  321.                     ;COMBINATION
  322.     LD    A,0
  323.     CP    C            ;IF C 0?
  324.     JR    NZ,CHEC02
  325.     DEC    B            ;IF C=0 THEN READJUST B BECAUSE
  326.                     ;IT WOULD LOOP 256 TOO MANY TIMES
  327. CHEC02:    LD    HL,(SRTBOT)        ;GET ADDRESS OF FIRST ENTRY
  328.     INC    HL            ;BYPASS DUMMY ENTRY AT BEGINNING
  329.     INC    HL
  330. CHECK0:    LD    E,(HL)            ;GET ADDRESS OF WORD IN MEMORY
  331.     INC    HL
  332.     LD    D,(HL)
  333.     INC    HL
  334.     PUSH    BC
  335.     PUSH    HL
  336.     LD    HL,WORD
  337.     LD    C,0FEH            ;CHARACTER COUNTER
  338.                     ;AT THE END, C=CHARS-1.  START OF WITH
  339.                     ;-2 SO THAT 0 AND 1 CHARACTER NOT
  340.                     ;COUNTED
  341. CHECK1:    LD    A,(DE)            ;GET A CHARACTER
  342.     LD    (HL),A            ;PUT IT IN WORD:
  343.     INC    C
  344.     DEC    DE
  345.     INC    HL
  346.     CP    0            ;END OF WORD?
  347.     JR    NZ,CHECK1        ;LOOP UNTIL END
  348.     LD    A,C
  349.     LD    (LASTC),A        ;NUMBER OF CHARACTERS
  350.     LD    HL,(UNQWRD)        ;RECORD # OF UNIQUE WORDS
  351.     INC    HL
  352.     LD    (UNQWRD),HL
  353.     CALL    WRDTST            ;SEARCH DICTIONARY FOR WORD
  354.     CP    1            ;FOUND?
  355.     JR    NZ,CHECK2        ;LEAVE UNMARKED IF NOT FOUND
  356.     INC    DE            ;POINT TO END MARKER OF WORD
  357.     LD    A,080H
  358.     LD    (DE),A            ;MARK WORD AS FOUND
  359.     JR    CHECK3
  360. CHECK2:    LD    HL,(MISWRD)        ;INCREMENT MISSED WORDS COUNTER
  361.     INC    HL
  362.     LD    (MISWRD),HL
  363. CHECK3:    POP    HL
  364.     POP    BC
  365.     DEC    C
  366.     JP    NZ,CHECK0        ;LOOP
  367.     DEC    B
  368.     JP    NZ,CHECK0        ;16 BIT LOOP INDEX
  369.     LD    HL,P2FCB        ;SET TO INPUT FROM PASS 2 FCB
  370.     LD    (FILPAT),HL
  371.     LD    HL,(P2OPTR)        ;SET PASS 2 INPUT POINTER
  372.     LD    (INPTR),HL
  373.     LD    A,(SAVPUT)        ;GET THE NORMAL FIRST INSTRUCTION
  374.                     ;AT PUTCHR
  375.     LD    (PUTCHR),A        ;PATCH IT INTO THE WRITE ROUTINE
  376.     LD    HL,P2BUF+512        ;PATCH NEW BUFFER INTO GETCHR
  377.     LD    (BUFPAT),HL
  378.     LD    HL,P2BUF
  379.     LD    (BUFPA0),HL
  380.     LD    (BUFPA1),HL
  381.     INC    HL
  382.     LD    (BUFPA2),HL
  383.     LD    A,(LASTCH)        ;SAVE LAST CHARACTER READ
  384.     LD    B,A
  385.     LD    A,(OLSTCH)        ;PUT OLD LASTCH BACK
  386.     LD    (LASTCH),A
  387.     LD    A,B
  388.     LD    (OLSTCH),A        ;SAVE CURRENT LASTCH
  389.     JR    MAIN
  390. TOTMSG:    DB    CR,LF,LF,'Total number of words in document:    $'
  391.  
  392. ;
  393. ; MAIN -- Do a second pass through the input file.  Compare each word to
  394. ;    the memory buffer to determine whether the words were found.
  395. ;    If a word was not found, mark it with the ERRCHR.
  396.  
  397. MAIN:    CALL    GETWRD            ;GET A WORD INTO SRCWRD:
  398.     JP    Z,DONE            ;IF EOF THEN STOP
  399.     CALL    CREWRD            ;CREATE WORD FROM SRCWRD:
  400.     LD    A,0            ;IS WORD AT LEAST 2 CHARS LONG?
  401.     CP    C
  402.     JR    Z,MAIN0            ;ACCEPT IF NOT
  403.     LD    A,41            ;IF LONGER THAN 40, ALSO ACCEPT
  404.     CP    C
  405.     JR    Z,MAIN0
  406.     CALL    MEMWRD            ;SEARCH FOR WORD IN MEMORY
  407.     LD    A,(DE)            ;GET MARKER FOR WORD
  408.     CP    080H            ;WORD SPELLED CORRECTLY?
  409.     JR    Z,MAIN0
  410.     LD    A,ERRCHR        ;IF NOT, MARK WORD
  411.     CALL    PUTCHR
  412. MAIN0:    LD    HL,SRCWRD        ;OUTPUT THE ORIGINAL WORD
  413. MAIN1:    LD    A,(HL)
  414.     CP    0            ;END OF WORD?
  415.     JR    Z,MAIN2
  416.     CALL    PUTCHR            ;OUTPUT CHARACTER
  417.     INC    HL            ;POINT TO NEXT CHARACTER
  418.     JR    MAIN1            ;LOOP
  419. MAIN2:    LD    A,(STOPED)        ;WAS PASS 1 INCOMPLETE
  420.     AND    A
  421.     JR    Z,MAIN            ;GET NEXT WORD IF NOT
  422.     LD    DE,P2FCB        ;COMPUTE CURRENT RECORD NUMBER
  423.     LD    C,36
  424.     CALL    BDOS
  425.     LD    DE,(P2FCB+21H)
  426.     LD    HL,(IFCB+21H)        ;COMPARE STOPPED RECORD NUMBER TO
  427.                     ;CURRENT
  428.     XOR    A            ;CLEAR CARRY
  429.     SBC    HL,DE
  430.     JP    NZ,MAIN            ;GET NEXT WORD IF NOT THE SAME
  431.     LD    HL,(OLDPTR)        ;GET POSITION IN RECORD
  432.     LD    DE,P2BUF-INBUF        ;OFFSET IT TO COMPARE WITH PASS 2 BUFF
  433.     ADD    HL,DE
  434.     LD    DE,(INPTR)
  435.     XOR    A
  436.     SBC    HL,DE            ;COMPARE STOPPED POS TO CURRENT
  437.     JP    NZ,MAIN            ;GET NEXT WORD IF NOT THE SAME
  438.     LD    A,0            ;UNMARK PASS 1 INCOMPLETE
  439.     LD    (STOPED),A
  440.     LD    HL,(INPTR)        ;SAVE PASS 2 INPUT POINTER
  441.     LD    (P2OPTR),HL
  442.     LD    HL,(OLDPTR)        ;GET OLD POINTER TO BUFFER
  443.     LD    (INPTR),HL        ;RESET BUFFER POINTER
  444.     LD    HL,IFCB            ;PATCH GETCHR: ROUTINE TO READ FROM
  445.                     ;PASS 1 FCB
  446.     LD    (FILPAT),HL
  447.     LD    HL,INBUF+512        ;PATCH THE CORRECT BUFFER INTO GETCHR
  448.     LD    (BUFPAT),HL
  449.     LD    HL,INBUF
  450.     LD    (BUFPA0),HL
  451.     LD    (BUFPA1),HL
  452.     INC    HL
  453.     LD    (BUFPA2),HL
  454.     LD    A,0C9H            ;MAKE PUTCHR NOT WORK
  455.     LD    (PUTCHR),A
  456.     LD    HL,(SRTBOT)        ;RESET MEMORY BUFFER POINTERS
  457.     INC    HL
  458.     INC    HL
  459.     LD    (SRTTOP),HL
  460.     LD    HL,(BDOS+1)        ;GET BDOS VECTOR
  461.     DEC    HL            ;POINT TO FREE MEMORY
  462.     LD    (FREE),HL        ;POINTER TO FREE MEMORY
  463.     LD    A,(LASTCH)        ;SAVE LAST CHARACTER READ
  464.     LD    B,A
  465.     LD    A,(OLSTCH)        ;PUT OLD LASTCH BACK
  466.     LD    (LASTCH),A
  467.     LD    A,B
  468.     LD    (OLSTCH),A        ;SAVE CURRENT LASTCH
  469.     JP    SRTFIL            ;FILL BUFFER AGAIN
  470.  
  471. ;
  472. ; DONE -- Write out the rest of the output buffer and then close and rename
  473. ;    output files.
  474.  
  475. DONE:    LD    HL,OBUFF        ;WRITE OUT REMAINING DATA IN BUFFER
  476.     LD    DE,128
  477. DONE1:    LD    A,EOF            ;DONE?
  478.     CP    (HL)
  479.     JR    Z,DONE3
  480.     PUSH    DE
  481.     PUSH    HL
  482.     LD    D,H            ;SET UP DMA ADDRESS
  483.     LD    E,L
  484.     LD    C,SETDMA
  485.     CALL    BDOS
  486.     LD    DE,OFCB            ;WRITE 128 BYTES TO FILE
  487.     LD    C,WRITE
  488.     CALL    BDOS
  489.     POP    HL
  490.     POP    DE
  491.     CP    0            ;ERROR?
  492.     JR    NZ,DONE2        ;DISK FULL --> BRANCH
  493.     ADD    HL,DE            ;POINT TO NEXT RECORD
  494.     JR    DONE1
  495. DONE2:    LD    C,STROUT        ;DISK FULL
  496.     LD    DE,DSKFUL        ;DISK FULL MESSAGE (SEE PUTCHR)
  497.     CALL    BDOS
  498.     CALL    BOOT
  499.  
  500. DONE3:    LD    DE,OFCB            ;CLOSE OUTPUT FILE
  501.     LD    C,CLOSE
  502.     CALL    BDOS
  503.     LD    A,'B'
  504.     LD    (OFCB+9),A
  505.     LD    A,'A'
  506.     LD    (OFCB+10),A
  507.     LD    A,'K'
  508.     LD    (OFCB+11),A
  509.     LD    A,(OFCB)        ;REMEMBER OUTPUT DRIVE NAME
  510.     PUSH    PSW
  511.     LD    A,(IFCB)        ;GET THE DRIVE ON WHICH INPUT WAS DONE
  512.     LD    (OFCB),A        ;TRY TO DELETE .BAK ON IT ONLY
  513.     LD    DE,OFCB
  514.     LD    C,DELETE
  515.     CALL    BDOS
  516.     LD    DE,IFCB+16        ;RENAME SOURCE TO SOURCE.BAK
  517.     LD    HL,OFCB
  518.     LD    BC,12            ;COPY FILENAME FOR RENAME
  519.     LDIR
  520.     LD    DE,IFCB
  521.     LD    C,RENAME
  522.     CALL    BDOS
  523.     LD    HL,IFCB+9        ;RENAME .$$$ TO SOURCE
  524.     LD    DE,IFCB+25
  525.     LD    BC,3
  526.     LDIR
  527.     LD    A,'$'
  528.     LD    (IFCB+9),A
  529.     LD    (IFCB+10),A
  530.     LD    (IFCB+11),A
  531.     POP    PSW            ;RESTORE OUTPUT DRIVE NAME
  532.     LD    (IFCB),A        ;AND PUT IT IN FCB
  533.     LD    DE,IFCB
  534.     LD    C,RENAME
  535.     CALL    BDOS
  536.                     ;NOW TAKE CARE OF USER DICTIONARIES
  537.     LD    DE,FILADD        ;DELETE FILE.ADD
  538.     LD    C,DELETE
  539.     CALL    BDOS
  540.     LD    DE,FILDIC        ;DELETE FILE.UDC
  541.     LD    C,DELETE
  542.     CALL    BDOS
  543.     LD    A,(MLTPAS)        ;WAS MORE THAN 1 PASS REQUIRED?
  544.     CP    0
  545.     JR    Z,DONE30        ;NO MESSAGE IF NOT
  546.     LD    DE,NOTOUT        ;OUTPUT: NO TOTALS PRINTED
  547.     LD    C,STROUT
  548.     CALL    BDOS
  549.     JR    DONE31
  550. DONE30:    LD    DE,UNQMSG        ;OUTPUT: # OF UNIQUE WORDS
  551.     LD    C,STROUT
  552.     CALL    BDOS
  553.     LD    HL,(UNQWRD)        ;PRINT # OF WORDS
  554.     CALL    DECOUT
  555.     LD    DE,MISMSG        ;OUTPUT: # OF "MISSPELLED" WORDS
  556.     LD    C,STROUT
  557.     CALL    BDOS
  558.     LD    HL,(MISWRD)        ;PRINT #
  559.     CALL    DECOUT
  560. DONE31:    LD    HL,(FILUDC)        ;DELETE FILE.D$$ IF IT HAS NO WORDS
  561.     LD    A,0
  562.     CP    H
  563.     JR    NZ,DONE4        ;RENAME IT TO FILE.UDC IF >0 WORDS
  564.     CP    L
  565.     JR    NZ,DONE4
  566.     LD    DE,FILD$$        ;DELETE IT
  567.     LD    C,DELETE
  568.     CALL    BDOS
  569.     CALL    BOOT
  570.  
  571. DONE4:    LD    HL,FILDIC        ;RENAME FILE.D$$ TO FILE.UDC
  572.     LD    DE,FILD$$+16
  573.     LD    BC,12
  574.     LDIR
  575.     LD    DE,FILD$$
  576.     LD    C,RENAME
  577.     CALL    BDOS
  578.     CALL    BOOT
  579. NOTOUT:    DB    CR,LF,'No subtotals available due to size of document.$'
  580. UNQMSG:    DB    CR,LF,'    Number of unique words:        $'
  581. MISMSG:    DB    CR,LF,'    Unique "misspelled" words:    $'
  582.  
  583. ;
  584. ; GETWRD -- Read a word from an input file.  Words are any series of
  585. ;    alphabetic characters (with or without parity set) and
  586. ;    apostrophes.
  587. ;
  588. ;        Returns:  C <-- number of characters in word
  589. ;              Z flag set if EOF
  590.  
  591. GETWRD:    CALL    GETCHR            ;GET A CHARACTER
  592.     CP    EOF            ;END OF FILE?
  593.     RET    Z
  594.     CALL    LEGAL            ;TEST IF LEGAL
  595.     LD    (LASTCH),A        ;SAVE LAST CHARACTER
  596.     JR    Z,KILPER        ;EXIT LOOP IF LEGAL
  597.     CALL    PUTCHR            ;SEND CHARACTER DIRECTLY OUT
  598.     JR    GETWRD            ;LOOP UNTIL LEGAL
  599. KILPER:    LD    C,A
  600.     AND    07FH            ;MASK PARITY
  601.     CP    '.'            ;IS IT A DOT COMMAND?
  602.     LD    A,C
  603.     JR    NZ,GETWR0        ;GET WORD IF NOT
  604.     CALL    PUTCHR
  605. KILPE0:    CALL    GETCHR            ;ERADICATE THIS LINE
  606.     CP    EOF            ;END OF FILE?
  607.     RET    Z
  608.     CALL    PUTCHR            ;OUTPUT IT
  609.     LD    (LASTCH),A
  610.     AND    07FH            ;MASK PARITY
  611.     CP    LF            ;IS IT A LINE TERMINATOR?
  612.     JR    NZ,KILPE0        ;LOOP THROUGH WHOLE LINE
  613.     JR    GETWRD            ;GET A TEXT WORD NOW
  614. GETWR0:    LD    C,1            ;ZERO CHARACTER COUNTER
  615.     LD    HL,SRCWRD+1        ;INITIALIZE POINTER TO SRCWRD:
  616.     LD    (SRCWRD),A        ;STORE FIRST CHARACTER
  617. GETWR1:    CALL    GETCHR
  618. HYPTST:    CP    1FH            ;SOFT HYPHEN?
  619.     JP    Z,ISHYP
  620.     CP    1EH            ;UNUSED SOFT HYPHEN?
  621.     JP    NZ,NOTHYP
  622. ISHYP:    LD    (LASTCH),A        ;UPDATE LAST CHARACTER POINTER
  623.     LD    (HL),A            ;STORE HYPHEN
  624.     INC    HL
  625.     INC    C
  626.     CALL    GETCHR
  627. ISHYP0:    CP    CR OR 80H        ;SOFT RETURN AFTER HYPHEN?
  628.     JR    NZ,HYPTST        ;TEST FOR ANOTHER HYPHEN
  629.     LD    (LASTCH),A        ;UPDATE LAST CHARACTER POINTER
  630.     LD    (HL),A            ;STORE RETURN
  631.     INC    HL
  632.     INC    C
  633.     CALL    GETCHR
  634.     LD    B,A            ;SAVE THE CHAR
  635.     AND    07FH            ;KILL PARITY BIT
  636.     CP    LF            ;SOFT LINE FEED?
  637.     LD    A,B            ;RESTORE CHAR
  638.     JR    NZ,HYPTST        ;TEST FOR ANOTHER HYPHEN
  639.     LD    (LASTCH),A        ;UPDATE LAST CHARACTER POINTER
  640.     LD    (HL),A            ;STORE LF
  641.     INC    HL
  642.     INC    C
  643.     CALL    GETCHR
  644. ISHYP1:    CP    ' ' OR 80H        ;ELIMINATE SOFT SPACES AT START OF LINE
  645.     JR    NZ,ISHYP0        ;TEST FOR REST OF WORD
  646.     LD    (LASTCH),A        ;UPDATE LAST CHARACTER POINTER
  647.     LD    (HL),A            ;STORE SPACE
  648.     INC    HL
  649.     INC    C
  650.     CALL    GETCHR
  651.     JR    ISHYP1            ;TEST FOR MORE SPACES    
  652. NOTHYP:    CALL    LEGAL
  653.     JR    NZ,GETWR2        ;EXIT LOOP WHEN NOT WORD CHARACTER
  654.     LD    (LASTCH),A
  655.     LD    (HL),A
  656.     INC    HL
  657.     INC    C
  658.     JR    GETWR1
  659. GETWR2:    LD    (HL),0            ;MARK END OF WORD
  660.     LD    HL,(INPTR)        ;DECREMENT POINT FOR INPUT BUFFER
  661.                     ;SO FIRST CHAR AFTER WORD IS KEPT
  662.     DEC    HL
  663.     LD    (INPTR),HL
  664.     RET
  665.  
  666. ;
  667. ; LEGAL -- Determines whether character is alphabetic, an apostrophe,
  668. ;    or period for a dot command.
  669. ;
  670. ;        Returns:  Z flag set <-- characters was one of the above
  671. ;              Z flag clear <-- was not one of the above
  672.  
  673. LEGAL:    LD    B,A
  674.     AND    05FH            ;KILL PARITY AND LOWER CASE
  675.     CP    'A'            ;MUST BE GREATER THAN "A"
  676.     JP    C,LEGAL0
  677.     CP    'Z'+1            ;GREATER THAN "Z"
  678.     JP    NC,LEGAL0
  679.     LD    A,B
  680.     CP    A            ;SET ZERO FLAG
  681.     RET
  682. LEGAL0:    LD    A,B
  683.     AND    07FH            ;KILL ONLY PARITY
  684.     CP    27H            ;"'"
  685.     JR    Z,LEGAL1
  686.     LD    A,(LASTCH)        ;WAS LAST CHARACTER A LF?
  687.     AND    7FH            ;MASK PARITY
  688.     CP    LF
  689.     JR    NZ,LEGAL1
  690.     LD    A,B
  691.     CP    '.'            ;ACCEPT PERIODS SO DOT COMMAND ACCEPTED
  692. LEGAL1:    LD    A,B
  693.     RET
  694.  
  695. ;
  696. ; GETCHR -- Read a character from an input file into a buffer.  This routine
  697. ;    is used for a number of different purposes.  The file from which
  698. ;    to read is patched into FILPAT.  The buffer to which writes should
  699. ;    occur is patched into BUFPAT-BUFPA2.
  700. ;
  701. ;        Returns:  A  <-- next character from input file
  702.  
  703. GETCHR:    PUSH    BC
  704.     PUSH    DE
  705.     PUSH    HL
  706.     LD    HL,(INPTR)        ;POINTER FOR INPUT
  707.     LD    DE,INBUF+512        ;END OF INPUT BUFFER
  708. BUFPAT    EQU    $-2            ;PATCH FOR INPUT BUFFER
  709.     XOR    A            ;CLEAR CARRY
  710.     PUSH    HL
  711.     SBC    HL,DE            ;AT END OF BUFFER?
  712.     POP    HL
  713.     JP    Z,GETCH0        ;REFILL BUFFER
  714.     LD    A,(HL)            ;GET THE CHARACTER
  715.     INC    HL            ;INCREMENTED POINTER
  716.     LD    (INPTR),HL
  717. GETRET:    POP    HL
  718.     POP    DE
  719.     POP    BC
  720.     RET
  721. GETCH0:    LD    HL,INBUF
  722. BUFPA0    EQU    $-2            ;PATCH FOR INPUT BUFFER
  723.     LD    DE,128
  724.     LD    C,4
  725. GETCH2:    PUSH    BC
  726.     PUSH    DE
  727.     PUSH    HL
  728.     LD    A,EOF            ;MARK WITH EOF IN CASE NO RECORD
  729.     LD    (HL),A
  730.     LD    D,H            ;SET UP DMA ADDRESS FOR READ
  731.     LD    E,L
  732.     LD    C,SETDMA
  733.     CALL    BDOS            ;SET DMA ADDRESS
  734.     LD    DE,IFCB
  735. FILPAT    EQU    $-2            ;FCB PATCH ADDRESS
  736.     LD    C,READ            ;READ 128 BYTES OF INPUT FILE
  737.     CALL    BDOS
  738.     POP    HL
  739.     POP    DE
  740.     POP    BC
  741.     CP    0            ;SUCCESS?
  742.     JR    NZ,GETCH3        ;JUMP IF EOF
  743.     ADD    HL,DE            ;POINT TO NEXT RECORD ADDRESS
  744.     DEC    C
  745.     JP    NZ,GETCH2        ;LOOP FOR 4 RECORDS
  746. GETCH3:    LD    A,(INBUF)        ;GET FIRST CHARACTER
  747. BUFPA1    EQU    $-2            ;ANOTHER BUFFER PATCH
  748.     LD    (HL),EOF        ;PUT EOF AT BEGINNING OF FIRST UNUSED
  749.                     ;RECORD IN MEMORY
  750.     LD    HL,INBUF+1
  751. BUFPA2    EQU    $-2            ;AND YET ANOTHER BUFFER PATCH
  752.     LD    (INPTR),HL        ;SET UP POINTER TO RECORDS
  753.     JP    GETRET
  754.  
  755. ;
  756. ; CREWRD -- Converts the word in SRCWRD to a word in WORD.  Parity bits
  757. ;    are cleared, lower case is converted to upper case, and apostrophes
  758. ;    that are not imbedded in words are discarded.
  759.  
  760. CREWRD:    LD    HL,WORD            ;POINTER TO DESINATION BUFFER
  761.     LD    DE,SRCWRD        ;SOURCE BUFFER
  762.     LD    C,0
  763. CREWR0:    LD    A,(DE)            ;GET A CHARACTER
  764.     CP    0            ;END OF WORD?
  765.     JP    Z,CREWR2
  766.     AND    07FH            ;MASK PARITY
  767.     CP    027H            ;"'" CHARACTER?
  768.     JR    Z,CREWR3
  769.     AND    05FH            ;MASK PARITY AND CONVERT TO UPPER CASE
  770.     CP    'A'            ;IS IT ONLY A HYPHEN?
  771.     JR    C,CREWR1        ;IF SO, SKIP IT
  772. CREADD:    INC    C
  773.     LD    (HL),A            ;PUT CHARACTER IN WORD BUFFER
  774.     LD    A,41            ;MAXIMUM OF 40 CHARACTERS IN WORD
  775.     CP    C
  776.     RET    Z            ;WORD TOO LONG.  ACCEPT IT
  777.     INC    HL
  778. CREWR1:    INC    DE
  779.     JP    CREWR0
  780. CREWR2:    LD    (HL),0            ;MARK END OF WORD
  781.     LD    HL,LASTC        ;PUT NUMBER OF CHARACTERS IN LASTC
  782.     DEC    C            ;C=NUMBER OF CHARACTERS - 1
  783.     JP    P,CREWS2        ;JUMP IF C WASN'T ALREADY 0
  784.     INC    C
  785. CREWS2:    LD    (HL),C
  786.     RET
  787. CREWR3:    LD    A,0            ;IF FIRST CHARACTER IN WORD, IGNORE
  788.                     ;"'"
  789.     CP    C
  790.     JR    Z,CREWR1
  791.     INC    DE
  792.     LD    A,(DE)            ;IF LAST CHAR IN WORD, IGNORE
  793.     CP    0
  794.     DEC    DE
  795.     JR    Z,CREWR1
  796.     LD    A,27H            ;OTHERWISE, KEEP "'"
  797.     JR    CREADD
  798.  
  799. ;
  800. ; PUTCHR -- write a character to output file
  801. ;
  802. ;        Input:  A --> character to output
  803.  
  804. PUTCHR:    PUSH    PSW
  805.     PUSH    BC
  806.     PUSH    DE
  807.     PUSH    HL
  808.     LD    HL,(OPOSS)        ;GET CURRENT POSITION IN OBUFF
  809.     LD    (HL),A            ;PUT CHARACTER IN BUFFER
  810.     INC    HL
  811.     LD    (OPOSS),HL        ;UPDATE POINTER
  812.     LD    DE,OBUFF+512        ;AT END OF BUFFER?
  813.     XOR    A            ;CLEAR CARRY
  814.     SBC    HL,DE
  815.     JR    Z,PUTCH0        ;WRITE OUT DATA IF END OF BUFFER
  816. PUTRET:    POP    HL
  817.     POP    DE
  818.     POP    BC
  819.     POP    PSW
  820.     RET
  821. PUTCH0:    LD    C,4            ;LOOP COUNTER
  822.     LD    HL,OBUFF        ;ADDRESS OF DATA
  823.     LD    DE,128            ;LENGTH OF EACH RECORD
  824. PUTCH1:    PUSH    BC
  825.     PUSH    DE
  826.     PUSH    HL
  827.     LD    D,H            ;SET UP DMA ADDRESS
  828.     LD    E,L
  829.     LD    C,SETDMA
  830.     CALL    BDOS
  831.     LD    DE,OFCB            ;WRITE RECORD TO OUTPUT FILE
  832. OUTPAT    EQU    $-2            ;PATCH ADDRESS FOR OUTPUT FILE FCB
  833.     LD    C,WRITE
  834.     CALL    BDOS
  835.     CP    0            ;SUCCESS?
  836.     JR    NZ,PUTCH2        ;JUMP IF DISK FULL
  837.     POP    HL
  838.     POP    DE
  839.     POP    BC
  840.     ADD    HL,DE            ;POINT TO NEXT RECORD
  841.     DEC    C
  842.     JP    NZ,PUTCH1        ;LOOP FOR 512 BYTE BUFFER
  843.     LD    HL,OBUFF        ;RESET POINTER
  844.     LD    (OPOSS),HL
  845.     CALL    CTRLZ            ;FILL BUFFER WITH EOF CHARACTER
  846.     JP    PUTRET            ;RETURN
  847. PUTCH2:    LD    C,STROUT        ;DISK FULL ERROR
  848.     LD    DE,DSKFUL
  849.     CALL    BDOS
  850.     CALL    BOOT            ;GIVE UP
  851. DSKFUL:    DB    CR,LF,'Disk full -- aborting',CR,LF,'$'
  852.  
  853. ;
  854. ; CTRLZ -- Fill the output buffer with EOF characters to prepare it for
  855. ;    writing
  856.  
  857. CTRLZ:    LD    HL,OBUFF        ;BUFFER ADDRESS
  858.     LD    B,2            ;LOOP 256 BYTES 2 TIMES
  859.     LD    C,0
  860. CTRLZ0:    LD    (HL),EOF        ;PUT EOF IN BUFFER
  861.     INC    HL
  862.     DEC    C            ;FAST COUNTER
  863.     JR    NZ,CTRLZ0
  864.     DEC    B            ;SLOW COUNTER
  865.     JR    NZ,CTRLZ0
  866.     RET
  867.  
  868. ;
  869. ; MEMWRD -- put word in WORD into memory.  If word already exists in memory
  870. ;    then its the address of its status byte is returned in DE.  If the
  871. ;    word is not found, the word is placed in memory and the pointers
  872. ;    that alphabetize the words are updated.  If memory is full, a
  873. ;    1 is returned in A.  Otherwise 0 is returned in A.
  874.  
  875. MEMWRD:    LD    BC,(SRTBOT)        ;GET ADDRESS OF BOTTOM OF WORD POINTER
  876.     LD    DE,(SRTTOP)        ;TOP OF WORD POINTER
  877.     JR    MEMSKP
  878. MEMWR0:    POP    HL
  879.     POP    DE
  880.     POP    BC
  881.     JP    M,MEMW00
  882.     LD    D,H            ;MOVE HIGH POINTER DOWN
  883.     LD    E,L
  884.     JR    MEMSKP
  885. MEMW00:    LD    B,H            ;MOVE LOW POINTER UP
  886.     LD    C,L
  887. MEMSKP:    LD    H,D            ;HL IS POINTER TO RECORD BETWEEN DE AND
  888.     LD    L,E            ;BC
  889.     XOR    A            ;CLEAR CARRY
  890.     SBC    HL,BC
  891.     LD    A,0            ;IS BC+1=HL?
  892.     CP    H
  893.     JP    NZ,MEMWR1
  894.     LD    A,2
  895.     CP    L
  896.     JP    NZ,MEMWR1
  897.     LD    HL,(SRTTOP)        ;UPDATE SRTTOP=SRTTOP+2
  898.     INC    HL
  899.     INC    HL
  900.     LD    (SRTTOP),HL
  901.     XOR    A            ;CLEAR CARRY
  902.     PUSH    HL
  903.     SBC    HL,DE            ;NUMBER OF BYTES IN TABLE TO MOVE
  904.     LD    B,H            ;PUT NUMBER OF COUNTER FOR LDDR
  905.     LD    C,L
  906.     POP    HL
  907.     PUSH    DE            ;SAVE THE ADDRESS FOR NEW WORD
  908.     LD    D,H            ;PUT DESTINATION ADDRESS IN DE
  909.     LD    E,L
  910.     DEC    HL            ;SOURCE IN HL
  911.     DEC    HL
  912.     LDDR                ;PUT A SPACE FOR NEW POINTER IN TABLE
  913.     POP    DE
  914.     LD    HL,(FREE)        ;ADDRESS TO STORE NEW WORD
  915.     EX    DE,HL
  916.     LD    (HL),E            ;STORE ADDRESS OF WORD IN TABLE
  917.     INC    HL
  918.     LD    (HL),D
  919.     LD    HL,WORD
  920.     LD    A,(LASTC)        ;GET NUMBER OF CHARACTERS
  921.     LD    B,A
  922.     INC    B            ;B = NUMBER OF CHARACTERS IN WORD + 1
  923.     INC    B
  924. MEMW01:    LD    A,(HL)            ;GET A CHARACTER
  925.     LD    (DE),A            ;PUT IT IN MEMORY
  926.     DEC    DE            ;STORE WORD BACKWARDS
  927.     INC    HL            ;NEXT CHAR IN WORD
  928.     DJNZ    MEMW01    
  929.     LD    (FREE),DE        ;UPDATE FREE MEMORY POINTER
  930.     EX    DE,HL
  931.     LD    DE,45            ;ALLOW ROOM FOR ANOTHER WORD
  932.     XOR    A            ;CLEAR CARRY
  933.     SBC    HL,DE
  934.     LD    DE,(SRTTOP)        ;POINTER TO TOP OF POINTER TABLE
  935.     XOR    A
  936.     SBC    HL,DE            ;IS ANY MEMORY LEFT?
  937.     JR    C,MEMFUL        ;IF NOT, NO MORE MEMORY
  938.     LD    A,0            ;INDICATE MEMORY LEFT
  939.     RET
  940. MEMFUL:    LD    A,1            ;NO MEMORY LEFT
  941.     RET
  942. MEMWR1:    RRC    L            ;DIVIDE HL BY 2
  943.     LD    A,L
  944.     AND    07EH            ;MAKE IT EVEN
  945.     LD    L,A
  946.     LD    A,0
  947.     RRC    H
  948.     ADC    A,0            ;IF BIT 0 OF H SET, THEN C SET
  949.     RRC    A
  950.     OR    L
  951.     LD    L,A
  952.     LD    A,H
  953.     AND    07FH
  954.     LD    H,A
  955.     ADD    HL,BC            ;HL POINTS TO RECORD BETWEEN BC AND
  956.                     ;DE
  957.     PUSH    BC
  958.     PUSH    DE
  959.     PUSH    HL
  960.     LD    E,(HL)            ;DE= ADDRESS OF COMPARISON WORD IN BUFF
  961.     INC    HL
  962.     LD    D,(HL)
  963.     LD    HL,WORD            ;HL= ADDRESS OF NEW WORD BUFFER
  964. MEMWR2:    LD    A,(DE)            ;GET A CHARACTER
  965.     AND    07FH            ;KILL CARRY (FOR 0 BYTE OF CORRECTED
  966.                     ;WORDS)
  967.     CP    (HL)            ;COMPARE THEM
  968.     JP    NZ,MEMWR0        ;IF .NE. THEN TRY ANOTHER WORD
  969.     LD    A,0
  970.     CP    (HL)            ;END OF WORD?
  971.     DEC    DE            ;DECREMENT WORD TABLE POINTER (WORDS
  972.                     ;ARE STORED BACKWARDS
  973.     INC    HL            ;INCREMENT POINTER (DON'T AFFECT
  974.                     ;FLAGS)
  975.     JR    NZ,MEMWR2
  976.     POP    HL
  977.     POP    BC            ;TRASH OLD DE
  978.     POP    BC
  979.     INC    DE            ;POINT TO 0 OR 080H AT END OF WORD
  980.                     ; (80H IS CORRECTED AND WORD FOUND)
  981.     RET                ;DON'T BOTHER TO BUFFER THE SAME WORD
  982.  
  983. ;
  984. ; AUXDIC -- Open SPELL.DIC and load it into memory.  Open FILE.UDC and load
  985. ;    it as well.  If FILE.ADD exists (wordstar dictionary addition file),
  986. ;    load it and put its contents in FILE.UDC.
  987.  
  988. AUXDIC:    LD    HL,NEXT            ;ZERO THE MEMORY DICTIONARY
  989.     LD    A,0
  990.     LD    (HL),A
  991.  
  992. AUXDI2:    LD    DE,FILD$$        ;MAKE TEMPORARY .DIC OUTPUT FILE
  993.     LD    C,DELETE
  994.     CALL    BDOS
  995.     LD    DE,FILD$$
  996.     LD    C,MAKE
  997.     CALL    BDOS
  998.     LD    HL,FILD$$        ;PATCH THIS FCB INTO OUTPUT ROUTINE
  999.     LD    (OUTPAT),HL
  1000.     LD    A,(SAVPUT)        ;MAKE PUTCHR: WRITE TO A FILE
  1001.     LD    (PUTCHR),A
  1002.     LD    DE,FILDIC        ;TRY TO OPEN FILE.UDC
  1003.     LD    C,OPEN
  1004.     CALL    BDOS
  1005.     CP    0FFH            ;FOUND?
  1006.     JP    Z,AUXDI4        ;JUMP IF NOT
  1007.     LD    HL,FILDIC        ;PATCH GETCHR: TO READ FROM THIS FILE
  1008.     LD    (FILPAT),HL
  1009.     LD    HL,INBUF+512        ;PATCH INPTR TO READ ON FIRST CALL
  1010.     LD    (INPTR),HL
  1011. AUXDI3:    CALL    GETWRD            ;GET A WORD INTO SRCWRD:
  1012.     JP    Z,AUXDI4        ;IF EOF THEN START CHECKING
  1013.     CALL    CREWRD            ;CREATE WORD FROM SRCWRD:
  1014.     LD    A,0            ;IS IT AT LEAST 2 CHARS LONG?
  1015.     CP    C
  1016.     JR    Z,AUXDI3        ;FORGET IT IF NOT
  1017.     LD    A,41            ;IF LONGER THAN 40, ALSO FORGET IT
  1018.     CP    C
  1019.     JR    Z,AUXDI3
  1020.     PUSH    HL
  1021.     LD    HL,(FILUDC)        ;INCREMENT COUNTER FOR WORDS OUTPUT
  1022.     INC    HL            ;  TO FILE.UDC
  1023.     LD    (FILUDC),HL
  1024.     POP    HL
  1025.     CALL    SAVWRD            ;PUT WORD IN MEMORY
  1026.     LD    HL,WORD            ;PUT WORD IN OUTPUT FILE
  1027. AUXDH3:    LD    A,(HL)            ;GET A CHARACTER
  1028.     CP    0            ;END OF WORD?
  1029.     JR    Z,AUXDI3        ;QUIT OUTPUT IF END
  1030.     CALL    PUTCHR            ;OUTPUT CHARACTER
  1031.     INC    HL
  1032.     JR    AUXDH3
  1033.  
  1034. AUXDI4:    LD    DE,FILADD        ;TRY TO OPEN FILE.ADD
  1035.     LD    C,OPEN
  1036.     CALL    BDOS
  1037.     CP    0FFH            ;FOUND?
  1038.     JP    Z,AUXDI7        ;RETURN IF NOT
  1039.     LD    HL,FILADD        ;PATCH GETCHR: TO READ FROM FILE.ADD
  1040.     LD    (FILPAT),HL
  1041.     LD    HL,INBUF+512        ;SET INPTR TO READ ON FIRST CALL
  1042.     LD    (INPTR),HL
  1043.     LD    A,CR            ;PUT CR LF IN OUTPUT FILE
  1044.     CALL    PUTCHR
  1045.     LD    A,LF
  1046.     CALL    PUTCHR
  1047. AUXDI5:    CALL    GETCHR            ;GET A CHARACTER FROM FILE.ADD
  1048.                     ;IGNORE ALL WORD TYPES EXCEPT 0FFH
  1049.                     ;(EOF)
  1050.     CP    0FFH            ;END OF WORDS IN CURRENT RECORD?
  1051.     JR    Z,AUXDI5        ;IF YES, LOOP THROUGH RECORD
  1052.     CP    0            ;ZERO USED AS FILLER CHARACTER?
  1053.     JP    Z,AUXDI5
  1054.     CP    EOF            ;EOF?
  1055.     JP    Z,AUXDI7
  1056.     CALL    GETCHR            ;THIS CHARACTER IS LENGTH OF WORD
  1057.     CP    0            ;NO CHARACTERS?
  1058.     JR    Z,AUXDI5
  1059.     LD    B,A
  1060.     LD    HL,WORD            ;BUFFER IT IN WORD
  1061. AUXDI6:    CALL    GETCHR            ;GET A CHARACTER
  1062.     LD    (HL),A            ;SAVE IT IN WORD:
  1063.     INC    HL
  1064.     DJNZ    AUXDI6            ;GET WHOLE WORD
  1065.     LD    A,0            ;MARK END OF WORD
  1066.     LD    (HL),A
  1067.     CALL    SAVWRD            ;PUT WORD IN MEMORY
  1068.     JP    Z,AUXDI5        ;IF WORD ALREADY IN MEMORY THEN DON'T
  1069.                     ;OUTPUT TO FILE.UDC
  1070.     PUSH    HL
  1071.     LD    HL,(FILUDC)        ;INCREMENT COUNTER FOR WORDS OUTPUT
  1072.     INC    HL            ;  TO FILE.UDC
  1073.     LD    (FILUDC),HL
  1074.     POP    HL
  1075.     LD    HL,WORD            ;OUTPUT WORD
  1076. AUXDH6:    LD    A,(HL)            ;GET A CHARACTER
  1077.     INC    HL
  1078.     CP    0            ;END?
  1079.     JR    Z,AUXDK6
  1080.     CALL    PUTCHR
  1081.     JR    AUXDH6
  1082. AUXDK6:    LD    A,CR            ;PUT CR LF IN OUTPUT FILE
  1083.     CALL    PUTCHR
  1084.     LD    A,LF
  1085.     CALL    PUTCHR
  1086.     JP    AUXDI5            ;GET ANOTHER CHARACTER
  1087.  
  1088. AUXDI7:    LD    HL,OBUFF        ;WRITE OUT REMAINING DATA IN BUFFER
  1089.     LD    DE,128
  1090. AUXDI8:    LD    A,EOF            ;DONE?
  1091.     CP    (HL)
  1092.     JR    Z,AUXDJ0
  1093.     PUSH    DE
  1094.     PUSH    HL
  1095.     LD    D,H            ;SET UP DMA ADDRESS
  1096.     LD    E,L
  1097.     LD    C,SETDMA
  1098.     CALL    BDOS
  1099.     LD    DE,FILD$$        ;WRITE 128 BYTES TO FILE
  1100.     LD    C,WRITE
  1101.     CALL    BDOS
  1102.     POP    HL
  1103.     POP    DE
  1104.     CP    0            ;ERROR?
  1105.     JR    NZ,AUXDI9        ;DISK FULL --> BRANCH
  1106.     ADD    HL,DE            ;POINT TO NEXT RECORD
  1107.     JR    AUXDI8
  1108. AUXDI9:    LD    C,STROUT        ;DISK FULL
  1109.     LD    DE,DSKFUL        ;DISK FULL MESSAGE (SEE PUTCHR)
  1110.     CALL    BDOS
  1111.     CALL    BOOT
  1112.  
  1113. AUXDJ0:    CALL    RDICT            ;READ SPELL.DIC
  1114.     LD    HL,BOOT+81H        ;POINT TO INPUT LINE BUFFER
  1115.     LD    A,(BOOT+80H)        ;NUMBER OF CHARACTERS
  1116.     LD    B,A
  1117.     LD    A,' '            ;LOOK FOR A SPACE TO INDICATE END OF
  1118.                     ;INPUT FILE NAME
  1119. AUXDJ1:    CP    (HL)
  1120.     JR    Z,AUXDJ2        ;EXIT LOOP IF SPACE
  1121.     INC    HL            ;NEXT CHARACTER
  1122.     DJNZ    AUXDJ1            ;LOOP WHILE CHARACTERS LEFT
  1123.     JR    AUXRET            ;NOTHING AFTER FILE.  JUST RETURN.
  1124. AUXDJ2:    LD    A,'$'            ;NOW LOOK FOR $ TO INDICATE MORE DICTS.
  1125. AUXDJ3:    CP    (HL)
  1126.     JR    Z,AUXDJ4        ;EXIT LOOP IF FOUND
  1127.     INC    HL
  1128.     DJNZ    AUXDJ3            ;CONTINUE WHILE CHARACTERS LEFT
  1129.     JR    AUXRET            ;NOT FOUND
  1130. AUXDJ4:    LD    A,' '            ;ELMINATE SPACES
  1131.     INC    HL            ;SKIP '$'
  1132.     DJNZ    AUXDJ5            ;CONTINUE IF CHAR LEFT
  1133.     JR    AUXRET
  1134. AUXDJ5:    CP    (HL)
  1135.     JR    NZ,AUXDJ6        ;STOP IF NOT SPACE
  1136.     INC    HL
  1137.     DJNZ    AUXDJ5
  1138.     JR    AUXRET            ;DONE IF JUST SPACES
  1139. AUXDJ6:    LD    A,0
  1140.     LD    (SPLDIC),A        ;USE DEFAULT DRIVE
  1141.     LD    DE,SPLDIC+1        ;FCB BUFFER TO USE
  1142.     LD    A,' '            ;NULL FILE NAME (SPACES)
  1143.     PUSH    BC
  1144.     LD    B,8            ;FIRST DO FILENAME, NOT EXTENSION
  1145. AUXDJ7:    LD    (DE),A
  1146.     INC    DE            ;CLEAR ENTIRE FILENAME
  1147.     DJNZ    AUXDJ7
  1148.     LD    DE,SPLDIC+12        ;GET REST OF FCB
  1149.     LD    B,24
  1150.     LD    A,0            ;ZERO REST OF FCB
  1151. AUXDJ8:    LD    (DE),A
  1152.     INC    DE
  1153.     DJNZ    AUXDJ8
  1154.     POP    BC
  1155.     LD    DE,SPLDIC+1        ;POINT TO FCB
  1156.     LD    C,0            ;NO CHARACTERS WRITTEN TO FCB YET
  1157.     LD    A,2            ;ARE AT LEAST 3 CHAR LEFT?
  1158.     CP    B
  1159.     JP    NC,AUXDJ9        ;IF NOT, CAN'T BE A DRIVE SPECIFIED
  1160.     INC    HL
  1161.     LD    A,(HL)            ;SEE IF NEXT CHAR IS A ':'
  1162.     DEC    HL
  1163.     CP    ':'
  1164.     JR    NZ,AUXDJ9        ;JUMP IF NO DRIVE SPECIFIED
  1165.     LD    A,(HL)            ;GET THE DRIVE
  1166.     INC    HL            ;POINT TO NEXT CHAR AFTER :
  1167.     INC    HL
  1168.     DEC    B
  1169.     DEC    B
  1170.     AND    11011111B        ;MAKE SURE IT'S UPPER CASE
  1171.     SUB    'A'-1            ;MAKE DRIVE NUMBER BASED AT 0
  1172.     LD    (SPLDIC),A        ;STORE IT IN FCB
  1173. AUXDJ9:    LD    A,(HL)            ;GET A CHARACTER
  1174.     CP    ' '            ;END OF FILENAME?
  1175.     JR    Z,AUXDK2        ;READ THE FILE
  1176.     CP    '.'            ;PERIOD?  DISCARD EXTENSION IF YES.
  1177.     JR    Z,AUXDK0
  1178.     LD    (DE),A            ;FCB IT
  1179.     INC    DE
  1180.     INC    C
  1181.     LD    A,8            ;8 CHARACTERS WRITTEN YET?
  1182.     CP    C
  1183.     JR    Z,AUXDK0
  1184.     INC    HL
  1185.     DJNZ    AUXDJ9
  1186.     JR    AUXDK2            ;READ THE FILE
  1187. AUXDK0:    LD    A,' '            ;SEARCH FOR SPACE TO END FILENAME
  1188.                     ;DISCARD EXTRA CHARACTERS
  1189. AUXDK1:    CP    (HL)
  1190.     JR    Z,AUXDK2
  1191.     INC    HL            ;TRY NEXT CHAR
  1192.     DJNZ    AUXDK1
  1193. AUXDK2:    DEC    HL            ;POINT TO CHAR BEFORE END OR SPACE
  1194.     INC    B            ;1 MORE LEFT NOW
  1195.     CALL    RDICT            ;READ FROM THE DICTIONARY
  1196.     JP    AUXDJ4            ;TRY FOR ANOTHER DICTIONARY
  1197.  
  1198. AUXRET:    LD    DE,FILD$$        ;CLOSE TEMPORARY FILE
  1199.     LD    C,CLOSE
  1200.     CALL    BDOS
  1201.     LD    HL,OFCB            ;PATCH PUTCHR: TO OUTPUT TO FILE.$$$
  1202.     LD    (OUTPAT),HL
  1203.     LD    A,0C9H            ;RETURN OPCODE
  1204.     LD    (PUTCHR),A        ;MAKE PUTCHR: DO NOT OUTPUT
  1205.     CALL    CTRLZ            ;CLEAR OUTPUT BUFFER
  1206.     LD    HL,OBUFF        ;CLEAR OUTPUT BUFFER POSITION
  1207.     LD    (OPOSS),HL
  1208.     LD    HL,(FREE)        ;GET ADDRESS OF NEXT FREE BYTE
  1209.     INC    HL
  1210.     LD    (SRTBOT),HL        ;POINT TO TABLE FOR INPUT FILE INDEX
  1211.     INC    HL
  1212.     INC    HL
  1213.     LD    (SRTTOP),HL        ;TOP OF TABLE
  1214.     LD    HL,(BDOS+1)        ;GET ADDRESS OF BDOS
  1215.     DEC    HL            ;POINT TO FREE MEMORY
  1216.     LD    (FREE),HL
  1217.     LD    HL,INBUF+512
  1218.     LD    (INPTR),HL        ;SET INPUT FILE POINTER TO READ RECORD
  1219.                     ;ON NEXT GETCHR: CALL
  1220.     CALL    CTRLZ            ;CLEAN OUTPUT FILE BUFFER
  1221.     LD    A,LF            ;RESET LASTCH FOR INPUT
  1222.     LD    (LASTCH),A
  1223.     LD    DE,UDCMSG        ;OUTPUT: "Words read from...FILE.UDC"
  1224.     LD    C,STROUT
  1225.     CALL    BDOS
  1226.     LD    HL,(FILUDC)        ;NUMBER OF WORDS WRITTEN
  1227.     LD    B,H            ;GOES IN BC
  1228.     LD    C,L
  1229.     LD    HL,FILD$$        ;FCB ADDRESS IN HL
  1230.     LD    A,'U'            ;CHANGE 'FILENAME.D$$' TO '.UDC'
  1231.     LD    (FILD$$+9),A
  1232.     LD    A,'D'
  1233.     LD    (FILD$$+10),A
  1234.     LD    A,'C'
  1235.     LD    (FILD$$+11),A
  1236.     CALL    TYPFIL            ;WRITE FILENAME AND # TO CONSOLE
  1237.     LD    A,'D'            ;CHANGE IT BACK TO '.D$$'
  1238.     LD    (FILD$$+9),A
  1239.     LD    A,'$'
  1240.     LD    (FILD$$+10),A
  1241.     LD    (FILD$$+11),A
  1242.     RET
  1243. UDCMSG:    DB    CR,LF,'Words written to dictionary $'
  1244.  
  1245. ;
  1246. ; RDICT - Read dictionary in SPLDIC FCB
  1247. ;
  1248. RDICT:    PUSH    PSW
  1249.     PUSH    BC
  1250.     PUSH    DE
  1251.     PUSH    HL
  1252.     LD    HL,INBUF+512
  1253.     LD    (INPTR),HL        ;SET INPUT FILE POINTER TO READ RECORD
  1254.                     ;ON NEXT GETCHR CALL
  1255.     LD    HL,0
  1256.     LD    (SPLDC),HL        ;RESET # WORDS READ
  1257.     LD    DE,SPLDIC        ;FCB FOR SPELL.DIC
  1258.     LD    C,OPEN
  1259.     CALL    BDOS
  1260.     PUSH    PSW
  1261.     LD    C,CURDSK        ;GET THE DEFAULT DRIVE BEFORE ITS
  1262.     CALL    BDOS            ;    TOO LATE
  1263.     INC    A
  1264.     LD    (DEFDRV),A
  1265.     POP    PSW
  1266.     CP    0FFH            ;FOUND?
  1267.     JR    NZ,RDICT0        ;YES, READ FROM IT
  1268.     LD    A,(SPLDIC)        ;WAS DEFAULT DRIVE TESTED?
  1269.     CP    0
  1270.     JR    NZ,RDICT2        ;IF SPECIFIC DRIVE TESTED AND NOT
  1271.                     ;FOUND THEN GIVE UP
  1272.     LD    A,1            ;TRY DRIVE "A"
  1273.     LD    (SPLDIC),A
  1274.     LD    DE,SPLDIC
  1275.     LD    C,OPEN
  1276.     CALL    BDOS
  1277.     CP    0FFH            ;FOUND?
  1278.     JP    Z,RDICT2        ;IF NOT, GIVE UP
  1279. RDICT0:    LD    HL,SPLDIC        ;PATCH FCB ADDRESS INTO GETWRD
  1280.     LD    (FILPAT),HL
  1281. RDICT1:    CALL    GETWRD            ;GET A WORD INTO SRCWRD:
  1282.     JP    Z,RDICT3        ;IF EOF THEN START CHECKING
  1283.     CALL    CREWRD            ;CREATE WORD FROM SRCWRD:
  1284.     LD    A,0            ;IS IT AT LEAST 2 CHARS LONG?
  1285.     CP    C
  1286.     JR    Z,RDICT1        ;FORGET IT IF NOT
  1287.     LD    A,41            ;IF LONGER THAN 40, ALSO FORGET IT
  1288.     CP    C
  1289.     JR    Z,RDICT1
  1290.     PUSH    HL
  1291.     LD    HL,(SPLDC)        ;INCREMENT COUNTER FOR WORDS IN
  1292.     INC    HL            ;   SPELL.DIC
  1293.     LD    (SPLDC),HL
  1294.     POP    HL
  1295.     CALL    SAVWRD            ;PUT WORD IN MEMORY
  1296.     JR    RDICT1
  1297.  
  1298. RDICT2:    LD    DE,RNT            ;PRINT CR,LF
  1299.     LD    C,STROUT
  1300.     CALL    BDOS
  1301.     LD    A,(SPLDIC)            ;DEFAULT DRIVE USED?
  1302.     CP    0
  1303.     JR    NZ,RDICU0        ;JUMP IF NOT
  1304.     LD    A,(DEFDRV)        ;GET DEFAULT DRIVE
  1305.     LD    (SPLDIC),A        ;AND PUT IT IN FCB
  1306. RDICU0:    LD    A,(SPLDIC)        ;GET DRIVE
  1307.     ADD    A,'A'-1            ;MAKE IT A LETTER
  1308.     LD    C,CONOUT
  1309.     LD    E,A
  1310.     CALL    BDOS            ;PRINT DRIVE NAME
  1311.     LD    E,':'
  1312.     LD    C,CONOUT
  1313.     CALL    BDOS            ;AND A COLON
  1314.     LD    DE,SPLDIC+1        ;POINT TO FILENAME
  1315.     LD    HL,SPLDIC+12        ;POINT TO FIRST BYTE AFTER NAME
  1316.     LD    A,'$'
  1317.     LD    (SPLDIC+12),A        ;MARK END FOR OUPTUT
  1318.     LD    C,STROUT
  1319.     CALL    BDOS            ;PRINT THE FILE NAME
  1320.  
  1321.     LD    DE,RNT0            ;PRINT NOT FOUND
  1322.     LD    C,STROUT
  1323.     CALL    BDOS
  1324.     JR    RDICTR
  1325. RNT:    DB    CR,LF,'$'
  1326. RNT0:    DB    ' not found$'
  1327.  
  1328. RDICT3:    LD    DE,RDIWRD        ;FOUND MESSAGE
  1329.     LD    C,STROUT
  1330.     CALL    BDOS
  1331.     LD    HL,(SPLDC)        ;STORE # WORDS READ IN BC
  1332.     LD    B,H
  1333.     LD    C,L
  1334.     LD    HL,SPLDIC        ;FCB ADDRESS
  1335.     CALL    TYPFIL            ;TYPE FILE NAME AND # WORDS IN IT
  1336.     JR    RDICTR
  1337. RDIWRD:    DB    CR,LF,'Words read from dictionary  $'
  1338.  
  1339. RDICTR:    POP    HL
  1340.     POP    DE
  1341.     POP    BC
  1342.     POP    PSW
  1343.     RET
  1344.  
  1345. ;
  1346. ; TYPFIL -- print name of dictionary file being read and words found in it
  1347. ;
  1348. ;    Input:  BC -->  Number of words found in file
  1349. ;        HL -->  Address of file's FCB
  1350. ;
  1351. TYPFIL:    PUSH    PSW
  1352.     PUSH    BC
  1353.     PUSH    DE
  1354.     PUSH    HL
  1355.     LD    A,(HL)            ;DEFAULT DRIVE USED?
  1356.     CP    0
  1357.     JR    NZ,TYPFI0        ;JUMP IF NOT
  1358.     LD    A,(DEFDRV)        ;GET DEFAULT DRIVE
  1359.     LD    (HL),A            ;AND PUT IT IN FCB
  1360. TYPFI0:    LD    A,(HL)            ;GET DRIVE
  1361.     ADD    A,'A'-1            ;MAKE IT A LETTER
  1362.     PUSH    BC
  1363.     PUSH    HL
  1364.     LD    C,CONOUT
  1365.     LD    E,A
  1366.     CALL    BDOS            ;PRINT DRIVE NAME
  1367.     LD    E,':'
  1368.     LD    C,CONOUT
  1369.     CALL    BDOS            ;AND A COLON
  1370.     POP    HL
  1371.     LD    D,H
  1372.     LD    E,L
  1373.     INC    DE            ;POINT TO FILENAME
  1374.     LD    BC,12
  1375.     ADD    HL,BC            ;HL POINTS TO END OF FILENAME
  1376.     LD    A,'$'
  1377.     LD    (HL),A            ;MARK END FOR OUPTUT
  1378.     LD    C,STROUT
  1379.     CALL    BDOS            ;PRINT THE FILE NAME
  1380.     LD    DE,TYPSPA        ;PRINT SPACES AFTER NAME
  1381.     LD    C,STROUT
  1382.     CALL    BDOS
  1383.     POP    BC
  1384.     LD    H,B            ;NUMBER OF WORDS FOUND
  1385.     LD    L,C
  1386.     CALL    DECOUT            ;PRINT NUMBER
  1387.     POP    HL
  1388.     POP    DE
  1389.     POP    BC
  1390.     POP    PSW
  1391.     RET
  1392. TYPSPA:    DB    ':    $'
  1393.  
  1394. ;
  1395. ; SAVWRD -- put WORD in memory dictionary
  1396. ;
  1397.  
  1398. SAVWRD:    CALL    USRTST            ;WAS WORD ALREADY MARKED?
  1399.     CP    1
  1400.     RET    Z            ;RETURN WITH Z SET IF ALREADY MARKED
  1401.     LD    HL,(FREE)        ;GET NEXT AVAILABLE BYTE
  1402.     LD    DE,WORD            ;POINT TO WORD
  1403. SAVWR0:    LD    A,(DE)            ;GET A CHARACTER
  1404.     LD    (HL),A            ;STORE IT IN BUFFER
  1405.     INC    DE            ;INCREMENT POINTERS
  1406.     INC    HL
  1407.     CP    0            ;END OF WORD?
  1408.     JR    NZ,SAVWR0
  1409.     LD    (HL),A            ;MARK END OF TABLE WITH 0
  1410.     LD    (FREE),HL        ;UPDATE FREE MEMORY POINTER
  1411.     LD    A,1
  1412.     AND    A            ;MAKE FOR Z NOT SET
  1413.     RET
  1414.  
  1415. ;
  1416. ; WRDTST -- Search for WORD in dictionary.  If it is not found, try
  1417. ;    stripping of suffixes and looking for new word with a flag set.
  1418. ;
  1419. ;        Returns in A:  0 <-- WORD not found
  1420. ;                   1 <-- WORD found
  1421. ;                   2 <-- root word found but necessary
  1422. ;                     suffix flag not set.  Returned
  1423. ;                     only if suffixes were stripped.
  1424.  
  1425. WRDTST:    PUSH    BC
  1426.     PUSH    DE
  1427.     PUSH    HL
  1428.     LD    HL,0
  1429.     LD    (FLAG),HL        ;NO FLAGS FOR FIRST LOOKUP
  1430.     CALL    FINDIT            ;LOOK FOR WORD IN DICTIONARY
  1431.     PUSH    PSW
  1432.     LD    A,1            ;ASSUME THAT WORD WAS FOUND AND
  1433.                     ;INDICATE WORKING IN ALPHABETICAL ORDER
  1434.                     ;STILL (DECODING OF CURRENT RECORD
  1435.                     ;BY LOOKUP ROUTINE CAN CONTINUE FROM
  1436.                     ;CURRENT POSITION)
  1437.     LD    (ALPHA),A
  1438.     POP    PSW
  1439.     CP    0            ;NOT FOUND?
  1440.     JP    Z,WRDTS0        ;KEEP TRYING IF NOT FOUND
  1441. WRDRET:    POP    HL
  1442.     POP    DE
  1443.     POP    BC
  1444.     RET
  1445.  
  1446. WRDTS0:    CALL    USRTST            ;TEST USER DICTIONARY
  1447.     CP    1            ;FOUND?
  1448.     JP    Z,WRDRET
  1449.     LD    A,0            ;NOT WORKING IN ALPHABETICAL ORDER
  1450.                     ;ANY MORE
  1451.     LD    (ALPHA),A
  1452.     LD    HL,LASTC        ;PUT NUMBER OF CHARACTERS -1 IN C
  1453.     LD    C,(HL)
  1454.     LD    B,0            ;MAKE BC AN OFFSET TO LAST CHAR
  1455.     LD    HL,WORD            ;POINT TO WORD
  1456.     ADD    HL,BC            ;POINT TO LAST CHARACTER IN WORD
  1457.     LD    A,(HL)
  1458.     QISIT    'E',FLGV        ;WORD ENDS IN "E"
  1459.     QISIT    'H',FLGH        ;"H"
  1460.     QISIT    'Y',FLGY        ;"LY"
  1461.     QISIT    'G',FLGG        ;"ING"
  1462.     QISIT    'N',FLGN        ;"TION, "EN"
  1463.     QISIT    'D',FLGD        ;"ED", "IED"
  1464.     QISIT    'T',FLGT        ;"EST", "IEST"
  1465.     QISIT    'R',FLGR        ;"ER", "IER"
  1466.     QISIT    'S',FLGS        ;LOTS OF WORDS ENDING IN "S"
  1467.     LD    A,0
  1468.     JP    WRDRET            ;NO FLAGS FIT
  1469.  
  1470. FLGV:    LD    A,2            ;WORD MUST BE 4 CHARS LONG
  1471.     CP    C
  1472.     JP    P,WRDNOT        ;NOT FOUND IF TOO SHORT
  1473.     LD    DE,VFLAG        ;LOOKING FOR V FLAG
  1474.     LD    (FLAG),DE
  1475.     DEC    HL            ;CHARACTER BEFORE
  1476.     ISIT    'V'
  1477.     DEC    HL
  1478.     ISIT    'I'
  1479.     LD    (HL),'E'        ;GET "CREATIVE"
  1480.     INC    HL
  1481.     LD    (HL),0
  1482.     CALL    FINDIT
  1483.     CP    0            ;FOUND?
  1484.     JP    NZ,WRDRET        ;BRANCH IF FOUND
  1485.     DEC    HL            ;POINT TO CHAR BEFORE NEW "E"
  1486.     DEC    HL
  1487.     JISIT    'E',WRDNOT        ;KILL "CREATEIVE"
  1488.     INC    HL
  1489.     LD    (HL),0
  1490.     CALL    FINDIT
  1491.     JP    WRDRET
  1492.  
  1493. FLGH:    LD    A,2            ;MUST BE 4 CHARS LONG
  1494.     CP    C
  1495.     JP    P,WRDNOT
  1496.     LD    DE,HFLAG        ;SEEKING WORD WITH H FLAG SET
  1497.     LD    (FLAG),DE
  1498.     DEC    HL
  1499.     ISIT    'T'
  1500.     DEC    HL
  1501.     JISIT    'Y',WRDNOT        ;KILL "TWENTYTH"
  1502.     INC    HL
  1503.     LD    (HL),0            ;NEW END OF WORD
  1504.     CALL    FINDIT            ;GET "HUNDREDTH"
  1505.     CP    0            ;FOUND?
  1506.     JP    NZ,WRDRET        ;RETURN IS FOUND
  1507.     LD    A,4            ;WORDS WITH "IETH" MUST BE 6 CHARS LONG
  1508.     CP    C
  1509.     JP    P,WRDNOT
  1510.     DEC    HL
  1511.     ISIT    'E'
  1512.     DEC    HL
  1513.     ISIT    'I'
  1514.     LD    (HL),'Y'        ;MODIFY WORD TO END IN "Y"
  1515.     INC    HL
  1516.     LD    (HL),0
  1517.     CALL    FINDIT            ;GET "TWENTIETH"
  1518.     JP    WRDRET
  1519.  
  1520. FLGY:    LD    A,2            ;MUST BE 4 CHARACTERS LONG (AT LEAST)
  1521.     CP    C
  1522.     JP    P,WRDNOT
  1523.     LD    DE,YFLAG        ;WORDS MUST HAVE Y FLAG SET
  1524.     LD    (FLAG),DE
  1525.     DEC    HL
  1526.     ISIT    'L'
  1527.     LD    (HL),0            ;MARK NEW END OF WORD
  1528.     CALL    FINDIT            ;GET "QUICKLY"
  1529.     JP    WRDRET
  1530.  
  1531. FLGG:    LD    A,2            ;MUST BE AT LEAST 4 CHARS LONG
  1532.     CP    C
  1533.     JP    P,WRDNOT
  1534.     LD    DE,GFLAG        ;SET G FLAG
  1535.     LD    (FLAG),DE
  1536. FLGGE:    DEC    HL
  1537.     ISIT    'N'
  1538.     DEC    HL
  1539.     ISIT    'I'
  1540.     LD    (HL),'E'
  1541.     INC    HL
  1542.     LD    (HL),0
  1543.     CALL    FINDIT            ;GET "FILING"
  1544.     CP    0
  1545.     JP    NZ,WRDRET        ;RETURN IF FOUND
  1546.     DEC    HL
  1547.     DEC    HL
  1548.     JISIT    'E',WRDNOT        ;KILL "FILEING"
  1549.     INC    HL
  1550.     LD    (HL),0
  1551.     CALL    FINDIT            ;GET "CROSSING"
  1552.     JP    WRDRET
  1553.  
  1554. FLGN:    LD    A,2            ;MUST BE 4 CHARS LONG
  1555.     CP    C
  1556.     JP    P,WRDNOT
  1557.     LD    DE,NFLAG        ;SET N FLAG
  1558.     LD    (FLAG),DE
  1559. FLGNEE:    DEC    HL
  1560.     JISIT    'O',FLGNO        ;WORD WITH "TION"
  1561.     ISIT    'E'            ;IF .EQ. "TION" THEN .EQ. "EN"
  1562.     DEC    HL
  1563.     JISIT    'E',WRDNOT        ;KILL "CREATEEN"
  1564.     JISIT    'Y',WRDNOT        ;KILL "MULTIPLYEN"
  1565.     INC    HL
  1566.     LD    (HL),0
  1567.     CALL    FINDIT            ;GET "FALLEN"
  1568.     JP    WRDRET
  1569. FLGNO:    LD    A,3            ;MUST BE 4 CHARS LONG
  1570.     CP    C
  1571.     JP    P,WRDNOT
  1572.     DEC    HL
  1573.     ISIT    'I'
  1574.     LD    (HL),'E'
  1575.     INC    HL
  1576.     LD    (HL),0
  1577.     CALL    FINDIT            ;GET "CREATION"
  1578.     CP    0
  1579.     JP    NZ,WRDRET        ;RETURN IF FOUND
  1580.     LD    A,7            ;MUST BE AT LEAST 9 CHARS LONG
  1581.     CP    C
  1582.     JP    P,WRDNOT
  1583.     DEC    HL
  1584.     DEC    HL
  1585.     ISIT    'T'
  1586.     DEC    HL
  1587.     ISIT    'A'
  1588.     DEC    HL
  1589.     ISIT    'C'
  1590.     DEC    HL
  1591.     ISIT    'I'
  1592.     LD    (HL),'Y'
  1593.     INC    HL
  1594.     LD    (HL),0
  1595.     CALL    FINDIT
  1596.     JP    WRDRET
  1597.  
  1598. FLGD:    LD    A,2            ;MUST BE 4 CHARACTERS LONG
  1599.     CP    C
  1600.     JP    P,WRDRET
  1601.     LD    DE,DFLAG        ;SET D FLAG
  1602.     LD    (FLAG),DE
  1603. FLGDE:    DEC    HL
  1604.     ISIT    'E'
  1605.     INC    HL
  1606.     LD    (HL),0
  1607.     CALL    FINDIT            ;GET "CREATED"
  1608.     CP    0
  1609.     JP    NZ,WRDRET
  1610.     DEC    HL
  1611.     DEC    HL
  1612.     JISIT    'E',WRDNOT        ;KILL "CREATEED"
  1613.     LD    A,(HL)
  1614.     CP    'Y'            ;IF .NE. "Y" TRY OTHER SUFFIXES
  1615.     JP    NZ,FLGD5
  1616.     DEC    HL
  1617.     CALL    VOWEL            ;VOWEL MUST BE BEFORE "Y"
  1618.     JP    NZ,WRDNOT
  1619.     INC    HL
  1620.     INC    HL
  1621.     LD    (HL),0
  1622.     CALL    FINDIT            ;GET "CONVEYED"
  1623.     JP    WRDRET
  1624. FLGD5:    INC    HL
  1625.     LD    (HL),0
  1626.     CALL    FINDIT            ;GET "CROSSED"
  1627.     CP    0
  1628.     JP    NZ,WRDRET        ;RETURN IF FOUND
  1629.     DEC    HL
  1630.     ISIT    'I'
  1631.     DEC    HL
  1632.     CALL    VOWEL            ;CAN'T BE A VOWEL
  1633.     JP    Z,WRDNOT
  1634.     INC    HL
  1635.     LD    (HL),'Y'
  1636.     INC    HL
  1637.     LD    (HL),0
  1638.     CALL    FINDIT            ;GET "IMPLIED"
  1639.     JP    WRDRET
  1640.  
  1641. FLGT:    LD    A,2            ;MUST BE AT LEAST 4 CHARS LONG
  1642.     CP    C
  1643.     JP    P,WRDNOT
  1644.     LD    DE,TFLAG        ;T FLAG MUST BE SET
  1645.     LD    (FLAG),DE
  1646.     DEC    HL
  1647.     JISIT    'S',FLGDE        ;SAME RULES AS 'D' FLAG IF ENDS
  1648.                     ;IN "ST"
  1649.     JP    WRDNOT            ;NOT FOUND IF NOT "ST"
  1650.  
  1651. FLGR:    LD    A,2            ;MUST BE AT LEAST 4 CHARS LONG
  1652.     CP    C
  1653.     JP    P,WRDNOT
  1654.     LD    DE,RFLAG        ;SET R FLAG
  1655.     LD    (FLAG),DE
  1656. FLGRE:    JP    FLGDE            ;SAME RULES AS D FLAG
  1657.  
  1658. FLGS:    LD    A,2            ;MUST BE 4 CHARS LONG
  1659.     CP    C
  1660.     JP    P,WRDNOT
  1661.     LD    DE,SFLAG        ;TRY PURE "S" FLAG FIRST
  1662.     LD    (FLAG),DE
  1663.     DEC    HL
  1664.     JISIT    'S',FLGP        ;"NESS", "INESS"
  1665.     JISIT    27H,FLGM        ;"'S"
  1666.     CALL    SXZH            ;IS IT S, X, Z OR H?
  1667.     JP    Z,WRDNOT        ;IF YES, THEN ILLEGAL WORD
  1668.     LD    A,(HL)            ;PURE "S" LEGAL IF .NE. "Y"
  1669.     CP    'Y'
  1670.     JR    NZ,FLGS2
  1671.     DEC    HL
  1672.     CALL    VOWEL
  1673.     JP    NZ,WRDNOT        ;ILLEGAL WORD IF NOT A VOWEL
  1674.     INC    HL
  1675. FLGS2:    INC    HL
  1676.     LD    (HL),0
  1677.     CALL    FINDIT            ;GET "CONVEYS", "BATS"
  1678.     CP    0
  1679.     JP    NZ,WRDRET        ;RETURN IF FOUND
  1680.     DEC    HL
  1681.     LD    A,(HL)
  1682.     QISIT    'R',FLGZ        ;"ERS", "IERS"
  1683.     QISIT    'N',FLGX        ;"IONS", "ICATIONS", "ENS"
  1684.     QISIT    'G',FLGJ        ;"INGS"
  1685.     ISIT    'E'
  1686.     DEC    HL
  1687.     CALL    SXZH
  1688.     JP    NZ,FLGS5        ;IF LETTER NOT S,X,Z OR H TRY "IES"
  1689.     INC    HL
  1690.     LD    (HL),0
  1691.     CALL    FINDIT            ;GET "FIXES"
  1692.     JP    WRDRET
  1693. FLGS5:    ISIT    'I'
  1694.     DEC    HL
  1695.     CALL    VOWEL
  1696.     JP    Z,WRDNOT        ;CAN'T BE A VOWEL
  1697.     INC    HL
  1698.     LD    (HL),'Y'
  1699.     INC    HL
  1700.     LD    (HL),0
  1701.     CALL    FINDIT            ;GET "IMPLIES"
  1702.     JP    WRDRET
  1703.  
  1704. FLGX:    LD    DE,XFLAG        ;SET X FLAG
  1705.     LD    (FLAG),DE
  1706.     JP    FLGNEE            ;SAVE AS "N" FLAG NOW
  1707.  
  1708. FLGJ:    LD    DE,JFLAG        ;SET J FLAG
  1709.     LD    (FLAG),DE
  1710.     JP    FLGGE            ;SAVE AS "G" FLAG NOW
  1711.  
  1712. FLGZ:    LD    DE,ZFLAG        ;SET Z FLAG
  1713.     LD    (FLAG),DE
  1714.     JP    FLGRE            ;SAVE AS "R" FLAG NOW
  1715.  
  1716. FLGP:    LD    A,3            ;MUST BE 5 CHARS LONG
  1717.     CP    C
  1718.     JP    P,WRDNOT
  1719.     LD    DE,PFLAG        ;SET P FLAG
  1720.     LD    (FLAG),DE
  1721.     DEC    HL
  1722.     ISIT    'E'
  1723.     DEC    HL
  1724.     ISIT    'N'
  1725.     DEC    HL
  1726.     LD    A,(HL)
  1727.     CP    'Y'
  1728.     JP    NZ,FLGP4        ;LEGAL IF .NE. "Y"
  1729.     DEC    HL
  1730.     CALL    VOWEL
  1731.     JP    NZ,WRDNOT        ;ILLEGAL IF "Y" AND NO VOWEL
  1732.     INC    HL
  1733. FLGP4:    INC    HL
  1734.     LD    (HL),0
  1735.     CALL    FINDIT            ;GET "LATENESS", "GRAYNESS"
  1736.     CP    0
  1737.     JP    NZ,WRDRET        ;RETURN IF FOUND
  1738.     DEC    HL
  1739.     ISIT    'I'
  1740.     DEC    HL
  1741.     CALL    VOWEL
  1742.     JP    Z,WRDNOT        ;CAN'T BE A VOWEL
  1743.     INC    HL
  1744.     LD    (HL),'Y'
  1745.     INC    HL
  1746.     LD    (HL),0
  1747.     CALL    FINDIT            ;GET "CLOUDINESS"
  1748.     JP    WRDRET
  1749.  
  1750. FLGM:    LD    DE,MFLAG        ;SET M FLAG
  1751.     LD    (FLAG),DE
  1752.     LD    (HL),0
  1753.     CALL    FINDIT            ;GET "DOG'S"
  1754.     JP    WRDRET
  1755.  
  1756. WRDNOT:    LD    A,0            ;NOT FOUND
  1757.     JP    WRDRET
  1758. ;
  1759. ; VOWEL -- determine whether character in (HL) is a vowel.
  1760. ;
  1761. ;        Returns:  Z flag SET <-- is a vowel
  1762. ;              Z flag CLEAR <-- is not a vowel
  1763.  
  1764. VOWEL:    PUSH    BC
  1765.     PUSH    HL
  1766.     LD    A,(HL)            ;GET CHARACTER
  1767.     LD    HL,VOWELS        ;POINTER TO VOWELS
  1768.     LD    BC,5            ;5 VOWELS
  1769.     CPIR                ;TEST AGAINST ALL VOWELS
  1770.                     ;SET STATUS BITS TO BE USED AFTER RET
  1771.     POP    HL
  1772.     POP    BC
  1773.     RET
  1774. VOWELS:    DB    'AEIOU'
  1775.  
  1776. ;
  1777. ; SXZH -- same as VOWEL put for the characters S, X, Z and H
  1778.  
  1779. SXZH:    PUSH    BC
  1780.     PUSH    HL
  1781.     LD    A,(HL)            ;GET CHARACTER
  1782.     LD    HL,SXZH0        ;POINTER TO CHARACTER LIST
  1783.     LD    BC,4            ;4 POTENTIAL MATCHES
  1784.     CPIR                ;TEST AGAINST S, X, Z, H
  1785.     POP    HL
  1786.     POP    BC
  1787.     RET
  1788. SXZH0:    DB    'SXZH'
  1789.  
  1790. ;
  1791. ; Determine which record of dictionary would contain WORD.  Puts record in
  1792. ;    BC
  1793.  
  1794. FINDIT:    PUSH    BC
  1795.     PUSH    DE
  1796.     PUSH    HL
  1797.     LD    A,(ALPHA)        ;STILL IN ALPHABETICAL ORDER?
  1798.     AND    A
  1799.     JP    NZ,FINLO5        ;DON'T DECREMENT POINTERS IF YES
  1800.  
  1801.     LD    HL,(LSTADR)        ;GET ADDRESS OF LAST DICTIONARY POINTER
  1802.                     ;USED
  1803. FINLOW:    LD    DE,WORD
  1804.     EX    DE,HL
  1805.     LD    BC,4
  1806. FINLO1:    LD    A,(DE)            ;MAKE SURE THAT CURRENT RECORD IS
  1807.                     ;BEFORE WORD
  1808.     INC    DE
  1809.     CPI
  1810.     JP    M,FINLO5        ;IF EARLIER, JUMP
  1811.     JR    NZ,FINLO2        ;IF LATER, THEN DECREMENT
  1812.     JP    PE,FINLO1        ;LOOP WHILE BC-1 .NE. 0
  1813. FINLO2:    LD    BC,(LSTREC)        ;DECREMENT THE POINTERS
  1814.     DEC    BC
  1815.     LD    HL,0            ;IS IT TOO LOW?
  1816.     XOR    A
  1817.     SBC    HL,BC
  1818.     JR    Z,FINLO5        ;IF SO, THEN FORGET IT
  1819.     LD    (LSTREC),BC
  1820.     LD    HL,(LSTADR)
  1821.     LD    DE,4
  1822.     XOR    A            ;CLEAR CARRY
  1823.     SBC    HL,DE
  1824.     LD    (LSTADR),HL
  1825.     JP    FINLOW            ;TRY AGAIN
  1826.  
  1827. FINLO5:    LD    BC,(LSTREC)        ;GET LAST RECORD NUMBER READ
  1828.     LD    HL,(LSTADR)        ;GET ADDRESS OF LAST DICTIONARY POINTER
  1829.                     ;USED
  1830. FINDI0:    PUSH    BC
  1831.     PUSH    HL
  1832.     LD    DE,WORD
  1833.     EX    DE,HL
  1834.     LD    BC,4            ;COMPARING UP TO 4 CHARACTERS
  1835. FINDI1:    LD    A,(DE)            ;GET A CHARACTER FROM POINTER TABLE
  1836.     INC    DE
  1837.     CPI                ;COMPARE TO WORD:
  1838.     JR    NZ,FINDI2        ;JUMP IF DIFFERENT
  1839.     JP    PO,FINDI3        ;JUMP IF ALL 4 CHARACTERS EQUAL
  1840.     JR    FINDI1            ;TRY ANOTHER
  1841. FINDI2:    JP    P,FINDI3        ;TOO FAR IN DICTIONARY
  1842.     LD    DE,4
  1843.     POP    HL
  1844.     POP    BC
  1845.     ADD    HL,DE            ;POINT TO NEXT RECORD INDEX
  1846.     INC    BC
  1847.     JP    FINDI0
  1848. FINDI3:    POP    HL
  1849.     POP    BC
  1850. FINDI4:    DEC    BC
  1851.     LD    DE,4
  1852.     XOR    A            ;CLEAR CARRY
  1853.     SBC    HL,DE
  1854.     LD    (LSTREC),BC        ;UPDATE POINTERS
  1855.     LD    (LSTADR),HL
  1856.  
  1857. ;
  1858. ; LOOKUP -- loop through as many records as it takes to be sure that word is
  1859. ;    not in dictionary
  1860.  
  1861. LOOKUP:    CALL    DICFND
  1862.     CP    0FFH            ;IF RETURN STATUS=0FFH THEN WORD COULD
  1863.                     ;BE IN NEXT RECORD
  1864.     JR    NZ,LOOKU0        ;RETURN IF NOT IN NEXT RECORD
  1865.     INC    BC
  1866.     LD    HL,0+(TABBOT-TABTOP)/4    ;MAKE SURE NOT PAST LAST RECORD
  1867.     XOR    A            ;CLEAR THE CARRY BIT
  1868.     SBC    HL,BC
  1869.     JR    NZ,LOOKUP        ;TRY NEXT RECORD IF NOT AT END
  1870.     LD    A,0
  1871. LOOKU0:    POP    HL            ;RESTORE THE STACK
  1872.     POP    DE
  1873.     POP    BC
  1874.     RET
  1875.  
  1876. ;
  1877. ; DICFND  -- read record in BC from dictionary.  Determine whether WORD is
  1878. ;    in it.
  1879. ;
  1880. ;        Returns in A:  0 <-- word not found
  1881. ;                   1 <-- word found
  1882. ;                   2 <-- word found but flag not set
  1883. ;                 0FFH<-- word not found but it may be in next
  1884. ;                     record
  1885.  
  1886. DICFND:    PUSH    HL
  1887.     PUSH    DE
  1888.     PUSH    BC
  1889.     RLC    B            ;MULTIPLY BC BY 2 SO IT POINTS TO
  1890.                     ;256 BYTE RECORD
  1891.     RLC    C
  1892.     LD    A,0
  1893.     ADC    A,B            ;GET THE CARRY FROM RLC C
  1894.     LD    B,A
  1895.     LD    A,C
  1896.     AND    0FEH            ;KILL BIT 0
  1897.     LD    C,A
  1898.     LD    HL,(DICREC)        ;GET THE CURRENT RECORD IN RAM
  1899.     DEC    HL            ;POINT TO FIRST 128 BYTES OF 256
  1900.                     ;BYTE DICTIONARY RECORDS
  1901.     XOR    A            ;CLEAR CARRY BIT
  1902.     SBC    HL,BC            ;ATTEMPT TO READ THE SAME RECORD?
  1903.     JR    NZ,DICDSK        ;IF NO, READ FROM DISK
  1904.     LD    A,(ALPHA)        ;WORKING IN APHABETICAL ORDER?
  1905.     AND    A
  1906.     JP    NZ,DICFO1        ;JUST GET ANOTHER WORD IF YES
  1907.     LD    A,(CURBIT)        ;ROTATE CURRENT BYTE SO IT IS THE RIGHT
  1908.                     ;POSITION IN CASE SAME RECORD USED
  1909.     AND    0111B            ;IS IT ON CORRECT ROTATION NOW?
  1910.     JR    Z,DICFN0
  1911.     LD    HL,(CURBYT)        ;ADDRESS OF CURRENT BYTE
  1912.     LD    B,A
  1913.     LD    A,8            ;MUST COMPLETE 8 ROTATIONS, TOTAL
  1914.     SUB    B            ;SUBTRACT NUMBER ALREADY DONE
  1915.     LD    B,A
  1916. ROTATE:    RLC    (HL)
  1917.     DJNZ    ROTATE
  1918.     JP    DICFN0            ;START TESTING WORDS
  1919. DICDSK:    PUSH    BC
  1920.     LD    (DICREC),BC        ;NEW RECORD TO READ
  1921.     LD    C,SETDMA        ;SET DMA TO DICTIONARY BUFFER
  1922.     LD    DE,DICBUF        ;DICIONARY BUFFER IN RAM
  1923.     CALL    BDOS
  1924.     LD    C,RANREA        ;BDOS RANDOM READ CODE
  1925.     LD    DE,DICFCB        ;FCB OF DICTIONARY
  1926.     CALL    BDOS
  1927.     POP    BC
  1928.     INC    BC            ;GET 256 BYTES
  1929.     LD    (DICREC),BC        ;NEXT RECORD NUMBER
  1930.     LD    C,SETDMA        ;DMA ADDRESS 256 BYTES HIGHER
  1931.     LD    DE,DICBUF+128
  1932.     CALL    BDOS
  1933.     LD    C,RANREA
  1934.     LD    DE,DICFCB
  1935.     CALL    BDOS            ;READ NEXT RECORD
  1936.  
  1937. DICFN0:    LD    HL,DICBUF-1        ;INITIALIZE POINTER TO DICTIONARY
  1938.                     ;BUFFER
  1939.     LD    (CURBYT),HL
  1940.     LD    A,0            ;CURRENT BIT=0
  1941.     LD    (CURBIT),A
  1942. DICFN1:    CALL    MOVWRD            ;GET A WORD
  1943. DICFO1:    LD    HL,WORD            ;POINT TO WORD
  1944.     LD    BC,DICWRD        ;POINTER TO DICTIONARY WORD
  1945. DICFN2:    LD    A,(BC)            ;GET A LETTER FROM DICTIONARY WORD
  1946.     CP    (HL)            ;THE SAME?
  1947.     INC    HL            ;POINT TO NEXT CHARACTER
  1948.     INC    BC
  1949.     JR    NZ,DICFN4        ;IF NOT, TRY SOME MORE OR END
  1950.     CP    0            ;END OF WORD?
  1951.     JR    NZ,DICFN2        ;TRY ANOTHER CHARACTER
  1952.     LD    C,1            ;INDICATE WORD FOUND
  1953.     LD    HL,(DICFL)
  1954.     LD    A,(FLAG)        ;GET FIRST FLAG
  1955.     CP    0            ;NO FLAG WANTED?
  1956.     JR    Z,DICFN3        ;TRY NEXT BYTE OF FLAG IF NONE
  1957.     AND    L
  1958.     CP    0            ;INDICATE WORD FOUND IF .NE. 0
  1959.     JR    NZ,DICRET
  1960.     LD    C,2            ;INDICATE MAIN WORD FOUND/NO FLAG
  1961.     JR    DICRET
  1962. DICFN3:    LD    A,(FLAG+1)        ;TRY NEXT FLAG BYTE
  1963.     CP    0            ;NO FLAG WANTED?
  1964.     JR    Z,DICRET        ;IF NONE WANTED THEN WORD FOUND
  1965.     AND    H
  1966.     CP    0            ;FOUND IF .NE. 0
  1967.     JR    NZ,DICRET
  1968.     LD    C,2            ;INDICATE MAIN WORD FOUND/NO FLAG
  1969.     JR    DICRET
  1970.  
  1971. DICFN4:    JP    M,DICFN1        ;IF TEST WORD IS EARLIER IN ALPHABET,
  1972.                     ;TRY NEXT DICTIONARY WORD
  1973.     LD    C,0            ;NOT FOUND
  1974. ;    JP    DICRET
  1975.  
  1976. DICRET:    LD    A,C            ;PUT STATUS BYTE IN A
  1977.     POP    BC
  1978.     POP    DE
  1979.     POP    HL
  1980.     RET
  1981.  
  1982. ;
  1983. ; MOVWRD -- read a word from the dictionary by decoding the flags.
  1984. ;
  1985. ;        Returns:  DICWRD <-- word from dictionary
  1986.  
  1987. MOVWRD:    LD    A,0
  1988.     LD    B,4
  1989.     CALL    GETBIT            ;GET 4 BITS INTO A
  1990.     LD    HL,DICWRD        ;POINT TO DICTIONARY WORD BUFFER
  1991.     LD    B,0
  1992.     LD    C,A            ;NUMBER OF CHARACTERS TO KEEP
  1993.     ADD    HL,BC
  1994. MOVWR1:    LD    A,0
  1995.     LD    B,3            ;GET FIRST 3 OF 5 BITS FOR CHARACTER
  1996.     CALL    GETBIT            ;BITS IN A
  1997.     CP    0111B            ;IS IT AN END OF WORD MARK?
  1998.     JR    Z,GETFLG        ;GET THE FLAGS NOW
  1999.     LD    B,2            ;GET REMAINING 2 BITS
  2000.     CALL    GETBIT
  2001.     CP    0            ;IF ZERO THEN END OF RECORD
  2002.     JP    Z,MOVMOR        ;INDICATE MAY BE IN NEXT RECORD
  2003.     ADD    A,40H            ;MAKE IT ASCII
  2004.     CP    'Z'+1            ;IS IT AN ENCODED "'"?
  2005.     JR    NZ,MOVWR4        ;JUMP IF NOT
  2006.     LD    A,027H            ;MAKE IT A "'"
  2007. MOVWR4:    LD    (HL),A            ;BUFFER THE CHARACTER
  2008.     INC    HL
  2009.     JR    MOVWR1            ;GET ANOTHER CHARACTER
  2010. MOVMOR:    LD    C,0FFH            ;INDICATE MAY BE IN NEXT RECORD
  2011.     POP    DE            ;GET USELESS RETURN WORD
  2012.     JP    DICRET            ;RETURN
  2013.  
  2014. ;
  2015. ; GETFLG -- read suffix flags from buffer.
  2016. ;
  2017. ;        Returns:  DICFL <-- 16 byte flag word
  2018.  
  2019. GETFLG:    LD    A,0
  2020.     LD    (HL),A            ;MARK THE END OF THE WORD
  2021.     LD    B,4            ;GET 4 BITS FOR NUMBER OF FLAGS VALUE
  2022.     CALL    GETBIT
  2023.     LD    B,A            ;NUMBER OF BITS IN B
  2024.     LD    HL,0
  2025.     CP    0            ;ARE ANY BITS THERE TO COPY?
  2026.     JP    Z,GETFL8        ;RETURN IF NONE
  2027.     PUSH    BC
  2028.     CP    8            ;MORE THAN 8 BITS?
  2029.     JP    M,GETFL1        ;JUMP IF NOT
  2030.     LD    B,7            ;GET 7 BITS FOR FIRST BYTE
  2031. GETFL1:    LD    A,0
  2032.     CALL    GETBIT
  2033.     POP    BC
  2034.     LD    L,A            ;THIS IS THE LOW BYTE OF FLAGS
  2035.     LD    A,B
  2036.     CP    8            ;GET MORE IF GREATER THAN 8 BITS
  2037.     JP    P,GETFL4
  2038.     LD    A,7            ;COMPUTE NUMBER OF ROTATIONS NECESSARY
  2039.                     ;TO PUT IT IN THE RIGHT PLACE
  2040.     SUB    B
  2041.     JP    Z,GETFL8        ;IF EXACTLY 7 THEN DONE
  2042.     LD    B,A            ;COUNTER
  2043. GETFL3:    RLC    L
  2044.     DJNZ    GETFL3
  2045.     JP    GETFL8            ;NO RETURN
  2046. GETFL4:    SUB    7            ;GET NUMBER OF BITS NEEDED FOR BYTE 2
  2047.     LD    B,A
  2048.     LD    A,0
  2049.     PUSH    BC
  2050.     CALL    GETBIT            ;GET BIT FOR HIGH BYTE OF STATUS FLAG
  2051.     POP    BC
  2052.     LD    H,A            ;SAVE HIGH BYTE
  2053.     LD    A,7            ;COMPUTE NUMBER OF ROTATIONS LEFT
  2054.     SUB    B
  2055.     JR    Z,GETFL8        ;RETURN IF NONE
  2056.     LD    B,A
  2057. GETFL6:    RLC    H
  2058.     DJNZ    GETFL6
  2059. GETFL8:    LD    (DICFL),HL        ;SAVE THE FLAG
  2060.     RET
  2061.  
  2062. ;
  2063. ; GETBIT -- read number of bits in B from dictionary buffer.
  2064. ;
  2065. ;        Returns:  A <-- byte value of B bits
  2066.  
  2067. GETBIT:    PUSH    DE
  2068.     PUSH    HL
  2069.     EX    AF,AF'            ;A HOLDS DESIRED DECODED BYTE.
  2070.                     ;A' HOLD CURRENT BIT VALUE
  2071.  
  2072.     LD    A,(CURBIT)
  2073.     LD    HL,(CURBYT)        ;ADDRESS OF CURRENT BYTE FOR OUTPUT
  2074.     LD    D,(HL)            ;D = CURRENT BYTE VALUE
  2075.     EX    AF,AF'
  2076. GETBI0:    EX    AF,AF'            ;GET CURRENT BIT VALUE
  2077.     AND    0111B            ;MASK 1ST THREE BITS
  2078.     JR    NZ,GETBI1        ;IF .NE. 0 THEN NOT TIME TO INC CURBYT
  2079.     LD    (HL),D            ;RESTORE OLD BYTE TO ORIGINAL VALUE
  2080.     INC    HL
  2081.     LD    (CURBYT),HL
  2082.     LD    D,(HL)            ;UPDATE D = CURRENT BYTE VALUE
  2083. GETBI1:    INC    A
  2084.     EX    AF,AF'            ;BACK TO DECODED BYTE
  2085.     RLC    D            ;MOVE BYTE SO NEXT BIT IN RIGHT PLACE
  2086.     RLC    A            ;MAKE A READY TO RECEIVE
  2087.     BIT    0,D            ;IS THE BIT ON?
  2088.     JR    Z,GETBI2        ;DON'T SET A IF IT ISN'T
  2089.     OR    1            ;SET BIT 1 OF A
  2090. GETBI2:    DJNZ    GETBI0            ;LOOP THROUGH DESIRED NUMBER OF BITS
  2091.     EX    AF,AF'            ;GET CURRENT BIT
  2092.     LD    (CURBIT),A        ;UPDATE IT
  2093.     EX    AF,AF'
  2094.     LD    (HL),D            ;UPDATE BYTE FOR NEXT CALL
  2095.     POP    HL
  2096.     POP    DE
  2097.     RET
  2098.  
  2099. ;
  2100. ; USRTST -- test user dictionary in memory for WORD.
  2101. ;
  2102. ;        Returns in A:  0 <-- word not found
  2103. ;                   1 <-- word found
  2104.  
  2105. USRTST:    LD    HL,NEXT            ;BEGINNING OF USER DICTIONARY BUFFER
  2106.     LD    A,0
  2107.     CP    (HL)            ;DOES ONE EXIST?
  2108.     RET    Z            ;CAN'T FIND ELEMENT OF AN EMPTY SET!
  2109.     LD    DE,WORD            ;ADDRESS OF WORD FOR COMPARING
  2110. USRTS1:    LD    A,(DE)            ;GET A CHARACTER
  2111.     CP    (HL)            ;ARE THEY THE SAME?
  2112.     JR    NZ,USRTS2        ;IF NOT SAME, TRY ANOTHER WORD
  2113.     INC    DE
  2114.     INC    HL
  2115.     CP    0            ;END OF WORD?
  2116.     JR    NZ,USRTS1        ;LOOP THROUGH WHOLE WORD
  2117.     LD    A,1            ;FOUND IT!
  2118.     RET
  2119. USRTS2:    LD    A,0
  2120. USRTS3:    CP    (HL)            ;LOOK FOR END OF WORD
  2121.     INC    HL
  2122.     JR    NZ,USRTS3
  2123.     CP    (HL)            ;IF NEXT BYTE ALSO 0 THEN END OF TABLE
  2124.     RET    Z
  2125.     LD    DE,WORD
  2126.     JR    USRTS1            ;TEST ANOTHER WORD
  2127.  
  2128. ;
  2129. ;  DECOUT - Output number in HL to console in decimal
  2130. ;
  2131.  
  2132. DECOUT:    PUSH    PSW
  2133.     PUSH    BC
  2134.     PUSH    DE
  2135.     PUSH    HL
  2136.     LD    B,0            ;B WILL BE 1 ONCE NON-ZERO CHAR OUTPUT
  2137.     LD    DE,10000        ;START BY TRYING 10,000'S
  2138.     CALL    NUMOUT            ;OUTPUT A NUMBER
  2139.     LD    DE,1000            ;1000'S
  2140.     CALL    NUMOUT
  2141.     LD    DE,100
  2142.     CALL    NUMOUT
  2143.     LD    DE,10
  2144.     CALL    NUMOUT
  2145.     LD    B,1            ;GUARANTEE THAT 0 WILL PRINT
  2146.     LD    DE,1
  2147.     CALL    NUMOUT
  2148.     POP    HL
  2149.     POP    DE
  2150.     POP    BC
  2151.     POP    PSW
  2152.     RET
  2153.  
  2154. NUMOUT:    LD    C,0            ;COUNTER FOR NUMBER OF SUBTRACTIONS
  2155. NUMOU0:    INC    C            ;COUNT LOOPS THROUGH SUBTRACTION
  2156.     XOR    A            ;CLEAR CARRY
  2157.     SBC    HL,DE            ;SUBTRACT UNITS UNTIL CARRY
  2158.     JP    NC,NUMOU0
  2159.     ADD    HL,DE            ;RESET TO LAST POSITIVE VALUE
  2160.     DEC    C            ;DON'T COUNT LAST SUBRTRACTION
  2161.     JR    NZ,NUMOU1        ;IF NOT ZERO, THEN OUTPUT
  2162.     CP    B            ;ANYTHING OUTPUT YET?
  2163.     RET    Z            ;IF NOT, THEN DON'T PRINT A 0
  2164. NUMOU1:    LD    B,1            ;INDICATE OUTPUT SENT
  2165.     LD    A,C
  2166.     ADD    A,'0'            ;CONVERT TO ASCII
  2167.     LD    E,A            ;OUTPUT TO CONSOLE
  2168.     LD    C,CONOUT        ;CONSOLE OUTPUT CODE
  2169.     PUSH    BC
  2170.     PUSH    HL
  2171.     CALL    BDOS
  2172.     POP    HL
  2173.     POP    BC
  2174.     RET
  2175.  
  2176.  
  2177.  
  2178. INPTR:    DW    INBUF+512        ;POINTER TO CURRENT BYTE IN INPUT BUFF
  2179. OPOSS:    DW    OBUFF            ;POINTER TO CURRENT BYTE IN OUTPUT BUFF
  2180. SRTBOT:    DW    NEXT            ;POINTER TO BEGINNING OF MEMORY POINTER
  2181.                     ;TABLE OF ALPHABETIZED WORDS FROM INPUT
  2182.                     ;FILE
  2183. SRTTOP:    DW    NEXT+2            ;POINTER TO TOP OF MEMORY POINTER TABLE
  2184. FREE:    DW    NEXT            ;POINTER TO NEXT FREE BYTE IN TPA
  2185. LASTCH:    DB    LF            ;LAST CHARACTER INDICATOR
  2186. OLSTCH:    DB    LF            ;BUFFER FOR OLD LAST CHARACTER WHEN
  2187.                     ;MULTIPLE INPUT FCB'S IN USE
  2188. SAVPUT:    DS    1            ;BUFFER FOR NORMAL FIRST INSTRUCTION
  2189.                     ;AT PUTCHR.  USED WHILE OUTPUT IS
  2190.                     ;DISABLED
  2191. DICFL:    DW    0            ;DICTIONARY FLAG FOR COMPARE
  2192. CURBYT:    DW    DICBUF-1        ;CURRENT BYTE OF DICBUF (FOR GETBIT)
  2193. CURBIT:    DB    0            ;CURRENT BIT OF BYTE (FOR GETBIT)
  2194. ALPHA:    DB    0            ;0 IF NOT WORKING IN ALPHABETICAL
  2195.                     ;ORDER (DID FLAG SEEK).  1 IF IN ORDER
  2196. LSTREC:    DW    1            ;RECORD NUMBER OF LAST DICTIONARY
  2197.                     ;RECORD READ
  2198. LSTADR:    DW    TABTOP+4        ;POINTER TO TABLE WHERE FIRST 4 BYTES
  2199.                     ;OF LAST RECORD READ ARE FOUND
  2200. OLDPTR:    DW    0            ;POINTER FOR PASS 1 OF INPUT FILE IS
  2201.                     ;SAVED HERE DURING PASS 2 IF ALL OF
  2202.                     ;FILE DID NOT FIT IN MEMORY
  2203. P2OPTR:    DW    P2BUF+512        ;POINTER FOR PASS2 OF INPUT FILE IS
  2204.                     ;SAVED HERE DURING PASS 1 IF ALL OF
  2205.                     ;FILE DID NOT FIT IN MEMORY
  2206. STOPED:    DB    0            ;IS 1 IF ALL OF FILE DID NOT FIT IN
  2207.                     ;MEMORY
  2208. MLTPAS:    DB    0            ;SAME AS STOPED BUT NEVER RESET ONCE
  2209.                     ;SET
  2210. DEFDRV:    DB    0            ;RECEIVES DEFAULT DRIVE VALUE
  2211. SPLDC:    DW    0            ;STORES NUMBER OF WORDS IN SPELL.DIC
  2212. FILUDC:    DW    0            ;STORES NUMBER OF WORDS WRITTEN TO
  2213.                     ;FILE.UDC
  2214. TOTWRD:    DW    0            ;RECORDS TOTAL NUMBER OF WORDS IN DOC
  2215. UNQWRD:    DW    0            ;NUMBER OF UNIQUE WORDS IN DOC
  2216. MISWRD:    DW    0            ;NUMBER OF MISSPELLED WORDS
  2217.  
  2218. OFCB:    DB    0,'        $$$'        ;FCB FOR OUTPUT FILE
  2219.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2220.     DB    0,0,0,0,0,0,0,0,0,0,0
  2221. P2FCB:    DB    0,'           '        ;FCB FOR PASS 2 OF INPUT FILE
  2222.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2223.     DB    0,0,0,0,0,0,0,0,0,0,0
  2224. FILDIC:    DB    0,'        UDC'        ;FCB FILE FILE.UDC
  2225.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2226.     DB    0,0,0,0,0,0,0,0,0,0,0
  2227. FILADD:    DB    0,'        ADD'        ;FCB FOR FILE.ADD
  2228.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2229.     DB    0,0,0,0,0,0,0,0,0,0,0
  2230. FILD$$:    DB    0,'        D$$'        ;FCB FOR TEMPORARY FILE FILE.D$$
  2231.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2232.     DB    0,0,0,0,0,0,0,0,0,0,0
  2233. SPLDIC:    DB    0,'SPELL   DIC'        ;FCB FOR SPELL.DIC
  2234.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2235.     DB    0,0,0,0,0,0,0,0,0,0,0
  2236. DICFCB:    DB    0,'DICT    DIC'        ;FCB FOR DICTIONARY FILE
  2237.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0
  2238.     DB    0,0,0,0,0,0,0,0
  2239. DICREC:    DB    0,0,0            ;RECORD NUMBER FOR RANDOM READ
  2240.                     ;(STILL PART OF FCB)
  2241.  
  2242. STACK    EQU    $+50            ;STACK
  2243. SRCWRD    EQU    STACK            ;BUFFER FOR UNFIXED WORD
  2244. WORD    EQU    SRCWRD+100        ;BUFFER FOR FIXED WORD
  2245. DICWRD    EQU    WORD+41            ;BUFFER FOR WORDS READ FROM DICTIONARY
  2246. FLAG    EQU    DICWRD+41        ;BUFFER FOR DESIRED DICTIONARY FLAG
  2247. LASTC    EQU    FLAG+2            ;BUFFER FOR LAST CHARACTER READ
  2248. DICBUF    EQU    LASTC+1            ;BUFFER FOR DICTIONARY RECORD
  2249. INBUF    EQU    DICBUF+258        ;INPUT BUFFER FOR PASS 1
  2250. P2BUF    EQU    INBUF+513        ;INPUT BUFFER FOR PASS 2
  2251. OBUFF    EQU    P2BUF+513        ;OUTPUT BUFFER
  2252. NEXT    EQU    OBUFF+513        ;ADDRESS OF NEXT FREE BYTE
  2253.     END    START
  2254.