summaryrefslogtreecommitdiff
path: root/v2.0/source/SORT.ASM
diff options
context:
space:
mode:
Diffstat (limited to 'v2.0/source/SORT.ASM')
-rw-r--r--v2.0/source/SORT.ASM420
1 files changed, 420 insertions, 0 deletions
diff --git a/v2.0/source/SORT.ASM b/v2.0/source/SORT.ASM
new file mode 100644
index 0000000..a4f39e8
--- /dev/null
+++ b/v2.0/source/SORT.ASM
@@ -0,0 +1,420 @@
1TITLE SORT FILTER FOR MS-DOS
2;
3; Sort /R /+n
4; /R -> reverse sort
5; /+n -> sort on column n
6;
7; Written by: Chris Peters
8;
9; Modification History:
10; 3-18-83 MZ Fix CR-LF at end of buffer
11; Fix small file sorting
12; Fix CR-LF line termination bug
13; Comment the Damn source
14;
15FALSE EQU 0
16TRUE EQU NOT FALSE
17
18;NOTE: "internat" must be false if KANJI version
19internat equ true
20;NOTE: see above
21
22.xlist
23.xcref
24 INCLUDE DOSSYM.ASM
25.cref
26.list
27
28sys MACRO name ; system call macro
29 MOV AH,name
30 INT 21h
31 ENDM
32save MACRO reglist ; push those registers
33IRP reg,<reglist>
34 PUSH reg
35ENDM
36ENDM
37restore MACRO reglist ; pop those registers
38IRP reg,<reglist>
39 POP reg
40ENDM
41ENDM
42
43MAXREC EQU 256 ; MAXIMUM NUL RECORD SIZE
44
45SPACE EQU 0 ; Offset zero in the allocated block
46BUFFER EQU MAXREC ; Offset MAXREC in the allocated block
47
48SUBTTL Segments used in load order
49
50
51CODE SEGMENT
52CODE ENDS
53
54CONST SEGMENT PUBLIC BYTE
55CONST ENDS
56
57CSTACK SEGMENT STACK
58 DB 128 DUP (0) ; initial stack to be clear
59CSTACK ENDS
60
61DG GROUP CODE,CONST,CSTACK
62
63CODE SEGMENT
64ASSUME CS:DG,DS:NOTHING,ES:NOTHING,SS:CSTACK
65
66COLUMN DW 0 ; COLUMN TO USE FOR KEY + 1
67SWITCH DB '/'
68
69SORT:
70;
71; check for proper version number of system
72;
73 sys GET_VERSION
74 XCHG AH,AL ; Turn it around to AH.AL
75 CMP AX,200H ; Version 2.00 only
76 JAE OKDOS ; Success
77 MOV DX,OFFSET DG:BADVER ; Get error message
78 PUSH CS ; Get DS addressability
79 POP DS
80 sys STD_CON_STRING_OUTPUT ; Send to STDOUT
81 PUSH ES ; long segment
82 PUSH COLUMN ; offset zero
83LONG_RET PROC FAR
84 RET ; long return to OS
85LONG_RET ENDP
86;
87; get proper switch character
88;
89OKDOS:
90 MOV AL,0 ; Get current switch character
91 sys CHAR_OPER
92 MOV SWITCH,DL
93;
94; parse command line
95;
96 MOV SI,80H ; pointer to command line
97 CLD ; go left to right
98 XOR CX,CX
99 LODSB
100 MOV CL,AL ; CX = length of command line
101SWITCH_LOOP:
102 CALL GET_CHAR ; get a character
103 CMP AL,SWITCH ; beginning of switch?
104 JNZ SWITCH_LOOP ; No, get next character
105 CALL GET_CHAR ; get 1st char of switch
106 CMP AL,'+' ; Column to sort?
107 JZ SWITCH_NUMBER ; Yes, parse a number
108 OR AL,20h ; convert to lower case
109 CMP AL,'r' ; Reverse sort?
110 JNZ SWITCH_LOOP ; No, get next switch
111 MOV CS:CODE_PATCH,72h ; sleaze JAE into JB
112 JMP SWITCH_LOOP ; get next switch
113SWITCH_NUMBER:
114 MOV COLUMN,0 ; start off at 0
115SWITCH_NEXT_NUMBER:
116 CALL GET_CHAR ; get supposed digit
117 SUB AL,'0' ; convert to number
118 JB SWITCH_LOOP ; less than '0'
119 CMP AL,9 ; is it a valid digit?
120 JA SWITCH_LOOP ; nope, get next switch
121 CBW ; make it a full word
122 MOV BX,AX ; save byte away
123 MOV AX,10 ; decimal number system
124 MUL COLUMN ; take previous result
125 ADD AX,BX ; add in low order digit
126 MOV COLUMN,AX ; save away value
127 JMP SWITCH_NEXT_NUMBER ; get next character
128GET_CHAR:
129 JCXZ END_GET ; End of line
130 DEC CX ; dec char count
131 LODSB ; get the character
132 RET ; return
133END_GET:
134 POP AX ; nuke return on stack
135;
136; set up column for proper sort offset
137;
138END_SWITCH:
139 ADD COLUMN,2
140 CMP COLUMN,2
141 JZ GOT_COL
142 DEC COLUMN
143
144;
145; Get sorting area, no more than 64K
146;
147GOT_COL:
148 MOV BX,1000H ; 64K worth of paragraphs
149GET_MEM:
150 sys ALLOC ; allocate them from somewhere
151 JNC GOT_MEM ; if error, BX has amount free, try to get it
152 OR BX,BX ; but, is BX = 0?
153 JNZ GET_MEM ; nope, try to allocate it
154 JMP SIZERR ; complain
155
156GOT_MEM:
157 MOV DS,AX ; Point DS to buffer
158 MOV ES,AX ; and point ES to buffer
159 MOV CL,4 ; 2^4 bytes per paragraph
160 SHL BX,CL ; Find out how many bytes we have
161
162;
163; clear out temporary record area
164;
165 MOV CX,MAXREC/2 ; Size of temporary buffer (words)
166 MOV AX,' ' ; Character to fill with
167 MOV DI,SPACE ; Beginning of temp buffer
168 REP STOSW ; Blam.
169;
170; read in file from standard input
171;
172 MOV DX,BUFFER + 2 ; DX = place to begin reading
173 MOV CX,BX ; CX is the max number to read
174 SUB CX,MAXREC + 2 ; remember offset of temp buffer
175SORTL:
176 XOR BX,BX ; Standard input
177 sys READ ; Read it in
178 ADD DX,AX ; Bump pointer by count read
179 SUB CX,AX ; subtract from remaining the count read
180 JZ SIZERR ; if buffer is full then error
181 OR AX,AX ; no chars read -> end of file
182 JNZ SORTL ; there were chars read. go read again
183 JMP SHORT SIZOK ; trim last ^Z terminated record
184SIZERR:
185 MOV SI,OFFSET DG:ERRMSG ; not enough memory error
186ERROR_EXIT:
187 PUSH CS ; DS addressability
188 POP DS
189 LODSW ; get length
190 MOV CX,AX ; put into appropriate register
191 MOV DX,SI ; get output destination
192 MOV BX,2 ; output to standard error
193 sys WRITE ; and write it out
194 MOV AL,1 ; return an error code
195 sys EXIT
196
197;
198; Look for a ^Z. Terminate buffer at 1st ^Z.
199;
200SIZOK:
201 MOV BX,DX ; save end pointer
202 MOV CX,DX ; get pointer to end of text
203 SUB CX,BUFFER+2 ; dif in pointers is count
204 MOV AL,1AH ; char is ^Z
205 MOV DI,BUFFER+2 ; point to beginning of text
206 REPNZ SCASB ; find one
207 JNZ NoBack ; nope, try to find CRLF
208 DEC BX ; pretend that we didn't see ^Z
209NoBack:
210 SUB BX,CX ; sub from endpointer the number left
211 SUB BX,2 ; Hope for a CR LF at end
212 CMP WORD PTR [BX],0A0Dh ; Was there one there?
213 JZ GOTEND ; yep, here is the end
214 ADD BX,2 ; nope, bump back to SCASB spot
215 CMP BYTE PTR [BX],AL ; Was there ^Z there?
216 JZ GOTEND ; yep, chop it
217 INC BX ; Nope, skip last char
218GOTEND:
219 MOV BP,BX ; BP = filesize-2(CRLF)+temp buffer+2
220 MOV WORD PTR DS:[BP],0 ; 0 at end of the file
221;
222; We now turn the entire buffer into a linked list of chains by
223; replacing CRLFs with the length of the following line (with 2 for CRLF)
224;
225 MOV BX,BUFFER ; pointer to line head (length)
226 MOV DI,BUFFER+2 ; pointer to line text
227REPLACE_LOOP:
228 MOV AL,13 ; char to look for is CR
229 MOV CX,BP ; count = end pointer
230 SUB CX,DI ; chop off start point to get length
231 INC CX ; add 1???
232REPLACE_SCAN:
233 REPNZ SCASB ; look for CR
234 JNZ REPLACE_SKIP ; count exhausted
235 CMP BYTE PTR [DI],10 ; LF there?
236 JNZ REPLACE_SCAN ; nope, continue scanning
237REPLACE_SKIP:
238 MOV AX,DI ; AX to point after CR
239 DEC AX ; AX to point to CR
240 save <AX> ; save pointer
241 SUB AX,BX ; AX is length of line found
242 MOV [BX],AX ; stuff it in previous link
243 restore <BX> ; get pointer to next
244 INC DI ; skip LF???
245 JCXZ END_REPLACE_LOOP ; no more to scan -> go sort
246 JMP REPLACE_LOOP ; look for next
247
248END_REPLACE_LOOP:
249 MOV WORD PTR [BX],0 ; terminate file with nul
250 LEA BP,[BX+2] ; remember the null line at end
251 MOV DI,BUFFER ; DI is start of unsorted section
252
253;
254; begin sort. Outer loop steps over all unsorted lines
255;
256OUTER_SORT_LOOP:
257 MOV BX,DI ; BX is start of unsorted section
258 MOV SI,BX ; SI is scanning place link
259 CMP WORD PTR [BX],0 ; are we at the end of the buffer?
260 JNZ INNER_SORT_LOOP ; No, do inner process
261 JMP END_OUTER_SORT_LOOP ; yes, go dump out
262
263;
264; BX points to best guy found so far. We scan through the sorted section
265; to find an appropriate insertion point
266;
267INNER_SORT_LOOP:
268 ADD SI,[SI] ; link to next fellow
269 MOV AX,[SI] ; get length of comparison guy
270 OR AX,AX ; test for end of buffer
271 JZ END_INNER_SORT_LOOP ; if zero then figure out insertion
272 save <SI,DI> ; save SI,DI
273 MOV DI,BX ; DI = pointer to tester link
274 SUB AX,COLUMN ; adjust length for column
275 JA AXOK ; more chars in tester than column?
276 MOV SI,SPACE ; point SI to blank area
277 MOV AX,MAXREC ; make AX be max length
278AXOK:
279 MOV DX,[DI] ; get length of best guy
280 SUB DX,COLUMN ; adjust length for column
281 JA DXOK ; there are more chars after column
282 MOV DI,SPACE ; point air to a space
283 MOV DX,MAXREC ; really big record
284DXOK:
285 MOV CX,AX ; AX is shortest record
286 CMP AX,DX ; perhaps DX is shorter
287 JB SMALL ; nope, leace CX alone
288 MOV CX,DX ; DX is shorter, put length in CX
289SMALL:
290 ADD DI,COLUMN ; offset into record
291 ADD SI,COLUMN ; offset into other record
292if not internat
293 REPZ CMPSB ; compare every one
294 endif
295if internat
296 push bx
297 push ax
298 mov bx,offset dg:table
299tloop: lodsb
300 xlat byte ptr cs:[bx]
301 mov ah,al
302 mov al,es:[di]
303 inc di
304 xlat byte ptr cs:[bx]
305 cmp ah,al
306 loopz tloop
307 pop ax
308 pop bx
309 endif
310 restore <DI,SI> ; get head pointers back
311 JNZ TESTED_NOT_EQUAL ; didn't exhaust counter, conditions set
312 CMP AX,DX ; check string lengths
313TESTED_NOT_EQUAL:
314;
315; note! jae is patched to a jbe if file is to be sorted in reverse!
316;
317CODE_PATCH LABEL BYTE
318 JAE INNER_SORT_LOOP ; if this one wasn't better then go again
319 MOV BX,SI ; it was better, save header
320 JMP INNER_SORT_LOOP ; and scan again
321
322END_INNER_SORT_LOOP:
323 MOV SI,BX ; SI is now the best person
324 CMP SI,DI ; check best for current
325 JZ END_INSERT ; best equals current, all done
326
327;
328; SI points to best line found so far
329; DI points to a place to insert this line
330; DI is guaranteed to be < SI
331; make room for line at destination
332;
333 MOV DX,[SI] ; get length of line
334 save <SI,DI> ; save positions of people
335 STD ; go right to left
336 MOV CX,BP ; get end of file pointer
337 SUB CX,DI ; get length from destination to end
338 MOV SI,BP ; start from end
339 DEC SI ; SI points to end of file
340 MOV DI,SI ; destination is end of file
341 ADD DI,DX ; DI points to new end of file
342 REP MOVSB ; blam. Move every one up
343 CLD ; back left to right
344 restore <DI,SI> ; get old source and destination
345;
346; MOVE NEW LINE INTO PLACE
347;
348 save <DI> ; save destination
349 ADD SI,DX ; adjust for previous movement
350 save <SI> ; save this value
351 MOV CX,DX ; get number to move
352 REP MOVSB ; blam. move the new line in
353 restore <SI,DI> ; get back destination and new source
354;
355; DELETE LINE FROM OLD PLACE
356;
357 save <DI> ; save destination
358 MOV CX,BP ; pointer to end
359 ADD CX,DX ; remember bump
360 SUB CX,SI ; get count of bytes to move
361 INC CX ; turn it into a word
362 SHR CX,1 ; or a count of words
363 MOV DI,SI ; new destination of move
364 ADD SI,DX ; offset of block
365 REP MOVSW ; blam, squeeze out the space
366 restore <DI> ; get back original destination
367 MOV WORD PTR DS:[BP-2],0 ; remake the end of file mark
368
369END_INSERT:
370 ADD DI,[DI] ; link to next guy
371 JMP OUTER_SORT_LOOP ; and continue
372;
373; PUT BACK IN THE CR-LF
374;
375END_OUTER_SORT_LOOP:
376 MOV DI,BUFFER ; start at beginning (where else)
377 MOV CX,[DI] ; count of butes
378
379INSERT_LOOP:
380 ADD DI,CX ; point to next length
381 MOV CX,[DI] ; get length
382 MOV WORD PTR [DI],0A0DH ; replace length with CRLF
383 CMP CX,0 ; check for end of file
384 JNZ INSERT_LOOP ; nope, try again
385
386WRITE_FILE:
387 MOV DX,BUFFER+2 ; get starting point
388 MOV CX,BP ; pointer to end of buffer
389 SUB CX,DX ; dif in pointers is number of bytes
390 MOV BX,1 ; to standard output
391 sys WRITE ; write 'em out
392 JC BADWRT ; some bizarre error -> flag it
393 CMP AX,CX ; did we write what was expected?
394 JZ WRTOK ; yes, say bye bye
395BADWRT:
396 MOV SI,OFFSET dg:ERRMSG2 ; strange write error
397 JMP ERROR_EXIT ; bye bye
398WRTOK:
399 XOR AL,AL ; perfect return (by convention)
400 sys EXIT ; bye!
401
402CODE ENDS
403
404CONST SEGMENT PUBLIC BYTE
405 EXTRN BADVER:BYTE,ERRMSG:BYTE,ERRMSG2:BYTE
406if internat
407 extrn table:byte
408 endif
409CONST ENDS
410
411SUBTTL Initialized Data
412PAGE
413CSTACK SEGMENT STACK
414 DB 96 dup (0)
415CSTACK ENDS
416
417 END SORT
418
419
420 \ No newline at end of file