From 2d04cacc5322951f187bb17e017c12920ac8ebe2 Mon Sep 17 00:00:00 2001 From: Mark Zbikowski Date: Thu, 25 Apr 2024 21:24:10 +0100 Subject: MZ is back! --- v4.0/src/CMD/SORT/MAKEFILE | 36 ++ v4.0/src/CMD/SORT/SORT.ASM | 1000 +++++++++++++++++++++++++++++++++++++++++ v4.0/src/CMD/SORT/SORT.LNK | 4 + v4.0/src/CMD/SORT/SORT.SKL | 12 + v4.0/src/CMD/SORT/SORTMES.ASM | 85 ++++ 5 files changed, 1137 insertions(+) create mode 100644 v4.0/src/CMD/SORT/MAKEFILE create mode 100644 v4.0/src/CMD/SORT/SORT.ASM create mode 100644 v4.0/src/CMD/SORT/SORT.LNK create mode 100644 v4.0/src/CMD/SORT/SORT.SKL create mode 100644 v4.0/src/CMD/SORT/SORTMES.ASM (limited to 'v4.0/src/CMD/SORT') diff --git a/v4.0/src/CMD/SORT/MAKEFILE b/v4.0/src/CMD/SORT/MAKEFILE new file mode 100644 index 0000000..d64b66b --- /dev/null +++ b/v4.0/src/CMD/SORT/MAKEFILE @@ -0,0 +1,36 @@ +#************************** makefile for cmd\... *************************** + +msg =..\..\messages +dos =..\..\dos +inc =..\..\inc +hinc =..\..\h + +# +####################### dependencies begin here. ######################### +# + +all: sort.exe + +sort.ctl: sort.skl \ + $(msg)\$(COUNTRY).msg \ + makefile + +sort.obj: sort.asm \ + makefile \ + sort.ctl \ + sort.cla \ + sort.cl1 \ + sort.cl2 \ + $(inc)\parse.asm \ + $(inc)\psdata.inc \ + $(inc)\syscall.inc \ + $(inc)\msgserv.asm \ + $(inc)\sysmsg.inc + +sortmes.obj: sort.asm \ + makefile \ + $(inc)\syscall.inc + +sort.exe: sort.obj sortmes.obj + link sort+sortmes,sort.exe; + exefix sort.exe 1 1 diff --git a/v4.0/src/CMD/SORT/SORT.ASM b/v4.0/src/CMD/SORT/SORT.ASM new file mode 100644 index 0000000..0a60eb8 --- /dev/null +++ b/v4.0/src/CMD/SORT/SORT.ASM @@ -0,0 +1,1000 @@ +TITLE SORT FILTER FOR DOS + PAGE ,132 ; +;********************************************************** +;* +;* UTILITY NAME: sort +;* +;* SOURCE FILE NAME: sort.asm +;* +;* UTILITY FUNCTION: +;* +;* External non-resident utility, written in Assembler. +;* Reads from the standard input device until end-of-file, +;* sorts the data (up to 64k) and writes the results to +;* the standard output device. Input and output can be +;* redirected. +;* +;* INPUT (Command line) +;* +;* SORT [/R] [/+ n] +;* +;* /R - Sort in reverse order +;* /+n - Start sorting in column "n" , default 1 +;* +;* OUTPUT: +;* Sorted data will be written to the standard output device. +;* +;* ERROR CONDITIONS: +;* Incorrect DOS version +;* Insufficient disk space on target +;* Insufficient memory to allocate SORT buffer +;* Invalid parameter +;* +;* INTERNAL REFERENCES: +;* Main +;* +;* SOURCE HISTORY: +;* Modification History: +;* 3-18-83 MZ (Microsoft) +;* Fix CR-LF at end of buffer +;* Fix small file sorting +;* Fix CR-LF line termination bug +;* Comment the Damn source +;* +;* 6-23-86 RW (IBM) +;* Add DOS 3.30 support for multiple languages +;* Inclusion of common DOS VERSION check equate +;* +;* ;AN000; Code added in DOS 4.0 +;* 5-19-87 RW (IBM) (DOS 4.0) +;* Addition of IBM Parser Service Routines +;* Addition of DOS Message Retriever Service Routines +;* Add code page file tag support +;* +;* ;AN001; Code added in DOS 4.0 +;* ;AN002; DCR 191 +;* 9-18-87 BL (IBM) (DOS 4.0) +;* Added Extended Attribute support for code page checking +;* and file type checking. +;* ;AN003; PTM 1805 +;* 10-19-87 BL (IBM) (DOS 4.0) +;* +;* ;AN004; PTM +;* 01-29-87 BL (IBM) (DOS 4.0) +;* Ran tool INSPECT on .lst file for optimizations +;********************************************************** + + PAGE ; +;------------------------- +;--- Macro definitions +;------------------------- +BREAK MACRO subtitle + SUBTTL subtitle + PAGE +ENDM + + + +sys MACRO name ;system call macro + MOV AH,name + INT 21h + ENDM + + + +save MACRO reglist ;push those registers +IRP reg, + PUSH reg +ENDM +ENDM + + + +restore MACRO reglist ;pop those registers +IRP reg, + POP reg +ENDM +ENDM + + + PAGE ; +;------------------------------- +;--- Equates +;------------------------------- +FALSE EQU 0 +TRUE EQU NOT FALSE +MAXREC EQU 256 ;MAXIMUM NUL RECORD SIZE + +SPACE EQU 0 ;Offset zero in the allocated block +BUFFER EQU MAXREC ;Offset MAXREC in the allocated block + +RETCODE_NOERROR equ 0 ;AN000; DOS return code (errorlevel) +RETCODE_ERROR equ 1 ;AN000; DOS return code (errorlevel) + +NO_CODEPAGE equ 0 ;AN000; Tag for files with no codepage + +GetCPSW equ 3303h ;AN000; Int 021h function calls +GetExtAttr equ 5702h ;AN000; +SetExtAttr equ 5704h ;AN000; +;----------------------- +;-- Parser equates +;----------------------- +EOL EQU -1 ;AN000; Indicator for End-Of-Line +NOERROR EQU 0 ;AN000; Return Indicator for No Errors + +FarSW equ 0 ;AN000; +DateSW equ 0 ;AN000; +TimeSW equ 0 ;AN000; +FileSW equ 0 ;AN000; +CAPSW equ 0 ;AN000; +CmpxSW equ 0 ;AN000; +NumSW equ 1 ;AN000; +KeySW equ 0 ;AN000; +SwSW equ 1 ;AN000; +Val1SW equ 1 ;AN000; +Val2SW equ 0 ;AN000; +Val3SW equ 0 ;AN000; +DrvSW equ 0 ;AN000; +QusSW equ 0 ;AN000; + +;----------------------- +;-- Message equates +;----------------------- +STDIN equ 0 +STDOUT equ 1 +STDERR equ 2 + +Msg_NoMem equ 2 ;AC003; +Msg_NoDisk equ 4 ;AC003; +Msg_sort equ 5 ;AN003; +Msg_switch equ 3 ;AN003; + +;------------------------------ +; EXTENDED ATTRIBUTE Equates +;------------------------------ +EAISBINARY equ 02h ;AN001; ea_type +EASYSTEM equ 8000h ;AN001; ea_flags + + PAGE ; +;---------------------; +.xlist ; +.xcref ; +INCLUDE syscall.inc ; +INCLUDE sysmsg.inc ; ;AN000; Include message equates and MACROS +.cref ; +.list ; +;---------------------; + +MSG_UTILNAME ;AN000; + +SUBTTL Segments used in load order + + +CODE SEGMENT +CODE ENDS + +CONST SEGMENT PUBLIC BYTE +CONST ENDS + + +;----------------------- +;--- Stack Segment +;----------------------- +CSTACK SEGMENT STACK + db 128 DUP (0) ;initial stack to be clear + +CSTACK ENDS + + + +;------------------------------- +;--- Group +;------------------------------- +DG GROUP CODE,CONST,CSTACK + + +;------------------------------- +;--- Code Segment +;------------------------------- +CODE SEGMENT +ASSUME CS:DG,DS:DG,ES:NOTHING,SS:CSTACK + +;------------------------------- +;--- Data Definition +;------------------------------- +COLUMN dw 0 ;COLUMN TO USE FOR KEY + 1 +cp_reset db FALSE ;AN000;Flag indicating if Code Page was reset on target file + +;------------------------------------------DOS 3.30 - Russ Whitehead +CTRY_INFO db ? +CTRY_TABLE_OFF dw ? +CTRY_TABLE_SEG dw ? +;------------------------------------------ + +MSG_SERVICES ;AN000; +ASSUME ds:nothing + +;---------------------------------------- +;- STRUCTURE TO QUERY EXTENDED ATTRIBUTES +;---------------------------------------- +querylist struc ;AN001; ;query general list +qea_num dw 1 ;AN001; +qea_type db EAISBINARY ;AN001; +qea_flags dw EASYSTEM ;AN001; +qea_namelen db ? ;AN001; +qea_name db " " ;AN001; +querylist ends ;AN001; + +cp_qlist querylist <1,EAISBINARY,EASYSTEM,2,"CP"> ;AN001; ;query code page attr. + +cp_list label word ;AN001; ;code page attr. get/set list + dw 1 ;AN001; ; # of list entries + db EAISBINARY ;AN001; ; ea type + dw EASYSTEM ;AN001; ; ea flags + db ? ;AN001; ; ea return code + db 2 ;AN001; ; ea name length + dw 2 ;AN001; ; ea value length + db "CP" ;AN001; ; ea name +cp dw ? ;AN001; ; ea value (code page) +cp_len equ ($ - cp_list) ;AN001; + +;-------Save area for Code Pages +src_cp dw ? ;AN000; Save area for current code page +tgt_cp dw ? ;AN000; Save area for current code page +endlist label word ;AN000; + + PAGE ; +;****************************************************************************** +;* PARSER DATA STRUCTURES FOLLOW +;****************************************************************************** + +;------------------------------ +;- STRUCTURE TO DEFINE ADDITIONAL COMMAND LINE DELIMITERS +;------------------------------ +parms label word ;AN000; + dw parmsx ;AN000; POINTER TO PARMS STRUCTURE + db 1 ;AN000; DELIMITER LIST FOLLOWS + db 1 ;AN000; NUMBER OF ADDITIONAL DELIMITERS + db ";" ;AN000; ADDITIONAL DELIMITER + +;------------------------------ +;- STRUCTURE TO DEFINE SORT SYNTAX REQUIREMENTS +;------------------------------ +parmsx label word ;AN000; + db 0,0 ;AN000; THERE ARE NO POSITIONAL PARAMETERS + db 2 ;AN000; THERE ARE 2 SWITCHES (/R AND /+n) + dw sw1 ;AN000; POINTER TO FIRST SWITCH DEFINITION AREA + dw sw2 ;AN000; POINTER TO SECOND SWITCH DEFINITION AREA + dw 0 ;AN000; THERE ARE NO KEYWORDS IN SORT SYNTAX + +;------------------------------ +;- STRUCTURE TO DEFINE THE /R SWITCH +;------------------------------ +sw1 label word ;AN000; + dw 0 ;AN000; NO MATCH FLAGS + dw 0 ;AN000; NO FUNCTION FLAGS + dw switchbuff ;AN000; PLACE RESULT IN switchbufF + dw novals ;AN000; NO VALUE LIST + db 1 ;AN000; ONLY ONE SWITCH IN FOLLOWING LIST +rev_sw db "/R",0 ;AN000; /R INDICATES REVERSE SORT + +;------------------------------ +;- STRUCTURE TO DEFINE THE /+n SWITCH +;------------------------------ +NUMERIC equ 08000h ;AN000; Control flag for numeric value +NO_COLON equ 0020h ;AN000; + +sw2 label word ;AN000; + dw NUMERIC ;AN000; MATCH_FLAGS + dw NO_COLON ;AN000; NO FUNCTION FLAGS + dw switchbuff ;AN000; PLACE RESULT IN switchbufF + dw valuelist ;AN000; NEED VALUE LIST FOR n + db 1 ;AN000; ONLY 1 SWITCH ON FOLLOWING LIST +col_sw db "/+",0 ;AN000; /+n INDICATES BEGIN SORT IN COLUMN n + +;------------------------------ +;- VALUE LIST DEFINITION FOR NO VALUES +;------------------------------ +novals label word ;AN000; + DB 0 ;AN000; VALUE LIST + +;------------------------------ +;- VALUE LIST DEFINITION FOR /+n +;------------------------------ +valuelist label word ;AN000; + db 1 ;AN000; ONE VALUE ALLOWED + db 1 ;AN000; ONLY ONE RANGE + db 1 ;AN000; IDENTIFY THE RANGE + dd 1,65535 ;AN000; USER CAN SPECIFY /+1 THROUGH /+65535 + +;------------------------------ +;- RETURN BUFFER FOR SWITCH INFORMATION +;------------------------------ +switchbuff label word ;AN000; +sb_type db ? ;AN000; TYPE RETURNED +sb_item_tag db ? ;AN000; SPACE FOR ITEM TAG +sb_synonym dw ? ;AN000; ES:sb_synonym points to synonym + +sb_value dw ? ;AN000; SPACE FOR VALUE +sb_value_extra dw ? ;AN000; UNUSED SPACE FOR VALUE + + PAGE ; +;************************************************************** +;* +;* SUBROUTINE NAME: main +;* +;* SUBROUTINE FUNCTION: +;* Mainline routine, performs SYSLODMSG, calls routines to +;* parse command line, performs the SORT and writes the +;* results. +;* +;* INPUT: +;* Command Line. +;* +;* File to be sorted will be read from Standard Input +;* device handle 0. +;* +;* OUTPUT: +;* Sorted data will be written to the Standard Output +;* device handle 1. +;* +;* NORMAL EXIT: +;* SORT will normally exit when data was successfully read +;* in up to 64k or EOF, sorted, and displayed to the +;* standard output device. +;* +;* ERROR EXIT: +;* If any of the following errors, SORT will display the +;* corresponding error message and terminate. +;* +;* Insufficient disk space on target device +;* Incorrect DOS version +;* Insufficient memory to sort +;* +;************************************************************ + +;------------------------- +; Preload messages +;------------------------- + MSG_SERVICES ;AN000; + MSG_SERVICES ;AN002; Make retriever services available + + mov ax,cs ;AN003; ;load ES to the right area, + mov es,ax ;AN003; + mov ds,ax ;AN003; +SORT: + call sysloadmsg ;AN000; Preload messages, Check DOS Version. + ;If Inc DOS Ver or error loading messages, + ;SYSLOADMSG will show msg and terminate for us + jnc parser ;AN000; If no error, parse command line + call sysdispmsg ;AN000; There was error. Let SYSDISPMSG Display + cmp bx,-1 ;AN000; Is this DOS 1.0 or 1.1 ? + je OLD_ABORT ;AN000; Yes, terminate old way + + mov ah,Exit ;AN000; No, terminate new way + mov al,0 ;AN000; Errorlevel 0 (Compatible!) + int 021h ;AN000; Bye bye! + +OLD_ABORT: ;AN000; CS should point to PSP + mov ah,Abort ;AN000; Terminate program (AH=0) + int 021h ;AN000; Bye bye! +;----------------------------------- +;- DOS version is ok. Parse cmd line +;----------------------------------- +PARSER: ;AN000; message and terminate + call parse ;AN000; Parse command line + +;----------------------------------- +; set up column for proper sort offset +;----------------------------------- + + ADD COLUMN,2 + CMP COLUMN,2 + JZ GOT_COL + DEC COLUMN + +;------------------------------------ +; Get sorting area, no more than 64K +;------------------------------------ +GOT_COL: + MOV BX,1000H ;64K worth of paragraphs +GET_MEM: + mov bp,bx ;AN003; save buffer length + sys ALLOC ;allocate them from somewhere + JNC GOT_MEM ;if error, BX has amount free, try to get it + OR BX,BX ;but, is BX = 0? + JNZ GET_MEM ;nope, try to allocate it + JMP short SIZERR ;AN004; ;complain + +GOT_MEM: +;------------------------------------RussW:--Following add in DOS 3.3 for Nat Lang Support + push ax ;Save AX + push ds ;Save DS + push es ;Save ES + mov al,6 ;Function for Get collating sequence + mov bx,-1 ;Get active code page + mov dx,-1 ;Get info from active country + mov cx,5 ;Number of bytes to be returned + push cs ;Place code segment + pop es ;in ES + mov di,offset ctry_info ;Return area for 5 byte requested information + sys GetExtCntry ;Get extended country information + ;Ok, now copy the table in DOS to our segment + lds si,dword ptr cs:ctry_table_off + mov di,seg dg + mov es,di + mov di,offset dg:table + mov cx,word ptr [si] + add si,2 + mov ax,256 + sub ax,cx + add di,ax + cld + rep movsb + ;Done copying, so restore regs and cont + pop es ;Restore ES + pop ds ;Restore DS + pop ax ;Restore AX +;------------------------------------RussW:--End 3.3 addition + MOV DS,AX ;Point DS to buffer + MOV ES,AX ;and point ES to buffer + MOV CL,4 ;2^4 bytes per paragraph + MOV BX,BP ;AN003; restore buffer length + SHL BX,CL ;Find out how many bytes we have + MOV BP,BX ;AN003; save buffer length in bytes + +;--------------------------- +; Clear out temporary record area +;--------------------------- + MOV CX,MAXREC/2 ;Size of temporary buffer (words) + MOV AX,' ' ;Character to fill with + XOR DI,DI ;AN004; ;Beginning of temp buffer + REP STOSW ;Blam. +;----------------------------------- +; Make sure source and target code pages are the same +;----------------------------------- + call match_codepages ;AN000; Make sure codepages are the same +;--------------------------- +; read in file from standard input +;--------------------------- + MOV DX,BUFFER + 2 ;DX = place to begin reading + MOV CX,BP ;AN003; ;CX is the max number to read + SUB CX,MAXREC + 2 ;remember offset of temp buffer +SORTL: + XOR BX,BX ;Standard input + sys READ ;Read it in + ADD DX,AX ;Bump pointer by count read + SUB CX,AX ;subtract from remaining the count read + JZ SIZERR ;if buffer is full then error + OR AX,AX ;no chars read -> end of file + JNZ SORTL ;there were chars read. go read again + JMP SHORT SIZOK ;trim last ^Z terminated record +SIZERR: + mov ax,msg_NoMem ;AN000; not enough memory error + mov dh,-1 ;AN003; class: utility error + call error_exit ;AN000; and write it out + +;--------------------------- +; Look for a ^Z. Terminate buffer at 1st ^Z. +;--------------------------- +SIZOK: + MOV BX,DX ;save end pointer + MOV CX,DX ;get pointer to end of text + SUB CX,BUFFER+2 ;dif in pointers is count + MOV AL,1AH ;char is ^Z + MOV DI,BUFFER+2 ;point to beginning of text + REPNZ SCASB ;find one + JNZ NoBack ;nope, try to find CRLF + DEC BX ;pretend that we didn't see ^Z +NoBack: + SUB BX,CX ;sub from endpointer the number left + SUB BX,2 ;Hope for a CR LF at end + CMP WORD PTR [BX],0A0Dh ;Was there one there? + JZ GOTEND ;yep, here is the end + ADD BX,2 ;nope, bump back to SCASB spot + CMP BYTE PTR [BX],AL ;Was there ^Z there? + JZ GOTEND ;yep, chop it + INC BX ;Nope, skip last char +GOTEND: + MOV BP,BX ;BP = filesize-2(CRLF)+temp buffer+2 + MOV WORD PTR DS:[BP],0 ;0 at end of the file + +;--------------------------- +; We now turn the entire buffer into a linked list of chains by +; replacing CRLFs with the length of the following line (with 2 for CRLF) +;--------------------------- + MOV BX,BUFFER ;pointer to line head (length) + MOV DI,BUFFER+2 ;pointer to line text +REPLACE_LOOP: + MOV AL,13 ;char to look for is CR + MOV CX,BP ;count = end pointer + SUB CX,DI ;chop off start point to get length + INC CX ;add 1??? +REPLACE_SCAN: + REPNZ SCASB ;look for CR + JNZ REPLACE_SKIP ;count exhausted + CMP BYTE PTR [DI],10 ;LF there? + JNZ REPLACE_SCAN ;nope, continue scanning +REPLACE_SKIP: + MOV AX,DI ;AX to point after CR + DEC AX ;AX to point to CR + save ;save pointer + SUB AX,BX ;AX is length of line found + MOV [BX],AX ;stuff it in previous link + restore ;get pointer to next + INC DI ;skip LF??? + JCXZ END_REPLACE_LOOP ;no more to scan -> go sort + JMP REPLACE_LOOP ;look for next + +END_REPLACE_LOOP: + MOV WORD PTR [BX],0 ;terminate file with nul + LEA BP,[BX+2] ;remember the null line at end + MOV DI,BUFFER ;DI is start of unsorted section + +;--------------------------- +; begin sort. Outer loop steps over all unsorted lines +;--------------------------- +OUTER_SORT_LOOP: + MOV BX,DI ;BX is start of unsorted section + MOV SI,BX ;SI is scanning place link + CMP WORD PTR [BX],0 ;are we at the end of the buffer? + JNZ INNER_SORT_LOOP ;No, do inner process + JMP END_OUTER_SORT_LOOP ;yes, go dump out + +;--------------------------- +; BX points to best guy found so far. We scan through the sorted section +; to find an appropriate insertion point +;--------------------------- +INNER_SORT_LOOP: + ADD SI,[SI] ;link to next fellow + MOV AX,[SI] ;get length of comparison guy + OR AX,AX ;test for end of buffer + JZ END_INNER_SORT_LOOP ;if zero then figure out insertion + save ;save SI,DI + MOV DI,BX ;DI = pointer to tester link + SUB AX,COLUMN ;adjust length for column + JA AXOK ;more chars in tester than column? + XOR SI,SI ;AN004; ;point SI to blank area + MOV AX,MAXREC ;make AX be max length +AXOK: + MOV DX,[DI] ;get length of best guy + SUB DX,COLUMN ;adjust length for column + JA DXOK ;there are more chars after column + XOR DI,DI ;AN004; ;point air to a space + MOV DX,MAXREC ;really big record +DXOK: + MOV CX,AX ;AX is shortest record + CMP AX,DX ;perhaps DX is shorter + JB SMALL ;nope, leace CX alone + MOV CX,DX ;DX is shorter, put length in CX +SMALL: + ADD DI,COLUMN ;offset into record + ADD SI,COLUMN ;offset into other record + push bx + push ax + mov bx,offset dg:table +tloop: lodsb + xlat byte ptr cs:[bx] + mov ah,al + mov al,es:[di] + inc di + xlat byte ptr cs:[bx] + cmp ah,al + loopz tloop + pop ax + pop bx + restore ;get head pointers back + JNZ TESTED_NOT_EQUAL ;didn't exhaust counter, conditions set + CMP AX,DX ;check string lengths +TESTED_NOT_EQUAL: + +;--------------------------- +; NOTE! jae is patched to a jbe if file is to be sorted in reverse! +;--------------------------- +CODE_PATCH label byte + JAE INNER_SORT_LOOP ;if this one wasn't better then go again + MOV BX,SI ;it was better, save header + JMP INNER_SORT_LOOP ;and scan again + +END_INNER_SORT_LOOP: + MOV SI,BX ;SI is now the best person + CMP SI,DI ;check best for current + JZ END_INSERT ;best equals current, all done + +;--------------------------- +; SI points to best line found so far +; DI points to a place to insert this line +; DI is guaranteed to be < SI +; make room for line at destination +;--------------------------- + MOV DX,[SI] ;get length of line + save ;save positions of people + STD ;go right to left + MOV CX,BP ;get end of file pointer + SUB CX,DI ;get length from destination to end + MOV SI,BP ;start from end + DEC SI ;SI points to end of file + MOV DI,SI ;destination is end of file + ADD DI,DX ;DI points to new end of file + REP MOVSB ;blam. Move every one up + CLD ;back left to right + restore ;get old source and destination +;--------------------------- +; MOVE NEW LINE INTO PLACE +;--------------------------- + save ;save destination + ADD SI,DX ;adjust for previous movement + save ;save this value + MOV CX,DX ;get number to move + REP MOVSB ;blam. move the new line in + restore ;get back destination and new source +;--------------------------- +; DELETE LINE FROM OLD PLACE +;--------------------------- + save ;save destination + MOV CX,BP ;pointer to end + ADD CX,DX ;remember bump + SUB CX,SI ;get count of bytes to move + INC CX ;turn it into a word + SHR CX,1 ;or a count of words + MOV DI,SI ;new destination of move + ADD SI,DX ;offset of block + REP MOVSW ;blam, squeeze out the space + restore ;get back original destination + MOV WORD PTR DS:[BP-2],0 ;remake the end of file mark + +END_INSERT: + ADD DI,[DI] ;link to next guy + JMP OUTER_SORT_LOOP ;and continue +;------------------------------ +; PUT BACK IN THE CR-LF +;------------------------------ +END_OUTER_SORT_LOOP: + MOV DI,BUFFER ;start at beginning (where else) + MOV CX,[DI] ;count of butes + +INSERT_LOOP: + ADD DI,CX ;point to next length + MOV CX,[DI] ;get length + MOV WORD PTR [DI],0A0DH ;replace length with CRLF + AND CX,CX ;AN004; ;check for end of file + JNZ INSERT_LOOP ;nope, try again + +WRITE_FILE: + MOV DX,BUFFER+2 ;get starting point + MOV CX,BP ;pointer to end of buffer + SUB CX,DX ;dif in pointers is number of bytes + MOV BX,1 ;to standard output + sys WRITE ;write 'em out + JC BADWRT ;some bizarre error -> flag it + CMP AX,CX ;did we write what was expected? + JZ WRTOK ;yes, say bye bye +BADWRT: + +;;;;; mov ax,msg_NoDisk ;AN000; Strange write error +;;;;; mov dh,-1 ;AN003; class: extended error +;;;;; call error_exit ;AN000; Bye bye + mov al,RETCODE_ERROR ;AN000; return an error code (errorlevel) + sys EXIT ;AN000; +WRTOK: + MOV AL,RETCODE_NOERROR ;AN000; Errorlevel 0 (No error!) + sys EXIT ;bye! + + PAGE ; +;************************************************************ +;* +;* SUBROUTINE NAME: display_msg +;* +;* SUBROUTINE FUNCTION: +;* Display the requested message to the specified handle +;* +;* INPUT: +;* 1) AX = Number of the message to be displayed. +;* 2) BX = Handle to be written to. +;* +;* OUTPUT: +;* The message corresponding to the requested msg number will +;* be written to the requested handle. There is no substitution +;* text in SORT. +;* +;* NORMAL EXIT: +;* Message will be successfully written to requested handle. +;* +;* ERROR EXIT: +;* None. Note that theoretically an error can be returned from +;* SYSDISPMSG, but there is nothing that the application can do. +;* +;* INTERNAL REFERENCES: +;* System Display Message service routines +;* +;* EXTERNAL REFERENCES: +;* None +;* +;************************************************************ + +display_msg proc near ;AN000; + push ds ;AN000; save DS value + push cs ;AN000; get DS addressability + pop ds ;AN000; + + xor cx,cx ;AN004; ;AN000; No substitution text +;; mov dh,-1 ;AN003; Message class + ; 1=DOS Extended error + ; 2=DOS Parse error + ; -1=Utility message + mov dl,0 ;AN000; DOS INT 21H function number to use for input + ; 00H=No input, 01H=Keyboard input, + ; 07H=Direct Console Input Without Echo, + ; 08H=Console Input Without Echo, 0AH=Buffered Keyboard Input + call SYSDISPMSG ;AN000; + + pop ds ;AN000; restore DS + ret ;AN000; +display_msg ENDP ;AN000; + + PAGE ; +;************************************************************ +;* +;* SUBROUTINE NAME: parse +;* +;* SUBROUTINE FUNCTION: +;* Call the DOS PARSE Service Routines to process the command +;* line. Search for valid switches (/R and /+n) and take +;* appropriate action for each. Display error message and +;* terminate on error. +;* +;* INPUT: None +;* +;* OUTPUT: None +;* +;* NORMAL EXIT: +;* +;* If /R specified, then patches code to perform reverse sort +;* by changing JAE to a JB. +;* +;* If /+n entered, COLUMN will be set to "n," otherwise COLUMN +;* will be set to 1. +;* +;* ERROR EXIT: +;* +;* If user enters any parameter or switch other than /R or /+n, +;* or an invalid value for "n", then this routine will display +;* the "Invalid Parameter" error message and terminate with +;* errorlevel 1. +;* +;* EXTERNAL REFERENCES: +;* System parse service routines +;* INT21 - GET PSP Function Call 062h +;* +;************************************************************ + +parse proc near ;AN000; + + sys GetCurrentPSP ;AN000; Get PSP address, returned in BX + + mov ds,bx ;AN000; Put PSP Seg in DS + mov si,081h ;AN000; Offset of command line in PSP + cmp byte ptr ds:080h,0 ;AN000; Check length of command line + je end_parse ;AN000; If 0 len, the we are done parsing + xor cx,cx ;AN000; Number of parms processed so far = 0 + push cs ;AN000; Put CS + pop es ;AN000; in ES +;--------------------------------- +;- Loop for each operand at DS:SI (Initially PSP + 081h) +;--------------------------------- +parse_loop: ;AN000; + mov di,offset parms ;AN000; Address of parse control block + xor dx,dx ;AN000; Reserved + call sysparse ;AN000; Parse parm at DS:SI + cmp ax,EOL ;AN000; Q: Are we at end of command line? + je end_parse ;AN000; YES: We are done + and ax,ax ;AN004; ;AN000; NO: Q: Any errors? + jne parse_error ;AN000; YES: Display msg and terminate + mov bx,sb_synonym ;AN000; Get offset of switch entered +;---------------------------------- +;- If user said /R, then patch code +;---------------------------------- + cmp bx,offset rev_sw ;AN000; If user specified /R + jne check_column ;AN000; + mov cs:code_patch,072h ;AN000; Sleazy patch to make reverse order sort + jmp parse_loop ;AN000; Look for another parm + +;--------------------------------------------- +;- If user said /+n, then save COLUMN index +;--------------------------------------------- +check_column: ;AN000; + cmp bx,offset col_sw ;AN000; Q: Did user specified /+n ? + jne switch_error ;AC003; No: Unrecognized parm + mov ax,sb_value ;AN000; Yes: Get number entered by user + mov column,ax ;AN000; Set up column to begin sort + jmp parse_loop ;AN000; Check for next parm + +;------------------------------------------------------------ +;- If any other parameter specified, display message and die +;------------------------------------------------------------ +switch_error: ;AN003; + mov ax,Msg_switch ;AN003; +parse_error: ;AN000; + mov dh,2 ;AN003; class: parse error + call error_exit ;AN000; Terminate utility + +end_parse: ;AN000; + ret ;AN000; +parse endp ;AN000; + + PAGE ; +;************************************************************ +;* +;* SUBROUTINE NAME: error_exit +;* +;* SUBROUTINE FUNCTION: +;* Displays the message number in AX to the standard +;* error device, then terminates with errorlevel 1. +;* +;* INPUT: AX = Message number +;* +;* INTERNAL REFERENCES: +;* display_msg +;* +;* EXTERNAL REFERENCES: +;* INT 021h - Terminate Function 043h +;* +;************************************************************ +error_exit proc near ;AN000; + call prt_sort ;AN003; + mov bx,STDERR ;AN000; output to standard error + xor cx,cx ;AN004; ;AN003; + call display_msg ;AN000; and write it out + mov al,RETCODE_ERROR ;AN000; return an error code (errorlevel) + sys EXIT ;AN000; + ret ;AN000; Meaningless RET +error_exit endp ;AN000; + + +;************************************************************ +;* +;* SUBROUTINE NAME: match_codepages +;* +;* SUBROUTINE FUNCTION: +;* Check to see if Code Page Support is active. If so, +;* check code page of input and output handles. If the +;* source file has a code page file tag AND the target +;* handles code page is different, then set code page +;* of the target to that of the source. +;* +;* INTERNAL REFERENCES: +;* none +;* +;* EXTERNAL REFERENCES: +;* INT 021h - Check CPSW +;* INT 021h - Get Extended Attributes by Handle +;* INT 021h - Set Extended Attributes by Handle +;* +;************************************************************ + +match_codepages proc near ;AN000; + +;----------------------------------- +; Check status of Code page support +;----------------------------------- + push es ;AN000; Save ES register + push ds ;AN001; Save DS register +; + mov ax,cs ;AN001; ES, DS -> CS + mov ds,ax ;AN001; + mov es,ax ;AN001; +; + mov ax,GetCPSW ;AN000; Get CPSW state, assume support is OFF + int 021h ;AN000; DL: 0=NotSupported,1=Supported + cmp dl,1 ;AN000; CPSW supported if DL=1 + jne done_cpsw ;AN000; If not supported, we're done +;----------------------------------- +; Get Code Pages of STDIN and STDOUT +;----------------------------------- + mov ax,GetExtAttr ;AN000; Get Extended Attributes by Handle + mov bx,STDOUT ;AN000; For Standard output device + mov di,offset cp_list ;AC001; Return buffer address + mov si,offset cp_qlist ;AN001; Query the code page attribute + mov cx,cp_len ;AN001; return buffer length + int 021h ;AN000; + jc done_cpsw ;AN000; Error condition, let system handle + mov ax,cp ;AN000; Save target code page + mov tgt_cp,ax ;AN000; for later reference + + mov ax,GetExtAttr ;AN000; Get Extended Attributes by Handle + xor bx,bx ;AN004; ;AN000; bx = STDIN (0) For Standard input device + mov di,offset cp_list ;AC001; Return buffer address + mov si,offset cp_qlist ;AN001; Query the code page attribute + mov cx,cp_len ;AN001; return buffer length + int 021h ;AN000; + jc done_cpsw ;AN000; Error condition, let system handle + mov ax,cp ;AN000; Save source code page + mov src_cp,ax ;AN000; for later reference + + mov ax,src_cp ;AN000; Get source codepage + and ax,ax ;AN004; ;AN000; IF no codepage + je done_cpsw ;AN000; THEN no action required; + cmp ax,tgt_cp ;AN000; IF src_cp = tgt_cp + je done_cpsw ;AN000; THEN no action required; +;------------------------------------- +;- Set CP of target to that of source +;------------------------------------- + mov cp_reset,TRUE ;AN000; Set flag indicating change + mov ax,SetExtAttr ;AN000; Set Extended Attributes by Handle + mov bx,STDOUT ;AN000; For Standard output device + mov di,offset cp_list ;AC001; Input buffer address + int 021h ;AN000; + +done_cpsw: ;AN000; + pop ds ;AN001; Restore DS register + pop es ;AN000; Restore ES register + ret ;AN000; +match_codepages endp ;AN000; + + PAGE ; +;************************************************************ +;* +;* SUBROUTINE NAME: prt_sort +;* +;* SUBROUTINE FUNCTION: +;* Preceeds all error messages with "SORT: ". +;* +;* INTERNAL REFERENCES: +;* none +;* EXTERNAL REFERENCES: +;* none +;************************************************************ +prt_sort proc near ;AN003; + push ax ;AN003; + push dx ;AN003; +; + mov dh,-1 ;AN003; + mov ax,Msg_sort ;AN003; + xor cx,cx ;AN004; ;AN003; + mov bx,STDERR ;AN003; + call display_msg ;AN003; +; + pop dx ;AN003; + pop ax ;AN003; +; + ret ;AN003; +prt_sort endp ;AN003; + + + PAGE ; +;-------------------- +.xlist +.xcref +INCLUDE parse.asm +include msgdcl.inc +.cref +.list +;-------------------- + +CODE ENDS + + + + + + + +CONST SEGMENT PUBLIC BYTE + + extrn table:byte + +CONST ENDS + + + + +SUBTTL Initialized Data +;------------------------------- +;--- Stack Segment +;------------------------------- +CSTACK SEGMENT STACK + db (362 - 80h) + 96 dup (0) ;(362 - 80h) == New - Old IBM + ;interrupt reqs. == size of growth +CSTACK ENDS + + END SORT diff --git a/v4.0/src/CMD/SORT/SORT.LNK b/v4.0/src/CMD/SORT/SORT.LNK new file mode 100644 index 0000000..6ad8920 --- /dev/null +++ b/v4.0/src/CMD/SORT/SORT.LNK @@ -0,0 +1,4 @@ +SORT+ +SORTMES +SORT.EXE; + \ No newline at end of file diff --git a/v4.0/src/CMD/SORT/SORT.SKL b/v4.0/src/CMD/SORT/SORT.SKL new file mode 100644 index 0000000..b7a695f --- /dev/null +++ b/v4.0/src/CMD/SORT/SORT.SKL @@ -0,0 +1,12 @@ +:util SORT ;AN000; +:class 1 ;AN000; + +:class 2 ;Parser errors ;AN003; + +:class A ;AN000; +:use 1 COMMON1 ;AN000; ;"Incorrect DOS version",CR,LF +:use 2 EXTEND8 ;AN000; ;"Insufficient memory",CR,LF +:use 4 COMMON20 ;AN003; +:def 5 "SORT: " ;AN003; + +:end ;AN000; diff --git a/v4.0/src/CMD/SORT/SORTMES.ASM b/v4.0/src/CMD/SORT/SORTMES.ASM new file mode 100644 index 0000000..24761e4 --- /dev/null +++ b/v4.0/src/CMD/SORT/SORTMES.ASM @@ -0,0 +1,85 @@ +TITLE SORT Messages + +false equ 0 +true equ not false +msver equ false +ibm equ true +internat equ true + +msg Macro lbl,msg +local a +public lbl,lbl&len +lbl&len dw a - lbl +lbl db msg +a label byte +endm + +CONST SEGMENT PUBLIC BYTE + +if internat + public table +;This table defibes the coalating sequence to be used for +;international characters. This table also equates +;lower case character to upper case unlike a straight ASCII sort. +;If your character set is like the IBM PC simply turn +;on the IBM conditional. If it is different simply modify the +;table appropriately. Note: to insert a foreign language character +;between two ASCII characters it will be necessary to +;"shift" all the ASCII characters to make room for a new character. +;If this is done be sure to equate the foreign characters to the new +;values instead of the old values which have been set here to the +;upper case ASCII values. + +table db 0,1,2,3,4,5,6,7 + db 8,9,10,11,12,13,14,15 + db 16,17,18,19,20,21,22,23 + db 24,25,26,27,28,29,30,31 + db " ","!",'"',"#","$","%","&","'" + db "(",")","*","+",",","-",".","/" + db "0","1","2","3","4","5","6","7" + db "8","9",":",";","<","=",">","?" + db "@","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","[","\","]","^","_" + db "`","A","B","C","D","E","F","G" + db "H","I","J","K","L","M","N","O" + db "P","Q","R","S","T","U","V","W" + db "X","Y","Z","{","|","}","~",127 +if msver + db 128,129,130,131,132,133,134,135 + db 136,137,138,139,140,141,142,143 + db 144,145,146,147,148,149,150,151 + db 152,153,154,155,156,157,158,159 + db 160,161,162,163,164,165,166,167 + db 168,169,170,171,172,173,174,175 + endif +if ibm + db "C","U","E","A","A","A","A","C" + db "E","E","E","I","I","I","A","A" + db "E","A","A","O","O","O","U","U" + db "Y","O","U","$","$","$","$","$" + db "A","I","O","U","N","N",166,167 + db "?",169,170,171,172,"!",'"','"' + endif + db 176,177,178,179,180,181,182,183 + db 184,185,186,187,188,189,190,191 + db 192,193,194,195,196,197,198,199 + db 200,201,202,203,204,205,206,207 + db 208,209,210,211,212,213,214,215 + db 216,217,218,219,220,221,222,223 +if ibm + db 224,"S" +endif +if msver + db 224,225 +endif + db 226,227,228,229,230,231 + db 232,233,234,235,236,237,238,239 + db 240,241,242,243,244,245,246,247 + db 248,249,250,251,252,253,254,255 + endif + +CONST ENDS + END + \ No newline at end of file -- cgit v1.2.3