1 TITLE SORT FILTER FOR DOS
3 ;**********************************************************
7 ;* SOURCE FILE NAME: sort.asm
11 ;* External non-resident utility, written in Assembler.
12 ;* Reads from the standard input device until end-of-file,
13 ;* sorts the data (up to 64k) and writes the results to
14 ;* the standard output device. Input and output can be
17 ;* INPUT (Command line)
21 ;* /R - Sort in reverse order
22 ;* /+n - Start sorting in column "n" , default 1
25 ;* Sorted data will be written to the standard output device.
28 ;* Incorrect DOS version
29 ;* Insufficient disk space on target
30 ;* Insufficient memory to allocate SORT buffer
33 ;* INTERNAL REFERENCES:
37 ;* Modification History:
38 ;* 3-18-83 MZ (Microsoft)
39 ;* Fix CR-LF at end of buffer
40 ;* Fix small file sorting
41 ;* Fix CR-LF line termination bug
42 ;* Comment the Damn source
45 ;* Add DOS 3.30 support for multiple languages
46 ;* Inclusion of common DOS VERSION check equate
48 ;* ;AN000; Code added in DOS 4.0
49 ;* 5-19-87 RW (IBM) (DOS 4.0)
50 ;* Addition of IBM Parser Service Routines
51 ;* Addition of DOS Message Retriever Service Routines
52 ;* Add code page file tag support
54 ;* ;AN001; Code added in DOS 4.0
56 ;* 9-18-87 BL (IBM) (DOS 4.0)
57 ;* Added Extended Attribute support for code page checking
58 ;* and file type checking.
60 ;* 10-19-87 BL (IBM) (DOS 4.0)
63 ;* 01-29-87 BL (IBM) (DOS 4.0)
64 ;* Ran tool INSPECT on .lst file for optimizations
65 ;**********************************************************
68 ;-------------------------
69 ;--- Macro definitions
70 ;-------------------------
78 sys
MACRO name
;system call macro
85 save
MACRO reglist
;push those registers
93 restore MACRO reglist
;pop those registers
101 ;-------------------------------
103 ;-------------------------------
106 MAXREC EQU
256 ;MAXIMUM NUL RECORD SIZE
108 SPACE EQU
0 ;Offset zero in the allocated block
109 BUFFER EQU MAXREC
;Offset MAXREC in the allocated block
111 RETCODE_NOERROR equ
0 ;AN000; DOS return code (errorlevel)
112 RETCODE_ERROR equ
1 ;AN000; DOS return code (errorlevel)
114 NO_CODEPAGE equ
0 ;AN000; Tag for files with no codepage
116 GetCPSW equ 3303h
;AN000; Int 021h function calls
117 GetExtAttr equ 5702h
;AN000;
118 SetExtAttr equ 5704h
;AN000;
119 ;-----------------------
121 ;-----------------------
122 EOL EQU
-1 ;AN000; Indicator for End-Of-Line
123 NOERROR EQU
0 ;AN000; Return Indicator for No Errors
140 ;-----------------------
142 ;-----------------------
147 Msg_NoMem equ
2 ;AC003;
148 Msg_NoDisk equ
4 ;AC003;
149 Msg_sort equ
5 ;AN003;
150 Msg_switch equ
3 ;AN003;
152 ;------------------------------
153 ; EXTENDED ATTRIBUTE Equates
154 ;------------------------------
155 EAISBINARY equ
02h ;AN001; ea_type
156 EASYSTEM equ 8000h
;AN001; ea_flags
159 ;---------------------;
162 INCLUDE syscall.inc ;
163 INCLUDE sysmsg
.inc ; ;AN000; Include message equates and MACROS
166 ;---------------------;
168 MSG_UTILNAME
<SORT
> ;AN000;
170 SUBTTL Segments
used in load order
176 CONST
SEGMENT PUBLIC BYTE
180 ;-----------------------
182 ;-----------------------
184 db 128 DUP (0) ;initial stack to be clear
190 ;-------------------------------
192 ;-------------------------------
193 DG GROUP
CODE,CONST
,CSTACK
196 ;-------------------------------
198 ;-------------------------------
200 ASSUME
CS:DG
,DS:DG
,ES:NOTHING
,SS:CSTACK
202 ;-------------------------------
204 ;-------------------------------
205 COLUMN dw 0 ;COLUMN TO USE FOR KEY + 1
206 cp_reset db FALSE
;AN000;Flag indicating if Code Page was reset on target file
208 ;------------------------------------------DOS 3.30 - Russ Whitehead
212 ;------------------------------------------
214 MSG_SERVICES
<MSGDATA
> ;AN000;
217 ;----------------------------------------
218 ;- STRUCTURE TO QUERY EXTENDED ATTRIBUTES
219 ;----------------------------------------
220 querylist
struc ;AN001; ;query general list
222 qea_type db EAISBINARY
;AN001;
223 qea_flags dw EASYSTEM
;AN001;
224 qea_namelen db ?
;AN001;
225 qea_name db " " ;AN001;
226 querylist ends
;AN001;
228 cp_qlist querylist
<1,EAISBINARY
,EASYSTEM
,2,"CP"> ;AN001; ;query code page attr.
230 cp_list
label word ;AN001; ;code page attr. get/set list
231 dw 1 ;AN001; ; # of list entries
232 db EAISBINARY
;AN001; ; ea type
233 dw EASYSTEM
;AN001; ; ea flags
234 db ?
;AN001; ; ea return code
235 db 2 ;AN001; ; ea name length
236 dw 2 ;AN001; ; ea value length
237 db "CP" ;AN001; ; ea name
238 cp dw ?
;AN001; ; ea value (code page)
239 cp_len equ
($ - cp_list
) ;AN001;
241 ;-------Save area for Code Pages
242 src_cp dw ?
;AN000; Save area for current code page
243 tgt_cp dw ?
;AN000; Save area for current code page
244 endlist
label word ;AN000;
247 ;******************************************************************************
248 ;* PARSER DATA STRUCTURES FOLLOW
249 ;******************************************************************************
251 ;------------------------------
252 ;- STRUCTURE TO DEFINE ADDITIONAL COMMAND LINE DELIMITERS
253 ;------------------------------
254 parms
label word ;AN000;
255 dw parmsx
;AN000; POINTER TO PARMS STRUCTURE
256 db 1 ;AN000; DELIMITER LIST FOLLOWS
257 db 1 ;AN000; NUMBER OF ADDITIONAL DELIMITERS
258 db ";" ;AN000; ADDITIONAL DELIMITER
260 ;------------------------------
261 ;- STRUCTURE TO DEFINE SORT SYNTAX REQUIREMENTS
262 ;------------------------------
263 parmsx
label word ;AN000;
264 db 0,0 ;AN000; THERE ARE NO POSITIONAL PARAMETERS
265 db 2 ;AN000; THERE ARE 2 SWITCHES (/R AND /+n)
266 dw sw1
;AN000; POINTER TO FIRST SWITCH DEFINITION AREA
267 dw sw2
;AN000; POINTER TO SECOND SWITCH DEFINITION AREA
268 dw 0 ;AN000; THERE ARE NO KEYWORDS IN SORT SYNTAX
270 ;------------------------------
271 ;- STRUCTURE TO DEFINE THE /R SWITCH
272 ;------------------------------
273 sw1
label word ;AN000;
274 dw 0 ;AN000; NO MATCH FLAGS
275 dw 0 ;AN000; NO FUNCTION FLAGS
276 dw switchbuff
;AN000; PLACE RESULT IN switchbufF
277 dw novals
;AN000; NO VALUE LIST
278 db 1 ;AN000; ONLY ONE SWITCH IN FOLLOWING LIST
279 rev_sw db "/R",0 ;AN000; /R INDICATES REVERSE SORT
281 ;------------------------------
282 ;- STRUCTURE TO DEFINE THE /+n SWITCH
283 ;------------------------------
284 NUMERIC equ
08000h ;AN000; Control flag for numeric value
285 NO_COLON equ
0020h ;AN000;
287 sw2
label word ;AN000;
288 dw NUMERIC
;AN000; MATCH_FLAGS
289 dw NO_COLON
;AN000; NO FUNCTION FLAGS
290 dw switchbuff
;AN000; PLACE RESULT IN switchbufF
291 dw valuelist
;AN000; NEED VALUE LIST FOR n
292 db 1 ;AN000; ONLY 1 SWITCH ON FOLLOWING LIST
293 col_sw db "/+",0 ;AN000; /+n INDICATES BEGIN SORT IN COLUMN n
295 ;------------------------------
296 ;- VALUE LIST DEFINITION FOR NO VALUES
297 ;------------------------------
298 novals
label word ;AN000;
299 DB 0 ;AN000; VALUE LIST
301 ;------------------------------
302 ;- VALUE LIST DEFINITION FOR /+n
303 ;------------------------------
304 valuelist
label word ;AN000;
305 db 1 ;AN000; ONE VALUE ALLOWED
306 db 1 ;AN000; ONLY ONE RANGE
307 db 1 ;AN000; IDENTIFY THE RANGE
308 dd 1,65535 ;AN000; USER CAN SPECIFY /+1 THROUGH /+65535
310 ;------------------------------
311 ;- RETURN BUFFER FOR SWITCH INFORMATION
312 ;------------------------------
313 switchbuff
label word ;AN000;
314 sb_type db ?
;AN000; TYPE RETURNED
315 sb_item_tag db ?
;AN000; SPACE FOR ITEM TAG
316 sb_synonym dw ?
;AN000; ES:sb_synonym points to synonym
318 sb_value dw ?
;AN000; SPACE FOR VALUE
319 sb_value_extra dw ?
;AN000; UNUSED SPACE FOR VALUE
322 ;**************************************************************
324 ;* SUBROUTINE NAME: main
326 ;* SUBROUTINE FUNCTION:
327 ;* Mainline routine, performs SYSLODMSG, calls routines to
328 ;* parse command line, performs the SORT and writes the
334 ;* File to be sorted will be read from Standard Input
338 ;* Sorted data will be written to the Standard Output
342 ;* SORT will normally exit when data was successfully read
343 ;* in up to 64k or EOF, sorted, and displayed to the
344 ;* standard output device.
347 ;* If any of the following errors, SORT will display the
348 ;* corresponding error message and terminate.
350 ;* Insufficient disk space on target device
351 ;* Incorrect DOS version
352 ;* Insufficient memory to sort
354 ;************************************************************
356 ;-------------------------
358 ;-------------------------
359 MSG_SERVICES
<SORT
.ctl
,SORT
.cla
,SORT
.cl1
,SORT
.cl2
> ;AN000;
360 MSG_SERVICES
<DISPLAYmsg
,LOADmsg
,CHARmsg
,NOCHECKSTDIN
> ;AN002; Make retriever services available
362 mov ax,cs ;AN003; ;load ES to the right area,
366 call sysloadmsg
;AN000; Preload messages, Check DOS Version.
367 ;If Inc DOS Ver or error loading messages,
368 ;SYSLOADMSG will show msg and terminate for us
369 jnc parser
;AN000; If no error, parse command line
370 call sysdispmsg
;AN000; There was error. Let SYSDISPMSG Display
371 cmp bx,-1 ;AN000; Is this DOS 1.0 or 1.1 ?
372 je OLD_ABORT
;AN000; Yes, terminate old way
374 mov ah,Exit
;AN000; No, terminate new way
375 mov al,0 ;AN000; Errorlevel 0 (Compatible!)
376 int 021h ;AN000; Bye bye!
378 OLD_ABORT: ;AN000; CS should point to PSP
379 mov ah,Abort
;AN000; Terminate program (AH=0)
380 int 021h ;AN000; Bye bye!
381 ;-----------------------------------
382 ;- DOS version is ok. Parse cmd line
383 ;-----------------------------------
384 PARSER: ;AN000; message and terminate
385 call parse
;AN000; Parse command line
387 ;-----------------------------------
388 ; set up column for proper sort offset
389 ;-----------------------------------
396 ;------------------------------------
397 ; Get sorting area, no more than 64K
398 ;------------------------------------
400 MOV BX,1000H
;64K worth of paragraphs
402 mov bp,bx ;AN003; save buffer length
403 sys ALLOC
;allocate them from somewhere
404 JNC GOT_MEM
;if error, BX has amount free, try to get it
405 OR BX,BX ;but, is BX = 0?
406 JNZ GET_MEM
;nope, try to allocate it
407 JMP short SIZERR
;AN004; ;complain
410 ;------------------------------------RussW:--Following add in DOS 3.3 for Nat Lang Support
414 mov al,6 ;Function for Get collating sequence
415 mov bx,-1 ;Get active code page
416 mov dx,-1 ;Get info from active country
417 mov cx,5 ;Number of bytes to be returned
418 push cs ;Place code segment
420 mov di,offset ctry_info
;Return area for 5 byte requested information
421 sys GetExtCntry
;Get extended country information
422 ;Ok, now copy the table in DOS to our segment
423 lds si,dword ptr cs:ctry_table_off
426 mov di,offset dg
:table
434 ;Done copying, so restore regs and cont
438 ;------------------------------------RussW:--End 3.3 addition
439 MOV DS,AX ;Point DS to buffer
440 MOV ES,AX ;and point ES to buffer
441 MOV CL,4 ;2^4 bytes per paragraph
442 MOV BX,BP ;AN003; restore buffer length
443 SHL BX,CL ;Find out how many bytes we have
444 MOV BP,BX ;AN003; save buffer length in bytes
446 ;---------------------------
447 ; Clear out temporary record area
448 ;---------------------------
449 MOV CX,MAXREC
/2 ;Size of temporary buffer (words)
450 MOV AX,' ' ;Character to fill with
451 XOR DI,DI ;AN004; ;Beginning of temp buffer
453 ;-----------------------------------
454 ; Make sure source and target code pages are the same
455 ;-----------------------------------
456 call match_codepages
;AN000; Make sure codepages are the same
457 ;---------------------------
458 ; read in file from standard input
459 ;---------------------------
460 MOV DX,BUFFER
+ 2 ;DX = place to begin reading
461 MOV CX,BP ;AN003; ;CX is the max number to read
462 SUB CX,MAXREC
+ 2 ;remember offset of temp buffer
464 XOR BX,BX ;Standard input
466 ADD DX,AX ;Bump pointer by count read
467 SUB CX,AX ;subtract from remaining the count read
468 JZ SIZERR
;if buffer is full then error
469 OR AX,AX ;no chars read -> end of file
470 JNZ SORTL
;there were chars read. go read again
471 JMP SHORT SIZOK
;trim last ^Z terminated record
473 mov ax,msg_NoMem
;AN000; not enough memory error
474 mov dh,-1 ;AN003; class: utility error
475 call error_exit
;AN000; and write it out
477 ;---------------------------
478 ; Look for a ^Z. Terminate buffer at 1st ^Z.
479 ;---------------------------
481 MOV BX,DX ;save end pointer
482 MOV CX,DX ;get pointer to end of text
483 SUB CX,BUFFER
+2 ;dif in pointers is count
484 MOV AL,1
AH ;char is ^Z
485 MOV DI,BUFFER
+2 ;point to beginning of text
486 REPNZ SCASB ;find one
487 JNZ NoBack
;nope, try to find CRLF
488 DEC BX ;pretend that we didn't see ^Z
490 SUB BX,CX ;sub from endpointer the number left
491 SUB BX,2 ;Hope for a CR LF at end
492 CMP WORD PTR [BX],0A0Dh ;Was there one there?
493 JZ GOTEND
;yep, here is the end
494 ADD BX,2 ;nope, bump back to SCASB spot
495 CMP BYTE PTR [BX],AL ;Was there ^Z there?
496 JZ GOTEND
;yep, chop it
497 INC BX ;Nope, skip last char
499 MOV BP,BX ;BP = filesize-2(CRLF)+temp buffer+2
500 MOV WORD PTR DS:[BP],0 ;0 at end of the file
502 ;---------------------------
503 ; We now turn the entire buffer into a linked list of chains by
504 ; replacing CRLFs with the length of the following line (with 2 for CRLF)
505 ;---------------------------
506 MOV BX,BUFFER
;pointer to line head (length)
507 MOV DI,BUFFER
+2 ;pointer to line text
509 MOV AL,13 ;char to look for is CR
510 MOV CX,BP ;count = end pointer
511 SUB CX,DI ;chop off start point to get length
514 REPNZ SCASB ;look for CR
515 JNZ REPLACE_SKIP
;count exhausted
516 CMP BYTE PTR [DI],10 ;LF there?
517 JNZ REPLACE_SCAN
;nope, continue scanning
519 MOV AX,DI ;AX to point after CR
520 DEC AX ;AX to point to CR
521 save
<AX> ;save pointer
522 SUB AX,BX ;AX is length of line found
523 MOV [BX],AX ;stuff it in previous link
524 restore <BX> ;get pointer to next
526 JCXZ END_REPLACE_LOOP
;no more to scan -> go sort
527 JMP REPLACE_LOOP
;look for next
530 MOV WORD PTR [BX],0 ;terminate file with nul
531 LEA BP,[BX+2] ;remember the null line at end
532 MOV DI,BUFFER
;DI is start of unsorted section
534 ;---------------------------
535 ; begin sort. Outer loop steps over all unsorted lines
536 ;---------------------------
538 MOV BX,DI ;BX is start of unsorted section
539 MOV SI,BX ;SI is scanning place link
540 CMP WORD PTR [BX],0 ;are we at the end of the buffer?
541 JNZ INNER_SORT_LOOP
;No, do inner process
542 JMP END_OUTER_SORT_LOOP
;yes, go dump out
544 ;---------------------------
545 ; BX points to best guy found so far. We scan through the sorted section
546 ; to find an appropriate insertion point
547 ;---------------------------
549 ADD SI,[SI] ;link to next fellow
550 MOV AX,[SI] ;get length of comparison guy
551 OR AX,AX ;test for end of buffer
552 JZ END_INNER_SORT_LOOP
;if zero then figure out insertion
553 save
<SI,DI> ;save SI,DI
554 MOV DI,BX ;DI = pointer to tester link
555 SUB AX,COLUMN
;adjust length for column
556 JA AXOK
;more chars in tester than column?
557 XOR SI,SI ;AN004; ;point SI to blank area
558 MOV AX,MAXREC
;make AX be max length
560 MOV DX,[DI] ;get length of best guy
561 SUB DX,COLUMN
;adjust length for column
562 JA DXOK
;there are more chars after column
563 XOR DI,DI ;AN004; ;point air to a space
564 MOV DX,MAXREC
;really big record
566 MOV CX,AX ;AX is shortest record
567 CMP AX,DX ;perhaps DX is shorter
568 JB SMALL
;nope, leace CX alone
569 MOV CX,DX ;DX is shorter, put length in CX
571 ADD DI,COLUMN
;offset into record
572 ADD SI,COLUMN
;offset into other record
575 mov bx,offset dg
:table
577 xlat byte ptr cs:[bx]
581 xlat byte ptr cs:[bx]
586 restore <DI,SI> ;get head pointers back
587 JNZ TESTED_NOT_EQUAL
;didn't exhaust counter, conditions set
588 CMP AX,DX ;check string lengths
591 ;---------------------------
592 ; NOTE! jae is patched to a jbe if file is to be sorted in reverse!
593 ;---------------------------
594 CODE_PATCH
label byte
595 JAE INNER_SORT_LOOP
;if this one wasn't better then go again
596 MOV BX,SI ;it was better, save header
597 JMP INNER_SORT_LOOP
;and scan again
600 MOV SI,BX ;SI is now the best person
601 CMP SI,DI ;check best for current
602 JZ END_INSERT
;best equals current, all done
604 ;---------------------------
605 ; SI points to best line found so far
606 ; DI points to a place to insert this line
607 ; DI is guaranteed to be < SI
608 ; make room for line at destination
609 ;---------------------------
610 MOV DX,[SI] ;get length of line
611 save
<SI,DI> ;save positions of people
612 STD ;go right to left
613 MOV CX,BP ;get end of file pointer
614 SUB CX,DI ;get length from destination to end
615 MOV SI,BP ;start from end
616 DEC SI ;SI points to end of file
617 MOV DI,SI ;destination is end of file
618 ADD DI,DX ;DI points to new end of file
619 REP MOVSB ;blam. Move every one up
620 CLD ;back left to right
621 restore <DI,SI> ;get old source and destination
622 ;---------------------------
623 ; MOVE NEW LINE INTO PLACE
624 ;---------------------------
625 save
<DI> ;save destination
626 ADD SI,DX ;adjust for previous movement
627 save
<SI> ;save this value
628 MOV CX,DX ;get number to move
629 REP MOVSB ;blam. move the new line in
630 restore <SI,DI> ;get back destination and new source
631 ;---------------------------
632 ; DELETE LINE FROM OLD PLACE
633 ;---------------------------
634 save
<DI> ;save destination
635 MOV CX,BP ;pointer to end
636 ADD CX,DX ;remember bump
637 SUB CX,SI ;get count of bytes to move
638 INC CX ;turn it into a word
639 SHR CX,1 ;or a count of words
640 MOV DI,SI ;new destination of move
641 ADD SI,DX ;offset of block
642 REP MOVSW ;blam, squeeze out the space
643 restore <DI> ;get back original destination
644 MOV WORD PTR DS:[BP-2],0 ;remake the end of file mark
647 ADD DI,[DI] ;link to next guy
648 JMP OUTER_SORT_LOOP
;and continue
649 ;------------------------------
650 ; PUT BACK IN THE CR-LF
651 ;------------------------------
653 MOV DI,BUFFER
;start at beginning (where else)
654 MOV CX,[DI] ;count of butes
657 ADD DI,CX ;point to next length
658 MOV CX,[DI] ;get length
659 MOV WORD PTR [DI],0A0DH ;replace length with CRLF
660 AND CX,CX ;AN004; ;check for end of file
661 JNZ INSERT_LOOP
;nope, try again
664 MOV DX,BUFFER
+2 ;get starting point
665 MOV CX,BP ;pointer to end of buffer
666 SUB CX,DX ;dif in pointers is number of bytes
667 MOV BX,1 ;to standard output
668 sys WRITE
;write 'em out
669 JC BADWRT
;some bizarre error -> flag it
670 CMP AX,CX ;did we write what was expected?
671 JZ WRTOK
;yes, say bye bye
674 ;;;;; mov ax,msg_NoDisk ;AN000; Strange write error
675 ;;;;; mov dh,-1 ;AN003; class: extended error
676 ;;;;; call error_exit ;AN000; Bye bye
677 mov al,RETCODE_ERROR
;AN000; return an error code (errorlevel)
680 MOV AL,RETCODE_NOERROR
;AN000; Errorlevel 0 (No error!)
684 ;************************************************************
686 ;* SUBROUTINE NAME: display_msg
688 ;* SUBROUTINE FUNCTION:
689 ;* Display the requested message to the specified handle
692 ;* 1) AX = Number of the message to be displayed.
693 ;* 2) BX = Handle to be written to.
696 ;* The message corresponding to the requested msg number will
697 ;* be written to the requested handle. There is no substitution
701 ;* Message will be successfully written to requested handle.
704 ;* None. Note that theoretically an error can be returned from
705 ;* SYSDISPMSG, but there is nothing that the application can do.
707 ;* INTERNAL REFERENCES:
708 ;* System Display Message service routines
710 ;* EXTERNAL REFERENCES:
713 ;************************************************************
715 display_msg proc
near ;AN000;
716 push ds ;AN000; save DS value
717 push cs ;AN000; get DS addressability
720 xor cx,cx ;AN004; ;AN000; No substitution text
721 ;; mov dh,-1 ;AN003; Message class
722 ; 1=DOS Extended error
725 mov dl,0 ;AN000; DOS INT 21H function number to use for input
726 ; 00H=No input, 01H=Keyboard input,
727 ; 07H=Direct Console Input Without Echo,
728 ; 08H=Console Input Without Echo, 0AH=Buffered Keyboard Input
729 call SYSDISPMSG
;AN000;
731 pop ds ;AN000; restore DS
733 display_msg ENDP
;AN000;
736 ;************************************************************
738 ;* SUBROUTINE NAME: parse
740 ;* SUBROUTINE FUNCTION:
741 ;* Call the DOS PARSE Service Routines to process the command
742 ;* line. Search for valid switches (/R and /+n) and take
743 ;* appropriate action for each. Display error message and
744 ;* terminate on error.
752 ;* If /R specified, then patches code to perform reverse sort
753 ;* by changing JAE to a JB.
755 ;* If /+n entered, COLUMN will be set to "n," otherwise COLUMN
760 ;* If user enters any parameter or switch other than /R or /+n,
761 ;* or an invalid value for "n", then this routine will display
762 ;* the "Invalid Parameter" error message and terminate with
765 ;* EXTERNAL REFERENCES:
766 ;* System parse service routines
767 ;* INT21 - GET PSP Function Call 062h
769 ;************************************************************
771 parse proc
near ;AN000;
773 sys GetCurrentPSP
;AN000; Get PSP address, returned in BX
775 mov ds,bx ;AN000; Put PSP Seg in DS
776 mov si,081h ;AN000; Offset of command line in PSP
777 cmp byte ptr ds:080h,0 ;AN000; Check length of command line
778 je end_parse
;AN000; If 0 len, the we are done parsing
779 xor cx,cx ;AN000; Number of parms processed so far = 0
780 push cs ;AN000; Put CS
782 ;---------------------------------
783 ;- Loop for each operand at DS:SI (Initially PSP + 081h)
784 ;---------------------------------
786 mov di,offset parms
;AN000; Address of parse control block
787 xor dx,dx ;AN000; Reserved
788 call sysparse
;AN000; Parse parm at DS:SI
789 cmp ax,EOL
;AN000; Q: Are we at end of command line?
790 je end_parse
;AN000; YES: We are done
791 and ax,ax ;AN004; ;AN000; NO: Q: Any errors?
792 jne parse_error
;AN000; YES: Display msg and terminate
793 mov bx,sb_synonym
;AN000; Get offset of switch entered
794 ;----------------------------------
795 ;- If user said /R, then patch code
796 ;----------------------------------
797 cmp bx,offset rev_sw
;AN000; If user specified /R
798 jne check_column
;AN000;
799 mov cs:code_patch
,072h ;AN000; Sleazy patch to make reverse order sort
800 jmp parse_loop
;AN000; Look for another parm
802 ;---------------------------------------------
803 ;- If user said /+n, then save COLUMN index
804 ;---------------------------------------------
805 check_column: ;AN000;
806 cmp bx,offset col_sw
;AN000; Q: Did user specified /+n ?
807 jne switch_error
;AC003; No: Unrecognized parm
808 mov ax,sb_value
;AN000; Yes: Get number entered by user
809 mov column
,ax ;AN000; Set up column to begin sort
810 jmp parse_loop
;AN000; Check for next parm
812 ;------------------------------------------------------------
813 ;- If any other parameter specified, display message and die
814 ;------------------------------------------------------------
815 switch_error: ;AN003;
816 mov ax,Msg_switch
;AN003;
818 mov dh,2 ;AN003; class: parse error
819 call error_exit
;AN000; Terminate utility
826 ;************************************************************
828 ;* SUBROUTINE NAME: error_exit
830 ;* SUBROUTINE FUNCTION:
831 ;* Displays the message number in AX to the standard
832 ;* error device, then terminates with errorlevel 1.
834 ;* INPUT: AX = Message number
836 ;* INTERNAL REFERENCES:
839 ;* EXTERNAL REFERENCES:
840 ;* INT 021h - Terminate Function 043h
842 ;************************************************************
843 error_exit proc
near ;AN000;
844 call prt_sort
;AN003;
845 mov bx,STDERR
;AN000; output to standard error
846 xor cx,cx ;AN004; ;AN003;
847 call display_msg
;AN000; and write it out
848 mov al,RETCODE_ERROR
;AN000; return an error code (errorlevel)
850 ret ;AN000; Meaningless RET
851 error_exit endp
;AN000;
854 ;************************************************************
856 ;* SUBROUTINE NAME: match_codepages
858 ;* SUBROUTINE FUNCTION:
859 ;* Check to see if Code Page Support is active. If so,
860 ;* check code page of input and output handles. If the
861 ;* source file has a code page file tag AND the target
862 ;* handles code page is different, then set code page
863 ;* of the target to that of the source.
865 ;* INTERNAL REFERENCES:
868 ;* EXTERNAL REFERENCES:
869 ;* INT 021h - Check CPSW
870 ;* INT 021h - Get Extended Attributes by Handle
871 ;* INT 021h - Set Extended Attributes by Handle
873 ;************************************************************
875 match_codepages proc
near ;AN000;
877 ;-----------------------------------
878 ; Check status of Code page support
879 ;-----------------------------------
880 push es ;AN000; Save ES register
881 push ds ;AN001; Save DS register
883 mov ax,cs ;AN001; ES, DS -> CS
887 mov ax,GetCPSW
;AN000; Get CPSW state, assume support is OFF
888 int 021h ;AN000; DL: 0=NotSupported,1=Supported
889 cmp dl,1 ;AN000; CPSW supported if DL=1
890 jne done_cpsw
;AN000; If not supported, we're done
891 ;-----------------------------------
892 ; Get Code Pages of STDIN and STDOUT
893 ;-----------------------------------
894 mov ax,GetExtAttr
;AN000; Get Extended Attributes by Handle
895 mov bx,STDOUT
;AN000; For Standard output device
896 mov di,offset cp_list
;AC001; Return buffer address
897 mov si,offset cp_qlist
;AN001; Query the code page attribute
898 mov cx,cp_len
;AN001; return buffer length
900 jc done_cpsw
;AN000; Error condition, let system handle
901 mov ax,cp
;AN000; Save target code page
902 mov tgt_cp
,ax ;AN000; for later reference
904 mov ax,GetExtAttr
;AN000; Get Extended Attributes by Handle
905 xor bx,bx ;AN004; ;AN000; bx = STDIN (0) For Standard input device
906 mov di,offset cp_list
;AC001; Return buffer address
907 mov si,offset cp_qlist
;AN001; Query the code page attribute
908 mov cx,cp_len
;AN001; return buffer length
910 jc done_cpsw
;AN000; Error condition, let system handle
911 mov ax,cp
;AN000; Save source code page
912 mov src_cp
,ax ;AN000; for later reference
914 mov ax,src_cp
;AN000; Get source codepage
915 and ax,ax ;AN004; ;AN000; IF no codepage
916 je done_cpsw
;AN000; THEN no action required;
917 cmp ax,tgt_cp
;AN000; IF src_cp = tgt_cp
918 je done_cpsw
;AN000; THEN no action required;
919 ;-------------------------------------
920 ;- Set CP of target to that of source
921 ;-------------------------------------
922 mov cp_reset
,TRUE
;AN000; Set flag indicating change
923 mov ax,SetExtAttr
;AN000; Set Extended Attributes by Handle
924 mov bx,STDOUT
;AN000; For Standard output device
925 mov di,offset cp_list
;AC001; Input buffer address
929 pop ds ;AN001; Restore DS register
930 pop es ;AN000; Restore ES register
932 match_codepages endp
;AN000;
935 ;************************************************************
937 ;* SUBROUTINE NAME: prt_sort
939 ;* SUBROUTINE FUNCTION:
940 ;* Preceeds all error messages with "SORT: ".
942 ;* INTERNAL REFERENCES:
944 ;* EXTERNAL REFERENCES:
946 ;************************************************************
947 prt_sort proc
near ;AN003;
952 mov ax,Msg_sort
;AN003;
953 xor cx,cx ;AN004; ;AN003;
954 mov bx,STDERR
;AN003;
955 call display_msg
;AN003;
961 prt_sort endp
;AN003;
965 ;--------------------
972 ;--------------------
982 CONST
SEGMENT PUBLIC BYTE
991 SUBTTL Initialized
Data
992 ;-------------------------------
994 ;-------------------------------
996 db (362 - 80h
) + 96 dup (0) ;(362 - 80h) == New - Old IBM
997 ;interrupt reqs. == size of growth