page 75,132
codeseg segment para 'code'
	assume cs:codeseg,ds:codeseg,es:codeseg
;=======================================================================
;= EXPAND_TABS							       =
;= -----------							       =
;= Function: Expand tab characters into blanks (TABLINE-->NOTABLINE    =
;=								       =
;= Call: EXPAND_TABS(var TABLINE,NOTABLINE:lstring);		       =
;=	     where  TABLINE   = input line (may have tabs in it).      =
;=		    NOTABLINE = final line			       =
;=								       =
;= Calling parameter offsets (frame contents):			       =
;=		+00,02,04 caller's BP, IP, CS registers                =
;=		+06 address of lstring NOTABLINE		       =
;=		+08 max length of lstring NOTABLINE		       =
;=		+10 address of lstring TABLINE			       =
;=		+12 max length of lstring TABLINE		       =
;=======================================================================
EXPAND_TABS  proc far
	 public EXPAND_TABS	;use from Pascal
	 push	bp		;save callers frame pointer
	 mov	bp,sp		;set frame pointer
	 mov	si,[bp+6]	;SI=A(NOTABLINE)
	 mov	byte ptr [si],0 ;default length of NOTABLINE = 0
	 mov	bx,[bp+10]	;address of TABLINE in caller's DS seg
	 sub	cx,cx		;CX = 0
	 mov	cl,[bx] 	;CX = current TABLINE length
	 inc	bx		;skip TABLINE[0] = lstring length
	 push	es		;save caller's extra seg reg.
	 jcxz	exrtrn		;don't process if nothing in string
				;------ Set ES to DS for 'Scan ------
	 mov	ax,ds		;ES & DS are used by scan(SCAB & SCAW)
	 mov	es,ax		;instructions and must get data that is
				;defined in the caller's DS area.
	 push	cx		;save length of TABLINE
				;------ Are there any tab char? ------
	 mov	di,bx		;DI= offset fo 1st element of TABLINE
	 cld			;clear DF, causing incr thru TABLINE
	 mov	al,09H		;Compare char 9 = TAB
REPNE	 scasb			;scan TABLINE for AX char - repeat CX
	 pop	cx		;CX= length of TABLINE
	 je	yestabs 	;JMP=> tabs found
				;------ Is line all blank? ------
	 mov	di,bx		;DI= offset of 1st element of TABLINE
	 mov	al,20H		;Compare char = blank
REPE	 scasb			;scan TABLINE for non blnk, CX times
	 je	exrtrn		;return if all blank (leave length=0)
	 mov	si,[bp+10]	;------Move TABLINE to NOTABLINE------
	 mov	di,[bp+6]	;A(NOTABLINE)
	 sub	cx,cx		;
	 mov	cl,[si] 	;length of TABLINE
	 inc	cx		;include byte 0 in move
REP	 movsb			;TABLINE -> NOTABLINE
	 jmp	short exrtrn	;exit
				;------ Process tab character ------
yestabs: sub	dx,dx		;DX=last col of TABLINE processed
	 dec	bx		;BX= A(TABLINE[0])
	 mov	di,bx		;DI= A(TABLINE[0])
				;      === GET_BYTE ===
tabloop: inc	dx		;incr TABLINE pointer
	 mov	bx,dx		;get updated pointer
	 mov	al,[bx][di]	;get nxt byte = A(TABLINE)+pointer
				;      =================
	 cmp	al,09H		;is this a tab char?
	 je	tabfound	;jmp if tab
	 call	PUT_BYTE	;put AL to NOTABLINE
	 jmp	short tabend	;
tabfound:sub	ax,ax		;
	 mov	al,[si] 	;AX= col position of nxt char
	 push	cx		;save counter
	 mov	cx,8		;COLUMN/8
	 div	cl		;AX/CL --> AL=Quotient	 AH=Remainder
	 sub	cl,ah		;CX= 8-(COLmod 8) = # blanks to insert
	 mov	al,20H		;blank char
tabblnk: call	PUT_BYTE	;put it into NOTABLINE
	 loop	short tabblnk	;repeat for all blanks to fill in
	 pop	cx		;get length left in NOTABLINE
tabend:  loop	short tabloop	;do all NOTABLINE char
				;---- Return to calling program ----
exrtrn:  pop	es		;restore caller's ES
	 pop	bp		;restore caller's frame pointer
	 ret	8
				;------------ DATA--------------
COL_IN	 db	0		;current col in NOTABLINE
				;(1st chr is length of expanded string)
EXPAND_TABS endp		;
				;========= PUT_BYTE =========
PUT_BYTE proc	near		;Move AL to nxt byte of NOTABLINE
	 inc	byte ptr [si]	;incr NOTABLINE[0] = lstring length
	 sub	bx,bx		;
	 mov	bl,byte ptr [si];pointer to nxt byte
	 add	bx,si		;A(NOTABLINE)+next byte
	 mov	[bx],al 	;save byte
	 ret			;return to calling point
PUT_BYTE endp			;===================================
codeseg  ends			;end segment
	 end			;end assembly
