;	SCCSID = @(#)msgfout.asm	6.2 91/03/26
;	SCCSID = @(#)msgfout.asm	6.2 91/03/26
PAGE	60,132
;********************************************************************
;   Modification history
;
;4-23	include error2.inc added
;5-21	fix DBCS_PROC routine to write message out when message length = 0
;	and processing malformed DBCS chars.
;6-6	make fixes to support FamilyAPI (3X BOX)
;6-11	make fixes to one centralized GETDBCSEV far call the 1rst time
;	thru, and save DBCS info in global data seg. (ptm 580)
;7-29 fix Family API version, so that 16 bytes of local variables are generated
;8-7  fix ptm 2302 by checking for msglength < 2 when only character is CR
;9-15 fix Family API version, to use RealEnter macro to setup stack frame
;12-11	Add Trace Hooks support in protect mode.
;12-11	changed cmp reg,0 -> or reg,reg to shrink code. (a tiny bit!!)
;12-13	build error: made 'extrn msgtrace:near' protect mode only !!!
;1-27-87 fix dbcs indent problem (do not call nxt_nonbl after writing message,
;	 ONLY if writing caused by CR/LF and message length > 0 !!)
;3-02-87 fix trap 13 problem when 79 chars are in buffer and try to add
;	 cr/lf !! -> so just add a blank and write buffer (ptm2426)
;3-02-87 fix trap 13 problem when 80 chars are in buffer and try to add
;	 blank (due to above fix) in ADD_CR routine
;4-01-87 have automatic data seg of size screen_with, to avoid failing
;	 in low/out of memory conditions.
;10-30-87 add Get/Clear Semaphore around getting and writing into buffer to
;@WWM	 prevent same process/different threads from clobbering the message.
; 2-26-88 Changed DBCS_PROC to not output the lead byte of a message if there
; @@1	  isn't room for the trailing byte.
; 4-20-88 Modified Write_Msg to call Do_Write routine, so that DosPutMessage
; @@2	  can be called from ring 2.
; 6-15-88 Modified WORD_SIZE to get correct size of word if it is terminated by
; @@3	  only a CR (not a CR/LF).  Also fixed DBCS_PROC to not trap if a CR is
;	  the last character in a buffer.  1.2 PTM 1029
; 7-27-88 Changed NXT_NONBL to not skip over CR/LF, unless it's preceeded by
;	  blanks. PTM 2960
; 5-23-89 Removed Pre and Post tracing code. WWM
; 9-24-89 Changed the semaphore to a FSRamSem, and added the exit list routine
; ##1	  to make sure the semaphore is cleared if a thread dies.  PTR AR4454
;10-05-89 Removed ExitList routine because it wasn't necessary.
;
.XALL
.LIST
IFNDEF	FamilyAPI
.286c
ENDIF	;FamilyAPI
TITLE  Message Retriever - DosPutMessage - IBM CONFIDENTIAL
SUBTTL Externals
;/********************** START OF SPECIFICATIONS **********************/
;/*								      */
;/* SOURCE FILE NAME:  MSGFOUT					      */
;/*								      */
;/* DESCRIPTIVE NAME:  FORMAT AND OUTPUT MESSAGE TO HANDLE	      */
;/*								      */
;/* COPYRIGHT: (TOP SOURCE FILE ONLY)				      */
;/*								      */
;/* STATUS: RELEASE 1 LEVEL 0					      */
;/*								      */
;/* FUNCTION:  OUTPUTS THE MESSAGE IN A BUFFER PASSED BY THE CALLER   */
;/*	       TO THE SPECIFIED HANDLE. THE MESSAGE IS FORMATTED TO   */
;/*	       PREVENT WORD WRAPPING.				      */
;/*								      */
;/* NOTES:  SCREEN WIDTH IS ASSUMED TO BE 80 COLUMNS. THAT IS TO      */
;/*	    SAY THAT IF A WORD SPANS COLUMN 80, THE WORD IS STARTED   */
;/*	    IN COLUMN 1 OF THE NEXT LINE.			      */
;/*								      */
;/*	    WORD WRAPPING ALGORITHM ASSUMES THAT THE FIRST CHARACTER  */
;/*	    TO BE WRITTEN WILL APPEAR IN COLUMN 1.		      */
;/*								      */
;/*	    IF THE CHARACTER WRITTEN IN COLUMN 80 IS THE FIRST BYTE   */
;/*	    OF A DOUBLE-BYTE CHARACTER, A SINGLE-BYTE SPACE WILL BE   */
;/*	    INSERTED AND THE DOUBLE-BYTE CHARACTER WILL BE WRITTEN    */
;/*	    AT THE START OF THE NEXT LINE.			      */
;/*								      */
;/*    DEPENDENCIES:  NONE					      */
;/*								      */
;/*    RESTRICTIONS:  NONE					      */
;/*								      */
;/*    PATCH LABEL: (TOP SOURCE FILE ONLY)			      */
;/*								      */
;/* ENTRY POINTS:  DOSPUTMESSAGE				      */
;/*								      */
;/* INTERNAL REFERENCES:					      */
;/*								      */
;/*		  WORD_SIZE - DETERMINE SIZE OF WORD		      */
;/*		  BUFF_ADD - ADD WORD TO BUFFER 		      */
;/*		  ADD_CR - ADD CR/LF TO BUFFER			      */
;/*		  WRITE_MSG - WRITE LOCAL BUFFER TO HANDLE	      */
;/*		  NXT_NONBL - GET NEXT NON-BLANK		      */
;/*		  DBCS_PROC - PROCESS DBCS STRING		      */
;/*|I		  COL_78TH - PROCESS 78TH COLUMN		      */
;/*|I		  BUFF_REFRESH - REFRESH WRITE BUFFER		      */
;/*|I		  CHK_LEAD_BYTE - CHECK FOR LEAD BYTE		      */
;/*								      */
;/* EXTERNAL REFERENCES:  DOSWRITE				      */
;/*			  DOSGETDBCSEV				      */
;/*|H			  DOSALLOCSEG				      */
;/*|H			  DOSFREESEG				      */
;/*								      */
;/*********************** END OF SPECIFICATIONS ***********************/
PAGE
;
;***********************************************************************
; PUBLICS
;***********************************************************************
	PUBLIC	CHK_LEAD_BYTE
	PUBLIC	CHECK_DBCS
	PUBLIC	RESULT		;@@2
IFNDEF FamilyAPI		;##1
	PUBLIC	PutFSRamSem
ENDIF ;FamilyAPI		;##1
;
;***********************************************************************
; EXTERNALS
;***********************************************************************
include dc1segs.inc
;@WWM
IFNDEF	FamilyAPI
initseg SEGMENT
	extrn  GlobalSeg:word			       ; ptr to global segment
	extrn  LocalSeg:word			       ; ptr to local segment
initseg ENDS
ENDIF	;FamilyAPI

	EXTRN	DOSGETDBCSEV:FAR
	EXTRN	DOSWRITE:FAR
;;;;	EXTRN	DOSALLOCSEG:FAR
;;;;	EXTRN	DOSFREESEG:FAR
IFNDEF	FamilyAPI
	extrn	msgtrace:near
	EXTRN	DOSSYSTRACE:FAR
	EXTRN	DOSFSRAMSEMREQUEST:FAR		; @WWM new
	EXTRN	DOSFSRAMSEMCLEAR:FAR		;      new
	EXTRN	DOSCALLBACK:FAR 		;      new
	EXTRN	Do_Write:FAR			;      new
ELSE
	EXTRN	COUNTRY_CODE:DWORD
	EXTRN	FROM_GETMSG:BYTE
ENDIF
;
SUBTTL Includes
	PAGE
;---------------------------------------------------------
; INCLUDES HERE
;---------------------------------------------------------
	INCLUDE msgfequ.inc		;EQUATES
	INCLUDE msgfmac.inc		;MACROS
.XLIST
	INCLUDE error.inc		;ERROR CODES
	INCLUDE error2.inc		;new ERROR CODES
	INCLUDE basemaca.inc		;DOS MACROS
	INCLUDE infoseg.inc		;symbols for Infoseg
	INCL_DOSSEMAPHORES EQU	1	;DOSFSRSEM definition
	INCLUDE bsedos.inc		;DOSFSRSEM defintion
.LIST
;
SUBTTL Data and Code Segment Definitions and Local Variables
	PAGE
;**************************************************************************
; THE FOLLOWING DATA SEGMENT DECLARATION IS USED TO DEFINE THE GLOBAL
; DATA SEGMENT USED FOR NLS CALL
;*****************************************************************************
IFNDEF FamilyAPI
dbcseg	SEGMENT
ELSE
dbcseg	SEGMENT word public 'data'
ENDIF ;FamilyAPI
DBCS_ENV	db	10 dup (0)	;DBCS ENVIRONMENT VECTOR SIZE = 10
CNTRY_CODE	dd	0		;SET COUNTRY CODE
					;INPUT = 0, OUTPUT = CURRENT COUNTRY
;;;;;DCR361
;DBCS_DONE	db	0		;flag: 0= dbcs call not done
;					       1= dbcs call done
;;;;;;;;;;;
dbcseg	ENDS
;**************************************************************************
; THE FOLLOWING DATA SEGMENT DECLARATION IS USED TO DEFINE LOCAL VARIABLES
; 'AT 0' WILL CAUSE THE ASSEMBLER NOT TO GENERATE CODE
;*****************************************************************************
IFNDEF	FamilyAPI
dseg	SEGMENT
ELSE
dseg	SEGMENT word public 'data'      ; ##1
ENDIF	;FamilyAPI
BUFFER		DB	screen_width DUP(0)	;LOCAL BUFFER FOR OUTPUT
						;ASSUME 80 (SCREEN WIDTH)
RESULT		dw	0			;# bytes written by DosWrite, @@2
IFNDEF FamilyAPI
  PutFSRamSem	 DOSFSRSEM <14,0,0,0,0,0>	;intialize to zero  ##1
ENDIF ;FamilyAPI
dseg	ENDS

;;;;;DCR361
iseg	SEGMENT
IFNDEF FamilyAPI
	EXTRN	COUNTRY_CODE:DWORD
	EXTRN	FROM_GETMSG:BYTE
ENDIF ;FamilyAPI
iseg	ENDS
;;;;;;;;;;;
;****************************************************************************
;
code	SEGMENT
	ASSUME	CS:code, ES:dseg
;***************************************************************************
;	DECLARE DOSPUTMESSAGE PUBLIC
;	DECLARE DOSPUTMESSAGE PROC FAR
;***************************************************************************
	PROCEDURE	DOSPUTMESSAGE,FAR
;
;****************************************************************************
;      CREATE MASK FOR PARAMETERS PASSED ON THE STACK
;***************************************************************************
	ARGVAR		MESSAGEBUFFER,DWORD	;MESSAGE BUFFER ADDRESS
	ARGVAR		MESSAGELENGTH,WORD	;MESSAGE LENGTH
	ARGVAR		FILEHANDLE,WORD 	;FILE HANDLE
;****************************************************************************
; END OF PARAMETERS
;****************************************************************************
;******************************************************************************
;	CREATE LOCAL VARIABLE MASK ON THE STACK
;******************************************************************************
;;;;	LOCALVAR	SELECTOR,WORD		;SELECTOR FOR ALLOCATE
	LOCALVAR	BUFF_AVAIL,WORD 	;COUNT OF BYTES AVAILABLE
	LOCALVAR	SYS_ERROR,WORD		;SYSTEM ERROR FIELD
	LOCALVAR	DUMMY_MSG_LEN,WORD	;MESSAGE LENGTH FIELD
	LOCALVAR	BLANK_WORD,BYTE 	;0=NON-BLANK, 1=BLANK WORD (WORD_SIZE)
	LOCALVAR	IS_DOUBLE,WORD		;COLUMN COUNT FOR DOUBLE BYTE CHARACTER
	LOCALVAR	IS_BLNK,WORD		;COLUMN COUNT FOR SINGLE BYTE BLANK
;****************************************************************************
; END OF LOCAL	VARIABLES
;****************************************************************************
SUBTTL DosPutMessage Main Routine
	PAGE
;/********************** START OF SPECIFICATIONS *********************/
;/*								     */
;/* SUBROUTINE NAME:  DOSPUTMESSAGE				     */
;/*								     */
;/* DESCRIPTIVE NAME:  FORMAT AND OUTPUT MESSAGE TO HANDLE MAIN LINE */
;/*		       ROUTINE					     */
;/*								     */
;/* FUNCTION: OUTPUTS THE MESSAGE IN A BUFFER PASSED BY THE CALLER   */
;/*	      TO THE SPECIFIED HANDLE. THE MESSAGE IS FORMATTED TO   */
;/*	      PREVENT WORD WRAPPING.				     */
;/*								     */
;/* NOTES:  NONE						     */
;/*								     */
;/* RESTRICTIONS: NONE						     */
;/*								     */
;/* ENTRY POINT:  DOSPUTMESSAGE 				     */
;/*    LINKAGE:   CALL FAR					     */
;/*								     */
;/* INPUT:  FILEHANDLE	= FILE HANDLE  (WORD)			     */
;/*	    MESSAGELENGTH = MESSAGE LENGTH  (WORD)		     */
;/*	    MESSAGEBUFFER = MESSAGE BUFFER ADDRESS  (DOUBLE WORD)    */
;/*								     */
;/* EXIT-NORMAL:  AX = 0					     */
;/*								     */
;/*								     */
;/* EXIT-ERROR:   AX = ERROR CODE:				     */
;/*								     */
;/*|D ERROR_WRITE_PROTECT  = ATTEMPT TO WRITE TO WRITE PROTECT DISK  */
;/*|D ERROR_INVALID_HANDLE = INVALID FILE HANLDE		     */
;/*|D ERROR_MR_UN_PERFORM  = UNABLE TO PERFORM REQUESTED FUNCTION    */
;/*|D				- OUT OF PAPER			     */
;/*|D				- WRITE OR CRC ERROR		     */
;/*|D				- UNABLE TO ALLOCATE STORAGE	     */
;/*|D				- DRIVE NOT READY		     */
;/*|D				- ETC				     */
;/*								     */
;/* EFFECTS:  NONE						     */
;/*								     */
;/* INTERNAL REFERENCES:					     */
;/*   ROUTINES:   WORD_SIZE - DETERMINE SIZE OF WORD		     */
;/*		  BUFF_ADD - ADD WORD TO BUFFER 		     */
;/*		  ADD_CR - ADD CR/LF TO BUFFER			     */
;/*		  WRITE_MSG - WRITE LOCAL BUFFER TO HANDLE	     */
;/*		  NXT_NONBL - GET NEXT NON-BLANK		     */
;/*		  DBCS_PROC - PROCESS DBCS STRING		     */
;/*								     */
;/* EXTERNAL REFERENCES:					     */
;/*    ROUTINES:						     */
;/*			  DOSGETDBCSEV				     */
;/*|H			  DOSALLOCSEG				     */
;/*|H			  DOSFREESEG				     */
;/*								     */
;/*********************** END OF SPECIFICATIONS **********************/
PAGE
IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI
;
; --------------------------------------------------------
;	SAVE CALLERS ENVIRONMENT
; --------------------------------------------------------
;
	SAVE_CALLER
;
	CLD				;CLEAR DIRECTION FLAG

IFNDEF	FamilyAPI
;****************************
;	Trace hook
;	PreInvocation - DosPutmessage

	push	TraceCode_PrePutMessage
	push	0
	push	messagelength
	push	filehandle
	call	MSGTRACE
;
;****************************
ENDIF	;FamilyAPI

	mov	ax,dseg
	mov	es,ax			;es points to instance data

;;********************************************************************
;@WWM	    CALL DOSFSSEMREQUEST - OBTAIN A Fast, Safe RAM SEMAPHORE
;
IFNDEF	 FamilyAPI			; ##1

	mov	ax, 0FFFFh
	push	dseg			; selector of FS semaphore
	push	offset PutFSRamSem	; offset of FS semaphore
	push	ax			; Indefinite wait (-1 high word)
	push	ax			; Indefinite wait (-1 low word )
	call	DOSFSRAMSEMREQUEST	; OBTAIN FSRAM SEMAPHORE
ENDIF ;FamilyAPI			; ##1

;
;***DT	preDOSPUTMESSAGE - DosPutMessage pre-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_PRE_DOSPUTMESSAGE>,
;	   TP=.PREPUTMSG,
;	   TYPE=(PRE,API),
;	   GROUP = MSG,
;	   DESC="(OS) DosPutMessage Pre-Invocation",
;	   FMT="File Handle = %PW"
;	   FMT="Message Length = %PW",
;	   MEM=(RSS+BP+12,DIRECT,2),
;	   MEM=(RSS+BP+10,DIRECT,2),

	PUBLIC PREPUTMSG

;
; GET CALLERS PARAMETERS
;
CONT_1:
	LDS	SI,MESSAGEBUFFER     ;POINT DS:SI TO CALLERS BUFFER
PREPUTMSG:

;;********************************************************************

;
;
; INITIALIZE LOCAL BUFFER POINTER;
; BUFF_AVAIL = SCREEN_WIDTH
; INITIALIZE IO_ERROR
;
	LEA	DI,BUFFER		     ;ES:DI POINTS TO LOCAL BUFFER
	MOV	BUFF_AVAIL,SCREEN_WIDTH      ;BUFF_AVAIL = SCREEN_WIDTH
	MOV	SYS_ERROR,0
;
; CALL DOSGETDBCSEV - GET DBCS ENVIRONMENT VECTOR;
;
;;;;;DCR361
	PUSH	DS			;Save DS
	MOV	AX,ISEG 		;Get addressability to iseg
	MOV	DS,AX
	ASSUME	DS:ISEG
	MOV	BYTE PTR FROM_GETMSG,0	;clear flag
	mov	ax,dbcseg		;get addressibility to dbcseg
	mov	ds,ax
	assume	ds:dbcseg
	MOV	WORD PTR CNTRY_CODE,0	;set default data
	MOV	WORD PTR CNTRY_CODE+2,0
	POP	DS			;restore DS
	assume	ds:dseg
;;;;;;;;;;;
	CALL   CHECK_DBCS	       ;GET DBCS ENVIRONMENT VECTOR
	jnc    FMT_LOOP 	       ;if not carry, SINGLE BYTE
;
; IF DBCS THEN
;   DO;
;     SAVE DBCS VECTOR;
;     CALL DBCS_PROC - PROCESS DBCS STRING;
;
	CALL	DBCS_PROC		;ELSE DOUBLE BYTE
	JMP	CLEAN_UP		;DONE
;
; DO WHILE MSG_LENGTH > 0 AND I/O_ERROR = 0;
;
FMT_LOOP:
	CMP	MESSAGELENGTH,0
	JNZ	NOT_DONE
	JMP	CLEAN_UP
NOT_DONE:
	CMP	SYS_ERROR,0
	JZ	NO_ERRORx
	JMP	CLEAN_UP
NO_ERRORx:
;
; CALL WORD_SIZE - GET SIZE OF NEXT WORD IN INPUT BUFFER;
;
	CALL	WORD_SIZE
	JNC	NO_CRLF
;
; IF CRLF FLAG SET THEN
;   IF SIZE <= BUFF_AVAIL THEN
;
	CMP	BUFF_AVAIL,AX
	JL	TOO_BIG
;
;    DO;
;      CALL BUFF_ADD - ADD WORD TO LOCAL BUFFER;
;
	CALL	BUFF_ADD
;
;|     IF MESSAGE_LENGTH > 0 THEN
;
	CMP	MESSAGELENGTH,0
	JZ	CLEAN_UP			;IF MSG_LEN=0, DONE
;
;|	DO;
;	  CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CALL	WRITE_MSG
;
;	   BUFF_AVAIL = SCREEN_WIDTH (80)
;
	MOV	BUFF_AVAIL,SCREEN_WIDTH
	JMP	FMT_LOOP
;
;    ELSE
;
TOO_BIG:
;
;     CALL ADD_CR - ADD CR & LF TO LOCAL BUFFER;
;
	CALL	ADD_CR
	JMP	FMT_LOOP
;
;  ELSE
;
NO_CRLF:
;
;    IF SIZE+2 <= BUFF_AVAIL THEN
;
	ADD	AX,2		       ;BUMP SIZE OF AX BY 2
	CMP	BUFF_AVAIL,AX	       ;COMPARE WITH BYTES AVAILABLE
	JL	WORD_TOO_BIG	       ;JUMP IF TOO BIG
	SUB	AX,2		       ;READJUST SIZE
;
;      CALL BUFF_ADD - ADD WORD TO LOCAL BUFFER;
;
	CALL	BUFF_ADD	       ;ADD WORD TO BUFFER
	JMP	FMT_LOOP
;
WORD_TOO_BIG:
;    ELSE
;      CALL ADD_CR - ADD CR & LF TO LOCAL BUFFER;
;
	SUB	AX,2		       ;READJUST SIZE
	CALL	ADD_CR		       ;ADD CR & LF TO BUFFER AND FLUSH
	JMP	FMT_LOOP
;
CLEAN_UP:
;
;;***********************************************************************
;@WWM	    CALL DOSSEMCLEAR - RELEASE RAM SEMAPHORE;
;
IFNDEF	 FamilyAPI			; ##1

	PUSH	dseg			; segment of PutFSRamSem
	PUSH	offset PutFSRamSem	; pass FSRAM semaphore data
	CALL	DOSFSRAMSEMCLEAR	; clear semaphore

ENDIF	;FamilyAPI			; ##1
;@WWM
;;***********************************************************************

GET_RET_CODE:
	MOV	AX,SYS_ERROR		; SET UP ERROR CODE FOR RETURN
;
GET_OUT:

;
;***DT	postDOSPUTMESSAGE - DosPutMessage post-invocation trace point
;
;    TRACE MINOR = <RAS_DC1_POST_DOSPUTMESSAGE>,
;	   TP=.POSTPUTMSG,
;	   TYPE=(POST,API),
;	   GROUP = MSG,
;	   DESC="(OS) DosPutMessage Post-Invocation",
;	   FMT="Return Code = %W",
;	   REGS=(AX),

IFNDEF	FamilyAPI
;****************************
;	Trace hook
;	PostInvocation - DosPutmessage

	push	TraceCode_PostPutMessage
	push	0
	push	0
	push	ax
	call	MSGTRACE
;
;****************************
ENDIF	;FamilyAPI

	PUBLIC POSTPUTMSG
POSTPUTMSG:

	RESTORE_CALLER	8		;RESTORE REGS AND RETURN
DOSPUTMESSAGE	ENDP
;*********************************************************************
SUBTTL Word_Size Routine
	PAGE
;/* ******************** START OF SPECIFICATIONS ********************** */
;/*									*/
;/* SUBROUTINE NAME:  WORD_SIZE 					*/
;/*									*/
;/* DESCRIPTIVE NAME: GET SIZE OF NEXT INPUT BUFFER WORD		*/
;/*									*/
;/* FUNCTION:	      USES CURRENT POINTER TO INPUT BUFFER AND		*/
;/*		      DETERMINES THE SIZE OF THE NEXT "WORD".           */
;/*		      A WORD CAN BE A SERIES OF BLANK OR NON-BLANK	*/
;/*		      CHARACTERS.  A WORD CAN INCLUDE A CR LF AT	*/
;/*		      THE END, REGARDLESS OF WHETHER THE WORD		*/
;/*		      CONTAINS ALL BLANKS OR ALL CHARACTERS.		*/
;/*									*/
;/*  NOTES:								*/
;/*  RESTRICTIONS: NONE 						*/
;/*									*/
;/* ENTRY POINT:      WORD_SIZE 					*/
;/*    LINKAGE:       CALL NEAR 					*/
;/*									*/
;/* INPUT:								*/
;/*		      DS:SI --> CALLERS BUFFER				*/
;/*		      POINTS TO CURRENT BYTE OF CALLERS BUFFER		*/
;/*		      ALL OTHER PREVIOUS BYTES HAVE BEEN PROCESSED	*/
;/*									*/
;/* EXIT-NORMAL:							*/
;/* |L<--	      CFL = 0, AX = LENGTH OF WORD, NO CR & LF		*/
;/* |L<--	      CFL = 1, AX = LENGTH OF WORD, WORD INCLUDES	*/
;/*				    A CR & LF.				*/
;/* EXIT-ERROR: 							*/
;/*									*/
;/* INTERNAL REFERENCES:						*/
;/*    ROUTINES:							*/
;/*									*/
;/* EXTERNAL REFERENCES:						*/
;/*    ROUTINES:							*/
;/*									*/
;/* ********************* END OF SPECIFICATIONS *********************** */
	PAGE
WORD_SIZE	PROC	NEAR
; ESTABLISH CURRENT CHARACTER (CC) - MSG_BUFFER(PTR);
;
	MOV	BL,[SI] 	       ;FETCH CURRENT CHARACTER
;
;| ESTABLISH MESSAGE LENGTH;
;
	MOV	AX,MESSAGELENGTH
	MOV	DUMMY_MSG_LEN,AX
;
; COUNT = 0;
;
	XOR	AX,AX		       ;CLEAR AX FOR COUNT
;
; P = PTR;
;
	PUSH	SI		       ;SAVE SI AND USE AS INDEX P
;
; IF CC = " " THEN
;
	CMP	BL,' '                 ;TEST FOR BLANK
	JNZ	NOT_BLANK	       ;JUMP IF NOT
;
;|  SET BLANK_WORD FLAG;
;
	MOV	BLANK_WORD,1
;
;|  DO WHILE MSG_BUFF(P) = " " AND ML > 0;
;
BLOOP:
	CMP	BYTE PTR [SI],' '       ;TEST FOR BLANK
	JNZ	NON_BLANK
;
;     INCREMENT COUNT;
;
	INC	AX
;
;     INCREMENT P;
;
	INC	SI
;
;|    DECREMENT ML;
;
	DEC	DUMMY_MSG_LEN	     ;DECREMENT ML
	JZ	IS_DONE 		;IF 0, DONE
	JMP	BLOOP
;
NON_BLANK:
	JMP	CLEAR_CR
;
; ELSE
;
NOT_BLANK:
;
;| CLEAR BLANK_WORD FLAG;
;
	MOV	BLANK_WORD,0
;
;|  DO WHILE MSG_BUFF(P) = CHARACTER AND MSG_BUFF(P) *= CR AND ML > 0;
;
NBLOOP:
	CMP	BYTE PTR [SI],' '      ;TEST FOR BLANK
	JZ	IS_BLANK
	CMP	BYTE PTR [SI],CR       ;TEST FOR CR
	JZ	IS_BLANK
;
;     INCREMENT COUNT;
;
	INC	AX
;
;     INCREMENT P;
;
	INC	SI
;
;|    DECREMENT ML;
;
	DEC	DUMMY_MSG_LEN	     ;DECREMENT ML
	JZ	IS_DONE 		;IF 0, DONE
	JMP	NBLOOP
;
IS_BLANK:
CLEAR_CR:
;
; CLEAR CRLF FLAG;
;
	CLC
;
; IF MSG_BUFF(P) = CR THEN
;
	CMP	BYTE PTR [SI],CR
	JNZ	NOT_CR
;
;   DO;
;     if ml < 2
;|    count = count + 1;
;|    ml = ml - 1;
;
	cmp	dummy_msg_len,2
	jae	length_is_2
	inc	ax
	dec	dummy_msg_len	     ;subtract 1 from ml
	jmp	is_done
;
length_is_2:
;   else
;   DO;
;     COUNT = COUNT + 1;
;     IF MSG_BUFF(P) = LF THEN
;	COUNT = COUNT + 1;
;
	inc	ax		     ;@@3
	inc	si
	cmp	byte ptr [si],LF     ;see if next character is a line feed
	jnz	IS_DONE 	     ;not a line feed
	inc	ax		     ;@@3
;
IS_DONE:
;
;     SET CRLF FLAG;
;
	STC
;
;   END;
;
NOT_CR:
	POP	SI
	RET
WORD_SIZE ENDP
;*********************************************************************
SUBTTL Buff_Add Routine
	PAGE
;/********************** START OF SPECIFICATIONS ******************** */
;/*								      */
;/* SUBROUTINE NAME:  BUFF_ADD					      */
;/*								      */
;/* DESCRIPTIVE NAME: ADD WORD TO BUFFER			      */
;/*								      */
;/* FUNCTION:	      USES CURRENT POINTER TO INPUT BUFFER AND ADDS   */
;/*		      THE BYTES FOLLOWING UP TO BUT NOT INCLUDING     */
;/*		      THE NEXT BLANK CHARACTER. 		      */
;/*								      */
;/*  NOTES:							      */
;/*  RESTRICTIONS: NONE 					      */
;/*								      */
;/* ENTRY POINT:      BUFF_ADD					      */
;/*    LINKAGE:       CALL NEAR 				      */
;/*								      */
;/* INPUT:		AX = COUNT OF BYTES TO ADD		      */
;/*			DS:SI --> CALLERS BUFFER		      */
;/*			ES:DI --> LOCAL BUFFER			      */
;/*								      */
;/* EXIT-NORMAL:						      */
;/*								      */
;/* EXIT-ERROR: 						      */
;/*								      */
;/* INTERNAL REFERENCES:					      */
;/*    ROUTINES:      WRITE_MSG - WRITE BUFFER TO HANDLE	      */
;/*								      */
;/* EXTERNAL REFERENCES:					      */
;/*    ROUTINES:						      */
;/*								      */
;/*********************** END OF SPECIFICATIONS ********************* */
	PAGE
BUFF_ADD PROC	NEAR
;
; GET MESSAGE_BUFFER POINTER;
;	POINTER TO MESSAGE BUFFER IN DS:SI
;
; GET LOCAL BUFFER POINTER;
;	POINTER TO LOCAL BUFFER IN ES:DI
;
;   SUBTRACT COUNT FROM BUFF_AVAIL;
;
	SUB	BUFF_AVAIL,AX
	JNC	WORD_FITS			;IF WORD IS > SCREEN_WIDTH
	ADD	BUFF_AVAIL,AX			;THEN ADD IT BACK
	MOV	AX,SCREEN_WIDTH 		;SET WORD LENGTH = SCREEN_WIDTH
	SUB	AX,2				;ALLOW ROOM FOR CR/LF
	SUB	BUFF_AVAIL,AX			;SUBTRACT NEW COUNT FROM BUFF_AVAIL
;
WORD_FITS:
;
;   SUBTRACT COUNT FROM MSG_LENGTH;
;
	SUB	MESSAGELENGTH,AX
;
; DO WHILE COUNT > 0;
;   MOVE BYTE FROM MESSAGE_BUFFER TO LOCAL BUFFER;
;   BUMP POINTERS;
;   DECREMENT COUNT;
;
	MOV	CX,AX
REP	MOVSB
;
; END;
;
; IF MSG_LENGTH = 0 THEN
;   CALL WRITE_MSG - WRITE LOCAL BUFFER TO HANDLE;
;
	CMP	MESSAGELENGTH,0
	JNZ	NO_FLUSH
	CALL	WRITE_MSG
NO_FLUSH:
	RET
BUFF_ADD ENDP
;*********************************************************************
SUBTTL Write_Msg Routine
	PAGE
;/* ******************** START OF SPECIFICATIONS ***********************/
;/*								       */
;/* SUBROUTINE NAME:  WRITE_MSG 				       */
;/*								       */
;/* DESCRIPTIVE NAME: WRITE MESSAGE				       */
;/*								       */
;/* FUNCTION:	      WRITES THE MESSAGE TEXT IN THE LOCAL BUFFER      */
;/*		      TO THE HANDLE PASSED BY THE USER. 	       */
;/*								       */
;/*  NOTES:							       */
;/*  RESTRICTIONS: NONE 					       */
;/*								       */
;/* ENTRY POINT:      WRITE_MSG 				       */
;/*    LINKAGE:       CALL NEAR 				       */
;/*								       */
;/* INPUT:							       */
;/*|L								       */
;/*		      ES:DI = LOCAL BUFFER POINTER		       */
;/*								       */
;/* EXIT-NORMAL:      AX = 0					       */
;/*								       */
;/*								       */
;/* EXIT-ERROR: 						       */
;/*|L		      SYS_ERROR = RETURN CODE			       */
;/*								       */
;/*|D ERROR_WRITE_PROTECT  = ATTEMPT TO WRITE TO WRITE PROTECT DISK    */
;/*|D ERROR_INVALID_HANDLE = INVALID FILE HANLDE		       */
;/*|D ERROR_MR_UN_PERFORM  = UNABLE TO PERFORM REQUESTED FUNCTION      */
;/*|D				- OUT OF PAPER			       */
;/*|D				- WRITE OR CRC ERROR		       */
;/*|D				- UNABLE TO ALLOCATE STORAGE	       */
;/*|D				- DRIVE NOT READY		       */
;/*|D				- ETC				       */
;/*								       */
;/* INTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*								       */
;/* EXTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*    SYSTEM CALLS:  DOSWRITE					       */
;/*								       */
;/* ********************* END OF SPECIFICATIONS ************************/;
	PAGE
WRITE_MSG PROC	NEAR
; CALCULATE LENGTH FOR WRITE;
;
	MOV	CX,SCREEN_WIDTH     ;GET BUFFER LENGTH
	SUB	CX,BUFF_AVAIL	    ;SUBTRACT AVAILABLE BYTES FOR LENGTH
;
; GET CALLERS HANDLE;
;
	MOV	AX,FILEHANDLE	       ;GET HANDLE
;
; GET LOCAL BUFFER ADDRESS;
;
	LEA	DI,BUFFER	       ;GET BUFFER ADDRESS
;
; GET ADDRESS FOR RESULT OF WRITE;
;
	LEA	BX,RESULT	       ;ADDRESS OF RESULT
;
; CALL DOSWRITE;
; *** NOTE: Do_Write routine will no longer be needed when DosWrite can write
;	    to standard out (the screen) when called from ring 2.
;

IFNDEF	FamilyAPI			;@@2
	push	ax			;@@2
	mov	ax,cs			;Use DosCallBack to call Do_Write @@2
	and	ax,3			; if running at ring 2		  @@2
	cmp	ax,3			;@@2
	pop	ax			;@@2
	jz	SKIP_CALLBACK		;@@2
	push	SEG	Do_Write	;@@2
	push	OFFSET	Do_Write	;@@2
	call	DOSCALLBACK		;@@2
	jmp	SKIP_DOSWRITE		;@@2

SKIP_CALLBACK:
	CALL	Do_Write		;DO DOS WRITE

SKIP_DOSWRITE:				;@@2

ELSE
	PUSH	AX			;SAVE HANDLE
	PUSH	ES			;SAVE BUFFER SEGMENT (dseg)
	PUSH	DI			;SAVE BUFFER OFFSET
	PUSH	CX			;SAVE BUFFER LENGTH
	PUSH	ES			;SAVE RESULT SEGMENT (dseg)
	PUSH	BX			;SAVE RESULT OFFSET
	CALL	DOSWRITE		;DO DOS WRITE
ENDIF	;FamilyAPI			;@@2

;
; IF RET CODE = ERROR_WRITE_PROTECT OR RET CODE = ERROR_INVALID_HANDLE THEN
; ELSE RETURN ERROR_MR_UN_PERFORM
;
	or	ax,ax
	JNZ	CHK_W_ERR
;
	CMP	ES:RESULT,CX	; BUG 704 ACTUAL BYTES WRITTEN = BYTES REQUESTED ?
	JZ	SAVE_ERR		;OK
;
CHK_W_ERR:
;
	CMP	AX,ERROR_WRITE_PROTECT
	JZ	SAVE_ERR
	CMP	AX,ERROR_INVALID_HANDLE
	JZ	SAVE_ERR
	MOV	AX,ERROR_MR_UN_PERFORM
SAVE_ERR:
	MOV	SYS_ERROR,AX	     ;SAVE ERROR IF ONE OCCURED
	RET
WRITE_MSG ENDP
;*********************************************************************
SUBTTL Add_Cr Routine
	PAGE
;/* ******************** START OF SPECIFICATIONS ***********************/
;/*								       */
;/* SUBROUTINE NAME:  ADD_CR					       */
;/*								       */
;/* DESCRIPTIVE NAME: ADD CR & LF TO LOCAL BUFFER		       */
;/*								       */
;/* FUNCTION:	      ADDS CARRIAGE RETURN AND LINE FEED TO LOCAL      */
;/*		      BUFFER AND WRITES THE BUFFER TO HANDLE.  IF      */
;/*		      NO ERROR, NXT_NONBL IS CALLED TO FIND NEXT       */
;/*		      NON-BLANK WORD.  IF FOUND, BUFF_ADD IS	       */
;/*		      CALLED TO ADD THAT WORD.			       */
;/*								       */
;/*  NOTES:							       */
;/*  RESTRICTIONS: NONE 					       */
;/*								       */
;/* ENTRY POINT:      ADD_CR					       */
;/*    LINKAGE:       CALL NEAR 				       */
;/*								       */
;/* INPUT:							       */
;/*								       */
;/* EXIT-NORMAL:						       */
;/*								       */
;/* EXIT-ERROR: 						       */
;/*								       */
;/* INTERNAL REFERENCES:					       */
;/*    ROUTINES:      BUFF_ADD - ADD WORD TO BUFFER		       */
;/*		      WRITE_MSG - WRITE LOCAL BUFFER TO HANDLE	       */
;/*|6		      NXT_NONBL - GET NEXT NON BLANK CHARACTER	       */
;/*								       */
;/* EXTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*								       */
;/* ********************* END OF SPECIFICATIONS ************************/
	PAGE
ADD_CR	PROC	NEAR
;
	CMP	BUFF_AVAIL,SCREEN_WIDTH 	;IF BUFFER EMPTY, THEN
	JZ	SKIP_WRITE			;DO NOT WRITE IT OUT
;
	PUSH	AX				;save count
;
	cmp	buff_avail, 1		;if number of free bytes in buffer
	ja	cr_lf			;is > 1, then add cr/lf
	jb	w_buff			;is < 1, then write out buffer as is
	mov	al,' '                  ;else stuff a blank
	stosb				; to end and of buffer
	mov	ax, buff_avail		;get buff_avail
	dec	ax			;dec for blank
	mov	buff_avail,ax		;save it back
	jmp	short w_buff		;go write buffer
;
cr_lf:
;
; ADD CR & LF TO LOCAL BUFFER;
;
	MOV	AX,LF*256+CR	       ;PUT CR,LF IN AX
	STOSW			       ;STORE IT IN BUFFER
;
; ADJUST BUFF_AVAIL;
;
	MOV	AX,BUFF_AVAIL	       ;FETCH BUFF_AVAIL
	SUB	AX,2		       ;SUBTRACT 2 FOR CR LF
	MOV	BUFF_AVAIL,AX	       ;SAVE IT BACK
;
w_buff:
;
; CLEAR I/O_ERROR FLAG;
;
	XOR	AX,AX		       ;CLEAR AX
	MOV	SYS_ERROR,AX	       ;STORE IT IN SYS_ERROR
;
; CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CALL	WRITE_MSG
;
; IF WRITE SUCCEEDED THEN
;
	POP	AX		       ;RESTORE COUNT
	CMP	SYS_ERROR,0
	JNZ	WRITE_ERR
;
;   DO;
;
;
;     BUFF_AVAIL = SCREEN_WIDTH (80)
;
	MOV	BUFF_AVAIL,SCREEN_WIDTH
;
SKIP_WRITE:
;
;|    CALL NXT_NONBL - GET NEXT NON-BLANK CHARACTER;
;
	CALL	NXT_NONBL
;
;|    IF NOT BLANK WORD THEN
;
	CMP	BLANK_WORD,1
	JZ	WRITE_ERR
;
;     CALL BUFF_ADD - ADD WORD TO BUFFER;
;
	CALL	BUFF_ADD
;
;   END;
;
WRITE_ERR:
	RET
ADD_CR	ENDP
;*********************************************************************
SUBTTL Nxt_Nonbl Routine
	PAGE
;/* ******************** START OF SPECIFICATIONS ***********************/
;/*								       */
;/* SUBROUTINE NAME:  NXT_NONBL 				       */
;/*								       */
;/* DESCRIPTIVE NAME: NEXT NON-BLANK				       */
;/*								       */
;/* FUNCTION:	MOVES POINTER TO NEXT NON-BLANK IN CALLERS BUFFER,     */
;/*		SO THAT THE FIRST CHARACTER TO BE WRITTEN IN COLUMN 1  */
;/*		IS NON-BLANK.					       */
;/*								       */
;/*  NOTES:							       */
;/*  RESTRICTIONS: NONE 					       */
;/*								       */
;/* ENTRY POINT:      NXT_NONBL 				       */
;/*    LINKAGE:       CALL NEAR 				       */
;/*								       */
;/* INPUT:							       */
;/*		      DS:SI =  MESSAGE BUFFER POINTER		       */
;/*								       */
;/* EXIT-NORMAL:						       */
;/* |L<--							       */
;/*								       */
;/* EXIT-ERROR: 						       */
;/*								       */
;/* INTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*								       */
;/* EXTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*    SYSTEM CALLS:						       */
;/*								       */
;/* ********************* END OF SPECIFICATIONS ************************/ ;
	PAGE
NXT_NONBL	PROC	NEAR
;
; If first byte is CR, skip to end.
;
	CMP	BYTE PTR [SI],CR       ;If CR, exit
	JZ	NXT_END
;
; DO WHILE MSG_BUFF(PTR) = " " AND MSG_LENGTH > 0;
;
NXT_LOOP:
	CMP	MESSAGELENGTH,0        ;IS LENGTH = 0 ?
	JZ	NXT_END 	       ;IF IT IS, THEN DONE
	CMP	BYTE PTR [SI],' '      ;ELSE, TEST FOR BLANK
	JNZ	NXT_CR		       ;IF NOT BLANK, THEN IS IT CR ?
;
;     INCREMENT PTR;
;     DECREMENT MSG_LENGTH;
;
NOT_ZERO:			       ;YES, IT IS BLANK CHARACTER
	INC	SI
	DEC	MESSAGELENGTH
	JMP	NXT_LOOP
;
; END;
;
NXT_CR:
;
; IF MSG_BUFF(PTR) = CR THEN
;
	CMP	BYTE PTR [SI],CR       ;TEST FOR CR
	JNZ	NXT_END
;
;   DO;
;     Skip past CR/LF, or just CR
;
	INC	SI
	DEC	MESSAGELENGTH
	JZ	NXT_END 		;no more characters in string
	CMP	byte ptr [si],LF	;see if next character is a line feed
	JNZ	NXT_END
	INC	SI
	DEC	MESSAGELENGTH
;
;   END;
; END NXT_NONBL;
;
NXT_END:
	RET
NXT_NONBL	ENDP
;*********************************************************************
SUBTTL DBCS_Proc Routine
	PAGE
;/* ******************** START OF SPECIFICATIONS ***********************/
;/*								       */
;/* SUBROUTINE NAME:  DBCS_PROC 				       */
;/*								       */
;/* DESCRIPTIVE NAME: PROCESS DBCS STRING			       */
;/*								       */
;/* FUNCTION:  COPY MESSAGE TEXT FROM MESSAGE BUFFER TO WRITE BUFFER   */
;/*	       IF DBCS ENVIRONMENT VECTOR RETURNS NON-ZERO INFORMATION.*/
;/*	       FORMATS WRITE BUFFER TO PREVENT DOUBLE-BYTE CHARACTER   */
;/*	       FROM WRAPING ON 80TH COLUMN.			       */
;/*								       */
;/*  NOTES:							       */
;/*  RESTRICTIONS: NONE 					       */
;/*								       */
;/* ENTRY POINT:      DBCS_PROC 				       */
;/*    LINKAGE:       CALL NEAR 				       */
;/*								       */
;/* INPUT:							       */
;/*		      ES:DI =  WRITE BUFFER POINTER		       */
;/*		      DS:SI =  MESSAGE BUFFER POINTER		       */
;/*								       */
;/* EXIT-NORMAL:						       */
;/*								       */
;/* EXIT-ERROR: 						       */
;/*								       */
;/* INTERNAL REFERENCES:					       */
;/*    ROUTINES:      WRITE_MSG - WRITE BUFFER TO HANDLE	       */
;/*|I		      COL_78TH - PROCESS 78TH COLUMN		       */
;/*|I		      BUFF_REFRESH - REFRESH WRITE BUFFER	       */
;/*|I		      CHK_LEAD_BYTE - CHECK FOR LEAD BYTE	       */
;/*								       */
;/* EXTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*    SYSTEM CALLS:						       */
;/*								       */
;/* ********************* END OF SPECIFICATIONS ************************/ ;
	PAGE
DBCS_PROC	PROC	NEAR
; GET DBCS_ENV_VECTOR;
;    POINTER TO DBCS ENVIRONMENT VECTOR IN DBCSEG:DBCS_ENV
;
; GET MESSAGE_BUFFER POINTER;
;    POINTER TO MESSAGE BUFFER IN DS:SI
;
; GET MESSAGE_LENTH;
;    MESSAGE LENGTH IN MESSAGELENGTH
;
; GET WRITE_BUFFER POINTER;
;    POINTER TO WRITE BUFFER IN ES:BUFFER
;
; WRITE_BUFFER_LEN = SCREEN_WIDTH
;    BUFFER LENGTH IN BUFF_AVAIL = SCREEN_WIDTH
;
; IS_DOUBLE = 0;
;
	MOV	IS_DOUBLE,0
;
; IS_BLANK = 0;
;
	MOV	IS_BLNK,0
;
; CC = 0;
;
	XOR	AX,AX
;
; P = 0
;	[SI] = P
;
; INITIALIZE IO_ERROR
;
	MOV	SYS_ERROR,0
;
; DO WHILE MESSAGE_LENGTH > 0 AND NO_IO_ERROR;
;
DB_LOOP:
	CMP	MESSAGELENGTH,0
	JNZ	DB_NOT_DONE
	JMP	DB_CLEAN_UP
DB_NOT_DONE:
	CMP	SYS_ERROR,0
	JZ	DB_NO_ERROR
	JMP	DB_CLEAN_UP
DB_NO_ERROR:
;
;   IF MESSAGE_BUFFER(P) = LEAD BYTE THEN
;
	PUSH	AX			;SAVE COUNT
	MOV	AL,BYTE PTR [SI]	;MOVE CHARACTER IN AL
	CALL	CHK_LEAD_BYTE		;CHECK FOR LEAD BYTE CHAR
	POP	AX			;RESTORE COUNT
	JNC	NOT_DBCS		;JUMP IF NOT LEAD BYTE
;
;      IF WRITE_BUFFER_LEN >=4 THEN
;
	CMP	BUFF_AVAIL,4
	JB	NOT_4
;
;	DO;
;	  IS_DOUBLE = CC;
;
	MOV	IS_DOUBLE,AX
;
;
;	IF MESSAGE_LENGTH >=2 THEN
;
	CMP	MESSAGELENGTH,2
	JB	MALFORMED_DBC
;
;	  MOVE 2 BYTES FROM MESSAGE_BUFFER TO WRITE_BUFFER;
;	  DECREMENT COUNTERS;
;	  BUMP POINTERS;
;
	MOVE_W	  <MESSAGELENGTH>,<BUFF_AVAIL>
	JMP	DB_CHK_DONE
;
;	END;
;|P	ELSE
;|P	  DO;
;
MALFORMED_DBC:
;
;|P	    MOVE 1 BYTE FROM MESSAGE_BUFFER TO WRITE_BUFFER;
;|P	    DECREMENT COUNTERS;
;|P	    BUMP POINTERS;
;
;@@1	MOVSB	If not room for trailing byte, don't output lead byte.
	DEC	MESSAGELENGTH
;@@1	DEC	BUFF_AVAIL
;@@1	INC	AX
;
;|P	  END;
;
DB_CHK_DONE:
;
;|P	  IF MESSAGE_LENGTH = 0 THEN
;|P	    CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CMP	MESSAGELENGTH,0
	JNZ	DB_NOT_FINISHED
	CALL	WRITE_MSG
;
DB_NOT_FINISHED:
	JMP	DB_LOOP
;
NOT_4:
;	 END;
;      ELSE
;	 IF MESSAGE_LENGTH = 2 THEN
;
	CMP	MESSAGELENGTH,2
	JNZ	NOT_2
;
;	   DO;
;	     MOVE 2 BYTES FROM MESSAGE_BUFFER TO WRITE_BUFFER;
;	     DECREMENT COUNTERS;
;	     BUMP POINTERS;
;
	MOVE_W	  <MESSAGELENGTH>,<BUFF_AVAIL>
;
;	     CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CALL	WRITE_MSG
;
;	   END;
;
	JMP	DB_CLEAN_UP
;
NOT_2:
;	 ELSE
;	   DO;
;	     ADD CR/LF;
;
	SUB	BUFF_AVAIL,2		;ACCOUNT FOR CR/LF
	MOV	AX,LF*256+CR		;PUT CR, LF IN AX
	STOSW				;STORE IN IN WRITE BUFFER
;
;	     CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CALL	WRITE_MSG
;
;|	     IF WRITE SUCCESSFUL AND MESSAGE_LENGTH > 0 THEN
;|	     DO;
	CMP	SYS_ERROR,0
	JZ	CONT_2
	JMP	DB_CLEAN_UP
CONT_2:
	CMP	MESSAGELENGTH,0
	JNZ	CONT_3
	JMP	DB_CLEAN_UP
;
CONT_3:
;
;|		      CALL BUFF_REFRESH - REFRESH WRITE BUFFER;
;
	CALL	BUFF_REFRESH
	CALL	NXT_NONBL		; new for dbcs indent fix
;
;|	     END;
;	   END;
;
	JMP	DB_LOOP
;
;
NOT_DBCS:
;
;   ELSE
;|    IF MESSAGE_BUFFER(P) = CR THEN
;|	 DO;
;
	CMP	BYTE PTR [SI],CR
	JNZ	LEN_3
;
;we have a CR, look for a LF
	movsb				;@@3 move CR into our buffer
	inc	ax			;increment count
	dec	BUFF_AVAIL
	dec	MESSAGELENGTH
	jz	DBCS_WRITE		;End of buffer & user doesn't want LF
	push	ax
	mov	al,byte ptr [si]	;Check for lead byte
	call	CHK_LEAD_BYTE
	pop	ax
	jc	DBCS_WRITE
	cmp	byte ptr [si],LF	;Surprise! a LF, put into buffer
	jnz	DBCS_WRITE		;Not a LF, output current string
	movsb				;move LF
	inc	ax
	dec	BUFF_AVAIL
	dec	MESSAGELENGTH		;@@3
;
;|	   CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
DBCS_WRITE:				;@@3
	CALL	WRITE_MSG
;
;|	   IF WRITE SUCCESSFUL AND MESSAGE_LENGTH > 0 THEN
;|	   DO;
;
	CMP	SYS_ERROR,0
	JNZ	DB_CLEAN_UP
	CMP	MESSAGELENGTH,0
	JZ	DB_CLEAN_UP
;
;|		    CALL BUFF_REFRESH - REFRESH WRITE BUFFER;
;
	CALL	BUFF_REFRESH
;
;|	   END;
;|	 END;
;
	JMP	DB_LOOP
;
LEN_3:
;|    ELSE
;      IF WRITE_BUFFER_LEN >=3 THEN
;	DO;
;
	CMP	BUFF_AVAIL,3
	JB	LEN_2
;
;	  IF MESSAGE_BUFFER(P) = " " THEN
;	     IS_BLANK = CC;
;
	CMP	BYTE PTR [SI],' '
	JNZ	SKIP_BL
	MOV	IS_BLNK,AX
;
SKIP_BL:
;	  MOVE 1 BYTE FROM MESSAGE_BUFFER TO WRITE_BUFFER;
;	  DECREMENT COUNTERS;
;	  BUMP POINTERS;
;
	MOVSB
	DEC	MESSAGELENGTH
	DEC	BUFF_AVAIL
	INC	AX
;
;	END;
;
	cmp	messagelength,0 		;check for more chars
	jnz	still_more			;more ? yes

	call	write_msg			;else write message out

still_more:

	JMP	DB_LOOP
;
;
LEN_2:
;
;      ELSE
;	 IF MESSAGE_LENGTH = 2 THEN
;	   DO;
;
	CMP	MESSAGELENGTH,2
	JNZ	LEN_1
;
;	     MOVE 2 BYTES FROM MESSAGE_BUFFER TO WRITE_BUFFER;
;	     DECREMENT COUNTERS;
;	     BUMP POINTERS;
;
	MOVE_W	  <MESSAGELENGTH>,<BUFF_AVAIL>
;
;	     CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CALL	WRITE_MSG
;
;	   END;
;
	JMP	DB_LOOP
;
;	 ELSE
LEN_1:
;	   DO;
;	     PROCESS SINGLE BYTE IN 78TH POSITION (SEE SUBCHART);
;
	CALL	COL_78TH
;
;	     ADD CR/FL;
;
	SUB	BUFF_AVAIL,2		;ACCOUNT FOR CR/LF
	MOV	AX,LF*256+CR		;PUT CR, LF IN AX
	STOSW				;STORE IN IN WRITE BUFFER
;
;	     CALL WRITE_MSG - WRITE LOCAL BUFFER;
;
	CALL	WRITE_MSG
;
;|	     IF WRITE SUCCESSFUL AND MESSAGE_LENGTH > 0 THEN
;
	CMP	SYS_ERROR,0
	JNZ	DB_CLEAN_UP
	CMP	MESSAGELENGTH,0
	JZ	DB_CLEAN_UP
;
;|		   DO;
;|		      CALL BUFF_REFRESH - REFRESH WRITE BUFFER;
;
	CALL	BUFF_REFRESH
	CALL	NXT_NONBL		; new for dbcs indent fix
;
;|		   END;
;|	     END;
;	   END;
	JMP	DB_LOOP
;
;
DB_CLEAN_UP:
	RET
;
; END;
; END DBCS_PROC;
DBCS_PROC	ENDP
;*********************************************************************
SUBTTL Col_78th Routine
	PAGE
;/*| ******************** START OF SPECIFICATIONS ***********************/
;/*|									*/
;/*| SUBROUTINE NAME:  COL_78TH 					*/
;/*|									*/
;/*| DESCRIPTIVE NAME: PROCESS 78TH COLUMN				*/
;/*|									*/
;/*| FUNCTION:	DETERMINES WHAT TO DO WITH THE SINGLE BYTE CHARACTER	*/
;/*|		IN THE 78TH POSITION IN THE WRITE BUFFER.		*/
;/*|									*/
;/*|									*/
;/*|  NOTES:								*/
;/*|  RESTRICTIONS: NONE						*/
;/*|									*/
;/*| ENTRY POINT:      COL_78TH 					*/
;/*|	LINKAGE:       CALL NEAR					*/
;/*|									*/
;/*| INPUT:								*/
;/*|		       ES:DI =	WRITE BUFFER POINTER			*/
;/*|		       DS:SI =	MESSAGE BUFFER POINTER			*/
;/*|									*/
;/*|									*/
;/*| EXIT-NORMAL:							*/
;/*|									*/
;/*| EXIT-ERROR:							*/
;/*|									*/
;/*| INTERNAL REFERENCES:						*/
;/*|	ROUTINES:      CHK_LEAD_BYTE - CHECK FOR LEAD BYTE		*/
;/*|									*/
;/*| EXTERNAL REFERENCES:						*/
;/*|	ROUTINES:							*/
;/*|	SYSTEM CALLS:							*/
;/*|									*/
;/*| ********************* END OF SPECIFICATIONS ************************/ ;
	PAGE
COL_78TH	PROC	NEAR
;
;
	PUSH	AX		;SAVE COUNT
;
; IF MESSAGE_LENGTH > 1 AND MESSAGE_BUFFER(P+1) = " " OR MESSAGE_BUFFER(P+1) =
;	LEAD BYTE THEN;
;
	CMP	MESSAGELENGTH,1
	JBE	COL_END
	CMP	BYTE PTR [SI],' '       ;TEST FOR BLANK
	JZ	COL_END 		;IF BLANK, RETURN
	MOV	AL,BYTE PTR [SI]	;MOVE CHARACTER IN AL
	CALL	CHK_LEAD_BYTE		;CHECK FOR LEAD BYTE CHAR
	JC	COL_END 		;IF LEAD BYTE, RETURN
;
;  ELSE
;    IF IS_BLANK > IS_DOUBLE THEN
;
	MOV	AX,IS_BLNK
	CMP	AX,IS_DOUBLE
	JBE	COL_END
;
;      DO;
;|	    DECREMENT POINTERS BY (CC - IS_BLANK);
;|	    INCREMENT MESSAGE_LENGTH BY (CC - IS_BLANK);
;|	    CC = CC - (CC - IS_BLANK);
;
	POP	AX		;RESTORE COUNT (CC)
	MOV	CX,AX
	SUB	CX,IS_BLNK
	SUB	SI,CX
	SUB	DI,CX
	ADD	MESSAGELENGTH,CX
	ADD	BUFF_AVAIL,CX
	SUB	AX,CX
	PUSH	AX
;
;	    END;
; END 78TH_COLUMN;
COL_END:
	POP	AX		;RESTORE COUNT
	RET
;
COL_78TH	ENDP
;*********************************************************************
SUBTTL Buff_Refresh Routine
	PAGE
;/*| ******************** START OF SPECIFICATIONS ***********************/
;/*|									*/
;/*| SUBROUTINE NAME:  BUFF_REFRESH					*/
;/*|									*/
;/*| DESCRIPTIVE NAME: REFRESH WRITE BUFFER AND FIND NEXT NON BLANK	*/
;/*|									*/
;/*| FUNCTION:	REINITIALIZES LOCAL BUFFER POINTER AND LOCAL BUFFER	*/
;/*|		SIZE. RESETS CURRENT COLUMN (CC) TO ZERO.		*/
;/*|									*/
;/*|  NOTES:								*/
;/*|  RESTRICTIONS: NONE						*/
;/*|									*/
;/*| ENTRY POINT:      BUFF_REFRESH					*/
;/*|	LINKAGE:       CALL NEAR					*/
;/*|									*/
;/*| INPUT:								*/
;/*|		       ES:DI =	WRITE BUFFER POINTER			*/
;/*|		       DS:SI =	MESSAGE BUFFER POINTER			*/
;/*|									*/
;/*|									*/
;/*| EXIT-NORMAL:							*/
;/*|									*/
;/*| EXIT-ERROR:							*/
;/*|									*/
;/*| INTERNAL REFERENCES:						*/
;/*|	ROUTINES:      none						*/
;/*|									*/
;/*| EXTERNAL REFERENCES:						*/
;/*|	ROUTINES:							*/
;/*|	SYSTEM CALLS:							*/
;/*|									*/
;/*| ********************* END OF SPECIFICATIONS ************************/ ;
	PAGE
BUFF_REFRESH	PROC	NEAR
;
;|   REFRESH WRITE_BUFFER;
;
	LEA	DI,BUFFER
;
;|   RE-INITIALIZE WRITE_BUFFER POINTER;
;|   WRITE_BUFFER_LEN = SCREEN_WIDTH
;
	MOV	BUFF_AVAIL,SCREEN_WIDTH
;
;|   CC = 0;
;|   IS_DOUBLE = 0;
;|   IS_BLANK = 0;
;
	XOR	AX,AX
	MOV	IS_DOUBLE,0
	MOV	IS_BLNK,0
;
BL_END:
	RET
;
;| END BUFF_REFRESH;
;
BUFF_REFRESH	ENDP
;*********************************************************************
SUBTTL Chk_Lead_Byte Routine
	PAGE
;/*| ******************** START OF SPECIFICATIONS ***********************/
;/*|									*/
;/*| SUBROUTINE NAME:  CHK_LEAD_BYTE					*/
;/*|									*/
;/*| DESCRIPTIVE NAME: CHECK FOR LEAD BYTE				*/
;/*|									*/
;/*| FUNCTION:	DETERMINES IF CHARACTER IS THE LEAD BYTE OF A DOUBLE	*/
;/*|		BYTE CHARACTER. 					*/
;/*|									*/
;/*|  NOTES:								*/
;/*|									*/
;/*|	VALID LEAD BYTE RANGE FOLLOWING COUNTRIES:  (CURRENTLY DEFINED) */
;/*|									*/
;/*|	JAPAN:	81H-9FH 						*/
;/*|		E0H-FCH 						*/
;/*|									*/
;/*|	KOREAN: 81H-BFH 						*/
;/*|									*/
;/*|	PRC :	81H-FCH 						*/
;/*|									*/
;/*|	TAIWAN: 81H-FCH 						*/
;/*|									*/
;/*|	TABLES TERMINATED BY 2 BYTES OF ZEROES (0,0)			*/
;/*|									*/
;/*|  RESTRICTIONS: NONE						*/
;/*|									*/
;/*| ENTRY POINT:      CHK_LEAD_BYTE					*/
;/*|	LINKAGE:       CALL NEAR					*/
;/*|									*/
;/*| INPUT:								*/
;/*|		       AL = CHARACTER TO TEST				*/
;/*|									*/
;/*| EXIT-NORMAL:      CARRY FLAG CLEAR = SINGLE BYTE			*/
;/*|		       CARRY FLAG SET	= LEAD BYTE			*/
;/*| EXIT-ERROR:							*/
;/*|									*/
;/*| INTERNAL REFERENCES:						*/
;/*|	ROUTINES:							*/
;/*|									*/
;/*| EXTERNAL REFERENCES:						*/
;/*|	ROUTINES:							*/
;/*|	SYSTEM CALLS:							*/
;/*|									*/
;/*| ********************* END OF SPECIFICATIONS ************************/
	PAGE
CHK_LEAD_BYTE	PROC	NEAR
		push	ds
		push	bx
		PUSH	DI			       ;SAVE DI

		mov	bx,dbcseg
		mov	ds,bx
		assume	ds:dbcseg

		XOR	DI,DI			       ;COUNT = 0
;
;| IF CHARACTER >= LOW-RANGE AND CHARACTER <= HI-RANGE THEN
;
LEAD_LOOP:
		CMP	AL,BYTE PTR DBCS_ENV[DI]    ;COMPARE WITH MIN VALUE
		JB	NOTLEAD 		    ;IF < MIN
		INC	DI
		CMP	AL,BYTE PTR DBCS_ENV[DI]    ;COMPARE WITH MAX VALUE
		JBE	ISLEAD			    ;IF <= MAX
		INC	DI
		CMP	WORD PTR DBCS_ENV[DI],0     ;IF END OF RANGE TABLE
		JZ	NOTLEAD 		    ;THEN NOT LEAD BYTE
		JMP	LEAD_LOOP
;
;|     NOT LEAD BYTE;
;
NOTLEAD:
		CLC
		JMP	CHK_END
;
;| ELSE
;|     IS LEAD BYTE;
;
ISLEAD:
		STC
;
;| CHK_LEAD_BYTE END;
;
CHK_END:
		POP	DI		;RESTORE DI
		pop	bx
		pop	ds
		RET
CHK_LEAD_BYTE	ENDP
;*********************************************************************
SUBTTL Check_DBCS Routine
	PAGE
;/*| ******************** START OF SPECIFICATIONS ***********************/
;/*|									*/
;/*| SUBROUTINE NAME:  CHECK_DBCS					*/
;/*|									*/
;/*| DESCRIPTIVE NAME: GET DBCS LEAD BYTE TABLE 			*/
;/*|									*/
;/*| FUNCTION:	CALLS DOSGETDBCSEV TO GET LEAD BYTE RANGE TABLE AND SAVE*/
;/*|		INFORMATION IN GLOBAL DATA AREA.			*/
;/*|									*/
;/*|  NOTES: 1rst time thru, DBCS_DONE flag will be set to 1		*/
;/*|									*/
;/*|  RESTRICTIONS: NONE						*/
;/*|									*/
;/*| ENTRY POINT:      CHECK_DBCS					*/
;/*|	LINKAGE:       CALL NEAR					*/
;/*|									*/
;/*| INPUT:								*/
;/*|		       none						*/
;/*|									*/
;/*| EXIT-NORMAL:      CARRY FLAG CLEAR = SINGLE BYTE			*/
;/*|		       CARRY FLAG SET	= LEAD BYTE TABLE EXISTS (DBCS) */
;/*| EXIT-ERROR:							*/
;/*|									*/
;/*| INTERNAL REFERENCES:						*/
;/*|	ROUTINES:							*/
;/*|									*/
;/*| EXTERNAL REFERENCES:						*/
;/*|	ROUTINES:							*/
;/*|	SYSTEM CALLS:	 DOSGETDBCSEV					*/
;/*|									*/
;/*| ********************* END OF SPECIFICATIONS ************************/
	PAGE
CHECK_DBCS	PROC	NEAR
;
; CALL DOSGETDBCSEV - GET DBCS ENVIRONMENT VECTOR;
;
	push	ds
	push	ax
	push	es

;;;;;DCR361
;	mov	ax,dbcseg
;	mov	ds,ax
;	assume	ds:dbcseg
;
;	check for first time thru ?
;
;	cmp	dbcs_done,1		;if not 1rst time thru
;	jz	dbcs_chk		;then just check contents of lead byte table
;
;	else it is 1rst time and do the GetDBCSev call
;
;	mov	dbcs_done,1		;set dbcs call done !

	MOV	AX,ISEG 		;Get addressability to iseg
	MOV	DS,AX
	ASSUME	DS:ISEG
	mov	ax,dbcseg
	mov	es,ax
	assume	es:dbcseg
	cmp	from_getmsg,0		;check the call from
	jz	skip01			;use default
	mov	ax,word ptr country_code	;set current country ID
	mov	es:word ptr CNTRY_CODE,ax
	mov	ax,word ptr country_code+2	;set current code page
	mov	es:word ptr CNTRY_CODE+2,ax
skip01:
	mov	ax,dbcseg
	mov	ds,ax
	assume	ds:dbcseg
;;;;;;;;;;;
	MOV	AX,size DBCS_ENV	;GET BUFFER LENGTH FOR DBCS VECTOR
	PUSH	AX			;PUSH LENGTH
	LEA	AX,CNTRY_CODE		;GET COUNTRY CODE FOR INPUT
	PUSH	DS			;PUSH SELECTOR
	PUSH	AX			;PUSH OFFSET
	LEA	AX,DBCS_ENV		;GET BUFFER FOR DATA
	PUSH	DS			;PUSH SELECTOR
	PUSH	AX			;PUSH OFFSET
	CALL	DOSGETDBCSEV		;GET DBCS ENVIRONMENT VECTOR
	or	ax,ax			;AX = GOOD
	JNZ	single_b		;IF ERROR, ASSUME: SINGLE BYTE !!!!

;;;;;DCR361
;dbcs_chk:
;;;;;;;;;;;
	CMP	WORD PTR DBCS_ENV,0	;IF FIRST 2 BYTES ARE ZEROES THEN
	JZ	single_b		;SINGLE BYTE
	stc				;else lead byte table exists (DBCS)
	jmp	dbcs_exit

single_b:
	clc

dbcs_exit:
	pop	es
	pop	ax
	pop	ds

		RET
CHECK_DBCS	ENDP
;*********************************************************************
code	ENDS
	END
