home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
txtutl
/
ascutils.arc
/
SPCTAB.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-05-23
|
7KB
|
265 lines
PAGE 55,130
; SPCTAB
;
bufspc equ 0400h
stkspc equ 0100h
midbuf equ 0200h
codeseg segment
assume cs:codeseg, ds:codeseg
org 100h
spctab proc far
start: jmp init
; messages -
errmsg1 db 0Dh, 0Ah, 'Read Error', 0Dh, 0Ah, '$'
errmsg2 db 0Dh, 0Ah, 'Could not get enough memory.', 0Dh, 0Ah, '$'
help_msg db 0Dh, 0Ah, 'SPCTAB is a filter that converts spaces'
db ' in standard input to TABs in standard', 0Dh, 0Ah
db 'output where possible. It also trims a line, that'
db ' is, it deletes all trailing', 0Dh, 0Ah
db 'spaces in a line.', 0Dh, 0Ah, 0Dh, 0Ah
db 'Usage: SPCTAB [<fname] [>fname]', 0Dh, 0Ah, '$'
errmsg3 db 0Dh, 0Ah, 'Write Error', 0Dh, 0Ah, '$'
; variables -
count dw 0
; Note - space for the 1024 byte buffer and the 256 byte stack is allocated
; here, rather than being stored in the task image on disk.
;
init: mov bx,offset buffer + bufspc + stkspc ; req. mem.
add bx,010h
mov cl,4
shr bx,cl ; get it in paragraphs
mov ah,04Ah ; set it - cf=1 if error
int 021h
mov dx,offset errmsg2
jc err_exit ; exit with error message
mov ax,0
mov di,offset buffer ; else initialize buffer
mov cx,bufspc + stkspc ; and stack space to 0
shr cx,1 ; (div by 2 for words)
cld
rep stosw
mov sp,offset buffer + bufspc + stkspc ; init sp
mov si,80h ; get cmd line char count
cmp byte ptr [si],0 ; into cx and incr by 1
je Main
mov cl,[si]
inc cx
skpspc: inc si ; skip any blanks
cmp byte ptr [si],20h
loopz skpspc
jcxz Main ; skip if cmd line is all
cmp byte ptr [si],3Fh ; spaces. Check for '?'
jne Main ; ignore other chars
mov dx,offset help_msg ; if '?' found, exit with
jmp short err_exit ; 'help' message
Main: call get_line ; get line from std input
jc err_exit ; cf=1 is error
or ax,ax
jz norm_exit ; 0 char count is end
call fix_line ; convert spcs to tabs
call put_line ; write line to std output
jc err_exit ; if cf=1, exit with err msg
jmp short Main ; else continue.
; Note - here err_exit outputs the messages to std error rather than std
; out, so even if I/O is redirected from the cmd line, the message
; will be output to the console rather than the output file.
err_exit: mov di,dx ; point di to error message
mov cx,0FFh ; set cx to 255 ( countdown limit )
mov al,024h ; "$"
cld
repnz scasb ; incr di to message terminator
dec di ; decr to last char of message
mov cx,di ; arithmetic to get char count in cx
sub cx,dx
mov bx,2 ; handle for std error
mov ah,040h ; output message
int 021h
mov al,1 ; exit status = 1
norm_exit: mov ah,04Ch
int 021h
spctab endp
; SUBROUTINE
; gets a line from std input
get_line proc near
mov si,offset buffer
get_1: mov dx,si
mov bx,0 ; handle for std input
mov cx,1
mov ah,03Fh ; read cx chars
int 021h
jc get_err ; cf=1 if input error
cmp byte ptr [si],0Ah ; eoln found
je get_ok
or ax,ax ; ax=0 if kybd input eof
jz get_ok
xor ax,ax ; (make ax=0 on eof)
cmp byte ptr [si],1Ah ; eof found (disk file)
je get_ok
inc si
jmp short get_1
get_ok: clc
ret
get_err: mov dx,offset errmsg1
stc
ret
get_line endp
; SUBROUTINE
; This is where the transformation takes place.
; Basically, you're on your own to understand this.
;
fix_line proc near
mov count,0
mov si,offset buffer
mov di,offset buffer + midbuf
xor bx,bx
fix_loop_1: lodsb ; get a char (adv si)
bigloop: cmp al,020h ; BL ?
je fix_2 ; yes, next procedure.
cmp al,0Dh ; CR ?
jne fix_1a
sub di,bx ; skip this if CR
fix_1a: stosb ; not BL, not CR, so store it (adv di)
cmp al,9 ; HT ?
jne fix_1b ; if not, skip this
add count,8 ; yes, add 8 to count
and count,0FFF8h ; discard mod 8 remainder
inc bx ; incr bx value
jmp short fix_loop_1 ; continue
fix_1b: inc count ; non-space char, incr count
cmp al,0Ah ; check for NL
je fix_done ; (exit this scene - line done.)
xor bx,bx ; not NL, null bx value
jmp short fix_loop_1 ; continue
; ----------
fix_2: push bx ; point bx to first BL input
mov bx,si
dec bx
fix_3: lodsb ; while char is BL, cont to get
cmp al,020h
je fix_3
mov dx,si ; point dx to last BL input
dec dx
sub dx,bx ; subtract bx to get # of BL's
mov ax,count ; put count in ax and bx
mov bx,ax
add ax,8 ; advance ax to next TS
and ax,0FFF8h
sub ax,bx ; subtract pos of 1st BL in series
pop bx ; restore old bx value
xor cx,cx ; null cx
cmp dx,ax
jb fix_4 ; dx hasn't reached next TS yet
add count,ax ; dx reached next TS, add ax to count
mov bx,1 ; set bx value to 1
sub dx,ax ; move pointer back ax BL's
mov al,9 ; output a Tab char.
stosb ; (di is keeping track here)
mov cx,dx ; put dx value in cx
shr cx,1 ; and divide by 8 (# of TS's)
shr cx,1
shr cx,1
fix_4: cmp byte ptr [si-1],9 ; was last char output a tab?
jne fix_5 ; if not, skip this next
inc cx ; else add 1 TS
inc si ; incr char pointer
and dx,0FFF8h ; discard dx mod 8 remainder
jmp short fix_4 ; continue while char = tab.
fix_5: or cx,cx ; if cx=0 skip this next
jz fix_6
add bx,cx ; add cx to bx tab count
mov ax,cx ; put cx into ax
shl ax,1 ; multiply by 8
shl ax,1
shl ax,1
add count,ax ; add ax to count
mov al,9 ; put tab char in al
rep stosb ; output cx tabs (adv di)
fix_6: mov cx,dx ; put output pointer in cx
and cx,7 ; cx mod 8
or cx,cx ; if it's 0, skip next
jz fix_7
add bx,cx ; else add cx to bx counter
add count,cx ; add cx to count (?)
mov al,020h ; put BL in al
rep stosb ; output cx BL's (adv di)
fix_7: mov al,[si-1] ; put that last char back in al
jmp bigloop ; and do it again.
fix_done: mov cx,di ; put di pointer in cx
sub cx,offset buffer + midbuf ; sub start of buffer
ret
fix_line endp
; SUBROUTINE
; sends line to std output
put_line proc near
jcxz put_ok
push cx ; cx should have char count
mov dx,offset buffer + midbuf
mov bx,1 ; handle for std output
mov ah,040h ; output cx chars.
int 021h
pop cx
jc put_err ; cf=1 if error.
sub cx,ax ; ax = cx if ok.
jnz put_err
put_ok: clc
ret
put_err: mov dx,offset errmsg3
stc
ret
put_line endp
buffer db 0 ; buffer area: 1024 bytes allocated
; at pgm start (followed by 256 stack).
codeseg ends
end start