-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathTABS.ASM
517 lines (439 loc) · 10.6 KB
/
TABS.ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
Title TABS - Align ASCII File
Page 82,132
Comment | Version 1.2, April 27, 1984
TABS Command
-----------------
Purpose: Replace blanks with TAB character(s).
Format: TABS d:input.ext d:output.ext
Remarks: Any TAB characters found are first expanded. Thus, if TABS
appear within quoted strings - out of context - they will
be expanded incorrectly.
In replacing blanks with tabs, quoted strings are ignored.
The maximum logical record size is 255, see MAXREC equate.
Defacto tab columns are 9,17,25,...
V. Buerg, March, 1984. For public domain use.
----------------- |
Cseg Segment Public Para 'CODE'
Assume CS:Cseg,DS:Cseg,ES:Nothing
Tabs Proc Far
Push DS ;DOS convention
Sub AX,AX
Push AX
Mov CS:Stk_Top,SP ;Save stack ptr to insure return
Mov AH,30h
Int 21h ;Verify DOS 2.0 or later
Mov DX,Offset Sorry
Cmp AL,2
Jb Error
Call GetFile ;Get file names
Call OpenIn ;Open input
Call OpenOut ;Open output
Call Inform ;Display "cooking" message
Call GenTab ;Generate tabs
Call Flush ;Empty the output buffer
Mov DX,Offset EofMsg ;Say END-OF-FILE
Error: Mov SP,Stk_Top ;Insure proper return
Mov AH,9 ;Print any message
Int 21h
Call Close ;Close files
Ret ;Return to DOS
Page
Buflen Equ 16*1024 ;I/O buffer size
Maxrec Equ 255 ;Longest logical record
S_Quote Equ 34 ;Single quote
D_Quote Equ 39 ;Double quote
Tab Equ 9
Lf Equ 10
Cr Equ 13
Eof Equ 1Ah
Rec Db Maxrec Dup (0) ;Current record
Rlen Dw 0 ;Current record length
Sw Db 0 ;Number of blanks skipped
Qsw Db 0 ;Quote switch
Stk_Top Dw 0 ;SP at entry
MsgIn Db Cr,Lf,'Enter INPUT file name> $'
Msg1 Db Cr,Lf,'Input failed to open>'
InKey Db 32,32 ;Keyboard buffer
Input Db 64 Dup (0),0,'$' ;Drive:path\name.ext
IHandle Dw 0 ;Input file handle
Ilen Dw 0 ;Input block length
Iptr Dw 0 ;Offset to next char
MsgOut Db Cr,Lf,'Enter OUTPUT file name> $'
Msg2 Db Cr,Lf,'Output failed to open>'
OutKey Db 32,32
Output Db 64 Dup (0),0,'$'
OHandle Dw 0 ;Output file handle
Olen Dw 0 ;Output block size
Optr Dw 0 ;Offset to next char
Sorry Db Cr,Lf,'Sorry, PC DOS Version 2 required',Cr,Lf,'$'
Msg3 Db Cr,Lf,'I/O error reading',Cr,Lf,'$'
Msg4 Db Cr,Lf,'I/O error writing',Cr,Lf,'$'
Cooking Db Cr,Lf,'TABBING: $'
Mark Db ' => $'
EofMsg Db Cr,Lf,'End of File',Cr,Lf,'$'
NewLine Db CR,LF,'-$'
Code2 Db 'File not found $'
Code3 Db 'Path not found $'
Code4 Db 'Too many files $'
Code5 Db 'Access denied $'
Page
; Replace blanks with tabs
GenTab Proc Near
Loop: Call GetRec ;Get a record
Mov CX,Rlen ; its length
Sub BX,BX ;Output column
Mov Sw,0 ;No blanks yet
Mov Qsw,0 ;No quotes yet
Or CX,CX ;Any data in record?
Jnz Set1
Jmp Null ; no, just CR-LF
Set1: Mov SI,Offset Rec ;Look for blanks and
Wloop: Lodsb ; replace strings of blanks
Inc BX ; with tab characters
Cmp AL,D_Quote ;Don't count blanks
Jne Chk1 ; within single or double
Xor Qsw,2 ; quoted strings
Jmp Chk2
Chk1: Cmp AL,S_Quote ;Insert TABs for any
Jne Chk3 ; blanks skipped before
Xor Qsw,1 ; a quote
Chk2: Cmp Sw,0 ;Must re-insert
Je Check ; any blanks skipped
Jmp Insert ; if not enough for a TAB
Chk3: Cmp AL,' ' ;Tis a blank?
; Jmp Check ;for DETAB
Jne Check ; no, see if eof
Test Qsw,3 ;Within quotes?
Jnz Check
Inc Sw
Test BL,07h ;Ready for a tab?
Jnz Tloop ; no, keep going
Mov AL,Tab ; yes, send one
Jmp Copy
Check: Cmp AL,Eof ;End of file?
Je Done ; yes, all done
; Jmp Copy ;for DETAB
Test Qsw,3 ;When a non-blank is
Jnz Copy ; encountered, insert a TAB
Cmp Sw,0 ; if there were blanks
Je Copy ; before it
Mov DX,BX
Dec DL
Test DL,07h ;If the non-blank is not
Jnz Insert ; in a TAB column, then
Push AX ; keeps all the blanks
Mov AL,Tab
Call PutChar
Pop AX
Jmp Copy
Insert: Push AX ;Insert any blanks that
Mov DL,Sw ; didn't line up on
Blanks: Cmp DL,1 ; a TAB column
Jb None
Mov AL,' '
Call PutChar
Dec DL ;Decr insert count
Jmp Blanks ; and continue
None: Pop AX ;Get char back
Copy: Call PutChar ; and write it
Mov Sw,0 ;Ind not blank
Tloop: Loop Wloop
Null: Mov AL,Cr ;Append CR
Call PutChar
Mov AL,Lf ; and LF
Call PutChar
Jmp Loop
Done: Ret
GenTab Endp
Page
; Build a logical record
GetRec Proc Near
Push DI
Sub DI,DI ;Target record offset
Mov Rlen,0 ; and length
Mov Qsw,0 ;Quote indicator
Get1: Call GetChar ;Build up a logical record
Cmp AL,Cr ; by looking for a CR or LF
Je Get1 ; as end-of-record
Cmp AL,Lf
Je Get7
Cmp AL,S_Quote ;Don't expand tabs
Jne Get2 ; found within a
Xor Qsw,1 ; quoted string
Get2: Cmp AL,D_Quote
Jne Get3
Xor Qsw,2
Get3: Cmp AL,Tab ;Is it TAB?
Jne Get5 ; no, pass it
Test Qsw,3 ;Within quotes?
Jnz Get5 ; yes, pass it
Get4: Mov Rec[DI],' ' ;Expand embedded tabs
Inc DI ; with blanks
Test DI,0007h
Jz Get1
Jmp Get4
Get5: Mov Rec[DI],AL ;Build the record by
Inc DI ; copying each character
Cmp DI,Maxrec ; or TABs expanded to blanks
Jae Get6
Cmp AL,Eof ;Is it EOF?
Je Get6 ; yes, all done
Jmp Get1 ; no, continue
Get6: Mov Rlen,DI ;Final record length
Pop DI
Ret
Get7: Cmp Rec-1[DI],' ' ;Strip trailing blanks
Jne Get6
Dec DI
Jz Get6
Jmp Get7
GetRec Endp
Page
; Extract one char from record
GetChar Proc Near ;Read char into AL
Push CX
Push SI
Read1: Cmp Ilen,0 ;Any in buffer?
Je Read ; no, read next block
Mov SI,Iptr ; yes, get offset in buf
Push DS
Mov AX,Seg InBuf ;Copy a char from the
Mov DS,AX ; input (segment) buffer
Lodsb
Pop DS
Mov Iptr,SI ;Offset for next one
Dec Ilen ;Decr buffer size left
Jmp Read4 ; and return with AL
Read: Mov BX,IHandle ;Read a block of data
Mov CX,BufLen ; into Input (segment) buffer
Sub DX,DX
Push DS
Mov AX,Seg InBuf
Mov DS,AX
Mov AH,3Fh
Int 21h
Pop DS
Mov Iptr,0 ;Reset buffer ptr
Mov Ilen,AX ; and length
Jc Read2
Or AX,AX ;Anything read?
Jnz Read1 ; yes, pick it up
Mov AL,Eof ; no, return EOF
Jmp Read4
Read2: Mov DX,Offset Msg3 ;Say I/O ERROR
Jmp Error
Read4: Pop SI
Pop CX
Ret
GetChar Endp
Page
; Block output records
PutChar Proc Near ;Write from AL
Push AX
Push BP
Push BX
Push CX
Push DI
Push DX
Mov DI,Optr ;Offset in buffer
Mov DX,Seg OutBuf
Push ES ;Get buffer segment
Mov ES,DX
Stosb ;Place into buffer
Pop ES
Inc Olen ;Incr the length
Mov Optr,DI ; and buffer ptr
Cmp Olen,Buflen ;Full block?
Jb Write2 ; no, return
Mov CX,Buflen ; yes,write it
Jmp Write3
Flush: Push AX ;Write data left over
Push BP ; in output buffer
Push BX
Push CX
Push DI
Push DX
Mov CX,Olen ;Any left in output?
Or CX,CX
Jz Write2
Write3: Mov BX,OHandle ;Get file handle
Mov BP,CX ;Save size requested
Sub DX,DX
Push DS ;Set up DS:DX
Mov AX,Seg OutBuf ; in buffer segment
Mov DS,AX
Mov AH,40h ;Write the block
Int 21h
Pop DS
Mov Optr,0 ;Reset buffer ptr
Mov Olen,0 ; and size used
Jc Writer ;Write OK?
Cmp BP,AX ;Wrote all data?
Je Write2 ; yes, good
Writer: Mov DX,Offset Msg4 ; no, say I/O error
Jmp Error
Write2: Pop DX
Pop DI
Pop CX
Pop BX
Pop BP
Pop AX
Ret
PutChar Endp
Page
; Open input file
OpenIn Proc Near
Mov DX,Offset Input
Mov AL,0 ;For input
Mov AH,3Dh ;Open a file
Int 21h
Jnc Openi
Mov DX,Offset Msg1
Jmp OpenErr
Openi: Mov IHandle,AX
Ret
OpenIn Endp
; Open output file
OpenOut Proc Near
Mov DX,Offset Output
Sub CX,CX ;Normal file attribute
Mov AH,3Ch ;Create a file
Int 21h
Jnc Openo
Mov DX,Offset Msg2
Jmp OpenErr
Openo: Mov OHandle,AX
Ret
OpenOut Endp
; Determine why OPEN failed
OpenErr:Cmp AL,2 ;AL has reason code
Jb Opene
Cmp AL,5
Ja Opene
Sub BX,BX ;Get offset to reason
Mov BL,AL ; text for open failure
Mov CL,4
Shl BX,CL
Mov AH,9 ;Say OPEN FAILED
Int 21h
Mov DX,Offset NewLine
Mov AH,9
Int 21h
Lea DX,Code2-32[BX]
Opene: Jmp Error
; Close input/output
Close Proc Near ;Close files
Mov BX,IHandle ; input
Mov AH,3Eh
Int 21h
Mov BX,OHandle ; output
Mov AH,3Eh
Int 21h
Ret
Close Endp
Page
; Get file names from command line
GetFile Proc Near ;Get file name(s)
Push CS ;DS points to PSB
Pop ES ;Now ES points to data
Mov SI,80h ;Point to command line
Sub BP,BP ;Indicates first or second name
Sub CH,CH ;The PSP may contain one or two
Or CL,Byte Ptr DS:[SI] ; filenames separated by blanks
Jz GetF5
Lea DI,ES:Input
Inc SI
GetF1: Lodsb ;Copy command line to file names
Cmp AL,' ' ; by skipping leading blanks
Jne GetF2 ; until a CR is found
Or BP,BP ; or until the length is zero
Jz GetF4 ;If a second blank is found,
Mov AX,2400h ; append zero and dollar sign
Stosw
Lea DI,ES:Output ; and it starts the second file name
Jmp GetF4
GetF2: Cmp AL,Cr ;Is it CR, end of line?
Je GetF5 ; yes, end of command
Stosb ; no, save in name
Mov BP,DI ; and indicate data copied
GetF4: Loop GetF1
GetF5: Mov AX,2400h ;Append zero and dollar sign
Stosw
Mov AX,CS ;When done, set up
Mov DS,AX ; segment registers
GetF7: Cmp Input,0 ;Any input name?
Jne GetF8 ; yes, try output name
Mov DI,Offset MsgIn ; no, ask for one
Mov SI,Offset InKey
Call AskName ;Get the input file name
GetF8: Cmp Output,0 ;Any output name?
Jne GetF9 ; yes, that was easy
Mov DI,Offset MsgOut ; no, ask for it
Mov SI,Offset OutKey
Call AskName ;Get the output name
GetF9: Cmp Word Ptr Output+1,003Ah ;If just a drive is given
Jne GetFend ; for the output,
Mov CX,64 ; use the input filename
Mov DI,Offset Output+2
Mov SI,Offset Input
Cmp Input+1,':' ;If drive was given for
Jne GetF10 ; input, must skip over it
Dec CL
Dec CL ;Adjust pointers passed drive
Dec SI
Dec SI
GetF10: Rep Movsb
GetFend:Ret
GetFile Endp
Page
; Ask for file name(s)
AskName Proc Near ;Ask for input file name
Push DI ;Ptr to prompt msg
Push SI ;Ptr to reply buffer
Mov Byte Ptr [SI],64 ;Reply length
Ask1: Mov DX,DI
Mov AH,9 ;Print the prompt msg
Int 21h
Mov DX,SI ;Read console reply
Mov AH,10
Int 21h
Sub BX,BX ;If a reply is given,
Add BL,1[SI] ; append a zero as the
Jz Ask1 ; ASCIIZ name stopper
Mov Word Ptr 2[SI][BX],2400h
Mov Word Ptr 0[SI],' ' ;Clear error message part
Pop SI
Pop DI
Ret
AskName Endp
; Display "cooking" message
Inform Proc Near
Mov AH,9
Mov DX,Offset Cooking
Int 21h
Mov AH,9
Mov DX,Offset Input
Int 21h
Mov AH,9
Mov DX,Offset Mark
Int 21h
Mov AH,9
Mov DX,Offset Output
Int 21h
Ret
Inform Endp
Tabs Endp
Cseg Ends
Stk Segment Byte Stack 'STACK'
Db 128 Dup (?)
Stk Ends
InBuf Segment Public Byte 'DATA'
Db Buflen Dup (?)
InBuf Ends
OutBuf Segment Public Byte 'DATA'
Db Buflen Dup (?)
OutBuf Ends
End Tabs
; Clock_cntr.Yr < 179
mov AX,BX ;AL = yy
or AL,AL ;Same as 'cmp AL,0'