summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/SORT/SORT.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v4.0/src/CMD/SORT/SORT.ASM')
-rw-r--r--v4.0/src/CMD/SORT/SORT.ASM1000
1 files changed, 1000 insertions, 0 deletions
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 @@
1TITLE SORT FILTER FOR DOS
2 PAGE ,132 ;
3;**********************************************************
4;*
5;* UTILITY NAME: sort
6;*
7;* SOURCE FILE NAME: sort.asm
8;*
9;* UTILITY FUNCTION:
10;*
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
15;* redirected.
16;*
17;* INPUT (Command line)
18;*
19;* SORT [/R] [/+ n]
20;*
21;* /R - Sort in reverse order
22;* /+n - Start sorting in column "n" , default 1
23;*
24;* OUTPUT:
25;* Sorted data will be written to the standard output device.
26;*
27;* ERROR CONDITIONS:
28;* Incorrect DOS version
29;* Insufficient disk space on target
30;* Insufficient memory to allocate SORT buffer
31;* Invalid parameter
32;*
33;* INTERNAL REFERENCES:
34;* Main
35;*
36;* SOURCE HISTORY:
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
43;*
44;* 6-23-86 RW (IBM)
45;* Add DOS 3.30 support for multiple languages
46;* Inclusion of common DOS VERSION check equate
47;*
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
53;*
54;* ;AN001; Code added in DOS 4.0
55;* ;AN002; DCR 191
56;* 9-18-87 BL (IBM) (DOS 4.0)
57;* Added Extended Attribute support for code page checking
58;* and file type checking.
59;* ;AN003; PTM 1805
60;* 10-19-87 BL (IBM) (DOS 4.0)
61;*
62;* ;AN004; PTM
63;* 01-29-87 BL (IBM) (DOS 4.0)
64;* Ran tool INSPECT on .lst file for optimizations
65;**********************************************************
66
67 PAGE ;
68;-------------------------
69;--- Macro definitions
70;-------------------------
71BREAK MACRO subtitle
72 SUBTTL subtitle
73 PAGE
74ENDM
75
76
77
78sys MACRO name ;system call macro
79 MOV AH,name
80 INT 21h
81 ENDM
82
83
84
85save MACRO reglist ;push those registers
86IRP reg,<reglist>
87 PUSH reg
88ENDM
89ENDM
90
91
92
93restore MACRO reglist ;pop those registers
94IRP reg,<reglist>
95 POP reg
96ENDM
97ENDM
98
99
100 PAGE ;
101;-------------------------------
102;--- Equates
103;-------------------------------
104FALSE EQU 0
105TRUE EQU NOT FALSE
106MAXREC EQU 256 ;MAXIMUM NUL RECORD SIZE
107
108SPACE EQU 0 ;Offset zero in the allocated block
109BUFFER EQU MAXREC ;Offset MAXREC in the allocated block
110
111RETCODE_NOERROR equ 0 ;AN000; DOS return code (errorlevel)
112RETCODE_ERROR equ 1 ;AN000; DOS return code (errorlevel)
113
114NO_CODEPAGE equ 0 ;AN000; Tag for files with no codepage
115
116GetCPSW equ 3303h ;AN000; Int 021h function calls
117GetExtAttr equ 5702h ;AN000;
118SetExtAttr equ 5704h ;AN000;
119;-----------------------
120;-- Parser equates
121;-----------------------
122EOL EQU -1 ;AN000; Indicator for End-Of-Line
123NOERROR EQU 0 ;AN000; Return Indicator for No Errors
124
125FarSW equ 0 ;AN000;
126DateSW equ 0 ;AN000;
127TimeSW equ 0 ;AN000;
128FileSW equ 0 ;AN000;
129CAPSW equ 0 ;AN000;
130CmpxSW equ 0 ;AN000;
131NumSW equ 1 ;AN000;
132KeySW equ 0 ;AN000;
133SwSW equ 1 ;AN000;
134Val1SW equ 1 ;AN000;
135Val2SW equ 0 ;AN000;
136Val3SW equ 0 ;AN000;
137DrvSW equ 0 ;AN000;
138QusSW equ 0 ;AN000;
139
140;-----------------------
141;-- Message equates
142;-----------------------
143STDIN equ 0
144STDOUT equ 1
145STDERR equ 2
146
147Msg_NoMem equ 2 ;AC003;
148Msg_NoDisk equ 4 ;AC003;
149Msg_sort equ 5 ;AN003;
150Msg_switch equ 3 ;AN003;
151
152;------------------------------
153; EXTENDED ATTRIBUTE Equates
154;------------------------------
155EAISBINARY equ 02h ;AN001; ea_type
156EASYSTEM equ 8000h ;AN001; ea_flags
157
158 PAGE ;
159;---------------------;
160.xlist ;
161.xcref ;
162INCLUDE syscall.inc ;
163INCLUDE sysmsg.inc ; ;AN000; Include message equates and MACROS
164.cref ;
165.list ;
166;---------------------;
167
168MSG_UTILNAME <SORT> ;AN000;
169
170SUBTTL Segments used in load order
171
172
173CODE SEGMENT
174CODE ENDS
175
176CONST SEGMENT PUBLIC BYTE
177CONST ENDS
178
179
180;-----------------------
181;--- Stack Segment
182;-----------------------
183CSTACK SEGMENT STACK
184 db 128 DUP (0) ;initial stack to be clear
185
186CSTACK ENDS
187
188
189
190;-------------------------------
191;--- Group
192;-------------------------------
193DG GROUP CODE,CONST,CSTACK
194
195
196;-------------------------------
197;--- Code Segment
198;-------------------------------
199CODE SEGMENT
200ASSUME CS:DG,DS:DG,ES:NOTHING,SS:CSTACK
201
202;-------------------------------
203;--- Data Definition
204;-------------------------------
205COLUMN dw 0 ;COLUMN TO USE FOR KEY + 1
206cp_reset db FALSE ;AN000;Flag indicating if Code Page was reset on target file
207
208;------------------------------------------DOS 3.30 - Russ Whitehead
209CTRY_INFO db ?
210CTRY_TABLE_OFF dw ?
211CTRY_TABLE_SEG dw ?
212;------------------------------------------
213
214MSG_SERVICES <MSGDATA> ;AN000;
215ASSUME ds:nothing
216
217;----------------------------------------
218;- STRUCTURE TO QUERY EXTENDED ATTRIBUTES
219;----------------------------------------
220querylist struc ;AN001; ;query general list
221qea_num dw 1 ;AN001;
222qea_type db EAISBINARY ;AN001;
223qea_flags dw EASYSTEM ;AN001;
224qea_namelen db ? ;AN001;
225qea_name db " " ;AN001;
226querylist ends ;AN001;
227
228cp_qlist querylist <1,EAISBINARY,EASYSTEM,2,"CP"> ;AN001; ;query code page attr.
229
230cp_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
238cp dw ? ;AN001; ; ea value (code page)
239cp_len equ ($ - cp_list) ;AN001;
240
241;-------Save area for Code Pages
242src_cp dw ? ;AN000; Save area for current code page
243tgt_cp dw ? ;AN000; Save area for current code page
244endlist label word ;AN000;
245
246 PAGE ;
247;******************************************************************************
248;* PARSER DATA STRUCTURES FOLLOW
249;******************************************************************************
250
251;------------------------------
252;- STRUCTURE TO DEFINE ADDITIONAL COMMAND LINE DELIMITERS
253;------------------------------
254parms 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
259
260;------------------------------
261;- STRUCTURE TO DEFINE SORT SYNTAX REQUIREMENTS
262;------------------------------
263parmsx 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
269
270;------------------------------
271;- STRUCTURE TO DEFINE THE /R SWITCH
272;------------------------------
273sw1 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
279rev_sw db "/R",0 ;AN000; /R INDICATES REVERSE SORT
280
281;------------------------------
282;- STRUCTURE TO DEFINE THE /+n SWITCH
283;------------------------------
284NUMERIC equ 08000h ;AN000; Control flag for numeric value
285NO_COLON equ 0020h ;AN000;
286
287sw2 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
293col_sw db "/+",0 ;AN000; /+n INDICATES BEGIN SORT IN COLUMN n
294
295;------------------------------
296;- VALUE LIST DEFINITION FOR NO VALUES
297;------------------------------
298novals label word ;AN000;
299 DB 0 ;AN000; VALUE LIST
300
301;------------------------------
302;- VALUE LIST DEFINITION FOR /+n
303;------------------------------
304valuelist 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
309
310;------------------------------
311;- RETURN BUFFER FOR SWITCH INFORMATION
312;------------------------------
313switchbuff label word ;AN000;
314sb_type db ? ;AN000; TYPE RETURNED
315sb_item_tag db ? ;AN000; SPACE FOR ITEM TAG
316sb_synonym dw ? ;AN000; ES:sb_synonym points to synonym
317
318sb_value dw ? ;AN000; SPACE FOR VALUE
319sb_value_extra dw ? ;AN000; UNUSED SPACE FOR VALUE
320
321 PAGE ;
322;**************************************************************
323;*
324;* SUBROUTINE NAME: main
325;*
326;* SUBROUTINE FUNCTION:
327;* Mainline routine, performs SYSLODMSG, calls routines to
328;* parse command line, performs the SORT and writes the
329;* results.
330;*
331;* INPUT:
332;* Command Line.
333;*
334;* File to be sorted will be read from Standard Input
335;* device handle 0.
336;*
337;* OUTPUT:
338;* Sorted data will be written to the Standard Output
339;* device handle 1.
340;*
341;* NORMAL EXIT:
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.
345;*
346;* ERROR EXIT:
347;* If any of the following errors, SORT will display the
348;* corresponding error message and terminate.
349;*
350;* Insufficient disk space on target device
351;* Incorrect DOS version
352;* Insufficient memory to sort
353;*
354;************************************************************
355
356;-------------------------
357; Preload messages
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
361
362 mov ax,cs ;AN003; ;load ES to the right area,
363 mov es,ax ;AN003;
364 mov ds,ax ;AN003;
365SORT:
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
373
374 mov ah,Exit ;AN000; No, terminate new way
375 mov al,0 ;AN000; Errorlevel 0 (Compatible!)
376 int 021h ;AN000; Bye bye!
377
378OLD_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;-----------------------------------
384PARSER: ;AN000; message and terminate
385 call parse ;AN000; Parse command line
386
387;-----------------------------------
388; set up column for proper sort offset
389;-----------------------------------
390
391 ADD COLUMN,2
392 CMP COLUMN,2
393 JZ GOT_COL
394 DEC COLUMN
395
396;------------------------------------
397; Get sorting area, no more than 64K
398;------------------------------------
399GOT_COL:
400 MOV BX,1000H ;64K worth of paragraphs
401GET_MEM:
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
408
409GOT_MEM:
410;------------------------------------RussW:--Following add in DOS 3.3 for Nat Lang Support
411 push ax ;Save AX
412 push ds ;Save DS
413 push es ;Save ES
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
419 pop es ;in ES
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
424 mov di,seg dg
425 mov es,di
426 mov di,offset dg:table
427 mov cx,word ptr [si]
428 add si,2
429 mov ax,256
430 sub ax,cx
431 add di,ax
432 cld
433 rep movsb
434 ;Done copying, so restore regs and cont
435 pop es ;Restore ES
436 pop ds ;Restore DS
437 pop ax ;Restore AX
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
445
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
452 REP STOSW ;Blam.
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
463SORTL:
464 XOR BX,BX ;Standard input
465 sys READ ;Read it in
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
472SIZERR:
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
476
477;---------------------------
478; Look for a ^Z. Terminate buffer at 1st ^Z.
479;---------------------------
480SIZOK:
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,1AH ;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
489NoBack:
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
498GOTEND:
499 MOV BP,BX ;BP = filesize-2(CRLF)+temp buffer+2
500 MOV WORD PTR DS:[BP],0 ;0 at end of the file
501
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
508REPLACE_LOOP:
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
512 INC CX ;add 1???
513REPLACE_SCAN:
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
518REPLACE_SKIP:
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
525 INC DI ;skip LF???
526 JCXZ END_REPLACE_LOOP ;no more to scan -> go sort
527 JMP REPLACE_LOOP ;look for next
528
529END_REPLACE_LOOP:
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
533
534;---------------------------
535; begin sort. Outer loop steps over all unsorted lines
536;---------------------------
537OUTER_SORT_LOOP:
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
543
544;---------------------------
545; BX points to best guy found so far. We scan through the sorted section
546; to find an appropriate insertion point
547;---------------------------
548INNER_SORT_LOOP:
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
559AXOK:
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
565DXOK:
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
570SMALL:
571 ADD DI,COLUMN ;offset into record
572 ADD SI,COLUMN ;offset into other record
573 push bx
574 push ax
575 mov bx,offset dg:table
576tloop: lodsb
577 xlat byte ptr cs:[bx]
578 mov ah,al
579 mov al,es:[di]
580 inc di
581 xlat byte ptr cs:[bx]
582 cmp ah,al
583 loopz tloop
584 pop ax
585 pop 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
589TESTED_NOT_EQUAL:
590
591;---------------------------
592; NOTE! jae is patched to a jbe if file is to be sorted in reverse!
593;---------------------------
594CODE_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
598
599END_INNER_SORT_LOOP:
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
603
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
645
646END_INSERT:
647 ADD DI,[DI] ;link to next guy
648 JMP OUTER_SORT_LOOP ;and continue
649;------------------------------
650; PUT BACK IN THE CR-LF
651;------------------------------
652END_OUTER_SORT_LOOP:
653 MOV DI,BUFFER ;start at beginning (where else)
654 MOV CX,[DI] ;count of butes
655
656INSERT_LOOP:
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
662
663WRITE_FILE:
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
672BADWRT:
673
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)
678 sys EXIT ;AN000;
679WRTOK:
680 MOV AL,RETCODE_NOERROR ;AN000; Errorlevel 0 (No error!)
681 sys EXIT ;bye!
682
683 PAGE ;
684;************************************************************
685;*
686;* SUBROUTINE NAME: display_msg
687;*
688;* SUBROUTINE FUNCTION:
689;* Display the requested message to the specified handle
690;*
691;* INPUT:
692;* 1) AX = Number of the message to be displayed.
693;* 2) BX = Handle to be written to.
694;*
695;* OUTPUT:
696;* The message corresponding to the requested msg number will
697;* be written to the requested handle. There is no substitution
698;* text in SORT.
699;*
700;* NORMAL EXIT:
701;* Message will be successfully written to requested handle.
702;*
703;* ERROR EXIT:
704;* None. Note that theoretically an error can be returned from
705;* SYSDISPMSG, but there is nothing that the application can do.
706;*
707;* INTERNAL REFERENCES:
708;* System Display Message service routines
709;*
710;* EXTERNAL REFERENCES:
711;* None
712;*
713;************************************************************
714
715display_msg proc near ;AN000;
716 push ds ;AN000; save DS value
717 push cs ;AN000; get DS addressability
718 pop ds ;AN000;
719
720 xor cx,cx ;AN004; ;AN000; No substitution text
721;; mov dh,-1 ;AN003; Message class
722 ; 1=DOS Extended error
723 ; 2=DOS Parse error
724 ; -1=Utility message
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;
730
731 pop ds ;AN000; restore DS
732 ret ;AN000;
733display_msg ENDP ;AN000;
734
735 PAGE ;
736;************************************************************
737;*
738;* SUBROUTINE NAME: parse
739;*
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.
745;*
746;* INPUT: None
747;*
748;* OUTPUT: None
749;*
750;* NORMAL EXIT:
751;*
752;* If /R specified, then patches code to perform reverse sort
753;* by changing JAE to a JB.
754;*
755;* If /+n entered, COLUMN will be set to "n," otherwise COLUMN
756;* will be set to 1.
757;*
758;* ERROR EXIT:
759;*
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
763;* errorlevel 1.
764;*
765;* EXTERNAL REFERENCES:
766;* System parse service routines
767;* INT21 - GET PSP Function Call 062h
768;*
769;************************************************************
770
771parse proc near ;AN000;
772
773 sys GetCurrentPSP ;AN000; Get PSP address, returned in BX
774
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
781 pop es ;AN000; in ES
782;---------------------------------
783;- Loop for each operand at DS:SI (Initially PSP + 081h)
784;---------------------------------
785parse_loop: ;AN000;
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
801
802;---------------------------------------------
803;- If user said /+n, then save COLUMN index
804;---------------------------------------------
805check_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
811
812;------------------------------------------------------------
813;- If any other parameter specified, display message and die
814;------------------------------------------------------------
815switch_error: ;AN003;
816 mov ax,Msg_switch ;AN003;
817parse_error: ;AN000;
818 mov dh,2 ;AN003; class: parse error
819 call error_exit ;AN000; Terminate utility
820
821end_parse: ;AN000;
822 ret ;AN000;
823parse endp ;AN000;
824
825 PAGE ;
826;************************************************************
827;*
828;* SUBROUTINE NAME: error_exit
829;*
830;* SUBROUTINE FUNCTION:
831;* Displays the message number in AX to the standard
832;* error device, then terminates with errorlevel 1.
833;*
834;* INPUT: AX = Message number
835;*
836;* INTERNAL REFERENCES:
837;* display_msg
838;*
839;* EXTERNAL REFERENCES:
840;* INT 021h - Terminate Function 043h
841;*
842;************************************************************
843error_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)
849 sys EXIT ;AN000;
850 ret ;AN000; Meaningless RET
851error_exit endp ;AN000;
852
853
854;************************************************************
855;*
856;* SUBROUTINE NAME: match_codepages
857;*
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.
864;*
865;* INTERNAL REFERENCES:
866;* none
867;*
868;* EXTERNAL REFERENCES:
869;* INT 021h - Check CPSW
870;* INT 021h - Get Extended Attributes by Handle
871;* INT 021h - Set Extended Attributes by Handle
872;*
873;************************************************************
874
875match_codepages proc near ;AN000;
876
877;-----------------------------------
878; Check status of Code page support
879;-----------------------------------
880 push es ;AN000; Save ES register
881 push ds ;AN001; Save DS register
882;
883 mov ax,cs ;AN001; ES, DS -> CS
884 mov ds,ax ;AN001;
885 mov es,ax ;AN001;
886;
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
899 int 021h ;AN000;
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
903
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
909 int 021h ;AN000;
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
913
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
926 int 021h ;AN000;
927
928done_cpsw: ;AN000;
929 pop ds ;AN001; Restore DS register
930 pop es ;AN000; Restore ES register
931 ret ;AN000;
932match_codepages endp ;AN000;
933
934 PAGE ;
935;************************************************************
936;*
937;* SUBROUTINE NAME: prt_sort
938;*
939;* SUBROUTINE FUNCTION:
940;* Preceeds all error messages with "SORT: ".
941;*
942;* INTERNAL REFERENCES:
943;* none
944;* EXTERNAL REFERENCES:
945;* none
946;************************************************************
947prt_sort proc near ;AN003;
948 push ax ;AN003;
949 push dx ;AN003;
950;
951 mov dh,-1 ;AN003;
952 mov ax,Msg_sort ;AN003;
953 xor cx,cx ;AN004; ;AN003;
954 mov bx,STDERR ;AN003;
955 call display_msg ;AN003;
956;
957 pop dx ;AN003;
958 pop ax ;AN003;
959;
960 ret ;AN003;
961prt_sort endp ;AN003;
962
963
964 PAGE ;
965;--------------------
966.xlist
967.xcref
968INCLUDE parse.asm
969include msgdcl.inc
970.cref
971.list
972;--------------------
973
974CODE ENDS
975
976
977
978
979
980
981
982CONST SEGMENT PUBLIC BYTE
983
984 extrn table:byte
985
986CONST ENDS
987
988
989
990
991SUBTTL Initialized Data
992;-------------------------------
993;--- Stack Segment
994;-------------------------------
995CSTACK SEGMENT STACK
996 db (362 - 80h) + 96 dup (0) ;(362 - 80h) == New - Old IBM
997 ;interrupt reqs. == size of growth
998CSTACK ENDS
999
1000 END SORT