;++
;
; Filter to do software tabs.
;
; JCL is tab stops (sep. by blanks).  Default is every 8.
;
; Ex: tab 10 16 35 <foo.s
; Will display foo.s using S/370 Assembler H tabs.
;
; 31-Dec-90  JMBW  Created.
;
;--
	.radix	8
;
bs=	10
tab=	11
lf=	12
cr=	15
;
code	segment
	assume	cs:code
;
start:	; start here
	cld			;DF=0
	mov	si,offset 80h	;pt at JCL
	lodsb			;get a char
	cbw			;ah=0
	mov	bx,ax		;copy
	mov	[bx+si],ah	;zap end
	mov	bx,offset tabs	;pt at tab table
	xor	di,di		;start at 0
jcl1:	; get next # from JCL
	lodsb			;get a char
	or	al,al		;eol?
	jz	jcl7		;skip
	cmp	al,' '		;blank or ctrl?
	jbe	jcl1		;yes, ignore
	dec	si		;unget
	xor	ah,ah		;zap ah
jcl2:	lodsb			;get a digit
	sub	al,'0'		;cvt to binary
	cmp	al,9d		;digit?
	ja	jcl3		;no
	aad			;convert #
	mov	ah,al		;copy
	jmp	short jcl2	;loop
jcl3:	; process this stop, # in ah
	dec	si		;unget
	or	ah,ah		;=0 or no valid digs?
	jz	jcl4		;error
	mov	al,ah		;copy
	xor	ah,ah		;zap high
	dec	ax		;-1
	sub	ax,di		;.GT. where we are now?
	ja	jcl5		;yes
	je	jcl1		;same, ignore
jcl4:	; error
	push	cs		;copy cs
	pop	ds		;to ds
	mov	dx,offset badjcl ;pt at msg
	mov	ah,09h		;func=print string
	int	21h
	mov	ax,4C01h	;func=punt
	int	21h
jcl5:	mov	cx,ax		;find # to go
jcl6:	mov	cs:[bx+di],cl	;insert #
	inc	di		;skip it
	loop	jcl6		;loop
	jmp	short jcl1	;next #
jcl7:	; no more tab stops
	or	di,di		;were there any at all?
	jz	jcl9		;no, default is intact
	mov	cx,400		;end of table
	sub	cx,di		;# to go
	jz	jcl9		;already full
	mov	al,1		;other tabs are 1 col apart
jcl8:	mov	cs:[bx+di],al	;add one
	inc	di		;+1
	loop	jcl8		;loop
jcl9:	; init for main loop
	mov	ax,seg ibuf	;set up buffer segs
	mov	ds,ax
	mov	ax,seg obuf
	mov	es,ax
	xor	bx,bx		;col=0
	xor	di,di		;begn of output buf
	mov	dx,177000	;lots of space
loop1:	; get (next) buffer of input file
	push	bx		;save col
	push	dx		;and output count
	xor	dx,dx		;offset
	mov	cx,177000	;count
	xor	bx,bx		;col
	mov	ah,3Fh		;func=read
	int	21h		;do it
	pop	dx		;[restore]
	pop	bx
	jc	eof		;punt
	mov	cx,ax		;copy count
	jcxz	eof		;eof
	xor	si,si		;pt at begn
loop2:	; get next character
	lodsb			;get a char
	cmp	al,cr		;possible ctrl char?
	jbe	cc		;yes
store1:	inc	bl		;col +1
store2:	stosb			;save
	dec	dx		;count
	loopnz	loop2		;loop
	jnz	loop1		;must be cx=0
	call	flush		;dx=0, flush buf
	jcxz	loop1		;cx was 0 too
	jmp	short loop2	;nope, just loop
cc:	; may be an interesting char
	je	cr1		;cr, skip
	cmp	al,lf		;lf?
	je	store2		;no change in col
	cmp	al,tab		;tab?
	je	tab1
	cmp	ax,bs		;bs?
	jne	store1		;no
	; backspace - col-1
	or	bl,bl		;at left marg?
	jz	store2
	dec	bx		;no, -1
	jmp	short store2
cr1:	; carriage return
	xor	bl,bl		;left marg
	jmp	short store2	;save
tab1:	; tab
	push	cx		;save
	mov	cl,cs:tabs[bx]	;get # to move
	add	bl,cl		;advance
	xor	ch,ch		;ch=0
tab2:	mov	al,' '		;blank
tab3:	stosb			;save one
	dec	dx		;count it
	loopnz	tab3		;loop
	jnz	tab4		;we're done
	call	flush		;flush
	or	cx,cx		;anything left to do?
	jnz	tab2		;yes, reload al and go
tab4:	pop	cx		;restore
	loop	loop2		;loop
	jmp	short loop1	;get more
;
eof:	; end of input file
	call	flush		;flush last buf (may be empty)
	mov	ax,4C00h	;func=exit, errorlevel=0
	int	21h
;+
;
; Flush output buffer.
;
; dx	# free in output buf
; di	ptr to next free loc
;
; bx, cx, si preserved.
;
;-
flush:	push	bx		;save
	push	cx
	push	ds
	push	es		;toss es
	pop	ds		;to ds
	xor	dx,dx		;offset
	mov	cx,di		;count
	mov	bx,0001h	;stdout
	mov	ah,40h		;func=write
	int	21h
	pop	ds		;restore
	pop	cx
	pop	bx
	xor	di,di		;output ptr
	mov	dx,177000	;# free
	ret
;
badjcl	db	'?Invalid JCL',cr,lf,'$'
;
tabs	label	byte		;here's the table
	rept	400/10
	db	10,7,6,5,4,3,2,1 ;default is every 8. columns
	endm
;
code	ends
ibuf	segment
	db	177000 dup(?)
ibuf	ends
obuf	segment
	db	177000 dup(?)
obuf	ends
pdl	segment	stack 'stack'	;goddamned TLINK requires 'STACK'
	dw	100h dup(?)
pdl	ends
	end	start

