Category : Word Processors
Archive   : RPSRT102.ZIP
Filename : RPSRT102.ASM

 
Output of file : RPSRT102.ASM contained in archive : RPSRT102.ZIP
; Int Numbers
DOS Equ 21H
Kbrd Equ 16H
;
; Dos Func Numbers
ReadNoEcho Equ 0800H
ClearReadNoEcho Equ 0C08H
SelectDisk Equ 0E00H
CurrDisk Equ 1900H
SetDTA Equ 1A00H
SetCtrlVect Equ 2523H
GetDate Equ 2A00H
GetTime Equ 2C00H
DosVersion Equ 3000H
GetCtrlState Equ 3300H
SetCtrlState Equ 3301H
DiskFree Equ 3600H
CreateFile Equ 3C00H
OpenForRead Equ 3D00H
OpenForWrite Equ 3D01H
Close Equ 3E00H
Read Equ 3F00H
Write Equ 40H
Delete Equ 4100H
SetFileAtBeg Equ 4200H
GetFileLoc Equ 4201H
GetFileLen Equ 4202H
IoctlGet Equ 4400H
IoctlSet Equ 4401H
ForceDup Equ 4600H
AllocMemory Equ 48H
FreeMemory Equ 49H
SetBlock Equ 4AH
FindFirst Equ 4E00H
FindNext Equ 4F00H
;
CtrlStateOn Equ 01H
Hidden Equ 02H
System Equ 04H
;
ExitProg Equ 4CH
;
; Std Handles
StdInput Equ 00H
StdOutput Equ 01H
StdError Equ 02H
;
; Chars
Space Equ 20H
Slash Equ '/'
CtrlZ Equ 1AH
LF Equ 0AH
CR Equ 0DH
CRLF Equ 0A0DH
Escp Equ 1BH
PageUp Equ 49H
PageDown Equ 51H
;
KeyReverse Equ 0001H
KeyZero Equ 0002H
KeyASCII Equ 0004H
KeyPascal Equ 0008H
KeyInteger Equ 0010H
KeyUnsigned Equ 0020H
KeyMicro Equ 0040H
KeyTurbo Equ 0080H
KeyFloat Equ 0100H
;
KeyDecimal Equ 0200H
KeyNumDisp Equ 0400H
;
Question Equ '?'
LengthParm Equ ':'
ASCIIParm Equ 'A'
NoBreakParm Equ 'B'
ZeroParm Equ 'C'
DupParm Equ 'D'
ErrorParm Equ 'E'
FixedParm Equ 'F'
FloatParm Equ 'F'
IntegerParm Equ 'I'
MicroParm Equ 'M'
NullParm Equ 'N'
PascalParm Equ 'P'
QuietParm Equ 'Q'
ReverseParm Equ 'R'
TempParm Equ 'T'
TurboParm Equ 'T'
UnsignedParm Equ 'U'
CtrlZParm Equ 'Z'
;
DecimalParm Equ 'D'
NumDispParm Equ 'N'
;
StartColumn Equ 1111H
RelColumn Equ 1111H
KeyLength Equ 1111H
;
GotBinStrErr Equ 01H
GotDiffBinErr Equ 02H
GotNumbNotFErr Equ 04H
GotOtherErr Equ 80H
;
BegSegm Struc
Beg DW ?
Segm DW ?
BegSegm Ends
;
CdeSeg Segment Para Public 'Code'
Assume CS:CdeSeg,DS:CdeSeg,ES:CdeSeg,SS:CdeSeg
;
Org 80H
ParmsLen DB ? ;Set up ref to cmd parms.
Parms DB 127 Dup(?)
;
Org 100H ;Set start addr for COM module.
MainStart: Jmp MainRoutine
;
Version5 DB 0
DefaultSortKey DB 0
GotQuiet DB 0
IpDevice DB ?
DosStart_Hou DB ? ;Start time Hour
DosStart_Min DB ? ; Min
DosStart_Sec DB ? ; Sec
DosStart_Hun DB ? ; Hundredths
DosEnds_Hou DB ? ;End time Hour
DosEnds_Min DB ? ; Min
DosEnds_Sec DB ? ; Sec
DosEnds_Hun DB ? ; Hundredths


TimeMsg DB 'Processing Took '
TimeMsgHou DB '00'
DB ':'
TimeMsgMin DB '00'
DB ':'
TimeMsgSec DB '00'
DB '.'
TimeMsgHun DB '00'
DB CR,LF
TimeMsgLen EQU $ - TimeMsg
;
; Syntax Errors
;
SlashNullMsg DB '001: Slash (/) must be followed by a parameter.$'
BadSwitchMsg DB '002: Illegal parameter: $'
SecondTFMsg DB '003: Only one /X switch is allowed.$'
PAndCNgMsg DB '004: /P and /C are incompatible.$'
BadRcdLenMsg DB '005: Record len must be between 1 and 32,750 in: $'
PNotFNGMsg DB '006: Pascal string key only allowed in fixed len '
DB 'record: $'
PMustBeFMsg DB '007: /P only allowed for fixed length records.$'
NumbNotFNGMsg DB '008: Binary number key (F,I,M,T or U) '
DB 'only allowed in fixed len record: $'
FixNotAllowMsg DB '009: /X switch not allowed for fixed length records.$'
;BadStartParmMsg DB '015: Syntax for /S parameter is /S[-]nnn not: $'
;BigStartParmMsg DB '016: ASCII code in /S parameter must not exceed 255: $'
BadDriveMsg DB '010: One and only one temp drive letter may be entered: $'
NotExistMsg DB '011: Non-existent drive: $'
NgDriveMsg DB '012: Invalid character for the drive: $'
BadStartMsg DB '013: Start column must be between 1 and 32,750: $'
BigStartMsg DB '014: Start column must not exceed record len: $'
SecondStartMsg DB '015: Only one start column allowed: $'
BadKeyMsg DB '016: Error in sort key: $'
BadKeyLenMsg DB '017: Key len must be between 1 and 32,750: $'
BigKeyLenMsg DB '018: Key len is too big to fit in record: $'
SecondKeyLenMsg DB '019: Only one key length allowed: $'
NGFloatLenMsg DB '020: Length for 80x87 floating point number'
DB ' must be 4, 8 or 10: $'
NGMicroLenMsg DB '021: Length for GWBASIC/BASICA floating '
DB 'point number must be 4 or 8: $'
NGTurboLenMsg DB '022: Length for Turbo Pascal floating point'
DB ' number must be 6: $'
PascalLenNGMsg DB '023: Length for Pascal strings must be between 2 and 256:'
DB ' $'
PascalDefNGMsg DB '024: Length for Pascal strings must be between 2 and 256.$'
PascalZeroNGMsg DB '025: "P" and "C" attributes are incompatible: $'
SwitchKeyNGMsg DB '026: C attribute conflicts with /P: $'
BinaryStringMsg DB '027: Sort key cannot be both a binary number and a string: $'
DiffBinaryMsg DB '028: Only one binary key type allowed in a sort key: $'
SecondIpMsg DB '029: Only one list of input files and a single output'
DB ' file may be given.',13,10
DB ' Found additional file spec: $'
OutputPlusMsg DB '030: Multiple files not allowed in output spec: $'
MisplacedMsg DB '031: Misplaced plus sign in input file list: $'
FileAndRedirMsg DB '032: Input is redirected to the standard input, '
DB 'so output must go to',13,10
DB ' the standard output. The following file spec '
DB 'is illegal: $'
DeviceMsg DB '033: You must specify an input file.$'
NoErrorSpecMsg DB '034: No name specified for error file: $'
;
VersionMsg DB '037: RPSORT requires MS DOS version 2.00 or later.$'
;
; Memory Problems
;
NoMemoryMsg DB '040: Not enough memory. RPSORT requires 30,000 bytes.$'
TwoRcdMsg DB '041: Not enough memory to hold at least two '
DB 'records/lines at a time.$'
;
; File Doesn't Meet RPSORT Requirements
;
LinGTMaxMsg DB '043: Line exceeds max length of 32750 bytes.$'
PascTooLongMsg DB '044: Found Pascal string whose length byte '
DB 'exceeds specified key length.$'
;
; Input/Output Problems
;
NoDataMsg DB '046: No data in input file(s) so nothing to do.$'
NoFileMsg DB '047: Input file not found: '
NoFileEnd Label Byte
ReadErrorMsg DB '048: Error reading input file.$'
FullOutMsg DB '049: No room on disk to write sorted output file.$'
FullTempMsg DB '050: No room on disk to write temp file.$'
NoTempDirMsg DB '051: Unable to create temp file.$'
NoOpDirMsg DB '052: Unable to create output file.$'
FullErrDirMsg DB '053: Unable to create error file: $'
FullErrMsg DB 13,10,' ERROR 054: Ran out of space on disk attempting '
DB 'to write error file.',13,10
DB ' Redirecting error messages to the screen.',13,10
FullErrEnd Label Byte
;
; Unexpected Errors
;
AllocMsg DB '059: Error allocating memory. $'
DiskErrorMsg DB '060: Unknown error accessing disk.$'
;
SuccessMsg DB 13,10,'Sort successfully completed.',13,10
SuccessEnd Label Byte
SyntaxMsg DB 13,10,'Enter the RPSORT command with no parameters to get '
DB 'a description of the syntax.',13,10
SyntaxFin Label Byte
ShortRcdMsg DB 13,10,'Found short record at end of input file. Will'
DB ' delete it from output file.',13,10
ShortRcdEnd Label Byte
MissCRLFMsg DB 13,10,'Added carriage return and line feed which '
DB 'was missing for last line in file.',13,10
MissCRLFEnd Label Byte
;
QuitMsg DB 13,10,'Do you wish to quit RPSORT? Press "Esc" to quit, any'
DB ' other key to continue.',13,10
QuitEnd Label Byte
ContinueMsg DB 'Continuing...',13,10
ContinueEnd Label Byte
;
Even
XlatTable DB 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
DB 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
DB ' !"#$%&',39,'()*+,-./0123456789:;<=>?'
DB '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'
DB '`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~',127
ForeignChars DB 'CUEAAAACEEEIIIAAEAAOOOUUYOU$$$$$AIOUNN'
DB 166,167,'?',169,170,171,172,'!',34,34
DB 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
DB 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
DB 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
DB 224,'S',226,227,228,229,230,231,232,233,234,235,236,237,238,239
DB 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
;
IndicatorBits DB KeyAscii,255,KeyZero,255,255,81H,255,255
DB KeyInteger,255,255,255,KeyMicro,255,255,KeyPascal,255
DB KeyReverse,255,KeyTurbo,KeyUnsigned,255,255,255,255,255
;
MainRoutine Proc Near
Mov AX,GetTime ;Get Start Time
Int Dos
Mov DosStart_Hou,CH
Mov DosStart_Min,CL
Mov DosStart_Sec,DH
Mov DosStart_Hun,DL
Sti
Call DoCopyRight
Mov AX,DosVersion
Int DOS
Cmp AL,2
Jae Main2
Mov DX,Offset VersionMsg
Jmp DisplayExit
Main2: Cmp AL,5
Jb Main3
Mov Version5,0FFH
Mov CommandSize,0A00H
Mov LeaveCmdSize,2E00H
Main3: Mov AX,SetDTA
Mov DX,Offset DiskXferArea
Int DOS
Mov AX,CurrDisk
Int DOS
Add AL,41H
Mov DefaultDisk,AL
Mov SI,Offset CompRtnEnd - 1 ;End of code to move.
Mov DI,SP
Sub DI,512 ;End addr for dest of move.
;Leaves 512 bytes for stack.
Cmp DI,SI ;Jump if stk alloc overlays code
Ja ChkStdIP
Jmp NoMemory ;and mem is thus too small.
ChkStdIP: Mov AX,IoctlGet
Mov BX,StdInput ;Handle for std ip.
Int DOS ;Ck if ip is a device.
Mov IpDevice,DL ;If no sign, it is a file
Mov CX,Offset CompRtnEnd - Offset CompRoutine
Std
Rep Movsb
Inc DI
Mov ModelCodeLoc,DI
Sub DI,Offset CompRoutine
Mov CompMove,DI
DoGetParms: Call GetParms ;Parse switches and sort keys.
Cmp CodePointer,Offset CompRoutine
Jnz ChkIfError ;Chk if sort keys were given.
Cmp GotSortKey,0
Jnz ChkIfError
Mov DefaultSortKey,0FFH
Call CreateKey ;If no keys given, create std key.
Call ChkKeyInRcd
ChkIfError: Cmp GotError,0
Jz MoveStack
Mov DX,Offset SyntaxMsg
Mov CX,Offset SyntaxFin - Offset SyntaxMsg
Call WriteStdError2
Jmp ErrorExit
MoveStack: Mov DI,CodePointer
Add DI,512 ;Allow 512 byte stack after key code.
And DI,0FFFEH
Mov SP,DI ;Prev code assures this is avail.
Call SetupCtrlBrk
Call SetupMemory
Cmp InputFileCt,0 ;If zero then no filespecs.
Jnz NextSpec2
CallLoadStd: Call LoadStd ;Use std ip.
Jmp Short DoSetPtrs
NextSpec: Mov AL,InputFileCt
Or AL,WildCard
Jz DoSetPtrs
NextSpec2: Call LoadSpec
Jnc NextSpec ;Go back if mem avail.
DoSetPtrs: Cmp GotData,0
Jnz DoSetPtrs2
Mov DX,Offset NoDataMsg
Jmp DisplayExit
DoSetPtrs2: Mov Byte Ptr FromMain,0FFH
Call SetupPointers ;Create array of ptrs to lines.
Call SortData ;Qsort of ptrs based on keys in lines
Cmp FinalOutput,0
Jz NotFinal
Cmp GotOutput,0
Jz DoWriteData
Call OpenOutput
Jmp Short DoWriteData
NotFinal: Cmp WriteHandle,StdOutput
Ja DoWriteData
Call SetupTempFiles
DoWriteData: Call WriteData ;Use ptrs to write lines in seq.
Cmp MoreData,0
Jz CheckMerge
Mov Byte Ptr NeedMerge,0FFH
Call ReSetupMemory
Cmp HaveSpecs,0
Jz CallLoadStd
Jmp NextSpec2
CheckMerge: Cmp NeedMerge,0
Jz GoBackOk
Call MergeData ;Mod WriteData code and do merge.
GoBackOk: Cmp GotQuiet,0
Jnz SetRetZero
Mov DX,Offset SuccessMsg
Mov CX,Offset SuccessEnd - Offset SuccessMsg
Call WriteStdError2
SetRetZero: Xor AX,AX ;Ret code is 0.
GoBack: Push AX
Cmp ErrorHandle,StdError
Jz GoBack2
Mov BX,ErrorHandle
Mov AX,Close ;Close error file.
Int Dos
Goback2: Mov AX,SetCtrlState
Mov DL,CtrlState
Int Dos
Call ComputeTime
Pop AX
Mov AH,ExitProg
Int DOS
MainRoutine Endp
;
ComputeTime Proc Near ;Display Elapsed time
Mov AX,GetTime ;Get End Time
Int Dos
Mov DosEnds_Hou,CH
Mov DosEnds_Min,CL
Mov DosEnds_Sec,DH
Mov DosEnds_Hun,DL
Mov AL,DL
Mov AH,100
Mov Di,offset TimeMsgHun
Sub AL,DosStart_Hun
Call Conv_Byte

Mov AL,DosEnds_Sec
Mov AH,60
Mov Di,offset TimeMsgSec
Sbb AL,DosStart_Sec
Call Conv_Byte

Mov AL,DosEnds_Min
Mov AH,60
Mov Di,offset TimeMsgMin
Sbb AL,DosStart_Min
Call Conv_Byte

Mov AL,DosEnds_Hou
Mov AH,24
Mov Di,offset TimeMsgHou
Sbb AL,DosStart_Hou
Call Conv_Byte
Mov DX,Offset TimeMsg
Mov CX,TimeMsgLen
Call WriteStdError2
Ret

ComputeTime Endp

Conv_Byte proc near ;convert binary byte to hex ASCII.
;call with AL = binary value
; DI = addr to store string
;returns AX, DI, CX modified.

pushf
cmp Ah,Al
Ja Conv_Byte2
Xor Cl,Cl ;If > max, convert it to max-based
Sub Cl,Al ; 256 - number -> max - number
Sub Ah,Cl
Mov Al,Ah
Conv_Byte2: Xor ah,ah ;clear upper byte
mov cl,10 ;Divide binary data by 10
div cl ;to force to decimal
call Ascii ;the quotient becomes the first
stosb ;ASCII character.
mov al,ah
call Ascii ;the remainder becomes the second
stosb ;ASCII character.
popf
ret
Conv_Byte endp

Ascii proc near ;convert value 0-0fFH in AL
add al,'0' ;into a "hex ASCII" character.
cmp al,'9'
jle Ascii2 ;jump if in range 0-9,
add al,'A'-'9'-1 ;offset it to range A-F
Ascii2: ret ;return ASCII char in AL.
Ascii endp

DoCopyRight Proc Near
Mov SI,Offset Parms ;Ofs of cmd line parms.
Xor CX,CX
Mov CL,ParmsLen ;Len of cmd line parms.
Mov ParmBegInit,SI
Mov ParmCharsInit,CX
Mov BX,Offset XlatTable
FindSlashQ: Jcxz DispCopyRight
Dec CX
Lodsb
Cmp AL,Space
Jz FindSlashQ
Cmp AL,Slash
Jnz DispCopyRight
Jcxz DispCopyRight
Dec CX
Lodsb
Xlat
Cmp AL,QuietParm
Jnz DispCopyRight
Mov GotQuiet,0FFH
Mov ParmBegInit,SI
Mov ParmCharsInit,CX
Ret
DispCopyRight: Mov DX,Offset CopyRightMsg
Mov CX,Offset CopyRightEnd - Offset CopyRightMsg
Call WriteStdError2
Ret
DoCopyRight Endp
;
SetupCtrlBrk Proc Near
Mov AX,GetCtrlState
Int DOS
Mov CtrlState,DL
Mov AX,SetCtrlState
Mov DL,CtrlStateOn
Int DOS
Mov AX,SetCtrlVect
Mov DX,Offset CtrlBrkHandler
Int DOS
Cmp GotOutput,0
Jz SetupCtrlRet
Mov AX,OpenForWrite
Mov DX,Offset NulASCIIZ
Int DOS
Mov BX,AX
Mov CX,StdOutput
Mov AX,ForceDup
Int DOS
SetupCtrlRet: Ret
SetupCtrlBrk Endp
;
CtrlBrkHandler Proc Far
Push AX
Push BX
Push CX
Push DX
Push SI
Push DI
Push BP
Push DS
Push ES
Push CS
Pop DS
Cmp NoBreak,0
Jnz DontBreak
Test IpDevice,80H
Jz DoExit
Cmp GotOutput,0
Jz DoExit
AskYN: Mov DX,Offset QuitMsg
Mov CX,Offset QuitEnd - Offset QuitMsg
Call WriteStdError2
StdIPIsDevice: Mov AX,ClearReadNoEcho
Int DOS
ChkEscp: Cmp AL,Escp
Jz DoExit
Mov DX,Offset ContinueMsg
Mov CX,Offset ContinueEnd - Offset ContinueMsg
Call WriteStdError2
DontBreak: Cmp GotOutput,0
Jnz DontBreak2
Mov AX,GetFileLoc
Xor CX,CX
Mov DX,CX
Mov BX,StdOutput
Int DOS
Jc DontBreak2
Mov CX,DX
Mov DX,AX
Sub DX,4
Sbb CX,0
Jc DontBreak2
Mov AX,SetFileAtBeg
Mov BX,StdOutput
Int DOS
DontBreak2: Clc
Jmp Short CtrlBrkRet
DoExit: Call FinalDeletes
Stc
CtrlBrkRet: Pop ES
Pop DS
Pop BP
Pop DI
Pop SI
Pop DX
Pop CX
Pop BX
Pop AX
Ret
CtrlBrkHandler Endp
;
Even
;
DataArea Equ $
;
Data BegSegm 64 Dup(<>) ;Pts to first byte of ip data.
DataEnd DW 64 Dup(?) ;Pts after end of ip data.
;
BlockOfs DD 64 Dup(?) ;Offset in block on disk to read from next.
BlockPos DD 64 Dup(?) ;Offset in file on disk of block.
BlockLen DD 64 Dup(?) ;Length of block on disk.
;
Pointer BegSegm 16 Dup(<>)
PointerEnd DW 16 Dup(?) ;Pts to byte after end of ptrs.
;
TopIndex DW 64 Dup(?)
;
WriteBuff BegSegm <>
MemoryBegSeg DW ? ;Beg of avail mem.
MemoryEndSeg DW ? ;End of avail mem.
BelowLow DW ? ;3/4 of avail memory para below
BelowHi DW ? ;the location of transient COMMAND.COM.
BegSeg DW ?
BegOfs DW ?
NextSeg DW ? ;Next avail seg addr.
NextOfs DW ?
LastSeg DW ?
PtrSeg DW ?
PtrOfs DW ?
FileSizeLo DW ?
FileSizeHi DW ?
MemParaAvail DW ?
MaxSegCount DW ?
MaxSegSize DW ?
Handle DW ?
UseHandle DW ?
ExtraEnd DD ?
MaxSegs DW ?
BegBlock DW ? ;Block that goes into first mem seg this time.
EndBlock DW ? ;Block that goes into last mem seg this time.
BlockSeg DW ? ;Segment for table of block locations.
NewBlockCt DW ? ;BlockCt to be used in next phase of merge.
NewBlockSeg DW ? ;Segment for new table of block locations.
NewBlockBeg DW ? ;First entry in new table of block locations.
NewBlockEnd DW ? ;Next entry in new table of block locations.
RemainderSegs DW ?
ExtraHandle DW ?
IpNamePtr DW ?
;
TempName1 DB 15 Dup(?)
TempName2 DB 15 Dup(?)
TempName3 DB 15 Dup(?)
;
DiskXferArea DB 21 Dup(?)
IpAttr DB ?
IpTime DW ?
IpData DW ?
IpSize DD ?
IpNameExt DB 13 Dup(?)
IpASCIIZ DB 128 Dup(?)
;
Org DataArea
;
CopyRightMsg DB 13,10,'RPSORT v1.02 Dec. 15, 1992,'
DB ' Copyright 1991 by Bob Pirko,'
DB ' All rights reserved',13,10
CopyRightEnd Label Byte
;
Syntax DB 13,10,'Usage: RPSORT [/Q] [/Eerrfile] [/]? [in' ;01
DB 'putfile[+inputfile]] [outputfile] [/A]'
DB 13,10,' [/B] [/C] [/D] [/Fnnnn] [/N] ' ;02
DB '[/P] [/R] [/Td] [/Z] [sort key defin...]',13,10
DB 13,10,'Sort key defin syntax: /+ [col] [:len]' ;04
DB ' [A] [C] [F] [I] [M] [P] [R] [T] [U]'
DB 13,10,'---------------------------------------' ;05
DB '----------------------------------------'
SyntaxEnd Label Byte
;
LastLine DB 13,10,' (Press PageUp or'
LastLine2 DB ' PageDown'
LastLine3 DB ' to see other syntax screens or Esc to exit)'
LastLineEnd Label Byte
;
Syntax1Screen DB 13,10,'RPSORT greatly improves upon the featur' ;06
DB 'es and the performance of the sort'
DB 13,10,'utility distributed with Microsoft DOS.' ;07
DB ' First, RPSORT does everything that'
DB 13,10,'the DOS SORT does. Virtually any comma' ;08
DB 'nd that works with the DOS SORT will'
DB 13,10,'work with RPSORT and produce the same r' ;09
DB 'esult.',13,10
DB 13,10,'But RPSORT does much more. It can sort' ;11
DB ' very large files and supports multiple'
DB 13,10,'sort keys. It is extremely fast. I kn' ;12
DB 'ow of no sort utility that outspeeds it.',13,10
DB 13,10,'RPSORT sorts text files. These consist' ;14
DB ' of lines each ended by CRLF (i.e. a'
DB 13,10,'carriage return and a line feed). It a' ;15
DB 'lso sorts files of fixed length records'
DB 13,10,'such as those produced by many BASIC, P' ;16
DB 'ascal and C language programs.',13,10
DB 13,10,'RPSORT supports numerous sort key types' ;18
DB ' including regular text keys, C language'
DB 13,10,'strings, Turbo Pascal strings, signed a' ;19
DB 'nd unsigned binary integers of any'
DB 13,10,'length and several types of binary floa' ;20
DB 'ting point numbers.',13,10
DB 13,10,'RPSORT can delete null lines (consistin' ;22
DB 'g only of CRLF). It can also delete'
DB 13,10,'records/lines whose sort keys duplicate' ;23
DB ' those in a previous record/line.',13,10
DB 13,10,' (Press ' ;25
Syntax1End Label Byte
;
Syntax2Screen DB 13,10,'Parameters may be entered in any order ' ;06
DB 'except as noted below.',13,10
DB 13,10,'RPSORT may be run as a filter using red' ;08
DB 'irection.',13,10
DB 13,10,' For example: RPSORT opfile';10
DB 13,10,' or: DIR | RPSORT | MORE',13,10 ;11
DB 13,10,'Input and output may be specified direc' ;13
DB 'tly. Input is one or more filespecs'
DB 13,10,'separated by plus signs. Output must b' ;14
DB 'e a single file. Input filespec(s) must'
DB 13,10,'precede output filespec. Filespecs may' ;15
DB ' include a path. Wildcard characters'
DB 13,10,'are allowed. Input files are sorted to' ;16
DB 'gether into the single output file.',13,10
DB 13,10,' For example: RPSORT ipfile*.txt+c' ;18
DB ':\mydir\ip??file.txt opfile',13,10
DB 13,10,'By default, RPSORT assumes the input is' ;20
DB ' a text file and that the entire line is'
DB 13,10,'the sort key. The sort is case insensi' ;21
DB 'tive (lower equals upper case) and just'
DB 13,10,'like the DOS SORT it equates foreign le' ;22
DB 'tters, punctuation, and currency symbols'
DB 13,10,'to their English equivalents. The foll' ;23
DB 'owing screens describe other options.',13,10
Syntax2End Label Byte
;
Syntax3Screen DB 13,10,'/Q if it is the first parameter suppres' ;06
DB 'ses copyright and success messages.'
DB 13,10,'/Eerrfile directs error messages to a f' ;07
DB 'ile. Should precede all but /Q.'
DB 13,10,'/? or ? produces these syntax screens. ' ;08
DB ' RPSORT with no parameters also does.'
DB 13,10,'/A does an ASCII sort. This is case se' ;09
DB 'nsitive (lower not equal upper case).'
DB 13,10,'/B tells RPSORT to ignore any control b' ;10
DB 'reak entered from the keyboard.'
DB 13,10,'/C says that text keys are terminated b' ;11
DB 'y a binary zero (C language strings).'
DB 13,10,'/D deletes any record whose sortkeys du' ;12
DB 'plicate those in a previous record.'
DB 13,10,'/Fnnnn says that the input consists of ' ;13
DB 'fixed length records of nnnn bytes.'
DB 13,10,'/N deletes any null lines (those consis' ;14
DB 'ting only of a CRLF sequence).'
DB 13,10,'/P uses the first byte of text keys as ' ;15
DB 'the key length (Turbo Pascal strings).'
DB 13,10,'/R specifies a reverse (descending orde' ;16
DB 'r) sort.'
DB 13,10,'/Td designates drive to be used for tem' ;17
DB 'p files instead of default drive.'
DB 13,10,'/Z says to ignore any Ctrl-Z in a text ' ;18
DB 'file and use the entire file. Normally'
DB 13,10,' RPSORT (just like MS-DOS) treats Ctr' ;19
DB 'l-Z as the end of a text file.',13,10
DB 13,10,'/R applies to all sort key definitions ' ;21
DB 'while /A, /C and /P apply to all text'

DB 13,10,"sort keys. Sort key definitions can't " ;22
DB 'over-ride them. To sort some keys one'
DB 13,10,'way and some another way, use the sort ' ;23
DB 'key attributes on the next screen.',13,10
Syntax3End Label Byte
;
Syntax4Screen DB 13,10,'A sort key definition has the above for' ;06
DB 'm with no spaces between the attributes.',13,10
DB 13,10,' col is starting column of this key. ' ;08
DB ' Col 1 is the first col in the record.'
DB 13,10,' len is the length of this key.' ;09
DB 13,10,' A does an ASCII (case sensitive) s' ;10
DB 'ort for the key.'
DB 13,10,' C treats a binary zero as the end ' ;11
DB 'of the key (i.e. a C type string).'
DB 13,10,' Len should equal max C string le' ;12
DB 'ngth (e.g. if "char mystr[8]", len = 8).'
DB 13,10,' F sorts this key as 80x87 binary f' ;13
DB 'loating point number. Len is 4, 8 or 10.'
DB 13,10,' I sorts this key as a signed binar' ;14
DB 'y integer. This may be any length.'
DB 13,10,' M sorts this key as a binary float' ;15
DB 'ing point number defined by BASICA,'
DB 13,10,' GWBASIC or older versions of Mic' ;16
DB 'rosoft QuickBASIC. Len is 4 or 8.'
DB 13,10,' P uses the first byte of this key ' ;17
DB 'as the key length (a Pascal string).'
DB 13,10,' Len must equal max Pascal string' ;18
DB ' length + 1 (e.g. if string[8] len = 9).'
DB 13,10,' R does a reverse (descending) sort' ;19
DB ' for this key.'
DB 13,10,' T sorts this key as a Turbo Pascal' ;20
DB ' number of type "real". Len must be 6.'
DB 13,10,' U sorts this key as an unsigned bi' ;21
DB 'nary integer. This may be any length.',13,10
DB 13,10,'Attributes F, I, M, P, T and U are only' ;23
DB ' allowed for fixed length records.',13,10
Syntax4End Label Byte
;
Syntax5Screen DB 13,10,'1. RPSORT as a filter. Input is a text' ;06
DB ' file. Sort key is the entire line.',13,10
DB 13,10,' RPSORT SORT.DAT' ;08
DB 13,10
DB 13,10,'2. Combine two files. Do an ASCII (cas' ;10
DB 'e sensitive) sort. Write the output to'
DB 13,10,' SORT.DAT. Put temp files on the C d' ;11
DB 'rive. Key is 5 bytes at column 4.',13,10
DB 13,10,' RPSORT DATA1.DAT+C:\MYDIR\DATA2' ;13
DB '.DAT SORT.DAT /TC /A /+4:5',13,10
DB 13,10,'3. Sort a file of 90 byte records. The' ;15
DB ' first key is a Turbo Pascal real number'
DB 13,10,' at column 15. The second key is a T' ;16
DB 'urbo Pascal string of type string[11].',13,10
DB 13,10,' RPSORT PASFILE.DAT SORTFILE.DA' ;18
DB 'T /F90 /+15:6T /+1:12P',13,10
DB 13,10,'4. Sort a file of 70 byte records. Bot' ;20
DB 'h keys are C type strings. The first'
DB 13,10,' key is ASCII (case sensitive) the se' ;21
DB 'cond is case insensitive by default.',13,10
DB 13,10,' RPSORT CFILE.DAT SORT.DAT /F70' ;23
DB ' /C /+5:10A /+23:7',13,10
DB 13,10,' (Press PageUp' ;25
Syntax5End Label Byte
;
Syntax1List DW Syntax,SyntaxEnd-Syntax
DW Syntax1Screen,Syntax1End-Syntax1Screen
DW LastLine2,LastLineEnd-LastLine2
Syntax2List DW Syntax,SyntaxEnd-Syntax
DW Syntax2Screen,Syntax2End-Syntax2Screen
DW LastLine,LastLineEnd-LastLine
Syntax3List DW Syntax,SyntaxEnd-Syntax
DW Syntax3Screen,Syntax3End-Syntax3Screen
DW LastLine,LastLineEnd-LastLine
Syntax4List DW Syntax,SyntaxEnd-Syntax
DW Syntax4Screen,Syntax4End-Syntax4Screen
DW LastLine,LastLineEnd-LastLine
Syntax5List DW Syntax,SyntaxEnd-Syntax
DW Syntax5Screen,Syntax5End-Syntax5Screen
DW LastLine3,LastLineEnd-LastLine3
SyntaxLastList Label Word
SyntaxPtrs DW Syntax1List,Syntax2List,Syntax3List,Syntax4List
DW Syntax5List,SyntaxLastList
SyntaxScrNo DW 0
;
Even
;
ParmBeg DW ?
ParmChars DW ?
ParmBegInit DW ?
ParmCharsInit DW ?
CodePointer DW CompRoutine
ModelCodeLoc DW ?
CompMove DW ?
FixedLen DW 0
LongestLen DW 0
MaxAllowLen DW 32750
KeyTypInit DW 0
KeyTyp DW 0
StartCol DW 0
RelCol DW 0
KeyLen DW 0
PrevEndCol DW 0
LenBuckSize DW 2
WriteHandle DW StdOutput
OutputHandle DW StdOutput
ReadHandle DW StdInput
ErrorHandle DW StdError
TempHandle1 DW 0
TempHandle2 DW 0
TempHandle3 DW 0
ExtraNumb DW 0
HowManySegs DW 0
ThisTimeSegs DW 0
LineEnd DW CRLF
NewLine DW CRLF
DataMax DW 65520
DataPara DW 0FFFH
SegCount DW 0 ;SegCount = (seg ct) * 2.
SegNumb DW 0 ;Segment info ptr.
MaxPara DW 23FEH ;This is 144K. Allows loading full 64K of data.
MinPara DW 0C00H ;Require 48K (or 1/3 total mem) to load data.
MinBuff DW 0400H ;Reserve 16K (or 1/9 total mem) for write buff.
MergeBuff DW 0800H ;Reserve 32K for writebuff during merge.
MergeSeg DW 0400H ;Let minimum merge segment be 16K.
BlockCt DW 0 ;Count of entries in table of block locations.
BlockBeg DW 0008H ;First entry in table of block locations.
BlockEnd DW 0008H ;Next entry in table of block locations.
PointerMax DW 65520 ;Max val for ptr end.
WriteBuffEnd DW 65535 ;Max space for write buff.
PrevAddr Label DWord
PrevOfs DW 0FFFFH
PrevSeg DW 0
PrevBuffOfs DW 0FFFFH
InputAddr DW ?
InputEnd DW ?
ErrorAddr DW ?
OutputAddr DW ?
OutputEnd DW ?
StackHigh DW ?
All1Start DW ?
SecondStart DW ?
Fix1Start DW ?
Line1Start DW ?
CompFinish DW ?
OrigStart DW ?
FixPlus2 DW ?
ParmOfs DW ? ;Pts to next byte of cmd line parms.
ParmBytes DW ? ;Ct of remain cmd line bytes.
RetFromErrSP DW ?
ReservedForPtrs DW 0
CommandSize DW 0600H
LeaveCmdSize DW 2A00H
;
ERRORWord DB ' ERROR '
DidErrorWord DB 0
Quote DB '"'
TwelveSpaces DB 13,10,12 Dup(' ')
GotParms DB 0
GotSortKey DB 0
GotInput DB 0
GotOutput DB 0
FromMain DB 0
MoreData DB 0
NeedMerge DB 0
FinalOutput DB 0FFH
OpenedOutput DB 0
HaveSpecs DB 0
EndData DB 0
InputFileCt DB 0
WildCard DB 0
TotalFileCt DB 1
DefaultDisk DB 0
TempDisk DB 0
UseRcdLen DB 0
GotCtrlZ DB 0
PrtCtrlZ DB 1AH
SkipSetupTop DB 0
IgnoreCtrlZ DB 0
FirstExtra DB 0FFH
FirstMerge DB 0FFH
UseExtra DB 0
LastIsExtra DB 0
MustSetPtrs DB 0
ElimDup DB 0
ElimNull DB 0
NoBreak DB 0
ParmPass DB 0
GotData DB 0
GotStringParm DB ?
GotBinaryParm DB ?
GotCParm DB ?
GotPParm DB ?
GotEParm DB ?
CtrlState DB ?
GotError DB 0
KeyCount DB 0
GotKeyErr DB 0
ErrorCode DB 0
PtrsAgain DB 0
NulASCIIZ DB 'NUL',0
;
GetParmsFin Proc Near
Cmp ParmPass,2
Jb GetParms
Cmp GotParms,0
Jnz GetParmsRet
Mov AX,IoctlGet
Mov BX,StdInput ;Handle for std ip.
Int DOS ;Ck if ip is a device.
Or DL,DL ;If no sign, it is a file
Jns GetParmsRet ;else it is a device.
Jmp HelpScreen
GetParmsRet: Ret
;
GetParmsFin Endp
;
DoDisplayError: Call DisplayError
Jmp Short RestorePtr
DoDispErrParm: Call DispErrorParm
RestorePtr: Mov SP,RetFromErrSP
Mov CX,ParmChars
Mov SI,ParmBeg
Dec CX
Inc SI
SkipParm: Jcxz NextParmChar
Lodsb
Dec CX
Cmp AL,Space
Jz NextParmChar
Cmp AL,Slash
Jnz SkipParm
Dec SI
Inc CX
Jmp Short NextParmChar
;
GetParms Proc Near
Cld
Mov RetFromErrSP,SP
Inc ParmPass
Mov SI,ParmBegInit ;Ofs of cmd line parms.
Mov CX,ParmCharsInit ;Len of cmd line parms.
Mov BX,Offset XlatTable
NextParmChar: Jcxz GetParmsFin ;No more parms if CX = 0.
Mov ParmBeg,SI
Mov ParmChars,CX
Lodsb
Dec CX
Cmp AL,Space
Jz NextParmChar
Cmp AL,Question
Jnz IsItSlash
Jmp HelpScreen
IsItSlash: Cmp AL,Slash
Jz GotSlash
Cmp ParmPass,1
Jz DoFileName
Jmp SkipParm
DoFileName: Mov GotParms,0FFH
Call SaveFileAddr
Jmp NextParmChar
GotSlash: Jcxz ErrSlashNull ;/ must be followed by something.
Dec CX
Lodsb ;Load char following /.
Cmp AL,Question
Jnz GotParm
Jmp HelpScreen
ErrSlashNull: Mov DX,Offset SlashNullMsg
Jmp DoDisplayError
GotParm: Mov GotParms,0FFH
Cmp AL,Space
Jz ErrSlashNull
Cmp AL,Slash
Jnz IsItSortKey
Inc CX
Dec SI
Jmp ErrSlashNull
IsItSortKey: Cmp AL,'+' ;Is it sort key spec.
Jz DoSortKey ;If "+" then must be sort key.
Cmp AL,'0' ;If number then
Jb MustBeSwitch ;must be
Cmp AL,':' ;sortkey.
Ja MustBeSwitch
Inc CX
Dec SI
DoSortKey: Cmp ParmPass,2
Jz DoGetSortKey
Jmp SkipParm
DoGetSortKey: Call GetSortKey
Jmp NextParmChar
MustBeSwitch: Cmp ParmPass,1
Jz DoSwitch
Jmp SkipParm
DoSwitch: Xlat ;Lower case to upper case.
Mov DX,AX
Call GetIndicBit ;Chk for valid parm.
Js IsItFixed ;Jump if not.
Cmp AX,KeyPascal
Ja IsItFixed ;Jump if not valid global parm.
Or KeyTypInit,AX ;Set global switch bit.
Jmp Short CheckExtraChar
ErrBadRcdLen: Mov FixedLen,32750
Mov DX,Offset BadRcdLenMsg
Jmp DoDispErrParm
IsItFixed: Mov AX,DX
Cmp AL,FixedParm
Jnz ChkIfIgnCtrlZ
Cmp FixedLen,0
Jz TestFixedLen
Mov AX,3446H ;Error 004: second /F.
Jmp Short Second
TestFixedLen: Jcxz ErrBadRcdLen
Dec CX
Lodsb
Call GetNumb
Cmp DX,32750
Ja ErrBadRcdLen
Or DX,DX
Jz ErrBadRcdLen
Mov FixedLen,DX
Call AnyExtraChar
Mov LongestLen,DX
Inc DX
Inc DX
Mov FixPlus2,DX
Mov LenBuckSize,0
Jmp NextParmChar
ChkIfIgnCtrlZ: Cmp AL,CtrlZParm
Jnz ChkIfElimDup
Mov IgnoreCtrlZ,0FFH
CheckExtraChar: Call AnyExtraChar
Jmp NextParmChar
ChkIfElimDup: Cmp AL,DupParm
Jnz ChkIfNoBreak
Mov ElimDup,0FFH
Jmp CheckExtraChar
ChkIfNoBreak: Cmp AL,NoBreakParm
Jnz ChkIfElimNull
Mov NoBreak,0FFH
Jmp CheckExtraChar
ChkIfElimNull: Cmp AL,NullParm
Jnz ChkIfErrFile
Mov ElimNull,0FFH
Jmp CheckExtraChar
ChkIfErrFile: Cmp AL,ErrorParm
Jnz ChkIfTemp
Call CheckErrorFile
Jmp NextParmChar
ChkIfTemp: Call IsItTemp
Jnz BadSwitch
Jmp CheckExtraChar
BadSwitch: Mov DX,Offset BadSwitchMsg
Jmp DoDispErrParm
Second: Mov SecondTFMsg+15,AL
Mov SecondTFMsg+2,AH
Mov DX,Offset SecondTFMsg
Jmp DoDisplayError
GetParms Endp
;
AnyExtraChar Proc Near
Jcxz AnyExtraRet
Cmp Byte Ptr [SI],Slash
Jz AnyExtraRet
Cmp Byte Ptr [SI],Space
Jz AnyExtraRet
ExtraChar: Jmp BadSwitch
AnyExtraRet: Ret
AnyExtraChar Endp
;
CheckErrorFile Proc Near
Cmp GotEParm,0
Jz CheckErrFile2
Mov AX,3745H ;Error 007: second /E.
Jmp Second
CheckErrFile2: Mov GotEParm,0FFH
Jcxz NoErrorSpec
Mov ErrorAddr,SI ;Offset of error file name
Dec CX
Lodsb
Cmp AL,Space
Jz NoErrorSpec
Cmp AL,Slash
Jz NoErrorSpec
NewError: Jcxz GotErrorName
Lodsb
Dec CX
Cmp AL,Space
Jz DecErrorPtr
Cmp AL,Slash
Jnz NewError
DecErrorPtr: Dec SI
Inc CX
GotErrorName: Mov AL,0
Xchg AL,[SI]
Push AX
Push SI
Push CX
Mov AX,CreateFile
Mov DX,ErrorAddr
Xor CX,CX
Int DOS
Jc FullErrDir
Mov ErrorHandle,AX
Pop CX
Pop SI
Pop AX
Xchg AL,[SI]
Ret
NoErrorSpec: Mov DX,Offset NoErrorSpecMsg
Jmp DoDispErrParm
FullErrDir: Pop CX
Pop SI
Pop AX
Xchg AL,[SI]
Mov DX,Offset FullErrDirMsg
Jmp DoDispErrParm
CheckErrorFile Endp
;
HelpScreen Proc Near
Mov SyntaxScrNo,0
Mov DI,Offset Syntax1List
Mov SI,Offset Syntax2List
Call PrintScreen2
HelpScreen1: Mov AX,ClearReadNoEcho
Int DOS
HelpScreen2: Or AL,AL
Jz GetExtended
Cmp AL,Escp
Jz NoMoreScreens
ReadAnother: Mov AX,ReadNoEcho
Int DOS
Jmp HelpScreen2
GetExtended: Mov AX,ReadNoEcho
Int DOS
Cmp AL,PageUp
Jz DoPageUp
Cmp AL,PageDown
Jnz ReadAnother
DoPageDown: Mov DI,SyntaxScrNo
Cmp DI,4
Je ReadAnother
Inc SyntaxScrNo
Jmp Short DispScreen
DoPageUp: Mov DI,SyntaxScrNo
Cmp DI,0
Je ReadAnother
Dec SyntaxScrNo
DispScreen: Call PrintScreen
Jmp HelpScreen1
NoMoreScreens: Xor AL,AL
Jmp GoBack
HelpScreen Endp
;
PrintScreen Proc Near
Mov DI,SyntaxScrNo
Shl DI,1
Add DI,Offset SyntaxPtrs
Lea SI,[DI+2]
Mov DI,[DI]
Mov SI,[SI]
PrintScreen2: Mov DX,[DI]
Mov CX,[DI+2]
Call WriteStdError2
Add DI,4
Cmp DI,SI
Jb PrintScreen2
Ret
PrintScreen Endp
;
IsItTemp Proc Near
Cmp AL,TempParm
Jnz IsItTempRet
Cmp TempDisk,0
Jz IsItTemp2
Mov AX,3654H ;Error 006: second /T.
Jmp Second
IsItTemp2: Mov AX,SelectDisk
Mov DL,DefaultDisk
Sub DL,41H
Int DOS
Add AL,40H
Mov DL,AL ;Max drive letter.
Xor DH,DH ;Count of drives
NextTempDrive: Jcxz CheckTempCt
Lodsb
Dec CX
Xlat
Cmp AL,Space
Je CheckTempCt
Cmp AL,Slash
Jz CheckTempCT
Cmp AL,'A'
Jb BadDriveLett
Cmp AL,'Z'
Ja BadDriveLett
Cmp AL,DL
Ja NotExistDrive
Inc DH
Mov TempDisk,AL
Jmp NextTempDrive
CheckTempCT: Dec DH
Js BadDriveLett2
Jnz BadDriveLett2
Jcxz IsItTempOK
Inc CX
Dec SI
IsItTempOK: Xor DX,DX
IsItTempRet: Ret
BadDriveLett: Mov DX,Offset NgDriveMsg
Jmp DoDispErrParm
BadDriveLett2: Mov DX,Offset BadDriveMsg
Jmp DoDispErrParm
NotExistDrive: Mov DX,Offset NotExistMsg
Jmp DoDispErrParm
IsItTemp Endp
;
GetIndicBit Proc Near
Cmp AL,'A'
Jb MakeFFFF
Cmp AL,'Z'
Ja MakeFFFF
Push BX
Mov BX,Offset IndicatorBits - 'A'
Xlat ;Get indicator bit.
Pop BX
Cmp AL,255
Jz MakeFFFF
Mov AH,0
Cmp AL,81H
Jb WhatKind
Sub AL,80H
Xchg AL,AH
WhatKind: Cmp AX,KeyReverse
Jz GetIndicRet
Cmp AX,KeyPascal
Ja IsItNumbIndic
Mov GotStringParm,0FFH
Jnz GetIndicRet
Jmp Short GetIndicRet
IsItNumbIndic: Cmp AX,KeyFloat
Jmp Short GetIndicRet
MakeFFFF: Mov AX,65535
GetIndicRet: Or AX,AX
Ret
GetIndicBit Endp
;
GetSortKey Proc Near
Mov GotSortKey,0FFH
Call CreateKey ;Setup default sort key rcd.
Mov GotStringParm,0
Mov GotBinaryParm,0
Mov GotCParm,0
Mov GotPParm,0
Mov GotKeyErr,0
NextKeyParm: Jcxz JmpChkKeyIn ;Jmp if no more parms.
Dec CX
Lodsb ;Get next sort key byte.
Xlat ;Conv low case to up case.
Cmp AL,Space ;If space this sort key is done,
Jnz IsNextSlash
JmpChkKeyIn: Jmp ChkKeyIn ;go get the next one.
IsNextSlash: Cmp AL,Slash ;If / this sort key is done,
Jz JmpChkKeyIn ;go get the next one.
Mov DX,AX
Call GetIndicBit ;Chk for valid parm.
Jns CmpKeyRev
Jmp CheckKeyLen ;Jump if not.
CmpKeyRev: Cmp AX,KeyReverse
Je JmpSaveIndic
Cmp AX,KeyPascal
Jbe CmpGotBin
Jmp CheckNumbStr
CmpGotBin: Cmp GotBinaryParm,0
Jz CmpKeyZero
Test GotKeyErr,GotBinStrErr
Jnz CmpKeyZero
Or GotKeyErr,GotBinStrErr
Mov DX,Offset BinaryStringMsg
Call DispErrorParm
CmpKeyZero: Cmp AX,KeyZero
Jnz PascalCmp
Mov GotCParm,0FFH
Cmp GotPParm,0
Jnz PascalZeroNg
Test KeyTypInit,KeyPascal
Jnz DoPSwitchCKey
Jmp SaveIndic
DoPSwitchCKey: Mov SwitchKeyNGMsg+2,'5'
Mov SwitchKeyNGMsg+5,'C'
Mov SwitchKeyNGMsg+33,'P'
Mov DX,Offset SwitchKeyNGMsg
Call DispErrorParm
JmpSaveIndic: Jmp SaveIndic
PascalZeroNG: Mov DX,Offset PascalZeroNGMsg
Call DispErrorParm
Jmp SaveIndic
PascalCmp: Cmp AX,KeyPascal
Ja CheckNumbStr
Je SetGotPParm
Jmp SaveIndic
SetGotPParm: Mov GotPParm,0FFH
Cmp GotCParm,0
Jnz PascalZeroNg
Test KeyTypInit,KeyZero
Jz CheckPasFix

Mov SwitchKeyNGMsg+2,'6'
Mov SwitchKeyNGMsg+5,'P'
Mov SwitchKeyNGMsg+33,'C'
Mov DX,Offset SwitchKeyNGMsg
Call DispErrorParm
CheckPasFix: Cmp FixedLen,0
Jnz SaveIndic
Mov DX,Offset PNotFNGMsg
Call DispErrorParm
Jmp Short SaveIndic
CheckNumbStr: Cmp GotStringParm,0
Jz CheckNumbFix
Test GotKeyErr,GotBinStrErr
Jnz SaveIndic
Or GotKeyErr,GotBinStrErr
Mov DX,Offset BinaryStringMsg
Call DispErrorParm
Jmp Short SaveIndic
CheckNumbFix: Cmp FixedLen,0
Jnz CheckPrevNumb
Test GotKeyErr,GotNumbNotFErr
Jnz CheckPrevNumb
Or GotKeyErr,GotNumbNotFErr
Mov DX,Offset NumbNotFNGMsg
Call DispErrorParm
CheckPrevNumb: Cmp GotBinaryParm,0
Mov GotBinaryParm,0FFH
Jz SaveIndic
Mov DX,KeyTyp
And DX,KeyInteger+KeyUnSigned+KeyMicro+KeyTurbo+KeyFloat
Test DX,AX
Jnz SaveIndic ;If same type of binary then ok.
Test GotKeyErr,GotDiffBinErr
Jnz SaveIndic
Or GotKeyErr,GotDiffBinErr
Mov DX,Offset DiffBinaryMsg
Call DispErrorParm
SaveIndic: Or KeyTyp,AX ;Set the switch bit.
Jmp NextKeyParm ;Get next byte in sort key.
CheckKeyLen: Mov AX,DX
Cmp AL,LengthParm ;Chk if parm is key len.
Jz GetKeyLen ;If so jmp.
Cmp AL,'0'
Jb BadSortKey
Cmp AL,'9'
Ja BadSortKey
Call GetNumb ;Else must be start col.
Cmp DX,32750
Ja BadStartCol
Or DX,DX
Jz BadStartCol
Cmp StartCol,0
Jnz SecondStartCol ;Jmp if already got StartCol.
Mov StartCol,DX ;Store start col.
Jmp NextKeyParm
GetKeyLen: Jcxz BadKeyLen ;Len must have at least one digit.
Dec CX
Lodsb ;Load 1st digit of len.
Call GetNumb ;Returns numeric val in DX.
Cmp DX,32750
Ja BadKeyLen
Or DX,DX
Jz BadKeyLen
Cmp KeyLen,0
Jnz SecondKeyLen ;Jmp if already got KeyLen.
Mov KeyLen,DX ;Store key len.
Jmp NextKeyParm ;Get nxt byte of sort key.
ChkKeyIn: Push AX
Call ChkKeyInRcd
Pop AX
Jcxz GetSortKeyRet
Cmp AL,Space
Jz GetSortKeyRet
Inc CX
Dec SI
GetSortKeyRet: Ret
BadStartCol: Mov DX,Offset BadStartMsg
Call DispErrorParm
Jmp NextKeyParm
BadSortKey: Test GotKeyErr,0FFH
Jz DoBadSortKey
Jmp NextKeyParm
DoBadSortKey: Mov DX,Offset BadKeyMsg
Call DispErrorParm
Jmp NextKeyParm
SecondStartCol: Mov DX,Offset SecondStartMsg
Call DispErrorParm
Jmp NextKeyParm
BadKeyLen: Mov DX,Offset BadKeyLenMsg
Call DispErrorParm
Jmp NextKeyParm
SecondKeyLen: Mov DX,Offset SecondKeyLenMsg
Call DispErrorParm
Jmp NextKeyParm
GetSortKey Endp
;
;
JmpNoMem1: Jmp NoMemory
;
CreateKey Proc Near
Push CX
Push SI
Cld
Add KeyCount,1
Mov AX,StartCol
Test KeyTyp,KeyInteger+KeyUnsigned+KeyFloat+KeyMicro+KeyTurbo
Jz NotBinNumb
Sub AX,KeyLen
Dec AX
Jmp Short SavePrevEnd
NotBinNumb: Add AX,Keylen
SavePrevEnd: Mov PrevEndCol,AX
Mov StartCol,0
Mov RelCol,0
Mov KeyLen,0
Mov DI,CodePointer ;DI = addr of next key rout.
Mov AX,KeyTypInit
Test AX,KeyPascal
Jz SetKeyTyp
Cmp KeyCount,1
Jnz SetKeyTyp
Cmp FixedLen,0
Jnz CheckPAndC
Mov DX,Offset PMustBeFMsg
Call DisplayError
CheckPAndC: Test AX,KeyZero
Jz SetKeyTyp
Mov DX,Offset PAndCNGMsg
Call DisplayError
SetKeyTyp: Mov KeyTyp,AX
Cmp GotError,0
Jz SetKeyTyp2
Jmp Short CreateKeyRet
SetKeyTyp2: Mov SecondStart,0
Cmp DI,Offset CompRoutine
Jz All1
Mov DI,OrigStart
Mov SI,CompMove
Add SI,Offset SecondBeg
Mov CX,Offset SecondEnd - Offset SecondBeg
Mov SecondStart,DI
Rep Movsb
All1: Mov SI,CompMove
Add SI,Offset All1Beg
Mov CX,Offset All1End - Offset All1Beg
Mov All1Start,DI
Rep Movsb
Mov CodePointer,DI
Cmp DI,ModelCodeLoc
Jb CreateKeyRet
NoMemory9: Jmp NoMemory
CreateKeyRet: Pop SI
Pop CX
Ret
CreateKey Endp
;
FileAndRedir: Mov DX,Offset FileAndRedirMsg
Jmp DoDispErrParm
;
SaveFileAddr Proc Near
Test IpDevice,80H
Jz FileAndRedir ;Jump if input redirected.
Dec SI
Inc CX
Cmp GotInput,0
Jnz OutputFile
Mov GotInput,0FFH
Mov HaveSpecs,0FFH
Mov InputAddr,SI
NewInput: Jcxz MisplacedPlus ;Jump if plus at end.
Lodsb
Dec CX
Cmp AL,'+'
Jz MisplacedPlus ;Jump if plus at beginning.
Inc InputFileCt
NextNameChar: Jcxz SaveInputEnd2
Lodsb
Dec CX
Cmp AL,Space
Jz SaveInputEnd
Cmp AL,Slash
Jz SaveInputEnd
Cmp AL,'+'
Jnz NextNameChar
Jmp Short NewInput
SaveInputEnd: Dec SI
Inc CX
SaveInputEnd2: Mov InputEnd,SI
Mov AL,InputFileCt
Mov TotalFileCt,AL
Ret
;
OutputFile: Cmp GotOutput,0
Jnz SecondIpOp
Mov GotOutput,0FFH
Mov OutputAddr,SI
NextOpChar: Jcxz SaveOutputEnd2
Lodsb
Dec CX
Cmp AL,Space
Jz SaveOutputEnd2
Cmp AL,Slash
Jz SaveOutputEnd
Cmp AL,'+'
Jnz NextOpChar
Jmp Short OutputPlus
SaveOutputEnd: Dec SI
Inc CX
SaveOutputEnd2: Mov OutputEnd,SI
Ret
;
SecondIpOp: Mov DX,Offset SecondIpMsg
Jmp DoDispErrParm
OutputPlus: Mov DX,Offset OutputPlusMsg
Jmp DoDispErrParm
MisplacedPlus: Mov DX,Offset MisplacedMsg
Jmp DoDispErrParm
;
SaveFileAddr Endp
;
AllocError: Mov DX,Offset AllocMsg
Jmp DisplayExit
;
SetupMemory Proc Near
Mov BX,SP ;Add 31 to SP val assures that BX pts
Add BX,31 ;beyond stack and allows round para up.
Mov CL,4
Shr BX,CL ;Convert to para.
Mov AH,SetBlock
Int DOS ;Dealloc mem above stack.
Jc AllocError
Mov AH,AllocMemory
Mov BX,0FFFFH ;Ask how much mem avail.
Int DOS ;Ret BX = avail para.
Cmp Ax,8 ;Code 8 means not enough mem, so OK.
Jnz AllocError ;Else is fatal.
Mov AH,AllocMemory ;Now alloc all avail mem.
Int DOS
Jc AllocError
Cmp BX,0200H ;Insist on 512 para (8192 bytes).
Jae SetupMem2
NoMemory: Mov DX,Offset NoMemoryMsg
Jmp DisplayExit
SetupMem2: Mov MemParaAvail,BX
Mov MemoryBegSeg,AX
Mov NextSeg,AX
Mov NextOfs,0
Mov Data.Segm,AX
Mov Data.Beg,0
Add BX,AX ;Seg addr of end of avail space.
Mov MemoryEndSeg,BX ;End of avail mem.
Dec BX ;Allow one para for block table.
Mov LastSeg,BX ;End of mem avail for data.
Mov BlockSeg,BX
Mov DS,BX
Mov DS:Word Ptr[000CH],0
Mov DS:Word Ptr[000EH],0
Push CS
Pop DS
Mov CX,FixedLen
Jcxz Short MakeOfs2 ;Jmp if not fixed len.
Cmp CX,2
Jae FixedLenGE2
Mov DataMax,32752
Mov DataPara,07FFH
Mov AX,32752
Jmp Short FixedMaxPara
FixedLenGE2: Mov AX,65520
Xor DX,DX
Div CX ;AX is max number of rcds in 65520 bytes.
Mov BX,65520
Sub BX,DX ;Get ofs after last byte of last rcd.
Mov DataMax,BX ;Save in DataMax.
Add BX,15
Mov CL,4
Shr BX,CL
Mov DataPara,BX ;Save # of para to contain rcds.
FixedMaxPara: Mul FixPlus2 ;DX:AX = space for DataMax + pointers.
Add AX,15
Adc DX,0
Shr DX,1 ;1st shift involves DX because might exceed 64K.
Rcr AX,1
Mov CL,3
Shr AX,CL ;AX = para for DataMax + ptrs.
Add AX,0400H ;Add 16K for write buff.
Mov MaxPara,AX
Jmp Short ChkMinPara
MakeOfs2: Mov NextOfs,2
Mov DS,NextSeg
Mov AX,CS:LineEnd
Mov DS:Word Ptr[0],AX
Push CS
Pop DS
ChkMinPara: Mov AX,MemParaAvail
Mov BX,AX
Cmp AX,4800H ;Do we have at least 288K avail.
Jae CalcMaxAllow ;If so, MergeBuff=32K, MergeSeg=16K.
Xor DX,DX
Push AX
Mov CX,9 ;Else MergeBuff = ninth of avail mem.
Div CX
Mov MergeBuff,AX
Shr AX,1
Cmp AX,0100H
Jae SvMergeSeg
Mov AX,0100H ;At least 4K for MergeSeg.
SvMergeSeg: Mov MergeSeg,AX ;MergeSeg = one half of MergeBuff.
Pop AX
Cmp AX,2400H ;Do we have at least 144K avail.
Jae CalcMaxAllow ;If so, MinPara = 48K, MinBuff = 16K.
Xor DX,DX
Mov CX,3 ;Else MinPara = third of avail memory.
Div CX
Mov MinPara,AX
Xor DX,DX
Div CX ;And MinBuff = 1/9 avail memory.
Mov MinBuff,AX
CalcMaxAllow: Sub BX,MinBuff ;MemParaAvail - MinBuff.
Shr BX,1 ;One half of avail memory.
Dec BX
Dec BX ;Allow for two one para ptr segs.
Cmp BX,07FFH ;If GE 32752 bytes then OK.
Jae SetupMemRet
Mov CL,4
Shl BX,CL
Mov MaxAllowLen,BX
Cmp BX,FixedLen
Jb CantHoldTwo
SetupMemRet: Mov AX,MemParaAvail
Sub AX,CommandSize
Jc SetupMemRet2
Mov CX,12
Mul CX
Cmp FixedLen,0
Jz StoreBelow
Mov BX,AX ;BX = BelowLow.
Mov AX,DX ;AX = BelowHi.
Xor DX,DX ;DX:AX = BelowHi.
Mov CX,FixPlus2
Div CX ;AX = Hi part of BelowHi / FixPlus2.
Xchg AX,BX ;BX = Hi BelowHi/FixPlus2. DX:AX = Rem:BelowLow.
Div CX ;BX:AX = Below / FixPlus2.
Mov CX,FixedLen
Xchg BX,AX ;BX = Quotient low. AX = Quotient high.
Mul CX ;AX = FixedLen * Quotient high.
Xchg BX,AX ;BX = FixedLen*QuotHi. AX = QuotLow.
Mul CX ;DX:AX = QuotLow * FixedLen.
Add DX,BX ;DX:AX = (Below / FixPlus2) * FixedLen.
StoreBelow: Mov BelowLow,AX
Mov BelowHi,DX
SetupMemRet2: Ret
CantHoldTwo: Cmp CS:MaxAllowLen,32750
Jb DoTwoRcdMsg
Mov DX,Offset LinGTMaxMsg
Jmp DisplayExit
DoTwoRcdMsg: Mov DX,Offset TwoRcdMsg
Jmp DisplayExit
SetupMemory Endp
;
ReSetupMemory Proc Near
Cmp FixedLen,0
Jz ResetLines
Mov AX,MemoryBegSeg
Mov NextSeg,AX
Mov NextOfs,0
Mov SegCount,0
Ret
ResetLines: Mov DI,SegCount
Shl DI,1
Mov AX,NextSeg
Mov BX,Data.Segm[DI]
Sub AX,BX ;Full para in last part line.
Mov CL,4
Shl AX,CL ;Bytes equiv to para in part line.
Mov DS,BX
Mov SI,CS:Data.Beg[DI] ;DS:SI pts to part line.
Sub AX,SI ;Subt ofs of part line.
Add AX,CS:NextOfs ;Add bytes after last para.
Mov BX,AX ;Hold len of last part line.
Mov DX,AX
And AL,0F0H
Sub DX,AX ;Bytes after full para.
Mov CS:NextOfs,DX ;NextOfs after move.
Shr AX,CL ;Number of para.
Add AX,CS:Data.Segm[0] ;Compute NextSeg after move.
Mov CS:NextSeg,AX
Mov CX,BX ;Recover len of last part line.
Xor DI,DI
Mov ES,CS:Data.Segm[0] ;ES:DI points to dest for move.
Cld
Shr CX,1
Jnc MovePartWords
Movsb
MovePartWords: Rep Movsw
Mov CS:SegCount,0
Mov AX,CS:LineEnd
Mov ES:Word Ptr[0],AX
Push CS
Push CS
Pop DS
Pop ES
Ret
;
ReSetupMemory Endp
;
LoadStd Proc Near
Cmp MoreData,0
Jnz DoLoadStd
Test IpDevice,80H
Jnz DeviceErr ;If sign bit is on StdIp is a device.
Mov Handle,StdInput ;Save std ip handle.
DoLoadStd: Call LoadFile ;Load the file.
Ret
DeviceErr: Mov DX,Offset DeviceMsg
Jmp DisplayExit
LoadStd Endp
;
LoadSpec Proc Near
Cmp MoreData,0
Jnz DoLoadSpec
Cmp WildCard,0
Jz LoadSpec2
Mov AX,FindNext
Int DOS
Jc LoadSpec2
Call MoveToASCIIZ ;DX=ASCIIZ offset, DI points after zero.
Jmp Short OpenSpec
LoadSpec2: Mov WildCard,0
Cmp InputFileCt,0
Jnz LoadSpec3
Clc
Ret
LoadSpec3: Dec InputFileCt
Mov DI,InputAddr
Mov DX,DI ;DX pts to ASCIIZ string.
Mov CX,InputEnd
Sub CX,DI
Cld
Mov AL,'+' ;Look for term plus
Repne Scasb ;after filespec.
Jz StoreZero ;Jmp if found term plus.
Inc DI ;Hit end of parms. Inc DI for following move.
StoreZero: Mov Byte Ptr[DI-1],0 ;Put 0 at end of ASCIIZ string.
Mov InputAddr,DI ;Save ptr to next
Call AnyWildCard
Jnc OpenSpec ;Jump if no wildcards.
Mov WildCard,0FFH
Mov AX,FindFirst
Mov CX,Hidden+System
Int DOS
Jc FileOpenNG
Call MoveToASCIIZ ;DX=ASCIIZ offset, DI points after zero.
OpenSpec: Mov AX,OpenForRead ;Open the file for read.
Int DOS
Jc FileOpenNG ;Jmp if open was no good.
Mov Handle,AX ;Save handle.
DoLoadSpec: Call LoadFile ;Load the file.
Jc LoadSpecRet
Mov BX,Handle
Mov AX,Close ;Close the file.
Int Dos
Clc
LoadSpecRet: Ret
FileOpenNg: Push DX ;Save addr of ASCIIZ string.
Call WriteNewLine
Call WriteERROR
Mov DX,Offset NoFileMsg
Mov CL,Offset NoFileEnd - Offset NoFileMsg
Call WriteStdError
Pop DX ;Recover ASCIIZ addr.
Mov CX,DI ;Pts to end of ASCIIZ.
Sub CX,DX
Dec CX ;Len of ASCIIZ.
Call WriteStdError
Call WriteNewLine
Mov CS:ErrorCode,47
Jmp ErrorExit
LoadSpec Endp
;
AnyWildCard Proc Near
; Scan from [DI-2] to [DX] and if find "?" or "*" in file name or ext (i.e.
; if find one of these before find "\" or ":":
; . Move drive and path to IpASCIIZ area.
; . Save offset of next byte in IpASCIIZ area at IpNamePtr.
; . Preserve DX and DI.
; . Return with carry set.
; Otherwise:
; . Preserve DX and DI.
; . Return with carry clear.
Mov CX,DI
Sub CX,DX
Dec CX
Lea SI,[DI-2]
Std
FindWild: Lodsb
Cmp AL,'?'
Jz FoundWild
Cmp AL,'*'
Jz FoundWild
Cmp AL,'\'
Jz NotFoundWild
Cmp AL,':'
Jz NotFoundWild
Loop FindWild
NotFoundWild: Clc
Cld
Ret
FoundWild: Dec CX
Jz OnlyFileName
ScanSlashColon: Lodsb
Cmp AL,'\'
Jz GotPath
Cmp AL,':'
Jz GotPath
Loop ScanSlashColon
OnlyFileName: Mov AX,Offset IpASCIIZ
Mov IpNamePtr,AX
Cld
Stc
Ret
GotPath: Cld
Mov SI,DX
Push DI
Mov DI,Offset IpASCIIZ
Rep Movsb
Mov IpNamePtr,DI
Pop DI
Stc
Ret
AnyWildCard Endp
;
MoveToASCIIZ Proc Near
; Copy file name at IpNameExt to [IPNamePtr].
; Load IpNamePtr into DX.
; Load DI with adress of byte after binary zero.
Cld
Mov SI,Offset IpNameExt
Mov DI,IpNamePtr
Mov CX,13
Mov DX,Offset IpASCIIZ
NextASCIIZ: Lodsb
Stosb
Cmp AL,0
Loopne NextASCIIZ
Ret
MoveToASCIIZ Endp
;
MemIsFull Proc Near
Push CS
Pop DS ;Restore ptr to code seg.
Mov MoreData,0FFH
Cmp WriteHandle,1
Ja MemIsFull2
Mov WriteHandle,0
MemIsFull2: Mov FileSizeHi,BP
Mov FileSizeLo,DI
Mov GotData,1
Mov FinalOutput,0
Stc
Ret
MemIsFull Endp
;
LoadFile Proc Near
Mov BX,Handle
Cmp CS:MoreData,0
Jz NewFile
Mov CS:MoreData,0
Mov BP,CS:FileSizeHi
Mov DI,CS:FileSizeLo
Jmp LoadFile2
NewFile: Mov AX,GetFileLen
Xor CX,CX
Mov DX,CX
Int DOS ;DX:AX = len of file
Push AX
Push DX
Mov AX,SetFileAtBeg
Xor CX,CX
Mov DX,CX
Int DOS
Pop BP
Pop DI ;BP:DI = File len.
Cmp TotalFileCt,1
Jnz NewFile2
Cmp WildCard,0
Jnz NewFile2
Mov AX,LeaveCmdSize
Cmp MemParaAvail,AX
Jb NewFile2
Mov AX,DI
Mov DX,BP
Sub AX,BelowLow
Sbb DX,BelowHi
Jnc NewFile2
Mov AX,CommandSize
Sub MemoryEndSeg,AX
Sub LastSeg,AX
Sub BlockSeg,AX
Sub MemParaAvail,AX
Push DS
Mov DS,BlockSeg
Mov DS:Word Ptr[000CH],0
Mov DS:Word Ptr[000EH],0
Pop DS
NewFile2: Mov CX,FixedLen
Jcxz LoadFile1
Mov AX,BP ;High part of file len.
Xor DX,DX
Div CX
Mov AX,DI ;Low part of file len.
Div CX ;DX = remainder of div by FixedLen.
Sub DI,DX ;Subtract remainder from file len to
Sbb BP,0 ;get multiple of FixedLen.
Or DX,DX
Jz LoadFile1
Push BP
Push DI
Mov DX,Offset ShortRcdMsg
Mov CX,Offset ShortRcdEnd - Offset ShortRcdMsg
Call WriteStdError2
Pop DI
Pop BP
LoadFile1: Mov DX,BP
Or DX,DI
Jnz LoadFile2
Jmp LoadRet
LoadFile2: Mov DS,CS:NextSeg
Mov DX,CS:NextOfs ;DS:DX = load addr.
Mov AX,DS
Mov BX,CS:LastSeg
Sub BX,AX
Sub BX,CS:ReservedForPtrs ;Avail para.
Cmp BX,CS:MaxPara
Jbe LoadFile2A
Mov CX,CS:DataMax
Jmp Short LoadFile5
LoadFile2A: Cmp BX,CS:MinPara
Jb JmpMemIsFull
Sub BX,CS:MinBuff
Cmp CS:FixedLen,0
Jnz LoadFile3
Mov CL,3 ;Use half of space for data and half for ptrs.
Shl BX,CL
Mov CX,BX
Jmp Short LoadFile4
LoadFile3: Dec BX
Mov AX,BX
Mov CX,16
Push DX
Mul CX
Div CS:FixPlus2
Mul CS:FixedLen
Pop DX
Mov CX,AX ;CX = avail bytes in seg.
Cmp CX,CS:FixedLen
Jae LoadFile5
JmpMemIsFull: Jmp MemIsFull
LoadFile4: Sub CX,DX ;CX = avail bytes in seg.
LoadFile5: Sub DI,CX
Sbb BP,0
Jnc BiggerThanSeg ;Jmp if rest of file bigger then seg.
Add CX,DI ;else use len of rest of file.
Xor DI,DI
Mov BP,DI ;Remain len of file is 0.
Mov CS:MustSetPtrs,0
Jmp Short DoRead
BiggerThanSeg: Mov CS:MustSetPtrs,0FFH
DoRead: Mov BX,CS:Handle
Mov AX,Read ;Read up to avail bytes in seg.
Int DOS
Jc JmpReadErr ;Jmp if read no good.
Cmp AX,CX ;Do bytes read = bytes req.
Jnz JmpReadErr ;Jmp if they don't.
Mov BX,AX ;Hold # of bytes read.
Cmp CS:FixedLen,0
Jnz AdjustOfs
;
Push DS
Pop ES
Cld
ScanCtrlZ: Push DI
Mov DI,DX
Add DI,BX
Sub DI,CX ;Start ofs for Ctrl-Z scan.
Mov AL,CtrlZ
Repne Scasb
Mov SI,DI
Pop DI
Jnz AdjustOfs
Dec BX
Mov CS:GotCtrlZ,0FFH
Cmp CS:IgnoreCtrlZ,0
Jz AdjustBytes
Jcxz AdjustOfs
Call DeleteCtrlZ
Jmp ScanCtrlZ
AdjustBytes: Sub BX,CX ;Number bytes of data.
;
Jnz AdjustBytes2
Jmp LoadRet
AdjustBytes2: Add CS:NextOfs,BX
Mov CS:EndData,0
Mov AX,BX
Shr AX,1
Shr AX,1
Shr AX,1
Shr AX,1
Add CS:ReservedForPtrs,AX
Jmp Short LoadFin
JmpReadErr: Jmp ReadError
AdjustOfs: Add CS:NextOfs,BX
Mov CS:EndData,0
Cmp CS:FixedLen,0
Jnz FixReserved
Mov AX,BX
Shr AX,1
Shr AX,1
Shr AX,1
Shr AX,1
Add CS:ReservedForPtrs,AX
Jmp Short AdjustOfs2
FixReserved: Push DX
Mov AX,BX
Xor DX,DX
Div CS:FixedLen
Shr AX,1
Shr AX,1
Shr AX,1
Add CS:ReservedForPtrs,AX
Pop DX
AdjustOfs2: Mov AX,BP
Or AX,DI
Jz LoadFin
Push BP
Push DI
Mov CS:FromMain,0
Call SetupPointers
Pop DI
Pop BP
Jmp LoadFile2
LoadFin: Mov CS:GotData,1
Cmp CS:Fixedlen,0
Jnz LoadRet
Add BX,DX ;Pt after last byte.
Mov AX,Word Ptr[BX-2]
Cmp AX,CS:LineEnd
Jz AdjNextOfs
Xchg AH,AL
Cmp AX,CS:LineEnd
Jz AdjNextOfs
Inc BX
Cmp AL,CS:Byte Ptr LineEnd + 1
Jz LoadFin3
LoadFin2: Cmp AL,CS:Byte Ptr LineEnd
Jz LoadFin3
Inc BX
LoadFin3: Mov AX,CS:LineEnd
Mov Word Ptr[BX-2],AX
Push BX
Push DS
Push CS
Pop DS
Mov DX,Offset MissCRLFMsg
Mov CX,Offset MissCRLFEnd - Offset MissCRLFMsg
Call WriteStdError2
Pop DS
Pop BX
AdjNextOfs: Mov CS:NextOfs,BX
LoadRet: Call SetupPointers
Push CS
Push CS
Pop DS
Pop ES
Clc
Ret
ReadError: Mov DX,Offset ReadErrorMsg
Jmp DisplayExit
LoadFile Endp
;
DeleteCtrlZ Proc Near
Push DI
Push CX
Lea DI,[SI-1]
Shr CX,1
Jnc DeleteCtrlZ2
Movsb
DeleteCtrlZ2: Rep Movsw
Pop CX
Pop DI
Ret
DeleteCtrlZ Endp
;
SetupPointers Proc Near
;
Cld
Mov SI,CS:SegCount
Shl SI,1
Mov AX,CS:NextOfs
Mov DX,AX
And AL,0F0H
Sub DX,AX ;Ofs for load.
Mov CS:NextOfs,DX
Mov BP,DX ;Hold NextOfs
Mov CL,4
Shr AX,CL
Add AX,CS:NextSeg
Mov CS:NextSeg,AX
Cmp CS:PtrsAgain,0
Jz SetupPtrs1
Mov CS:PtrsAgain,0
Mov CS:EndData,0
Jmp Short SetupPtrs2
SetupPtrs1: Cmp CS:EndData,0
Jz SetupPtrs2
Mov CS:EndData,0
Ret
SetupPtrs2: Mov DI,AX ;Hold NextSeg
Sub AX,CS:Data.Segm[SI]
Mov CX,16
Mul CX ;DX:AX = ofs of NextSeg from DataSeg[SI].
Add AX,BP
Adc DX,0 ;Ofs of Next loc from DataSeg[SI].
Sub AX,CS:LenBuckSize ;If lines, pt to 1st len buck.
Sbb DX,0
Jz SetupPtrs3
Cmp CS:FromMain,0
Jnz SetPtrsAgain
Cmp DX,1
Jbe UseDataMax
SetPtrsAgain: Mov CS:PtrsAgain,0FFH
Jmp Short UseDataMax ;Jmp if more than 65535.
SetupPtrs3: Cmp AX,CS:Data.Beg[SI]
Ja ChkDataMax
Ret ;Return if no data.
ChkDataMax: Cmp AX,CS:DataMax
Jae UseDataMax
Cmp CS:FromMain,0
Jnz SaveDataEnd
Cmp CS:MustSetPtrs,0
Jnz SaveDataEnd
Ret ;Return if LT DataMax and not final time.
UseDataMax: Mov AX,CS:DataMax
SaveDataEnd: Push AX ;Save end of data ptr in seg.
Mov BX,CS:LastSeg
Inc DI ;NextSeg plus 1.
Mov CX,BX
Sub BX,DI ;Avail para.
Cmp BX,0FFFH
Jbe GetPtrSegBeg
Mov BX,0FFFH
GetPtrSegBeg: Sub CX,BX
Mov DS,CX
Mov CS:Pointer.Segm[SI],CX
Mov CL,3
Shl BX,CL
Mov DX,BX ;Max ptr ct.
Shl BX,1
Dec BX
Dec BX
Mov CS:Pointer.Beg[SI],BX
Les DI,CS:Data[SI]
Pop CX
Add CX,CS:LenBuckSize
Sub CX,DI ;Number of data bytes.
Mov SI,BX ;ES:DI=Data,DS:SI=Ptr,DX=PtrCt,CX=DataBytes.
Cmp CS:FixedLen,0
Jz LinePtrs
Jmp NextFix
;
LinePtrs: Mov BX,CX
Shr BX,1
Shr BX,1
Shr BX,1
Shr BX,1
Sub CS:ReservedForPtrs,BX
Jnc NextLine
Mov CS:ReservedForPtrs,0
NextLine: Mov BX,DI ;Pt to len field.
Dec CX
Inc DI
Dec CX
Inc DI ;Pt to line.
Mov BP,CX ;Hold remain len of data.
Jcxz FinishSegLine ;Jmp if no more data.
Mov AX,CS:LineEnd
ScanForCR: Dec CX
Scasb
Jcxz EndOfData2
Jnz ScanForCR2
Cmp ES:Byte Ptr[DI],AH ;If next char is not LF
Jz PointToCr
ScanForCR2: Repne Scasb ;Find CR.
Jcxz EndOfData ;Jmp if no CR or CR in last byte.
Cmp ES:Byte Ptr[DI-2],AH
Jnz ScanForCR3
Dec DI
Inc CX
Jmp Short PointToCR
ScanForCR3: Cmp ES:Byte Ptr[DI],AH ;If next char is not LF then
Jnz ScanForCR2 ;cont the search.
PointToCR: Inc CX
Dec DI ;Pt back to CR.
SaveLineLen: Sub BP,CX ;BP = len of line
Jnz SaveLineLen2
Cmp CS:ElimNull,0
Jnz NextLine
SaveLineLen2: Mov ES:[BX],BP ;Store line len in prev CRLF buck.
Add BP,2
Cmp BP,CS:LongestLen
Jbe IncLineCt
Cmp BP,CS:MaxAllowLen
Ja LineLongJmp
Mov CS:LongestLen,BP
IncLineCt: Sub BP,2
Dec DX
Mov [SI],BX ;Store addr of line in ptr buck.
Dec SI
Dec SI
Jmp NextLine
EndOfData: Jnz EndOfData2
Cmp ES:Byte Ptr[DI-2],AH
Jnz EndOfData2
Dec DI
Inc CX
Jmp PointToCR
LineLongJmp: Jmp CantHoldTwo
EndOfData2: Sub DI,BP ;Ptr to 1st byte in line.
Add BP,2
Cmp BP,CS:MaxAllowLen
Ja LineLongJmp
Mov CS:EndData,0FFH
Sub BP,2
FinishSegLine: Dec DI
Dec DI
Mov AX,SI
FinishPtrs: Mov BX,CS
Mov DS,BX
Mov ES,BX
Mov SI,SegCount
Mov BX,SI
Cmp AX,Pointer.Beg[BX+SI]
Jz FinPtrsRet
Mov DataEnd[SI],DI
Inc AX
Inc AX
Mov PointerEnd[SI],AX
And AL,0F0H
Sub PointerEnd[SI],AX
Sub Pointer.Beg[SI+BX],AX
Mov CL,4
Shr AX,CL
Add AX,Pointer.Segm[SI+BX]
Mov Pointer.Segm[SI+BX],AX
Mov LastSeg,AX
Inc SI
Inc SI
Mov SegCount,SI
Mov BX,SI
Mov AX,DI
And AL,0F0H
Sub DI,AX
Mov Data.Beg[SI+BX],DI
Mov CL,4
Shr AX,CL
Add AX,Data.Segm[SI+BX-4]
Mov Data.Segm[SI+BX],AX
Jmp SetupPointers
FinPtrsRet: Ret
;
NextFix: Mov AX,CX ;AX = Size of data seg.
Xor DX,DX
Div CS:FixedLen ;AX = # of Rcds
Mov CX,AX
Shr AX,1
Shr AX,1
Shr AX,1
Sub CS:ReservedForPtrs,AX
Jnc NextFix2
Mov CS:ReservedForPtrs,0
NextFix2: Mov AX,DI
Mov BX,DS
Mov ES,BX
Mov DI,SI
Mov BP,CS:FixedLen
Std
StoreFixedPtr: Stosw
Add AX,BP
Loop StoreFixedPtr
Cld
Xchg AX,DI
Jmp FinishPtrs
;
SetupPointers Endp
;
FourDigits Proc Near
Mov BP,10
Inc AH
Inc AL
Mul AH
Mov CX,4
NextDig: Xor DX,DX
Div BP
Or DL,30H
Mov DS:Byte Ptr[SI],DL
Inc SI
Loop NextDig
Ret
FourDigits Endp
;
SetupTempFiles Proc Near
Cmp CS:TempDisk,0
Jnz SetTempFiles2
Mov AL,CS:DefaultDisk
Mov CS:TempDisk,AL
SetTempFiles2: Mov DL,CS:TempDisk
Mov DH,':'
Mov Word Ptr TempName1,DX
Mov Word Ptr TempName2,DX
Mov Word Ptr TempName3,DX
Mov SI,Offset TempName1+2
Mov DI,0
Call CreateTempFile
Mov WriteHandle,AX
Mov TempHandle1,AX
Mov SI,Offset TempName2+2
Mov DI,1
Call CreateTempFile
Mov ReadHandle,AX
Mov TempHandle2,AX
Mov SI,Offset TempName3+2
Mov DI,2
Call CreateTempFile
Mov TempHandle3,AX
Mov ExtraHandle,AX
Ret
SetupTempFiles Endp
;
CreateTempFile Proc Near
Push SI
Mov AX,GetTime
Int DOS
Mov AX,DX
Add DI,CX
Call FourDigits
Mov AX,DI
Call FourDigits
Mov DI,SI
Mov AX,422EH
Stosw
Mov AX,4250H
Stosw
Xor AL,AL
Stosb
Pop DX
Dec DX
Dec DX
Xor CX,CX
Mov AX,CreateFile
Int DOS
Jc FullTempDir
Ret
FullTempDir: Mov DX,Offset NoTempDirMsg
Jmp DisplayExit
CreateTempFile Endp
;
OpenOutput Proc Near
Mov DI,CS:OutputEnd
Mov CS:Byte Ptr[DI],0
Mov DX,CS:OutputAddr
Push CS
Pop DS
Xor CX,CX
Mov AX,CreateFile
Int DOS
Jc FullOpDir
Mov CS:OpenedOutput,0FFH
Mov CS:WriteHandle,AX
Mov CS:OutputHandle,AX
Ret
FullOpDir: Mov DX,Offset NoOpDirMsg
Jmp DisplayExit
OpenOutput Endp
;
WriteSetup Proc Near
Cld
Mov CX,CS:SegCount
Mov SI,CX
Dec SI
Dec SI
Mov CS:SegNumb,SI
Cmp CS:SkipSetupTop,0
Jz DoSetup
Jmp WriteSetupRet
DoSetUp: Mov CS:WriteBuffEnd,65535
Shr CX,1
Xor AX,AX
Mov DI,Offset TopIndex
SetupTop: Stosw
Inc AX
Inc AX
Loop SetupTop
Mov AX,CS:NextSeg
Inc AX
Mov CS:WriteBuff.Segm,AX
Mov CS:WriteBuff.Beg,0
Mov DX,CS:LastSeg
Sub DX,AX
Cmp DX,1000H
Jae SortTopRcds
Mov CL,4
Shl DX,CL
SaveLength: Mov CS:WriteBuffEnd,DX
SortTopRcds: Xor SI,SI ;Init J.
Push SI
TopNextJ: Pop SI ;Get prev J.
Cmp SI,CS:SegNumb
Je WriteSetupRet
Inc SI
Inc SI ;Next J.
Push SI
Mov BP,SI ;Init prev I.
Cmp CS:UseRcdLen,0
Jz UsePointerJ
Mov SI,CS:TopIndex[SI] ;Contents of Jth TopIndex buck.
Push SI ;Will insert this in proper buck.
Shl SI,1
Lds SI,CS:Data[SI] ;DS:SI pts low rcd in data seg.
Jmp Short TopNextI
UsePointerJ: Mov BX,CS:TopIndex[SI] ;Contents of Jth TopIndex buck.
Push BX ;Will insert this in proper buck.
Shl BX,1
Lds SI,CS:Pointer[BX]
Mov SI,Word Ptr[SI] ;Ofs of low rcd in data seg.
Mov DS,CS:Data.Segm[BX] ;DS:SI pts low rcd in data seg.
TopNextI: Dec BP
Dec BP ;Next I.
Js TopInsert
Mov DI,BP
Cmp CS:UseRcdLen,0
Jz UsePointerI
Mov DI,CS:TopIndex[DI] ;Contents of Jth TopIndex buck.
Push DI ;Will insert this in proper buck.
Shl DI,1
Les DI,CS:Data[DI] ;ES:DI pts low rcd in data seg.
Jmp Short TopCompare
UsePointerI: Mov BX,CS:TopIndex[DI] ;Contents of Jth TopIndex buck.
Push BX ;Will insert this in proper buck.
Shl BX,1
Les DI,CS:Pointer[BX]
Mov DI,ES:Word Ptr[DI] ;Ofs of low rcd in data seg.
Mov ES,CS:Data.Segm[BX] ;ES:DI pts low rcd in data seg.
TopCompare: Push SI
Call CompRoutine
Jnc TopAddFour
TopNotInsert: Pop SI ;Restore ofs of Jth line.
Pop DI ;Get contents of Ith buck.
Mov CS:TopIndex[BP+2],DI ;Store in I+1th buck.
Jmp TopNextI ;Recompute I.
TopAddFour: Add SP,4 ;Discard Jth rcd ofs and Ith index.
TopInsert: Pop SI ;Get contents of Jth buck.
Mov CS:TopIndex[BP+2],SI ;Store in I+1th buck.
Jmp TopNextJ
WriteSetupRet: Ret
;
WriteSetup Endp
;
WriteData Proc Near
Mov SI,CS:OrigStart
Mov CS:Word Ptr[SI+4],0DB8CH
Mov CS:Byte Ptr[SI+6],08CH
Call WriteSetup
Mov CS:PrevOfs,0FFFFH
Jmp Short WriteLowRcd
NextLowJ: Inc CX
Inc CX ;CH = 0, CL SegNumb + 2.
Mov BX,CX
Shr BX,1
And BL,0FEH ;First trial TopIndex.
Mov BP,CS:TopIndex ;Contents of Jth TopIndex buck.
Push BP ;Will insert this in proper buck.
Shl BP,1
Lds SI,CS:Pointer[BP]
Mov SI,Word Ptr[SI] ;Ofs of low rcd in data seg.
Mov DS,CS:Data.Segm[BP] ;DS:SI pts low rcd in data seg.
NextLowI: Mov BP,CS:TopIndex[BX] ;Contents of Jth TopIndex buck.
Shl BP,1
Les DI,CS:Pointer[BP]
Mov DI,ES:Word Ptr[DI] ;Ofs of low rcd in data seg.
Mov ES,CS:Data.Segm[BP] ;ES:DI pts low rcd in data seg.
Push CX
Mov BP,BX
Mov DX,SI
Call CompRoutine
Mov SI,DX
Mov BX,BP
Pop CX
Jnc GoUp
GoDown: Mov CL,BL
Add BL,CH
Shr BL,1
And BL,0FEH
Cmp BL,CH
Ja NextLowI
Jmp Short FoundPos
GoUp: Mov CH,BL
Add BL,CL
Shr BL,1
And BL,0FEH
Cmp BL,CH
Ja NextLowI
FoundPos: Mov CX,BX
Shr CX,1
Mov DI,Offset TopIndex
Lea SI,[DI+2]
Mov AX,CS
Mov ES,AX
Mov DS,AX
Rep Movsw
Pop BP
Mov [DI],BP
WriteLowRcd: Mov BX,CS:TopIndex ;Index in 0th buck.
Shl BX,1
Lds SI,CS:Pointer[BX]
Mov SI,Word Ptr[SI] ;Ofs of low rcd in data seg.
Mov DS,CS:Data.Segm[BX] ;Data seg for low rcd.
Call DoWriteLow
Jc WriteLowRcd
SetNextSearch: Mov AX,CS
Mov DS,AX
Mov ES,AX
Mov BX,TopIndex ;Contents of 1st top index buck.
Mov DI,BX
Mov CX,Pointer.Beg[BX+DI]
Jcxz SetNext3
Dec CX
Dec CX
Cmp CX,PointerEnd[BX]
Jb SetNext3
Mov Pointer.Beg[BX+DI],CX
Jmp Short SetJEqSegNumb
SetNext3: Sub SegNumb,2
Js WriteFin
Mov CX,SegNumb
Shr CX,1 ;Ct of TopIndex bucks.
Inc CX
Mov DI,Offset TopIndex ;Pt to 1st TopIndex buck.
Lea SI,[DI+2] ;Pt to 2nd TopIndex buck.
Rep Movsw
Jmp WriteLowRcd
SetJEqSegNumb: Mov CX,SegNumb ;Pt to last TopIndex buck.
Jcxz WriteLowRcd
Jmp NextLowJ
WriteFin: Call WriteBuffer
Mov BX,CS:WriteHandle
Cmp CS:FinalOutput,0
Jz NotFinalOp
Cmp CS:GotCtrlZ,0
Jz CloseOutput
Mov AX,CS
Mov DS,AX
Mov DX,Offset PrtCtrlZ
Mov CX,1
Mov AH,Write
Int DOS
CloseOutput: Mov BX,WriteHandle
Cmp BX,StdOutput
Jz WriteRet
Mov AX,Close
Int DOS
Jmp Short WriteRet
NotFinalOp: Mov AX,GetFileLoc
Xor CX,CX
Mov DX,CX
Int DOS
Jc DiskError61
Mov SI,CS:BlockEnd
Mov DS,CS:BlockSeg
Mov Word Ptr[SI],AX
Mov Word Ptr[SI+2],DX
Inc CS:BlockCt
Sub SI,4
Jnc StoreBlockEnd
Dec CS:BlockSeg
Add CS:BlockBeg,10H
Add SI,10H
StoreBlockEnd: Mov CS:BlockEnd,SI
Mov AX,CS:BlockSeg
Mov CS:LastSeg,AX
WriteRet: Mov AX,CS
Mov DS,AX
Mov ES,AX
Mov SI,OrigStart
Mov CS:Word Ptr[SI+4],0FE39H
Mov CS:Byte Ptr[SI+6],0C3H
Ret
;
WriteBuffer: Mov DS,CS:WriteBuff.Segm
Mov CX,CS:WriteBuff.Beg ;Len to write.
Jcxz WriteBufferRet
Xor DX,DX
WriteBuffer2: Mov CS:PrevBuffOfs,0FFFFH
Mov BX,CS:WriteHandle ;Write to std op.
Mov AH,Write
Int DOS
Jc DiskError62 ;Err msg if write NG.
Cmp AX,CX
Jnz FullDisk ;Err if not write req bytes.
Mov CS:WriteBuff.Beg,0
WriteBufferRet: Ret
;
DiskError61: Mov AX,3136H
Jmp Short DiskError
DiskError62: Mov AX,3236H
DiskError: Mov DX,Offset DiskErrorMsg
Mov CS:Word Ptr DiskErrorMsg+1,AX
Jmp DisplayExit
;
FullDisk: Cmp BX,StdOutput
Jz FullOut
Cmp CS:FinalOutput,0
Jnz FullOut
FullTemp: Mov DX,Offset FullTempMsg
Jmp DisplayExit
FullOut: Mov DX,Offset FullOutMsg
Jmp DisplayExit
;
WriteData Endp
;
DoWriteLow Proc Near
Cmp CS:ElimDup,0
Jz MoveLine2
Les DI,CS:PrevAddr
Mov CS:PrevOfs,SI
Mov CS:PrevSeg,DS
Cmp DI,0FFFFH
Jnz DoCheckDup
Mov DI,CS:PrevBuffOfs
Cmp DI,0FFFFH
Jz MoveLine2
Mov ES,CS:WriteBuff.Segm
Cmp CS:FinalOutput,0
Jz DoCheckDup
Cmp CS:FixedLen,0
Jnz DoCheckDup
Mov CX,CS:WriteBuff.Beg
Sub CX,DI ;Length of last line in write buffer.
Dec CX
Dec CX ;Length excluding CRLF.
Dec DI
Dec DI ;Point to where length field should be.
Xchg CX,ES:[DI] ;Xchg length for current contents.
Push CX
Push DI
Mov DX,SI
Call CompRoutine
Sahf
Mov SI,DX
Pop DI
Pop CX
Mov ES:[DI],CX ;Restore contents of bucket.
Jnz MoveLine2
Clc
Ret
DoCheckDup: Mov DX,SI
Call CompRoutine
Sahf
Mov SI,DX
Jnz MoveLine2
Clc
Ret
MoveLine2: Mov AX,CS:FixedLen
Or AX,AX
Jnz MoveLine4
MoveLine3: Lodsw ;AX = line len.
Inc AX
Inc AX ;Len of line + CRLF.
MoveLine4: Mov CX,CS:WriteBuffEnd
Les DI,CS:WriteBuff
Sub CX,DI ;Remain space in buffer.
Sub CX,AX
Xchg CX,AX ;CX = Line len.
Jae RoomForLine ;Jmp if enough space in buff.
Or DI,DI ;Chk if data in buff.
Jz WriteInPlace ;Jmp if nothing in buff.
Call WriteBuffer ;OK if something in buff.
Mov CS:PrevOfs,0FFFFH ;Don't compare line to itself.
Stc
Ret
RoomForLine: Mov CS:PrevBuffOfs,DI
Add CS:WriteBuff.Beg,CX
Cmp CS:FinalOutput,0
Jnz RoomForLine1
Sub SI,CS:LenBuckSize
Jmp Short RoomForLine1B
RoomForLine1: Cmp CS:FixedLen,0
Jz RoomForLine2
RoomForLine1B: Shr CX,1
Jnc MoveWords1
Movsb
MoveWords1: Rep Movsw
Clc
Ret
RoomForLine2: Shr CX,1
Dec CX
Jnc MoveWords2
Movsb
MoveWords2: Rep Movsw
Mov AX,CS:LineEnd
Stosw ;Move CRLF to buff.
Clc
Ret
WriteInPlace: Cmp CS:FinalOutput,0
Jnz DoWrtInPlace1
Sub SI,CS:LenBuckSize
Mov DX,SI
Call WriteBuffer2
Clc
Ret
DoWrtInPlace1: Mov DX,SI
Cmp CS:FixedLen,0
Jz DoWrtInPlace2
Call WriteBuffer2
Clc
Ret
DoWrtInPlace2: Add SI,CX
Mov AX,CS:LineEnd
Xchg Word Ptr[SI-2],AX
Push AX
Call WriteBuffer2
Pop AX
Mov Word Ptr[SI-2],AX
Clc
Ret
DoWriteLow Endp
;
WriteDataM Proc Near
Call WriteSetup
Cmp CS:SkipSetupTop,0
Jz WriteLowRcdM
Jmp SetJEqSegNumbM
NextLowJM: Inc CX
Inc CX ;CH = 0, CL SegNumb + 2.
Mov BX,CX
Shr BX,1
And BL,0FEH ;First trial TopIndex.
Mov SI,CS:TopIndex ;Contents of Jth TopIndex buck.
Push SI ;Will insert this in proper buck.
Shl SI,1
Lds SI,CS:Data[SI] ;DS:SI pts low rcd in data seg.
NextLowIM: Mov DI,CS:TopIndex[BX] ;Contents of Jth TopIndex buck.
Shl DI,1
Les DI,CS:Data[DI] ;ES:DI pts low rcd in data seg.
Push CX
Mov BP,BX
Mov DX,SI
Call CompRoutine
Mov SI,DX
Mov BX,BP
Pop CX
Jnc GoUpM
GoDownM: Mov CL,BL
Add BL,CH
Shr BL,1
And BL,0FEH
Cmp BL,CH
Ja NextLowIM
Jmp Short FoundPosM
GoUpM: Mov CH,BL
Add BL,CL
Shr BL,1
And BL,0FEH
Cmp BL,CH
Ja NextLowIM
FoundPosM: Mov CX,BX
Shr CX,1
Mov DI,Offset TopIndex
Lea SI,[DI+2]
Mov AX,CS
Mov ES,AX
Mov DS,AX
Rep Movsw
Pop BP
Mov [DI],BP
WriteLowRcdM: Mov SI,CS:TopIndex ;Index in 0th buck.
Shl SI,1
Lds SI,CS:Data[SI] ;DS:SI pts low rcd in data seg.
Call DoWriteLow
Jc WriteLowRcdM
SetNextSearchM: Mov AX,CS
Mov DS,AX
Mov ES,AX
Mov BX,TopIndex ;Contents of 1st top index buck.
Mov DI,BX
Mov SI,Data.Beg[BX+DI]
Mov CX,FixedLen
Jcxz SetNext2BM
Add SI,CX ;Offset of next line in segment.
Mov Data.Beg[BX+DI],SI
Cmp SI,DataEnd[BX]
Jae WriteFinM
Jmp Short SetJEqSegNumbM
SetNext2BM: Mov DS,Data.Segm[BX+DI]
Lodsw
Add SI,AX ;Offset of next line in segment.
Mov CS:Data.Beg[BX+DI],SI
Cmp SI,CS:DataEnd[BX]
Jae WriteFinM
Lodsw
Add SI,AX
Jc WriteFinM
Cmp SI,CS:DataEnd[BX]
Ja WriteFinM
Mov CX,CS
Mov DS,CX
SetJEqSegNumbM: Mov CX,CS:SegNumb ;Pt to last TopIndex buck.
Jcxz WriteLowRcdM
Jmp NextLowJM
WriteFinM: Ret
;
WriteDataM Endp
;
MergeData Proc Near
;
Mov SI,CS:OrigStart
Mov CS:Word Ptr[SI+4],0DB8CH
Mov CS:Byte Ptr[SI+6],08CH
Mov CS:UseRcdLen,0FFH
;
;Repeat {Until BlockCt = 1}
;
; Initialize NewBlockBeg, NewBlockEnd and NewBlockSeg
MergeData1: Mov AX,CS:BlockSeg
Mov CS:LastSeg,AX
Mov CS:NewBlockBeg,0008H
Mov CS:NewBlockEnd,0008H
Mov AX,CS:MemoryEndSeg
Dec AX
Mov CS:NewBlockSeg,AX
Mov AX,CS:LastSeg
Sub AX,CS:MemoryBegSeg
Sub AX,CS:MergeBuff
Mov BX,CS:LongestLen
Add BX,15
Mov CL,4
Shr BX,CL
Mov CX,CS:MergeSeg ;Minimum for segment.
Cmp CX,BX
Jae CompMaxSegCt
Mov CX,BX
CompMaxSegCt: Xor DX,DX
Div CX
Cmp AX,2
Jae StoreMaxSegCt
Or AX,AX
Jz CompMaxSegCt2
Mov AX,CX
CompMaxSegCt2: Add AX,DX ;Recover avail mem paragraphs.
Shr AX,1 ;Half of avail mem paragraphs.
Cmp AX,BX
Jbe TwoRcdNG ;Jmp if not room for two records.
Mov AX,2 ;Else set two segments.
Jmp Short StoreMaxSegCt
TwoRcdNG: Jmp DoTwoRcdMsg ;Error if not room for two data seg.
StoreMaxSegCt: Mov CS:MaxSegCount,AX
;
; HowManySegs = the minimum of:
; a. 64
; b. BlockCt
; c. MaxSegCount
;
Mov BP,CS:BlockCT
Cmp BP,AX
Jbe MergeData2
Xchg BP,AX
MergeData2: Cmp BP,64
Jbe MergeData3
Mov BP,64
MergeData3: Mov CS:HowManySegs,BP
;
; Swap WriteHandle with ReadHandle.
Mov BX,CS:WriteHandle
Xchg BX,CS:ReadHandle
Mov CS:WriteHandle,BX
;
; Truncate WriteHandle file.
Cmp CS:FirstMerge,0
Jnz MergeData3B
Call TruncFile
;
; NewBlockCt = (BlockCt) / HowManySegs.
; Since HowManySegs LE BlockCt, NewBlockCt GE 1.
MergeData3B: Mov CS:FirstMerge,0
Mov CS:UseExtra,0
Mov CS:LastIsExtra,0
Mov AX,CS:BlockCt
Xor DX,DX
Div CS:HowManySegs
Mov CS:NewBlockCt,AX
Mov CS:RemainderSegs,DX
;
; If RemainderSegs <> 0 and NewBlockCT = 1 then:
; a. ThisTimeSegs = RemainderSegs + 1.
; b. BegBlock = BlockCt - RemainderSegs - 1.
; c. Swap WriteHandle with ExtraHandle.
; d. Truncate ExtraHandle file.
; e. Call CalcMaxSegSize.
; f. Call MergeOneBlock.
; g. Call WriteBuffer.
; h. Set UseExtra = 0FFH.
; i. Swap WriteHandle with ExtraHandle.
; j. Store length of extra file in ExtraEnd.
; k. Reduce length of write file by ExtraEnd.
; l. RemainderSegs = 0.
Or DX,DX
Jnz MergeData5H1
JmpMergeData5I: Jmp MergeData5I ;Jump if RemainderSegs = 0.
MergeData5H1: Cmp AX,1
Jnz JmpMergeData5I ;Jump if NewBlockCt <> 1.
Inc DX
Mov CS:ThisTimeSegs,DX ;Will merge RemainderSegs + 1.
Mov AX,CS:BlockCT
Sub AX,DX
Mov CS:BegBlock,AX
Mov BX,CS:WriteHandle
Xchg BX,CS:ExtraHandle
Mov CS:WriteHandle,BX
Cmp CS:FirstExtra,0
Jnz MergeData5H
Call TruncFile
MergeData5H: Mov CS:FirstExtra,0
Call CalcMaxSegSize
Call MergeOneBlock
Call WriteBuffer
Mov CS:UseExtra,0FFH
;
Mov AX,GetFileLen
Mov BX,CS:WriteHandle
Xor CX,CX
Mov DX,CX
Int DOS
Jnc SaveExtraEnd
DoError73: Mov AX,3337H
Jmp DiskError
SaveExtraEnd: Mov CS:Word Ptr ExtraEnd,AX
Mov CS:Word Ptr ExtraEnd+2,DX
;
Mov BX,CS:WriteHandle
Xchg BX,CS:ExtraHandle
Mov CS:WriteHandle,BX
;
Mov SI,CS:BegBlock
Dec SI
Call GetFileLocn
Mov BX,CS:ReadHandle ;CX:DX = New read file size.
Call TruncFile2
Mov CS:RemainderSegs,0
;
; Get MaxSegSize for the merge down to NewBlockCt.
MergeData5I: Mov AX,CS:HowManySegs
Mov CS:ThisTimeSegs,AX
Call CalcMaxSegSize
;
; If NewBlockCt <> 1 go and merge the blocks
; else close and delete WriteHandle
; set WriteHandle = output file.
Cmp CS:NewBlockCt,1
Jnz MergeData5L
Mov CS:FinalOutput,0FFH
; Close and delete the WriteHandle file.
Mov BX,CS:WriteHandle
Mov DX,Offset TempName1
Cmp BX,CS:TempHandle1
Jz MergeData5C2
Mov DX,Offset TempName2
Mov CS:TempHandle2,0
Jmp Short MergeData5D
MergeData5C2: Mov CS:TempHandle1,0
MergeData5D: Mov AX,CS
Mov DS,AX
Call CloseDelete
; WriteHandle = output file handle.
Cmp CS:GotOutput,0
Jz UseStdOp
Call OpenOutput
Jmp Short MergeData5L
UseStdOp: Mov CS:WriteHandle,StdOutput
;
; If RemainderSegs <> 0 then NewBlockCt = NewBlockCt + 1
; else RemainderSegs = HowManySegs.
MergeData5L: Cmp CS:RemainderSegs,0
Jz MergeData5J
Inc CS:NewBlockCt
Jmp Short MergeData6
MergeData5J: Mov CX,CS:HowManySegs
Mov CS:RemainderSegs,CX
;
; For N = NewBlockCt - 1 To 0 Step -1
MergeData6: Mov CX,CS:NewBlockCT
Dec CX
MergeData7: Push CX
;
; If N = 0 and UseExtra = 0FFH then LastIsExtra = 0FFH.
; If N = 0 ThisTimeSegs = RemainderSegs
Or CX,CX
Jnz MergeData8
Mov AX,CS:RemainderSegs
Cmp AX,CS:ThisTimeSegs
Jz MergeData7B
Mov CS:ThisTimeSegs,AX
Push CX
Call CalcMaxSegSize
Pop CX
MergeData7B: Cmp CS:UseExtra,0
Jz MergeData8
Mov CS:LastIsExtra,0FFH
;
; BegBlock = (NewBlockCt - N - 1) * HowManySegs
MergeData8: Mov AX,CS:NewBlockCt
Dec AX
Sub AX,CX
Mul CS:HowManySegs
Mov CS:BegBlock,AX
Add AX,CS:ThisTimeSegs
Dec AX
Mov CS:EndBlock,AX
;
Call MergeOneBlock
;
; We come here when we when have finished one of the new blocks. Just as was
; done by WriteData we must save the ending position of the new block in the
; block table (reusing one of the buckets used for one of the old blocks)
; and must store the new blockend blockbeg and blockseg values. Since the
; old values are still needed, we store them in NewBlockEnd, NewBlockBeg and
; NewBlockSeg.
MergeData17: Call WriteBuffer
Cmp CS:FinalOutput,0
Jnz MergeData19
;
Mov AX,GetFileLen
Mov BX,CS:WriteHandle
Xor CX,CX
Mov DX,CX
Int DOS
Jnc SaveWriteEnd
DoError74: Mov AX,3437H
Jmp DiskError
SaveWriteEnd: Mov SI,CS:NewBlockEnd
Mov DS,CS:NewBlockSeg
Mov Word Ptr[SI],AX
Mov Word Ptr[SI+2],DX
Sub SI,4
Jnc MergeData18
Dec CS:NewBlockSeg
Add CS:NewBlockBeg,10H
Add SI,10H
MergeData18: Mov CS:NewBlockEnd,SI
;
; Next N
MergeData19: Pop CX
Dec CX
Js MergeData19B
Jmp MergeData7
;
; BlockCt = NewBlockCt: BlockEnd = NewBlockEnd
; BlockBeg = NewBlockBeg: BlockSeg = NewBlockSeg
MergeData19B: Mov AX,CS:NewBlockEnd
Mov CS:BlockEnd,AX
Mov AX,CS:NewBlockBeg
Mov CS:BlockBeg,AX
Mov AX,CS:NewBlockSeg
Mov CS:BlockSeg,AX
Mov AX,CS:NewBlockCt
Mov CS:BlockCt,AX
;
;Until BlockCt = 1
Cmp AX,1
Jz MergeData19C
Jmp MergeData1
;
;Write CtrlZ if input file had one.
MergeData19C: Mov AX,CS
Mov DS,AX
Cmp GotCtrlZ,0
Jz MergeData19C2
Mov DX,Offset PrtCtrlZ
Mov CX,1
Mov BX,WriteHandle
Mov AH,Write
Int DOS
;Close the output file if it is not the standard output.
MergeData19C2: Mov BX,WriteHandle
Cmp BX,StdOutput
Jz MergeData19D
Mov AX,Close
Int DOS
;Close and delete the ReadHandle and ExtraHandle files.
MergeData19D: Cmp NeedMerge,0
Jz MergeDataRet
Mov BX,ReadHandle
Mov DX,Offset TempName1
Cmp BX,TempHandle1
Jz MergeData19E
Mov DX,Offset TempName2
Mov TempHandle2,0
Jmp Short MergeData20
MergeData19E: Mov TempHandle1,0
MergeData20: Call CloseDelete
Mov BX,ExtraHandle
Mov ExtraHandle,0
Mov DX,Offset TempName3
Call CloseDelete
MergeDataRet: Ret
;
MergeData Endp
;
TruncFile Proc Near
Xor CX,CX
Mov DX,CX
TruncFile2: Mov AX,SetFileAtBeg
Int DOS
Jc TruncNg63
Mov AH,Write
Xor CX,CX
Int DOS
Jc TruncNG64
Or AX,AX
Jnz TruncNg65
Ret
TruncNg63: Mov AX,3336H
Jmp DiskError
TruncNg64: Mov AX,3436H
Jmp DiskError
TruncNg65: Mov AX,3536H
Jmp DiskError
TruncFile Endp
;
GetFileLocn Proc Near
Mov DS,CS:BlockSeg
Mov BX,CS:BlockBeg
Shl SI,1
Shl SI,1
Sub BX,SI
Mov DX,[BX]
Mov CX,[BX+2] ;CX:DX = Loc in file.
Ret
GetFileLocn Endp
;
CalcMaxSegSize Proc Near
;
; MaxSegSize = Minimum of:
; a. (Avail Mem - MinBuff) / ThisTimeSegs
; b. 64K (1000H paragraphs).
;
Mov AX,CS:LastSeg
Sub AX,CS:MemoryBegSeg
Sub AX,CS:MergeBuff
Xor DX,DX
Div CS:ThisTimeSegs
Mov BX,CS:DataPara
Cmp AX,BX
Jb MergeData4
Mov AX,CS:DataMax
Jmp Short MergeData5
MergeData4: Mov CL,4
Shl AX,CL
Mov CX,CS:FixedLen
Jcxz MergeData5
Xor DX,DX
Div CX
Mul CX
MergeData5: Mov CS:MaxSegSize,AX
Ret
CalcMaxSegSize Endp
;
MergeOneBlock Proc Near
; SegCount = HowManySegs
Mov AX,CS:ThisTimeSegs
Shl AX,1
Mov CS:SegCount,AX
;
; NextSeg = MemoryBegSeg
Mov AX,CS:MemoryBegSeg
Mov CS:NextSeg,AX
;
; If LastIsExtra = 0FFH
; then MaxSegs = ThisTimeSegs - 2
; else MaxSegs = ThisTimeSegs - 1.
Mov AX,CS:ThisTimeSegs
Dec AX
Cmp CS:LastIsExtra,0
Jz StoreMaxSegs
Dec AX
StoreMaxSegs: Mov CS:MaxSegs,AX
;
; For M = 0 To MaxSegs
Xor CX,CX
Mov CS:SkipSetupTop,0
;
; If BlockLen(BegBlock + M) >= MaxSegSize Then
; SegLen(M) = MaxSegSize
; Else
; SegLen(M) = BlockLen(BegBlock + M)
; EndIf
MergeData9: Push CX
Mov DS,CS:BlockSeg
Mov BX,CS:BlockBeg
Mov DI,CX
Shl DI,1
Shl DI,1 ;4 * M
Mov AX,CS:BegBlock
Shl AX,1
Shl AX,1 ;4 * BegBlock
Sub BX,AX
Sub BX,DI ;Point to table entry for BegBlock + M.
Mov AX,[BX]
Mov DX,[BX+2] ;Location of end of block.
Mov SI,[BX+4]
Mov BP,[BX+6] ;Location of beg of block.
Call ReadOneBlock
;
; BlockOfs(M) = SegLen(M)
MergeData11B: Pop DI ;Recover M.
Mov AX,DI ;Hold M.
Shl DI,1
Shl DI,1 ;Point to BlockOfs bucket.
Mov CS:Word Ptr BlockOfs[DI],CX
Mov CS:Word Ptr BlockOfs[DI+2],0
;
; Next M
Mov CX,AX
Inc CX
Cmp CX,CS:MaxSegs
Jbe MergeData9
;
MergeData11C: Cmp CS:LastIsExtra,0
Jz DoMergeWrite1
Mov DI,CX
Push DI
Shl DI,1
Mov CS:ExtraNumb,DI
Shl DI,1 ;4 * M
Mov AX,CS:Word Ptr ExtraEnd
Mov DX,CS:Word Ptr ExtraEnd+2 ;Location of end of block.
Xor SI,SI
Mov BP,SI ;Location of beg of block.
Mov BX,CS:ReadHandle
Xchg BX,CS:ExtraHandle
Mov CS:ReadHandle,BX
Call ReadOneBlock
Mov BX,CS:ReadHandle
Xchg BX,CS:ExtraHandle
Mov CS:ReadHandle,BX
;
; BlockOfs(M) = SegLen(M)
Pop DI ;Recover M.
Shl DI,1
Shl DI,1 ;Point to BlockOfs bucket.
Mov CS:Word Ptr BlockOfs[DI],CX
Mov CS:Word Ptr BlockOfs[DI+2],0
;
DoMergeWrite1: Mov CS:PrevOfs,0FFFFH
DoMergeWrite: Call WriteDataM
Mov CS:SkipSetupTop,0FFH
;
; Empty = TopIndex(1)
Mov BX,CS:TopIndex
;
; Check for partial line, if any, and move to beginning of segment.
Mov CX,CS:DataEnd[BX]
Shl BX,1
Mov SI,CS:Data.Beg[BX]
Sub CX,SI
Je MergeData12 ;Jump if no partial line.
Xor DI,DI
Mov AX,CS:Data.Segm[BX]
Mov DS,AX
Mov ES,AX
Shr CX,1
Jnc PartWords
Movsb
PartWords: Rep Movsw
Mov CS:Data.Beg[BX],DI
Jmp Short MergeData12B
;
; If BlockLen(Empty) <= BlockOfs(Empty) Then
; SegCount = SegCount - 1
; If SegCount > 0 Then
; Goto DoMergeWrite
; Else
; Goto FinishNewBlock
; EndIf
; EndIf
MergeData12: Mov CS:Data.Beg[BX],0
MergeData12B: Mov AX,CS:Word Ptr BlockLen[BX]
Mov DX,CS:Word Ptr BlockLen[BX+2]
Sub AX,CS:Word Ptr BlockOfs[BX]
Sbb DX,CS:Word Ptr BlockOfs[BX+2]
Jb MergeData13
Mov CX,DX
Or CX,AX
Jnz MergeData14
MergeData13: Cmp CS:Data.Beg[BX],0
Jnz MergeData14
Cmp CS:LastIsExtra,0
Jz MergeData13B
Shr BX,1
Cmp BX,CS:ExtraNumb
Jnz MergeData13B
Mov CS:LastIsExtra,0
MergeData13B: Sub CS:SegCount,2
Jz JmpMergeOneRet
Mov AX,CS
Mov DS,AX
Mov ES,AX
Mov BX,TopIndex
Mov CX,SegCount
Shr CX,1
Mov DI,Offset TopIndex
Lea SI,[DI+2]
Rep Movsw
Mov [DI],BX
Jmp DoMergeWrite
JmpMergeOneRet: Jmp MergeOneRet
;
; If BlockLen(Empty) - BlockOfs(Empty) >= MaxSegSize Then
; SegLen(Empty) = SegMax
; Else
; SegLen(Empty) = BlockLen(BegBlock + Empty) - BlockOfs(BegBlock + Empty);
; EndIf
MergeData14: Add AX,CS:Data.Beg[BX]
Adc DX,0
Or DX,DX
Jnz MergeData15
Cmp AX,CS:MaxSegSize
Jbe MergeData16
MergeData15: Mov AX,CS:MaxSegSize
;
; Read SegLen(Empty) bytes from Block(BegBlock + Empty) into Seg(Empty)
; BlockOfs(Empty) = BlockOfs(Empty) + SegLen(Empty)
; Goto DoMergeWrite
MergeData16: Shr BX,1
Mov CS:DataEnd[BX],AX
Push AX
Mov AX,CS:ReadHandle
Mov CS:UseHandle,AX
Cmp CS:LastIsExtra,0
Jz MergeData16B
Cmp BX,CS:ExtraNumb
Jnz MergeData16B
Mov AX,CS:ExtraHandle
Mov CS:UseHandle,AX
MergeData16B: Mov AX,SetFileAtBeg
Shl BX,1
Mov DX,CS:Word Ptr BlockPos[BX]
Mov CX,CS:Word Ptr BlockPos[BX+2]
Add DX,CS:Word Ptr BlockOfs[BX]
Adc CX,CS:Word Ptr BlockOfs[BX+2]
Push BX
Mov BX,CS:UseHandle
Int DOS
Jc GoNgWrite66
Pop BX
Pop CX
Mov DX,CS:Data.Beg[BX]
Mov CS:Data.Beg[BX],0
Sub CX,DX
Add CS:Word Ptr BlockOfs[BX],CX
Adc CS:Word Ptr BlockOfs[BX+2],0
Mov DS,CS:Data.Segm[BX]
Mov BX,CS:UseHandle
Mov AX,Read
Int DOS
Jc GoNGWrite67
Cmp AX,CX
Jne GoNGWrite68
Jmp DoMergeWrite1
MergeOneRet: Ret
GoNGWrite66: Mov AX,3636H
Jmp DiskError
GoNGWrite67: Mov AX,3736H
Jmp DiskError
GoNGWrite68: Mov AX,3836H
Jmp DiskError
MergeOneBlock Endp
;
ReadOneBlock Proc Near
Sub AX,SI
Sbb DX,BP ;Length of block.
Mov CS:Word Ptr BlockLen[DI],AX
Mov CS:Word Ptr BlockLen[DI+2],DX
Mov CS:Word Ptr BlockPos[DI],SI
Mov CS:Word Ptr BlockPos[DI+2],BP
Jnz MergeData10
Cmp AX,CS:MaxSegSize
Jb MergeData11
MergeData10: Mov AX,CS:MaxSegSize
MergeData11: Shr DI,1
Mov CS:DataEnd[DI],AX
Mov DX,CS:NextSeg
Shl DI,1
Mov CS:Data.Segm[DI],DX
Mov CS:Data.Beg[DI],0
Mov DI,AX
Add DI,15
Mov CL,4
Shr DI,CL
Add CS:NextSeg,DI
;
; Read SegLen(M) bytes from loc zero in Block(BegBlock + M) into Seg(M)
Push DX
Push AX
Mov AX,SetFileAtBeg
Mov DX,SI
Mov CX,BP
Mov BX,CS:ReadHandle
Int DOS
Jc JmpNGWrite69
Pop CX
Pop DS
Mov BX,CS:ReadHandle
Mov AX,Read
Xor DX,DX
Int DOS
Jc JmpNGWrite70
Cmp AX,CX
Je ReadOneBlkRet
JmpNGWrite69: Mov AX,3936H
Jmp DiskError
JmpNGWrite70: Mov AX,3037H
Jmp DiskError
ReadOneBlkRet: Ret
ReadOneBlock Endp
;
FindMsgEnd Proc Near
Push CS
Push CS
Pop DS
Pop ES
Cld
Push DX
Cmp GotError,0
Jnz DoWriteERROR
Mov SI,DX
Inc SI
Lodsw
And AX,0F0FH
Xchg AH,AL ;AH = hi digit, AL = lo digit of code.
Aad
Mov ErrorCode,AL
Call WriteNewLine
DoWriteERROR: Call WriteERROR
Pop DX
Or GotKeyErr,GotOtherErr
Mov GotError,0FFH
Mov DI,DX ;Address of message
Mov CX,256
Mov AL,'$'
Repne Scasb
Dec DI ;Point back to '$'.
Mov CX,DI
Sub CX,DX
Call WriteStdError
Ret
FindMsgEnd Endp
;
DispErrorParm Proc Near
Push DS
Push ES
Push CX
Push SI
Push BX
Push AX
Call FindMsgEnd
Push CX ;Save length of message.
Mov DX,ParmBeg
Mov SI,DX
Mov CX,ParmChars ;Remaining parm characters.
Lodsb
Dec CX
Jcxz EndOfParm
NextErrorChar: Lodsb
Cmp AL,Slash
Jz EndOfParm
Cmp AL,Space
Jz EndOfParm
Loop NextErrorChar
Jmp Short EndOfParm2
EndOfParm: Dec SI
EndOfParm2: Mov CX,SI
Sub CX,DX
Pop AX ;Retreive length of message.
Add AX,8 ;Length of " ERROR " plus quote.
Cmp AX,80
Jbe EndOfParm3
Sub AX,80
EndOfParm3: Add AX,CX ;Add length of parm.
Cmp AX,79
Jb EndOfParm4
Push CX
Push DX
Mov DX,Offset TwelveSpaces
Mov CX,14
Call WriteStdError
Pop DX
Pop CX
EndOfParm4: Push CX
Push DX
Mov DX,Offset Quote
Mov CX,1
Call WriteStdError
Pop DX
Pop CX
Call WriteStdError
Mov DX,Offset Quote
Mov CX,1
Call WriteStdError
Jmp Short DispError2
DispErrorParm Endp
;
DisplayError Proc Near
Push DS
Push ES
Push CX
Push SI
Push BX
Push AX
Call FindMsgEnd
DispError2: Call WriteNewLine
Mov CS:DidErrorWord,0
Pop AX
Pop BX
Pop SI
Pop CX
Pop ES
Pop DS
Ret
DisplayError Endp
;
DisplayExit Proc Near
Call DisplayError
ErrorExit: Call FinalDeletes
Mov AL,CS:ErrorCode
Jmp GoBack
DisplayExit Endp
;
FinalDeletes Proc Near
Push CS
Pop DS
Mov BX,TempHandle1
Mov TempHandle1,0
Mov DX,Offset TempName1
Call CloseDelete
Mov BX,TempHandle2
Mov TempHandle2,0
Mov DX,Offset TempName2
Call CloseDelete
Mov BX,TempHandle3
Mov TempHandle3,0
Mov DX,Offset TempName3
Call CloseDelete
Cmp OpenedOutput,0
Jz FinalDeleteRet
Mov BX,OutputHandle
Cmp BX,StdOutput
Jbe FinalDeleteRet
Mov DX,OutputAddr
Call CloseDelete
FinalDeleteRet: Ret
FinalDeletes Endp
;
CloseDelete Proc Near
Or BX,BX
Jz CloseDeleteRet
Mov AX,Close
Int DOS
Jc DoError71
Mov AX,Delete
Int DOS
Jc DoError72
CloseDeleteRet: Ret
DoError71: Mov AX,3137H
Jmp DiskError
DoError72: Mov AX,3237H
Jmp DiskError
CloseDelete Endp
;
WriteERROR: Mov CS:DidErrorWord,0FFH
Mov DX,Offset ERRORWord
Mov CX,7
Jmp Short WriteStdError2
;
WriteNewLine: Mov DX,Offset NewLine
Mov CX,2
;
WriteStdError Proc Near
Mov CH,0
WriteStdError2: Mov BX,ErrorHandle ;Write to StdError or error file.
Mov AH,Write
Int DOS
Jc WrtStdNG
Cmp AX,CX
Jz WrtStdErrRet
WrtStdNG: Cmp ErrorHandle,StdError
Jz WrtStdErrRet
Mov AX,Close
Int DOS
Mov ErrorHandle,StdError
Mov BX,StdError
Push DX
Push CX
Mov DX,Offset FullErrMsg
Mov CX,Offset FullErrEnd - Offset FullErrMsg
Mov AH,Write
Int DOS
Cmp CS:DidErrorWord,0
Jz WrtStdNG2
Call WriteERROR
Mov CS:DidErrorWord,0
WrtStdNG2: Pop CX
Pop DX
Jmp WriteStdError2
WrtStdErrRet: Ret
WriteStdError Endp
;
GetNumb Proc Near
Cld
Xor DX,DX ;Start with result = 0.
Mov DI,10
NextDigit: Cmp AL,30H ;Digit must
Jb FinNumb1 ;be between
Cmp AL,39H ;0 and 9.
Ja FinNumb1
And AX,0FH ;Strip high nibl.
Push AX
Xchg AX,DX ;AX now = prev result.
Mul DI ;Mult by 10.
Pop DX ;Recover new digit.
Jo Make65535 ;NG if GT 65535.
Add DX,AX ;DX = result so far.
Jc Make65535 ;NG if GT 65535.
Jcxz FinNumbRet
Dec CX
Lodsb
Jmp NextDigit
FinNumb1: Dec SI
Inc CX
FinNumbRet: Ret
Make65535: Mov DX,65535
AnyMoreNumb: Jcxz FinNumbRet
Dec CX
Lodsb
Cmp AL,30H
Jb FinNumb1
Cmp AL,39H
Ja FinNumb1
Jmp AnyMoreNumb
GetNumb Endp
PascTooLong: Mov DX,Offset PascTooLongMsg
Jmp DisplayExit
;
AtHighEnd: Xchg BP,SI
Xchg DX,BX
Mov CX,BP
Sub CX,DX
Jmp Short CheckPartSize
;
SortEnd Proc Near
Mov AX,CS
Mov DS,AX
Mov ES,AX
Ret
SortEnd Endp
;
SortData Proc Near
Cld
Mov StackHigh,SP
Mov AX,SegCount
Mov SegNumb,AX
SortNextSeg: Sub CS:SegNumb,2
Js SortEnd
Mov AH,30H
Int DOS
Mov SI,CS:SegNumb
Mov BX,SI
Mov DS,CS:Data.Segm[SI+BX]
Mov CS:BegSeg,DS
Mov ES,CS:Pointer.Segm[SI+BX]
Mov CS:PtrSeg,ES
Mov DX,CS:PointerEnd[SI] ;Ofs of last (Jth) ptr buck.
Mov BP,CS:Pointer.Beg[SI+BX] ;Ofs of first (Ith) ptr buck.
Mov CX,BP
Sub CX,DX
Jmp Short CheckPartSize
NewPartition: Pop SI ;Lo end of curr part.
Pop BX ;Hi end of curr part.
Xchg BX,DX
Dec BP ;BP is lo for upper part.
Dec BP ;DX is hi for upper part.
Inc BX ;BX is hi for low part.
Inc BX ;SI is lo for low part.
Mov CX,BP
Sub CX,DX ;Size of upper part.
Cmp CX,-2
Jz AtHighEnd
Mov AX,SI
Sub AX,BX ;Size of low part.
Jc CheckPartSize
Cmp AX,CX
Jae Save1Part ;Jmp if low part GE upper.
Xchg BX,DX
Xchg SI,BP
Xchg AX,CX
Save1Part: Push BX
Push SI
CheckPartSize: Shr CX,1
Jnz GetIOffset
FinishPart: Cmp SP,CS:StackHigh
Jb FinishPart2
Jmp SortNextSeg ;If no more parts we are done.
FinishPart2: Pop BP ;Lo ofs in part.
Pop DX ;Hi ofs in part.
Mov CX,BP
Sub CX,DX
Jmp CheckPartSize
GetIOffset: Push DX ;Hi ofs for new part.
Push BP ;Lo ofs for new part.
Mov DI,BP
Add DI,DX ;(Hi ofs + Lo ofs).
Rcr DI,1 ;(Hi ofs + Lo ofs) / 2.
Jpe ClearBit0
Mov SI,BP
Sub SI,DX
Shr SI,1
Shr SI,1
Jpe SubDiff
AddDiff: Add DI,SI ;Add (Hi - Lo) / 4.
Jmp Short ClearBit0
SubDiff: Shr SI,1
Sub DI,SI ;Sub (Hi - Lo) / 8.
ClearBit0: And DI,0FFFEH ;Make sure its on a word boundary.
Mov SI,ES:[BP] ;Former first rcd.
Xchg SI,ES:[DI] ;Swap ofs of rcd I
Mov ES:[BP],SI ;with ofs of former first rcd.
;
GetJOfSDown: Mov DI,DX ;Ofs of Jth ptr.
Mov DI,ES:[DI] ;Ofs of Jth rcd.
Push SI
Mov ES,CS:BegSeg
Call CompRoutine
Mov ES,CS:PtrSeg
Pop SI ;Recover ofs of Ith rcd.
Ja ReverseDown ;Jump if Ith rcd goes after Jth.
NextJDown: Inc DX ;Ofs of next Jth ptr buck.
Inc DX
Cmp DX,BP ;If J = I we have found correct
Jnz GetJOfsDown ;pos for the Ith ptr.
SaveIOfsDown: Mov ES:[BP],SI
Jmp NewPartition ;Setup new part.
ReverseDown: Mov DI,DX ;Ofs of Jth ptr.
Mov DI,ES:[DI] ;Ofs of Jth rcd.
Mov ES:[BP],DI ;Store in Ith ptr buck.
Xchg DX,BP ;I and J ptrs are swapped.
Jmp Short NextJUp ;Now must move upwards in search.
;
GetJOfSUp: Mov DI,DX ;Ofs of Jth ptr.
Mov DI,ES:[DI] ;Ofs of Jth rcd.
Push SI
Mov ES,CS:BegSeg
Call CompRoutine
Mov ES,CS:PtrSeg
Pop SI ;Recover ofs of Ith rcd.
Jb ReverseUp ;Jmp if Ith rcd goes before Jth.
NextJUp: Dec DX ;Ofs of next Jth ptr buck.
Dec DX
Cmp DX,BP ;If J = I we have found correct
Jne GetJOfsUp ;pos for the Ith ptr.
SaveIOfsUp: Mov ES:[BP],SI
Jmp NewPartition ;Setup new part.
ReverseUP: Mov DI,DX ;Ofs of Jth ptr.
Mov DI,ES:[DI] ;Ofs of Jth rcd.
Mov ES:[BP],DI ;Store in Ith ptr buck.
Xchg DX,BP ;I and J ptrs are swapped.
Jmp NextJDown ;Now move down in search.
;
SortData Endp
;
TempRealExp DW 0
TempRealShft1 DW 0
TempRealShft2 DW 0
TempReal1 DB 8 Dup(0)
TempReal2 DB 8 Dup(0)
;
TempUnNormal Proc Near
;
Call CalcExponent ;Returns BX=shft ct, AX=new exp.
Mov CS:TempRealExp,AX
Mov CS:TempRealShft1,BX
Push SI
Mov SI,DI
Push DS
Push ES
Pop DS
Call CalcExponent
Pop DS
Pop SI
Mov CS:TempRealShft2,BX
Cmp CS:TempRealExp,AX ;If the two exponents are unequal
Jne TempUnNormal2b ;then return proper carry flag.
Or AX,AX ;If new exps equal and both zero
Jnz TempUnNormal3 ;then return with z flag set.
TempUnNormal2b: Mov CX,10
Ret ;Return if new exponents not equal.
;
TempUnNormal3: Push DS
Push SI
Push ES
Push DI
Mov BX,CS:TempRealShft1
Mov DI,Offset TempReal1+7
Call MoveTempReal
Pop SI
Pop DS
Push DS
Push SI
Mov BX,CS:TempRealShft2
Mov DI,Offset TempReal2+7
Call MoveTempReal
Mov AX,CS
Mov ES,AX
Mov DS,AX
Mov SI,Offset TempReal1+7
Mov DI,Offset TempReal2+7
Mov CX,8
Rep Cmpsb
Pop DI
Pop ES
Pop SI
Pop DS
Mov CX,10
Ret
TempUnNormal Endp
;
CalcExponent Proc Near
Push SI
Sub SI,3 ;Point to high word of mantissa.
Mov CX,4
Xor BX,BX
NextWord: Lodsw
Or AX,AX
Js GotShift
Jnz GetShift2
Add BL,16
Loop NextWord
Jmp Short GotShift
GetShift1: Inc BX
GetShift2: Shl AX,1
Jnc GetShift1
GotShift: Pop SI
Cmp BX,64
Jnz GotShift2
Xor AX,AX ;If pseudo zero make new exp = 0.
Ret
GotShift2: Mov AX,[SI-1]
And AX,07FFFH
Jnz GotShift3 ;If exp is zero this must be a
Inc AX ;denormal so we increment it to one.
GotShift3: Sub AX,BX ;New exp = old exp - shift count.
Add AX,64 ;Make sure new exp is GE 0.
Ret
CalcExponent Endp
;
MoveTempReal Proc Near
Mov AX,CS
Mov ES,AX
Mov AX,BX
Mov CL,3
Shr AX,CL ;Number of leading zero bytes in mantissa.
Mov BH,AL ;Number of trailing zero bytes in new mantissa.
Sub SI,2 ;Skip exponent.
Sub SI,AX ;Points to first non-zero byte.
And BL,07H ;Number of lead zero bits in 1st non-zero byte.
Mov CL,BL
Mov BL,8
Sub BL,BH ;Number of non-zero bytes.
;
Push DX
Jz TrailingZeros
Lodsb
Mov DH,AL
Dec BL
Jz LastTempByte
;
NextTempByte: Lodsb
Mov DL,AL
Shl DX,CL
Mov AL,DH
Stosb
Mov DH,DL
Shr DH,CL
Dec BL
Jnz NextTempByte
;
LastTempByte: Shl DH,CL
Mov AL,DH
Stosb
TrailingZeros: Mov CL,BH
Xor AL,AL
Rep Stosb
Pop DX
Ret
MoveTempReal Endp
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CompRoutine Proc Near
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
CompRtnBeg:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Use for second and later sort keys.
;
SecondBeg: Sub CX,RelColumn
Add SI,CX
Add DI,CX
SecondEnd:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Use in all cases.
;
All1Beg: Mov CX,StartColumn ;Start col of key.
All1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If fixed length add the following code.
;
Fix1Beg: Add SI,CX ;Pt to key in Jth rcd.
Add DI,CX ;Pt to key in Ith rcd.
Mov CX,KeyLength ;Len of key.
Fix1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If Pascal add the following code.
;
Pascal1Beg: Xor AX,AX
Mov BX,AX
Lodsb ;Len of string in Jth line.
Mov BL,ES:[DI] ;Len of string in Ith line.
Inc DI
Dec CX
Xchg BX,CX ;BX = maxstrlen, CX = Ith strlen.
Cmp AX,CX
Jae GotShortLen
Xchg CX,AX ;CX = lesser string length.
GotShortLen: Lahf ;Save flags from compare.
Cmp AL,BL ;Greater str len versus key len.
Jbe GetPascRest
JmpPascTooLong: Mov AX,Offset PascTooLong
Jmp AX
GetPascRest: Sub BX,CX ;Rest of key len.
Sahf ;Set flags based on len compare in case one len
Pascal1End: ;is zero. This prevents spurious flags.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If lines add the following code.
;
Line1Beg: Lodsw
Add SI,CX ;Pt to key in Jth rcd.
Mov BX,ES:[DI] ;Len of Ith line.
Inc DI
Inc DI
Add DI,CX ;Pt to key in Ith rcd.
Xchg CX,AX ;Len of Jth line.
Cmp CX,BX
Jae GotShort
Xchg BX,CX ;BX = lesser length.
GotShort: Lahf
Cmp CX,StartColumn
MovKeyLen: Mov CX,KeyLength ;Len of key.
Ja ShortLen
BothShort: Mov BX,StartColumn
Add CX,BX
Sub SI,BX
Sub DI,BX
;
;As code for each key is created, this target is set to FinishBeg + 2.
;If this is last key then the OrigSeq code will be at this loc.
;If not last key then code for next key will start at this addr.
;
JmpOrigSeq: Jmp Short DoCompare ;If both too short then = compare.
ShortLen: Sub BX,StartColumn ;Remain short line len.
Ja DoCompare
Sahf ;One line too short so get flags based on len.
;
;Change following to Cmc followed by Ret if /R specified.
;
OnlyOneShort: Ret
Nop
;
DoCompare: Cmp BX,CX ;Remain short line len vs. key len.
Jae LineEq
Xchg CX,BX ;Len if only partial key in short line.
Sub BX,CX
Jmp Short Line1End
LineEq: Mov AH,40H ;Neither short so make =.
Xor BX,BX
Line1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If collating and not zero add the following.
;
CollNZ1Beg: Repe Cmpsb ;ASCII collating sort.
CollNZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If collating and zero and lines add the following.
;
LineCollZ1Beg: Push DX
Jmp Short LineCollZ1Mid2
LineCollZ1Mid1: Or AL,DL
Jz LineCollZ1Mid3
LineCollZ1Mid2: Lodsb
Mov DL,ES:[DI]
Inc DI
Cmp AL,DL
Loope LineCollZ1Mid1
Jne LineCollZ1Mid4
Or AL,DL
Jz LineCollZ1Mid3
Xor DX,DX ;Restore zero flag.
Jmp Short LineCollZ1Mid4
LineCollZ1Mid3: Mov AH,40H
LineCollZ1Mid4: Pop DX
LineCollZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If collating and zero and fixed add the following.
;
FixCollZ1Beg: Lodsb
Mov AH,ES:[DI]
Inc DI
Dec CX
Cmp AL,AH
Jnz FixCollZ1End
Jcxz FixCollZ1End
Or AL,AH
Jnz FixCollZ1Beg
FixCollZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If case insensitive and either Pascal or lines but not zero add the following.
;
LinePasNZ1Beg: Push AX
Push BX
LinePasNZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If case insensitive and not zero add the following.
;
CaseNZ1Beg: Jcxz CaseNZ1End ;For Pascal strings, CX could be zero.
Mov BX,Offset XlatTable
CaseNZNextChar: Lodsb ;Next byte of Jth line.
Xlat CS:XlatTable ;Xlat byte from Jth line.
Xchg AH,AL
Mov AL,ES:[DI]
Inc DI
Xlat CS:XlatTable ;Xlat byte from Ith line.
Cmp AH,AL ;J line byte vs. I line byte.
Loope CaseNZNextChar
CaseNZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If case insensitive and either Pascal or lines but not zero add the following.
;
LinePasNZ2Beg: Pop BX
Pop AX
LinePasNZ2End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If case insensitive and zero and lines add the following.
;
LineCaseZ1Beg: Push DX
Push BX
Mov BX,Offset XlatTable
Jmp Short LineCaseZ1Mid2
LineCaseZ1Mid1: Or AL,DL
Jz LineCaseZ1Mid3
LineCaseZ1Mid2: Lodsb
Xlat CS:XlatTable ;Xlat byte from Jth line.
Xchg DL,AL
Mov AL,ES:[DI]
Inc DI
Xlat CS:XlatTable ;Xlat byte from Ith line.
Cmp DL,AL
Loope LineCaseZ1Mid1
Jne LineCaseZ1Mid4
Or AL,DL
Jz LineCaseZ1Mid3
Xor DX,DX ;Restore zero flag.
Jmp Short LineCaseZ1Mid4
LineCaseZ1Mid3: Mov AH,40H
LineCaseZ1Mid4: Pop BX
Pop DX
LineCaseZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If case insensitive and zero and fixed add the following.
;
FixCaseZ1Beg: Push BX
Mov BX,Offset XlatTable
FixCaseZ1Mid1: Lodsb
Xlat CS:XlatTable ;Xlat byte from Jth line.
Xchg AH,AL
Mov AL,ES:[DI]
Inc DI
Dec CX
Xlat CS:XlatTable ;Xlat byte from Ith line.
Cmp AH,AL
Jnz FixCaseZ1Mid2
Jcxz FixCaseZ1Mid2
Or AL,AH
Jnz FixCaseZ1Mid1
FixCaseZ1Mid2: Pop BX
FixCaseZ1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If signed binary integer add the following.
;
Integer1Beg: Std
Lodsb
Mov AH,ES:[DI]
Dec DI
Dec CX
Add AL,80H
Add AH,80H
Cmp AL,AH
Jnz Integer1Mid
Repe Cmpsb
Integer1Mid: Cld
Not CX
Integer1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If unsigned binary integer add the following.
;
Unsigned1Beg: Std
Repe Cmpsb
Cld
Not CX
Unsigned1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If IEEE temp real float add the following.
;
TempReal1Beg: Std
Or CX,CX ;Clear zero and carry flags.
Mov AL,[SI]
Mov AH,ES:[DI]
Rcl AH,1 ;I use Rcl because it will never set
Jc SecondNegE ;the Z flag.
Rcl AL,1 ;I use Rcl because it will never set
Jc TempReal1Mid ;the Z flag.
BothPosE: Test Byte Ptr[SI-2],80H
Jz DoPosUnNormal
Test Byte Ptr ES:[DI-2],80H
Jz DoPosUnNormal
Repe Cmpsb
Jmp Short TempReal1Mid
DoPosUnNormal: Mov AX,Offset TempUnNormal
Call AX
Jmp Short TempReal1Mid
DoNegUnNormal: Mov AX,Offset TempUnNormal
Call AX
Jmp Short TestNegEqual
SecondNegE: Rcl AL,1 ;I use Rcl because it will never set
Jnc TempReal1Mid ;the Z flag.
BothNegE: Test Byte Ptr[SI-2],80H
Jz DoNegUnNormal
Test Byte Ptr ES:[DI-2],80H
Jz DoNegUnNormal
Repe Cmpsb
TestNegEqual: Je TempReal1Mid
Cmc
TempReal1Mid: Cld
Not CX
TempReal1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If IEEE float add the following.
;
;Note that a negative zero will sort low relative to a positive zero. I
;have decided to make this a feature since the code to make negative and
;positive zeros compare equal would be inefficient.
;
Float1Beg: Std
Or CX,CX ;Clear zero and carry flags.
Mov AL,[SI]
Mov AH,ES:[DI]
Rcl AH,1 ;I use Rcl because it will never set
Jc SecondNeg ;the Z flag.
Rcl AL,1 ;I use Rcl because it will never set
Jc Float1Mid ;the Z flag.
BothPos: Repe Cmpsb
Jmp Short Float1Mid
SecondNeg: Rcl AL,1 ;I use Rcl because it will never set
Jnc Float1Mid ;the Z flag.
BothNeg: Repe Cmpsb
Je Float1Mid
Cmc
Float1Mid: Cld
Not CX
Float1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If original Microsoft binary float add the following.
;
;Note that in this case negative and positive zeros will sort equal because.
;I don't check for sign if both exponents are zero because interpreted BASIC
;often leaves garbage in the mantissa in such cases.
;
Micro1Beg: Std
Mov AX,[SI-1] ;AH = exponent, AL contains sign.
Mov BX,ES:[DI-1] ;BH = exponent, BL contains sign.
Or BH,AH
Jz Micro1Mid ;If both exponents are zero don't
;compare the mantissas. Note that because we only continue
;if the Z flag is reset, we don't have to worry that we will
;have a spurious equal condition if signs are different.
Rcl BL,1 ;I use Rcl because it will never set
Jc SecondNegM ;the Z flag.
Rcl AL,1 ;I use Rcl because it will never set
Jc Micro1Mid ;the Z flag.
BothPosM: Repe Cmpsb
Jmp Short Micro1Mid
SecondNegM: Rcl AL,1 ;I use Rcl because it will never set
Jnc Micro1Mid ;the Z flag.
BothNegM: Repe Cmpsb
Je Micro1Mid
Cmc
Micro1Mid: Cld
Not CX
Micro1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If original Turbo Pascal binary float add the following.
;
Turbo1Beg: Std
Mov AL,[SI-5]
Mov AH,ES:[DI-5]
Or AL,AH ;If both exps zero don't compare
Jz Turbo1Mid ;mantissas. Otherwise clear Z flag.
Mov AL,[SI]
Mov AH,ES:[DI]
Rcl AH,1 ;I use Rcl because it will never set
Jc SecondNegT ;set the Z flag.
Rcl AL,1 ;I use Rcl because it will never set
Jc Turbo1Mid ;the Z flag.
BothPosT: Mov AL,[SI-5]
Mov AH,ES:[DI-5]
Cmp AL,AH
Jnz Turbo1Mid
Repe Cmpsb
Jmp Short Turbo1Mid

SecondNegT: Rcl AL,1 ;I use Rcl because it will never set
Jnc Turbo1Mid ;the Z flag.
BothNegT: Mov AL,[SI-5]
Mov AH,ES:[DI-5]
Cmp AL,AH
Jnz ReverseCarry
Repe Cmpsb
Je Turbo1Mid
ReverseCarry: Cmc
Turbo1Mid: Cld
Not CX
Turbo1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;In all cases add the following.
;
;If /R specified then Ret Nop becomes Cmc Ret.
;
All2Beg: Jz All2End
Mov AH,0 ;This is required by the ElimDup routine.
Ret
Nop
All2End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If lines or Pascal add the following.
;
;If /R specified then Ret Nop becomes Cmc Ret.
;
LinePascal3Beg: Sahf
Jz SameLen
Mov AH,0 ;This is required by the ElimDup routine.
Ret
Nop
SameLen: Add CX,BX
;
LinePascal3End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Add the following for all cases.
;
;This code added after each key is processed but is overlain by next key.
;
OrigBeg:
OrigSeq: Mov AH,40H ;This is required by the ElimDup routine.
Inc SI ;These Incs are required because a numeric Cmp
Inc DI ;might reduce to 0FFFFH for 1st item in seg.
Cmp SI,DI ;If keys are EQ, we maintain the
Ret ;orig seq for ident keys.
DB 0C1H
Cmp BX,CX
Ret
OrigEnd:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
CompRtnEnd:
;
CompRoutine Endp
;

ChkKeyInRcd Proc Near
Push CX
Push SI
Cmp FixedLen,0
Jz CompStartCol
Cmp KeyCount,1
Jnz CompStartCol
CmpElimNull: Cmp ElimNull,0
Jz CompStartCol
NullFix: Mov FixNotAllowMsg+2,'4'
Mov FixNotAllowMsg+6,'N'
Mov DX,Offset FixNotAllowMsg
Call DisplayError
CompStartCol: Cmp StartCol,0
Jz ChkKeyInRcd2
Dec StartCol ;Dec StartCol if not 0.
ChkKeyInRcd2: Mov DX,FixedLen
Or DX,DX
Jnz ChkKeyInRcd3 ;Jmp if fixed len.
Mov DX,32750
ChkKeyInRcd3: Sub DX,StartCol ;DX = FixedLen or 32750 less StartCol.
Lahf
Cmp KeyLen,0
Jnz ChkKeyInRcd4
Test KeyTyp,KeyTurbo
Jz ChkKeyInRcd3b
Mov KeyLen,6
Jmp Short ChkKeyInRcd4
ChkKeyInRcd3B: Mov KeyLen,DX
ChkKeyInRcd4: Sahf
Ja SubKeyLen
Mov DX,Offset BigStartMsg
Call DispErrorParm
Jmp Short ChkKeyInRcd5
SubKeyLen: Sub DX,KeyLen
Jae ChkKeyInRcd5 ;Rcd len must be >= KeyLen.
Cmp FixedLen,0
Jnz BigKeyLen
Add KeyLen,DX ;If lines and big key len let keylen equal
;32750 - StartCol.
Jmp Short ChkKeyInRcd5
BigKeyLen: Mov DX,Offset BigKeyLenMsg
Call DispErrorParm
ChkKeyInRcd5: Test KeyTyp,KeyInteger+KeyUnsigned+KeyFloat+KeyMicro+KeyTurbo
Jz CheckPascal
Mov AX,Keylen
Add AX,StartCol
Dec AX
Mov StartCol,AX
And KeyTyp,0FFFFH XOR KeyASCII+KeyZero+KeyPascal
Test KeyTyp,KeyMicro+KeyTurbo+KeyFloat
Jz JmpCalcRelCol
Test KeyTyp,KeyTurbo
Jz Test4Or8
Cmp KeyLen,6
Jz CalcRelCol
Mov DX,Offset NGTurboLenMsg
Call DispErrorParm
JmpCalcRelCol: Jmp Short CalcRelCol
NGFloatLen: Mov DX,Offset NGFloatLenMsg
Call DispErrorParm
Jmp Short CalcRelCol
NGMicroLen: Mov DX,Offset NGMicroLenMsg
Call DispErrorParm
Jmp Short CalcRelCol
;
Test4Or8: Cmp KeyLen,4
Jz CalcRelCol
Cmp KeyLen,8
Jz CalcRelCol
Test KeyTyp,KeyMicro
Jnz NGMicroLen
Cmp KeyLen,10
Jnz NGFloatLen
Jmp Short CalcRelCol
CheckPascal: Test KeyTyp,KeyPascal
Jz CalcRelCol
Cmp DefaultSortKey,0
Jz ChkPascalLen
Cmp FixedLen,0
Jz CalcRelCol
Cmp KeyLen,2
Jb PascalLenNgDef
Cmp KeyLen,256
Jbe CalcRelCol
PascalLenNGDef: Mov DX,Offset PascalDefNGMsg
Call DisplayError
Jmp Short CalcRelCol
ChkPascalLen: Cmp KeyLen,2
Jb PascalLenNG
Cmp KeyLen,256
Jbe CalcRelCol
PascalLenNG: Mov DX,Offset PascalLenNGMsg
Call DispErrorParm
CalcRelCol: Mov DX,PrevEndCol
Cmp FixedLen,0
Jnz StoreRelCol
Inc DX
Inc DX
StoreRelCol: Mov RelCol,DX
Cmp GotError,0
Jz StoreRelCol2
Jmp ChkKeyRet
StoreRelCol2: Mov DI,CodePointer
Mov SI,CompMove
Cmp Fixedlen,0
Jz Line1
Mov Fix1Start,DI
Mov Line1Start,0
Add SI,Offset Fix1Beg

Test KeyTyp,KeyPascal
Jnz DoPascal
Mov CX,Offset Fix1End - Offset Fix1Beg
Jmp Short MoveKeyLen
DoPascal: Mov CX,Offset Pascal1End - Offset Fix1Beg
Jmp Short MoveKeyLen
Line1: Add SI,Offset Line1Beg
Mov CX,Offset Line1End - Offset Line1Beg
Mov Fix1Start,0
Mov Line1Start,DI
MoveKeyLen: Rep Movsb
Test KeyTyp,KeyInteger+KeyUnsigned+KeyFloat+KeyMicro+KeyTurbo
Jnz DoBinaryNumb
Test KeyTyp,KeyASCII
Jz JmpCaseInsen
Test KeyTyp,KeyZero
Jnz ASCIIZero
Mov SI,Offset CollNZ1Beg
Mov CX,Offset CollNZ1End - Offset CollNZ1Beg
Jmp Short MoveASCIICode
JmpCaseInsen: Jmp Short CaseInsen
DoBinaryNumb: Test KeyTyp,KeyInteger
Jz TestUnsigned
Mov SI,Offset Integer1Beg
Mov CX,Offset Integer1End - Offset Integer1Beg
Jmp Short MoveBinNumb
TestUnsigned: Test KeyTyp,KeyUnsigned
Jz TestFloat
Mov SI,Offset Unsigned1Beg
Mov CX,Offset Unsigned1End - Offset Unsigned1Beg
Jmp Short MoveBinNumb
TestFloat: Test KeyTyp,KeyFloat
Jz TestMicro
Cmp KeyLen,10
Jz DoTempReal
Mov SI,Offset Float1Beg
Mov CX,Offset Float1End - Offset Float1Beg
Jmp Short MoveBinNumb
DoTempReal: Mov SI,Offset TempReal1Beg
Mov CX,Offset TempReal1End - Offset TempReal1Beg
Jmp Short MoveBinNumb
TestMicro: Test KeyTyp,KeyMicro
Jz DoTurbo
Mov SI,Offset Micro1Beg
Mov CX,Offset Micro1End - Offset Micro1Beg
Jmp Short MoveBinNumb
DoTurbo: Mov SI,Offset Turbo1Beg
Mov CX,Offset Turbo1End - Offset Turbo1Beg
MoveBinNumb: Add SI,CompMove
Rep Movsb
Jmp Short All2
ASCIIZero: Cmp FixedLen,0
Jz LineASCIIZero
Mov SI,Offset FixCollZ1Beg
Mov CX,Offset FixCollZ1End - Offset FixCollZ1Beg
Jmp Short MoveASCIICode
LineASCIIZero: Mov SI,Offset LineCollZ1Beg
Mov CX,Offset LineCollZ1End - Offset LineCollZ1Beg
MoveASCIICode: Add SI,CompMove
Rep Movsb
Jmp Short All2
CaseInsen: Test KeyTyp,KeyZero
Jnz CaseZero
Cmp FixedLen,0
Jz LinesPascal1
Test KeyTyp,KeyPascal
Jz Case1
LinesPascal1: Mov SI,Offset LinePasNZ1Beg
Mov CX,Offset LinePasNZ2End - Offset LinePasNZ1Beg
Jmp Short MoveCaseCode
Case1: Mov SI,Offset CaseNZ1Beg
Mov CX,Offset CaseNZ1End - Offset CaseNZ1Beg
Jmp Short MoveCaseCode
CaseZero: Cmp FixedLen,0
Jz CaseZeroLines
Mov SI,Offset FixCaseZ1Beg
Mov CX,Offset FixCaseZ1End - Offset FixCaseZ1Beg
Jmp Short MoveCaseCode
CaseZeroLines: Mov SI,Offset LineCaseZ1Beg
Mov CX,Offset LineCaseZ1End - Offset LineCaseZ1beg
MoveCaseCode: Add SI,CompMove
Rep Movsb
All2: Mov SI,CompMove
Add SI,Offset All2Beg
Mov CX,Offset All2End - Offset All2Beg
Rep Movsb
Cmp FixedLen,0
Jz LinesPascal3
Test KeyTyp,KeyPascal
Jz CheckMemory
LinesPascal3: Mov SI,CompMove
Add SI,Offset LinePascal3Beg
Mov CX,Offset LinePascal3End - Offset LinePascal3Beg
Rep Movsb
CheckMemory: Mov CompFinish,DI
Mov CodePointer,DI
Cmp DI,ModelCodeLoc
Jb Chk2nd
Jmp NoMemory
Chk2nd: Cmp SecondStart,0 ;Jump if not SecondStart.
Jz DoAll1
Mov AX,RelCol
Mov DI,SecondStart
Mov [DI+2],AX ;Store imm val for RelColumn.
DoAll1: Mov DI,All1Start
Mov AX,StartCol
Mov [DI+1],AX
Cmp Fix1Start,0
Jz MustBeLines
Mov DI,Fix1Start
Mov AX,KeyLen
Mov [DI+5],AX
Test KeyTyp,KeyReverse
Jz MovOrigCode
Test KeyTyp,KeyPascal
Jnz RevLinesPascal
Mov DI,CompFinish
Mov [DI-2],0C3F5H
Jmp Short MovOrigCode
MustBeLines: Mov DI,Line1Start
Mov AX,StartCol
Mov [DI + Offset GotShort - Offset Line1Beg + 3],AX
Mov [DI + Offset ShortLen - Offset Line1Beg + 2],AX
Mov [DI+Offset BothShort-Offset Line1Beg+1],AX
Mov AX,KeyLen
Mov [DI+Offset MovKeyLen-Offset Line1Beg+1],AX
Mov AX,CompFinish
Sub AX,DI
Sub AX,Offset JmpOrigSeq - Offset Line1Beg + 2
Mov [DI + Offset JmpOrigSeq - Offset Line1Beg + 1],AL
Test KeyTyp,KeyReverse
Jz MovOrigCode
Mov [DI + Offset OnlyOneShort - Offset Line1Beg],0C3F5H
RevLinesPascal: Mov DI,CompFinish
Mov [DI - 4],0C3F5H
Mov [DI - 11],0C3F5H
MovOrigCode: Mov DI,CodePointer
Mov OrigStart,DI
Mov SI,Offset OrigBeg
Mov CX,Offset OrigEnd - Offset OrigBeg
Add SI,CompMove
Rep Movsb
Mov CodePointer,DI
Cmp DI,ModelCodeLoc
Jb ChkKeyRet
Jmp JmpNoMem1
ChkKeyRet: Pop SI
Pop CX
Ret
ChkKeyInRcd Endp

;
CdeSeg Ends
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

End MainStart

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If numeric and fixed add the following code.
;
;NumFix1Beg: Add SI,CX ;Point to Jth key.
; Add DI,CX ;Point to Ith key.
; Mov CX,KeyLength
; Push CX
;NumFix1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If numeric and lines add the following code.
;
;NumLine1Beg: Lodsw ;Length of Jth line.
; Add SI,CX ;Point to Jth key.
; Mov BX,ES:[DI] ;Length of Ith line.
; Inc DI
; Inc DI
; Add DI,CX ;Point to Ith key.
;
; Sub AX,CX ;Remaining len of Jth line.
; Ja NumLine1A
; Xor AX,AX
;NumLine1A: Sub BX,CX ;Remaining len of Ith line.
; Ja NumLine1B
; Xor BX,BX
;NumLine1B: Mov CX,KeyLength
; Cmp AX,CX
; Jbe NumLine1C
; Mov AX,CX ;Lesser of remain Jth len and keylen.
;NumLine1C: Cmp BX,CX
; Jbe NumLine1D
; Mov BX,CX ;Lesser of remain Ith len and keylen.
;NumLine1D: Mov CX,AX
; Push BX
;NumLine1End:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;If numeric add the following. Must preserve SI, DI, DS, ES return CX = 0
;let RelCol be zero.
;
;Numeric1Beg: Push ES
; Push DI
; Mov AX,CS
; Mov ES,AX
; Mov DI,Offset JNumber
; Call ConvertNumb
; Pop SI
; Pop DS
; Pop CX
; Call ConvertNumb
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;



  3 Responses to “Category : Word Processors
Archive   : RPSRT102.ZIP
Filename : RPSRT102.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/