home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / asm / RPSRT102.ZIP / RPSRT102.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-12-15  |  113.7 KB  |  4,658 lines

  1. ;    Int Numbers
  2. DOS        Equ    21H
  3. Kbrd        Equ    16H
  4. ;
  5. ;    Dos Func Numbers
  6. ReadNoEcho    Equ    0800H
  7. ClearReadNoEcho Equ    0C08H
  8. SelectDisk    Equ    0E00H
  9. CurrDisk    Equ    1900H
  10. SetDTA        Equ    1A00H
  11. SetCtrlVect    Equ    2523H
  12. GetDate     Equ    2A00H
  13. GetTime     Equ    2C00H
  14. DosVersion    Equ    3000H
  15. GetCtrlState    Equ    3300H
  16. SetCtrlState    Equ    3301H
  17. DiskFree    Equ    3600H
  18. CreateFile    Equ    3C00H
  19. OpenForRead    Equ    3D00H
  20. OpenForWrite    Equ    3D01H
  21. Close        Equ    3E00H
  22. Read        Equ    3F00H
  23. Write        Equ    40H
  24. Delete        Equ    4100H
  25. SetFileAtBeg    Equ    4200H
  26. GetFileLoc    Equ    4201H
  27. GetFileLen    Equ    4202H
  28. IoctlGet    Equ    4400H
  29. IoctlSet    Equ    4401H
  30. ForceDup    Equ    4600H
  31. AllocMemory    Equ    48H
  32. FreeMemory    Equ    49H
  33. SetBlock    Equ    4AH
  34. FindFirst    Equ    4E00H
  35. FindNext    Equ    4F00H
  36. ;
  37. CtrlStateOn    Equ    01H
  38. Hidden        Equ    02H
  39. System        Equ    04H
  40. ;
  41. ExitProg    Equ    4CH
  42. ;
  43. ;    Std Handles
  44. StdInput    Equ    00H
  45. StdOutput    Equ    01H
  46. StdError    Equ    02H
  47. ;
  48. ;    Chars
  49. Space        Equ    20H
  50. Slash        Equ    '/'
  51. CtrlZ        Equ    1AH
  52. LF        Equ    0AH
  53. CR        Equ    0DH
  54. CRLF        Equ    0A0DH
  55. Escp        Equ    1BH
  56. PageUp        Equ    49H
  57. PageDown    Equ    51H
  58. ;
  59. KeyReverse    Equ    0001H
  60. KeyZero     Equ    0002H
  61. KeyASCII    Equ    0004H
  62. KeyPascal    Equ    0008H
  63. KeyInteger    Equ    0010H
  64. KeyUnsigned    Equ    0020H
  65. KeyMicro    Equ    0040H
  66. KeyTurbo    Equ    0080H
  67. KeyFloat    Equ    0100H
  68. ;
  69. KeyDecimal    Equ    0200H
  70. KeyNumDisp    Equ    0400H
  71. ;
  72. Question    Equ    '?'
  73. LengthParm    Equ    ':'
  74. ASCIIParm    Equ    'A'
  75. NoBreakParm    Equ    'B'
  76. ZeroParm    Equ    'C'
  77. DupParm     Equ    'D'
  78. ErrorParm    Equ    'E'
  79. FixedParm    Equ    'F'
  80. FloatParm    Equ    'F'
  81. IntegerParm    Equ    'I'
  82. MicroParm    Equ    'M'
  83. NullParm    Equ    'N'
  84. PascalParm    Equ    'P'
  85. QuietParm    Equ    'Q'
  86. ReverseParm    Equ    'R'
  87. TempParm    Equ    'T'
  88. TurboParm    Equ    'T'
  89. UnsignedParm    Equ    'U'
  90. CtrlZParm    Equ    'Z'
  91. ;
  92. DecimalParm    Equ    'D'
  93. NumDispParm    Equ    'N'
  94. ;
  95. StartColumn    Equ    1111H
  96. RelColumn    Equ    1111H
  97. KeyLength    Equ    1111H
  98. ;
  99. GotBinStrErr    Equ    01H
  100. GotDiffBinErr    Equ    02H
  101. GotNumbNotFErr    Equ    04H
  102. GotOtherErr    Equ    80H
  103. ;
  104. BegSegm     Struc
  105.   Beg        DW    ?
  106.   Segm        DW    ?
  107. BegSegm     Ends
  108. ;
  109. CdeSeg        Segment Para Public 'Code'
  110.         Assume    CS:CdeSeg,DS:CdeSeg,ES:CdeSeg,SS:CdeSeg
  111. ;
  112.         Org    80H
  113. ParmsLen    DB    ?              ;Set up ref to cmd parms.
  114. Parms        DB    127 Dup(?)
  115. ;
  116.         Org    100H           ;Set start addr for COM module.
  117. MainStart:    Jmp    MainRoutine
  118. ;
  119. Version5    DB    0
  120. DefaultSortKey    DB    0
  121. GotQuiet    DB    0
  122. IpDevice    DB    ?
  123. DosStart_Hou    DB    ?           ;Start time Hour
  124. DosStart_Min    DB    ?           ;       Min
  125. DosStart_Sec    DB    ?           ;       Sec
  126. DosStart_Hun    DB    ?           ;       Hundredths
  127. DosEnds_Hou    DB    ?           ;End   time Hour
  128. DosEnds_Min    DB    ?           ;       Min
  129. DosEnds_Sec    DB    ?           ;       Sec
  130. DosEnds_Hun    DB    ?           ;       Hundredths
  131.  
  132.  
  133. TimeMsg     DB 'Processing Took '
  134. TimeMsgHou    DB '00'
  135.         DB ':'
  136. TimeMsgMin    DB '00'
  137.         DB ':'
  138. TimeMsgSec    DB '00'
  139.         DB '.'
  140. TimeMsgHun    DB '00'
  141.         DB CR,LF
  142. TimeMsgLen    EQU $ - TimeMsg
  143. ;
  144. ; Syntax Errors
  145. ;
  146. SlashNullMsg    DB    '001: Slash (/) must be followed by a parameter.$'
  147. BadSwitchMsg    DB    '002: Illegal parameter: $'
  148. SecondTFMsg    DB    '003: Only one /X switch is allowed.$'
  149. PAndCNgMsg    DB    '004: /P and /C are incompatible.$'
  150. BadRcdLenMsg    DB    '005: Record len must be between 1 and 32,750 in: $'
  151. PNotFNGMsg    DB    '006: Pascal string key only allowed in fixed len '
  152.         DB    'record: $'
  153. PMustBeFMsg    DB    '007: /P only allowed for fixed length records.$'
  154. NumbNotFNGMsg    DB    '008: Binary number key (F,I,M,T or U) '
  155.         DB    'only allowed in fixed len record: $'
  156. FixNotAllowMsg    DB    '009: /X switch not allowed for fixed length records.$'
  157. ;BadStartParmMsg DB     '015: Syntax for /S parameter is /S[-]nnn not: $'
  158. ;BigStartParmMsg DB     '016: ASCII code in /S parameter must not exceed 255: $'
  159. BadDriveMsg    DB    '010: One and only one temp drive letter may be entered: $'
  160. NotExistMsg    DB    '011: Non-existent drive: $'
  161. NgDriveMsg    DB    '012: Invalid character for the drive: $'
  162. BadStartMsg    DB    '013: Start column must be between 1 and 32,750: $'
  163. BigStartMsg    DB    '014: Start column must not exceed record len: $'
  164. SecondStartMsg    DB    '015: Only one start column allowed: $'
  165. BadKeyMsg    DB    '016: Error in sort key: $'
  166. BadKeyLenMsg    DB    '017: Key len must be between 1 and 32,750: $'
  167. BigKeyLenMsg    DB    '018: Key len is too big to fit in record: $'
  168. SecondKeyLenMsg DB    '019: Only one key length allowed: $'
  169. NGFloatLenMsg    DB    '020: Length for 80x87 floating point number'
  170.         DB    ' must be 4, 8 or 10: $'
  171. NGMicroLenMsg    DB    '021: Length for GWBASIC/BASICA floating '
  172.         DB    'point number must be 4 or 8: $'
  173. NGTurboLenMsg    DB    '022: Length for Turbo Pascal floating point'
  174.         DB    ' number must be 6: $'
  175. PascalLenNGMsg    DB    '023: Length for Pascal strings must be between 2 and 256:'
  176.         DB    ' $'
  177. PascalDefNGMsg    DB    '024: Length for Pascal strings must be between 2 and 256.$'
  178. PascalZeroNGMsg DB    '025: "P" and "C" attributes are incompatible: $'
  179. SwitchKeyNGMsg    DB    '026: C attribute conflicts with /P: $'
  180. BinaryStringMsg DB    '027: Sort key cannot be both a binary number and a string: $'
  181. DiffBinaryMsg    DB    '028: Only one binary key type allowed in a sort key: $'
  182. SecondIpMsg    DB    '029: Only one list of input files and a single output'
  183.         DB    ' file may be given.',13,10
  184.         DB    '            Found additional file spec: $'
  185. OutputPlusMsg    DB    '030: Multiple files not allowed in output spec: $'
  186. MisplacedMsg    DB    '031: Misplaced plus sign in input file list: $'
  187. FileAndRedirMsg DB    '032: Input is redirected to the standard input, '
  188.         DB    'so output must go to',13,10
  189.         DB    '  the standard output.  The following file spec '
  190.         DB    'is illegal: $'
  191. DeviceMsg    DB    '033: You must specify an input file.$'
  192. NoErrorSpecMsg    DB    '034: No name specified for error file: $'
  193. ;
  194. VersionMsg    DB    '037: RPSORT requires MS DOS version 2.00 or later.$'
  195. ;
  196. ; Memory Problems
  197. ;
  198. NoMemoryMsg    DB    '040: Not enough memory.  RPSORT requires 30,000 bytes.$'
  199. TwoRcdMsg    DB    '041: Not enough memory to hold at least two '
  200.         DB    'records/lines at a time.$'
  201. ;
  202. ; File Doesn't Meet RPSORT Requirements
  203. ;
  204. LinGTMaxMsg    DB    '043: Line exceeds max length of 32750 bytes.$'
  205. PascTooLongMsg    DB    '044: Found Pascal string whose length byte '
  206.         DB    'exceeds specified key length.$'
  207. ;
  208. ; Input/Output Problems
  209. ;
  210. NoDataMsg    DB    '046: No data in input file(s) so nothing to do.$'
  211. NoFileMsg    DB    '047: Input file not found: '
  212. NoFileEnd    Label    Byte
  213. ReadErrorMsg    DB    '048: Error reading input file.$'
  214. FullOutMsg    DB    '049: No room on disk to write sorted output file.$'
  215. FullTempMsg    DB    '050: No room on disk to write temp file.$'
  216. NoTempDirMsg    DB    '051: Unable to create temp file.$'
  217. NoOpDirMsg    DB    '052: Unable to create output file.$'
  218. FullErrDirMsg    DB    '053: Unable to create error file: $'
  219. FullErrMsg    DB    13,10,' ERROR 054: Ran out of space on disk attempting '
  220.         DB    'to write error file.',13,10
  221.         DB    '            Redirecting error messages to the screen.',13,10
  222. FullErrEnd    Label    Byte
  223. ;
  224. ;  Unexpected Errors
  225. ;
  226. AllocMsg    DB    '059: Error allocating memory.  $'
  227. DiskErrorMsg    DB    '060: Unknown error accessing disk.$'
  228. ;
  229. SuccessMsg    DB    13,10,'Sort successfully completed.',13,10
  230. SuccessEnd    Label    Byte
  231. SyntaxMsg    DB    13,10,'Enter the RPSORT command with no parameters to get '
  232.         DB    'a description of the syntax.',13,10
  233. SyntaxFin    Label    Byte
  234. ShortRcdMsg    DB    13,10,'Found short record at end of input file.  Will'
  235.         DB    ' delete it from output file.',13,10
  236. ShortRcdEnd    Label    Byte
  237. MissCRLFMsg    DB    13,10,'Added carriage return and line feed which '
  238.         DB    'was missing for last line in file.',13,10
  239. MissCRLFEnd    Label    Byte
  240. ;
  241. QuitMsg     DB    13,10,'Do you wish to quit RPSORT?  Press "Esc" to quit, any'
  242.         DB    ' other key to continue.',13,10
  243. QuitEnd     Label    Byte
  244. ContinueMsg    DB    'Continuing...',13,10
  245. ContinueEnd    Label    Byte
  246. ;
  247.         Even
  248. XlatTable    DB    0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  249.         DB    16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
  250.         DB    ' !"#$%&',39,'()*+,-./0123456789:;<=>?'
  251.         DB    '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'
  252.         DB    '`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~',127
  253. ForeignChars    DB    'CUEAAAACEEEIIIAAEAAOOOUUYOU$$$$$AIOUNN'
  254.         DB    166,167,'?',169,170,171,172,'!',34,34
  255.     DB 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
  256.     DB 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
  257.     DB 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
  258.     DB 224,'S',226,227,228,229,230,231,232,233,234,235,236,237,238,239
  259.     DB 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  260. ;
  261. IndicatorBits    DB    KeyAscii,255,KeyZero,255,255,81H,255,255
  262.         DB    KeyInteger,255,255,255,KeyMicro,255,255,KeyPascal,255
  263.         DB    KeyReverse,255,KeyTurbo,KeyUnsigned,255,255,255,255,255
  264. ;
  265. MainRoutine    Proc    Near
  266.         Mov    AX,GetTime     ;Get Start Time
  267.         Int    Dos
  268.         Mov    DosStart_Hou,CH
  269.         Mov    DosStart_Min,CL
  270.         Mov    DosStart_Sec,DH
  271.         Mov    DosStart_Hun,DL
  272.         Sti
  273.         Call    DoCopyRight
  274.         Mov    AX,DosVersion
  275.         Int    DOS
  276.         Cmp    AL,2
  277.         Jae    Main2
  278.         Mov    DX,Offset VersionMsg
  279.         Jmp    DisplayExit
  280. Main2:        Cmp    AL,5
  281.         Jb    Main3
  282.         Mov    Version5,0FFH
  283.         Mov    CommandSize,0A00H
  284.         Mov    LeaveCmdSize,2E00H
  285. Main3:        Mov    AX,SetDTA
  286.         Mov    DX,Offset DiskXferArea
  287.         Int    DOS
  288.         Mov    AX,CurrDisk
  289.         Int    DOS
  290.         Add    AL,41H
  291.         Mov    DefaultDisk,AL
  292.         Mov    SI,Offset CompRtnEnd - 1 ;End of code to move.
  293.         Mov    DI,SP
  294.         Sub    DI,512         ;End addr for dest of move.
  295.                      ;Leaves 512 bytes for stack.
  296.         Cmp    DI,SI         ;Jump if stk alloc overlays code
  297.         Ja    ChkStdIP
  298.         Jmp    NoMemory     ;and mem is thus too small.
  299. ChkStdIP:    Mov    AX,IoctlGet
  300.         Mov    BX,StdInput    ;Handle for std ip.
  301.         Int    DOS           ;Ck if ip is a device.
  302.         Mov    IpDevice,DL    ;If no sign, it is a file
  303.         Mov    CX,Offset CompRtnEnd - Offset CompRoutine
  304.         Std
  305.         Rep Movsb
  306.         Inc    DI
  307.         Mov    ModelCodeLoc,DI
  308.         Sub    DI,Offset CompRoutine
  309.         Mov    CompMove,DI
  310. DoGetParms:    Call    GetParms        ;Parse switches and sort keys.
  311.         Cmp    CodePointer,Offset CompRoutine
  312.         Jnz    ChkIfError        ;Chk if sort keys were given.
  313.         Cmp    GotSortKey,0
  314.         Jnz    ChkIfError
  315.         Mov    DefaultSortKey,0FFH
  316.         Call    CreateKey       ;If no keys given, create std key.
  317.         Call    ChkKeyInRcd
  318. ChkIfError:    Cmp    GotError,0
  319.         Jz    MoveStack
  320.         Mov    DX,Offset SyntaxMsg
  321.         Mov    CX,Offset SyntaxFin - Offset SyntaxMsg
  322.         Call    WriteStdError2
  323.         Jmp    ErrorExit
  324. MoveStack:    Mov    DI,CodePointer
  325.         Add    DI,512        ;Allow 512 byte stack after key code.
  326.         And    DI,0FFFEH
  327.         Mov    SP,DI         ;Prev code assures this is avail.
  328.         Call    SetupCtrlBrk
  329.         Call    SetupMemory
  330.         Cmp    InputFileCt,0  ;If zero then no filespecs.
  331.         Jnz    NextSpec2
  332. CallLoadStd:    Call    LoadStd    ;Use std ip.
  333.         Jmp Short DoSetPtrs
  334. NextSpec:    Mov    AL,InputFileCt
  335.         Or    AL,WildCard
  336.         Jz    DoSetPtrs
  337. NextSpec2:    Call    LoadSpec
  338.         Jnc    NextSpec      ;Go back if mem avail.
  339. DoSetPtrs:    Cmp    GotData,0
  340.         Jnz    DoSetPtrs2
  341.         Mov    DX,Offset NoDataMsg
  342.         Jmp    DisplayExit
  343. DoSetPtrs2:    Mov    Byte Ptr FromMain,0FFH
  344.         Call    SetupPointers      ;Create array of ptrs to lines.
  345.         Call    SortData      ;Qsort of ptrs based on keys in lines
  346.         Cmp    FinalOutput,0
  347.         Jz    NotFinal
  348.         Cmp    GotOutput,0
  349.         Jz    DoWriteData
  350.         Call    OpenOutput
  351.         Jmp Short DoWriteData
  352. NotFinal:    Cmp    WriteHandle,StdOutput
  353.         Ja    DoWriteData
  354.         Call    SetupTempFiles
  355. DoWriteData:    Call    WriteData     ;Use ptrs to write lines in seq.
  356.         Cmp    MoreData,0
  357.         Jz    CheckMerge
  358.         Mov Byte Ptr NeedMerge,0FFH
  359.         Call    ReSetupMemory
  360.         Cmp    HaveSpecs,0
  361.         Jz    CallLoadStd
  362.         Jmp    NextSpec2
  363. CheckMerge:    Cmp    NeedMerge,0
  364.         Jz    GoBackOk
  365.         Call    MergeData         ;Mod WriteData code and do merge.
  366. GoBackOk:    Cmp    GotQuiet,0
  367.         Jnz    SetRetZero
  368.         Mov    DX,Offset SuccessMsg
  369.         Mov    CX,Offset SuccessEnd - Offset SuccessMsg
  370.         Call    WriteStdError2
  371. SetRetZero:    Xor    AX,AX        ;Ret code is 0.
  372. GoBack:     Push    AX
  373.         Cmp    ErrorHandle,StdError
  374.         Jz    GoBack2
  375.         Mov    BX,ErrorHandle
  376.         Mov    AX,Close        ;Close error file.
  377.         Int    Dos
  378. Goback2:    Mov    AX,SetCtrlState
  379.         Mov    DL,CtrlState
  380.         Int    Dos
  381.         Call    ComputeTime
  382.         Pop    AX
  383.         Mov    AH,ExitProg
  384.         Int    DOS
  385. MainRoutine    Endp
  386. ;
  387. ComputeTime    Proc    Near           ;Display Elapsed time
  388.         Mov    AX,GetTime     ;Get End   Time
  389.         Int    Dos
  390.         Mov    DosEnds_Hou,CH
  391.         Mov    DosEnds_Min,CL
  392.         Mov    DosEnds_Sec,DH
  393.         Mov    DosEnds_Hun,DL
  394.         Mov    AL,DL
  395.         Mov    AH,100
  396.         Mov    Di,offset TimeMsgHun
  397.         Sub    AL,DosStart_Hun
  398.         Call    Conv_Byte
  399.  
  400.         Mov    AL,DosEnds_Sec
  401.         Mov    AH,60
  402.         Mov    Di,offset TimeMsgSec
  403.         Sbb    AL,DosStart_Sec
  404.         Call    Conv_Byte
  405.  
  406.         Mov    AL,DosEnds_Min
  407.         Mov    AH,60
  408.         Mov    Di,offset TimeMsgMin
  409.         Sbb    AL,DosStart_Min
  410.         Call    Conv_Byte
  411.  
  412.         Mov    AL,DosEnds_Hou
  413.         Mov    AH,24
  414.         Mov    Di,offset TimeMsgHou
  415.         Sbb    AL,DosStart_Hou
  416.         Call    Conv_Byte
  417.         Mov    DX,Offset TimeMsg
  418.         Mov    CX,TimeMsgLen
  419.         Call    WriteStdError2
  420.         Ret
  421.  
  422. ComputeTime    Endp
  423.  
  424. Conv_Byte      proc   near           ;convert binary byte to hex ASCII.
  425.                        ;call with AL = binary value
  426.                        ;      DI = addr to store string
  427.                        ;returns AX, DI, CX modified.
  428.  
  429.            pushf
  430.            cmp    Ah,Al
  431.            Ja     Conv_Byte2
  432.            Xor    Cl,Cl           ;If > max, convert it to max-based
  433.            Sub    Cl,Al           ; 256 - number -> max - number
  434.            Sub    Ah,Cl
  435.            Mov    Al,Ah
  436. Conv_Byte2:    Xor    ah,ah           ;clear upper byte
  437.            mov    cl,10           ;Divide binary data by 10
  438.            div    cl           ;to force to decimal
  439.            call   Ascii           ;the quotient becomes the first
  440.            stosb               ;ASCII character.
  441.            mov    al,ah
  442.            call   Ascii           ;the remainder becomes the second
  443.            stosb               ;ASCII character.
  444.            popf
  445.            ret
  446. Conv_Byte      endp
  447.  
  448. Ascii           proc   near           ;convert value 0-0fFH in AL
  449.            add    al,'0'           ;into a "hex ASCII" character.
  450.            cmp    al,'9'
  451.            jle    Ascii2           ;jump if in range 0-9,
  452.            add    al,'A'-'9'-1     ;offset it to range A-F
  453. Ascii2:        ret               ;return ASCII char in AL.
  454. Ascii           endp
  455.  
  456. DoCopyRight    Proc    Near
  457.         Mov    SI,Offset Parms    ;Ofs of cmd line parms.
  458.         Xor    CX,CX
  459.         Mov    CL,ParmsLen       ;Len of cmd line parms.
  460.         Mov    ParmBegInit,SI
  461.         Mov    ParmCharsInit,CX
  462.         Mov    BX,Offset XlatTable
  463. FindSlashQ:    Jcxz    DispCopyRight
  464.         Dec    CX
  465.         Lodsb
  466.         Cmp    AL,Space
  467.         Jz    FindSlashQ
  468.         Cmp    AL,Slash
  469.         Jnz    DispCopyRight
  470.         Jcxz    DispCopyRight
  471.         Dec    CX
  472.         Lodsb
  473.         Xlat
  474.         Cmp    AL,QuietParm
  475.         Jnz    DispCopyRight
  476.         Mov    GotQuiet,0FFH
  477.         Mov    ParmBegInit,SI
  478.         Mov    ParmCharsInit,CX
  479.         Ret
  480. DispCopyRight:    Mov    DX,Offset CopyRightMsg
  481.         Mov    CX,Offset CopyRightEnd - Offset CopyRightMsg
  482.         Call    WriteStdError2
  483.         Ret
  484. DoCopyRight    Endp
  485. ;
  486. SetupCtrlBrk    Proc    Near
  487.         Mov    AX,GetCtrlState
  488.         Int    DOS
  489.         Mov    CtrlState,DL
  490.         Mov    AX,SetCtrlState
  491.         Mov    DL,CtrlStateOn
  492.         Int    DOS
  493.         Mov    AX,SetCtrlVect
  494.         Mov    DX,Offset CtrlBrkHandler
  495.         Int    DOS
  496.         Cmp    GotOutput,0
  497.         Jz    SetupCtrlRet
  498.         Mov    AX,OpenForWrite
  499.         Mov    DX,Offset NulASCIIZ
  500.         Int    DOS
  501.         Mov    BX,AX
  502.         Mov    CX,StdOutput
  503.         Mov    AX,ForceDup
  504.         Int    DOS
  505. SetupCtrlRet:    Ret
  506. SetupCtrlBrk    Endp
  507. ;
  508. CtrlBrkHandler    Proc    Far
  509.         Push    AX
  510.         Push    BX
  511.         Push    CX
  512.         Push    DX
  513.         Push    SI
  514.         Push    DI
  515.         Push    BP
  516.         Push    DS
  517.         Push    ES
  518.         Push    CS
  519.         Pop    DS
  520.         Cmp    NoBreak,0
  521.         Jnz    DontBreak
  522.         Test    IpDevice,80H
  523.         Jz    DoExit
  524.         Cmp    GotOutput,0
  525.         Jz    DoExit
  526. AskYN:        Mov    DX,Offset QuitMsg
  527.         Mov    CX,Offset QuitEnd - Offset QuitMsg
  528.         Call    WriteStdError2
  529. StdIPIsDevice:    Mov    AX,ClearReadNoEcho
  530.         Int    DOS
  531. ChkEscp:    Cmp    AL,Escp
  532.         Jz    DoExit
  533.         Mov    DX,Offset ContinueMsg
  534.         Mov    CX,Offset ContinueEnd - Offset ContinueMsg
  535.         Call    WriteStdError2
  536. DontBreak:    Cmp    GotOutput,0
  537.         Jnz    DontBreak2
  538.         Mov    AX,GetFileLoc
  539.         Xor    CX,CX
  540.         Mov    DX,CX
  541.         Mov    BX,StdOutput
  542.         Int    DOS
  543.         Jc    DontBreak2
  544.         Mov    CX,DX
  545.         Mov    DX,AX
  546.         Sub    DX,4
  547.         Sbb    CX,0
  548.         Jc    DontBreak2
  549.         Mov    AX,SetFileAtBeg
  550.         Mov    BX,StdOutput
  551.         Int    DOS
  552. DontBreak2:    Clc
  553.         Jmp Short CtrlBrkRet
  554. DoExit:     Call    FinalDeletes
  555.         Stc
  556. CtrlBrkRet:    Pop    ES
  557.         Pop    DS
  558.         Pop    BP
  559.         Pop    DI
  560.         Pop    SI
  561.         Pop    DX
  562.         Pop    CX
  563.         Pop    BX
  564.         Pop    AX
  565.         Ret
  566. CtrlBrkHandler    Endp
  567. ;
  568.         Even
  569. ;
  570. DataArea    Equ    $
  571. ;
  572. Data        BegSegm 64 Dup(<>)      ;Pts to first byte of ip data.
  573. DataEnd     DW    64 Dup(?)      ;Pts after end of ip data.
  574. ;
  575. BlockOfs    DD    64 Dup(?) ;Offset in block on disk to read from next.
  576. BlockPos    DD    64 Dup(?) ;Offset in file on disk of block.
  577. BlockLen    DD    64 Dup(?) ;Length of block on disk.
  578. ;
  579. Pointer     BegSegm 16 Dup(<>)
  580. PointerEnd    DW    16 Dup(?)      ;Pts to byte after end of ptrs.
  581. ;
  582. TopIndex    DW    64 Dup(?)
  583. ;
  584. WriteBuff    BegSegm <>
  585. MemoryBegSeg    DW    ? ;Beg of avail mem.
  586. MemoryEndSeg    DW    ? ;End of avail mem.
  587. BelowLow    DW    ? ;3/4 of avail memory para below
  588. BelowHi     DW    ? ;the location of transient COMMAND.COM.
  589. BegSeg        DW    ?
  590. BegOfs        DW    ?
  591. NextSeg     DW    ? ;Next avail seg addr.
  592. NextOfs     DW    ?
  593. LastSeg     DW    ?
  594. PtrSeg        DW    ?
  595. PtrOfs        DW    ?
  596. FileSizeLo    DW    ?
  597. FileSizeHi    DW    ?
  598. MemParaAvail    DW    ?
  599. MaxSegCount    DW    ?
  600. MaxSegSize    DW    ?
  601. Handle        DW    ?
  602. UseHandle    DW    ?
  603. ExtraEnd    DD    ?
  604. MaxSegs     DW    ?
  605. BegBlock    DW    ?    ;Block that goes into first mem seg this time.
  606. EndBlock    DW    ?    ;Block that goes into last mem seg this time.
  607. BlockSeg    DW    ?    ;Segment for table of block locations.
  608. NewBlockCt    DW    ?    ;BlockCt to be used in next phase of merge.
  609. NewBlockSeg    DW    ?    ;Segment for new table of block locations.
  610. NewBlockBeg    DW    ?    ;First entry in new table of block locations.
  611. NewBlockEnd    DW    ?    ;Next  entry in new table of block locations.
  612. RemainderSegs    DW    ?
  613. ExtraHandle    DW    ?
  614. IpNamePtr    DW    ?
  615. ;
  616. TempName1    DB    15 Dup(?)
  617. TempName2    DB    15 Dup(?)
  618. TempName3    DB    15 Dup(?)
  619. ;
  620. DiskXferArea    DB    21 Dup(?)
  621. IpAttr        DB    ?
  622. IpTime        DW    ?
  623. IpData        DW    ?
  624. IpSize        DD    ?
  625. IpNameExt    DB    13 Dup(?)
  626. IpASCIIZ    DB    128 Dup(?)
  627. ;
  628.         Org    DataArea
  629. ;
  630. CopyRightMsg    DB    13,10,'RPSORT v1.02  Dec. 15, 1992,'
  631.         DB    ' Copyright 1991 by Bob Pirko,'
  632.         DB    ' All rights reserved',13,10
  633. CopyRightEnd    Label    Byte
  634. ;
  635. Syntax        DB    13,10,'Usage: RPSORT [/Q] [/Eerrfile] [/]? [in'  ;01
  636.         DB          'putfile[+inputfile]] [outputfile] [/A]'
  637.         DB    13,10,'          [/B] [/C] [/D] [/Fnnnn] [/N] '  ;02
  638.         DB          '[/P] [/R] [/Td] [/Z] [sort key defin...]',13,10
  639.         DB    13,10,'Sort key defin syntax:  /+ [col] [:len]'  ;04
  640.         DB          ' [A] [C] [F] [I] [M] [P] [R] [T] [U]'
  641.         DB    13,10,'---------------------------------------'  ;05
  642.         DB          '----------------------------------------'
  643. SyntaxEnd    Label Byte
  644. ;
  645. LastLine    DB    13,10,'   (Press PageUp or'
  646. LastLine2    DB          ' PageDown'
  647. LastLine3    DB          ' to see other syntax screens or Esc to exit)'
  648. LastLineEnd    Label Byte
  649. ;
  650. Syntax1Screen    DB    13,10,'RPSORT greatly improves upon the featur'   ;06
  651.         DB          'es and the performance of the sort'
  652.         DB    13,10,'utility distributed with Microsoft DOS.'   ;07
  653.         DB          '  First, RPSORT does everything that'
  654.         DB    13,10,'the DOS SORT does.  Virtually any comma'   ;08
  655.         DB          'nd that works with the DOS SORT will'
  656.         DB    13,10,'work with RPSORT and produce the same r'   ;09
  657.         DB          'esult.',13,10
  658.         DB    13,10,'But RPSORT does much more.  It can sort'   ;11
  659.         DB          ' very large files and supports multiple'
  660.         DB    13,10,'sort keys.  It is extremely fast.  I kn'   ;12
  661.         DB          'ow of no sort utility that outspeeds it.',13,10
  662.         DB    13,10,'RPSORT sorts text files.  These consist'   ;14
  663.         DB          ' of lines each ended by CRLF (i.e. a'
  664.         DB    13,10,'carriage return and a line feed).  It a'   ;15
  665.         DB          'lso sorts files of fixed length records'
  666.         DB    13,10,'such as those produced by many BASIC, P'   ;16
  667.         DB          'ascal and C language programs.',13,10
  668.         DB    13,10,'RPSORT supports numerous sort key types'   ;18
  669.         DB          ' including regular text keys, C language'
  670.         DB    13,10,'strings, Turbo Pascal strings, signed a'   ;19
  671.         DB          'nd unsigned binary integers of any'
  672.         DB    13,10,'length and several types of binary floa'   ;20
  673.         DB          'ting point numbers.',13,10
  674.         DB    13,10,'RPSORT can delete null lines (consistin'   ;22
  675.         DB          'g only of CRLF).  It can also delete'
  676.         DB    13,10,'records/lines whose sort keys duplicate'   ;23
  677.         DB          ' those in a previous record/line.',13,10
  678.         DB    13,10,'   (Press '                                ;25
  679. Syntax1End    Label Byte
  680. ;
  681. Syntax2Screen    DB    13,10,'Parameters may be entered in any order '   ;06
  682.         DB          'except as noted below.',13,10
  683.         DB    13,10,'RPSORT may be run as a filter using red'   ;08
  684.         DB          'irection.',13,10
  685.         DB    13,10,'  For example:    RPSORT   <ipfile   >opfile';10
  686.         DB    13,10,'           or:    DIR | RPSORT | MORE',13,10 ;11
  687.         DB    13,10,'Input and output may be specified direc'   ;13
  688.         DB          'tly.  Input is one or more filespecs'
  689.         DB    13,10,'separated by plus signs.  Output must b'   ;14
  690.         DB          'e a single file.  Input filespec(s) must'
  691.         DB    13,10,'precede output filespec.  Filespecs may'   ;15
  692.         DB          ' include a path.  Wildcard characters'
  693.         DB    13,10,'are allowed.  Input files are sorted to'   ;16
  694.         DB          'gether into the single output file.',13,10
  695.         DB    13,10,'  For example:    RPSORT ipfile*.txt+c'   ;18
  696.         DB          ':\mydir\ip??file.txt   opfile',13,10
  697.         DB    13,10,'By default, RPSORT assumes the input is'   ;20
  698.         DB          ' a text file and that the entire line is'
  699.         DB    13,10,'the sort key.  The sort is case insensi'   ;21
  700.         DB          'tive (lower equals upper case) and just'
  701.         DB    13,10,'like the DOS SORT it equates foreign le'   ;22
  702.         DB          'tters, punctuation, and currency symbols'
  703.         DB    13,10,'to their English equivalents.  The foll'   ;23
  704.         DB          'owing screens describe other options.',13,10
  705. Syntax2End    Label Byte
  706. ;
  707. Syntax3Screen    DB    13,10,'/Q if it is the first parameter suppres'   ;06
  708.         DB          'ses copyright and success messages.'
  709.         DB    13,10,'/Eerrfile directs error messages to a f'   ;07
  710.         DB          'ile.  Should precede all but /Q.'
  711.         DB    13,10,'/? or ? produces these syntax screens. '   ;08
  712.         DB          ' RPSORT with no parameters also does.'
  713.         DB    13,10,'/A does an ASCII sort.  This is case se'   ;09
  714.         DB          'nsitive (lower not equal upper case).'
  715.         DB    13,10,'/B tells RPSORT to ignore any control b'   ;10
  716.         DB          'reak entered from the keyboard.'
  717.         DB    13,10,'/C says that text keys are terminated b'   ;11
  718.         DB          'y a binary zero (C language strings).'
  719.         DB    13,10,'/D deletes any record whose sortkeys du'   ;12
  720.         DB          'plicate those in a previous record.'
  721.         DB    13,10,'/Fnnnn says that the input consists of '   ;13
  722.         DB          'fixed length records of nnnn bytes.'
  723.         DB    13,10,'/N deletes any null lines (those consis'   ;14
  724.         DB          'ting only of a CRLF sequence).'
  725.         DB    13,10,'/P uses the first byte of text keys as '   ;15
  726.         DB          'the key length (Turbo Pascal strings).'
  727.         DB    13,10,'/R specifies a reverse (descending orde'   ;16
  728.         DB          'r) sort.'
  729.         DB    13,10,'/Td designates drive to be used for tem'   ;17
  730.         DB          'p files instead of default drive.'
  731.         DB    13,10,'/Z says to ignore any Ctrl-Z in a text '   ;18
  732.         DB          'file and use the entire file.  Normally'
  733.         DB    13,10,'   RPSORT (just like MS-DOS) treats Ctr'   ;19
  734.         DB          'l-Z as the end of a text file.',13,10
  735.         DB    13,10,'/R applies to all sort key definitions '   ;21
  736.         DB          'while /A, /C and /P apply to all text'
  737.         DB    13,10,"sort keys.  Sort key definitions can't "   ;22
  738.         DB          'over-ride them.  To sort some keys one'
  739.         DB    13,10,'way and some another way, use the sort '   ;23
  740.         DB          'key attributes on the next screen.',13,10
  741. Syntax3End    Label Byte
  742. ;
  743. Syntax4Screen    DB    13,10,'A sort key definition has the above for'   ;06
  744.         DB          'm with no spaces between the attributes.',13,10
  745.         DB    13,10,'  col  is starting column of this key. '   ;08
  746.         DB          ' Col 1 is the first col in the record.'
  747.         DB    13,10,'  len  is the length of this key.'         ;09
  748.         DB    13,10,'  A    does an ASCII (case sensitive) s'   ;10
  749.         DB          'ort for the key.'
  750.         DB    13,10,'  C    treats a binary zero as the end '   ;11
  751.         DB          'of the key (i.e. a C type string).'
  752.         DB    13,10,'       Len should equal max C string le'   ;12
  753.         DB          'ngth (e.g. if "char mystr[8]", len = 8).'
  754.         DB    13,10,'  F    sorts this key as 80x87 binary f'   ;13
  755.         DB          'loating point number. Len is 4, 8 or 10.'
  756.         DB    13,10,'  I    sorts this key as a signed binar'   ;14
  757.         DB          'y integer.  This may be any length.'
  758.         DB    13,10,'  M    sorts this key as a binary float'   ;15
  759.         DB          'ing point number defined by BASICA,'
  760.         DB    13,10,'       GWBASIC or older versions of Mic'   ;16
  761.         DB          'rosoft QuickBASIC.  Len is 4 or 8.'
  762.         DB    13,10,'  P    uses the first byte of this key '   ;17
  763.         DB          'as the key length (a Pascal string).'
  764.         DB    13,10,'       Len must equal max Pascal string'   ;18
  765.         DB          ' length + 1 (e.g. if string[8] len = 9).'
  766.         DB    13,10,'  R    does a reverse (descending) sort'   ;19
  767.         DB          ' for this key.'
  768.         DB    13,10,'  T    sorts this key as a Turbo Pascal'   ;20
  769.         DB          ' number of type "real".  Len must be 6.'
  770.         DB    13,10,'  U    sorts this key as an unsigned bi'   ;21
  771.         DB          'nary integer.  This may be any length.',13,10
  772.         DB    13,10,'Attributes F, I, M, P, T and U are only'   ;23
  773.         DB          ' allowed for fixed length records.',13,10
  774. Syntax4End    Label Byte
  775. ;
  776. Syntax5Screen    DB    13,10,'1. RPSORT as a filter.  Input is a text'   ;06
  777.         DB          ' file.  Sort key is the entire line.',13,10
  778.         DB    13,10,'      RPSORT   <DATAINP.DAT   >SORT.DAT'   ;08
  779.         DB          13,10
  780.         DB    13,10,'2. Combine two files.  Do an ASCII (cas'   ;10
  781.         DB          'e sensitive) sort.  Write the output to'
  782.         DB    13,10,'   SORT.DAT.  Put temp files on the C d'   ;11
  783.         DB          'rive.  Key is 5 bytes at column 4.',13,10
  784.         DB    13,10,'      RPSORT   DATA1.DAT+C:\MYDIR\DATA2'   ;13
  785.         DB          '.DAT  SORT.DAT  /TC /A /+4:5',13,10
  786.         DB    13,10,'3. Sort a file of 90 byte records.  The'   ;15
  787.         DB          ' first key is a Turbo Pascal real number'
  788.         DB    13,10,'   at column 15.  The second key is a T'   ;16
  789.         DB          'urbo Pascal string of type string[11].',13,10
  790.         DB    13,10,'      RPSORT  PASFILE.DAT  SORTFILE.DA'    ;18
  791.         DB          'T  /F90 /+15:6T /+1:12P',13,10
  792.         DB    13,10,'4. Sort a file of 70 byte records.  Bot'   ;20
  793.         DB          'h keys are C type strings.  The first'
  794.         DB    13,10,'   key is ASCII (case sensitive) the se'   ;21
  795.         DB          'cond is case insensitive by default.',13,10
  796.         DB    13,10,'      RPSORT  CFILE.DAT  SORT.DAT  /F70'   ;23
  797.         DB          ' /C  /+5:10A /+23:7',13,10
  798.         DB    13,10,'   (Press PageUp'                          ;25
  799. Syntax5End    Label Byte
  800. ;
  801. Syntax1List    DW    Syntax,SyntaxEnd-Syntax
  802.         DW    Syntax1Screen,Syntax1End-Syntax1Screen
  803.         DW    LastLine2,LastLineEnd-LastLine2
  804. Syntax2List    DW    Syntax,SyntaxEnd-Syntax
  805.         DW    Syntax2Screen,Syntax2End-Syntax2Screen
  806.         DW    LastLine,LastLineEnd-LastLine
  807. Syntax3List    DW    Syntax,SyntaxEnd-Syntax
  808.         DW    Syntax3Screen,Syntax3End-Syntax3Screen
  809.         DW    LastLine,LastLineEnd-LastLine
  810. Syntax4List    DW    Syntax,SyntaxEnd-Syntax
  811.         DW    Syntax4Screen,Syntax4End-Syntax4Screen
  812.         DW    LastLine,LastLineEnd-LastLine
  813. Syntax5List    DW    Syntax,SyntaxEnd-Syntax
  814.         DW    Syntax5Screen,Syntax5End-Syntax5Screen
  815.         DW    LastLine3,LastLineEnd-LastLine3
  816. SyntaxLastList    Label Word
  817. SyntaxPtrs    DW    Syntax1List,Syntax2List,Syntax3List,Syntax4List
  818.         DW    Syntax5List,SyntaxLastList
  819. SyntaxScrNo    DW    0
  820. ;
  821.         Even
  822. ;
  823. ParmBeg     DW    ?
  824. ParmChars    DW    ?
  825. ParmBegInit    DW    ?
  826. ParmCharsInit    DW    ?
  827. CodePointer    DW    CompRoutine
  828. ModelCodeLoc    DW    ?
  829. CompMove    DW    ?
  830. FixedLen    DW    0
  831. LongestLen    DW    0
  832. MaxAllowLen    DW    32750
  833. KeyTypInit    DW    0
  834. KeyTyp        DW    0
  835. StartCol    DW    0
  836. RelCol        DW    0
  837. KeyLen        DW    0
  838. PrevEndCol    DW    0
  839. LenBuckSize    DW    2
  840. WriteHandle    DW    StdOutput
  841. OutputHandle    DW    StdOutput
  842. ReadHandle    DW    StdInput
  843. ErrorHandle    DW    StdError
  844. TempHandle1    DW    0
  845. TempHandle2    DW    0
  846. TempHandle3    DW    0
  847. ExtraNumb    DW    0
  848. HowManySegs    DW    0
  849. ThisTimeSegs    DW    0
  850. LineEnd     DW    CRLF
  851. NewLine     DW    CRLF
  852. DataMax     DW    65520
  853. DataPara    DW    0FFFH
  854. SegCount    DW    0          ;SegCount = (seg ct) * 2.
  855. SegNumb     DW    0          ;Segment info ptr.
  856. MaxPara     DW    23FEH  ;This is 144K. Allows loading full 64K of data.
  857. MinPara     DW    0C00H  ;Require 48K (or 1/3 total mem) to load data.
  858. MinBuff     DW    0400H  ;Reserve 16K (or 1/9 total mem) for write buff.
  859. MergeBuff    DW    0800H  ;Reserve 32K for writebuff during merge.
  860. MergeSeg    DW    0400H  ;Let minimum merge segment be 16K.
  861. BlockCt     DW    0    ;Count of entries in table of block locations.
  862. BlockBeg    DW    0008H    ;First entry in table of block locations.
  863. BlockEnd    DW    0008H    ;Next  entry in table of block locations.
  864. PointerMax    DW    65520          ;Max val for ptr end.
  865. WriteBuffEnd    DW    65535          ;Max space for write buff.
  866. PrevAddr    Label    DWord
  867. PrevOfs     DW    0FFFFH
  868. PrevSeg     DW    0
  869. PrevBuffOfs    DW    0FFFFH
  870. InputAddr    DW    ?
  871. InputEnd    DW    ?
  872. ErrorAddr    DW    ?
  873. OutputAddr    DW    ?
  874. OutputEnd    DW    ?
  875. StackHigh    DW    ?
  876. All1Start    DW    ?
  877. SecondStart    DW    ?
  878. Fix1Start    DW    ?
  879. Line1Start    DW    ?
  880. CompFinish    DW    ?
  881. OrigStart    DW    ?
  882. FixPlus2    DW    ?
  883. ParmOfs     DW    ?           ;Pts to next byte of cmd line parms.
  884. ParmBytes    DW    ?          ;Ct of remain cmd line bytes.
  885. RetFromErrSP    DW    ?
  886. ReservedForPtrs DW    0
  887. CommandSize    DW    0600H
  888. LeaveCmdSize    DW    2A00H
  889. ;
  890. ERRORWord    DB    ' ERROR '
  891. DidErrorWord    DB    0
  892. Quote        DB    '"'
  893. TwelveSpaces    DB    13,10,12 Dup(' ')
  894. GotParms    DB    0
  895. GotSortKey    DB    0
  896. GotInput    DB    0
  897. GotOutput    DB    0
  898. FromMain    DB    0
  899. MoreData    DB    0
  900. NeedMerge    DB    0
  901. FinalOutput    DB    0FFH
  902. OpenedOutput    DB    0
  903. HaveSpecs    DB    0
  904. EndData     DB    0
  905. InputFileCt    DB    0
  906. WildCard    DB    0
  907. TotalFileCt    DB    1
  908. DefaultDisk    DB    0
  909. TempDisk    DB    0
  910. UseRcdLen    DB    0
  911. GotCtrlZ    DB    0
  912. PrtCtrlZ    DB    1AH
  913. SkipSetupTop    DB    0
  914. IgnoreCtrlZ    DB    0
  915. FirstExtra    DB    0FFH
  916. FirstMerge    DB    0FFH
  917. UseExtra    DB    0
  918. LastIsExtra    DB    0
  919. MustSetPtrs    DB    0
  920. ElimDup     DB    0
  921. ElimNull    DB    0
  922. NoBreak     DB    0
  923. ParmPass    DB    0
  924. GotData     DB    0
  925. GotStringParm    DB    ?
  926. GotBinaryParm    DB    ?
  927. GotCParm    DB    ?
  928. GotPParm    DB    ?
  929. GotEParm    DB    ?
  930. CtrlState    DB    ?
  931. GotError    DB    0
  932. KeyCount    DB    0
  933. GotKeyErr    DB    0
  934. ErrorCode    DB    0
  935. PtrsAgain    DB    0
  936. NulASCIIZ    DB    'NUL',0
  937. ;
  938. GetParmsFin    Proc    Near
  939.         Cmp    ParmPass,2
  940.         Jb    GetParms
  941.         Cmp    GotParms,0
  942.         Jnz    GetParmsRet
  943.         Mov    AX,IoctlGet
  944.         Mov    BX,StdInput   ;Handle for std ip.
  945.         Int    DOS          ;Ck if ip is a device.
  946.         Or    DL,DL          ;If no sign, it is a file
  947.         Jns    GetParmsRet   ;else it is a device.
  948.         Jmp    HelpScreen
  949. GetParmsRet:    Ret
  950. ;
  951. GetParmsFin    Endp
  952. ;
  953. DoDisplayError: Call    DisplayError
  954.         Jmp Short RestorePtr
  955. DoDispErrParm:    Call    DispErrorParm
  956. RestorePtr:    Mov    SP,RetFromErrSP
  957.         Mov    CX,ParmChars
  958.         Mov    SI,ParmBeg
  959.         Dec    CX
  960.         Inc    SI
  961. SkipParm:    Jcxz    NextParmChar
  962.         Lodsb
  963.         Dec    CX
  964.         Cmp    AL,Space
  965.         Jz    NextParmChar
  966.         Cmp    AL,Slash
  967.         Jnz    SkipParm
  968.         Dec    SI
  969.         Inc    CX
  970.         Jmp Short NextParmChar
  971. ;
  972. GetParms    Proc    Near
  973.         Cld
  974.         Mov    RetFromErrSP,SP
  975.         Inc    ParmPass
  976.         Mov    SI,ParmBegInit       ;Ofs of cmd line parms.
  977.         Mov    CX,ParmCharsInit   ;Len of cmd line parms.
  978.         Mov    BX,Offset XlatTable
  979. NextParmChar:    Jcxz    GetParmsFin       ;No more parms if CX = 0.
  980.         Mov    ParmBeg,SI
  981.         Mov    ParmChars,CX
  982.         Lodsb
  983.         Dec    CX
  984.         Cmp    AL,Space
  985.         Jz    NextParmChar
  986.         Cmp    AL,Question
  987.         Jnz    IsItSlash
  988.         Jmp    HelpScreen
  989. IsItSlash:    Cmp    AL,Slash
  990.         Jz    GotSlash
  991.         Cmp    ParmPass,1
  992.         Jz    DoFileName
  993.         Jmp    SkipParm
  994. DoFileName:    Mov    GotParms,0FFH
  995.         Call    SaveFileAddr
  996.         Jmp    NextParmChar
  997. GotSlash:    Jcxz    ErrSlashNull    ;/ must be followed by something.
  998.         Dec    CX
  999.         Lodsb            ;Load char following /.
  1000.         Cmp    AL,Question
  1001.         Jnz    GotParm
  1002.         Jmp    HelpScreen
  1003. ErrSlashNull:    Mov    DX,Offset SlashNullMsg
  1004.         Jmp    DoDisplayError
  1005. GotParm:    Mov    GotParms,0FFH
  1006.         Cmp    AL,Space
  1007.         Jz    ErrSlashNull
  1008.         Cmp    AL,Slash
  1009.         Jnz    IsItSortKey
  1010.         Inc    CX
  1011.         Dec    SI
  1012.         Jmp    ErrSlashNull
  1013. IsItSortKey:    Cmp    AL,'+'          ;Is it sort key spec.
  1014.         Jz    DoSortKey    ;If "+" then must be sort key.
  1015.         Cmp    AL,'0'          ;If number then
  1016.         Jb    MustBeSwitch    ;must be
  1017.         Cmp    AL,':'          ;sortkey.
  1018.         Ja    MustBeSwitch
  1019.         Inc    CX
  1020.         Dec    SI
  1021. DoSortKey:    Cmp    ParmPass,2
  1022.         Jz    DoGetSortKey
  1023.         Jmp    SkipParm
  1024. DoGetSortKey:    Call    GetSortKey
  1025.         Jmp    NextParmChar
  1026. MustBeSwitch:    Cmp    ParmPass,1
  1027.         Jz    DoSwitch
  1028.         Jmp    SkipParm
  1029. DoSwitch:    Xlat            ;Lower case to upper case.
  1030.         Mov    DX,AX
  1031.         Call    GetIndicBit      ;Chk for valid parm.
  1032.         Js    IsItFixed         ;Jump if not.
  1033.         Cmp    AX,KeyPascal
  1034.         Ja    IsItFixed    ;Jump if not valid global parm.
  1035.         Or    KeyTypInit,AX     ;Set global switch bit.
  1036.         Jmp Short CheckExtraChar
  1037. ErrBadRcdLen:    Mov    FixedLen,32750
  1038.         Mov    DX,Offset BadRcdLenMsg
  1039.         Jmp    DoDispErrParm
  1040. IsItFixed:    Mov    AX,DX
  1041.         Cmp    AL,FixedParm
  1042.         Jnz    ChkIfIgnCtrlZ
  1043.         Cmp    FixedLen,0
  1044.         Jz    TestFixedLen
  1045.         Mov    AX,3446H        ;Error 004: second /F.
  1046.         Jmp Short Second
  1047. TestFixedLen:    Jcxz    ErrBadRcdLen
  1048.         Dec    CX
  1049.         Lodsb
  1050.         Call    GetNumb
  1051.         Cmp    DX,32750
  1052.         Ja    ErrBadRcdLen
  1053.         Or    DX,DX
  1054.         Jz    ErrBadRcdLen
  1055.         Mov    FixedLen,DX
  1056.         Call    AnyExtraChar
  1057.         Mov    LongestLen,DX
  1058.         Inc    DX
  1059.         Inc    DX
  1060.         Mov    FixPlus2,DX
  1061.         Mov    LenBuckSize,0
  1062.         Jmp    NextParmChar
  1063. ChkIfIgnCtrlZ:    Cmp    AL,CtrlZParm
  1064.         Jnz    ChkIfElimDup
  1065.         Mov    IgnoreCtrlZ,0FFH
  1066. CheckExtraChar: Call    AnyExtraChar
  1067.         Jmp    NextParmChar
  1068. ChkIfElimDup:    Cmp    AL,DupParm
  1069.         Jnz    ChkIfNoBreak
  1070.         Mov    ElimDup,0FFH
  1071.         Jmp    CheckExtraChar
  1072. ChkIfNoBreak:    Cmp    AL,NoBreakParm
  1073.         Jnz    ChkIfElimNull
  1074.         Mov    NoBreak,0FFH
  1075.         Jmp    CheckExtraChar
  1076. ChkIfElimNull:    Cmp    AL,NullParm
  1077.         Jnz    ChkIfErrFile
  1078.         Mov    ElimNull,0FFH
  1079.         Jmp    CheckExtraChar
  1080. ChkIfErrFile:    Cmp    AL,ErrorParm
  1081.         Jnz    ChkIfTemp
  1082.         Call    CheckErrorFile
  1083.         Jmp    NextParmChar
  1084. ChkIfTemp:    Call    IsItTemp
  1085.         Jnz    BadSwitch
  1086.         Jmp    CheckExtraChar
  1087. BadSwitch:    Mov    DX,Offset BadSwitchMsg
  1088.         Jmp    DoDispErrParm
  1089. Second:     Mov    SecondTFMsg+15,AL
  1090.         Mov    SecondTFMsg+2,AH
  1091.         Mov    DX,Offset SecondTFMsg
  1092.         Jmp    DoDisplayError
  1093. GetParms    Endp
  1094. ;
  1095. AnyExtraChar    Proc    Near
  1096.         Jcxz    AnyExtraRet
  1097.         Cmp    Byte Ptr [SI],Slash
  1098.         Jz    AnyExtraRet
  1099.         Cmp    Byte Ptr [SI],Space
  1100.         Jz    AnyExtraRet
  1101. ExtraChar:    Jmp    BadSwitch
  1102. AnyExtraRet:    Ret
  1103. AnyExtraChar    Endp
  1104. ;
  1105. CheckErrorFile    Proc    Near
  1106.         Cmp    GotEParm,0
  1107.         Jz    CheckErrFile2
  1108.         Mov    AX,3745H        ;Error 007: second /E.
  1109.         Jmp    Second
  1110. CheckErrFile2:    Mov    GotEParm,0FFH
  1111.         Jcxz    NoErrorSpec
  1112.         Mov    ErrorAddr,SI        ;Offset of error file name
  1113.         Dec    CX
  1114.         Lodsb
  1115.         Cmp    AL,Space
  1116.         Jz    NoErrorSpec
  1117.         Cmp    AL,Slash
  1118.         Jz    NoErrorSpec
  1119. NewError:    Jcxz    GotErrorName
  1120.         Lodsb
  1121.         Dec    CX
  1122.         Cmp    AL,Space
  1123.         Jz    DecErrorPtr
  1124.         Cmp    AL,Slash
  1125.         Jnz    NewError
  1126. DecErrorPtr:    Dec    SI
  1127.         Inc    CX
  1128. GotErrorName:    Mov    AL,0
  1129.         Xchg    AL,[SI]
  1130.         Push    AX
  1131.         Push    SI
  1132.         Push    CX
  1133.         Mov    AX,CreateFile
  1134.         Mov    DX,ErrorAddr
  1135.         Xor    CX,CX
  1136.         Int    DOS
  1137.         Jc    FullErrDir
  1138.         Mov    ErrorHandle,AX
  1139.         Pop    CX
  1140.         Pop    SI
  1141.         Pop    AX
  1142.         Xchg    AL,[SI]
  1143.         Ret
  1144. NoErrorSpec:    Mov    DX,Offset NoErrorSpecMsg
  1145.         Jmp    DoDispErrParm
  1146. FullErrDir:    Pop    CX
  1147.         Pop    SI
  1148.         Pop    AX
  1149.         Xchg    AL,[SI]
  1150.         Mov    DX,Offset FullErrDirMsg
  1151.         Jmp    DoDispErrParm
  1152. CheckErrorFile    Endp
  1153. ;
  1154. HelpScreen    Proc    Near
  1155.         Mov    SyntaxScrNo,0
  1156.         Mov    DI,Offset Syntax1List
  1157.         Mov    SI,Offset Syntax2List
  1158.         Call    PrintScreen2
  1159. HelpScreen1:    Mov    AX,ClearReadNoEcho
  1160.         Int    DOS
  1161. HelpScreen2:    Or    AL,AL
  1162.         Jz    GetExtended
  1163.         Cmp    AL,Escp
  1164.         Jz    NoMoreScreens
  1165. ReadAnother:    Mov    AX,ReadNoEcho
  1166.         Int    DOS
  1167.         Jmp    HelpScreen2
  1168. GetExtended:    Mov    AX,ReadNoEcho
  1169.         Int    DOS
  1170.         Cmp    AL,PageUp
  1171.         Jz    DoPageUp
  1172.         Cmp    AL,PageDown
  1173.         Jnz    ReadAnother
  1174. DoPageDown:    Mov    DI,SyntaxScrNo
  1175.         Cmp    DI,4
  1176.         Je    ReadAnother
  1177.         Inc    SyntaxScrNo
  1178.         Jmp Short DispScreen
  1179. DoPageUp:    Mov    DI,SyntaxScrNo
  1180.         Cmp    DI,0
  1181.         Je    ReadAnother
  1182.         Dec    SyntaxScrNo
  1183. DispScreen:    Call    PrintScreen
  1184.         Jmp    HelpScreen1
  1185. NoMoreScreens:    Xor    AL,AL
  1186.         Jmp    GoBack
  1187. HelpScreen    Endp
  1188. ;
  1189. PrintScreen    Proc    Near
  1190.         Mov    DI,SyntaxScrNo
  1191.         Shl    DI,1
  1192.         Add    DI,Offset SyntaxPtrs
  1193.         Lea    SI,[DI+2]
  1194.         Mov    DI,[DI]
  1195.         Mov    SI,[SI]
  1196. PrintScreen2:    Mov    DX,[DI]
  1197.         Mov    CX,[DI+2]
  1198.         Call    WriteStdError2
  1199.         Add    DI,4
  1200.         Cmp    DI,SI
  1201.         Jb    PrintScreen2
  1202.         Ret
  1203. PrintScreen    Endp
  1204. ;
  1205. IsItTemp    Proc    Near
  1206.         Cmp    AL,TempParm
  1207.         Jnz    IsItTempRet
  1208.         Cmp    TempDisk,0
  1209.         Jz    IsItTemp2
  1210.         Mov    AX,3654H        ;Error 006: second /T.
  1211.         Jmp    Second
  1212. IsItTemp2:    Mov    AX,SelectDisk
  1213.         Mov    DL,DefaultDisk
  1214.         Sub    DL,41H
  1215.         Int    DOS
  1216.         Add    AL,40H
  1217.         Mov    DL,AL        ;Max drive letter.
  1218.         Xor    DH,DH        ;Count of drives
  1219. NextTempDrive:    Jcxz    CheckTempCt
  1220.         Lodsb
  1221.         Dec    CX
  1222.         Xlat
  1223.         Cmp    AL,Space
  1224.         Je    CheckTempCt
  1225.         Cmp    AL,Slash
  1226.         Jz    CheckTempCT
  1227.         Cmp    AL,'A'
  1228.         Jb    BadDriveLett
  1229.         Cmp    AL,'Z'
  1230.         Ja    BadDriveLett
  1231.         Cmp    AL,DL
  1232.         Ja    NotExistDrive
  1233.         Inc    DH
  1234.         Mov    TempDisk,AL
  1235.         Jmp    NextTempDrive
  1236. CheckTempCT:    Dec    DH
  1237.         Js    BadDriveLett2
  1238.         Jnz    BadDriveLett2
  1239.         Jcxz    IsItTempOK
  1240.         Inc    CX
  1241.         Dec    SI
  1242. IsItTempOK:    Xor    DX,DX
  1243. IsItTempRet:    Ret
  1244. BadDriveLett:    Mov    DX,Offset NgDriveMsg
  1245.         Jmp    DoDispErrParm
  1246. BadDriveLett2:    Mov    DX,Offset BadDriveMsg
  1247.         Jmp    DoDispErrParm
  1248. NotExistDrive:    Mov    DX,Offset NotExistMsg
  1249.         Jmp    DoDispErrParm
  1250. IsItTemp    Endp
  1251. ;
  1252. GetIndicBit    Proc    Near
  1253.         Cmp    AL,'A'
  1254.         Jb    MakeFFFF
  1255.         Cmp    AL,'Z'
  1256.         Ja    MakeFFFF
  1257.         Push    BX
  1258.         Mov    BX,Offset IndicatorBits - 'A'
  1259.         Xlat            ;Get indicator bit.
  1260.         Pop    BX
  1261.         Cmp    AL,255
  1262.         Jz    MakeFFFF
  1263.         Mov    AH,0
  1264.         Cmp    AL,81H
  1265.         Jb    WhatKind
  1266.         Sub    AL,80H
  1267.         Xchg    AL,AH
  1268. WhatKind:    Cmp    AX,KeyReverse
  1269.         Jz    GetIndicRet
  1270.         Cmp    AX,KeyPascal
  1271.         Ja    IsItNumbIndic
  1272.         Mov    GotStringParm,0FFH
  1273.         Jnz    GetIndicRet
  1274.         Jmp Short GetIndicRet
  1275. IsItNumbIndic:    Cmp    AX,KeyFloat
  1276.         Jmp Short GetIndicRet
  1277. MakeFFFF:    Mov    AX,65535
  1278. GetIndicRet:    Or    AX,AX
  1279.         Ret
  1280. GetIndicBit    Endp
  1281. ;
  1282. GetSortKey    Proc    Near
  1283.         Mov    GotSortKey,0FFH
  1284.         Call    CreateKey        ;Setup default sort key rcd.
  1285.         Mov    GotStringParm,0
  1286.         Mov    GotBinaryParm,0
  1287.         Mov    GotCParm,0
  1288.         Mov    GotPParm,0
  1289.         Mov    GotKeyErr,0
  1290. NextKeyParm:    Jcxz    JmpChkKeyIn      ;Jmp if no more parms.
  1291.         Dec    CX
  1292.         Lodsb            ;Get next sort key byte.
  1293.         Xlat             ;Conv low case to up case.
  1294.         Cmp    AL,Space         ;If space this sort key is done,
  1295.         Jnz    IsNextSlash
  1296. JmpChkKeyIn:    Jmp    ChkKeyIn         ;go get the next one.
  1297. IsNextSlash:    Cmp    AL,Slash         ;If / this sort key is done,
  1298.         Jz    JmpChkKeyIn         ;go get the next one.
  1299.         Mov    DX,AX
  1300.         Call    GetIndicBit     ;Chk for valid parm.
  1301.         Jns    CmpKeyRev
  1302.         Jmp    CheckKeyLen      ;Jump if not.
  1303. CmpKeyRev:    Cmp    AX,KeyReverse
  1304.         Je    JmpSaveIndic
  1305.         Cmp    AX,KeyPascal
  1306.         Jbe    CmpGotBin
  1307.         Jmp    CheckNumbStr
  1308. CmpGotBin:    Cmp    GotBinaryParm,0
  1309.         Jz    CmpKeyZero
  1310.         Test    GotKeyErr,GotBinStrErr
  1311.         Jnz    CmpKeyZero
  1312.         Or    GotKeyErr,GotBinStrErr
  1313.         Mov    DX,Offset BinaryStringMsg
  1314.         Call    DispErrorParm
  1315. CmpKeyZero:    Cmp    AX,KeyZero
  1316.         Jnz    PascalCmp
  1317.         Mov    GotCParm,0FFH
  1318.         Cmp    GotPParm,0
  1319.         Jnz    PascalZeroNg
  1320.         Test    KeyTypInit,KeyPascal
  1321.         Jnz    DoPSwitchCKey
  1322.         Jmp    SaveIndic
  1323. DoPSwitchCKey:    Mov    SwitchKeyNGMsg+2,'5'
  1324.         Mov    SwitchKeyNGMsg+5,'C'
  1325.         Mov    SwitchKeyNGMsg+33,'P'
  1326.         Mov    DX,Offset SwitchKeyNGMsg
  1327.         Call    DispErrorParm
  1328. JmpSaveIndic:    Jmp    SaveIndic
  1329. PascalZeroNG:    Mov    DX,Offset PascalZeroNGMsg
  1330.         Call    DispErrorParm
  1331.         Jmp    SaveIndic
  1332. PascalCmp:    Cmp    AX,KeyPascal
  1333.         Ja    CheckNumbStr
  1334.         Je    SetGotPParm
  1335.         Jmp    SaveIndic
  1336. SetGotPParm:    Mov    GotPParm,0FFH
  1337.         Cmp    GotCParm,0
  1338.         Jnz    PascalZeroNg
  1339.         Test    KeyTypInit,KeyZero
  1340.         Jz    CheckPasFix
  1341.         Mov    SwitchKeyNGMsg+2,'6'
  1342.         Mov    SwitchKeyNGMsg+5,'P'
  1343.         Mov    SwitchKeyNGMsg+33,'C'
  1344.         Mov    DX,Offset SwitchKeyNGMsg
  1345.         Call    DispErrorParm
  1346. CheckPasFix:    Cmp    FixedLen,0
  1347.         Jnz    SaveIndic
  1348.         Mov    DX,Offset PNotFNGMsg
  1349.         Call    DispErrorParm
  1350.         Jmp Short SaveIndic
  1351. CheckNumbStr:    Cmp    GotStringParm,0
  1352.         Jz    CheckNumbFix
  1353.         Test    GotKeyErr,GotBinStrErr
  1354.         Jnz    SaveIndic
  1355.         Or    GotKeyErr,GotBinStrErr
  1356.         Mov    DX,Offset BinaryStringMsg
  1357.         Call    DispErrorParm
  1358.         Jmp Short SaveIndic
  1359. CheckNumbFix:    Cmp    FixedLen,0
  1360.         Jnz    CheckPrevNumb
  1361.         Test    GotKeyErr,GotNumbNotFErr
  1362.         Jnz    CheckPrevNumb
  1363.         Or    GotKeyErr,GotNumbNotFErr
  1364.         Mov    DX,Offset NumbNotFNGMsg
  1365.         Call    DispErrorParm
  1366. CheckPrevNumb:    Cmp    GotBinaryParm,0
  1367.         Mov    GotBinaryParm,0FFH
  1368.         Jz    SaveIndic
  1369.         Mov    DX,KeyTyp
  1370.         And    DX,KeyInteger+KeyUnSigned+KeyMicro+KeyTurbo+KeyFloat
  1371.         Test    DX,AX
  1372.         Jnz    SaveIndic    ;If same type of binary then ok.
  1373.         Test    GotKeyErr,GotDiffBinErr
  1374.         Jnz    SaveIndic
  1375.         Or    GotKeyErr,GotDiffBinErr
  1376.         Mov    DX,Offset DiffBinaryMsg
  1377.         Call    DispErrorParm
  1378. SaveIndic:    Or    KeyTyp,AX        ;Set the switch bit.
  1379.         Jmp    NextKeyParm      ;Get next byte in sort key.
  1380. CheckKeyLen:    Mov    AX,DX
  1381.         Cmp    AL,LengthParm    ;Chk if parm is key len.
  1382.         Jz    GetKeyLen        ;If so jmp.
  1383.         Cmp    AL,'0'
  1384.         Jb    BadSortKey
  1385.         Cmp    AL,'9'
  1386.         Ja    BadSortKey
  1387.         Call    GetNumb        ;Else must be start col.
  1388.         Cmp    DX,32750
  1389.         Ja    BadStartCol
  1390.         Or    DX,DX
  1391.         Jz    BadStartCol
  1392.         Cmp    StartCol,0
  1393.         Jnz    SecondStartCol ;Jmp if already got StartCol.
  1394.         Mov    StartCol,DX      ;Store start col.
  1395.         Jmp    NextKeyParm
  1396. GetKeyLen:    Jcxz    BadKeyLen       ;Len must have at least one digit.
  1397.         Dec    CX
  1398.         Lodsb            ;Load 1st digit of len.
  1399.         Call    GetNumb       ;Returns numeric val in DX.
  1400.         Cmp    DX,32750
  1401.         Ja    BadKeyLen
  1402.         Or    DX,DX
  1403.         Jz    BadKeyLen
  1404.         Cmp    KeyLen,0
  1405.         Jnz    SecondKeyLen   ;Jmp if already got KeyLen.
  1406.         Mov    KeyLen,DX        ;Store key len.
  1407.         Jmp    NextKeyParm      ;Get nxt byte of sort key.
  1408. ChkKeyIn:    Push    AX
  1409.         Call    ChkKeyInRcd
  1410.         Pop    AX
  1411.         Jcxz    GetSortKeyRet
  1412.         Cmp    AL,Space
  1413.         Jz    GetSortKeyRet
  1414.         Inc    CX
  1415.         Dec    SI
  1416. GetSortKeyRet:    Ret
  1417. BadStartCol:    Mov    DX,Offset BadStartMsg
  1418.         Call    DispErrorParm
  1419.         Jmp    NextKeyParm
  1420. BadSortKey:    Test    GotKeyErr,0FFH
  1421.         Jz    DoBadSortKey
  1422.         Jmp    NextKeyParm
  1423. DoBadSortKey:    Mov    DX,Offset BadKeyMsg
  1424.         Call    DispErrorParm
  1425.         Jmp    NextKeyParm
  1426. SecondStartCol: Mov    DX,Offset SecondStartMsg
  1427.         Call    DispErrorParm
  1428.         Jmp    NextKeyParm
  1429. BadKeyLen:    Mov    DX,Offset BadKeyLenMsg
  1430.         Call    DispErrorParm
  1431.         Jmp    NextKeyParm
  1432. SecondKeyLen:    Mov    DX,Offset SecondKeyLenMsg
  1433.         Call    DispErrorParm
  1434.         Jmp    NextKeyParm
  1435. GetSortKey    Endp
  1436. ;
  1437. ;
  1438. JmpNoMem1:    Jmp    NoMemory
  1439. ;
  1440. CreateKey    Proc    Near
  1441.         Push    CX
  1442.         Push    SI
  1443.         Cld
  1444.         Add    KeyCount,1
  1445.         Mov    AX,StartCol
  1446.         Test    KeyTyp,KeyInteger+KeyUnsigned+KeyFloat+KeyMicro+KeyTurbo
  1447.         Jz    NotBinNumb
  1448.         Sub    AX,KeyLen
  1449.         Dec    AX
  1450.         Jmp Short SavePrevEnd
  1451. NotBinNumb:    Add    AX,Keylen
  1452. SavePrevEnd:    Mov    PrevEndCol,AX
  1453.         Mov    StartCol,0
  1454.         Mov    RelCol,0
  1455.         Mov    KeyLen,0
  1456.         Mov    DI,CodePointer         ;DI = addr of next key rout.
  1457.         Mov    AX,KeyTypInit
  1458.         Test    AX,KeyPascal
  1459.         Jz    SetKeyTyp
  1460.         Cmp    KeyCount,1
  1461.         Jnz    SetKeyTyp
  1462.         Cmp    FixedLen,0
  1463.         Jnz    CheckPAndC
  1464.         Mov    DX,Offset PMustBeFMsg
  1465.         Call    DisplayError
  1466. CheckPAndC:    Test    AX,KeyZero
  1467.         Jz    SetKeyTyp
  1468.         Mov    DX,Offset PAndCNGMsg
  1469.         Call    DisplayError
  1470. SetKeyTyp:    Mov    KeyTyp,AX
  1471.         Cmp    GotError,0
  1472.         Jz    SetKeyTyp2
  1473.         Jmp Short CreateKeyRet
  1474. SetKeyTyp2:    Mov    SecondStart,0
  1475.         Cmp    DI,Offset CompRoutine
  1476.         Jz    All1
  1477.         Mov    DI,OrigStart
  1478.         Mov    SI,CompMove
  1479.         Add    SI,Offset SecondBeg
  1480.         Mov    CX,Offset SecondEnd - Offset SecondBeg
  1481.         Mov    SecondStart,DI
  1482.         Rep Movsb
  1483. All1:        Mov    SI,CompMove
  1484.         Add    SI,Offset All1Beg
  1485.         Mov    CX,Offset All1End - Offset All1Beg
  1486.         Mov    All1Start,DI
  1487.         Rep Movsb
  1488.         Mov    CodePointer,DI
  1489.         Cmp    DI,ModelCodeLoc
  1490.         Jb    CreateKeyRet
  1491. NoMemory9:    Jmp    NoMemory
  1492. CreateKeyRet:    Pop    SI
  1493.         Pop    CX
  1494.         Ret
  1495. CreateKey    Endp
  1496. ;
  1497. FileAndRedir:    Mov    DX,Offset FileAndRedirMsg
  1498.         Jmp    DoDispErrParm
  1499. ;
  1500. SaveFileAddr    Proc    Near
  1501.         Test    IpDevice,80H
  1502.         Jz    FileAndRedir    ;Jump if input redirected.
  1503.         Dec    SI
  1504.         Inc    CX
  1505.         Cmp    GotInput,0
  1506.         Jnz    OutputFile
  1507.         Mov    GotInput,0FFH
  1508.         Mov    HaveSpecs,0FFH
  1509.         Mov    InputAddr,SI
  1510. NewInput:    Jcxz    MisplacedPlus        ;Jump if plus at end.
  1511.         Lodsb
  1512.         Dec    CX
  1513.         Cmp    AL,'+'
  1514.         Jz    MisplacedPlus        ;Jump if plus at beginning.
  1515.         Inc    InputFileCt
  1516. NextNameChar:    Jcxz    SaveInputEnd2
  1517.         Lodsb
  1518.         Dec    CX
  1519.         Cmp    AL,Space
  1520.         Jz    SaveInputEnd
  1521.         Cmp    AL,Slash
  1522.         Jz    SaveInputEnd
  1523.         Cmp    AL,'+'
  1524.         Jnz    NextNameChar
  1525.         Jmp Short NewInput
  1526. SaveInputEnd:    Dec    SI
  1527.         Inc    CX
  1528. SaveInputEnd2:    Mov    InputEnd,SI
  1529.         Mov    AL,InputFileCt
  1530.         Mov    TotalFileCt,AL
  1531.         Ret
  1532. ;
  1533. OutputFile:    Cmp    GotOutput,0
  1534.         Jnz    SecondIpOp
  1535.         Mov    GotOutput,0FFH
  1536.         Mov    OutputAddr,SI
  1537. NextOpChar:    Jcxz    SaveOutputEnd2
  1538.         Lodsb
  1539.         Dec    CX
  1540.         Cmp    AL,Space
  1541.         Jz    SaveOutputEnd2
  1542.         Cmp    AL,Slash
  1543.         Jz    SaveOutputEnd
  1544.         Cmp    AL,'+'
  1545.         Jnz    NextOpChar
  1546.         Jmp Short OutputPlus
  1547. SaveOutputEnd:    Dec    SI
  1548.         Inc    CX
  1549. SaveOutputEnd2: Mov    OutputEnd,SI
  1550.         Ret
  1551. ;
  1552. SecondIpOp:    Mov    DX,Offset SecondIpMsg
  1553.         Jmp    DoDispErrParm
  1554. OutputPlus:    Mov    DX,Offset OutputPlusMsg
  1555.         Jmp    DoDispErrParm
  1556. MisplacedPlus:    Mov    DX,Offset MisplacedMsg
  1557.         Jmp    DoDispErrParm
  1558. ;
  1559. SaveFileAddr    Endp
  1560. ;
  1561. AllocError:    Mov    DX,Offset AllocMsg
  1562.         Jmp    DisplayExit
  1563. ;
  1564. SetupMemory    Proc    Near
  1565.         Mov    BX,SP       ;Add 31 to SP val assures that BX pts
  1566.         Add    BX,31       ;beyond stack and allows round para up.
  1567.         Mov    CL,4
  1568.         Shr    BX,CL       ;Convert to para.
  1569.         Mov    AH,SetBlock
  1570.         Int    DOS         ;Dealloc mem above stack.
  1571.         Jc    AllocError
  1572.         Mov    AH,AllocMemory
  1573.         Mov    BX,0FFFFH    ;Ask how much mem avail.
  1574.         Int    DOS         ;Ret BX = avail para.
  1575.         Cmp    Ax,8        ;Code 8 means not enough mem, so OK.
  1576.         Jnz    AllocError    ;Else is fatal.
  1577.         Mov    AH,AllocMemory    ;Now alloc all avail mem.
  1578.         Int    DOS
  1579.         Jc    AllocError
  1580.         Cmp    BX,0200H    ;Insist on 512 para (8192 bytes).
  1581.         Jae    SetupMem2
  1582. NoMemory:    Mov    DX,Offset NoMemoryMsg
  1583.         Jmp    DisplayExit
  1584. SetupMem2:    Mov    MemParaAvail,BX
  1585.         Mov    MemoryBegSeg,AX
  1586.         Mov    NextSeg,AX
  1587.         Mov    NextOfs,0
  1588.         Mov    Data.Segm,AX
  1589.         Mov    Data.Beg,0
  1590.         Add    BX,AX         ;Seg addr of end of avail space.
  1591.         Mov    MemoryEndSeg,BX       ;End of avail mem.
  1592.         Dec    BX            ;Allow one para for block table.
  1593.         Mov    LastSeg,BX        ;End of mem avail for data.
  1594.         Mov    BlockSeg,BX
  1595.         Mov    DS,BX
  1596.         Mov    DS:Word Ptr[000CH],0
  1597.         Mov    DS:Word Ptr[000EH],0
  1598.         Push    CS
  1599.         Pop    DS
  1600.         Mov    CX,FixedLen
  1601.         Jcxz    Short MakeOfs2    ;Jmp if not fixed len.
  1602.         Cmp    CX,2
  1603.         Jae    FixedLenGE2
  1604.         Mov    DataMax,32752
  1605.         Mov    DataPara,07FFH
  1606.         Mov    AX,32752
  1607.         Jmp Short FixedMaxPara
  1608. FixedLenGE2:    Mov    AX,65520
  1609.         Xor    DX,DX
  1610.         Div    CX        ;AX is max number of rcds in 65520 bytes.
  1611.         Mov    BX,65520
  1612.         Sub    BX,DX     ;Get ofs after last byte of last rcd.
  1613.         Mov    DataMax,BX    ;Save in DataMax.
  1614.         Add    BX,15
  1615.         Mov    CL,4
  1616.         Shr    BX,CL
  1617.         Mov    DataPara,BX     ;Save # of para to contain rcds.
  1618. FixedMaxPara:    Mul    FixPlus2     ;DX:AX = space for DataMax + pointers.
  1619.         Add    AX,15
  1620.         Adc    DX,0
  1621.         Shr    DX,1   ;1st shift involves DX because might exceed 64K.
  1622.         Rcr    AX,1
  1623.         Mov    CL,3
  1624.         Shr    AX,CL            ;AX = para for DataMax + ptrs.
  1625.         Add    AX,0400H         ;Add 16K for write buff.
  1626.         Mov    MaxPara,AX
  1627.         Jmp Short ChkMinPara
  1628. MakeOfs2:    Mov    NextOfs,2
  1629.         Mov    DS,NextSeg
  1630.         Mov    AX,CS:LineEnd
  1631.         Mov    DS:Word Ptr[0],AX
  1632.         Push    CS
  1633.         Pop    DS
  1634. ChkMinPara:    Mov    AX,MemParaAvail
  1635.         Mov    BX,AX
  1636.         Cmp    AX,4800H    ;Do we have at least 288K avail.
  1637.         Jae    CalcMaxAllow    ;If so, MergeBuff=32K, MergeSeg=16K.
  1638.         Xor    DX,DX
  1639.         Push    AX
  1640.         Mov    CX,9        ;Else MergeBuff = ninth of avail mem.
  1641.         Div    CX
  1642.         Mov    MergeBuff,AX
  1643.         Shr    AX,1
  1644.         Cmp    AX,0100H
  1645.         Jae    SvMergeSeg
  1646.         Mov    AX,0100H    ;At least 4K for MergeSeg.
  1647. SvMergeSeg:    Mov    MergeSeg,AX    ;MergeSeg = one half of MergeBuff.
  1648.         Pop    AX
  1649.         Cmp    AX,2400H    ;Do we have at least 144K avail.
  1650.         Jae    CalcMaxAllow    ;If so, MinPara = 48K, MinBuff = 16K.
  1651.         Xor    DX,DX
  1652.         Mov    CX,3        ;Else MinPara = third of avail memory.
  1653.         Div    CX
  1654.         Mov    MinPara,AX
  1655.         Xor    DX,DX
  1656.         Div    CX        ;And MinBuff = 1/9 avail memory.
  1657.         Mov    MinBuff,AX
  1658. CalcMaxAllow:    Sub    BX,MinBuff    ;MemParaAvail - MinBuff.
  1659.         Shr    BX,1        ;One half of avail memory.
  1660.         Dec    BX
  1661.         Dec    BX        ;Allow for two one para ptr segs.
  1662.         Cmp    BX,07FFH    ;If GE 32752 bytes then OK.
  1663.         Jae    SetupMemRet
  1664.         Mov    CL,4
  1665.         Shl    BX,CL
  1666.         Mov    MaxAllowLen,BX
  1667.         Cmp    BX,FixedLen
  1668.         Jb    CantHoldTwo
  1669. SetupMemRet:    Mov    AX,MemParaAvail
  1670.         Sub    AX,CommandSize
  1671.         Jc    SetupMemRet2
  1672.         Mov    CX,12
  1673.         Mul    CX
  1674.         Cmp    FixedLen,0
  1675.         Jz    StoreBelow
  1676.         Mov    BX,AX        ;BX = BelowLow.
  1677.         Mov    AX,DX        ;AX = BelowHi.
  1678.         Xor    DX,DX        ;DX:AX = BelowHi.
  1679.         Mov    CX,FixPlus2
  1680.         Div    CX        ;AX = Hi part of BelowHi / FixPlus2.
  1681.         Xchg    AX,BX ;BX = Hi BelowHi/FixPlus2. DX:AX = Rem:BelowLow.
  1682.         Div    CX        ;BX:AX = Below / FixPlus2.
  1683.         Mov    CX,FixedLen
  1684.         Xchg    BX,AX        ;BX = Quotient low. AX = Quotient high.
  1685.         Mul    CX        ;AX = FixedLen * Quotient high.
  1686.         Xchg    BX,AX        ;BX = FixedLen*QuotHi. AX = QuotLow.
  1687.         Mul    CX        ;DX:AX = QuotLow * FixedLen.
  1688.         Add    DX,BX        ;DX:AX = (Below / FixPlus2) * FixedLen.
  1689. StoreBelow:    Mov    BelowLow,AX
  1690.         Mov    BelowHi,DX
  1691. SetupMemRet2:    Ret
  1692. CantHoldTwo:    Cmp    CS:MaxAllowLen,32750
  1693.         Jb    DoTwoRcdMsg
  1694.         Mov    DX,Offset LinGTMaxMsg
  1695.         Jmp    DisplayExit
  1696. DoTwoRcdMsg:    Mov    DX,Offset TwoRcdMsg
  1697.         Jmp    DisplayExit
  1698. SetupMemory    Endp
  1699. ;
  1700. ReSetupMemory    Proc    Near
  1701.         Cmp    FixedLen,0
  1702.         Jz    ResetLines
  1703.         Mov    AX,MemoryBegSeg
  1704.         Mov    NextSeg,AX
  1705.         Mov    NextOfs,0
  1706.         Mov    SegCount,0
  1707.         Ret
  1708. ResetLines:    Mov    DI,SegCount
  1709.         Shl    DI,1
  1710.         Mov    AX,NextSeg
  1711.         Mov    BX,Data.Segm[DI]
  1712.         Sub    AX,BX        ;Full para in last part line.
  1713.         Mov    CL,4
  1714.         Shl    AX,CL        ;Bytes equiv to para in part line.
  1715.         Mov    DS,BX
  1716.         Mov    SI,CS:Data.Beg[DI] ;DS:SI pts to part line.
  1717.         Sub    AX,SI        ;Subt ofs of part line.
  1718.         Add    AX,CS:NextOfs       ;Add bytes after last para.
  1719.         Mov    BX,AX        ;Hold len of last part line.
  1720.         Mov    DX,AX
  1721.         And    AL,0F0H
  1722.         Sub    DX,AX        ;Bytes after full para.
  1723.         Mov    CS:NextOfs,DX       ;NextOfs after move.
  1724.         Shr    AX,CL        ;Number of para.
  1725.         Add    AX,CS:Data.Segm[0]    ;Compute NextSeg after move.
  1726.         Mov    CS:NextSeg,AX
  1727.         Mov    CX,BX        ;Recover len of last part line.
  1728.         Xor    DI,DI
  1729.         Mov    ES,CS:Data.Segm[0] ;ES:DI points to dest for move.
  1730.         Cld
  1731.         Shr    CX,1
  1732.         Jnc    MovePartWords
  1733.         Movsb
  1734. MovePartWords:    Rep Movsw
  1735.         Mov    CS:SegCount,0
  1736.         Mov    AX,CS:LineEnd
  1737.         Mov    ES:Word Ptr[0],AX
  1738.         Push    CS
  1739.         Push    CS
  1740.         Pop    DS
  1741.         Pop    ES
  1742.         Ret
  1743. ;
  1744. ReSetupMemory    Endp
  1745. ;
  1746. LoadStd     Proc    Near
  1747.         Cmp    MoreData,0
  1748.         Jnz    DoLoadStd
  1749.         Test    IpDevice,80H
  1750.         Jnz    DeviceErr    ;If sign bit is on StdIp is a device.
  1751.         Mov    Handle,StdInput  ;Save std ip handle.
  1752. DoLoadStd:    Call    LoadFile        ;Load the file.
  1753.         Ret
  1754. DeviceErr:    Mov    DX,Offset DeviceMsg
  1755.         Jmp    DisplayExit
  1756. LoadStd     Endp
  1757. ;
  1758. LoadSpec    Proc    Near
  1759.         Cmp    MoreData,0
  1760.         Jnz    DoLoadSpec
  1761.         Cmp    WildCard,0
  1762.         Jz    LoadSpec2
  1763.         Mov    AX,FindNext
  1764.         Int    DOS
  1765.         Jc    LoadSpec2
  1766.         Call    MoveToASCIIZ ;DX=ASCIIZ offset, DI points after zero.
  1767.         Jmp Short OpenSpec
  1768. LoadSpec2:    Mov    WildCard,0
  1769.         Cmp    InputFileCt,0
  1770.         Jnz    LoadSpec3
  1771.         Clc
  1772.         Ret
  1773. LoadSpec3:    Dec    InputFileCt
  1774.         Mov    DI,InputAddr
  1775.         Mov    DX,DI           ;DX pts to ASCIIZ string.
  1776.         Mov    CX,InputEnd
  1777.         Sub    CX,DI
  1778.         Cld
  1779.         Mov    AL,'+'           ;Look for term plus
  1780.         Repne Scasb         ;after filespec.
  1781.         Jz    StoreZero       ;Jmp if found term plus.
  1782.         Inc    DI    ;Hit end of parms. Inc DI for following move.
  1783. StoreZero:    Mov    Byte Ptr[DI-1],0    ;Put 0 at end of ASCIIZ string.
  1784.         Mov    InputAddr,DI      ;Save ptr to next
  1785.         Call    AnyWildCard
  1786.         Jnc    OpenSpec      ;Jump if no wildcards.
  1787.         Mov    WildCard,0FFH
  1788.         Mov    AX,FindFirst
  1789.         Mov    CX,Hidden+System
  1790.         Int    DOS
  1791.         Jc    FileOpenNG
  1792.         Call    MoveToASCIIZ ;DX=ASCIIZ offset, DI points after zero.
  1793. OpenSpec:    Mov    AX,OpenForRead        ;Open the file for read.
  1794.         Int    DOS
  1795.         Jc    FileOpenNG    ;Jmp if open was no good.
  1796.         Mov    Handle,AX       ;Save handle.
  1797. DoLoadSpec:    Call    LoadFile        ;Load the file.
  1798.         Jc    LoadSpecRet
  1799.         Mov    BX,Handle
  1800.         Mov    AX,Close        ;Close the file.
  1801.         Int    Dos
  1802.         Clc
  1803. LoadSpecRet:    Ret
  1804. FileOpenNg:    Push    DX          ;Save addr of ASCIIZ string.
  1805.         Call    WriteNewLine
  1806.         Call    WriteERROR
  1807.         Mov    DX,Offset NoFileMsg
  1808.         Mov    CL,Offset NoFileEnd - Offset NoFileMsg
  1809.         Call    WriteStdError
  1810.         Pop    DX               ;Recover ASCIIZ addr.
  1811.         Mov    CX,DI            ;Pts to end of ASCIIZ.
  1812.         Sub    CX,DX
  1813.         Dec    CX               ;Len of ASCIIZ.
  1814.         Call    WriteStdError
  1815.         Call    WriteNewLine
  1816.         Mov    CS:ErrorCode,47
  1817.         Jmp    ErrorExit
  1818. LoadSpec    Endp
  1819. ;
  1820. AnyWildCard    Proc    Near
  1821. ; Scan from [DI-2] to [DX] and if find "?" or "*" in file name or ext (i.e.
  1822. ; if find one of these before find "\" or ":":
  1823. ; . Move drive and path to IpASCIIZ area.
  1824. ; . Save offset of next byte in IpASCIIZ area at IpNamePtr.
  1825. ; . Preserve DX and DI.
  1826. ; . Return with carry set.
  1827. ; Otherwise:
  1828. ; . Preserve DX and DI.
  1829. ; . Return with carry clear.
  1830.         Mov    CX,DI
  1831.         Sub    CX,DX
  1832.         Dec    CX
  1833.         Lea    SI,[DI-2]
  1834.         Std
  1835. FindWild:    Lodsb
  1836.         Cmp    AL,'?'
  1837.         Jz    FoundWild
  1838.         Cmp    AL,'*'
  1839.         Jz    FoundWild
  1840.         Cmp    AL,'\'
  1841.         Jz    NotFoundWild
  1842.         Cmp    AL,':'
  1843.         Jz    NotFoundWild
  1844.         Loop    FindWild
  1845. NotFoundWild:    Clc
  1846.         Cld
  1847.         Ret
  1848. FoundWild:    Dec    CX
  1849.         Jz    OnlyFileName
  1850. ScanSlashColon: Lodsb
  1851.         Cmp    AL,'\'
  1852.         Jz    GotPath
  1853.         Cmp    AL,':'
  1854.         Jz    GotPath
  1855.         Loop    ScanSlashColon
  1856. OnlyFileName:    Mov    AX,Offset IpASCIIZ
  1857.         Mov    IpNamePtr,AX
  1858.         Cld
  1859.         Stc
  1860.         Ret
  1861. GotPath:    Cld
  1862.         Mov    SI,DX
  1863.         Push    DI
  1864.         Mov    DI,Offset IpASCIIZ
  1865.         Rep Movsb
  1866.         Mov    IpNamePtr,DI
  1867.         Pop    DI
  1868.         Stc
  1869.         Ret
  1870. AnyWildCard    Endp
  1871. ;
  1872. MoveToASCIIZ    Proc    Near
  1873. ; Copy file name at IpNameExt to [IPNamePtr].
  1874. ; Load IpNamePtr into DX.
  1875. ; Load DI with adress of byte after binary zero.
  1876.         Cld
  1877.         Mov    SI,Offset IpNameExt
  1878.         Mov    DI,IpNamePtr
  1879.         Mov    CX,13
  1880.         Mov    DX,Offset IpASCIIZ
  1881. NextASCIIZ:    Lodsb
  1882.         Stosb
  1883.         Cmp    AL,0
  1884.         Loopne    NextASCIIZ
  1885.         Ret
  1886. MoveToASCIIZ    Endp
  1887. ;
  1888. MemIsFull    Proc    Near
  1889.         Push    CS
  1890.         Pop    DS               ;Restore ptr to code seg.
  1891.         Mov    MoreData,0FFH
  1892.         Cmp    WriteHandle,1
  1893.         Ja    MemIsFull2
  1894.         Mov    WriteHandle,0
  1895. MemIsFull2:    Mov    FileSizeHi,BP
  1896.         Mov    FileSizeLo,DI
  1897.         Mov    GotData,1
  1898.         Mov    FinalOutput,0
  1899.         Stc
  1900.         Ret
  1901. MemIsFull    Endp
  1902. ;
  1903. LoadFile    Proc    Near
  1904.         Mov    BX,Handle
  1905.         Cmp    CS:MoreData,0
  1906.         Jz    NewFile
  1907.         Mov    CS:MoreData,0
  1908.         Mov    BP,CS:FileSizeHi
  1909.         Mov    DI,CS:FileSizeLo
  1910.         Jmp    LoadFile2
  1911. NewFile:    Mov    AX,GetFileLen
  1912.         Xor    CX,CX
  1913.         Mov    DX,CX
  1914.         Int    DOS              ;DX:AX = len of file
  1915.         Push    AX
  1916.         Push    DX
  1917.         Mov    AX,SetFileAtBeg
  1918.         Xor    CX,CX
  1919.         Mov    DX,CX
  1920.         Int    DOS
  1921.         Pop    BP
  1922.         Pop    DI        ;BP:DI = File len.
  1923.         Cmp    TotalFileCt,1
  1924.         Jnz    NewFile2
  1925.         Cmp    WildCard,0
  1926.         Jnz    NewFile2
  1927.         Mov    AX,LeaveCmdSize
  1928.         Cmp    MemParaAvail,AX
  1929.         Jb    NewFile2
  1930.         Mov    AX,DI
  1931.         Mov    DX,BP
  1932.         Sub    AX,BelowLow
  1933.         Sbb    DX,BelowHi
  1934.         Jnc    NewFile2
  1935.         Mov    AX,CommandSize
  1936.         Sub    MemoryEndSeg,AX
  1937.         Sub    LastSeg,AX
  1938.         Sub    BlockSeg,AX
  1939.         Sub    MemParaAvail,AX
  1940.         Push    DS
  1941.         Mov    DS,BlockSeg
  1942.         Mov    DS:Word Ptr[000CH],0
  1943.         Mov    DS:Word Ptr[000EH],0
  1944.         Pop    DS
  1945. NewFile2:    Mov    CX,FixedLen
  1946.         Jcxz    LoadFile1
  1947.         Mov    AX,BP        ;High part of file len.
  1948.         Xor    DX,DX
  1949.         Div    CX
  1950.         Mov    AX,DI        ;Low part of file len.
  1951.         Div    CX        ;DX = remainder of div by FixedLen.
  1952.         Sub    DI,DX        ;Subtract remainder from file len to
  1953.         Sbb    BP,0        ;get multiple of FixedLen.
  1954.         Or    DX,DX
  1955.         Jz    LoadFile1
  1956.         Push    BP
  1957.         Push    DI
  1958.         Mov    DX,Offset ShortRcdMsg
  1959.         Mov    CX,Offset ShortRcdEnd - Offset ShortRcdMsg
  1960.         Call    WriteStdError2
  1961.         Pop    DI
  1962.         Pop    BP
  1963. LoadFile1:    Mov    DX,BP
  1964.         Or    DX,DI
  1965.         Jnz    LoadFile2
  1966.         Jmp    LoadRet
  1967. LoadFile2:    Mov    DS,CS:NextSeg
  1968.         Mov    DX,CS:NextOfs        ;DS:DX = load addr.
  1969.         Mov    AX,DS
  1970.         Mov    BX,CS:LastSeg
  1971.         Sub    BX,AX
  1972.         Sub    BX,CS:ReservedForPtrs    ;Avail para.
  1973.         Cmp    BX,CS:MaxPara
  1974.         Jbe    LoadFile2A
  1975.         Mov    CX,CS:DataMax
  1976.         Jmp Short LoadFile5
  1977. LoadFile2A:    Cmp    BX,CS:MinPara
  1978.         Jb    JmpMemIsFull
  1979.         Sub    BX,CS:MinBuff
  1980.         Cmp    CS:FixedLen,0
  1981.         Jnz    LoadFile3
  1982.         Mov    CL,3    ;Use half of space for data and half for ptrs.
  1983.         Shl    BX,CL
  1984.         Mov    CX,BX
  1985.         Jmp Short LoadFile4
  1986. LoadFile3:    Dec    BX
  1987.         Mov    AX,BX
  1988.         Mov    CX,16
  1989.         Push    DX
  1990.         Mul    CX
  1991.         Div    CS:FixPlus2
  1992.         Mul    CS:FixedLen
  1993.         Pop    DX
  1994.         Mov    CX,AX         ;CX = avail bytes in seg.
  1995.         Cmp    CX,CS:FixedLen
  1996.         Jae    LoadFile5
  1997. JmpMemIsFull:    Jmp    MemIsFull
  1998. LoadFile4:    Sub    CX,DX         ;CX = avail bytes in seg.
  1999. LoadFile5:    Sub    DI,CX
  2000.         Sbb    BP,0
  2001.         Jnc    BiggerThanSeg ;Jmp if rest of file bigger then seg.
  2002.         Add    CX,DI         ;else use len of rest of file.
  2003.         Xor    DI,DI
  2004.         Mov    BP,DI         ;Remain len of file is 0.
  2005.         Mov    CS:MustSetPtrs,0
  2006.         Jmp Short DoRead
  2007. BiggerThanSeg:    Mov    CS:MustSetPtrs,0FFH
  2008. DoRead:     Mov    BX,CS:Handle
  2009.         Mov    AX,Read    ;Read up to avail bytes in seg.
  2010.         Int    DOS
  2011.         Jc    JmpReadErr    ;Jmp if read no good.
  2012.         Cmp    AX,CX         ;Do bytes read = bytes req.
  2013.         Jnz    JmpReadErr    ;Jmp if they don't.
  2014.         Mov    BX,AX         ;Hold # of bytes read.
  2015.         Cmp    CS:FixedLen,0
  2016.         Jnz    AdjustOfs
  2017. ;
  2018.         Push    DS
  2019.         Pop    ES
  2020.         Cld
  2021. ScanCtrlZ:    Push    DI
  2022.         Mov    DI,DX
  2023.         Add    DI,BX
  2024.         Sub    DI,CX            ;Start ofs for Ctrl-Z scan.
  2025.         Mov    AL,CtrlZ
  2026.         Repne Scasb
  2027.         Mov    SI,DI
  2028.         Pop    DI
  2029.         Jnz    AdjustOfs
  2030.         Dec    BX
  2031.         Mov    CS:GotCtrlZ,0FFH
  2032.         Cmp    CS:IgnoreCtrlZ,0
  2033.         Jz    AdjustBytes
  2034.         Jcxz    AdjustOfs
  2035.         Call    DeleteCtrlZ
  2036.         Jmp    ScanCtrlZ
  2037. AdjustBytes:    Sub    BX,CX            ;Number bytes of data.
  2038. ;
  2039.         Jnz    AdjustBytes2
  2040.         Jmp    LoadRet
  2041. AdjustBytes2:    Add    CS:NextOfs,BX
  2042.         Mov    CS:EndData,0
  2043.         Mov    AX,BX
  2044.         Shr    AX,1
  2045.         Shr    AX,1
  2046.         Shr    AX,1
  2047.         Shr    AX,1
  2048.         Add    CS:ReservedForPtrs,AX
  2049.         Jmp Short LoadFin
  2050. JmpReadErr:    Jmp    ReadError
  2051. AdjustOfs:    Add    CS:NextOfs,BX
  2052.         Mov    CS:EndData,0
  2053.         Cmp    CS:FixedLen,0
  2054.         Jnz    FixReserved
  2055.         Mov    AX,BX
  2056.         Shr    AX,1
  2057.         Shr    AX,1
  2058.         Shr    AX,1
  2059.         Shr    AX,1
  2060.         Add    CS:ReservedForPtrs,AX
  2061.         Jmp Short AdjustOfs2
  2062. FixReserved:    Push    DX
  2063.         Mov    AX,BX
  2064.         Xor    DX,DX
  2065.         Div    CS:FixedLen
  2066.         Shr    AX,1
  2067.         Shr    AX,1
  2068.         Shr    AX,1
  2069.         Add    CS:ReservedForPtrs,AX
  2070.         Pop    DX
  2071. AdjustOfs2:    Mov    AX,BP
  2072.         Or    AX,DI
  2073.         Jz    LoadFin
  2074.         Push    BP
  2075.         Push    DI
  2076.         Mov    CS:FromMain,0
  2077.         Call    SetupPointers
  2078.         Pop    DI
  2079.         Pop    BP
  2080.         Jmp    LoadFile2
  2081. LoadFin:    Mov    CS:GotData,1
  2082.         Cmp    CS:Fixedlen,0
  2083.         Jnz    LoadRet
  2084.         Add    BX,DX            ;Pt after last byte.
  2085.         Mov    AX,Word Ptr[BX-2]
  2086.         Cmp    AX,CS:LineEnd
  2087.         Jz    AdjNextOfs
  2088.         Xchg    AH,AL
  2089.         Cmp    AX,CS:LineEnd
  2090.         Jz    AdjNextOfs
  2091.         Inc    BX
  2092.         Cmp    AL,CS:Byte Ptr LineEnd + 1
  2093.         Jz    LoadFin3
  2094. LoadFin2:    Cmp    AL,CS:Byte Ptr LineEnd
  2095.         Jz    LoadFin3
  2096.         Inc    BX
  2097. LoadFin3:    Mov    AX,CS:LineEnd
  2098.         Mov    Word Ptr[BX-2],AX
  2099.         Push    BX
  2100.         Push    DS
  2101.         Push    CS
  2102.         Pop    DS
  2103.         Mov    DX,Offset MissCRLFMsg
  2104.         Mov    CX,Offset MissCRLFEnd - Offset MissCRLFMsg
  2105.         Call    WriteStdError2
  2106.         Pop    DS
  2107.         Pop    BX
  2108. AdjNextOfs:    Mov    CS:NextOfs,BX
  2109. LoadRet:    Call    SetupPointers
  2110.         Push    CS
  2111.         Push    CS
  2112.         Pop    DS
  2113.         Pop    ES
  2114.         Clc
  2115.         Ret
  2116. ReadError:    Mov    DX,Offset ReadErrorMsg
  2117.         Jmp    DisplayExit
  2118. LoadFile    Endp
  2119. ;
  2120. DeleteCtrlZ    Proc    Near
  2121.         Push    DI
  2122.         Push    CX
  2123.         Lea    DI,[SI-1]
  2124.         Shr    CX,1
  2125.         Jnc    DeleteCtrlZ2
  2126.         Movsb
  2127. DeleteCtrlZ2:    Rep Movsw
  2128.         Pop    CX
  2129.         Pop    DI
  2130.         Ret
  2131. DeleteCtrlZ    Endp
  2132. ;
  2133. SetupPointers    Proc    Near
  2134. ;
  2135.         Cld
  2136.         Mov    SI,CS:SegCount
  2137.         Shl    SI,1
  2138.         Mov    AX,CS:NextOfs
  2139.         Mov    DX,AX
  2140.         And    AL,0F0H
  2141.         Sub    DX,AX            ;Ofs for load.
  2142.         Mov    CS:NextOfs,DX
  2143.         Mov    BP,DX            ;Hold NextOfs
  2144.         Mov    CL,4
  2145.         Shr    AX,CL
  2146.         Add    AX,CS:NextSeg
  2147.         Mov    CS:NextSeg,AX
  2148.         Cmp    CS:PtrsAgain,0
  2149.         Jz    SetupPtrs1
  2150.         Mov    CS:PtrsAgain,0
  2151.         Mov    CS:EndData,0
  2152.         Jmp Short SetupPtrs2
  2153. SetupPtrs1:    Cmp    CS:EndData,0
  2154.         Jz    SetupPtrs2
  2155.         Mov    CS:EndData,0
  2156.         Ret
  2157. SetupPtrs2:    Mov    DI,AX            ;Hold NextSeg
  2158.         Sub    AX,CS:Data.Segm[SI]
  2159.         Mov    CX,16
  2160.         Mul    CX        ;DX:AX = ofs of NextSeg from DataSeg[SI].
  2161.         Add    AX,BP
  2162.         Adc    DX,0      ;Ofs of Next loc from DataSeg[SI].
  2163.         Sub    AX,CS:LenBuckSize    ;If lines, pt to 1st len buck.
  2164.         Sbb    DX,0
  2165.         Jz    SetupPtrs3
  2166.         Cmp    CS:FromMain,0
  2167.         Jnz    SetPtrsAgain
  2168.         Cmp    DX,1
  2169.         Jbe    UseDataMax
  2170. SetPtrsAgain:    Mov    CS:PtrsAgain,0FFH
  2171.         Jmp Short UseDataMax         ;Jmp if more than 65535.
  2172. SetupPtrs3:    Cmp    AX,CS:Data.Beg[SI]
  2173.         Ja    ChkDataMax
  2174.         Ret                  ;Return if no data.
  2175. ChkDataMax:    Cmp    AX,CS:DataMax
  2176.         Jae    UseDataMax
  2177.         Cmp    CS:FromMain,0
  2178.         Jnz    SaveDataEnd
  2179.         Cmp    CS:MustSetPtrs,0
  2180.         Jnz    SaveDataEnd
  2181.         Ret           ;Return if LT DataMax and not final time.
  2182. UseDataMax:    Mov    AX,CS:DataMax
  2183. SaveDataEnd:    Push    AX               ;Save end of data ptr in seg.
  2184.         Mov    BX,CS:LastSeg
  2185.         Inc    DI               ;NextSeg plus 1.
  2186.         Mov    CX,BX
  2187.         Sub    BX,DI            ;Avail para.
  2188.         Cmp    BX,0FFFH
  2189.         Jbe    GetPtrSegBeg
  2190.         Mov    BX,0FFFH
  2191. GetPtrSegBeg:    Sub    CX,BX
  2192.         Mov    DS,CX
  2193.         Mov    CS:Pointer.Segm[SI],CX
  2194.         Mov    CL,3
  2195.         Shl    BX,CL
  2196.         Mov    DX,BX            ;Max ptr ct.
  2197.         Shl    BX,1
  2198.         Dec    BX
  2199.         Dec    BX
  2200.         Mov    CS:Pointer.Beg[SI],BX
  2201.         Les    DI,CS:Data[SI]
  2202.         Pop    CX
  2203.         Add    CX,CS:LenBuckSize
  2204.         Sub    CX,DI            ;Number of data bytes.
  2205.         Mov    SI,BX       ;ES:DI=Data,DS:SI=Ptr,DX=PtrCt,CX=DataBytes.
  2206.         Cmp    CS:FixedLen,0
  2207.         Jz    LinePtrs
  2208.         Jmp    NextFix
  2209. ;
  2210. LinePtrs:    Mov    BX,CX
  2211.         Shr    BX,1
  2212.         Shr    BX,1
  2213.         Shr    BX,1
  2214.         Shr    BX,1
  2215.         Sub    CS:ReservedForPtrs,BX
  2216.         Jnc    NextLine
  2217.         Mov    CS:ReservedForPtrs,0
  2218. NextLine:    Mov    BX,DI            ;Pt to len field.
  2219.         Dec    CX
  2220.         Inc    DI
  2221.         Dec    CX
  2222.         Inc    DI               ;Pt to line.
  2223.         Mov    BP,CX            ;Hold remain len of data.
  2224.         Jcxz    FinishSegLine        ;Jmp if no more data.
  2225.         Mov    AX,CS:LineEnd
  2226. ScanForCR:    Dec    CX
  2227.         Scasb
  2228.         Jcxz    EndOfData2
  2229.         Jnz    ScanForCR2
  2230.         Cmp    ES:Byte Ptr[DI],AH   ;If next char is not LF
  2231.         Jz    PointToCr
  2232. ScanForCR2:    Repne Scasb             ;Find CR.
  2233.         Jcxz    EndOfData         ;Jmp if no CR or CR in last byte.
  2234.         Cmp    ES:Byte Ptr[DI-2],AH
  2235.         Jnz    ScanForCR3
  2236.         Dec    DI
  2237.         Inc    CX
  2238.         Jmp Short PointToCR
  2239. ScanForCR3:    Cmp    ES:Byte Ptr[DI],AH   ;If next char is not LF then
  2240.         Jnz    ScanForCR2         ;cont the search.
  2241. PointToCR:    Inc    CX
  2242.         Dec    DI             ;Pt back to CR.
  2243. SaveLineLen:    Sub    BP,CX             ;BP = len of line
  2244.         Jnz    SaveLineLen2
  2245.         Cmp    CS:ElimNull,0
  2246.         Jnz    NextLine
  2247. SaveLineLen2:    Mov    ES:[BX],BP       ;Store line len in prev CRLF buck.
  2248.         Add    BP,2
  2249.         Cmp    BP,CS:LongestLen
  2250.         Jbe    IncLineCt
  2251.         Cmp    BP,CS:MaxAllowLen
  2252.         Ja    LineLongJmp
  2253.         Mov    CS:LongestLen,BP
  2254. IncLineCt:    Sub    BP,2
  2255.         Dec    DX
  2256.         Mov    [SI],BX       ;Store addr of line in ptr buck.
  2257.         Dec    SI
  2258.         Dec    SI
  2259.         Jmp    NextLine
  2260. EndOfData:    Jnz    EndOfData2
  2261.         Cmp    ES:Byte Ptr[DI-2],AH
  2262.         Jnz    EndOfData2
  2263.         Dec    DI
  2264.         Inc    CX
  2265.         Jmp    PointToCR
  2266. LineLongJmp:    Jmp    CantHoldTwo
  2267. EndOfData2:    Sub    DI,BP            ;Ptr to 1st byte in line.
  2268.         Add    BP,2
  2269.         Cmp    BP,CS:MaxAllowLen
  2270.         Ja    LineLongJmp
  2271.         Mov    CS:EndData,0FFH
  2272.         Sub    BP,2
  2273. FinishSegLine:    Dec    DI
  2274.         Dec    DI
  2275.         Mov    AX,SI
  2276. FinishPtrs:    Mov    BX,CS
  2277.         Mov    DS,BX
  2278.         Mov    ES,BX
  2279.         Mov    SI,SegCount
  2280.         Mov    BX,SI
  2281.         Cmp    AX,Pointer.Beg[BX+SI]
  2282.         Jz    FinPtrsRet
  2283.         Mov    DataEnd[SI],DI
  2284.         Inc    AX
  2285.         Inc    AX
  2286.         Mov    PointerEnd[SI],AX
  2287.         And    AL,0F0H
  2288.         Sub    PointerEnd[SI],AX
  2289.         Sub    Pointer.Beg[SI+BX],AX
  2290.         Mov    CL,4
  2291.         Shr    AX,CL
  2292.         Add    AX,Pointer.Segm[SI+BX]
  2293.         Mov    Pointer.Segm[SI+BX],AX
  2294.         Mov    LastSeg,AX
  2295.         Inc    SI
  2296.         Inc    SI
  2297.         Mov    SegCount,SI
  2298.         Mov    BX,SI
  2299.         Mov    AX,DI
  2300.         And    AL,0F0H
  2301.         Sub    DI,AX
  2302.         Mov    Data.Beg[SI+BX],DI
  2303.         Mov    CL,4
  2304.         Shr    AX,CL
  2305.         Add    AX,Data.Segm[SI+BX-4]
  2306.         Mov    Data.Segm[SI+BX],AX
  2307.         Jmp    SetupPointers
  2308. FinPtrsRet:    Ret
  2309. ;
  2310. NextFix:    Mov    AX,CX            ;AX = Size of data seg.
  2311.         Xor    DX,DX
  2312.         Div    CS:FixedLen          ;AX = # of Rcds
  2313.         Mov    CX,AX
  2314.         Shr    AX,1
  2315.         Shr    AX,1
  2316.         Shr    AX,1
  2317.         Sub    CS:ReservedForPtrs,AX
  2318.         Jnc    NextFix2
  2319.         Mov    CS:ReservedForPtrs,0
  2320. NextFix2:    Mov    AX,DI
  2321.         Mov    BX,DS
  2322.         Mov    ES,BX
  2323.         Mov    DI,SI
  2324.         Mov    BP,CS:FixedLen
  2325.         Std
  2326. StoreFixedPtr:    Stosw
  2327.         Add    AX,BP
  2328.         Loop    StoreFixedPtr
  2329.         Cld
  2330.         Xchg    AX,DI
  2331.         Jmp    FinishPtrs
  2332. ;
  2333. SetupPointers    Endp
  2334. ;
  2335. FourDigits    Proc    Near
  2336.         Mov    BP,10
  2337.         Inc    AH
  2338.         Inc    AL
  2339.         Mul    AH
  2340.         Mov    CX,4
  2341. NextDig:    Xor    DX,DX
  2342.         Div    BP
  2343.         Or    DL,30H
  2344.         Mov    DS:Byte Ptr[SI],DL
  2345.         Inc    SI
  2346.         Loop    NextDig
  2347.         Ret
  2348. FourDigits    Endp
  2349. ;
  2350. SetupTempFiles    Proc    Near
  2351.         Cmp    CS:TempDisk,0
  2352.         Jnz    SetTempFiles2
  2353.         Mov    AL,CS:DefaultDisk
  2354.         Mov    CS:TempDisk,AL
  2355. SetTempFiles2:    Mov    DL,CS:TempDisk
  2356.         Mov    DH,':'
  2357.         Mov    Word Ptr TempName1,DX
  2358.         Mov    Word Ptr TempName2,DX
  2359.         Mov    Word Ptr TempName3,DX
  2360.         Mov    SI,Offset TempName1+2
  2361.         Mov    DI,0
  2362.         Call    CreateTempFile
  2363.         Mov    WriteHandle,AX
  2364.         Mov    TempHandle1,AX
  2365.         Mov    SI,Offset TempName2+2
  2366.         Mov    DI,1
  2367.         Call    CreateTempFile
  2368.         Mov    ReadHandle,AX
  2369.         Mov    TempHandle2,AX
  2370.         Mov    SI,Offset TempName3+2
  2371.         Mov    DI,2
  2372.         Call    CreateTempFile
  2373.         Mov    TempHandle3,AX
  2374.         Mov    ExtraHandle,AX
  2375.         Ret
  2376. SetupTempFiles    Endp
  2377. ;
  2378. CreateTempFile    Proc    Near
  2379.         Push    SI
  2380.         Mov    AX,GetTime
  2381.         Int    DOS
  2382.         Mov    AX,DX
  2383.         Add    DI,CX
  2384.         Call    FourDigits
  2385.         Mov    AX,DI
  2386.         Call    FourDigits
  2387.         Mov    DI,SI
  2388.         Mov    AX,422EH
  2389.         Stosw
  2390.         Mov    AX,4250H
  2391.         Stosw
  2392.         Xor    AL,AL
  2393.         Stosb
  2394.         Pop    DX
  2395.         Dec    DX
  2396.         Dec    DX
  2397.         Xor    CX,CX
  2398.         Mov    AX,CreateFile
  2399.         Int    DOS
  2400.         Jc    FullTempDir
  2401.         Ret
  2402. FullTempDir:    Mov    DX,Offset NoTempDirMsg
  2403.         Jmp    DisplayExit
  2404. CreateTempFile    Endp
  2405. ;
  2406. OpenOutput    Proc    Near
  2407.         Mov    DI,CS:OutputEnd
  2408.         Mov    CS:Byte Ptr[DI],0
  2409.         Mov    DX,CS:OutputAddr
  2410.         Push    CS
  2411.         Pop    DS
  2412.         Xor    CX,CX
  2413.         Mov    AX,CreateFile
  2414.         Int    DOS
  2415.         Jc    FullOpDir
  2416.         Mov    CS:OpenedOutput,0FFH
  2417.         Mov    CS:WriteHandle,AX
  2418.         Mov    CS:OutputHandle,AX
  2419.         Ret
  2420. FullOpDir:    Mov    DX,Offset NoOpDirMsg
  2421.         Jmp    DisplayExit
  2422. OpenOutput    Endp
  2423. ;
  2424. WriteSetup    Proc    Near
  2425.         Cld
  2426.         Mov    CX,CS:SegCount
  2427.         Mov    SI,CX
  2428.         Dec    SI
  2429.         Dec    SI
  2430.         Mov    CS:SegNumb,SI
  2431.         Cmp    CS:SkipSetupTop,0
  2432.         Jz    DoSetup
  2433.         Jmp    WriteSetupRet
  2434. DoSetUp:    Mov    CS:WriteBuffEnd,65535
  2435.         Shr    CX,1
  2436.         Xor    AX,AX
  2437.         Mov    DI,Offset TopIndex
  2438. SetupTop:    Stosw
  2439.         Inc    AX
  2440.         Inc    AX
  2441.         Loop    SetupTop
  2442.         Mov    AX,CS:NextSeg
  2443.         Inc    AX
  2444.         Mov    CS:WriteBuff.Segm,AX
  2445.         Mov    CS:WriteBuff.Beg,0
  2446.         Mov    DX,CS:LastSeg
  2447.         Sub    DX,AX
  2448.         Cmp    DX,1000H
  2449.         Jae    SortTopRcds
  2450.         Mov    CL,4
  2451.         Shl    DX,CL
  2452. SaveLength:    Mov    CS:WriteBuffEnd,DX
  2453. SortTopRcds:    Xor    SI,SI            ;Init J.
  2454.         Push    SI
  2455. TopNextJ:    Pop    SI               ;Get prev J.
  2456.         Cmp    SI,CS:SegNumb
  2457.         Je    WriteSetupRet
  2458.         Inc    SI
  2459.         Inc    SI               ;Next J.
  2460.         Push    SI
  2461.         Mov    BP,SI            ;Init prev I.
  2462.         Cmp    CS:UseRcdLen,0
  2463.         Jz    UsePointerJ
  2464.         Mov    SI,CS:TopIndex[SI]     ;Contents of Jth TopIndex buck.
  2465.         Push    SI             ;Will insert this in proper buck.
  2466.         Shl    SI,1
  2467.         Lds    SI,CS:Data[SI]    ;DS:SI pts low rcd in data seg.
  2468.         Jmp Short TopNextI
  2469. UsePointerJ:    Mov    BX,CS:TopIndex[SI]     ;Contents of Jth TopIndex buck.
  2470.         Push    BX             ;Will insert this in proper buck.
  2471.         Shl    BX,1
  2472.         Lds    SI,CS:Pointer[BX]
  2473.         Mov    SI,Word Ptr[SI]   ;Ofs of low rcd in data seg.
  2474.         Mov    DS,CS:Data.Segm[BX]    ;DS:SI pts low rcd in data seg.
  2475. TopNextI:    Dec    BP
  2476.         Dec    BP               ;Next I.
  2477.         Js    TopInsert
  2478.         Mov    DI,BP
  2479.         Cmp    CS:UseRcdLen,0
  2480.         Jz    UsePointerI
  2481.         Mov    DI,CS:TopIndex[DI]     ;Contents of Jth TopIndex buck.
  2482.         Push    DI             ;Will insert this in proper buck.
  2483.         Shl    DI,1
  2484.         Les    DI,CS:Data[DI]    ;ES:DI pts low rcd in data seg.
  2485.         Jmp Short TopCompare
  2486. UsePointerI:    Mov    BX,CS:TopIndex[DI]     ;Contents of Jth TopIndex buck.
  2487.         Push    BX             ;Will insert this in proper buck.
  2488.         Shl    BX,1
  2489.         Les    DI,CS:Pointer[BX]
  2490.         Mov    DI,ES:Word Ptr[DI]     ;Ofs of low rcd in data seg.
  2491.         Mov    ES,CS:Data.Segm[BX]    ;ES:DI pts low rcd in data seg.
  2492. TopCompare:    Push    SI
  2493.         Call    CompRoutine
  2494.         Jnc    TopAddFour
  2495. TopNotInsert:    Pop    SI               ;Restore ofs of Jth line.
  2496.         Pop    DI               ;Get contents of Ith buck.
  2497.         Mov    CS:TopIndex[BP+2],DI     ;Store in I+1th buck.
  2498.         Jmp    TopNextI         ;Recompute I.
  2499. TopAddFour:    Add    SP,4         ;Discard Jth rcd ofs and Ith index.
  2500. TopInsert:    Pop    SI               ;Get contents of Jth buck.
  2501.         Mov    CS:TopIndex[BP+2],SI     ;Store in I+1th buck.
  2502.         Jmp    TopNextJ
  2503. WriteSetupRet:    Ret
  2504. ;
  2505. WriteSetup    Endp
  2506. ;
  2507. WriteData    Proc    Near
  2508.         Mov    SI,CS:OrigStart
  2509.         Mov    CS:Word Ptr[SI+4],0DB8CH
  2510.         Mov    CS:Byte Ptr[SI+6],08CH
  2511.         Call    WriteSetup
  2512.         Mov    CS:PrevOfs,0FFFFH
  2513.         Jmp Short WriteLowRcd
  2514. NextLowJ:    Inc    CX
  2515.         Inc    CX        ;CH = 0, CL SegNumb + 2.
  2516.         Mov    BX,CX
  2517.         Shr    BX,1
  2518.         And    BL,0FEH          ;First trial TopIndex.
  2519.         Mov    BP,CS:TopIndex         ;Contents of Jth TopIndex buck.
  2520.         Push    BP             ;Will insert this in proper buck.
  2521.         Shl    BP,1
  2522.         Lds    SI,CS:Pointer[BP]
  2523.         Mov    SI,Word Ptr[SI]      ;Ofs of low rcd in data seg.
  2524.         Mov    DS,CS:Data.Segm[BP]  ;DS:SI pts low rcd in data seg.
  2525. NextLowI:    Mov    BP,CS:TopIndex[BX]     ;Contents of Jth TopIndex buck.
  2526.         Shl    BP,1
  2527.         Les    DI,CS:Pointer[BP]
  2528.         Mov    DI,ES:Word Ptr[DI]     ;Ofs of low rcd in data seg.
  2529.         Mov    ES,CS:Data.Segm[BP]    ;ES:DI pts low rcd in data seg.
  2530.         Push    CX
  2531.         Mov    BP,BX
  2532.         Mov    DX,SI
  2533.         Call    CompRoutine
  2534.         Mov    SI,DX
  2535.         Mov    BX,BP
  2536.         Pop    CX
  2537.         Jnc    GoUp
  2538. GoDown:     Mov    CL,BL
  2539.         Add    BL,CH
  2540.         Shr    BL,1
  2541.         And    BL,0FEH
  2542.         Cmp    BL,CH
  2543.         Ja    NextLowI
  2544.         Jmp Short FoundPos
  2545. GoUp:        Mov    CH,BL
  2546.         Add    BL,CL
  2547.         Shr    BL,1
  2548.         And    BL,0FEH
  2549.         Cmp    BL,CH
  2550.         Ja    NextLowI
  2551. FoundPos:    Mov    CX,BX
  2552.         Shr    CX,1
  2553.         Mov    DI,Offset TopIndex
  2554.         Lea    SI,[DI+2]
  2555.         Mov    AX,CS
  2556.         Mov    ES,AX
  2557.         Mov    DS,AX
  2558.         Rep Movsw
  2559.         Pop    BP
  2560.         Mov    [DI],BP
  2561. WriteLowRcd:    Mov    BX,CS:TopIndex       ;Index in 0th buck.
  2562.         Shl    BX,1
  2563.         Lds    SI,CS:Pointer[BX]
  2564.         Mov    SI,Word Ptr[SI]   ;Ofs of low rcd in data seg.
  2565.         Mov    DS,CS:Data.Segm[BX]    ;Data seg for low rcd.
  2566.         Call    DoWriteLow
  2567.         Jc    WriteLowRcd
  2568. SetNextSearch:    Mov    AX,CS
  2569.         Mov    DS,AX
  2570.         Mov    ES,AX
  2571.         Mov    BX,TopIndex         ;Contents of 1st top index buck.
  2572.         Mov    DI,BX
  2573.         Mov    CX,Pointer.Beg[BX+DI]
  2574.         Jcxz    SetNext3
  2575.         Dec    CX
  2576.         Dec    CX
  2577.         Cmp    CX,PointerEnd[BX]
  2578.         Jb    SetNext3
  2579.         Mov    Pointer.Beg[BX+DI],CX
  2580.         Jmp Short SetJEqSegNumb
  2581. SetNext3:    Sub    SegNumb,2
  2582.         Js    WriteFin
  2583.         Mov    CX,SegNumb
  2584.         Shr    CX,1             ;Ct of TopIndex bucks.
  2585.         Inc    CX
  2586.         Mov    DI,Offset TopIndex     ;Pt to 1st TopIndex buck.
  2587.         Lea    SI,[DI+2]        ;Pt to 2nd TopIndex buck.
  2588.         Rep Movsw
  2589.         Jmp    WriteLowRcd
  2590. SetJEqSegNumb:    Mov    CX,SegNumb          ;Pt to last TopIndex buck.
  2591.         Jcxz    WriteLowRcd
  2592.         Jmp    NextLowJ
  2593. WriteFin:    Call    WriteBuffer
  2594.         Mov    BX,CS:WriteHandle
  2595.         Cmp    CS:FinalOutput,0
  2596.         Jz    NotFinalOp
  2597.         Cmp    CS:GotCtrlZ,0
  2598.         Jz    CloseOutput
  2599.         Mov    AX,CS
  2600.         Mov    DS,AX
  2601.         Mov    DX,Offset PrtCtrlZ
  2602.         Mov    CX,1
  2603.         Mov    AH,Write
  2604.         Int    DOS
  2605. CloseOutput:    Mov    BX,WriteHandle
  2606.         Cmp    BX,StdOutput
  2607.         Jz    WriteRet
  2608.         Mov    AX,Close
  2609.         Int    DOS
  2610.         Jmp Short WriteRet
  2611. NotFinalOp:    Mov    AX,GetFileLoc
  2612.         Xor    CX,CX
  2613.         Mov    DX,CX
  2614.         Int    DOS
  2615.         Jc    DiskError61
  2616.         Mov    SI,CS:BlockEnd
  2617.         Mov    DS,CS:BlockSeg
  2618.         Mov    Word Ptr[SI],AX
  2619.         Mov    Word Ptr[SI+2],DX
  2620.         Inc    CS:BlockCt
  2621.         Sub    SI,4
  2622.         Jnc    StoreBlockEnd
  2623.         Dec    CS:BlockSeg
  2624.         Add    CS:BlockBeg,10H
  2625.         Add    SI,10H
  2626. StoreBlockEnd:    Mov    CS:BlockEnd,SI
  2627.         Mov    AX,CS:BlockSeg
  2628.         Mov    CS:LastSeg,AX
  2629. WriteRet:    Mov    AX,CS
  2630.         Mov    DS,AX
  2631.         Mov    ES,AX
  2632.         Mov    SI,OrigStart
  2633.         Mov    CS:Word Ptr[SI+4],0FE39H
  2634.         Mov    CS:Byte Ptr[SI+6],0C3H
  2635.         Ret
  2636. ;
  2637. WriteBuffer:    Mov    DS,CS:WriteBuff.Segm
  2638.         Mov    CX,CS:WriteBuff.Beg ;Len to write.
  2639.         Jcxz    WriteBufferRet
  2640.         Xor    DX,DX
  2641. WriteBuffer2:    Mov    CS:PrevBuffOfs,0FFFFH
  2642.         Mov    BX,CS:WriteHandle    ;Write to std op.
  2643.         Mov    AH,Write
  2644.         Int    DOS
  2645.         Jc    DiskError62          ;Err msg if write NG.
  2646.         Cmp    AX,CX
  2647.         Jnz    FullDisk         ;Err if not write req bytes.
  2648.         Mov    CS:WriteBuff.Beg,0
  2649. WriteBufferRet: Ret
  2650. ;
  2651. DiskError61:    Mov    AX,3136H
  2652.         Jmp Short DiskError
  2653. DiskError62:    Mov    AX,3236H
  2654. DiskError:    Mov    DX,Offset DiskErrorMsg
  2655.         Mov    CS:Word Ptr DiskErrorMsg+1,AX
  2656.         Jmp    DisplayExit
  2657. ;
  2658. FullDisk:    Cmp    BX,StdOutput
  2659.         Jz    FullOut
  2660.         Cmp    CS:FinalOutput,0
  2661.         Jnz    FullOut
  2662. FullTemp:    Mov    DX,Offset FullTempMsg
  2663.         Jmp    DisplayExit
  2664. FullOut:    Mov    DX,Offset FullOutMsg
  2665.         Jmp    DisplayExit
  2666. ;
  2667. WriteData    Endp
  2668. ;
  2669. DoWriteLow    Proc    Near
  2670.         Cmp    CS:ElimDup,0
  2671.         Jz    MoveLine2
  2672.         Les    DI,CS:PrevAddr
  2673.         Mov    CS:PrevOfs,SI
  2674.         Mov    CS:PrevSeg,DS
  2675.         Cmp    DI,0FFFFH
  2676.         Jnz    DoCheckDup
  2677.         Mov    DI,CS:PrevBuffOfs
  2678.         Cmp    DI,0FFFFH
  2679.         Jz    MoveLine2
  2680.         Mov    ES,CS:WriteBuff.Segm
  2681.         Cmp    CS:FinalOutput,0
  2682.         Jz    DoCheckDup
  2683.         Cmp    CS:FixedLen,0
  2684.         Jnz    DoCheckDup
  2685.         Mov    CX,CS:WriteBuff.Beg
  2686.         Sub    CX,DI        ;Length of last line in write buffer.
  2687.         Dec    CX
  2688.         Dec    CX        ;Length excluding CRLF.
  2689.         Dec    DI
  2690.         Dec    DI        ;Point to where length field should be.
  2691.         Xchg    CX,ES:[DI]    ;Xchg length for current contents.
  2692.         Push    CX
  2693.         Push    DI
  2694.         Mov    DX,SI
  2695.         Call    CompRoutine
  2696.         Sahf
  2697.         Mov    SI,DX
  2698.         Pop    DI
  2699.         Pop    CX
  2700.         Mov    ES:[DI],CX    ;Restore contents of bucket.
  2701.         Jnz    MoveLine2
  2702.         Clc
  2703.         Ret
  2704. DoCheckDup:    Mov    DX,SI
  2705.         Call    CompRoutine
  2706.         Sahf
  2707.         Mov    SI,DX
  2708.         Jnz    MoveLine2
  2709.         Clc
  2710.         Ret
  2711. MoveLine2:    Mov    AX,CS:FixedLen
  2712.         Or    AX,AX
  2713.         Jnz    MoveLine4
  2714. MoveLine3:    Lodsw                ;AX = line len.
  2715.         Inc    AX
  2716.         Inc    AX               ;Len of line + CRLF.
  2717. MoveLine4:    Mov    CX,CS:WriteBuffEnd
  2718.         Les    DI,CS:WriteBuff
  2719.         Sub    CX,DI           ;Remain space in buffer.
  2720.         Sub    CX,AX
  2721.         Xchg    CX,AX            ;CX = Line len.
  2722.         Jae    RoomForLine          ;Jmp if enough space in buff.
  2723.         Or    DI,DI            ;Chk if data in buff.
  2724.         Jz    WriteInPlace         ;Jmp if nothing in buff.
  2725.         Call    WriteBuffer          ;OK if something in buff.
  2726.         Mov    CS:PrevOfs,0FFFFH ;Don't compare line to itself.
  2727.         Stc
  2728.         Ret
  2729. RoomForLine:    Mov    CS:PrevBuffOfs,DI
  2730.         Add    CS:WriteBuff.Beg,CX
  2731.         Cmp    CS:FinalOutput,0
  2732.         Jnz    RoomForLine1
  2733.         Sub    SI,CS:LenBuckSize
  2734.         Jmp Short RoomForLine1B
  2735. RoomForLine1:    Cmp    CS:FixedLen,0
  2736.         Jz    RoomForLine2
  2737. RoomForLine1B:    Shr    CX,1
  2738.         Jnc    MoveWords1
  2739.         Movsb
  2740. MoveWords1:    Rep Movsw
  2741.         Clc
  2742.         Ret
  2743. RoomForLine2:    Shr    CX,1
  2744.         Dec    CX
  2745.         Jnc    MoveWords2
  2746.         Movsb
  2747. MoveWords2:    Rep Movsw
  2748.         Mov    AX,CS:LineEnd
  2749.         Stosw                ;Move CRLF to buff.
  2750.         Clc
  2751.         Ret
  2752. WriteInPlace:    Cmp    CS:FinalOutput,0
  2753.         Jnz    DoWrtInPlace1
  2754.         Sub    SI,CS:LenBuckSize
  2755.         Mov    DX,SI
  2756.         Call    WriteBuffer2
  2757.         Clc
  2758.         Ret
  2759. DoWrtInPlace1:    Mov    DX,SI
  2760.         Cmp    CS:FixedLen,0
  2761.         Jz    DoWrtInPlace2
  2762.         Call    WriteBuffer2
  2763.         Clc
  2764.         Ret
  2765. DoWrtInPlace2:    Add    SI,CX
  2766.         Mov    AX,CS:LineEnd
  2767.         Xchg    Word Ptr[SI-2],AX
  2768.         Push    AX
  2769.         Call    WriteBuffer2
  2770.         Pop    AX
  2771.         Mov    Word Ptr[SI-2],AX
  2772.         Clc
  2773.         Ret
  2774. DoWriteLow    Endp
  2775. ;
  2776. WriteDataM    Proc    Near
  2777.         Call    WriteSetup
  2778.         Cmp    CS:SkipSetupTop,0
  2779.         Jz    WriteLowRcdM
  2780.         Jmp    SetJEqSegNumbM
  2781. NextLowJM:    Inc    CX
  2782.         Inc    CX        ;CH = 0, CL SegNumb + 2.
  2783.         Mov    BX,CX
  2784.         Shr    BX,1
  2785.         And    BL,0FEH          ;First trial TopIndex.
  2786.         Mov    SI,CS:TopIndex         ;Contents of Jth TopIndex buck.
  2787.         Push    SI             ;Will insert this in proper buck.
  2788.         Shl    SI,1
  2789.         Lds    SI,CS:Data[SI]         ;DS:SI pts low rcd in data seg.
  2790. NextLowIM:    Mov    DI,CS:TopIndex[BX]     ;Contents of Jth TopIndex buck.
  2791.         Shl    DI,1
  2792.         Les    DI,CS:Data[DI]      ;ES:DI pts low rcd in data seg.
  2793.         Push    CX
  2794.         Mov    BP,BX
  2795.         Mov    DX,SI
  2796.         Call    CompRoutine
  2797.         Mov    SI,DX
  2798.         Mov    BX,BP
  2799.         Pop    CX
  2800.         Jnc    GoUpM
  2801. GoDownM:    Mov    CL,BL
  2802.         Add    BL,CH
  2803.         Shr    BL,1
  2804.         And    BL,0FEH
  2805.         Cmp    BL,CH
  2806.         Ja    NextLowIM
  2807.         Jmp Short FoundPosM
  2808. GoUpM:        Mov    CH,BL
  2809.         Add    BL,CL
  2810.         Shr    BL,1
  2811.         And    BL,0FEH
  2812.         Cmp    BL,CH
  2813.         Ja    NextLowIM
  2814. FoundPosM:    Mov    CX,BX
  2815.         Shr    CX,1
  2816.         Mov    DI,Offset TopIndex
  2817.         Lea    SI,[DI+2]
  2818.         Mov    AX,CS
  2819.         Mov    ES,AX
  2820.         Mov    DS,AX
  2821.         Rep Movsw
  2822.         Pop    BP
  2823.         Mov    [DI],BP
  2824. WriteLowRcdM:    Mov    SI,CS:TopIndex       ;Index in 0th buck.
  2825.         Shl    SI,1
  2826.         Lds    SI,CS:Data[SI]        ;DS:SI pts low rcd in data seg.
  2827.         Call    DoWriteLow
  2828.         Jc    WriteLowRcdM
  2829. SetNextSearchM: Mov    AX,CS
  2830.         Mov    DS,AX
  2831.         Mov    ES,AX
  2832.         Mov    BX,TopIndex         ;Contents of 1st top index buck.
  2833.         Mov    DI,BX
  2834.         Mov    SI,Data.Beg[BX+DI]
  2835.         Mov    CX,FixedLen
  2836.         Jcxz    SetNext2BM
  2837.         Add    SI,CX      ;Offset of next line in segment.
  2838.         Mov    Data.Beg[BX+DI],SI
  2839.         Cmp    SI,DataEnd[BX]
  2840.         Jae    WriteFinM
  2841.         Jmp Short SetJEqSegNumbM
  2842. SetNext2BM:    Mov    DS,Data.Segm[BX+DI]
  2843.         Lodsw
  2844.         Add    SI,AX      ;Offset of next line in segment.
  2845.         Mov    CS:Data.Beg[BX+DI],SI
  2846.         Cmp    SI,CS:DataEnd[BX]
  2847.         Jae    WriteFinM
  2848.         Lodsw
  2849.         Add    SI,AX
  2850.         Jc    WriteFinM
  2851.         Cmp    SI,CS:DataEnd[BX]
  2852.         Ja    WriteFinM
  2853.         Mov    CX,CS
  2854.         Mov    DS,CX
  2855. SetJEqSegNumbM: Mov    CX,CS:SegNumb          ;Pt to last TopIndex buck.
  2856.         Jcxz    WriteLowRcdM
  2857.         Jmp    NextLowJM
  2858. WriteFinM:    Ret
  2859. ;
  2860. WriteDataM    Endp
  2861. ;
  2862. MergeData    Proc    Near
  2863. ;
  2864.         Mov    SI,CS:OrigStart
  2865.         Mov    CS:Word Ptr[SI+4],0DB8CH
  2866.         Mov    CS:Byte Ptr[SI+6],08CH
  2867.         Mov    CS:UseRcdLen,0FFH
  2868. ;
  2869. ;Repeat  {Until BlockCt = 1}
  2870. ;
  2871. ;  Initialize NewBlockBeg, NewBlockEnd and NewBlockSeg
  2872. MergeData1:    Mov    AX,CS:BlockSeg
  2873.         Mov    CS:LastSeg,AX
  2874.         Mov    CS:NewBlockBeg,0008H
  2875.         Mov    CS:NewBlockEnd,0008H
  2876.         Mov    AX,CS:MemoryEndSeg
  2877.         Dec    AX
  2878.         Mov    CS:NewBlockSeg,AX
  2879.         Mov    AX,CS:LastSeg
  2880.         Sub    AX,CS:MemoryBegSeg
  2881.         Sub    AX,CS:MergeBuff
  2882.         Mov    BX,CS:LongestLen
  2883.         Add    BX,15
  2884.         Mov    CL,4
  2885.         Shr    BX,CL
  2886.         Mov    CX,CS:MergeSeg    ;Minimum for segment.
  2887.         Cmp    CX,BX
  2888.         Jae    CompMaxSegCt
  2889.         Mov    CX,BX
  2890. CompMaxSegCt:    Xor    DX,DX
  2891.         Div    CX
  2892.         Cmp    AX,2
  2893.         Jae    StoreMaxSegCt
  2894.         Or    AX,AX
  2895.         Jz    CompMaxSegCt2
  2896.         Mov    AX,CX
  2897. CompMaxSegCt2:    Add    AX,DX        ;Recover avail mem paragraphs.
  2898.         Shr    AX,1        ;Half of avail mem paragraphs.
  2899.         Cmp    AX,BX
  2900.         Jbe    TwoRcdNG    ;Jmp if not room for two records.
  2901.         Mov    AX,2        ;Else set two segments.
  2902.         Jmp Short StoreMaxSegCt
  2903. TwoRcdNG:    Jmp    DoTwoRcdMsg    ;Error if not room for two data seg.
  2904. StoreMaxSegCt:    Mov    CS:MaxSegCount,AX
  2905. ;
  2906. ;  HowManySegs = the minimum of:
  2907. ;  a. 64
  2908. ;  b. BlockCt
  2909. ;  c. MaxSegCount
  2910. ;
  2911.         Mov    BP,CS:BlockCT
  2912.         Cmp    BP,AX
  2913.         Jbe    MergeData2
  2914.         Xchg    BP,AX
  2915. MergeData2:    Cmp    BP,64
  2916.         Jbe    MergeData3
  2917.         Mov    BP,64
  2918. MergeData3:    Mov    CS:HowManySegs,BP
  2919. ;
  2920. ;  Swap WriteHandle with ReadHandle.
  2921.         Mov    BX,CS:WriteHandle
  2922.         Xchg    BX,CS:ReadHandle
  2923.         Mov    CS:WriteHandle,BX
  2924. ;
  2925. ;  Truncate WriteHandle file.
  2926.         Cmp    CS:FirstMerge,0
  2927.         Jnz    MergeData3B
  2928.         Call    TruncFile
  2929. ;
  2930. ;  NewBlockCt = (BlockCt) / HowManySegs.
  2931. ;  Since HowManySegs LE BlockCt, NewBlockCt GE 1.
  2932. MergeData3B:    Mov    CS:FirstMerge,0
  2933.         Mov    CS:UseExtra,0
  2934.         Mov    CS:LastIsExtra,0
  2935.         Mov    AX,CS:BlockCt
  2936.         Xor    DX,DX
  2937.         Div    CS:HowManySegs
  2938.         Mov    CS:NewBlockCt,AX
  2939.         Mov    CS:RemainderSegs,DX
  2940. ;
  2941. ;  If RemainderSegs <> 0 and NewBlockCT = 1 then:
  2942. ;     a. ThisTimeSegs = RemainderSegs + 1.
  2943. ;     b. BegBlock = BlockCt - RemainderSegs - 1.
  2944. ;     c. Swap WriteHandle with ExtraHandle.
  2945. ;     d. Truncate ExtraHandle file.
  2946. ;     e. Call CalcMaxSegSize.
  2947. ;     f. Call MergeOneBlock.
  2948. ;     g. Call WriteBuffer.
  2949. ;     h. Set UseExtra = 0FFH.
  2950. ;     i. Swap WriteHandle with ExtraHandle.
  2951. ;     j. Store length of extra file in ExtraEnd.
  2952. ;     k. Reduce length of write file by ExtraEnd.
  2953. ;     l. RemainderSegs = 0.
  2954.         Or    DX,DX
  2955.         Jnz    MergeData5H1
  2956. JmpMergeData5I: Jmp    MergeData5I    ;Jump if RemainderSegs = 0.
  2957. MergeData5H1:    Cmp    AX,1
  2958.         Jnz    JmpMergeData5I    ;Jump if NewBlockCt <> 1.
  2959.         Inc    DX
  2960.         Mov    CS:ThisTimeSegs,DX ;Will merge RemainderSegs + 1.
  2961.         Mov    AX,CS:BlockCT
  2962.         Sub    AX,DX
  2963.         Mov    CS:BegBlock,AX
  2964.         Mov    BX,CS:WriteHandle
  2965.         Xchg    BX,CS:ExtraHandle
  2966.         Mov    CS:WriteHandle,BX
  2967.         Cmp    CS:FirstExtra,0
  2968.         Jnz    MergeData5H
  2969.         Call    TruncFile
  2970. MergeData5H:    Mov    CS:FirstExtra,0
  2971.         Call    CalcMaxSegSize
  2972.         Call    MergeOneBlock
  2973.         Call    WriteBuffer
  2974.         Mov    CS:UseExtra,0FFH
  2975. ;
  2976.         Mov    AX,GetFileLen
  2977.         Mov    BX,CS:WriteHandle
  2978.         Xor    CX,CX
  2979.         Mov    DX,CX
  2980.         Int    DOS
  2981.         Jnc    SaveExtraEnd
  2982. DoError73:    Mov    AX,3337H
  2983.         Jmp    DiskError
  2984. SaveExtraEnd:    Mov    CS:Word Ptr ExtraEnd,AX
  2985.         Mov    CS:Word Ptr ExtraEnd+2,DX
  2986. ;
  2987.         Mov    BX,CS:WriteHandle
  2988.         Xchg    BX,CS:ExtraHandle
  2989.         Mov    CS:WriteHandle,BX
  2990. ;
  2991.         Mov    SI,CS:BegBlock
  2992.         Dec    SI
  2993.         Call    GetFileLocn
  2994.         Mov    BX,CS:ReadHandle    ;CX:DX = New read file size.
  2995.         Call    TruncFile2
  2996.         Mov    CS:RemainderSegs,0
  2997. ;
  2998. ;  Get MaxSegSize for the merge down to NewBlockCt.
  2999. MergeData5I:    Mov    AX,CS:HowManySegs
  3000.         Mov    CS:ThisTimeSegs,AX
  3001.         Call    CalcMaxSegSize
  3002. ;
  3003. ;  If NewBlockCt <> 1 go and merge the blocks
  3004. ;   else close and delete WriteHandle
  3005. ;     set WriteHandle = output file.
  3006.         Cmp    CS:NewBlockCt,1
  3007.         Jnz    MergeData5L
  3008.         Mov    CS:FinalOutput,0FFH
  3009. ;  Close and delete the WriteHandle file.
  3010.         Mov    BX,CS:WriteHandle
  3011.         Mov    DX,Offset TempName1
  3012.         Cmp    BX,CS:TempHandle1
  3013.         Jz    MergeData5C2
  3014.         Mov    DX,Offset TempName2
  3015.         Mov    CS:TempHandle2,0
  3016.         Jmp Short MergeData5D
  3017. MergeData5C2:    Mov    CS:TempHandle1,0
  3018. MergeData5D:    Mov    AX,CS
  3019.         Mov    DS,AX
  3020.         Call    CloseDelete
  3021. ;  WriteHandle = output file handle.
  3022.         Cmp    CS:GotOutput,0
  3023.         Jz    UseStdOp
  3024.         Call    OpenOutput
  3025.         Jmp Short MergeData5L
  3026. UseStdOp:    Mov    CS:WriteHandle,StdOutput
  3027. ;
  3028. ;  If RemainderSegs <> 0 then NewBlockCt = NewBlockCt + 1
  3029. ;             else RemainderSegs = HowManySegs.
  3030. MergeData5L:    Cmp    CS:RemainderSegs,0
  3031.         Jz    MergeData5J
  3032.         Inc    CS:NewBlockCt
  3033.         Jmp Short MergeData6
  3034. MergeData5J:    Mov    CX,CS:HowManySegs
  3035.         Mov    CS:RemainderSegs,CX
  3036. ;
  3037. ;  For N = NewBlockCt - 1 To 0 Step -1
  3038. MergeData6:    Mov    CX,CS:NewBlockCT
  3039.         Dec    CX
  3040. MergeData7:    Push    CX
  3041. ;
  3042. ;  If N = 0 and UseExtra = 0FFH then LastIsExtra = 0FFH.
  3043. ;  If N = 0 ThisTimeSegs = RemainderSegs
  3044.         Or    CX,CX
  3045.         Jnz    MergeData8
  3046.         Mov    AX,CS:RemainderSegs
  3047.         Cmp    AX,CS:ThisTimeSegs
  3048.         Jz    MergeData7B
  3049.         Mov    CS:ThisTimeSegs,AX
  3050.         Push    CX
  3051.         Call    CalcMaxSegSize
  3052.         Pop    CX
  3053. MergeData7B:    Cmp    CS:UseExtra,0
  3054.         Jz    MergeData8
  3055.         Mov    CS:LastIsExtra,0FFH
  3056. ;
  3057. ;    BegBlock = (NewBlockCt - N - 1) * HowManySegs
  3058. MergeData8:    Mov    AX,CS:NewBlockCt
  3059.         Dec    AX
  3060.         Sub    AX,CX
  3061.         Mul    CS:HowManySegs
  3062.         Mov    CS:BegBlock,AX
  3063.         Add    AX,CS:ThisTimeSegs
  3064.         Dec    AX
  3065.         Mov    CS:EndBlock,AX
  3066. ;
  3067.         Call    MergeOneBlock
  3068. ;
  3069. ;    We come here when we when have finished one of the new blocks. Just as was
  3070. ;    done by WriteData we must save the ending position of the new block in the
  3071. ;    block table (reusing one of the buckets used for one of the old blocks)
  3072. ;    and must store the new blockend blockbeg and blockseg values.  Since the
  3073. ;    old values are still needed, we store them in NewBlockEnd, NewBlockBeg and
  3074. ;    NewBlockSeg.
  3075. MergeData17:    Call    WriteBuffer
  3076.         Cmp    CS:FinalOutput,0
  3077.         Jnz    MergeData19
  3078. ;
  3079.         Mov    AX,GetFileLen
  3080.         Mov    BX,CS:WriteHandle
  3081.         Xor    CX,CX
  3082.         Mov    DX,CX
  3083.         Int    DOS
  3084.         Jnc    SaveWriteEnd
  3085. DoError74:    Mov    AX,3437H
  3086.         Jmp    DiskError
  3087. SaveWriteEnd:    Mov    SI,CS:NewBlockEnd
  3088.         Mov    DS,CS:NewBlockSeg
  3089.         Mov    Word Ptr[SI],AX
  3090.         Mov    Word Ptr[SI+2],DX
  3091.         Sub    SI,4
  3092.         Jnc    MergeData18
  3093.         Dec    CS:NewBlockSeg
  3094.         Add    CS:NewBlockBeg,10H
  3095.         Add    SI,10H
  3096. MergeData18:    Mov    CS:NewBlockEnd,SI
  3097. ;
  3098. ;  Next N
  3099. MergeData19:    Pop    CX
  3100.         Dec    CX
  3101.         Js    MergeData19B
  3102.         Jmp    MergeData7
  3103. ;
  3104. ;  BlockCt = NewBlockCt:   BlockEnd = NewBlockEnd
  3105. ;  BlockBeg = NewBlockBeg: BlockSeg = NewBlockSeg
  3106. MergeData19B:    Mov    AX,CS:NewBlockEnd
  3107.         Mov    CS:BlockEnd,AX
  3108.         Mov    AX,CS:NewBlockBeg
  3109.         Mov    CS:BlockBeg,AX
  3110.         Mov    AX,CS:NewBlockSeg
  3111.         Mov    CS:BlockSeg,AX
  3112.         Mov    AX,CS:NewBlockCt
  3113.         Mov    CS:BlockCt,AX
  3114. ;
  3115. ;Until BlockCt = 1
  3116.         Cmp    AX,1
  3117.         Jz    MergeData19C
  3118.         Jmp    MergeData1
  3119. ;
  3120. ;Write CtrlZ if input file had one.
  3121. MergeData19C:    Mov    AX,CS
  3122.         Mov    DS,AX
  3123.         Cmp    GotCtrlZ,0
  3124.         Jz    MergeData19C2
  3125.         Mov    DX,Offset PrtCtrlZ
  3126.         Mov    CX,1
  3127.         Mov    BX,WriteHandle
  3128.         Mov    AH,Write
  3129.         Int    DOS
  3130. ;Close the output file if it is not the standard output.
  3131. MergeData19C2:    Mov    BX,WriteHandle
  3132.         Cmp    BX,StdOutput
  3133.         Jz    MergeData19D
  3134.         Mov    AX,Close
  3135.         Int    DOS
  3136. ;Close and delete the ReadHandle and ExtraHandle files.
  3137. MergeData19D:    Cmp    NeedMerge,0
  3138.         Jz    MergeDataRet
  3139.         Mov    BX,ReadHandle
  3140.         Mov    DX,Offset TempName1
  3141.         Cmp    BX,TempHandle1
  3142.         Jz    MergeData19E
  3143.         Mov    DX,Offset TempName2
  3144.         Mov    TempHandle2,0
  3145.         Jmp Short MergeData20
  3146. MergeData19E:    Mov    TempHandle1,0
  3147. MergeData20:    Call    CloseDelete
  3148.         Mov    BX,ExtraHandle
  3149.         Mov    ExtraHandle,0
  3150.         Mov    DX,Offset TempName3
  3151.         Call    CloseDelete
  3152. MergeDataRet:    Ret
  3153. ;
  3154. MergeData    Endp
  3155. ;
  3156. TruncFile    Proc    Near
  3157.         Xor    CX,CX
  3158.         Mov    DX,CX
  3159. TruncFile2:    Mov    AX,SetFileAtBeg
  3160.         Int    DOS
  3161.         Jc    TruncNg63
  3162.         Mov    AH,Write
  3163.         Xor    CX,CX
  3164.         Int    DOS
  3165.         Jc    TruncNG64
  3166.         Or    AX,AX
  3167.         Jnz    TruncNg65
  3168.         Ret
  3169. TruncNg63:    Mov    AX,3336H
  3170.         Jmp    DiskError
  3171. TruncNg64:    Mov    AX,3436H
  3172.         Jmp    DiskError
  3173. TruncNg65:    Mov    AX,3536H
  3174.         Jmp    DiskError
  3175. TruncFile    Endp
  3176. ;
  3177. GetFileLocn    Proc    Near
  3178.         Mov    DS,CS:BlockSeg
  3179.         Mov    BX,CS:BlockBeg
  3180.         Shl    SI,1
  3181.         Shl    SI,1
  3182.         Sub    BX,SI
  3183.         Mov    DX,[BX]
  3184.         Mov    CX,[BX+2]    ;CX:DX = Loc in file.
  3185.         Ret
  3186. GetFileLocn    Endp
  3187. ;
  3188. CalcMaxSegSize    Proc    Near
  3189. ;
  3190. ;  MaxSegSize = Minimum of:
  3191. ;  a. (Avail Mem - MinBuff) / ThisTimeSegs
  3192. ;  b. 64K (1000H paragraphs).
  3193. ;
  3194.         Mov    AX,CS:LastSeg
  3195.         Sub    AX,CS:MemoryBegSeg
  3196.         Sub    AX,CS:MergeBuff
  3197.         Xor    DX,DX
  3198.         Div    CS:ThisTimeSegs
  3199.         Mov    BX,CS:DataPara
  3200.         Cmp    AX,BX
  3201.         Jb    MergeData4
  3202.         Mov    AX,CS:DataMax
  3203.         Jmp Short MergeData5
  3204. MergeData4:    Mov    CL,4
  3205.         Shl    AX,CL
  3206.         Mov    CX,CS:FixedLen
  3207.         Jcxz    MergeData5
  3208.         Xor    DX,DX
  3209.         Div    CX
  3210.         Mul    CX
  3211. MergeData5:    Mov    CS:MaxSegSize,AX
  3212.         Ret
  3213. CalcMaxSegSize    Endp
  3214. ;
  3215. MergeOneBlock    Proc    Near
  3216. ;    SegCount = HowManySegs
  3217.         Mov    AX,CS:ThisTimeSegs
  3218.         Shl    AX,1
  3219.         Mov    CS:SegCount,AX
  3220. ;
  3221. ;    NextSeg = MemoryBegSeg
  3222.         Mov    AX,CS:MemoryBegSeg
  3223.         Mov    CS:NextSeg,AX
  3224. ;
  3225. ;    If LastIsExtra = 0FFH
  3226. ;    then MaxSegs = ThisTimeSegs - 2
  3227. ;    else MaxSegs = ThisTimeSegs - 1.
  3228.         Mov    AX,CS:ThisTimeSegs
  3229.         Dec    AX
  3230.         Cmp    CS:LastIsExtra,0
  3231.         Jz    StoreMaxSegs
  3232.         Dec    AX
  3233. StoreMaxSegs:    Mov    CS:MaxSegs,AX
  3234. ;
  3235. ;    For M = 0 To MaxSegs
  3236.         Xor    CX,CX
  3237.         Mov    CS:SkipSetupTop,0
  3238. ;
  3239. ;      If BlockLen(BegBlock + M) >= MaxSegSize Then
  3240. ;     SegLen(M) = MaxSegSize
  3241. ;      Else
  3242. ;     SegLen(M) = BlockLen(BegBlock + M)
  3243. ;      EndIf
  3244. MergeData9:    Push    CX
  3245.         Mov    DS,CS:BlockSeg
  3246.         Mov    BX,CS:BlockBeg
  3247.         Mov    DI,CX
  3248.         Shl    DI,1
  3249.         Shl    DI,1        ;4 * M
  3250.         Mov    AX,CS:BegBlock
  3251.         Shl    AX,1
  3252.         Shl    AX,1        ;4 * BegBlock
  3253.         Sub    BX,AX
  3254.         Sub    BX,DI        ;Point to table entry for BegBlock + M.
  3255.         Mov    AX,[BX]
  3256.         Mov    DX,[BX+2]    ;Location of end of block.
  3257.         Mov    SI,[BX+4]
  3258.         Mov    BP,[BX+6]    ;Location of beg of block.
  3259.         Call    ReadOneBlock
  3260. ;
  3261. ;      BlockOfs(M) = SegLen(M)
  3262. MergeData11B:    Pop    DI        ;Recover M.
  3263.         Mov    AX,DI        ;Hold M.
  3264.         Shl    DI,1
  3265.         Shl    DI,1        ;Point to BlockOfs bucket.
  3266.         Mov    CS:Word Ptr BlockOfs[DI],CX
  3267.         Mov    CS:Word Ptr BlockOfs[DI+2],0
  3268. ;
  3269. ;    Next M
  3270.         Mov    CX,AX
  3271.         Inc    CX
  3272.         Cmp    CX,CS:MaxSegs
  3273.         Jbe    MergeData9
  3274. ;
  3275. MergeData11C:    Cmp    CS:LastIsExtra,0
  3276.         Jz    DoMergeWrite1
  3277.         Mov    DI,CX
  3278.         Push    DI
  3279.         Shl    DI,1
  3280.         Mov    CS:ExtraNumb,DI
  3281.         Shl    DI,1        ;4 * M
  3282.         Mov    AX,CS:Word Ptr ExtraEnd
  3283.         Mov    DX,CS:Word Ptr ExtraEnd+2 ;Location of end of block.
  3284.         Xor    SI,SI
  3285.         Mov    BP,SI            ;Location of beg of block.
  3286.         Mov    BX,CS:ReadHandle
  3287.         Xchg    BX,CS:ExtraHandle
  3288.         Mov    CS:ReadHandle,BX
  3289.         Call    ReadOneBlock
  3290.         Mov    BX,CS:ReadHandle
  3291.         Xchg    BX,CS:ExtraHandle
  3292.         Mov    CS:ReadHandle,BX
  3293. ;
  3294. ;      BlockOfs(M) = SegLen(M)
  3295.         Pop    DI        ;Recover M.
  3296.         Shl    DI,1
  3297.         Shl    DI,1        ;Point to BlockOfs bucket.
  3298.         Mov    CS:Word Ptr BlockOfs[DI],CX
  3299.         Mov    CS:Word Ptr BlockOfs[DI+2],0
  3300. ;
  3301. DoMergeWrite1:    Mov    CS:PrevOfs,0FFFFH
  3302. DoMergeWrite:    Call    WriteDataM
  3303.         Mov    CS:SkipSetupTop,0FFH
  3304. ;
  3305. ;    Empty = TopIndex(1)
  3306.         Mov    BX,CS:TopIndex
  3307. ;
  3308. ;    Check for partial line, if any, and move to beginning of segment.
  3309.         Mov    CX,CS:DataEnd[BX]
  3310.         Shl    BX,1
  3311.         Mov    SI,CS:Data.Beg[BX]
  3312.         Sub    CX,SI
  3313.         Je    MergeData12    ;Jump if no partial line.
  3314.         Xor    DI,DI
  3315.         Mov    AX,CS:Data.Segm[BX]
  3316.         Mov    DS,AX
  3317.         Mov    ES,AX
  3318.         Shr    CX,1
  3319.         Jnc    PartWords
  3320.         Movsb
  3321. PartWords:    Rep Movsw
  3322.         Mov    CS:Data.Beg[BX],DI
  3323.         Jmp Short MergeData12B
  3324. ;
  3325. ;    If BlockLen(Empty) <= BlockOfs(Empty) Then
  3326. ;      SegCount = SegCount - 1
  3327. ;      If SegCount > 0 Then
  3328. ;     Goto DoMergeWrite
  3329. ;      Else
  3330. ;     Goto FinishNewBlock
  3331. ;      EndIf
  3332. ;    EndIf
  3333. MergeData12:    Mov    CS:Data.Beg[BX],0
  3334. MergeData12B:    Mov    AX,CS:Word Ptr BlockLen[BX]
  3335.         Mov    DX,CS:Word Ptr BlockLen[BX+2]
  3336.         Sub    AX,CS:Word Ptr BlockOfs[BX]
  3337.         Sbb    DX,CS:Word Ptr BlockOfs[BX+2]
  3338.         Jb    MergeData13
  3339.         Mov    CX,DX
  3340.         Or    CX,AX
  3341.         Jnz    MergeData14
  3342. MergeData13:    Cmp    CS:Data.Beg[BX],0
  3343.         Jnz    MergeData14
  3344.         Cmp    CS:LastIsExtra,0
  3345.         Jz    MergeData13B
  3346.         Shr    BX,1
  3347.         Cmp    BX,CS:ExtraNumb
  3348.         Jnz    MergeData13B
  3349.         Mov    CS:LastIsExtra,0
  3350. MergeData13B:    Sub    CS:SegCount,2
  3351.         Jz    JmpMergeOneRet
  3352.         Mov    AX,CS
  3353.         Mov    DS,AX
  3354.         Mov    ES,AX
  3355.         Mov    BX,TopIndex
  3356.         Mov    CX,SegCount
  3357.         Shr    CX,1
  3358.         Mov    DI,Offset TopIndex
  3359.         Lea    SI,[DI+2]
  3360.         Rep Movsw
  3361.         Mov    [DI],BX
  3362.         Jmp    DoMergeWrite
  3363. JmpMergeOneRet: Jmp    MergeOneRet
  3364. ;
  3365. ;    If BlockLen(Empty) - BlockOfs(Empty) >= MaxSegSize Then
  3366. ;     SegLen(Empty) = SegMax
  3367. ;    Else
  3368. ;     SegLen(Empty) = BlockLen(BegBlock + Empty) - BlockOfs(BegBlock + Empty);
  3369. ;    EndIf
  3370. MergeData14:    Add    AX,CS:Data.Beg[BX]
  3371.         Adc    DX,0
  3372.         Or    DX,DX
  3373.         Jnz    MergeData15
  3374.         Cmp    AX,CS:MaxSegSize
  3375.         Jbe    MergeData16
  3376. MergeData15:    Mov    AX,CS:MaxSegSize
  3377. ;
  3378. ;    Read SegLen(Empty) bytes from Block(BegBlock + Empty) into Seg(Empty)
  3379. ;    BlockOfs(Empty) = BlockOfs(Empty) + SegLen(Empty)
  3380. ;    Goto DoMergeWrite
  3381. MergeData16:    Shr    BX,1
  3382.         Mov    CS:DataEnd[BX],AX
  3383.         Push    AX
  3384.         Mov    AX,CS:ReadHandle
  3385.         Mov    CS:UseHandle,AX
  3386.         Cmp    CS:LastIsExtra,0
  3387.         Jz    MergeData16B
  3388.         Cmp    BX,CS:ExtraNumb
  3389.         Jnz    MergeData16B
  3390.         Mov    AX,CS:ExtraHandle
  3391.         Mov    CS:UseHandle,AX
  3392. MergeData16B:    Mov    AX,SetFileAtBeg
  3393.         Shl    BX,1
  3394.         Mov    DX,CS:Word Ptr BlockPos[BX]
  3395.         Mov    CX,CS:Word Ptr BlockPos[BX+2]
  3396.         Add    DX,CS:Word Ptr BlockOfs[BX]
  3397.         Adc    CX,CS:Word Ptr BlockOfs[BX+2]
  3398.         Push    BX
  3399.         Mov    BX,CS:UseHandle
  3400.         Int    DOS
  3401.         Jc    GoNgWrite66
  3402.         Pop    BX
  3403.         Pop    CX
  3404.         Mov    DX,CS:Data.Beg[BX]
  3405.         Mov    CS:Data.Beg[BX],0
  3406.         Sub    CX,DX
  3407.         Add    CS:Word Ptr BlockOfs[BX],CX
  3408.         Adc    CS:Word Ptr BlockOfs[BX+2],0
  3409.         Mov    DS,CS:Data.Segm[BX]
  3410.         Mov    BX,CS:UseHandle
  3411.         Mov    AX,Read
  3412.         Int    DOS
  3413.         Jc    GoNGWrite67
  3414.         Cmp    AX,CX
  3415.         Jne    GoNGWrite68
  3416.         Jmp    DoMergeWrite1
  3417. MergeOneRet:    Ret
  3418. GoNGWrite66:    Mov    AX,3636H
  3419.         Jmp    DiskError
  3420. GoNGWrite67:    Mov    AX,3736H
  3421.         Jmp    DiskError
  3422. GoNGWrite68:    Mov    AX,3836H
  3423.         Jmp    DiskError
  3424. MergeOneBlock    Endp
  3425. ;
  3426. ReadOneBlock    Proc    Near
  3427.         Sub    AX,SI
  3428.         Sbb    DX,BP        ;Length of block.
  3429.         Mov    CS:Word Ptr BlockLen[DI],AX
  3430.         Mov    CS:Word Ptr BlockLen[DI+2],DX
  3431.         Mov    CS:Word Ptr BlockPos[DI],SI
  3432.         Mov    CS:Word Ptr BlockPos[DI+2],BP
  3433.         Jnz    MergeData10
  3434.         Cmp    AX,CS:MaxSegSize
  3435.         Jb    MergeData11
  3436. MergeData10:    Mov    AX,CS:MaxSegSize
  3437. MergeData11:    Shr    DI,1
  3438.         Mov    CS:DataEnd[DI],AX
  3439.         Mov    DX,CS:NextSeg
  3440.         Shl    DI,1
  3441.         Mov    CS:Data.Segm[DI],DX
  3442.         Mov    CS:Data.Beg[DI],0
  3443.         Mov    DI,AX
  3444.         Add    DI,15
  3445.         Mov    CL,4
  3446.         Shr    DI,CL
  3447.         Add    CS:NextSeg,DI
  3448. ;
  3449. ;      Read SegLen(M) bytes from loc zero in Block(BegBlock + M) into Seg(M)
  3450.         Push    DX
  3451.         Push    AX
  3452.         Mov    AX,SetFileAtBeg
  3453.         Mov    DX,SI
  3454.         Mov    CX,BP
  3455.         Mov    BX,CS:ReadHandle
  3456.         Int    DOS
  3457.         Jc    JmpNGWrite69
  3458.         Pop    CX
  3459.         Pop    DS
  3460.         Mov    BX,CS:ReadHandle
  3461.         Mov    AX,Read
  3462.         Xor    DX,DX
  3463.         Int    DOS
  3464.         Jc    JmpNGWrite70
  3465.         Cmp    AX,CX
  3466.         Je    ReadOneBlkRet
  3467. JmpNGWrite69:    Mov    AX,3936H
  3468.         Jmp    DiskError
  3469. JmpNGWrite70:    Mov    AX,3037H
  3470.         Jmp    DiskError
  3471. ReadOneBlkRet:    Ret
  3472. ReadOneBlock    Endp
  3473. ;
  3474. FindMsgEnd    Proc    Near
  3475.         Push    CS
  3476.         Push    CS
  3477.         Pop    DS
  3478.         Pop    ES
  3479.         Cld
  3480.         Push    DX
  3481.         Cmp    GotError,0
  3482.         Jnz    DoWriteERROR
  3483.         Mov    SI,DX
  3484.         Inc    SI
  3485.         Lodsw
  3486.         And    AX,0F0FH
  3487.         Xchg    AH,AL    ;AH = hi digit, AL = lo digit of code.
  3488.         Aad
  3489.         Mov    ErrorCode,AL
  3490.         Call    WriteNewLine
  3491. DoWriteERROR:    Call    WriteERROR
  3492.         Pop    DX
  3493.         Or    GotKeyErr,GotOtherErr
  3494.         Mov    GotError,0FFH
  3495.         Mov    DI,DX        ;Address of message
  3496.         Mov    CX,256
  3497.         Mov    AL,'$'
  3498.         Repne Scasb
  3499.         Dec    DI        ;Point back to '$'.
  3500.         Mov    CX,DI
  3501.         Sub    CX,DX
  3502.         Call    WriteStdError
  3503.         Ret
  3504. FindMsgEnd    Endp
  3505. ;
  3506. DispErrorParm    Proc    Near
  3507.         Push    DS
  3508.         Push    ES
  3509.         Push    CX
  3510.         Push    SI
  3511.         Push    BX
  3512.         Push    AX
  3513.         Call    FindMsgEnd
  3514.         Push    CX        ;Save length of message.
  3515.         Mov    DX,ParmBeg
  3516.         Mov    SI,DX
  3517.         Mov    CX,ParmChars    ;Remaining parm characters.
  3518.         Lodsb
  3519.         Dec    CX
  3520.         Jcxz    EndOfParm
  3521. NextErrorChar:    Lodsb
  3522.         Cmp    AL,Slash
  3523.         Jz    EndOfParm
  3524.         Cmp    AL,Space
  3525.         Jz    EndOfParm
  3526.         Loop    NextErrorChar
  3527.         Jmp Short EndOfParm2
  3528. EndOfParm:    Dec    SI
  3529. EndOfParm2:    Mov    CX,SI
  3530.         Sub    CX,DX
  3531.         Pop    AX        ;Retreive length of message.
  3532.         Add    AX,8        ;Length of " ERROR " plus quote.
  3533.         Cmp    AX,80
  3534.         Jbe    EndOfParm3
  3535.         Sub    AX,80
  3536. EndOfParm3:    Add    AX,CX        ;Add length of parm.
  3537.         Cmp    AX,79
  3538.         Jb    EndOfParm4
  3539.         Push    CX
  3540.         Push    DX
  3541.         Mov    DX,Offset TwelveSpaces
  3542.         Mov    CX,14
  3543.         Call    WriteStdError
  3544.         Pop    DX
  3545.         Pop    CX
  3546. EndOfParm4:    Push    CX
  3547.         Push    DX
  3548.         Mov    DX,Offset Quote
  3549.         Mov    CX,1
  3550.         Call    WriteStdError
  3551.         Pop    DX
  3552.         Pop    CX
  3553.         Call    WriteStdError
  3554.         Mov    DX,Offset Quote
  3555.         Mov    CX,1
  3556.         Call    WriteStdError
  3557.         Jmp Short DispError2
  3558. DispErrorParm    Endp
  3559. ;
  3560. DisplayError    Proc    Near
  3561.         Push    DS
  3562.         Push    ES
  3563.         Push    CX
  3564.         Push    SI
  3565.         Push    BX
  3566.         Push    AX
  3567.         Call    FindMsgEnd
  3568. DispError2:    Call    WriteNewLine
  3569.         Mov    CS:DidErrorWord,0
  3570.         Pop    AX
  3571.         Pop    BX
  3572.         Pop    SI
  3573.         Pop    CX
  3574.         Pop    ES
  3575.         Pop    DS
  3576.         Ret
  3577. DisplayError    Endp
  3578. ;
  3579. DisplayExit    Proc    Near
  3580.         Call    DisplayError
  3581. ErrorExit:    Call    FinalDeletes
  3582.         Mov    AL,CS:ErrorCode
  3583.         Jmp    GoBack
  3584. DisplayExit    Endp
  3585. ;
  3586. FinalDeletes    Proc    Near
  3587.         Push    CS
  3588.         Pop    DS
  3589.         Mov    BX,TempHandle1
  3590.         Mov    TempHandle1,0
  3591.         Mov    DX,Offset TempName1
  3592.         Call    CloseDelete
  3593.         Mov    BX,TempHandle2
  3594.         Mov    TempHandle2,0
  3595.         Mov    DX,Offset TempName2
  3596.         Call    CloseDelete
  3597.         Mov    BX,TempHandle3
  3598.         Mov    TempHandle3,0
  3599.         Mov    DX,Offset TempName3
  3600.         Call    CloseDelete
  3601.         Cmp    OpenedOutput,0
  3602.         Jz    FinalDeleteRet
  3603.         Mov    BX,OutputHandle
  3604.         Cmp    BX,StdOutput
  3605.         Jbe    FinalDeleteRet
  3606.         Mov    DX,OutputAddr
  3607.         Call    CloseDelete
  3608. FinalDeleteRet: Ret
  3609. FinalDeletes    Endp
  3610. ;
  3611. CloseDelete    Proc    Near
  3612.         Or    BX,BX
  3613.         Jz    CloseDeleteRet
  3614.         Mov    AX,Close
  3615.         Int    DOS
  3616.         Jc    DoError71
  3617.         Mov    AX,Delete
  3618.         Int    DOS
  3619.         Jc    DoError72
  3620. CloseDeleteRet: Ret
  3621. DoError71:    Mov    AX,3137H
  3622.         Jmp    DiskError
  3623. DoError72:    Mov    AX,3237H
  3624.         Jmp    DiskError
  3625. CloseDelete    Endp
  3626. ;
  3627. WriteERROR:    Mov    CS:DidErrorWord,0FFH
  3628.         Mov    DX,Offset ERRORWord
  3629.         Mov    CX,7
  3630.         Jmp Short WriteStdError2
  3631. ;
  3632. WriteNewLine:    Mov    DX,Offset NewLine
  3633.         Mov    CX,2
  3634. ;
  3635. WriteStdError    Proc    Near
  3636.         Mov    CH,0
  3637. WriteStdError2: Mov    BX,ErrorHandle    ;Write to StdError or error file.
  3638.         Mov    AH,Write
  3639.         Int    DOS
  3640.         Jc    WrtStdNG
  3641.         Cmp    AX,CX
  3642.         Jz    WrtStdErrRet
  3643. WrtStdNG:    Cmp    ErrorHandle,StdError
  3644.         Jz    WrtStdErrRet
  3645.         Mov    AX,Close
  3646.         Int    DOS
  3647.         Mov    ErrorHandle,StdError
  3648.         Mov    BX,StdError
  3649.         Push    DX
  3650.         Push    CX
  3651.         Mov    DX,Offset FullErrMsg
  3652.         Mov    CX,Offset FullErrEnd - Offset FullErrMsg
  3653.         Mov    AH,Write
  3654.         Int    DOS
  3655.         Cmp    CS:DidErrorWord,0
  3656.         Jz    WrtStdNG2
  3657.         Call    WriteERROR
  3658.         Mov    CS:DidErrorWord,0
  3659. WrtStdNG2:    Pop    CX
  3660.         Pop    DX
  3661.         Jmp    WriteStdError2
  3662. WrtStdErrRet:    Ret
  3663. WriteStdError    Endp
  3664. ;
  3665. GetNumb  Proc    Near
  3666.         Cld
  3667.         Xor    DX,DX            ;Start with result = 0.
  3668.         Mov    DI,10
  3669. NextDigit:    Cmp    AL,30H           ;Digit must
  3670.         Jb    FinNumb1         ;be between
  3671.         Cmp    AL,39H           ;0 and 9.
  3672.         Ja    FinNumb1
  3673.         And    AX,0FH           ;Strip high nibl.
  3674.         Push    AX
  3675.         Xchg    AX,DX            ;AX now = prev result.
  3676.         Mul    DI               ;Mult by 10.
  3677.         Pop    DX               ;Recover new digit.
  3678.         Jo    Make65535         ;NG if GT 65535.
  3679.         Add    DX,AX            ;DX = result so far.
  3680.         Jc    Make65535         ;NG if GT 65535.
  3681.         Jcxz    FinNumbRet
  3682.         Dec    CX
  3683.         Lodsb
  3684.         Jmp    NextDigit
  3685. FinNumb1:    Dec    SI
  3686.         Inc    CX
  3687. FinNumbRet:    Ret
  3688. Make65535:    Mov    DX,65535
  3689. AnyMoreNumb:    Jcxz    FinNumbRet
  3690.         Dec    CX
  3691.         Lodsb
  3692.         Cmp    AL,30H
  3693.         Jb    FinNumb1
  3694.         Cmp    AL,39H
  3695.         Ja    FinNumb1
  3696.         Jmp    AnyMoreNumb
  3697. GetNumb  Endp
  3698. PascTooLong:    Mov    DX,Offset PascTooLongMsg
  3699.         Jmp    DisplayExit
  3700. ;
  3701. AtHighEnd:    Xchg    BP,SI
  3702.         Xchg    DX,BX
  3703.         Mov    CX,BP
  3704.         Sub    CX,DX
  3705.         Jmp Short CheckPartSize
  3706. ;
  3707. SortEnd     Proc    Near
  3708.         Mov    AX,CS
  3709.         Mov    DS,AX
  3710.         Mov    ES,AX
  3711.         Ret
  3712. SortEnd     Endp
  3713. ;
  3714. SortData    Proc    Near
  3715.         Cld
  3716.         Mov    StackHigh,SP
  3717.         Mov    AX,SegCount
  3718.         Mov    SegNumb,AX
  3719. SortNextSeg:    Sub    CS:SegNumb,2
  3720.         Js    SortEnd
  3721.         Mov    AH,30H
  3722.         Int    DOS
  3723.         Mov    SI,CS:SegNumb
  3724.         Mov    BX,SI
  3725.         Mov    DS,CS:Data.Segm[SI+BX]
  3726.         Mov    CS:BegSeg,DS
  3727.         Mov    ES,CS:Pointer.Segm[SI+BX]
  3728.         Mov    CS:PtrSeg,ES
  3729.         Mov    DX,CS:PointerEnd[SI]     ;Ofs of last (Jth) ptr buck.
  3730.         Mov    BP,CS:Pointer.Beg[SI+BX]  ;Ofs of first (Ith) ptr buck.
  3731.         Mov    CX,BP
  3732.         Sub    CX,DX
  3733.         Jmp Short CheckPartSize
  3734. NewPartition:    Pop    SI               ;Lo end of curr part.
  3735.         Pop    BX               ;Hi end of curr part.
  3736.         Xchg    BX,DX
  3737.         Dec    BP               ;BP is lo for upper part.
  3738.         Dec    BP               ;DX is hi for upper part.
  3739.         Inc    BX               ;BX is hi for low part.
  3740.         Inc    BX               ;SI is lo for low part.
  3741.         Mov    CX,BP
  3742.         Sub    CX,DX            ;Size of upper part.
  3743.         Cmp    CX,-2
  3744.         Jz    AtHighEnd
  3745.         Mov    AX,SI
  3746.         Sub    AX,BX            ;Size of low part.
  3747.         Jc    CheckPartSize
  3748.         Cmp    AX,CX
  3749.         Jae    Save1Part        ;Jmp if low part GE upper.
  3750.         Xchg    BX,DX
  3751.         Xchg    SI,BP
  3752.         Xchg    AX,CX
  3753. Save1Part:    Push    BX
  3754.         Push    SI
  3755. CheckPartSize:    Shr    CX,1
  3756.         Jnz    GetIOffset
  3757. FinishPart:    Cmp    SP,CS:StackHigh
  3758.         Jb    FinishPart2
  3759.         Jmp    SortNextSeg          ;If no more parts we are done.
  3760. FinishPart2:    Pop    BP               ;Lo ofs in part.
  3761.         Pop    DX               ;Hi ofs in part.
  3762.         Mov    CX,BP
  3763.         Sub    CX,DX
  3764.         Jmp    CheckPartSize
  3765. GetIOffset:    Push    DX               ;Hi ofs for new part.
  3766.         Push    BP               ;Lo ofs for new part.
  3767.         Mov    DI,BP
  3768.         Add    DI,DX            ;(Hi ofs + Lo ofs).
  3769.         Rcr    DI,1            ;(Hi ofs + Lo ofs) / 2.
  3770.         Jpe    ClearBit0
  3771.         Mov    SI,BP
  3772.         Sub    SI,DX
  3773.         Shr    SI,1
  3774.         Shr    SI,1
  3775.         Jpe    SubDiff
  3776. AddDiff:    Add    DI,SI            ;Add (Hi - Lo) / 4.
  3777.         Jmp Short ClearBit0
  3778. SubDiff:    Shr    SI,1
  3779.         Sub    DI,SI            ;Sub (Hi - Lo) / 8.
  3780. ClearBit0:    And    DI,0FFFEH         ;Make sure its on a word boundary.
  3781.         Mov    SI,ES:[BP]           ;Former first rcd.
  3782.         Xchg    SI,ES:[DI]           ;Swap ofs of rcd I
  3783.         Mov    ES:[BP],SI           ;with ofs of former first rcd.
  3784. ;
  3785. GetJOfSDown:    Mov    DI,DX            ;Ofs of Jth ptr.
  3786.         Mov    DI,ES:[DI]           ;Ofs of Jth rcd.
  3787.         Push    SI
  3788.         Mov    ES,CS:BegSeg
  3789.         Call    CompRoutine
  3790.         Mov    ES,CS:PtrSeg
  3791.         Pop    SI               ;Recover ofs of Ith rcd.
  3792.         Ja    ReverseDown         ;Jump if Ith rcd goes after Jth.
  3793. NextJDown:    Inc    DX              ;Ofs of next Jth ptr buck.
  3794.         Inc    DX
  3795.         Cmp    DX,BP           ;If J = I we have found correct
  3796.         Jnz    GetJOfsDown         ;pos for the Ith ptr.
  3797. SaveIOfsDown:    Mov    ES:[BP],SI
  3798.         Jmp    NewPartition        ;Setup new part.
  3799. ReverseDown:    Mov    DI,DX           ;Ofs of Jth ptr.
  3800.         Mov    DI,ES:[DI]          ;Ofs of Jth rcd.
  3801.         Mov    ES:[BP],DI          ;Store in Ith ptr buck.
  3802.         Xchg    DX,BP           ;I and J ptrs are swapped.
  3803.         Jmp Short NextJUp    ;Now must move upwards in search.
  3804. ;
  3805. GetJOfSUp:    Mov    DI,DX           ;Ofs of Jth ptr.
  3806.         Mov    DI,ES:[DI]          ;Ofs of Jth rcd.
  3807.         Push    SI
  3808.         Mov    ES,CS:BegSeg
  3809.         Call    CompRoutine
  3810.         Mov    ES,CS:PtrSeg
  3811.         Pop    SI        ;Recover ofs of Ith rcd.
  3812.         Jb    ReverseUp    ;Jmp if Ith rcd goes before Jth.
  3813. NextJUp:    Dec    DX        ;Ofs of next Jth ptr buck.
  3814.         Dec    DX
  3815.         Cmp    DX,BP        ;If J = I we have found correct
  3816.         Jne    GetJOfsUp    ;pos for the Ith ptr.
  3817. SaveIOfsUp:    Mov    ES:[BP],SI
  3818.         Jmp    NewPartition    ;Setup new part.
  3819. ReverseUP:    Mov    DI,DX        ;Ofs of Jth ptr.
  3820.         Mov    DI,ES:[DI]    ;Ofs of Jth rcd.
  3821.         Mov    ES:[BP],DI    ;Store in Ith ptr buck.
  3822.         Xchg    DX,BP        ;I and J ptrs are swapped.
  3823.         Jmp    NextJDown    ;Now move down in search.
  3824. ;
  3825. SortData    Endp
  3826. ;
  3827. TempRealExp    DW    0
  3828. TempRealShft1    DW    0
  3829. TempRealShft2    DW    0
  3830. TempReal1    DB    8 Dup(0)
  3831. TempReal2    DB    8 Dup(0)
  3832. ;
  3833. TempUnNormal    Proc    Near
  3834. ;
  3835.         Call    CalcExponent    ;Returns BX=shft ct, AX=new exp.
  3836.         Mov    CS:TempRealExp,AX
  3837.         Mov    CS:TempRealShft1,BX
  3838.         Push    SI
  3839.         Mov    SI,DI
  3840.         Push    DS
  3841.         Push    ES
  3842.         Pop    DS
  3843.         Call    CalcExponent
  3844.         Pop    DS
  3845.         Pop    SI
  3846.         Mov    CS:TempRealShft2,BX
  3847.         Cmp    CS:TempRealExp,AX ;If the two exponents are unequal
  3848.         Jne    TempUnNormal2b      ;then return proper carry flag.
  3849.         Or    AX,AX          ;If new exps equal and both zero
  3850.         Jnz    TempUnNormal3      ;then return with z flag set.
  3851. TempUnNormal2b: Mov    CX,10
  3852.         Ret            ;Return if new exponents not equal.
  3853. ;
  3854. TempUnNormal3:    Push    DS
  3855.         Push    SI
  3856.         Push    ES
  3857.         Push    DI
  3858.         Mov    BX,CS:TempRealShft1
  3859.         Mov    DI,Offset TempReal1+7
  3860.         Call    MoveTempReal
  3861.         Pop    SI
  3862.         Pop    DS
  3863.         Push    DS
  3864.         Push    SI
  3865.         Mov    BX,CS:TempRealShft2
  3866.         Mov    DI,Offset TempReal2+7
  3867.         Call    MoveTempReal
  3868.         Mov    AX,CS
  3869.         Mov    ES,AX
  3870.         Mov    DS,AX
  3871.         Mov    SI,Offset TempReal1+7
  3872.         Mov    DI,Offset TempReal2+7
  3873.         Mov    CX,8
  3874.         Rep Cmpsb
  3875.         Pop    DI
  3876.         Pop    ES
  3877.         Pop    SI
  3878.         Pop    DS
  3879.         Mov    CX,10
  3880.         Ret
  3881. TempUnNormal    Endp
  3882. ;
  3883. CalcExponent    Proc    Near
  3884.         Push    SI
  3885.         Sub    SI,3    ;Point to high word of mantissa.
  3886.         Mov    CX,4
  3887.         Xor    BX,BX
  3888. NextWord:    Lodsw
  3889.         Or    AX,AX
  3890.         Js    GotShift
  3891.         Jnz    GetShift2
  3892.         Add    BL,16
  3893.         Loop    NextWord
  3894.         Jmp Short GotShift
  3895. GetShift1:    Inc    BX
  3896. GetShift2:    Shl    AX,1
  3897.         Jnc    GetShift1
  3898. GotShift:    Pop    SI
  3899.         Cmp    BX,64
  3900.         Jnz    GotShift2
  3901.         Xor    AX,AX        ;If pseudo zero make new exp = 0.
  3902.         Ret
  3903. GotShift2:    Mov    AX,[SI-1]
  3904.         And    AX,07FFFH
  3905.         Jnz    GotShift3    ;If exp is zero this must be a
  3906.         Inc    AX        ;denormal so we increment it to one.
  3907. GotShift3:    Sub    AX,BX        ;New exp = old exp - shift count.
  3908.         Add    AX,64        ;Make sure new exp is GE 0.
  3909.         Ret
  3910. CalcExponent    Endp
  3911. ;
  3912. MoveTempReal    Proc    Near
  3913.         Mov    AX,CS
  3914.         Mov    ES,AX
  3915.         Mov    AX,BX
  3916.         Mov    CL,3
  3917.         Shr    AX,CL    ;Number of leading zero bytes in mantissa.
  3918.         Mov    BH,AL    ;Number of trailing zero bytes in new mantissa.
  3919.         Sub    SI,2    ;Skip exponent.
  3920.         Sub    SI,AX    ;Points to first non-zero byte.
  3921.         And    BL,07H    ;Number of lead zero bits in 1st non-zero byte.
  3922.         Mov    CL,BL
  3923.         Mov    BL,8
  3924.         Sub    BL,BH    ;Number of non-zero bytes.
  3925. ;
  3926.         Push    DX
  3927.         Jz    TrailingZeros
  3928.         Lodsb
  3929.         Mov    DH,AL
  3930.         Dec    BL
  3931.         Jz    LastTempByte
  3932. ;
  3933. NextTempByte:    Lodsb
  3934.         Mov    DL,AL
  3935.         Shl    DX,CL
  3936.         Mov    AL,DH
  3937.         Stosb
  3938.         Mov    DH,DL
  3939.         Shr    DH,CL
  3940.         Dec    BL
  3941.         Jnz    NextTempByte
  3942. ;
  3943. LastTempByte:    Shl    DH,CL
  3944.         Mov    AL,DH
  3945.         Stosb
  3946. TrailingZeros:    Mov    CL,BH
  3947.         Xor    AL,AL
  3948.         Rep Stosb
  3949.         Pop    DX
  3950.         Ret
  3951. MoveTempReal    Endp
  3952. ;
  3953. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3954. CompRoutine    Proc    Near
  3955. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3956. ;
  3957. CompRtnBeg:
  3958. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3959. ;Use for second and later sort keys.
  3960. ;
  3961. SecondBeg:    Sub    CX,RelColumn
  3962.         Add    SI,CX
  3963.         Add    DI,CX
  3964. SecondEnd:
  3965. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3966. ;Use in all cases.
  3967. ;
  3968. All1Beg:    Mov    CX,StartColumn       ;Start col of key.
  3969. All1End:
  3970. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3971. ;If fixed length add the following code.
  3972. ;
  3973. Fix1Beg:    Add    SI,CX            ;Pt to key in Jth rcd.
  3974.         Add    DI,CX            ;Pt to key in Ith rcd.
  3975.         Mov    CX,KeyLength        ;Len of key.
  3976. Fix1End:
  3977. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3978. ;If Pascal add the following code.
  3979. ;
  3980. Pascal1Beg:    Xor    AX,AX
  3981.         Mov    BX,AX
  3982.         Lodsb            ;Len of string in Jth line.
  3983.         Mov    BL,ES:[DI]    ;Len of string in Ith line.
  3984.         Inc    DI
  3985.         Dec    CX
  3986.         Xchg    BX,CX        ;BX = maxstrlen, CX = Ith strlen.
  3987.         Cmp    AX,CX
  3988.         Jae    GotShortLen
  3989.         Xchg    CX,AX        ;CX = lesser string length.
  3990. GotShortLen:    Lahf            ;Save flags from compare.
  3991.         Cmp    AL,BL        ;Greater str len versus key len.
  3992.         Jbe    GetPascRest
  3993. JmpPascTooLong: Mov    AX,Offset PascTooLong
  3994.         Jmp    AX
  3995. GetPascRest:    Sub    BX,CX        ;Rest of key len.
  3996.         Sahf        ;Set flags based on len compare in case one len
  3997. Pascal1End:            ;is zero.  This prevents spurious flags.
  3998. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3999. ;If lines add the following code.
  4000. ;
  4001. Line1Beg:    Lodsw
  4002.         Add    SI,CX            ;Pt to key in Jth rcd.
  4003.         Mov    BX,ES:[DI]           ;Len of Ith line.
  4004.         Inc    DI
  4005.         Inc    DI
  4006.         Add    DI,CX            ;Pt to key in Ith rcd.
  4007.         Xchg    CX,AX            ;Len of Jth line.
  4008.         Cmp    CX,BX
  4009.         Jae    GotShort
  4010.         Xchg    BX,CX            ;BX = lesser length.
  4011. GotShort:    Lahf
  4012.         Cmp    CX,StartColumn
  4013. MovKeyLen:    Mov    CX,KeyLength    ;Len of key.
  4014.         Ja    ShortLen
  4015. BothShort:    Mov    BX,StartColumn
  4016.         Add    CX,BX
  4017.         Sub    SI,BX
  4018.         Sub    DI,BX
  4019. ;
  4020. ;As code for each key is created, this target is set to FinishBeg + 2.
  4021. ;If this is last key then the OrigSeq code will be at this loc.
  4022. ;If not last key then code for next key will start at this addr.
  4023. ;
  4024. JmpOrigSeq:    Jmp Short DoCompare      ;If both too short then = compare.
  4025. ShortLen:    Sub    BX,StartColumn    ;Remain short line len.
  4026.         Ja    DoCompare
  4027.         Sahf     ;One line too short so get flags based on len.
  4028. ;
  4029. ;Change following to Cmc followed by Ret if /R specified.
  4030. ;
  4031. OnlyOneShort:    Ret
  4032.         Nop
  4033. ;
  4034. DoCompare:    Cmp    BX,CX        ;Remain short line len vs. key len.
  4035.         Jae    LineEq
  4036.         Xchg    CX,BX        ;Len if only partial key in short line.
  4037.         Sub    BX,CX
  4038.         Jmp Short Line1End
  4039. LineEq:     Mov    AH,40H        ;Neither short so make =.
  4040.         Xor    BX,BX
  4041. Line1End:
  4042. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4043. ;If collating and not zero add the following.
  4044. ;
  4045. CollNZ1Beg:    Repe Cmpsb        ;ASCII collating sort.
  4046. CollNZ1End:
  4047. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4048. ;If collating and zero and lines add the following.
  4049. ;
  4050. LineCollZ1Beg:    Push    DX
  4051.         Jmp Short LineCollZ1Mid2
  4052. LineCollZ1Mid1: Or    AL,DL
  4053.         Jz    LineCollZ1Mid3
  4054. LineCollZ1Mid2: Lodsb
  4055.         Mov    DL,ES:[DI]
  4056.         Inc    DI
  4057.         Cmp    AL,DL
  4058.         Loope    LineCollZ1Mid1
  4059.         Jne    LineCollZ1Mid4
  4060.         Or    AL,DL
  4061.         Jz    LineCollZ1Mid3
  4062.         Xor    DX,DX        ;Restore zero flag.
  4063.         Jmp Short LineCollZ1Mid4
  4064. LineCollZ1Mid3: Mov    AH,40H
  4065. LineCollZ1Mid4: Pop    DX
  4066. LineCollZ1End:
  4067. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4068. ;If collating and zero and fixed add the following.
  4069. ;
  4070. FixCollZ1Beg:    Lodsb
  4071.         Mov    AH,ES:[DI]
  4072.         Inc    DI
  4073.         Dec    CX
  4074.         Cmp    AL,AH
  4075.         Jnz    FixCollZ1End
  4076.         Jcxz    FixCollZ1End
  4077.         Or    AL,AH
  4078.         Jnz    FixCollZ1Beg
  4079. FixCollZ1End:
  4080. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4081. ;If case insensitive and either Pascal or lines but not zero add the following.
  4082. ;
  4083. LinePasNZ1Beg:    Push    AX
  4084.         Push    BX
  4085. LinePasNZ1End:
  4086. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4087. ;If case insensitive and not zero add the following.
  4088. ;
  4089. CaseNZ1Beg:    Jcxz    CaseNZ1End    ;For Pascal strings, CX could be zero.
  4090.         Mov    BX,Offset XlatTable
  4091. CaseNZNextChar: Lodsb                 ;Next byte of Jth line.
  4092.         Xlat    CS:XlatTable         ;Xlat byte from Jth line.
  4093.         Xchg    AH,AL
  4094.         Mov    AL,ES:[DI]
  4095.         Inc    DI
  4096.         Xlat    CS:XlatTable         ;Xlat byte from Ith line.
  4097.         Cmp    AH,AL             ;J line byte vs. I line byte.
  4098.         Loope    CaseNZNextChar
  4099. CaseNZ1End:
  4100. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4101. ;If case insensitive and either Pascal or lines but not zero add the following.
  4102. ;
  4103. LinePasNZ2Beg:    Pop    BX
  4104.         Pop    AX
  4105. LinePasNZ2End:
  4106. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4107. ;If case insensitive and zero and lines add the following.
  4108. ;
  4109. LineCaseZ1Beg:    Push    DX
  4110.         Push    BX
  4111.         Mov    BX,Offset XlatTable
  4112.         Jmp Short LineCaseZ1Mid2
  4113. LineCaseZ1Mid1: Or    AL,DL
  4114.         Jz    LineCaseZ1Mid3
  4115. LineCaseZ1Mid2: Lodsb
  4116.         Xlat    CS:XlatTable         ;Xlat byte from Jth line.
  4117.         Xchg    DL,AL
  4118.         Mov    AL,ES:[DI]
  4119.         Inc    DI
  4120.         Xlat    CS:XlatTable         ;Xlat byte from Ith line.
  4121.         Cmp    DL,AL
  4122.         Loope    LineCaseZ1Mid1
  4123.         Jne    LineCaseZ1Mid4
  4124.         Or    AL,DL
  4125.         Jz    LineCaseZ1Mid3
  4126.         Xor    DX,DX        ;Restore zero flag.
  4127.         Jmp Short LineCaseZ1Mid4
  4128. LineCaseZ1Mid3: Mov    AH,40H
  4129. LineCaseZ1Mid4: Pop    BX
  4130.         Pop    DX
  4131. LineCaseZ1End:
  4132. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4133. ;If case insensitive and zero and fixed add the following.
  4134. ;
  4135. FixCaseZ1Beg:    Push    BX
  4136.         Mov    BX,Offset XlatTable
  4137. FixCaseZ1Mid1:    Lodsb
  4138.         Xlat    CS:XlatTable         ;Xlat byte from Jth line.
  4139.         Xchg    AH,AL
  4140.         Mov    AL,ES:[DI]
  4141.         Inc    DI
  4142.         Dec    CX
  4143.         Xlat    CS:XlatTable         ;Xlat byte from Ith line.
  4144.         Cmp    AH,AL
  4145.         Jnz    FixCaseZ1Mid2
  4146.         Jcxz    FixCaseZ1Mid2
  4147.         Or    AL,AH
  4148.         Jnz    FixCaseZ1Mid1
  4149. FixCaseZ1Mid2:    Pop    BX
  4150. FixCaseZ1End:
  4151. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4152. ;If signed binary integer add the following.
  4153. ;
  4154. Integer1Beg:    Std
  4155.         Lodsb
  4156.         Mov    AH,ES:[DI]
  4157.         Dec    DI
  4158.         Dec    CX
  4159.         Add    AL,80H
  4160.         Add    AH,80H
  4161.         Cmp    AL,AH
  4162.         Jnz    Integer1Mid
  4163.         Repe Cmpsb
  4164. Integer1Mid:    Cld
  4165.         Not    CX
  4166. Integer1End:
  4167. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4168. ;If unsigned binary integer add the following.
  4169. ;
  4170. Unsigned1Beg:    Std
  4171.         Repe Cmpsb
  4172.         Cld
  4173.         Not    CX
  4174. Unsigned1End:
  4175. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4176. ;If IEEE temp real float add the following.
  4177. ;
  4178. TempReal1Beg:    Std
  4179.         Or    CX,CX        ;Clear zero and carry flags.
  4180.         Mov    AL,[SI]
  4181.         Mov    AH,ES:[DI]
  4182.         Rcl    AH,1        ;I use Rcl because it will never set
  4183.         Jc    SecondNegE    ;the Z flag.
  4184.         Rcl    AL,1        ;I use Rcl because it will never set
  4185.         Jc    TempReal1Mid    ;the Z flag.
  4186. BothPosE:    Test    Byte Ptr[SI-2],80H
  4187.         Jz    DoPosUnNormal
  4188.         Test    Byte Ptr ES:[DI-2],80H
  4189.         Jz    DoPosUnNormal
  4190.         Repe Cmpsb
  4191.         Jmp Short TempReal1Mid
  4192. DoPosUnNormal:    Mov    AX,Offset TempUnNormal
  4193.         Call    AX
  4194.         Jmp Short TempReal1Mid
  4195. DoNegUnNormal:    Mov    AX,Offset TempUnNormal
  4196.         Call    AX
  4197.         Jmp Short TestNegEqual
  4198. SecondNegE:    Rcl    AL,1        ;I use Rcl because it will never set
  4199.         Jnc    TempReal1Mid    ;the Z flag.
  4200. BothNegE:    Test    Byte Ptr[SI-2],80H
  4201.         Jz    DoNegUnNormal
  4202.         Test    Byte Ptr ES:[DI-2],80H
  4203.         Jz    DoNegUnNormal
  4204.         Repe Cmpsb
  4205. TestNegEqual:    Je    TempReal1Mid
  4206.         Cmc
  4207. TempReal1Mid:    Cld
  4208.         Not    CX
  4209. TempReal1End:
  4210. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4211. ;If IEEE float add the following.
  4212. ;
  4213. ;Note that a negative zero will sort low relative to a positive zero.  I
  4214. ;have decided to make this a feature since the code to make negative and
  4215. ;positive zeros compare equal would be inefficient.
  4216. ;
  4217. Float1Beg:    Std
  4218.         Or    CX,CX        ;Clear zero and carry flags.
  4219.         Mov    AL,[SI]
  4220.         Mov    AH,ES:[DI]
  4221.         Rcl    AH,1        ;I use Rcl because it will never set
  4222.         Jc    SecondNeg    ;the Z flag.
  4223.         Rcl    AL,1        ;I use Rcl because it will never set
  4224.         Jc    Float1Mid    ;the Z flag.
  4225. BothPos:    Repe Cmpsb
  4226.         Jmp Short Float1Mid
  4227. SecondNeg:    Rcl    AL,1        ;I use Rcl because it will never set
  4228.         Jnc    Float1Mid    ;the Z flag.
  4229. BothNeg:    Repe Cmpsb
  4230.         Je    Float1Mid
  4231.         Cmc
  4232. Float1Mid:    Cld
  4233.         Not    CX
  4234. Float1End:
  4235. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4236. ;If original Microsoft binary float add the following.
  4237. ;
  4238. ;Note that in this case negative and positive zeros will sort equal because.
  4239. ;I don't check for sign if both exponents are zero because interpreted BASIC
  4240. ;often leaves garbage in the mantissa in such cases.
  4241. ;
  4242. Micro1Beg:    Std
  4243.         Mov    AX,[SI-1]    ;AH = exponent, AL contains sign.
  4244.         Mov    BX,ES:[DI-1]    ;BH = exponent, BL contains sign.
  4245.         Or    BH,AH
  4246.         Jz    Micro1Mid    ;If both exponents are zero don't
  4247.         ;compare the mantissas.  Note that because we only continue
  4248.         ;if the Z flag is reset, we don't have to worry that we will
  4249.         ;have a spurious equal condition if signs are different.
  4250.         Rcl    BL,1        ;I use Rcl because it will never set
  4251.         Jc    SecondNegM    ;the Z flag.
  4252.         Rcl    AL,1        ;I use Rcl because it will never set
  4253.         Jc    Micro1Mid    ;the Z flag.
  4254. BothPosM:    Repe Cmpsb
  4255.         Jmp Short Micro1Mid
  4256. SecondNegM:    Rcl    AL,1        ;I use Rcl because it will never set
  4257.         Jnc    Micro1Mid    ;the Z flag.
  4258. BothNegM:    Repe Cmpsb
  4259.         Je    Micro1Mid
  4260.         Cmc
  4261. Micro1Mid:    Cld
  4262.         Not    CX
  4263. Micro1End:
  4264. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4265. ;If original Turbo Pascal binary float add the following.
  4266. ;
  4267. Turbo1Beg:    Std
  4268.         Mov    AL,[SI-5]
  4269.         Mov    AH,ES:[DI-5]
  4270.         Or    AL,AH        ;If both exps zero don't compare
  4271.         Jz    Turbo1Mid    ;mantissas.  Otherwise clear Z flag.
  4272.         Mov    AL,[SI]
  4273.         Mov    AH,ES:[DI]
  4274.         Rcl    AH,1        ;I use Rcl because it will never set
  4275.         Jc    SecondNegT    ;set the Z flag.
  4276.         Rcl    AL,1        ;I use Rcl because it will never set
  4277.         Jc    Turbo1Mid    ;the Z flag.
  4278. BothPosT:    Mov    AL,[SI-5]
  4279.         Mov    AH,ES:[DI-5]
  4280.         Cmp    AL,AH
  4281.         Jnz    Turbo1Mid
  4282.         Repe Cmpsb
  4283.         Jmp Short Turbo1Mid
  4284. SecondNegT:    Rcl    AL,1        ;I use Rcl because it will never set
  4285.         Jnc    Turbo1Mid    ;the Z flag.
  4286. BothNegT:    Mov    AL,[SI-5]
  4287.         Mov    AH,ES:[DI-5]
  4288.         Cmp    AL,AH
  4289.         Jnz    ReverseCarry
  4290.         Repe Cmpsb
  4291.         Je    Turbo1Mid
  4292. ReverseCarry:    Cmc
  4293. Turbo1Mid:    Cld
  4294.         Not    CX
  4295. Turbo1End:
  4296. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4297. ;In all cases add the following.
  4298. ;
  4299. ;If /R specified then Ret Nop becomes Cmc Ret.
  4300. ;
  4301. All2Beg:    Jz    All2End
  4302.         Mov    AH,0    ;This is required by the ElimDup routine.
  4303.         Ret
  4304.         Nop
  4305. All2End:
  4306. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4307. ;If lines or Pascal add the following.
  4308. ;
  4309. ;If /R specified then Ret Nop becomes Cmc Ret.
  4310. ;
  4311. LinePascal3Beg: Sahf
  4312.         Jz    SameLen
  4313.         Mov    AH,0    ;This is required by the ElimDup routine.
  4314.         Ret
  4315.         Nop
  4316. SameLen:    Add    CX,BX
  4317. ;
  4318. LinePascal3End:
  4319. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4320. ;Add the following for all cases.
  4321. ;
  4322. ;This code added after each key is processed but is overlain by next key.
  4323. ;
  4324. OrigBeg:
  4325. OrigSeq:    Mov    AH,40H    ;This is required by the ElimDup routine.
  4326.         Inc    SI    ;These Incs are required because a numeric Cmp
  4327.         Inc    DI    ;might reduce to 0FFFFH for 1st item in seg.
  4328.         Cmp    SI,DI    ;If keys are EQ, we maintain the
  4329.         Ret        ;orig seq for ident keys.
  4330.         DB    0C1H
  4331.         Cmp    BX,CX
  4332.         Ret
  4333. OrigEnd:
  4334. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4335. ;
  4336. CompRtnEnd:
  4337. ;
  4338. CompRoutine    Endp
  4339. ;
  4340.  
  4341. ChkKeyInRcd    Proc    Near
  4342.         Push    CX
  4343.         Push    SI
  4344.         Cmp    FixedLen,0
  4345.         Jz    CompStartCol
  4346.         Cmp    KeyCount,1
  4347.         Jnz    CompStartCol
  4348. CmpElimNull:    Cmp    ElimNull,0
  4349.         Jz    CompStartCol
  4350. NullFix:    Mov    FixNotAllowMsg+2,'4'
  4351.         Mov    FixNotAllowMsg+6,'N'
  4352.         Mov    DX,Offset FixNotAllowMsg
  4353.         Call    DisplayError
  4354. CompStartCol:    Cmp    StartCol,0
  4355.         Jz    ChkKeyInRcd2
  4356.         Dec    StartCol        ;Dec StartCol if not 0.
  4357. ChkKeyInRcd2:    Mov    DX,FixedLen
  4358.         Or    DX,DX
  4359.         Jnz    ChkKeyInRcd3            ;Jmp if fixed len.
  4360.         Mov    DX,32750
  4361. ChkKeyInRcd3:    Sub    DX,StartCol    ;DX = FixedLen or 32750 less StartCol.
  4362.         Lahf
  4363.         Cmp    KeyLen,0
  4364.         Jnz    ChkKeyInRcd4
  4365.         Test    KeyTyp,KeyTurbo
  4366.         Jz    ChkKeyInRcd3b
  4367.         Mov    KeyLen,6
  4368.         Jmp Short ChkKeyInRcd4
  4369. ChkKeyInRcd3B:    Mov    KeyLen,DX
  4370. ChkKeyInRcd4:    Sahf
  4371.         Ja    SubKeyLen
  4372.         Mov    DX,Offset BigStartMsg
  4373.         Call    DispErrorParm
  4374.         Jmp Short ChkKeyInRcd5
  4375. SubKeyLen:    Sub    DX,KeyLen
  4376.         Jae    ChkKeyInRcd5        ;Rcd len must be >= KeyLen.
  4377.         Cmp    FixedLen,0
  4378.         Jnz    BigKeyLen
  4379.         Add    KeyLen,DX ;If lines and big key len let keylen equal
  4380.                   ;32750 - StartCol.
  4381.         Jmp Short ChkKeyInRcd5
  4382. BigKeyLen:    Mov    DX,Offset BigKeyLenMsg
  4383.         Call    DispErrorParm
  4384. ChkKeyInRcd5:    Test    KeyTyp,KeyInteger+KeyUnsigned+KeyFloat+KeyMicro+KeyTurbo
  4385.         Jz    CheckPascal
  4386.         Mov    AX,Keylen
  4387.         Add    AX,StartCol
  4388.         Dec    AX
  4389.         Mov    StartCol,AX
  4390.         And    KeyTyp,0FFFFH XOR KeyASCII+KeyZero+KeyPascal
  4391.         Test    KeyTyp,KeyMicro+KeyTurbo+KeyFloat
  4392.         Jz    JmpCalcRelCol
  4393.         Test    KeyTyp,KeyTurbo
  4394.         Jz    Test4Or8
  4395.         Cmp    KeyLen,6
  4396.         Jz    CalcRelCol
  4397.         Mov    DX,Offset NGTurboLenMsg
  4398.         Call    DispErrorParm
  4399. JmpCalcRelCol:    Jmp Short CalcRelCol
  4400. NGFloatLen:    Mov    DX,Offset NGFloatLenMsg
  4401.         Call    DispErrorParm
  4402.         Jmp Short CalcRelCol
  4403. NGMicroLen:    Mov    DX,Offset NGMicroLenMsg
  4404.         Call    DispErrorParm
  4405.         Jmp Short CalcRelCol
  4406. ;
  4407. Test4Or8:    Cmp    KeyLen,4
  4408.         Jz    CalcRelCol
  4409.         Cmp    KeyLen,8
  4410.         Jz    CalcRelCol
  4411.         Test    KeyTyp,KeyMicro
  4412.         Jnz    NGMicroLen
  4413.         Cmp    KeyLen,10
  4414.         Jnz    NGFloatLen
  4415.         Jmp Short CalcRelCol
  4416. CheckPascal:    Test    KeyTyp,KeyPascal
  4417.         Jz    CalcRelCol
  4418.         Cmp    DefaultSortKey,0
  4419.         Jz    ChkPascalLen
  4420.         Cmp    FixedLen,0
  4421.         Jz    CalcRelCol
  4422.         Cmp    KeyLen,2
  4423.         Jb    PascalLenNgDef
  4424.         Cmp    KeyLen,256
  4425.         Jbe    CalcRelCol
  4426. PascalLenNGDef: Mov    DX,Offset PascalDefNGMsg
  4427.         Call    DisplayError
  4428.         Jmp Short CalcRelCol
  4429. ChkPascalLen:    Cmp    KeyLen,2
  4430.         Jb    PascalLenNG
  4431.         Cmp    KeyLen,256
  4432.         Jbe    CalcRelCol
  4433. PascalLenNG:    Mov    DX,Offset PascalLenNGMsg
  4434.         Call    DispErrorParm
  4435. CalcRelCol:    Mov    DX,PrevEndCol
  4436.         Cmp    FixedLen,0
  4437.         Jnz    StoreRelCol
  4438.         Inc    DX
  4439.         Inc    DX
  4440. StoreRelCol:    Mov    RelCol,DX
  4441.         Cmp    GotError,0
  4442.         Jz    StoreRelCol2
  4443.         Jmp    ChkKeyRet
  4444. StoreRelCol2:    Mov    DI,CodePointer
  4445.         Mov    SI,CompMove
  4446.         Cmp    Fixedlen,0
  4447.         Jz    Line1
  4448.         Mov    Fix1Start,DI
  4449.         Mov    Line1Start,0
  4450.         Add    SI,Offset Fix1Beg
  4451.         Test    KeyTyp,KeyPascal
  4452.         Jnz    DoPascal
  4453.         Mov    CX,Offset Fix1End - Offset Fix1Beg
  4454.         Jmp Short MoveKeyLen
  4455. DoPascal:    Mov    CX,Offset Pascal1End - Offset Fix1Beg
  4456.         Jmp Short MoveKeyLen
  4457. Line1:        Add    SI,Offset Line1Beg
  4458.         Mov    CX,Offset Line1End - Offset Line1Beg
  4459.         Mov    Fix1Start,0
  4460.         Mov    Line1Start,DI
  4461. MoveKeyLen:    Rep Movsb
  4462.         Test    KeyTyp,KeyInteger+KeyUnsigned+KeyFloat+KeyMicro+KeyTurbo
  4463.         Jnz    DoBinaryNumb
  4464.         Test    KeyTyp,KeyASCII
  4465.         Jz    JmpCaseInsen
  4466.         Test    KeyTyp,KeyZero
  4467.         Jnz    ASCIIZero
  4468.         Mov    SI,Offset CollNZ1Beg
  4469.         Mov    CX,Offset CollNZ1End - Offset CollNZ1Beg
  4470.         Jmp Short MoveASCIICode
  4471. JmpCaseInsen:    Jmp Short CaseInsen
  4472. DoBinaryNumb:    Test    KeyTyp,KeyInteger
  4473.         Jz    TestUnsigned
  4474.         Mov    SI,Offset Integer1Beg
  4475.         Mov    CX,Offset Integer1End - Offset Integer1Beg
  4476.         Jmp Short MoveBinNumb
  4477. TestUnsigned:    Test    KeyTyp,KeyUnsigned
  4478.         Jz    TestFloat
  4479.         Mov    SI,Offset Unsigned1Beg
  4480.         Mov    CX,Offset Unsigned1End - Offset Unsigned1Beg
  4481.         Jmp Short MoveBinNumb
  4482. TestFloat:    Test    KeyTyp,KeyFloat
  4483.         Jz    TestMicro
  4484.         Cmp    KeyLen,10
  4485.         Jz    DoTempReal
  4486.         Mov    SI,Offset Float1Beg
  4487.         Mov    CX,Offset Float1End - Offset Float1Beg
  4488.         Jmp Short MoveBinNumb
  4489. DoTempReal:    Mov    SI,Offset TempReal1Beg
  4490.         Mov    CX,Offset TempReal1End - Offset TempReal1Beg
  4491.         Jmp Short MoveBinNumb
  4492. TestMicro:    Test    KeyTyp,KeyMicro
  4493.         Jz    DoTurbo
  4494.         Mov    SI,Offset Micro1Beg
  4495.         Mov    CX,Offset Micro1End - Offset Micro1Beg
  4496.         Jmp Short MoveBinNumb
  4497. DoTurbo:    Mov    SI,Offset Turbo1Beg
  4498.         Mov    CX,Offset Turbo1End - Offset Turbo1Beg
  4499. MoveBinNumb:    Add    SI,CompMove
  4500.         Rep    Movsb
  4501.         Jmp Short All2
  4502. ASCIIZero:    Cmp    FixedLen,0
  4503.         Jz    LineASCIIZero
  4504.         Mov    SI,Offset FixCollZ1Beg
  4505.         Mov    CX,Offset FixCollZ1End - Offset FixCollZ1Beg
  4506.         Jmp Short MoveASCIICode
  4507. LineASCIIZero:    Mov    SI,Offset LineCollZ1Beg
  4508.         Mov    CX,Offset LineCollZ1End - Offset LineCollZ1Beg
  4509. MoveASCIICode:    Add    SI,CompMove
  4510.         Rep Movsb
  4511.         Jmp Short All2
  4512. CaseInsen:    Test    KeyTyp,KeyZero
  4513.         Jnz    CaseZero
  4514.         Cmp    FixedLen,0
  4515.         Jz    LinesPascal1
  4516.         Test    KeyTyp,KeyPascal
  4517.         Jz    Case1
  4518. LinesPascal1:    Mov    SI,Offset LinePasNZ1Beg
  4519.         Mov    CX,Offset LinePasNZ2End - Offset LinePasNZ1Beg
  4520.         Jmp Short MoveCaseCode
  4521. Case1:        Mov    SI,Offset CaseNZ1Beg
  4522.         Mov    CX,Offset CaseNZ1End - Offset CaseNZ1Beg
  4523.         Jmp Short MoveCaseCode
  4524. CaseZero:    Cmp    FixedLen,0
  4525.         Jz    CaseZeroLines
  4526.         Mov    SI,Offset FixCaseZ1Beg
  4527.         Mov    CX,Offset FixCaseZ1End - Offset FixCaseZ1Beg
  4528.         Jmp Short MoveCaseCode
  4529. CaseZeroLines:    Mov    SI,Offset LineCaseZ1Beg
  4530.         Mov    CX,Offset LineCaseZ1End - Offset LineCaseZ1beg
  4531. MoveCaseCode:    Add    SI,CompMove
  4532.         Rep Movsb
  4533. All2:        Mov    SI,CompMove
  4534.         Add    SI,Offset All2Beg
  4535.         Mov    CX,Offset All2End - Offset All2Beg
  4536.         Rep Movsb
  4537.         Cmp    FixedLen,0
  4538.         Jz    LinesPascal3
  4539.         Test    KeyTyp,KeyPascal
  4540.         Jz    CheckMemory
  4541. LinesPascal3:    Mov    SI,CompMove
  4542.         Add    SI,Offset LinePascal3Beg
  4543.         Mov    CX,Offset LinePascal3End - Offset LinePascal3Beg
  4544.         Rep Movsb
  4545. CheckMemory:    Mov    CompFinish,DI
  4546.         Mov    CodePointer,DI
  4547.         Cmp    DI,ModelCodeLoc
  4548.         Jb    Chk2nd
  4549.         Jmp    NoMemory
  4550. Chk2nd:     Cmp    SecondStart,0           ;Jump if not SecondStart.
  4551.         Jz    DoAll1
  4552.         Mov    AX,RelCol
  4553.         Mov    DI,SecondStart
  4554.         Mov    [DI+2],AX           ;Store imm val for RelColumn.
  4555. DoAll1:     Mov    DI,All1Start
  4556.         Mov    AX,StartCol
  4557.         Mov    [DI+1],AX
  4558.         Cmp    Fix1Start,0
  4559.         Jz    MustBeLines
  4560.         Mov    DI,Fix1Start
  4561.         Mov    AX,KeyLen
  4562.         Mov    [DI+5],AX
  4563.         Test    KeyTyp,KeyReverse
  4564.         Jz    MovOrigCode
  4565.         Test    KeyTyp,KeyPascal
  4566.         Jnz    RevLinesPascal
  4567.         Mov    DI,CompFinish
  4568.         Mov    [DI-2],0C3F5H
  4569.         Jmp Short MovOrigCode
  4570. MustBeLines:    Mov    DI,Line1Start
  4571.         Mov    AX,StartCol
  4572.         Mov    [DI + Offset GotShort - Offset Line1Beg + 3],AX
  4573.         Mov    [DI + Offset ShortLen - Offset Line1Beg + 2],AX
  4574.         Mov    [DI+Offset BothShort-Offset Line1Beg+1],AX
  4575.         Mov    AX,KeyLen
  4576.         Mov    [DI+Offset MovKeyLen-Offset Line1Beg+1],AX
  4577.         Mov    AX,CompFinish
  4578.         Sub    AX,DI
  4579.         Sub    AX,Offset JmpOrigSeq - Offset Line1Beg + 2
  4580.         Mov    [DI + Offset JmpOrigSeq - Offset Line1Beg + 1],AL
  4581.         Test    KeyTyp,KeyReverse
  4582.         Jz    MovOrigCode
  4583.         Mov    [DI + Offset OnlyOneShort - Offset Line1Beg],0C3F5H
  4584. RevLinesPascal: Mov    DI,CompFinish
  4585.         Mov    [DI - 4],0C3F5H
  4586.         Mov    [DI - 11],0C3F5H
  4587. MovOrigCode:    Mov    DI,CodePointer
  4588.         Mov    OrigStart,DI
  4589.         Mov    SI,Offset OrigBeg
  4590.         Mov    CX,Offset OrigEnd - Offset OrigBeg
  4591.         Add    SI,CompMove
  4592.         Rep Movsb
  4593.         Mov    CodePointer,DI
  4594.         Cmp    DI,ModelCodeLoc
  4595.         Jb    ChkKeyRet
  4596.         Jmp    JmpNoMem1
  4597. ChkKeyRet:    Pop    SI
  4598.         Pop    CX
  4599.         Ret
  4600. ChkKeyInRcd    Endp
  4601.  
  4602. ;
  4603. CdeSeg     Ends
  4604. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4605.  
  4606.         End    MainStart
  4607.  
  4608. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4609. ;If numeric and fixed add the following code.
  4610. ;
  4611. ;NumFix1Beg:    Add    SI,CX        ;Point to Jth key.
  4612. ;        Add    DI,CX        ;Point to Ith key.
  4613. ;        Mov    CX,KeyLength
  4614. ;        Push    CX
  4615. ;NumFix1End:
  4616. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4617. ;If numeric and lines add the following code.
  4618. ;
  4619. ;NumLine1Beg:    Lodsw            ;Length of Jth line.
  4620. ;        Add    SI,CX        ;Point to Jth key.
  4621. ;        Mov    BX,ES:[DI]    ;Length of Ith line.
  4622. ;        Inc    DI
  4623. ;        Inc    DI
  4624. ;        Add    DI,CX        ;Point to Ith key.
  4625. ;
  4626. ;        Sub    AX,CX        ;Remaining len of Jth line.
  4627. ;        Ja    NumLine1A
  4628. ;        Xor    AX,AX
  4629. ;NumLine1A:    Sub    BX,CX        ;Remaining len of Ith line.
  4630. ;        Ja    NumLine1B
  4631. ;        Xor    BX,BX
  4632. ;NumLine1B:    Mov    CX,KeyLength
  4633. ;        Cmp    AX,CX
  4634. ;        Jbe    NumLine1C
  4635. ;        Mov    AX,CX        ;Lesser of remain Jth len and keylen.
  4636. ;NumLine1C:    Cmp    BX,CX
  4637. ;        Jbe    NumLine1D
  4638. ;        Mov    BX,CX        ;Lesser of remain Ith len and keylen.
  4639. ;NumLine1D:    Mov    CX,AX
  4640. ;        Push    BX
  4641. ;NumLine1End:
  4642. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4643. ;If numeric add the following.    Must preserve SI, DI, DS, ES return CX = 0
  4644. ;let RelCol be zero.
  4645. ;
  4646. ;Numeric1Beg:    Push    ES
  4647. ;        Push    DI
  4648. ;        Mov    AX,CS
  4649. ;        Mov    ES,AX
  4650. ;        Mov    DI,Offset JNumber
  4651. ;        Call    ConvertNumb
  4652. ;        Pop    SI
  4653. ;        Pop    DS
  4654. ;        Pop    CX
  4655. ;        Call    ConvertNumb
  4656. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  4657.  
  4658.