home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 1156 / Cryptanalysis.sis (.txt) next >
EPOC Installation Package  |  2001-10-18  |  48KB  |  1,436 lines

  1. E:\Psioncd2work\Psioncd2\Sistemp\crack.opl!:\PsionCD\Cryptanalysis\crack.oplE:\Psioncd2work\Psioncd2\Sistemp\Bis.txt!:\PsionCD\Cryptanalysis\Bis.txtCryptanalysis 45.7 kB7
  2. REM      This program was written by James L. Dean on February 1, 2000.
  3. REM      It implements the algorithm given by George W. Hart in the September
  4. REM 1994 edition of the Communications of the ACM (Volume 37, Number 9).
  5. REM      Edgar Allan Poe used this method to crack simple substitution ciphers
  6. REM around 1839; consider the following from pages 784-785 of David Kahn's The
  7. REM Codebreakers:
  8. REM           The closest he ever came to doing so was when he
  9. REM           demonstrated how he deduced that a challenge sent him by
  10. REM           G.  W. Kulp, of Lewiston, Pennsylvania, was a false
  11. REM           cryptogram.  He picked out three words in the
  12. REM           cryptogram--MW, LAAM, and MLW.  Since "all English words
  13. REM           of but two letters consist of a vowel and a consonant," he
  14. REM           wrote, MW must be one of 30 words, which he listed. He
  15. REM           then inserted every letter of the alphabet in the middle
  16. REM           of all 30 words in an exhaustive trial process to see
  17. REM           which letters would make a sensible word out of MLW. Here
  18. REM           he found 18, including ash and tho'.  Turning to LAAM, he
  19. REM           observed, that "if MLW be ash, then LAAM will be a word of
  20. REM           this form, s..a, in which the dots represent two unknown
  21. REM           letters of the same kind." He ran through his 18 words in
  22. REM           this way, and found that the only one that gave a possible
  23. REM           meaning for LAAM was h..t, or hoot.  "LAAM is then hoot or
  24. REM           nothing. But the hypothesis of the word hoot is founded
  25. REM           upon that of the word tho'.... We now arrive at a definite
  26. REM           conclusion. Either Mr. Kulp's puzzle is not genuine, or MW
  27. REM           stands for to, MLW for tho', and LAAM for hoot. But it is
  28. REM           evident that this latter cannot be--for in that case both
  29. REM           W and A represent the letter 0. What follows?--why that
  30. REM           Mr. Kulp's puzzle is no puzzle at all. This demonstration
  31. REM           is as absolutely conclusive as any mathematical one could
  32. REM           be. The process of reasoning here employed is that
  33. REM           employed also in the solution of the cyphers."
  34. DECLARE EXTERNAL
  35. INCLUDE "DATE.OXH"
  36. EXTERNAL AddEncipheredWord&:(EncipheredWord$)
  37. EXTERNAL AddPlaintext:(PatternHead&,Pattern&,Plaintext$)
  38. EXTERNAL AddWordNotInWordList:(PatternPtr&)
  39. EXTERNAL FreePattern:(PatternPtr&)
  40. EXTERNAL GetCiphertext:
  41. EXTERNAL GetCiphertextPatterns:
  42. EXTERNAL GetEncipheredChar%:
  43. EXTERNAL GetMaxDistinctLettersPerWord:(EncipheredHead&)
  44. EXTERNAL GetPatternForPlaintextWord:(Pattern&)
  45. EXTERNAL GetWordListChar%:
  46. EXTERNAL GetWordListWord:(PreviousWord$)
  47. EXTERNAL GetWordsMatchingPatterns:
  48. EXTERNAL GoBackward:
  49. EXTERNAL GoForward:(KeepOnlyTheBest%,EncipheredHead&,CiphertextHead&)
  50. EXTERNAL IsLower%:(CurrentChar%)
  51. EXTERNAL IsUpper%:(CurrentChar%)
  52. EXTERNAL Main:
  53. EXTERNAL Malloc&:(NumBytes%)
  54. EXTERNAL OutputSolution:(EncipheredHead&,CiphertextHead&)
  55. EXTERNAL PatternForEncipheredWord&:(EncipheredWord&,EncipheredWordLen%)
  56. EXTERNAL PatternForWord&:(Word&,WordLen%)
  57. EXTERNAL Solve:(NumDistinctWords&,EncipheredHead&,SortedHead&,KeepOnlyTheBest%,CiphertextHead&)
  58. EXTERNAL Sort:
  59. EXTERNAL StrCmp%:(Str1&,Str2&)
  60. EXTERNAL StrICmp%:(Str1&,Str2&)
  61. EXTERNAL ToLower%:(CurrentChar%)
  62. EXTERNAL ToUpper%:(CurrentChar%)
  63. CONST AlphabetSize%=27
  64. CONST Apostrophe%=39
  65. CONST Asterisk%=42
  66. CONST EOF%=-1
  67. CONST False%=0
  68. CONST LowercaseA%=97
  69. CONST LowercaseZ%=122
  70. CONST Slash%=47
  71. CONST True%=-1
  72. CONST UppercaseA%=65
  73. CONST UppercaseZ%=90
  74. PROC Main:
  75.   GLOBAL Alphabetic%
  76.   GLOBAL CiphertextCharPtr&
  77.   GLOBAL CiphertextHead&
  78.   GLOBAL CiphertextPtr&
  79.   GLOBAL CiphertextTail&
  80.   GLOBAL EncipheredHead&
  81.   GLOBAL EncipheredPtrForMax&
  82.   GLOBAL EncipheredTail&
  83.   GLOBAL FatalError%
  84.   GLOBAL MaxDistinctLettersPerWord
  85.   GLOBAL NumDistinctWords&
  86.   GLOBAL PatternHead&
  87.   GLOBAL SortedHead&
  88.   GLOBAL Word$(255)
  89.   LOCAL ElapsedTime&
  90.   LOCAL EncipheredPtr1&
  91.   LOCAL KeepOnlyTheBest%
  92.   LOCAL NumChars%
  93.   LOCAL SortedPtr&
  94.   LOCAL StartTime&
  95.   LOCAL StopTime&
  96.   FatalError%=False%
  97.   ElapsedTime&=0
  98.   PRINT "        Cryptanalysis of Simple Substitution Ciphers with Word Divisions"
  99.   PRINT
  100.   KeepOnlyTheBest%=False%
  101.   GetCiphertext:
  102.   IF NOT FatalError%
  103.     IF CiphertextHead& = 0
  104.       FatalError%=True%
  105.       PRINT "Fatal error:  no ciphertext was entered."
  106.     ENDIF
  107.   ENDIF
  108.   IF NOT FatalError%
  109.     StartTime&=DTNow&:
  110.     GetCiphertextPatterns:
  111.     IF NOT FatalError%
  112.       IF PatternHead& = 0
  113.         FatalError%=True%
  114.         PRINT "Fatal error:  the cipher text contains no words."
  115.       ENDIF
  116.     ENDIF
  117.     IF NOT FatalError%
  118.       GetWordsMatchingPatterns:
  119.       IF NOT FatalError%
  120.         GetMaxDistinctLettersPerWord:(EncipheredHead&)
  121.         IF MaxDistinctLettersPerWord <= 0.0
  122.           FatalError%=True%
  123.           PRINT "Fatal error:  no word in the cipher text matched any pattern in the word list."
  124.         ENDIF
  125.         IF NOT FatalError%
  126.           SortedHead&=Malloc&:(20)
  127.           IF SortedHead& = 0
  128.             FatalError%=True%
  129.             PRINT "Fatal error:  out of memory."
  130.           ELSE
  131.             Sort:
  132.             IF NOT FatalError%
  133.               PRINT "Possible solutions (press a key to exit):"
  134.               Solve:(NumDistinctWords&,EncipheredHead&,SortedHead&,KeepOnlyTheBest%,CiphertextHead&)
  135.               StopTime&=DTNow&:
  136.               ElapsedTime&=DTSecsDiff&:(StartTime&,StopTime&)
  137.             ENDIF
  138.             WHILE SortedHead& <> 0
  139.               SortedPtr&=PEEKL(SortedHead&+16)
  140.               FREEALLOC SortedHead&
  141.               SortedHead&=SortedPtr&
  142.             ENDWH
  143.           ENDIF
  144.         ENDIF
  145.       ENDIF
  146.     ENDIF
  147.     FreePattern:(PatternHead&)
  148.     WHILE EncipheredHead& <> 0
  149.       EncipheredPtr1&=PEEKL(EncipheredHead&+12)
  150.       FREEALLOC PEEKL(EncipheredHead&)
  151.       FREEALLOC EncipheredHead&
  152.       EncipheredHead&=EncipheredPtr1&
  153.     ENDWH
  154.   ENDIF
  155.   WHILE CiphertextHead& <> 0
  156.     CiphertextPtr&=PEEKL(CiphertextHead&+4)
  157.     FREEALLOC PEEKL(CiphertextHead&)
  158.     FREEALLOC CiphertextHead&
  159.     CiphertextHead&=CiphertextPtr&
  160.   ENDWH
  161.   PRINT
  162.   IF ElapsedTime& > 0
  163.     PRINT "Elapsed time:  ";
  164.     PRINT ElapsedTime&;
  165.     IF ElapsedTime& = 1
  166.       PRINT " second"
  167.     ELSE
  168.       PRINT " seconds"
  169.     ENDIF
  170.   ENDIF
  171.   PRINT "Press Enter to exit."
  172.   INPUT Word$
  173. PROC GetCiphertext:
  174.   EXTERNAL CiphertextCharPtr&
  175.   EXTERNAL CiphertextHead&
  176.   EXTERNAL CiphertextPtr&
  177.   EXTERNAL CiphertextTail&
  178.   EXTERNAL FatalError%
  179.   LOCAL BytePtr&
  180.   LOCAL CiphertextCharNum%
  181.   LOCAL EncipheredText$(255)
  182.   LOCAL NumCiphertextChars%
  183.   PRINT "Enter enciphered text followed by a blank line."
  184.   PRINT
  185.   CiphertextHead&=0
  186.   CiphertextTail&=0
  187.     INPUT EncipheredText$
  188.     IF EncipheredText$ <> ""
  189.       CiphertextPtr&=Malloc&:(8)
  190.       IF CiphertextPtr& = 0
  191.         FatalError%=True%
  192.         PRINT "Fatal error:  out of memory."
  193.       ELSE
  194.         CiphertextCharPtr&=Malloc&:(2+LEN(EncipheredText$))
  195.         IF CiphertextCharPtr& = 0
  196.           FatalError%=True%
  197.           PRINT "Fatal error:  out of memory."
  198.           FREEALLOC CiphertextPtr&
  199.         ELSE
  200.           BytePtr&=CiphertextCharPtr&
  201.           CiphertextCharNum%=1
  202.           NumCiphertextChars%=LEN(EncipheredText$)
  203.           WHILE CiphertextCharNum% <= NumCiphertextChars%
  204.             POKEB BytePtr&,ASC(MID$(EncipheredText$,CiphertextCharNum%,1))
  205.             BytePtr&=BytePtr&+1
  206.             CiphertextCharNum%=CiphertextCharNum%+1
  207.           ENDWH
  208.           POKEB BytePtr&,10
  209.           BytePtr&=BytePtr&+1
  210.           POKEB BytePtr&,0
  211.           POKEL CiphertextPtr&,CiphertextCharPtr&
  212.           POKEL CiphertextPtr&+4,0
  213.           IF CiphertextTail& = 0
  214.             CiphertextHead&=CiphertextPtr&
  215.           ELSE
  216.             POKEL CiphertextTail&+4,CiphertextPtr&
  217.           ENDIF
  218.           CiphertextTail&=CiphertextPtr&
  219.         ENDIF
  220.       ENDIF
  221.     ENDIF
  222.   UNTIL FatalError% OR (EncipheredText$ = "")
  223.   RETURN
  224. PROC GetCiphertextPatterns:
  225.   EXTERNAL Alphabetic%
  226.   EXTERNAL CiphertextCharPtr&
  227.   EXTERNAL CiphertextHead&
  228.   EXTERNAL CiphertextPtr&
  229.   EXTERNAL CiphertextTail&
  230.   EXTERNAL EncipheredHead&
  231.   EXTERNAL EncipheredTail&
  232.   EXTERNAL FatalError%
  233.   EXTERNAL NumDistinctWords&
  234.   EXTERNAL PatternHead&
  235.   EXTERNAL Word$
  236.   LOCAL CurrentChar%
  237.   LOCAL EndOfFile%
  238.   LOCAL PatternPtr&
  239.   LOCAL WordLength%
  240.   PRINT "Getting patterns in enciphered text..."
  241.   NumDistinctWords&=0
  242.   EncipheredHead&=0
  243.   EncipheredTail&=0
  244.   PatternHead&=0
  245.   CiphertextPtr&=CiphertextHead&
  246.   CiphertextCharPtr&=PEEKL(CiphertextHead&)
  247.     EndOfFile%=False%
  248.     Alphabetic%=False%
  249.     WHILE (EndOfFile% = 0) AND (NOT Alphabetic%)
  250.       CurrentChar%=GetEncipheredChar%:
  251.       IF CurrentChar% = EOF%
  252.         EndOfFile%=True%
  253.       ELSE
  254.         IF CurrentChar% = Apostrophe%
  255.           Alphabetic%=True%
  256.         ELSE
  257.           CurrentChar%=ToLower%:(CurrentChar%)
  258.           IF IsLower%:(CurrentChar%)
  259.             Alphabetic%=True%
  260.           ENDIF
  261.         ENDIF
  262.       ENDIF
  263.     ENDWH
  264.     IF NOT EndOfFile%
  265.       Word$=""
  266.       WordLength%=0
  267.       DO
  268.         Word$=Word$+Chr$(CurrentChar%)
  269.         WordLength%=WordLength%+1
  270.         CurrentChar%=ToLower%:(GetEncipheredChar%:)
  271.       UNTIL (CurrentChar% = EOF%) OR (WordLength% >= 255) OR ((CurrentChar% <> Apostrophe%) AND (NOT IsLower%:(CurrentChar%)))
  272.       PatternPtr&=AddEncipheredWord&:(Word$)
  273.       IF (NOT FatalError%) AND (PEEKL(PatternPtr&+12) = 0)
  274.         AddWordNotInWordList:(PatternPtr&)
  275.       ENDIF
  276.     ENDIF
  277.   UNTIL FatalError% OR (CurrentChar% = EOF%)
  278.   RETURN
  279. PROC GetWordsMatchingPatterns:
  280.   EXTERNAL Alphabetic%
  281.   EXTERNAL FatalError%
  282.   EXTERNAL PatternHead&
  283.   EXTERNAL Word$
  284.   GLOBAL CharNum%
  285.   GLOBAL LineNum&
  286.   GLOBAL WordList$(81,60)
  287.   LOCAL Pattern&
  288.   LOCAL PreviousWord$(255)
  289.   PRINT "Getting words matching the patterns..."
  290.   WordList$(1)="AA/BBLE/COUT/DVE/BCCORDING/EUNT/CROSS/CT/DION/EVITIES/HY/DUA"
  291.   WordList$(2)="LLY/BDDED/DITION/CMINISTRATION/BFTER/BGAIN/FST/CE/CO/BHEAD/B"
  292.   WordList$(3)="ID/CR/BLL/CMOST/CONE/EG/CREADY/CSO/CTHOUGH/CWAYS/BM/CERICA/H"
  293.   WordList$(4)="N/CONG/DUNT/BN/CALYSIS/CD/COTHER/CSWER/CTI/CY/DONE/DTHING/BP"
  294.   WordList$(5)="PARENTLY/DEAR/GED/DROACH/BRE/DA/ES/CMY/COUND/CT/BS/CK/DED/CS"
  295.   WordList$(6)="OCIATION/BT/CTACK/DENTION/BUDIENCE/BVAILABLE/CERAGE/BWAY/AB/"
  296.   WordList$(7)="BACK/CD/CLL/CSED/DIC/ES/BE/CAUTIFUL/CCAME/EUSE/DOME/CD/CEN/C"
  297.   WordList$(8)="FORE/CGAN/DINNING/CHIND/CING/CLIEVE/DOW/CST/CTTER/DWEEN/CYON"
  298.   WordList$(9)="D/BIG/CLL/BLACK/COOD/CUE/BOARD/CDY/COK/CRN/CTH/CY/DS/BRING/C"
  299.   WordList$(10)="OUGHT/DWN/BUILDING/ET/CSINESS/CT/BY/AC/BALL/EED/CME/CN/DNOT/"
  300.   WordList$(11)="CR/DE/DRIED/DS/CSE/ES/CUSE/BENT/EER/ERAL/EURY/CRTAIN/HLY/BHA"
  301.   WordList$(12)="NGE/DRACTER/CIEF/DLD/FREN/COICE/CRISTIAN/CURCH/BITY/BLASS/CE"
  302.   WordList$(13)="AR/FLY/COSE/FD/CUB/BO/CLD/DLEGE/DOR/CME/ES/DING/DMITTEE/EON/"
  303.   WordList$(14)="EUNIST/HTY/DPANY/ELETE/ILY/CNCERNED/DDITIONS/DGRESS/DSIDER/I"
  304.   WordList$(15)="ED/DTINUED/EROL/CRNER/DPS/CST/ES/CULD/FN[T/DNTRIES/GY/FY/DPL"
  305.   WordList$(16)="E/DRSE/ET/CVERED/BUT/AD/BAILY/CRK/CTA/CY/DS/BE/CAD/DL/DTH/CC"
  306.   WordList$(17)="IDED/ESION/CEP/CFENSE/CGREE/CMOCRATIC/CPARTMENT/CSCRIBED/DIG"
  307.   WordList$(18)="N/GED/CTERMINED/CVELOPED/HMENT/BID/DN[T/CFFERENCE/IT/EICULT/"
  308.   WordList$(19)="CRECT/GION/GLY/CSTANCE/ERICT/BO/CES/CING/CNE/D[T/COR/CUBT/CW"
  309.   WordList$(20)="N/BR/CIVE/BUE/CRING/AE/BACH/CRLIER/EY/DTH/CST/BCONOMIC/BDUCA"
  310.   WordList$(21)="TION/BFFECT/GIVE/GS/DORT/GS/BIGHT/CTHER/BLEMENTS/CSE/BND/CGL"
  311.   WordList$(22)="AND/EISH/COUGH/CTIRE/BQUIPMENT/BSPECIALLY/CTABLISHED/BUROPE/"
  312.   WordList$(23)="BVEN/EING/DR/EY/FTHING/CIDENCE/BXAMPLE/CCEPT/CISTENCE/CPECT/"
  313.   WordList$(24)="GED/ERIENCE/CTENT/BYE/DS/AF/BACE/DT/CITH/CLL/CMILY/CR/DM/CTH"
  314.   WordList$(25)="ER/BEAR/CDERAL/CED/DL/EING/DT/CLT/CW/BIELD/CGURE/GS/CLLED/CN"
  315.   WordList$(26)="AL/FLY/DD/DE/CRE/DM/DST/CSCAL/CVE/BLOOR/BOLLOWED/GING/COD/DT"
  316.   WordList$(27)="/CR/DCE/FS/DEIGN/DM/EER/ES/DWARD/CUND/DR/BREE/EDOM/DNCH/CIEN"
  317.   WordList$(28)="D/GS/COM/DNT/BULL/CNCTION/CRTHER/CTURE/AG/BAME/CVE/BENERAL/H"
  318.   WordList$(29)="LY/CORGE/CT/DTING/BIRL/ES/CVE/EN/ES/BLASS/BO/CD/CING/CNE/COD"
  319.   WordList$(30)="/CT/CVERNMENT/BREAT/FER/DEN/COUND/EP/FS/DWING/ETH/BUN/AH/BAD"
  320.   WordList$(31)="/CIR/CLF/DL/CND/ES/CPPENED/CRD/CS/CVE/DING/BE/CAD/DR/ED/ET/D"
  321.   WordList$(32)="VY/CLD/DL/DP/CR/DE/DSELF/C[S/BIGH/EER/CM/DSELF/CS/DTORY/CT/B"
  322.   WordList$(33)="OLD/CME/CPE/CRSE/CSPITAL/CT/DEL/CUR/ES/DSE/CW/DEVER/BUMAN/CN"
  323.   WordList$(34)="DRED/CSBAND/AI/BDEA/ES/BF/B[LL/CM/BMAGE/CMEDIATELY/CPORTANT/"
  324.   WordList$(35)="BN/CCLUDE/GING/DOME/DREASE/ID/CDEED/DIVIDUAL/DUSTRIAL/HY/CFL"
  325.   WordList$(36)="UENCE/DORMATION/CSIDE/DTEAD/CTEREST/FNATIONAL/DO/CVOLVED/BS/"
  326.   WordList$(37)="CLAND/CSUE/BT/CS/C[S/CSELF/B[VE/AJ/BOB/CHN/BUST/EICE/AKEEP/C"
  327.   WordList$(38)="NNEDY/CPT/BIND/BNEW/COW/ELEDGE/EN/AL/BABOR/CCK/CND/DGUAGE/CR"
  328.   WordList$(39)="GE/FR/CST/CTE/ER/DTER/CW/CY/BEAD/EERS/DRNED/DST/DVE/CD/CFT/C"
  329.   WordList$(40)="NGTH/CSS/CT/DTER/GS/CVEL/BIFE/CGHT/CKE/CNE/ES/CST/CTERATURE/"
  330.   WordList$(41)="DTLE/CVE/ED/DING/BOCAL/CNG/EER/COK/EED/EING/CST/CT/CVE/CW/DE"
  331.   WordList$(42)="R/AM/BADE/CIN/CJOR/CKE/ES/DING/CN/DNER/DS/DY/CRCH/DKET/DRIED"
  332.   WordList$(43)="/CSS/CTERIAL/DTER/CY/DBE/BE/CAN/EING/ES/CDICAL/CET/EING/CMBE"
  333.   WordList$(44)="R/GS/CN/CRELY/CT/DHOD/GS/BIDDLE/CGHT/CLES/DITARY/DLION/CND/D"
  334.   WordList$(45)="UTES/CSS/BODERN/CMENT/CNEY/DTH/FS/CRAL/DE/DNING/CST/CTHER/CV"
  335.   WordList$(46)="E/ED/EMENT/DING/BR/CS/BUCH/CSIC/DT/BY/CSELF/AN/BAME/CTION/GA"
  336.   WordList$(47)="L/GS/DURAL/FE/BEAR/ELY/CCESSARY/CED/EED/ES/CGRO/CITHER/CVER/"
  337.   WordList$(48)="CW/CXT/BIGHT/BO/CN/CR/DMAL/DTH/CT/DE/DHING/CW/BUCLEAR/CMBER/"
  338.   WordList$(49)="GS/AOBTAINED/CVIOUSLY/BF/CF/DICE/CTEN/BH/BLD/BN/CCE/CE/DS/D["
  339.   WordList$(50)="S/CLY/BPEN/EED/DRATION/CPORTUNITY/BR/CDER/CGANIZATION/BTHER/"
  340.   WordList$(51)="FS/BUR/CT/DSIDE/BVER/BWN/AP/BAID/CPER/CRT/EICULAR/KLY/ES/EY/"
  341.   WordList$(52)="CSSED/DT/CTTERN/CY/BEACE/COPLE/CR/DFORMANCE/DHAPS/DIOD/DSON/"
  342.   WordList$(53)="GAL/GS/BHYSICAL/BICTURE/CECE/BLACE/DN/EE/ENING/ES/ET/DY/BOIN"
  343.   WordList$(54)="T/FS/CLICE/FY/ETICAL/COL/DR/CPULATION/CSITION/DSIBLE/DT/CWER"
  344.   WordList$(55)="/BRESENT/EIDENT/ES/FURE/CICE/DNCIPLE/DVATE/COBABLY/ELEM/HS/D"
  345.   WordList$(56)="CESS/DDUCTION/HS/DGRAM/HS/FESS/DPERTY/DVIDE/HD/BUBLIC/CRPOSE"
  346.   WordList$(57)="/CT/AQUALITY/CESTION/IS/CITE/AR/BACE/CDIO/CN/DGE/CTE/DHER/BE"
  347.   WordList$(58)="ACHED/ETION/DD/EING/EY/DL/ELY/DSON/CCEIVED/ENT/GLY/DORD/CD/C"
  348.   WordList$(59)="LIGION/HUS/CMEMBER/CPORT/GED/CQUIRED/CSEARCH/DPECT/EONSIBILI"
  349.   WordList$(60)="TY/DT/DULT/GS/CTURN/GED/BIGHT/CVER/BOAD/COM/BUN/DNING/AS/BAI"
  350.   WordList$(61)="D/CLES/CME/CT/CW/CY/DING/DS/BCHOOL/GS/CIENCE/BEASON/CCOND/DR"
  351.   WordList$(62)="ETARY/DTION/CE/DM/EED/ES/DN/CLF/CNSE/DT/CRIES/EOUS/DVED/EICE"
  352.   WordList$(63)="/HS/CT/CVEN/ERAL/BHALL/CE/CORT/DT/DULD/DW/EED/EN/BIDE/CMILAR"
  353.   WordList$(64)="/DPLE/FY/CNCE/DGLE/CTUATION/CX/CZE/BLOWLY/BMALL/BO/CCIAL/EET"
  354.   WordList$(65)="Y/CME/ETHING/FIMES/EWHAT/CN/CON/CRT/CUND/DTH/FERN/CVIET/BPAC"
  355.   WordList$(66)="E/CEAK/DCIAL/FFIC/CIRIT/CRING/BQUARE/BT/CAFF/DGE/DND/FARD/DR"
  356.   WordList$(67)="T/FED/DTE/FMENTS/FS/DY/CEP/ES/CILL/COCK/DOD/DP/EPED/DRY/CRAI"
  357.   WordList$(68)="GHT/DEET/ENGTH/DONG/CUDENT/HS/EY/BUBJECT/CCH/CDDENLY/CMMER/C"
  358.   WordList$(69)="N/CPPORT/CRE/DFACE/BYSTEM/AT/BABLE/CKE/EN/DING/CLK/CX/BECHNI"
  359.   WordList$(70)="CAL/CLL/CMPERATURE/CN/CRM/ES/CST/BH/CAN/DT/ES/CE/DIR/DM/ESEL"
  360.   WordList$(71)="VES/DN/DORY/DRE/FFORE/F[S/DSE/DY/CING/FS/EK/FING/DRD/ETY/DS/"
  361.   WordList$(72)="COSE/DUGHT/CREE/DOUGH/HOUT/CUS/BIME/ES/BO/CDAY/CGETHER/CLD/C"
  362.   WordList$(73)="O/DK/CP/CTAL/CWARD/DN/BRADE/DINING/CIAL/DED/COUBLE/CUE/DTH/C"
  363.   WordList$(74)="Y/DING/BURN/EED/BWENTY/CO/BYPE/ES/AU/BNLIKELY/CDER/FSTAND/CI"
  364.   WordList$(75)="ON/DTED/DVERSITY/CTIL/BP/CON/BS/CE/DD/CING/CUALLY/AVALUE/FS/"
  365.   WordList$(76)="CRIOUS/BERY/BIEW/BOICE/CLUME/AWAITING/CLKED/DL/CNT/EED/CR/CS"
  366.   WordList$(77)="/DHINGTON/DN[T/CTER/CY/DS/BE/CEK/ES/CLL/CNT/CRE/CST/EERN/BHA"
  367.   WordList$(78)="T/EEVER/CEN/DRE/DTHER/CICH/DLE/DTE/CO/DLE/DM/DSE/CY/BIDE/CFE"
  368.   WordList$(79)="/CLL/EIAM/CNDOW/CSH/CTH/EIN/EOUT/BOMAN/DEN/CRD/ES/DK/EED/EIN"
  369.   WordList$(80)="G/ES/DLD/CULD/FN[T/BRITTEN/CONG/DTE/AYEAR/ES/CS/CT/BORK/CU/D"
  370.   WordList$(81)="NG/DR/D[RE/!"
  371.   LineNum&=1
  372.   CharNum%=1
  373.   PreviousWord$=""
  374.   Pattern&=Malloc&:(256)
  375.   IF Pattern& = 0
  376.     FatalError%=True%
  377.     PRINT "Fatal error:  out of memory."
  378.   ELSE
  379.     DO
  380.       GetWordListWord:(PreviousWord$)
  381.       IF (NOT FatalError%) AND (Word$ <> "")
  382.         PreviousWord$=Word$
  383.         GetPatternForPlaintextWord:(Pattern&)
  384.         IF (Alphabetic%)
  385.           AddPlaintext:(PatternHead&,Pattern&,Word$)
  386.         ENDIF
  387.       ENDIF
  388.     UNTIL FatalError% OR (Word$ = "")
  389.     FREEALLOC Pattern&
  390.   ENDIF
  391.   RETURN
  392. PROC GetMaxDistinctLettersPerWord:(EncipheredHead&)
  393.   EXTERNAL EncipheredPtrForMax&
  394.   EXTERNAL MaxDistinctLettersPerWord
  395.   EXTERNAL NumDistinctWords&
  396.   LOCAL EncipheredPtr1&
  397.   LOCAL NumDistinctLettersPerWord
  398.   LOCAL PatternPtr&
  399.   LOCAL PlaintextCount&
  400.   MaxDistinctLettersPerWord=0.0
  401.   EncipheredPtr1&=EncipheredHead&
  402.   WHILE EncipheredPtr1& <> 0
  403.     PatternPtr&=PEEKL(EncipheredPtr1&+4)
  404.     PlaintextCount&=PEEKL(PatternPtr&+8)
  405.     IF PlaintextCount& <> 0
  406.       NumDistinctLettersPerWord=FLT(PEEKL(PatternPtr&))/FLT(PlaintextCount&)
  407.       IF NumDistinctLettersPerWord > MaxDistinctLettersPerWord
  408.         MaxDistinctLettersPerWord=NumDistinctLettersPerWord
  409.         EncipheredPtrForMax&=EncipheredPtr1&
  410.       ENDIF
  411.     ENDIF
  412.     EncipheredPtr1&=PEEKL(EncipheredPtr1&+12)
  413.   ENDWH
  414.   RETURN
  415. PROC Sort:
  416.   EXTERNAL CiphertextCharPtr&
  417.   EXTERNAL EncipheredHead&
  418.   EXTERNAL EncipheredPtrForMax&
  419.   EXTERNAL FatalError%
  420.   EXTERNAL NumDistinctWords&
  421.   EXTERNAL SortedHead&
  422.   LOCAL CipherTextChar%
  423.   LOCAL DuplicateWord%
  424.   LOCAL EncipheredPtr1&
  425.   LOCAL EncipheredPtr2&
  426.   LOCAL LetterNum%
  427.   LOCAL LetterUsed%(27)
  428.   LOCAL MaxMatchingLetters%
  429.   LOCAL NumMatchingLetters%
  430.   LOCAL PatternPtr&
  431.   LOCAL SortedPtr&
  432.   LOCAL SortedTail&
  433.   POKEL EncipheredPtrForMax&+8,SortedHead&
  434.   POKEL SortedHead&,PEEKL(EncipheredPtrForMax&)
  435.   PatternPtr&=PEEKL(EncipheredPtrForMax&+4)
  436.   POKEL SortedHead&+4,PatternPtr&
  437.   POKEL SortedHead&+8,PEEKL(PatternPtr&+12)
  438.   POKEL SortedHead&+12,0
  439.   POKEL SortedHead&+16,0
  440.   SortedTail&=SortedHead&
  441.   LetterNum%=1
  442.   WHILE LetterNum% <= AlphabetSize%
  443.     LetterUsed%(LetterNum%)=False%
  444.     LetterNum%=LetterNum%+1
  445.   ENDWH
  446.   CiphertextCharPtr&=PEEKL(EncipheredPtrForMax&)
  447.   CiphertextChar%=PEEKB(CiphertextCharPtr&)
  448.   WHILE CiphertextChar% <> 0
  449.     IF CiphertextChar% <> Apostrophe%
  450.       LetterUsed%((ToLower%:(CiphertextChar%)-LowercaseA%)+1)=True%
  451.     ENDIF
  452.     CiphertextCharPtr&=CiphertextCharPtr&+1
  453.     CiphertextChar%=PEEKB(CiphertextCharPtr&)
  454.   ENDWH
  455.   EncipheredPtr1&=PEEKL(EncipheredHead&+12)
  456.   WHILE (NOT FatalError%) AND (EncipheredPtr1& <> 0)
  457.     MaxMatchingLetters%=0
  458.     EncipheredPtrForMax&=0
  459.     EncipheredPtr2&=EncipheredHead&
  460.     WHILE EncipheredPtr2& <> 0
  461.       IF PEEKL(EncipheredPtr2&+8) = 0
  462.         NumMatchingLetters%=0
  463.         CiphertextCharPtr&=PEEKL(EncipheredPtr2&)
  464.         WHILE PEEKB(CiphertextCharPtr&) <> 0
  465.           IF PEEKB(CiphertextCharPtr&) <> Apostrophe%
  466.             IF LetterUsed%((ToLower%:(PEEKB(CiphertextCharPtr&))-LowercaseA%)+1)
  467.               NumMatchingLetters%=NumMatchingLetters%+1
  468.             ENDIF
  469.           ENDIF
  470.           CiphertextCharPtr&=CiphertextCharPtr&+1
  471.         ENDWH
  472.         IF NumMatchingLetters% >= MaxMatchingLetters%
  473.           MaxMatchingLetters%=NumMatchingLetters%
  474.           EncipheredPtrForMax&=EncipheredPtr2&
  475.         ENDIF
  476.       ENDIF
  477.       EncipheredPtr2&=PEEKL(EncipheredPtr2&+12)
  478.     ENDWH
  479.     DuplicateWord%=False%
  480.     EncipheredPtr2&=EncipheredHead&
  481.     WHILE (NOT DuplicateWord%) AND (EncipheredPtr2& <> 0)
  482.       IF PEEKL(EncipheredPtr2&+8)
  483.         IF StrICmp%:(PEEKL(EncipheredPtr2&),PEEKL(EncipheredPtrForMax&)) <> 0
  484.           EncipheredPtr2&=PEEKL(EncipheredPtr2&+12)
  485.         ELSE
  486.           DuplicateWord%=True%
  487.         ENDIF
  488.       ELSE
  489.         EncipheredPtr2&=PEEKL(EncipheredPtr2&+12)
  490.       ENDIF
  491.     ENDWH
  492.     IF DuplicateWord%
  493.       POKEL EncipheredPtrForMax&+8,PEEKL(EncipheredPtr2&+8)
  494.     ELSE
  495.       SortedPtr&=Malloc&:(20)
  496.       IF SortedPtr& = 0
  497.         FatalError%=True%
  498.         PRINT "Fatal error:  out of memory."
  499.       ELSE
  500.         NumDistinctWords&=NumDistinctWords&+1
  501.         POKEL EncipheredPtrForMax&+8,SortedPtr&
  502.         POKEL SortedPtr&,PEEKL(EncipheredPtrForMax&)
  503.         PatternPtr&=PEEKL(EncipheredPtrForMax&+4)
  504.         POKEL SortedPtr&+4,PatternPtr&
  505.         POKEL SortedPtr&+8,PEEKL(PatternPtr&+12)
  506.         POKEL SortedTail&+16,SortedPtr&
  507.         POKEL SortedPtr&+12,SortedTail&
  508.         POKEL SortedPtr&+16,0
  509.         SortedTail&=SortedPtr&
  510.         CiphertextCharPtr&=PEEKL(EncipheredPtrForMax&)
  511.         CiphertextChar%=PEEKB(CiphertextCharPtr&)
  512.         WHILE CiphertextChar% <> 0
  513.           IF CiphertextChar% <> Apostrophe%
  514.             LetterUsed%((ToLower%:(CiphertextChar%)-LowercaseA%)+1)=True%
  515.           ENDIF
  516.           CiphertextCharPtr&=CiphertextCharPtr&+1
  517.           CiphertextChar%=PEEKB(CiphertextCharPtr&)
  518.         ENDWH
  519.       ENDIF
  520.     ENDIF
  521.     EncipheredPtr1&=PEEKL(EncipheredPtr1&+12)
  522.   ENDWH
  523.   RETURN
  524. PROC GetEncipheredChar%:
  525.   EXTERNAL CiphertextCharPtr&
  526.   EXTERNAL CiphertextPtr&
  527.   LOCAL EncipheredChar%
  528.   IF CiphertextPtr& = 0
  529.     EncipheredChar%=EOF%
  530.   ELSE
  531.     EncipheredChar%=PEEKB(CiphertextCharPtr&)
  532.     CiphertextCharPtr&=CiphertextCharPtr&+1
  533.     IF PEEKB(CiphertextCharPtr&) = 0
  534.       CiphertextPtr&=PEEKL(CiphertextPtr&+4)
  535.       IF CiphertextPtr& <> 0
  536.         CiphertextCharPtr&=PEEKL(CiphertextPtr&)
  537.       ENDIF
  538.     ENDIF
  539.   ENDIF
  540.   RETURN EncipheredChar%
  541. PROC StrICmp%:(Str1&,Str2&)
  542.   LOCAL CharPtr1&
  543.   LOCAL CharPtr2&
  544.   LOCAL Char1%
  545.   LOCAL Char2%
  546.   LOCAL Result%
  547.   Result%=0
  548.   CharPtr1&=Str1&
  549.   CharPtr2&=Str2&
  550.   Char1%=PEEKB(CharPtr1&)
  551.   Char2%=PEEKB(CharPtr2&)
  552.   WHILE (Result% = 0) AND (Char1% <> 0)
  553.     Result%=Char1%-Char2%
  554.     IF Result% = 0
  555.       CharPtr1&=CharPtr1&+1
  556.       Char1%=PEEKB(CharPtr1&)
  557.       CharPtr2&=CharPtr2&+1
  558.       Char2%=PEEKB(CharPtr2&)
  559.     ENDIF
  560.   ENDWH
  561.   RETURN Result%
  562. PROC Solve:(NumDistinctWords&,EncipheredHead&,SortedHead&,KeepOnlyTheBest%,CiphertextHead&)
  563.   EXTERNAL CiphertextCharPtr&
  564.   EXTERNAL CiphertextPtr&
  565.   EXTERNAL FatalError%
  566.   GLOBAL Contradiction%
  567.   GLOBAL Decipherment$(27,1)
  568.   GLOBAL DeciphermentCount&(27)
  569.   GLOBAL Encipherment$(27,1)
  570.   GLOBAL EnciphermentCount&(27)
  571.   GLOBAL KeyPressed%
  572.   GLOBAL MaxScore&
  573.   GLOBAL NumPossibleSolutions&
  574.   GLOBAL Score&
  575.   GLOBAL SortedPtr&     
  576.   GLOBAL WordNum&
  577.   LOCAL Borrow%
  578.   LOCAL CharPtr1&
  579.   LOCAL CharPtr2&
  580.   LOCAL CurrentChar%
  581.   LOCAL DecipheredChar$(1)
  582.   LOCAL DecipheredIndex%
  583.   LOCAL EncipheredChar%
  584.   LOCAL EncipheredIndex%
  585.   NumPossibleSolutions&=0
  586.   CurrentChar%=1
  587.   WHILE CurrentChar% <= AlphabetSize%
  588.     Decipherment$(CurrentChar%)=""
  589.     DeciphermentCount&(CurrentChar%)=0
  590.     Encipherment$(CurrentChar%)=""
  591.     EnciphermentCount&(CurrentChar%)=0
  592.     CurrentChar%=CurrentChar%+1
  593.   ENDWH
  594.   Score&=0
  595.   MaxScore&=0
  596.   SortedPtr&=SortedHead&
  597.   WordNum&=0
  598.   KeyPressed%=False%
  599.   WHILE (SortedPtr& <> 0) AND (NOT KeyPressed%)
  600.     CharPtr1&=PEEKL(PEEKL(SortedPtr&+8))
  601.     IF PEEKB(CharPtr1&) <> 0
  602.       Score&=Score&+1
  603.     ENDIF
  604.     WordNum&=WordNum&+1
  605.     Contradiction%=False%
  606.     IF PEEKB(CharPtr1&) <> 0
  607.       REM Word in dictionary
  608.       CharPtr2&=PEEKL(SortedPtr&)
  609.       WHILE (NOT Contradiction%) AND (PEEKB(CharPtr2&) <> 0)
  610.         IF PEEKB(CharPtr1&) <> Apostrophe%
  611.           DecipheredChar$=CHR$(ToLower%:(PEEKB(CharPtr1&)))
  612.           EncipheredChar%=ToLower%:(PEEKB(CharPtr2&))
  613.           EncipheredIndex%=(EncipheredChar%-LowercaseA%)+1
  614.           IF DeciphermentCount&(EncipheredIndex%) <> 0
  615.             IF Decipherment$(EncipheredIndex%) = DecipheredChar$
  616.               DeciphermentCount&(EncipheredIndex%)=DeciphermentCount&(EncipheredIndex%)+1
  617.             ELSE
  618.               Contradiction%=True%
  619.             ENDIF
  620.           ELSE
  621.             Decipherment$(EncipheredIndex%)=DecipheredChar$
  622.             DeciphermentCount&(EncipheredIndex%)=1
  623.           ENDIF
  624.           DecipheredIndex%=(ASC(DecipheredChar$)-LowercaseA%)+1
  625.           IF EnciphermentCount&(DecipheredIndex%) <> 0
  626.             IF ASC(Encipherment$(DecipheredIndex%)) = EncipheredChar%
  627.               EnciphermentCount&(DecipheredIndex%)=EnciphermentCount&(DecipheredIndex%)+1
  628.             ELSE
  629.               Contradiction%=True%
  630.             ENDIF
  631.           ELSE
  632.             Encipherment$(DecipheredIndex%)=CHR$(EncipheredChar%)
  633.             EnciphermentCount&(DecipheredIndex%)=1
  634.           ENDIF
  635.         ENDIF
  636.         CharPtr1&=CharPtr1&+1
  637.         CharPtr2&=CharPtr2&+1
  638.       ENDWH
  639.     ELSE
  640.       REM Word not in dictionary
  641.       IF Score&+NumDistinctWords&-WordNum& < MaxScore&
  642.         Contradiction%=True%
  643.       ENDIF
  644.     ENDIF
  645.     IF Contradiction%
  646.       GoBackward:
  647.     ELSE
  648.       GoForward:(KeepOnlyTheBest%,EncipheredHead&,CiphertextHead&)
  649.     ENDIF
  650.     IF NOT KeyPressed%
  651.       IF KEY
  652.         KeyPressed%=True%
  653.       ENDIF
  654.     ENDIF
  655.   ENDWH
  656.   IF NOT FatalError%
  657.     IF NumPossibleSolutions& = 0
  658.       PRINT "No solutions were found."
  659.     ENDIF
  660.   ENDIF
  661.   RETURN
  662. PROC GoForward:(KeepOnlyTheBest%,EncipheredHead&,CiphertextHead&)
  663.   EXTERNAL CiphertextCharPtr&
  664.   EXTERNAL CiphertextPtr&
  665.   EXTERNAL Contradiction%
  666.   EXTERNAL Decipherment$()
  667.   EXTERNAL DeciphermentCount&()
  668.   EXTERNAL Encipherment$()
  669.   EXTERNAL EnciphermentCount&()
  670.   EXTERNAL KeyPressed%
  671.   EXTERNAL MaxScore&
  672.   EXTERNAL NumPossibleSolutions&
  673.   EXTERNAL Score&
  674.   EXTERNAL SortedPtr&
  675.   EXTERNAL WordNum&
  676.   LOCAL Borrow%
  677.   LOCAL CharPtr1&
  678.   LOCAL CharPtr2&
  679.   LOCAL Count&
  680.   LOCAL DecipheredChar$(1)
  681.   LOCAL DecipheredIndex%
  682.   LOCAL EncipheredChar%
  683.   LOCAL EncipheredIndex%
  684.   IF PEEKL(SortedPtr&+16) <> 0
  685.     SortedPtr&=PEEKL(SortedPtr&+16)
  686.   ELSE
  687.     IF Score& > MaxScore&
  688.       MaxScore&=Score&
  689.       IF KeepOnlyTheBest%
  690.         REM Delete previous solutions from display.
  691.         NumPossibleSolutions&=0
  692.       ENDIF
  693.     ENDIF
  694.     OutputSolution:(EncipheredHead&,CiphertextHead&)
  695.     IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  696.       Score&=Score&-1
  697.     ENDIF
  698.     WordNum&=WordNum&-1
  699.     Borrow%=True%
  700.     WHILE Borrow% AND (SortedPtr& <> 0) AND (NOT KeyPressed%)
  701.       CharPtr1&=PEEKL(PEEKL(SortedPtr&+8))
  702.       IF PEEKB(CharPtr1&) <> 0
  703.         Contradiction%=False%
  704.         CharPtr2&=PEEKL(SortedPtr&)
  705.         WHILE (NOT Contradiction%) AND (PEEKB(CharPtr2&) <> 0)
  706.           IF PEEKB(CharPtr1&) <> Apostrophe%
  707.             DecipheredChar$=CHR$(ToLower%:(PEEKB(CharPtr1&)))
  708.             EncipheredChar%=ToLower%:(PEEKB(CharPtr2&))
  709.             EncipheredIndex%=(EncipheredChar%-LowercaseA%)+1
  710.             IF Decipherment$(EncipheredIndex%) = DecipheredChar$
  711.               Count&=DeciphermentCount&(EncipheredIndex%)-1
  712.               DeciphermentCount&(EncipheredIndex%)=Count&
  713.               IF Count& = 0
  714.                 Decipherment$(EncipheredIndex%)=""
  715.               ENDIF
  716.             ELSE
  717.              Contradiction%=True%
  718.             ENDIF
  719.             DecipheredIndex%=(ASC(DecipheredChar$)-LowercaseA%)+1
  720.             IF ASC(Encipherment$(DecipheredIndex%)) = EncipheredChar%
  721.               Count&=EnciphermentCount&(DecipheredIndex%)-1
  722.               EnciphermentCount&(DecipheredIndex%)=Count&
  723.               IF Count& = 0
  724.                 Encipherment$(DecipheredIndex%)=""
  725.               ENDIF
  726.             ELSE
  727.               Contradiction%=True%
  728.             ENDIF
  729.           ENDIF
  730.           CharPtr1&=CharPtr1&+1
  731.           CharPtr2&=CharPtr2&+1
  732.         ENDWH
  733.       ENDIF
  734.       POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+8)+4)
  735.       IF PEEKL(SortedPtr&+8) <> 0
  736.         Borrow%=False%
  737.       ELSE
  738.         POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+4)+12)
  739.         SortedPtr&=PEEKL(SortedPtr&+12)
  740.         IF SortedPtr& <> 0
  741.           IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  742.             Score&=Score&-1
  743.           ENDIF
  744.         ENDIF
  745.         WordNum&=WordNum&-1
  746.       ENDIF
  747.       IF KEY
  748.         KeyPressed%=True%
  749.       ENDIF
  750.     ENDWH
  751.   ENDIF
  752.   RETURN
  753. PROC GoBackward:
  754.   EXTERNAL Contradiction%
  755.   EXTERNAL Decipherment$()
  756.   EXTERNAL DeciphermentCount&()
  757.   EXTERNAL Encipherment$()
  758.   EXTERNAL EnciphermentCount&()
  759.   EXTERNAL KeyPressed%
  760.   EXTERNAL Score&
  761.   EXTERNAL SortedPtr&     
  762.   EXTERNAL WordNum&
  763.   LOCAL Borrow%
  764.   LOCAL CharPtr1&
  765.   LOCAL CharPtr2&
  766.   LOCAL Count&
  767.   LOCAL DecipheredChar$(1)
  768.   LOCAL DecipheredIndex%
  769.   LOCAL EncipheredChar%
  770.   LOCAL EncipheredIndex%
  771.   IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  772.     Score&=Score&-1
  773.   ENDIF
  774.   WordNum&=WordNum&-1
  775.   Borrow%=True%
  776.   WHILE Borrow% AND (SortedPtr& <> 0) AND (NOT KeyPressed%)
  777.     CharPtr1&=PEEKL(PEEKL(SortedPtr&+8))
  778.     IF PEEKB(CharPtr1&) <> 0
  779.       Contradiction%=False%
  780.       CharPtr2&=PEEKL(SortedPtr&)
  781.       WHILE (NOT Contradiction%) AND (PEEKB(CharPtr2&) <> 0)
  782.         IF PEEKB(CharPtr1&) <> Apostrophe%
  783.           DecipheredChar$=CHR$(Tolower%:(PEEKB(CharPtr1&)))
  784.           EncipheredChar%=ToLower%:(PEEKB(CharPtr2&))
  785.           EncipheredIndex%=(EncipheredChar%-LowercaseA%)+1
  786.           IF Decipherment$(EncipheredIndex%) = DecipheredChar$
  787.             Count&=DeciphermentCount&(EncipheredIndex%)-1
  788.             DeciphermentCount&(EncipheredIndex%)=Count&
  789.             IF Count& = 0
  790.               Decipherment$(EncipheredIndex%)=""
  791.             ENDIF
  792.           ELSE
  793.            Contradiction%=True%
  794.           ENDIF
  795.           DecipheredIndex%=(ASC(DecipheredChar$)-LowercaseA%)+1
  796.           IF ASC(Encipherment$(DecipheredIndex%)) = EncipheredChar%
  797.             Count&=EnciphermentCount&(DecipheredIndex%)-1
  798.             EnciphermentCount&(DecipheredIndex%)=Count&
  799.             IF Count& = 0
  800.               Encipherment$(DecipheredIndex%)=""
  801.             ENDIF
  802.           ELSE
  803.             Contradiction%=True%
  804.           ENDIF
  805.         ENDIF
  806.         CharPtr1&=CharPtr1&+1
  807.         CharPtr2&=CharPtr2&+1
  808.       ENDWH
  809.     ENDIF
  810.     POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+8)+4)
  811.     IF PEEKL(SortedPtr&+8) <> 0
  812.       Borrow%=False%
  813.     ELSE
  814.       POKEL SortedPtr&+8,PEEKL(PEEKL(SortedPtr&+4)+12)
  815.       SortedPtr&=PEEKL(SortedPtr&+12)
  816.       IF SortedPtr& <> 0
  817.         IF PEEKB(PEEKL(PEEKL(SortedPtr&+8))) <> 0
  818.           Score&=Score&-1
  819.         ENDIF
  820.       ENDIF
  821.       WordNum&=WordNum&-1
  822.     ENDIF
  823.     IF KEY
  824.       KeyPressed%=True%
  825.     ENDIF
  826.   ENDWH
  827.   RETURN
  828. PROC OutputSolution:(EncipheredHead&,CiphertextHead&)
  829.   EXTERNAL CiphertextCharPtr&
  830.   EXTERNAL CiphertextPtr&
  831.   EXTERNAL Decipherment$()
  832.   EXTERNAL DeciphermentCount&()
  833.   EXTERNAL NumPossibleSolutions&
  834.   LOCAL CurrentChar%
  835.   LOCAL EncipheredIndex%
  836.   LOCAL EncipheredPtr&
  837.   LOCAL EndOfFile%
  838.   LOCAL Letter%
  839.   LOCAL PlaintextChar%
  840.   LOCAL PlaintextCharPtr& 
  841.   CiphertextPtr&=CiphertextHead&
  842.   CiphertextCharPtr&=PEEKL(CiphertextHead&)
  843.   NumPossibleSolutions&=NumPossibleSolutions&+1
  844.   EncipheredPtr&=EncipheredHead&
  845.   PRINT
  846.     EndOfFile%=False%
  847.     Letter%=False%
  848.     WHILE (NOT EndOfFile%) AND (NOT Letter%)
  849.       CurrentChar%=GetEncipheredChar%:
  850.       IF CurrentChar% = EOF%
  851.         EndOfFile%=True%
  852.       ELSE
  853.         IF CurrentChar% = Apostrophe%
  854.           Letter%=True%
  855.         ELSE
  856.           IF IsLower%:(CurrentChar%)
  857.             Letter%=True%
  858.           ELSE
  859.             IF IsUpper%:(CurrentChar%)
  860.               Letter%=True%
  861.             ELSE
  862.               IF CurrentChar% = 10
  863.                 PRINT
  864.               ELSE
  865.                 PRINT CHR$(CurrentChar%);
  866.               ENDIF
  867.             ENDIF
  868.           ENDIF
  869.         ENDIF
  870.       ENDIF
  871.     ENDWH
  872.     IF CurrentChar% <> EOF%
  873.       PlaintextCharPtr&=PEEKL(PEEKL(PEEKL(EncipheredPtr&+8)+8))
  874.       PlaintextChar%=PEEKB(PlaintextCharPtr&)
  875.       IF PlaintextChar% <> 0
  876.         DO
  877.           IF CurrentChar% = Apostrophe%
  878.             PRINT "'";
  879.           ELSE
  880.             IF IsLower%:(CurrentChar%)
  881.               CurrentChar%=ToLower%:(PlaintextChar%)
  882.             ELSE
  883.               CurrentChar%=ToUpper%:(PlaintextChar%)
  884.             ENDIF
  885.             PRINT CHR$(CurrentChar%);
  886.           ENDIF
  887.           PlaintextCharPtr&=PlaintextCharPtr&+1
  888.           PlaintextChar%=PEEKB(PlaintextCharPtr&)
  889.           CurrentChar%=GetEncipheredChar%:
  890.         UNTIL (CurrentChar% = EOF%) OR ((CurrentChar% <> Apostrophe%) AND (NOT IsLower%:(ToLower%:(CurrentChar%))))
  891.       ELSE
  892.         DO
  893.           IF CurrentChar% = Apostrophe%
  894.             PRINT CHR$(CurrentChar%);
  895.           ELSE
  896.             IF IsLower%:(CurrentChar%)
  897.               EncipheredIndex%=(CurrentChar%-LowercaseA%)+1
  898.               IF DeciphermentCount&(EncipheredIndex%) <> 0
  899.                 CurrentChar%=ToLower%:(ASC(Decipherment$(EncipheredIndex%)))
  900.               ELSE
  901.                 CurrentChar%=Asterisk%
  902.               ENDIF
  903.               PRINT CHR$(CurrentChar%);
  904.             ELSE
  905.               IF IsUpper%:(CurrentChar%)
  906.                 EncipheredIndex%=(CurrentChar%-UppercaseA%)+1
  907.                 IF DeciphermentCount&(EncipheredIndex%) <> 0
  908.                   CurrentChar%=ToUpper%:(ASC(Decipherment$(EncipheredIndex%)))
  909.                 ELSE
  910.                   CurrentChar%=Asterisk%
  911.                 ENDIF
  912.                 PRINT CHR$(CurrentChar%);
  913.               ELSE
  914.                 CurrentChar%=ToUpper%:(PEEKB(PlaintextCharPtr&))
  915.                 PRINT CHR$(CurrentChar%);
  916.               ENDIF
  917.             ENDIF
  918.           ENDIF
  919.           CurrentChar%=GetEncipheredChar%:
  920.         UNTIL (CurrentChar% = EOF%) OR ((CurrentChar% <> Apostrophe%) AND (NOT IsLower%:(ToLower%:(CurrentChar%))))
  921.       ENDIF
  922.       IF CurrentChar% <> EOF%
  923.         IF CurrentChar% = 10
  924.           PRINT
  925.         ELSE
  926.           PRINT CHR$(CurrentChar%);
  927.         ENDIF
  928.       ENDIF
  929.       EncipheredPtr&=PEEKL(EncipheredPtr&+12)
  930.     ENDIF
  931.   UNTIL CurrentChar% = EOF%
  932.   RETURN
  933. PROC AddWordNotInWordList:(PatternPtr&)
  934.   EXTERNAL FatalError%
  935.   LOCAL Plaintext&
  936.   LOCAL PlaintextPtr&
  937.   PlaintextPtr&=Malloc&:(8)
  938.   IF PlaintextPtr& = 0
  939.     FatalError%=True%
  940.     PRINT "Fatal error:  out of memory."
  941.   ELSE
  942.     Plaintext&=Malloc&:(1)
  943.     IF Plaintext& = 0
  944.       FatalError%=True%
  945.       PRINT "Fatal error:  out of memory."
  946.     ELSE
  947.       POKEB Plaintext&,0
  948.       POKEL PlaintextPtr&,Plaintext&
  949.       POKEL PlaintextPtr&+4,0
  950.       POKEL PatternPtr&+12,PlaintextPtr&
  951.     ENDIF
  952.   ENDIF
  953.   RETURN
  954. PROC AddPlaintext:(PatternHead&,Pattern&,Plaintext$)
  955.   EXTERNAL FatalError%
  956.   LOCAL BytePtr&
  957.   LOCAL Finished%
  958.   LOCAL GreaterPtr&
  959.   LOCAL InternalPtr&
  960.   LOCAL LesserPtr&
  961.   LOCAL NumPlaintextChars%
  962.   LOCAL Plaintext2&
  963.   LOCAL PlaintextCharNum%
  964.   LOCAL PlaintextPtr&
  965.   LOCAL Relation%
  966.   InternalPtr&=PatternHead&
  967.   Finished%=False%
  968.   WHILE NOT Finished%
  969.     Relation%=StrCmp%:(Pattern&,PEEKL(InternalPtr&+4))
  970.     IF Relation% < 0
  971.       LesserPtr&=PEEKL(InternalPtr&+16)
  972.       IF LesserPtr& <> 0
  973.         InternalPtr&=LesserPtr&
  974.       ELSE
  975.         Finished%=True%
  976.       ENDIF
  977.     ELSE
  978.       IF Relation% > 0
  979.         GreaterPtr&=PEEKL(InternalPtr&+20)
  980.         IF GreaterPtr& <> 0
  981.           InternalPtr&=GreaterPtr&
  982.         ELSE
  983.           Finished%=True%
  984.         ENDIF
  985.       ELSE
  986.         PlaintextPtr&=Malloc&:(8)
  987.         IF PlaintextPtr& = 0
  988.           FatalError%=True%
  989.           PRINT "Fatal error:  out of memory."
  990.         ELSE
  991.           NumPlaintextChars%=LEN(Plaintext$)
  992.           Plaintext2&=Malloc&:(1+NumPlaintextChars%)
  993.           IF Plaintext2& = 0
  994.             FatalError%=True%
  995.             PRINT "Fatal error:  out of memory."
  996.             FREEALLOC PlaintextPtr&
  997.           ELSE
  998.             BytePtr&=Plaintext2&
  999.             PlaintextCharNum%=1
  1000.             WHILE PlaintextCharNum% <= NumPlaintextChars%
  1001.               POKEB BytePtr&,ASC(MID$(Plaintext$,PlaintextCharNum%,1))
  1002.               BytePtr&=BytePtr&+1
  1003.               PlaintextCharNum%=PlaintextCharNum%+1
  1004.             ENDWH
  1005.             POKEB BytePtr&,0
  1006.             POKEL PlaintextPtr&,Plaintext2&
  1007.             POKEL InternalPtr&+8,PEEKL(InternalPtr&+8)+1
  1008.             POKEL PlaintextPtr&+4,PEEKL(InternalPtr&+12)
  1009.             POKEL InternalPtr&+12,PlaintextPtr&
  1010.           ENDIF
  1011.         ENDIF
  1012.         Finished%=True%
  1013.       ENDIF
  1014.     ENDIF
  1015.   ENDWH
  1016.   RETURN
  1017. PROC GetPatternForPlaintextWord:(PatternPtr&)
  1018.   EXTERNAL Word$
  1019.   EXTERNAL Alphabetic%
  1020.   LOCAL CharNum1%
  1021.   LOCAL CharPtr2&
  1022.   LOCAL CharNum3%
  1023.   LOCAL CharPtr4&
  1024.   LOCAL CharValue%
  1025.   LOCAL CurrentChar$(1)
  1026.   LOCAL LowercaseWord$(255)
  1027.   LOCAL NumChars%
  1028.   LOCAL NumDistinctChars%
  1029.   Alphabetic%=True%
  1030.   CharNum1%=1
  1031.   NumChars%=LEN(Word$)
  1032.   CharPtr2&=PatternPtr&
  1033.   LowercaseWord$=""
  1034.   WHILE Alphabetic% AND (CharNum1% <= NumChars%)
  1035.     CurrentChar$=MID$(Word$,CharNum1%,1)
  1036.     IF CurrentChar$ = "'"
  1037.       LowercaseWord$=LowercaseWord$+"'"
  1038.     ELSE
  1039.       CharValue%=ToLower%:(ASC(CurrentChar$))
  1040.       LowercaseWord$=LowercaseWord$+CHR$(CharValue%)
  1041.       Alphabetic%=IsLower%:(CharValue%)
  1042.     ENDIF
  1043.     POKEB CharPtr2&,0
  1044.     CharPtr2&=CharPtr2&+1
  1045.     CharNum1%=CharNum1%+1
  1046.   ENDWH
  1047.   IF Alphabetic%
  1048.     POKEB CharPtr2&,0
  1049.     NumDistinctChars%=0
  1050.     CharNum1%=1
  1051.     CharPtr2&=PatternPtr&
  1052.     WHILE CharNum1% <= NumChars%
  1053.       IF PEEKB(CharPtr2&) = 0
  1054.         CurrentChar$=MID$(Word$,CharNum1%,1)
  1055.         IF CurrentChar$ = "'"
  1056.           POKEB CharPtr2&,AlphabetSize%
  1057.         ELSE
  1058.           NumDistinctChars%=NumDistinctChars%+1
  1059.           POKEB CharPtr2&,NumDistinctChars%
  1060.           CharNum3%=CharNum1%+1
  1061.           CharPtr4&=CharPtr2&+1
  1062.           WHILE CharNum3% <= NumChars%
  1063.             IF MID$(Word$,CharNum3%,1) = CurrentChar$
  1064.               POKEB CharPtr4&,NumDistinctChars%
  1065.             ENDIF
  1066.             CharPtr4&=CharPtr4&+1
  1067.             CharNum3%=CharNum3%+1
  1068.           ENDWH
  1069.         ENDIF
  1070.       ENDIF
  1071.       CharPtr2&=CharPtr2&+1
  1072.       CharNum1%=CharNum1%+1
  1073.     ENDWH
  1074.   ENDIF
  1075.   RETURN
  1076. PROC FreePattern:(PatternPtr&)
  1077.   LOCAL PlaintextHead&
  1078.   LOCAL PlaintextPtr&
  1079.   IF PatternPtr& <> 0
  1080.     FreePattern:(PEEKL(PatternPtr&+16))
  1081.     FreePattern:(PEEKL(PatternPtr&+20))
  1082.     FREEALLOC PEEKL(PatternPtr&+4)
  1083.     PlaintextHead&=PEEKL(PatternPtr&+12)
  1084.     WHILE PlaintextHead& <> 0
  1085.       PlaintextPtr&=PEEKL(PlaintextHead&+4)
  1086.       FREEALLOC PEEKL(PlaintextHead&)
  1087.       FREEALLOC PlaintextHead&
  1088.       PlaintextHead&=PlaintextPtr&
  1089.     ENDWH
  1090.     FREEALLOC PatternPtr&
  1091.   ENDIF
  1092.   RETURN
  1093. PROC PatternForWord&:(Word&,WordLen%)
  1094.   EXTERNAL FatalError%
  1095.   EXTERNAL NumDistinctLetters&
  1096.   LOCAL CharPtr1&
  1097.   LOCAL CharPtr2&
  1098.   LOCAL CharPtr3&
  1099.   LOCAL CharPtr4&
  1100.   LOCAL Char1%
  1101.   LOCAL Char3%
  1102.   LOCAL NumDistinctChars&
  1103.   LOCAL Pattern&
  1104.   Pattern&=Malloc&:(1+WordLen%)
  1105.   IF Pattern& = 0
  1106.     FatalError%=True%
  1107.     PRINT "Fatal error:  out of memory."
  1108.     NumDistinctLetters&=0
  1109.   ELSE
  1110.     CharPtr1&=Word&
  1111.     CharPtr2&=Pattern&
  1112.     WHILE PEEKB(CharPtr1&) <> 0
  1113.       POKEB CharPtr2&,0
  1114.       CharPtr2&=CharPtr2&+1
  1115.       CharPtr1&=CharPtr1&+1
  1116.     ENDWH
  1117.     POKEB CharPtr2&,0
  1118.     NumDistinctChars&=0
  1119.     CharPtr1&=Word&
  1120.     CharPtr2&=Pattern&
  1121.     Char1%=PEEKB(CharPtr1&)
  1122.     WHILE Char1% <> 0
  1123.       IF PEEKB(CharPtr2&) = 0
  1124.         IF Char1% = Apostrophe%
  1125.           POKEB CharPtr2&,AlphabetSize%
  1126.         ELSE
  1127.           NumDistinctChars&=NumDistinctChars&+1
  1128.           POKEB CharPtr2&,NumDistinctChars&
  1129.           CharPtr3&=CharPtr1&+1
  1130.           Char3%=PEEKB(CharPtr3&)
  1131.           CharPtr4&=CharPtr2&+1
  1132.           WHILE Char3% <> 0
  1133.             IF Char3% = Char1%
  1134.               POKEB CharPtr4&,NumDistinctChars&
  1135.             ENDIF
  1136.             CharPtr4&=CharPtr4&+1
  1137.             CharPtr3&=CharPtr3&+1
  1138.             Char3%=PEEKB(CharPtr3&)
  1139.           ENDWH
  1140.         ENDIF
  1141.       ENDIF
  1142.       CharPtr2&=CharPtr2&+1
  1143.       CharPtr1&=CharPtr1&+1
  1144.       Char1%=PEEKB(CharPtr1&)
  1145.     ENDWH
  1146.     NumDistinctLetters&=NumDistinctChars&
  1147.   ENDIF
  1148.   RETURN Pattern&
  1149. PROC StrCmp%:(Str1&,Str2&)
  1150.   LOCAL CharPtr1&
  1151.   LOCAL CharPtr2&
  1152.   LOCAL Char1%
  1153.   LOCAL Char2%
  1154.   LOCAL Result%
  1155.   Result%=0
  1156.   CharPtr1&=Str1&
  1157.   CharPtr2&=Str2&
  1158.   Char1%=PEEKB(CharPtr1&)
  1159.   Char2%=PEEKB(CharPtr2&)
  1160.   WHILE (Result% = 0) AND (Char1% <> 0) AND (Char2% <> 0)
  1161.     Result%=Char1%-Char2%
  1162.     CharPtr1&=CharPtr1&+1
  1163.     Char1%=PEEKB(CharPtr1&)
  1164.     CharPtr2&=CharPtr2&+1
  1165.     Char2%=PEEKB(CharPtr2&)
  1166.   ENDWH
  1167.   IF Result% = 0
  1168.     Result%=Char1%-Char2%
  1169.   ENDIF
  1170.   RETURN Result%
  1171. PROC PatternForEncipheredWord&:(EncipheredWord&,EncipheredWordLen%)
  1172.   EXTERNAL FatalError%
  1173.   EXTERNAL PatternHead&
  1174.   GLOBAL NumDistinctLetters&
  1175.   LOCAL ExternalPtr&
  1176.   LOCAL Finished%
  1177.   LOCAL GreaterPtr&
  1178.   LOCAL InternalPtr&
  1179.   LOCAL LesserPtr&
  1180.   LOCAL Relation%
  1181.   LOCAL Pattern&
  1182.   InternalPtr&=0
  1183.   Pattern&=PatternForWord&:(EncipheredWord&,EncipheredWordLen%)
  1184.   IF (NOT FatalError%)
  1185.     IF (PatternHead&)
  1186.       InternalPtr&=PatternHead&
  1187.       Finished%=False%
  1188.       DO
  1189.         Relation%=StrCmp%:(Pattern&,PEEKL(InternalPtr&+4))
  1190.         IF Relation% < 0
  1191.           LesserPtr&=PEEKL(InternalPtr&+16)
  1192.           IF LesserPtr& <> 0
  1193.             InternalPtr&=LesserPtr&
  1194.           ELSE
  1195.             ExternalPtr&=Malloc&:(24)
  1196.             IF ExternalPtr& = 0
  1197.               FatalError%=True%
  1198.               PRINT "Fatal error:  out of memory."
  1199.             ELSE
  1200.               POKEL ExternalPtr&+4,Pattern&
  1201.               POKEL ExternalPtr&,NumDistinctLetters&
  1202.               POKEL ExternalPtr&+8,0
  1203.               POKEL ExternalPtr&+12,0
  1204.               POKEL ExternalPtr&+16,0
  1205.               POKEL ExternalPtr&+20,0
  1206.               POKEL InternalPtr&+16,ExternalPtr&
  1207.             ENDIF
  1208.             InternalPtr&=ExternalPtr&
  1209.             Finished%=True%
  1210.           ENDIF
  1211.         ELSE
  1212.           IF Relation% > 0
  1213.             GreaterPtr&=PEEKL(InternalPtr&+20)
  1214.             IF GreaterPtr& <> 0
  1215.               InternalPtr&=GreaterPtr&
  1216.             ELSE
  1217.               ExternalPtr&=Malloc&:(24)
  1218.               IF ExternalPtr& = 0
  1219.                 FatalError%=True%
  1220.                 PRINT "Fatal error:  out of memory."
  1221.               ELSE
  1222.                 POKEL ExternalPtr&+4,Pattern&
  1223.                 POKEL ExternalPtr&,NumDistinctLetters&
  1224.                 POKEL ExternalPtr&+8,0
  1225.                 POKEL ExternalPtr&+12,0
  1226.                 POKEL ExternalPtr&+16,0
  1227.                 POKEL ExternalPtr&+20,0
  1228.                 POKEL InternalPtr&+20,ExternalPtr&
  1229.               ENDIF
  1230.               InternalPtr&=ExternalPtr&
  1231.               Finished%=True%
  1232.             ENDIF
  1233.           ELSE
  1234.             FREEALLOC Pattern&
  1235.             Finished%=True%
  1236.           ENDIF
  1237.         ENDIF
  1238.       UNTIL Finished%
  1239.     ELSE
  1240.       InternalPtr&=Malloc&:(24)
  1241.       IF InternalPtr& = 0
  1242.         FatalError%=True%
  1243.         PRINT "Fatal error:  out of memory."
  1244.       ELSE
  1245.         POKEL InternalPtr&+4,Pattern&
  1246.         POKEL InternalPtr&,NumDistinctLetters&
  1247.         POKEL InternalPtr&+8,0
  1248.         POKEL InternalPtr&+12,0
  1249.         POKEL InternalPtr&+16,0
  1250.         POKEL InternalPtr&+20,0
  1251.         PatternHead&=InternalPtr&
  1252.       ENDIF
  1253.     ENDIF
  1254.   ENDIF
  1255.   RETURN InternalPtr&
  1256. PROC AddEncipheredWord&:(EncipheredWord$)
  1257.   EXTERNAL EncipheredHead&
  1258.   EXTERNAL EncipheredTail&
  1259.   EXTERNAL FatalError%
  1260.   EXTERNAL PatternHead&
  1261.   LOCAL Ciphertext&
  1262.   LOCAL BytePtr&
  1263.   LOCAL EncipheredWordIndex%
  1264.   LOCAL EncipheredWordLen%
  1265.   LOCAL ExternalPtr&
  1266.   LOCAL PatternPtr&
  1267.   PatternPtr&=0
  1268.   ExternalPtr&=Malloc&:(16)
  1269.   IF ExternalPtr& = 0
  1270.     FatalError%=True%
  1271.     PRINT "Fatal error:  out of memory."
  1272.   ELSE
  1273.     Ciphertext&=Malloc&:(1+LEN(EncipheredWord$))
  1274.     IF Ciphertext& = 0
  1275.       FatalError%=True%
  1276.       PRINT "Fatal error:  out of memory."
  1277.     ELSE
  1278.       BytePtr&=Ciphertext&
  1279.       EncipheredWordLen%=LEN(EncipheredWord$)
  1280.       EncipheredWordIndex%=1
  1281.       WHILE EncipheredWordIndex% <= EncipheredWordLen%
  1282.         POKEB BytePtr&,ASC(MID$(EncipheredWord$,EncipheredWordIndex%,1))
  1283.         BytePtr&=BytePtr&+1
  1284.         EncipheredWordIndex%=EncipheredWordIndex%+1
  1285.       ENDWH
  1286.       POKEB BytePtr&,0
  1287.       POKEL ExternalPtr&,Ciphertext&
  1288.       POKEL ExternalPtr&+8,0
  1289.       PatternPtr&=PatternForEncipheredWord&:(Ciphertext&,EncipheredWordLen%)
  1290.       POKEL ExternalPtr&+4,PatternPtr&
  1291.       POKEL ExternalPtr&+12,0
  1292.       IF EncipheredTail& <> 0
  1293.         POKEL EncipheredTail&+12,ExternalPtr&
  1294.       ELSE
  1295.         EncipheredHead&=ExternalPtr&
  1296.       ENDIF
  1297.       EncipheredTail&=ExternalPtr&
  1298.     ENDIF
  1299.   ENDIF
  1300.   RETURN PatternPtr&
  1301. PROC GetWordListWord:(PreviousWord$)
  1302.   EXTERNAL CharNum%
  1303.   EXTERNAL FatalError%
  1304.   EXTERNAL LineNum&
  1305.   EXTERNAL Word$
  1306.   EXTERNAL WordList$()
  1307.   LOCAL CurrentChar%
  1308.   LOCAL DupCount%
  1309.   Word$=""
  1310.   DupCount%=GetWordListChar%:
  1311.   IF DupCount% <> EOF%
  1312.     IF (DupCount% >= UppercaseA%) AND (DupCount% <= UppercaseZ%)
  1313.       DupCount%=DupCount%-UppercaseA%
  1314.       IF DupCount% > 0
  1315.         Word$=LEFT$(PreviousWord$,DupCount%)
  1316.       ENDIF
  1317.       DO
  1318.         CurrentChar%=GetWordListChar%:
  1319.         IF CurrentChar% = EOF%
  1320.           FatalError%=True%
  1321.           PRINT "Fatal error:  premature end of word list."
  1322.         ELSE
  1323.           IF (CurrentChar% >= UppercaseA%) AND (CurrentChar% <= UppercaseZ%)
  1324.             Word$=Word$+CHR$(ToLower%:(CurrentChar%))
  1325.           ELSE
  1326.             IF CurrentChar% = UppercaseZ%+1
  1327.               Word$=Word$+"'"
  1328.             ELSE
  1329.               IF CurrentChar% <> Slash%
  1330.                 FatalError%=True%
  1331.                 PRINT "Fatal error:  unexpected character in word list."
  1332.               ENDIF
  1333.             ENDIF
  1334.           ENDIF
  1335.         ENDIF
  1336.       UNTIL FatalError% OR (CurrentChar% = Slash%)
  1337.     ELSE
  1338.       FatalError%=True%
  1339.       PRINT "Fatal error:  invalid dup count in word list."
  1340.     ENDIF
  1341.   ENDIF
  1342.   RETURN
  1343. PROC GetWordListChar%:
  1344.   EXTERNAL CharNum%
  1345.   EXTERNAL LineNum&
  1346.   EXTERNAL WordList$()
  1347.   LOCAL CurrentChar$(1)
  1348.   LOCAL Result%
  1349.   CurrentChar$=MID$(WordList$(LineNum&),CharNum%,1)
  1350.   IF CurrentChar$ = "!"
  1351.     Result%=EOF%
  1352.   ELSE
  1353.     Result%=ASC(CurrentChar$)
  1354.     CharNum%=CharNum%+1
  1355.     IF CharNum% > LEN(WordList$(LineNum&))
  1356.       LineNum&=LineNum&+1
  1357.       CharNum%=1
  1358.     ENDIF
  1359.   ENDIF
  1360.   RETURN Result%
  1361. PROC Malloc&:(NumBytes%)
  1362.   LOCAL Result&
  1363.   ONERR AllocFailed
  1364.   Result&=ALLOC(NumBytes%)
  1365.   ONERR OFF
  1366.   RETURN Result&
  1367. AllocFailed::
  1368.   RETURN 0
  1369. PROC ToLower%:(CurrentChar%)
  1370.   LOCAL Result%
  1371.   IF CurrentChar% < UppercaseA%
  1372.     Result%=CurrentChar%
  1373.   ELSE
  1374.     IF CurrentChar% > UppercaseZ%
  1375.       Result%=CurrentChar%
  1376.     ELSE
  1377.       Result%=(CurrentChar%-UppercaseA%)+LowercaseA%
  1378.     ENDIF
  1379.   ENDIF
  1380.   RETURN Result%
  1381. PROC ToUpper%:(CurrentChar%)
  1382.   LOCAL Result%
  1383.   IF CurrentChar% < LowercaseA%
  1384.     Result%=CurrentChar%
  1385.   ELSE
  1386.     IF CurrentChar% > LowercaseZ%
  1387.       Result%=CurrentChar%
  1388.     ELSE
  1389.       Result%=(CurrentChar%-LowercaseA%)+UppercaseA%
  1390.     ENDIF
  1391.   ENDIF
  1392.   RETURN Result%
  1393. PROC IsLower%:(CurrentChar%)
  1394.   LOCAL Result%
  1395.   IF CurrentChar% < LowercaseA%
  1396.     Result%=False%
  1397.   ELSE
  1398.     IF CurrentChar% > LowercaseZ%
  1399.       Result%=False%
  1400.     ELSE
  1401.       Result%=True%
  1402.     ENDIF
  1403.   ENDIF
  1404.   RETURN Result%
  1405. PROC IsUpper%:(CurrentChar%)
  1406.   LOCAL Result%
  1407.   IF CurrentChar% < UppercaseA%
  1408.     Result%=False%
  1409.   ELSE
  1410.     IF CurrentChar% > UppercaseZ%
  1411.       Result%=False%
  1412.     ELSE
  1413.       Result%=True%
  1414.     ENDIF
  1415.   ENDIF
  1416.   RETURN Result%
  1417. *Texted.app
  1418. This SIS-file is designed by BISON Software. 
  1419. Bison Software doesn't accept any liability for the 
  1420. function of the programme to be installed. 
  1421. Please pay attention to the comment in the README file
  1422. of the author.
  1423. Before installing this software please make a
  1424. B A C K U P  of your Psion Series 5.
  1425. Have a lot of fun!
  1426. Diese SIS-Datei wurde von Bison Software erstellt.
  1427. Bison Software 
  1428. bernimmt keinerlei Garantie f
  1429. r die 
  1430. Funktion des zu installierenden Programmes. 
  1431. Bitte beachten Sie die Hinweise in der README Datei des
  1432. Autors.
  1433. Bevor Sie das Programm installieren machen Sie ein  
  1434. B A C K U P  Ihres Psion Serie 5.
  1435. Viel Spa
  1436.