	page ,132
;	SCCSID = @(#)tprintf.asm	4.3 85/07/02
;	SCCSID = @(#)tprintf.asm	4.3 85/07/02
TITLE	COMMAND Transient Printf routine
;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1991
; *                      All Rights Reserved.
; */

;
;	Revision History
;	================
;
;	M025	SR	9/12/90	Removed calls to SetStdInOn,SetStdInOff
;				SetStdOutOn & SetStdOutOff.
;


;****************************************************************
;*
;* ROUTINE:	STD_PRINTF/STD_EPRINTF
;*
;* FUNCTION:	Set up to print out a message using SYSDISPMSG.
;*		Set up substitutions if utility message.  Make
;*		sure any changes to message variables in TDATA
;*		are reset to avoid reloading the transient.
;*
;* INPUT:	Msg_Disp_Class	-  set to message class
;*		Msg_Cont_Flag	-  set to control flags
;*		DS	points to transient segment
;*
;*		if utility message:
;*		DX	points to a block with message number
;*			(word), number of substitutions (byte),
;*			followed by substitution list if there
;*			are substitutions.  If substitutions
;*			are not in transient segment they must
;*			be set.
;*		else
;*		AX	set to message number
;*
;* OUTPUT:	none
;*
;****************************************************************

.xlist
.xcref
	INCLUDE comsw.asm		;AC000;
	INCLUDE DOSSYM.INC
	INCLUDE comseg.asm
	INCLUDE comequ.asm		;AN000;
	INCLUDE SYSMSG.INC		;AN000;
.list
.cref

datares segment public
	extrn	pipeflag:byte
datares ends

TRANDATA	SEGMENT PUBLIC BYTE	;AC000;
	EXTRN	extend_buf_off:word	;AN000;
	EXTRN	Extend_Buf_ptr:word	;AN000;
	EXTRN	Extend_Buf_seg:word	;AN000;
	EXTRN	Msg_Cont_Flag:byte	;AN000;
	EXTRN	Msg_disp_Class:byte	;AN000;
	EXTRN	pipeemes_ptr:word
TRANDATA	ENDS

TRANSPACE	SEGMENT PUBLIC BYTE	;AC000;
	EXTRN	msg_flag:byte		;AN022;
	EXTRN	print_err_flag:word	;AN000;
	EXTRN	RESSEG:WORD
	EXTRN	String_ptr_2:word	;AC000;
	EXTRN	Subst_buffer:byte	;AN061;
;AD061; EXTRN	String_ptr_2_sb:word	;AN000;

	; include data area for message services

	MSG_UTILNAME <COMMAND>		;AN000; define utility name

	MSG_SERVICES <MSGDATA>		;AN000;

PRINTF_HANDLE	DW  ?			;AC000;

TRANSPACE	ENDS			;AC000;

TRANCODE	SEGMENT PUBLIC BYTE	;AC000;

	EXTRN	cerror:near
	EXTRN	crlf2:near
	EXTRN	tcommand:near		;AN026;

ASSUME	CS:TRANGROUP,DS:TRANGROUP,ES:NOTHING,SS:NOTHING ;AC000;

	PUBLIC	TSYSGETMSG		;AN000;
	PUBLIC	TSYSLOADMSG		;AN000;

PUBLIC Printf_Init
printf_init proc far
	call	std_printf
	ret
printf_init endp

Public	Printf_Crlf
PRINTF_CRLF:
	CALL	STD_PRINTF
	CALL	CRLF2
	RET

PUBLIC	Std_EPrintf
STD_EPRINTF:
	mov	Printf_Handle,2 		;AC000;Print to STDERR
	jmp	short NEW_PRINTF		;AC000;
PUBLIC	Std_Printf
STD_PRINTF:
	mov	Printf_Handle,1 		;AC000;Print to STDOUT

NEW_PRINTF:
	push	ax				;AN000;save registers
	push	bx				;AN000;
	push	cx				;AN000;
	push	es				;AN000;get local ES
	push	ds				;AN000;
	pop	es				;AN000;
	push	di				;AN000;
	push	si				;AN000;
	push	dx				;AN000;
	assume	es:trangroup			;AN000;
;AD061; mov	string_ptr_2_sb,0		;AN000;initialize
	mov	print_err_flag,0		;AN000;

UTILITY_SETUP:
	mov	si,dx				;AN000;Get offset of message number
	lodsw					;AN000;load message number
	push	ax				;AN000;save it
	lodsb					;AN000;get number of substitutions
	mov	cl,al				;AN000;set up CX as # of subst
	xor	ch,ch				;AN000;   SI now points to subst list
	pop	ax				;AN000;get message number back
	cmp	cx,0				;AN000;Any substitutions?
	jz	READY_TO_PRINT			;AN000;No - continue

;AD061;  add	 dx,Ptr_Seg_Pos 		 ;AN000;Point to position of first segment
;AD061;  push	 cx				 ;AN000;save substitution count

;AD061;SET_SUBST:
;AD061;  mov	 bx,dx				 ;AN000;get dx into base register
;AD061;  cmp	 word ptr [bx],0		 ;AN000;has segment been set?
;AD061;  jnz	 SUBST_SEG_SET			 ;AN000;if not 0, don't replace it
;AD061;  test	 word ptr [bx+3],date_type	 ;AN000;if date or time - don't set segment
;AD061;  jnz	 subst_seg_set			 ;AN000;yes - skip it
;AD061;  mov	 word ptr [bx],cs		 ;AN000;put segment of subst parm in list

;AD061;SUBST_SEG_SET:
;AD061;  add	 dx,Parm_Block_Size		 ;AN000;point to position of next segment
;AD061;  loop	 SET_SUBST			 ;AN000;keep replacing until complete
;AD061;  pop	 cx				 ;AN000;

;AD061;NO_REPLACEMENT:
;AD061;  mov	 bx,parm_off_pos [si]		 ;AN000;get subst offset
;AD061;  cmp	 bx,offset trangroup:string_ptr_2 ;AN000;this is used for double indirection
;AD061;  jnz	 ready_to_print 		 ;AN000;we already have address
;AD061;  mov	 dx,string_ptr_2		 ;AN000;get address in string_ptr_2
;AD061;  mov	 parm_off_pos [si],dx		 ;AN000;put proper address in table
;AD061;  mov	 string_ptr_2_sb,si		 ;AN000;save block changed

	mov	di,offset trangroup:subst_buffer;AN061; Get address of message subst buffer
	push	di				;AN061; save it
	push	cx				;AN061; save number of subst

MOVE_SUBST:
	push	cx				;AN061;save number of subst
	mov	bx,si				;AN061;save start of sublist
	mov	cx,parm_block_size		;AN061;get size of sublist
	rep	movsb				;AN061;move sublist
	test	byte ptr [bx.$M_S_FLAG],date_type ;AN061;are we doing date/time?
	jz	move_subst_cont 		;AN061;no - no need to reset
	mov	word ptr [bx.$M_S_VALUE],0	;AN061;reset original date or time to 0
	mov	word ptr [bx.$M_S_VALUE+2],0	;AN061;

MOVE_SUBST_CONT:				;AN061;
	pop	cx				;AN061;get number of subst back
	loop	move_subst			;AN061;move cx sublists

	pop	cx				;AN061;get number of subst
	push	ax				;AN061;save message number
	cmp	Msg_Disp_Class,Util_Msg_Class	;AN061;Is this a utility message
	jz	CHECK_FIX			;AN061;YES - go see if substitutions
	mov	msg_flag,ext_msg_class		;AN061;set message flag
	mov	di,offset trangroup:extend_buf_ptr ;AN061; Get address of extended message block
	xor	ax,ax				;AN061;clear ax register
	stosw					;AN061;clear out message number
	stosb					;AN061;clear out subst count

CHECK_FIX:					;AN061;
	pop	ax				;AN061;get message number back
	pop	di				;AN061;get start of sublists
	mov	si,di				;AN061;get into SI for msgserv
	mov	bx,si				;AN061;get into BX for addressing
	push	cx				;AN061;save number of subst

SET_SUBST:					;AN061;store the segment of the subst
	cmp	word ptr [bx.$M_S_VALUE+2],0	;AN061;was it set already?
	jnz	subst_seg_set			;AN061;if not 0, don't replace it
	test	byte ptr [bx.$M_S_FLAG],date_type ;AN061;don't replace if date or time
	jnz	subst_seg_set			;AN061;yes - skip it
	mov	word ptr [bx.$M_S_VALUE+2],cs	;AN061;set segment value

SUBST_SEG_SET:					;AN061;
	add	bx,parm_block_size		;AN061;go to next sublist
	loop	set_subst			;AN061;loop CX times
	pop	cx				;AN061;get number of subst back

	mov	bx,si				;AN061;get start of sublist to BX
	cmp	word ptr [bx.$M_S_VALUE],offset trangroup:string_ptr_2 ;AN061;are we using double indirection?
	jnz	ready_to_print			;AN061;no - we already have address
	mov	dx,string_ptr_2 		;AN061;get address in string_ptr_2
	mov	word ptr [bx.$M_S_VALUE],dx	;AN061;put it into the subst block

READY_TO_PRINT:
	mov	bx,Printf_Handle		;AN000;get print handle
	mov	dl,Msg_Cont_Flag		;AN000;set up control flag
	mov	dh,Msg_Disp_Class		;AN000;set up display class
	mov	Msg_Cont_Flag,No_Cont_Flag	;AN061;reset flags to avoid
	mov	Msg_Disp_Class,Util_Msg_Class	;AN061;   transient reload

;AD061; push	bx				;AN026; save registers
;AD061; push	cx				;AN026;
;AD061; push	dx				;AN026;
;AD061; push	si				;AN026;
;AD061; push	di				;AN026;
	push	ds				;AN026;
	push	es				;AN026;


	call	SYSDISPMSG			;AN000;call Rod

	pop	es				;AN026; restore registers
	pop	ds				;AN026;
;AD061; pop	di				;AN026;
;AD061; pop	si				;AN026;
;AD061; pop	dx				;AN026;
;AD061; pop	cx				;AN026;
;AD061; pop	bx				;AN026;

	jnc	Print_success			;AN000; everything went okay
	mov	print_err_flag,ax		;AN000;

print_success:
;AD061; cmp	Msg_Disp_Class,Util_Msg_Class	;AN000;Is this a utility message
;AD061; jz	CHECK_FIX			;AN000;YES - go see if substitutions
;AD061; mov	msg_flag,ext_msg_class		;AN022;set message flag
;AD061; mov	di,offset trangroup:extend_buf_ptr ;AN000; Get address of extended message block
;AD061; xor	ax,ax				;AN000;clear ax register
;AD061; stosw					;AN000;clear out message number
;AD061; stosb					;AN000;clear out subst count

;AD061;  CHECK_FIX:
;AD061;  pop	 dx				 ;AN000;restore dx
;AD061;  cmp	 cx,0				 ;AN000;Any substitutions?
;AD061;  jz	 NO_FIXUP			 ;AN000;No - leave

;AD061;  mov	 si,dx				 ;AN000;Reset changes so transient won't reload
;AD061;  add	 si,Ptr_Seg_Pos 		 ;AN000;Point to position of first segment

;AD061;FIX_SUBST:
;AD061;  mov	 word ptr [si],0		 ;AN000;reset segment to 0
;AD061;  add	 si,Parm_Block_Size		 ;AN000;point to position of next segment
;AD061;  loop	 FIX_SUBST			 ;AN000;keep replacing until complete
;AD061;  cmp	 string_ptr_2_sb,no_subst	 ;AN000;was double indirection used?
;AD061;  jz	 no_fixup			 ;AN000;no - we're finished
;AD061;  mov	 si,string_ptr_2_sb		 ;AN000;get offset changed
;AD061;  mov	 parm_off_pos [si],offset trangroup:string_ptr_2 ;AN000; set address back to string_ptr_2

;AD061;NO_FIXUP:
;AD061; mov	Msg_Cont_Flag,No_Cont_Flag	;AN000;reset flags to avoid
;AD061; mov	Msg_Disp_Class,Util_Msg_Class	;AN000;   transient reload
	pop	dx				;AN061;restore dx
	pop	si				;AN000;restore registers
	pop	di				;AN000;
	pop	es				;AN000;restore registers
	pop	cx				;AN000;
	pop	bx				;AN000;
	pop	ax				;AN000;
	cmp	print_err_flag,0		;AN000; if an error occurred - handle it
	jnz	print_err			;AN000;

	ret					;AC000;

print_err:
	push	cs
	pop	es
	cmp	Printf_Handle,2 		;AN026;Print to STDERR?
	jnz	not_stderr			;AN026;no - continue
	jmp	tcommand			;AN026;Yes - hopless - just exit

not_stderr:
	mov	ax,print_err_flag		;AN026;get extended error number back
	mov	es,[resseg]			; No, set up for error, load the
assume	es:resgroup				;  right error msg, and jmp to cerror.
	test	PipeFlag,-1
	jz	go_to_error
	invoke	PipeOff
	mov	dx,offset trangroup:pipeemes_ptr
	jmp	short print_err_exit			;AC000;

go_to_error:
	mov	msg_disp_class,ext_msg_class	;AN000; set up extended error msg class
	mov	dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
	mov	Extend_Buf_ptr,ax		;AN000; get message number in control block

PRINT_ERR_EXIT: 				;AC000;
	push	cs
	pop	es
	JMP	CERROR

;****************************************************************
;*
;* ROUTINE:	TSYSLOADMSG
;*
;* FUNCTION:	Interface to call SYSLOADMSG to avoid duplicate
;*		names since these routines are also used in the
;*		resident.
;*
;* INPUT:	Inputs to SYSLOADMSG
;*
;* OUTPUT:	Outputs from SYSLOADMSG
;*
;****************************************************************


TSYSLOADMSG	PROC	NEAR			;AN000;

	push	bx				;AN000;
	call sysloadmsg 			;AN000; call routine
	pop	bx				;AN000;
	ret					;AN000; exit

TSYSLOADMSG	ENDP				;AN000;

;****************************************************************
;*
;* ROUTINE:	TSYSGETMSG
;*
;* FUNCTION:	Interface to call SYSGETMSG to avoid duplicate
;*		names since these routines are also used in the
;*		resident.
;*
;* INPUT:	Inputs to SYSGETMSG
;*
;* OUTPUT:	Outputs from SYSGETMSG
;*
;****************************************************************


TSYSGETMSG	PROC	NEAR			;AN000;

	push	cx				;AN000;
	call sysgetmsg				;AN000; call routine
	pop	cx				;AN000;
	ret					;AN000; exit

TSYSGETMSG	ENDP				;AN000;

MSG_SERVICES <COMT,NOVERCHECKmsg,NEARmsg,LOADmsg,NOCHECKSTDIN,NOCHECKSTDOUT,GETmsg> ;AC026; The message services
MSG_SERVICES <COMT,NEARmsg,SETSTDIO,DISPLAYmsg,CHARmsg,NUMmsg,TIMEmsg,DATEmsg>	    ;AC026; The message services

PRINTF_LAST LABEL   WORD

include msgdcl.inc


TRANCODE    ENDS
	    END
