	.386P

vseg	equ	0b000h	;video ram segment address

;****************************************************************************
;*  									    *
;*  Procedure msout	On entry ds:si -> text, terminated with 0.	    *
;*  									    *
;*  Display message on standard output, convert parameters to hex ascii or  *
;*  decimal ascii for each n, n, n in message where n=number of digits.  *
;*  Repeat character c for nc, where n=(number of repetitions plus 30h).   *
;*  									    *
;****************************************************************************

litsg	equ	''		;next character is to be output directly
hexsg	equ	''		;hexadecimal conversion signal
decsg	equ	''		;decimal conversion signal
decsgn	equ	''		;decimal conversion, leading spaces suppressed
decsgc	equ	''		;decimal conversion, use commas
repsg	equ	''		;repeat character signal
sgchk	equ	''		;all characters below this value are literals

msout	proc	near
	pushad
	push	ds
	push	es
	push	ax

	mov	ax,cs
	mov	ds,ax
	mov	es,ax
	mov	di,os iobuf	;output buffer
	mov	bx,os msval	;parameter list
	cld

msorc:	lodsb			;read character
	cmp	al,sgchk
	jc	short msowc	;not conversion character

	cmp	al,hexsg
	jz	short mscvh	;hex conversion character
	xor	dh,dh		;decimal type flag
	cmp	al,decsg
	jz	short mscvd	;decimal conversion
	mov	dh,40h		;leading space suppress, bit 6
	cmp	al,decsgn
	jz	short mscvd	;decimal, suppress leading spaces
	shl	dh,1		;include commas, bit 7
	cmp	al,decsgc
	jz	short mscvd	;decimal with commas
	cmp	al,repsg
	jnz	short msolc	;not repeat character
	lodsb			;get number of repeats
	sub	al,30h		;ascii zero based
	movzx	cx,al		;count
	lodsb			;character to repeat
	rep	stosb		;expand
	jmp	short msorc

msolc:	cmp	al,litsg
	jnz	short msowc	;not literal signal
	lodsb			;no translation on character following

msowc:	stosb			;write character to buffer
	or	al,al
	jnz	short msorc	;not at end

	mov	si,os iobuf
	sub	di,si		;length
	dec	di
				;	jz	msox		;what?
	mov	cx,di
	pop	di		;dest
				;	mov	ah,40h
				;	mov	bx,1		;stdout
				;	int	21h		;write line
	mov	ax,vseg
	mov	es,ax		;video segment
	mov	ah,7		;attr
wrsc:	lodsb
	stosw
	loop	wrsc		;write ms to screen

msox:	pop	es
	pop	ds
	popad
	ret


; Binary to Hex Ascii Conversion

; ds:si->source text, es:di->output text, ds:bx->current binary parameter

mscvh:	lodsb			;read character after signal
	dec	al
	and	al,7		;number of digits (0-7 for 1-8)
	shl	al,2		;times bits per digit
	movzx	cx,al		;number of bits minus 4
	mov	eax,[bx]	;get parameter
	add	bx,4		;address next parameter
	ror	eax,cl		;bits 3-0 are ms digit
	shr	cx,2
	inc	cx		;number of digits

mshxd:	mov	dh,al		;save 2 digits
	call	cvhn		;convert al{3:0}
	mov	al,dh		;restore 2 digits
	rol	eax,4		;pull up next digit
	loop	mshxd
	jmp	short msorc	;continue with text

; Convert Binary in al to Hex Ascii at es:[di]+
;	Affects: ax, di

cvhb:	cld
	push	ax		;save low digit
	shr	al,4
	call	cvhn		;convert high digit
	pop	ax		;convert low digit
cvhn:	and	al,0fh
	or	al,90h		;90-99, 9A-9F
	daa			;90-99, 100-105
	adc	al,40h		;D0-D9, 41-46
	daa			;130-139, 41-46
	stosb			;store ascii 0-9, A-F
	ret


; Binary to Decimal Ascii Conversion

; ds:si->source text, es:di->output text, ds:bx->current binary parameter

; dh = 80h, include commas; dh = 40h, suppress leading spaces

mscvd:	lodsb			;read character after signal
	xor	ecx,ecx		;clear for use as index
	cmp	al,'w'
	jz	short msdwp	;16-bit conversion
	cmp	al,'b'
	jnz	short msdlp	;32-bit conversion

	mov	1[bx],cl	;8-bit conversion, zero high byte of low word
msdwp:	mov	2[bx],cx	;zero high word for 8/16-bit
	lodsb			;get next source character

msdlp:	dec	al
	and	al,0fh
	mov	cl,al		;number of decimal digits (0-9 for 1-10)
	mov	ebp,[bx]	;get parameter
	add	bx,4		;update current parameter address
	push	bx

msdsc:	sub	al,3
	jnc	short msdsc	;reduce al mod 3
	add	al,3		;add remainder
	mov	bl,al		;number of digits before first comma
	push	si		;save place in source text

	jcxz	msd1		;one digit only
	lea	si,dcval[ecx*4]	;index into 10 list for number of digits

msdxd:	std			;count downward
	lodsd			;get 10 where n is current digit
	cld			;count upward

	mov	dl,2fh		;ascii count
msdxi:	inc	dl
	js	short msdov	;overflow
	sub	ebp,eax		;subtract 10 from parameter value
	jnc	short msdxi
msdov:	add	ebp,eax		;leave remainder

	cmp	dl,3ah
	jc	short msdno	;no overflow
	stc
	rcr	ebp,1		;make sure it propagates
	mov	dl,'*'		;overflow character

msdno:	or	dh,dl		;bits 3-0 are zero if this is a leading zero
	test	dh,0fh		;check whether all zeros so far
	mov	al,dl		;current digit
	jnz	short msdpc	;display non-leading-zero
	mov	al,' '		;change leading zero to space

	test	dh,40h
	jnz	short msdx	;skip leading spaces and commas

msdpc:	stosb			;write digit to output buffer

	or	dh,dh
	jns	short msdx	;no commas

	dec	bl		;decrement comma counter
	jns	short msdx	;no action until zero
	cmp	al,' '
	jz	short msdco	;leave leading space
	mov	al,','
msdco:	stosb			;write comma to output buffer

	mov	bl,2		;reload counter
msdx:	loop	msdxd		;next digit
msd1:	mov	ax,bp		;last digit
	cmp	ax,10
	jc	short msd1n	;no overflow
	mov	al,1ah		;display *
msd1n:	xor	al,30h
	stosb

	pop	si		;restore current index in source text
	pop	bx		;restore current parameter index
	jmp	msorc		;continue with text

	align	4

dcval	equ	$-4		;10 table

	dd	10,100,1000,10000,100000,1000000
	dd	10000000,100000000,1000000000

msval:				;parameter list
mv1:	dd	0
mv2:	dd	0
mv3:	dd	0
mv4:	dd	0
mv5:	dd	0
mv6:	dd	0
mv7:	dd	0
mv8:	dd	0

iobuf:	db	512 dup (99h)	;output buffer

msout	endp
