include	clib.inc
include	stdio.inc
ifndef __386__
	extrn DIV32:NEAR
endif
BUFFERSIZE	= 512		; ANSI-specified minimum is 509

FLAG_SIGN	= 0001h     	; put plus or minus in front
FLAG_SIGNSP	= 0002h     	; put space or minus in front
FLAG_LEFT	= 0004h     	; left justify
FLAG_LEADZERO	= 0008h     	; pad with leading zeros
FLAG_LONG       = 0010h     	; long value given
FLAG_SHORT      = 0020h     	; short value given
FLAG_SIGNED	= 0040h     	; signed data given
FLAG_ALTERNATE	= 0080h     	; alternate form requested
FLAG_NEGATIVE	= 0100h     	; value is negative
FLAG_FORCEOCTAL = 0200h     	; force leading '0' for octals

_DATA	SEGMENT

cl_table label byte
	db	 06h, 00h, 00h, 06h, 00h, 01h, 00h, 00h
	db	 10h, 00h, 03h, 06h, 00h, 06h, 02h, 10h
	db	 04h, 45h, 45h, 45h, 05h, 05h, 05h, 05h
	db	 05h, 35h, 30h, 00h, 50h, 00h, 00h, 00h
	db	 00h, 20h, 28h, 38h, 50h, 58h, 07h, 08h
	db	 00h, 37h, 30h, 30h, 57h, 50h, 07h, 00h
	db	 00h, 20h, 20h, 08h, 00h, 00h, 00h, 00h
	db	 08h, 60h, 60h, 60h, 60h, 60h, 60h, 00h
	db	 00h, 70h, 78h, 78h, 78h, 78h, 78h, 08h
	db	 07h, 08h, 00h, 00h, 07h, 00h, 08h, 08h
	db	 08h, 00h, 00h, 08h, 00h, 08h, 00h, 00h
	db	 08h

formchar db	'bcdefginopsuxEGX'
nullstring db	'(null)',0

OPST_table 	label word
	dw	OPST_normal
	dw	OPST_percent
	dw	OPST_flag
	dw	OPST_width
	dw	OPST_dot
	dw	OPST_precision
	dw	OPST_size
	dw	OPST_type

;	public	output_proctab

output_proctab 	label word
	dw	OUTPUT_b
	dw      OUTPUT_c
	dw      OUTPUT_d
	dw      OUTPUT_dummy
	dw      OUTPUT_dummy
	dw      OUTPUT_dummy
	dw      OUTPUT_d
	dw      OUTPUT_n
	dw      OUTPUT_o
	dw	OUTPUT_p
	dw      OUTPUT_s
	dw      OUTPUT_u
	dw      OUTPUT_x
	dw	OUTPUT_dummy
	dw      OUTPUT_dummy
	dw      OUTPUT_xu

output_flush PF	?
	public	output_flush

_DATA	ENDS

S_OUTPUT STRUC
	OP_filep	PD ?
	OP_format	PD ?
	OP_charsout 	dw ?
	OP_hexoff	dw ?
	OP_state	dw ?
	OP_curadix	dw ?
	OP_prefix	db 2 dup(?)
	OP_count	dw ?
	OP_prefixlen	dw ?
	OP_no_output	dw ?
	OP_fldwidth	dw ?
	OP_padding	dw ?
	OP_text		dd ?
	OP_capitalize	dw ?
	OP_number	dd ?
	OP_ddtemp	dd ?
	OP_dwtemp	dw ?
	OP_buffer	db BUFFERSIZE dup(?)
	OP_STACK	dd ? ; [BP]
ifdef LPROG
	OP_CSIP		dw ?
endif
ifdef __CDECL__
	OP_ARGfile	PD ?
	OP_ARGformat	PD ?
	OP_argp		PD ?
else
	OP_argp		PD ?
	OP_ARGformat	PD ?
	OP_ARGfile	PD ?
endif
S_OUTPUT ENDS

_TEXT	SEGMENT

_output proc dist pascal public uses si di bp filep:dword,
	format:dword, argp:dword
local	OP[OP_STACK]:byte
	lea bp,OP
	movmx [bp.OP_format],[bp.OP_ARGformat]
	movmx [bp.OP_filep],[bp.OP_ARGfile]
	xor ax,ax
	mov [bp.OP_count],ax
	mov [bp.OP_charsout],ax
	mov [bp.OP_state],ax
	.repeat
	    les bx,[bp.OP_format]
	    inc word ptr [bp.OP_format]
	    mov al,es:[bx]
	    mov dl,al
	    .break .if !al
	    .break .if [bp.OP_charsout] > 7FFFh
	    .if al < ' ' || al > 'x'
		xor ax,ax
	    .else
		cbw
		mov bx,ax
		mov al,[bx+cl_table-32]
		cbw
		and ax,15
	    .endif
	    mov cx,ax
	    mov bx,ax
	    shl bx,3
	    add bx,[bp.OP_state]
	    mov al,[bx+cl_table]
	    cbw
	    sar ax,4
	    mov [bp.OP_state],ax
	    mov bx,ax
	    .if ax <= 7
		add bx,bx
		call OPST_table[bx]
	    .endif
	.until 0
	mov ax,[bp.OP_charsout]
	ret
_output	ENDP

OPST_normal PROC
	mov al,dl
OPST_normal ENDP

OUTPUT_PUTC PROC
	les bx,[bp.OP_filep]
	dec es:[bx.iob_cnt]
	jl OPPUTC_00
	inc word ptr es:[bx]
	les bx,es:[bx]
	mov es:[bx-1],al
    OPPUTC_01:
	inc [bp.OP_charsout]
	ret
    OPPUTC_00:
	push ax
	pushm [bp.OP_filep]
	assert  word ptr output_flush,0,jne,"OUTPUT"
	call output_flush
	cmp ax,-1
	jne OPPUTC_01
	mov [bp.OP_charsout],ax
	ret
OUTPUT_PUTC ENDP

OUTPUT_GETW PROC	; Get WORD from stack
	lea bx,[bp.OP_argp]
	mov ax,[bx+2]
	add word ptr [bx],2
	mov bx,[bx]
	mov es,ax
	mov ax,es:[bx-2]
	ret
OUTPUT_GETW ENDP

OUTPUT_GETD PROC 	; Get DWORD from stack
	lea bx,[bp.OP_argp]
	mov ax,[bx+2]
	add word ptr [bx],4
	mov bx,[bx]
	mov es,ax
      ifdef __386__
	mov eax,es:[bx-4]
      else
	mov ax,es:[bx-4]
	mov dx,es:[bx-2]
      endif
	ret
OUTPUT_GETD ENDP

OPST_percent PROC
	xor ax,ax
	mov [bp.OP_no_output],ax
	mov [bp.OP_fldwidth],ax
	mov [bp.OP_prefixlen],ax
	mov [bp.OP_capitalize],ax
	xor si,si ; bufferiswide (default)
	mov di,-1 ; precision
	ret
OPST_percent ENDP

OPST_flag PROC
	mov al,dl
	cbw
	.if al == '+'
	    or si,FLAG_SIGN    	; '+' force sign indicator
	.elseif al == ' '
	    or si,FLAG_SIGNSP  	; ' ' force sign or space
	.elseif al == '#'
	    or si,FLAG_ALTERNATE; '#' alternate form
	.elseif al == '-'
	    or si,FLAG_LEFT	; '-' left justify
	.elseif al == '0'
	    or si,FLAG_LEADZERO	; '0' pad with leading zeros
	.endif
	ret
OPST_flag ENDP

OPST_width PROC
	.if dl == '*'
	    call OUTPUT_GETW
	    mov [bp.OP_fldwidth],ax
	    .if ax < 0
		or si,4
		neg ax
		mov [bp.OP_fldwidth],ax
	    .endif
	.else
	    mov al,dl
	    cbw
	    push ax
	    mov ax,[bp.OP_fldwidth]
	    mov dx,10
	    imul dx
	    pop dx
	    add dx,ax
	    add dx,-48
	    mov [bp.OP_fldwidth],dx
	.endif
	ret
OPST_width ENDP

OPST_dot PROC
	xor di,di
	ret
OPST_dot ENDP

OPST_precision PROC
	.if dl == '*'
	    call OUTPUT_GETW
	    mov di,ax
	    .if ax < 0
		mov di,-1
	    .endif
	.else
	    mov al,dl
	    cbw
	    push ax
	    mov ax,di
	    mov dx,10
	    imul dx
	    pop dx
	    add dx,ax
	    add dx,-48
	    mov di,dx
	.endif
	ret
OPST_precision ENDP

OPST_size PROC
	.if dl == 'l'
	    or si,FLAG_LONG
	.endif
	ret
OPST_size ENDP

OPST_type PROC
	xor bx,bx
	mov cx,16
	.repeat
	    .if dl == [bx+formchar]
		add bx,bx
		call [bx+output_proctab]
		.break
	    .endif
	    inc bx
	.untilcxz
	call OUTPUT
	ret
OPST_type ENDP

OUTPUT_b PROC
	push si
	call OUTPUT_GETW
	test si,FLAG_LONG
	mov si,16
	jnz OUTPB_00
	mov si,8
    OUTPB_00:
	mov [bp.OP_count],si
    OUTPB_01:
	mov dx,ax
	xor cx,cx
    OUTPB_02:
	mov ax,dx
	shr ax,cl
	and ax,1
	add ax,48
	mov [bp.OP_buffer+si-1],al
	inc cx
	dec si
	jnz OUTPB_02
	pop si
	jmp OUTPUT_LDTEXT
OUTPUT_b ENDP

OUTPUT_c PROC
	call OUTPUT_GETW
	mov dx,ax
	mov [bp.OP_buffer],dl
	mov [bp.OP_count],1
OUTPUT_c ENDP

OUTPUT_LDTEXT PROC
	lea ax,[bp.OP_buffer]
	mov word ptr [bp.OP_text+2],ss
	mov word ptr [bp.OP_text],ax
	ret
OUTPUT_LDTEXT ENDP

OUTPUT_s PROC
	.if di == -1
	    mov cx,7FFFh
	.else
	    mov cx,di
	.endif
	call OUTPUT_GETD
      ifdef __386__
      	mov [bp.OP_text],eax
	test eax,eax
      else
	mov word ptr [bp.OP_text+2],dx
	mov word ptr [bp.OP_text],ax
	or ax,dx
      endif
	jnz OUTPS_02
    OUTPS_NULL:
	mov word ptr [bp.OP_text+2],ds
	mov word ptr [bp.OP_text],offset nullstring
    OUTPS_02:
	les bx,[bp.OP_text]
    OUTPS_03:
	cmp byte ptr es:[bx],0
	jz OUTPS_04
	inc bx
	dec cx
	jnz OUTPS_03
    OUTPS_04:
	sub bx,word ptr [bp.OP_text]
	mov [bp.OP_count],bx
	ret
OUTPUT_s ENDP

OUTPUT_n PROC
	call OUTPUT_GETD
	les bx,es:[bx-4]
	test si,FLAG_LONG
	jnz OUTPN_00
	mov ax,[bp.OP_charsout]
	mov es:[bx],ax
	ret
    OUTPN_00:
      ifdef __386__
	movzx eax,[bp.OP_charsout]
	mov es:[bx],eax
      else
	mov ax,[bp.OP_charsout]
	mov es:[bx],ax
	mov word ptr es:[bx+2],0
      endif
	mov [bp.OP_no_output],1
	ret
OUTPUT_n ENDP

OUTPUT_p PROC
	mov di,8
	or si,FLAG_LONG
OUTPUT_p ENDP

OUTPUT_xu PROC
	mov [bp.OP_hexoff],'A'-'9'-1
	jmp OPCOMMONHEX
OUTPUT_xu ENDP

OUTPUT_x PROC
	mov [bp.OP_hexoff],'a'-'9'-1
OUTPUT_x ENDP

OPCOMMONHEX PROC
	mov [bp.OP_curadix],16
	test si,FLAG_ALTERNATE
	jz OPCOMM_00
	mov [bp.OP_prefix],'0'
	mov [bp.OP_prefix+1],'x'
	mov [bp.OP_prefixlen],2
    OPCOMM_00:
	test si,FLAG_LONG
	jnz OUTPUT_LONGINT
	cmp [bp.OP_fldwidth],2
	jne OUTPUT_SHORTINT
	call OUTPUT_GETW
	mov ah,0
	jmp OUTPUT_UNSIGNED
OPCOMMONHEX ENDP

OUTPUT_o PROC
	mov [bp.OP_curadix],8
	test si,FLAG_ALTERNATE
	jz OUTPUT_GENINT
	or si,FLAG_FORCEOCTAL
	jmp OUTPUT_GENINT
OUTPUT_o ENDP

OUTPUT_d PROC
	or si,FLAG_SIGNED
OUTPUT_d ENDP

OUTPUT_u PROC
	mov [bp.OP_curadix],10
OUTPUT_u ENDP

OUTPUT_GENINT PROC
	test si,FLAG_LONG
	jz OUTPUT_SHORTINT
OUTPUT_GENINT ENDP

OUTPUT_LONGINT PROC
	call OUTPUT_GETD
	jmp OUTPUT_NUMBER
OUTPUT_LONGINT ENDP

OUTPUT_SHORTINT	PROC
	call OUTPUT_GETW
	test si,FLAG_SIGNED
	jz OUTPUT_UNSIGNED
  ifdef __386__
	movsx eax,ax
  else
	cwd
  endif
	jmp OUTPUT_NUMBER
OUTPUT_SHORTINT	ENDP

OUTPUT_UNSIGNED	PROC
  ifdef __386__
	movzx eax,ax
  else
	xor dx,dx
  endif
OUTPUT_UNSIGNED	ENDP

OUTPUT_NUMBER PROC
  ifdef __386__
	mov [bp.OP_ddtemp],eax
	test si,FLAG_SIGNED
	jz OPNUM_00
	cmp eax,0
	jnl OPNUM_00
	neg eax
	or si,FLAG_NEGATIVE
    OPNUM_00:
	mov [bp.OP_number],eax
  else
	mov word ptr [bp.OP_ddtemp],ax
	mov word ptr [bp.OP_ddtemp+2],dx
	test si,FLAG_SIGNED
	jz OPNUM_00
	test dx,dx
	jns OPNUM_00
	neg ax
	neg dx
	sbb dx,0
	or si,FLAG_NEGATIVE
    OPNUM_00:
	mov word ptr [bp.OP_number],ax
	mov word ptr [bp.OP_number+2],dx
  endif
	test di,di
	jnl OPNUM_01
	mov di,1
	jmp OPNUM_02
    OPNUM_01:
	and si,-9
    OPNUM_02:
  ifdef __386__
	test eax,eax
  else
	test ax,ax
	jnz OPNUM_03
	test dx,dx
  endif
	jnz OPNUM_03
	mov [bp.OP_prefixlen],ax
    OPNUM_03:
	lea ax,[bp.OP_buffer+512-1]
	mov word ptr [bp.OP_text+2],ss
	mov word ptr [bp.OP_text],ax
	jmp OPNUM_06
    OPNUM_04:
  ifdef __386__
	movzx ebx,[bp.OP_curadix]
	mov eax,[bp.OP_number]
	xor edx,edx
	div ebx
	mov [bp.OP_number],eax
	add dx,'0'
	mov cx,dx
  else
	xor cx,cx
	mov bx,[bp.OP_curadix]
	mov ax,word ptr [bp.OP_number]
	mov dx,word ptr [bp.OP_number+2]
	call DIV32
	mov word ptr [bp.OP_number],ax
	mov word ptr [bp.OP_number+2],dx
	add bx,'0'
	mov cx,bx
  endif
	cmp cx,'9'
	jng OPNUM_05
	add cx,[bp.OP_hexoff]
    OPNUM_05:
	les bx,[bp.OP_text]
	mov es:[bx],cl
	dec word ptr [bp.OP_text]
    OPNUM_06:
	mov cx,di
	dec di
	test cx,cx
	jg OPNUM_04
  ifdef __386__
	test eax,eax
  else
	or ax,dx
  endif
	jnz OPNUM_04
	lea ax,[bp.OP_buffer+512-1]
	sub ax,word ptr [bp.OP_text]
	mov [bp.OP_count],ax
	inc word ptr [bp.OP_text]
	test si,FLAG_FORCEOCTAL
	jz OUTPUT_dummy
	les bx,[bp.OP_text]
	cmp byte ptr es:[bx],'0'
	jne OPNUM_07
	cmp [bp.OP_count],0
	jne OUTPUT_dummy
    OPNUM_07:
	dec bx
	mov word ptr [bp.OP_text],bx
	mov byte ptr es:[bx],'0'
	inc [bp.OP_count]
OUTPUT_NUMBER ENDP

OUTPUT_dummy PROC
	ret
OUTPUT_dummy ENDP

OUTPUT_MULTI PROC
	push si
	push di
	xor ah,ah
	mov si,ax
	mov di,dx
	jmp OPMULTI_01
    OPMULTI_00:
	mov ax,si
	call OUTPUT_PUTC
	cmp [bp.OP_charsout],-1
	je OPMULTI_02
    OPMULTI_01:
	mov ax,di
	dec di
	test ax,ax
	jg OPMULTI_00
    OPMULTI_02:
	pop di
	pop si
	ret
OUTPUT_MULTI ENDP

OUTPUT_STRING PROC
	push di
	push si
	mov si,cx
	mov di,ax
	mov bx,dx
	jmp OPSTR_01
    OPSTR_00:
	mov es,di
	mov al,es:[bx]
	inc bx
	push bx
	cbw
	call OUTPUT_PUTC
	pop bx
	cmp [bp.OP_charsout],-1
	jz OPSTR_02
    OPSTR_01:
	mov ax,si
	dec si
	or ax,ax
	jg OPSTR_00
    OPSTR_02:
	pop si
	pop di
	ret
OUTPUT_STRING ENDP

OUTPUT PROC
	xor ax,ax
	cmp ax,[bp.OP_no_output]
	je OUTPUT_00
	ret
    OUTPUT_00:
	test si,FLAG_SIGNED
	jz OUTPUT_03
	test si,FLAG_NEGATIVE
	jz OUTPUT_01
	mov [bp.OP_prefix],'-'
	mov [bp.OP_prefixlen],1
	jmp OUTPUT_03
    OUTPUT_01:
	test si,FLAG_SIGN
	jz OUTPUT_02
	mov [bp.OP_prefix],43
	mov [bp.OP_prefixlen],1
	jmp OUTPUT_03
    OUTPUT_02:
	test si,FLAG_SIGNSP
	jz OUTPUT_03
	mov [bp.OP_prefix],' '
	mov [bp.OP_prefixlen],1
    OUTPUT_03:
	mov ax,[bp.OP_fldwidth]
	sub ax,[bp.OP_count]
	sub ax,[bp.OP_prefixlen]
	mov [bp.OP_padding],ax
	test si,FLAG_LEFT or FLAG_LEADZERO
	jnz OUTPUT_04
	mov dx,ax
	mov ax,' '
	call OUTPUT_MULTI
    OUTPUT_04:
	mov ax,ss
	lea dx,[bp.OP_prefix]
	mov cx,[bp.OP_prefixlen]
	call OUTPUT_STRING
	test si,FLAG_LEADZERO
	jz OUTPUT_05
	test si,FLAG_LEFT
	jnz OUTPUT_05
	mov ax,'0'
	mov dx,[bp.OP_padding]
	call OUTPUT_MULTI
    OUTPUT_05:
	cmp [bp.OP_count],0
	jng OUTPUT_08
	movmx [bp.OP_ddtemp],[bp.OP_text]
	mov ax,[bp.OP_count]
	mov [bp.OP_dwtemp],ax
	jmp OUTPUT_07
    OUTPUT_06:
	les bx,[bp.OP_ddtemp]
	inc word ptr [bp.OP_ddtemp]
	mov al,es:[bx]
	cbw
	call OUTPUT_PUTC
    OUTPUT_07:
	mov ax,[bp.OP_dwtemp]
	dec [bp.OP_dwtemp]
	or ax,ax
	jg OUTPUT_06
	jmp OUTPUT_09
    OUTPUT_08:
	mov ax,word ptr [bp.OP_text+2]
	mov dx,word ptr [bp.OP_text]
	mov cx,[bp.OP_count]
	call OUTPUT_STRING
    OUTPUT_09:
	test si,FLAG_LEFT
	jz OUTPUT_10
	mov ax,' '
	mov dx,[bp.OP_padding]
	call OUTPUT_MULTI
    OUTPUT_10:
	ret
OUTPUT	ENDP

_TEXT	ENDS

	END
