;
;	Microsoft Confidential
;	Copyright (C) Microsoft Corporation 1991
;	All Rights Reserved.
;

; * * * * * * * * * * * * START OF SPECIFICATIONS * * * * * * * * * * * * * * *
;
; MODULE NAME: MSGSERV.SAL
;
; DESCRIPTIVE NAME: Message Services SALUT file
;
; FUNCTION: This module incorporates all the messages services and
;	    is called upon at build time to INCLUDE the code requested
;	    by a utility. Code is requested using the macro MSG_SERVICES.
;
; ENTRY POINT: Since this a collection of subroutines, entry point is at
;	    requested procedure.
;
; INPUT: Since this a collection of subroutines, input is dependent on function
;	    requested.
;
; EXIT-NORMAL: In all cases, CARRY FLAG = 0
;
; EXIT-ERROR: In all cases, CARRY FLAG = 1
;
; INTERNAL REFERENCES: (list of included subroutines)
;
;	- SYSLOADMSG
;	- SYSDISPMSG
;	- SYSGETMSG
;
;
; EXTERNAL REFERENCES: None
;
; NOTES: At build time, some modules must be included. These are only included
;	 once using assembler switches. Other logic is included at the request
;	 of the utility.
;
;	 COMR and COMT are assembler switches to conditionally assemble code
;	 for RESIDENT COMMAND.COM and TRANSIENT COMMAND.COM to reduce resident
;	 storage and multiple EQUates.
;
; REVISION HISTORY: Created MAY 1987
;
;     Label: DOS - - Message Retriever
;	     (c) Copyright 1988 Microsoft
;
;
; * * * * * * * * * * * * END OF SPECIFICATIONS * * * * * * * * * * * * * * * *
; Page 

    $SALUT	     $M  (2,5,22,62)			     ;;AN000;; Set SALUT formatting

IF  $M_STRUC						     ;;AN000;; IF we haven't included the structures yet THEN
    $M_STRUC	     =	FALSE				     ;;AN000;;	 Let the assembler know that we have
							     ;;AN000;;	   and include them

    PAGE
    SUBTTL	     DOS - Message Retriever - MSGSTR.INC Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; STRUCTURE: $M_SUBLIST_STRUC
;;
;; Replacable parameters are described by a sublist structure
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_SUBLIST_STRUC STRUC					     ;;AN000;;
							     ;;
    $M_S_SIZE	     DB        11			     ;;AN000;; SUBLIST size  (PTR to next SUBLIST)
    $M_S_RESV	     DB        0			     ;;AN000;; RESERVED
    $M_S_VALUE	     DD        ?			     ;;AN000;; Time, Date or PTR to data item
    $M_S_ID	     DB        ?			     ;;AN000;; n of %n
    $M_S_FLAG	     DB        ?			     ;;AN000;; Data-type flags
    $M_S_MAXW	     DB        ?			     ;;AN000;; Maximum field width
    $M_S_MINW	     DB        ?			     ;;AN000;; Minimum field width
    $M_S_PAD	     DB        ?			     ;;AN000;; Character for Pad field
							     ;;
$M_SUBLIST_STRUC ENDS					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; STRUCTURE: $M_CLASS_ID
;;
;; Each class will be defined by this structure.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_CLASS_ID STRUC					     ;;AN000;;
							     ;;
    $M_CLS_ID	     DB        -1			     ;;AN000;; Class identifer
    $M_COMMAND_VER   DW        EXPECTED_VERSION 	     ;;AN003;; COMMAND.COM version check
    $M_NUM_CLS_MSG   DB        0			     ;;AN000;; Total number of message in class
							     ;;
$M_CLASS_ID ENDS					     ;;
							     ;;AN000;;
    $M_CLASS_ID_SZ   EQU       SIZE $M_CLASS_ID 	     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; STRUCTURE: $M_ID_STRUC
;;
;; Each message will be defined by this structure.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_ID STRUC						     ;;AN000;;
							     ;;
    $M_NUM	     DW        -1			     ;;AN000;; Message Number
    $M_TXT_PTR	     DW        ?			     ;;AN000;; Pointer to message text
							     ;;
$M_ID ENDS						     ;;AN000;;
							     ;;AN000;; Status Flag Values:
    $M_ID_SZ	     EQU       SIZE $M_ID		     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; STRUCTURE: $M_RES_ADDRS
;;
;; Resident data area definition of variables
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_RES_ADDRS STRUC					     ;;AN000;;
							     ;;
    $M_EXT_ERR_ADDRS DD        0			     ;;AN000;; Allow pointers to THREE Extended error locations
    $M_EXT_FILE      DD        0			     ;;AN001;;
    $M_EXT_COMMAND   DD        0			     ;;AN000;;
    $M_EXT_TERM      DD        -1			     ;;AN000;;
    $M_PARSE_COMMAND DD        0			     ;;AN000;;
    $M_PARSE_ADDRS   DD        0			     ;;AN000;; Allow pointers to TWO Parse error locations
    $M_PARSE_TERM    DD        -1			     ;;AN000;;
    $M_CRIT_ADDRS    DD        0			     ;;AN000;; Allow pointers to TWO Critical error locations
    $M_CRIT_COMMAND  DD        0			     ;;AN000;;
    $M_CRIT_TERM     DD        -1			     ;;AN000;;
    $M_DISK_PROC_ADDR DD       -1			     ;;AN004;; Address of READ_DISK_PROC
    $M_CLASS_ADDRS   DD        $M_NUM_CLS DUP(0)	     ;;AN000;; Allow pointers to specified classes
    $M_CLS_TERM      DD        -1			     ;;AN000;;
    $M_DBCS_VEC      DD        0			     ;;AN000;; Save DBCS vector
    $M_HANDLE	     DW        ?			     ;;AN000;;
    $M_SIZE	     DB        0			     ;;AN000;;
    $M_CRLF	     DB        0DH,0AH			     ;;AN004;; CR LF message
    $M_CLASS	     DB        ?			     ;;AN004;; Saved class
    $M_RETURN_ADDR   DW        ?			     ;;AN000;;
    $M_MSG_NUM	     DW        $M_NULL			     ;;AN000;;
    $M_DIVISOR	     DW        10			     ;;AN000;; Default = 10 (must be a WORD for division)
    $M_TEMP_BUF      DB        $M_TEMP_BUF_SZ DUP("$")	     ;;AN000;; Temporary buffer
    $M_BUF_TERM      DB        "$"			     ;;AN000;;

$M_RES_ADDRS ENDS					     ;;AN000;;
							     ;;
$M_RES_ADDRS_SZ EQU  SIZE $M_RES_ADDRS			     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; STRUCTURE: $M_COUNTRY_INFO
;;
;; Important fields of the Get Country Information call
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_COUNTRY_INFO STRUC					     ;;AN000;; Expected Country infomation
							     ;;
    $M_HEADER	     DB       $M_RES_ADDRS_SZ-$M_TEMP_BUF_SZ-1 DUP(?) ;;AN000;; Go past first part of struc
    $M_DATE_FORMAT   DW       ? 			     ;;AN000;; <------- Date Format
    $M_CURR_SEPARA   DB       5 DUP(?)			     ;;AN000;;
    $M_THOU_SEPARA   DB       ?,0			     ;;AN000;; <------- Thou Separator
    $M_DECI_SEPARA   DB       ?,0			     ;;AN000;; <------- Decimal Separator
    $M_DATE_SEPARA   DB       ?,0			     ;;AN000;; <------- Date Separator
    $M_TIME_SEPARA   DB       ?,0			     ;;AN000;; <------- Time Separator
    $M_CURR_FORMAT   DB       ? 			     ;;AN000;;
    $M_SIG_DIGS_CU   DB       ? 			     ;;AN000;;
    $M_TIME_FORMAT   DB       ? 			     ;;AN000;; <------- Time Format
							     ;;
$M_COUNTRY_INFO ENDS					     ;;AN000;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
ELSE							     ;;AN000;;	ELSE if we have already included the STRUCTURES
; 
    $SALUT  $M	(2,5,13,62)				     ;;AN000;;	Set SALUT formatting for code section

    IF	    MSGDATA					     ;;AN000;;	IF this is a request to include the data area
      MSGDATA =  FALSE					     ;;AN000;;	  Let the assembler know not to include it again
							     ;;AN000;;	  and include it
      PAGE
      SUBTTL  DOS - Message Retriever - MSGRES.TAB Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	DATA NAME: $M_RES_TABLE
;;
;;	REFERENCE LABEL: $M_RT
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF    COMR						     ;;AN000;; Since COMMAND.COM includes this twice
      $M_RT   EQU	       $M_RT2			     ;;AN000;;	we must redefine the label so no
      $M_RT2  LABEL  BYTE				     ;;AN000;;	 assembly errors occur
      $M_ALTLABEL = TRUE				     ;;AN000;; Flag that label was changed
ELSE							     ;;AN000;;
      $M_RT   LABEL   BYTE				     ;;AN000;;
ENDIF							     ;;AN000;;
      $M_RES_ADDRS <>					     ;;AN000;; Resident addresses
							     ;;
      include COPYRIGH.INC				     ;;AN001;; Include Copyright 1988 Microsoft
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ENDIF						     ;;AN000;; END of include of Data table

; 
    IF	    NOT  $M_MSGDATA_ONLY			     ;;AN000;; IF this was a request for only the data table THEN
							     ;; 	don't include any more code
							     ;;AN000;; Figure out what other code to include
      IF      DISK_PROC 				     ;;AN003;;	 Is the request to include the READ_DISK code
	IF	COMR					     ;;AN003;;	 (Only Resident COMMAND.COM should ask for it)
	  $M_RT   EQU		   $M_RT2		     ;;AN003;;
	ENDIF
	DISK_PROC = FALSE				     ;;AN003;;	 Yes, THEN include it and reset flag
	PAGE
	SUBTTL	DOS - Message Retriever - DISK_PROC Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: DISK_PROC
;;
;;	FUNCTION: Used in COMMAND.COM if we need to access the Parse or Extended
;;		  errors from disk\diskette
;;	INPUTS: AX has the message number
;;		DX has the message class
;;		AND ... the COMMAND.COM Variable RESGROUP:COMSPEC is
;;		assumed to be set!!
;;
;;	OUTPUTS: ES:DI points to message length (BYTE) followed by text
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
	PUBLIC	READ_DISK_PROC				     ;;
							     ;;
READ_DISK_PROC PROC FAR 				     ;;AN003;;

	PUSH	AX					     ;;AN003;; Save everything
	PUSH	BX					     ;;AN003;;
	PUSH	DX					     ;;AN003;;
	PUSH	SI					     ;;AN003;;
	PUSH	BP					     ;;AN003;;
	PUSH	DS					     ;;AN003;;
	PUSH	DI					     ;;AN003;;
	MOV	BP,AX					     ;;AN003;; Save message number
	MOV	AX,DOS_EXTENDED_OPEN			     ;;AN003;; Set INT 21 function
	LEA	SI,RESGROUP:COMSPEC			     ;;AN003;; Get addressibilty to COMMAND.COM
	PUSH	CS					     ;;AN003;;
	POP	DS					     ;;AN003;;
	MOV	DI,-1					     ;;AN003;; No extended attribute list
	MOV	BX,NO_CRIT_OPEN 			     ;;AN003;; Don't generate critical error
	MOV	DX,NOT_EX_FAIL_EX_OPEN			     ;;AN003;; Open Flag
	INT	21H					     ;;AN003;; Open the file
	POP	DI					     ;;AN003;; Retreive LSEEK pointer
							     ;;AN003;; Error ?
	$IF	NC,LONG 				     ;;AN003;;	No,
	  PUSH	  DI					     ;;AN003;; Save LSEEK pointer
	  MOV	  BX,AX 				     ;;AN003;;	 Set handle in BX
	  MOV	  AX,DOS_LSEEK_FILE			     ;;AN003;;	 LSEEK to the errors
	  XOR	  CX,CX 				     ;;AN003;;	   Value has been set by COMMAND.COM
	  MOV	  DX,DI 				     ;;AN003;;
	  INT	  21H					     ;;AN003;;	 LSEEK the file
	  POP	  DX					     ;;AN003;; Retreive LSEEK pointer
							     ;;AN003;;	 Error ?
	  $IF	  NC					     ;;AN003;;	  No,
	    INC     CX					     ;;AN003;;	   Set flag to first pass
	    $DO 					     ;;AN003;;
	      PUSH    DX				     ;;AN003;;	   Save LSEEK pointer
	      PUSH    CX				     ;;AN003;;	   Save first pass flag
	      PUSH    AX				     ;;AN003;;	   Save number of messages (if set yet)
	      XOR     SI,SI				     ;;AN003;;	   Reset buffer index
	      MOV     AH,DOS_READ_BYTE			     ;;AN003;;	   Read
	      MOV     CX,$M_TEMP_BUF_SZ 		     ;;AN003;;	     the first part of the header
	      LEA     DX,$M_RT.$M_TEMP_BUF		     ;;AN003;;	       into the temp buffer
	      INT     21H				     ;;AN003;;	   Read it
	      MOV     DI,DX				     ;;AN003;;
	      POP     AX				     ;;AN003;;
	      POP     CX				     ;;AN003;;
	      OR      CX,CX				     ;;AN003;;
	      $IF     NZ				     ;;AN003;;
		XOR	CX,CX				     ;;AN003;;	   Set flag to second pass
		XOR	AH,AH				     ;;AN003;;	   Get number of messages in class
		MOV	AL,DS:[DI].$M_NUM_CLS_MSG	     ;;AN003;;
		MOV	SI,$M_CLASS_ID_SZ		     ;;AN003;;	   Initialize index
		CMP	DS:[DI].$M_COMMAND_VER,EXPECTED_VERSION ;;AN003;;  Is this the right version of COMMAND.COM?
	      $ENDIF					     ;;AN003;;
	      POP     DX				     ;;AN003;;
	      $IF     Z 				     ;;AN003;;	   Yes,
		$SEARCH 				     ;;AN003;;
		  CMP	  BP,WORD PTR $M_RT.$M_TEMP_BUF[SI]  ;;AN003;;	     Is this the message I'm looking for?
		$EXITIF Z				     ;;AN003;;	     Yes, (ZF=1)
		  CLC					     ;;AN003;;	      Reset carry, exit search
		$ORELSE 				     ;;AN003;;	     No,  (ZF=0)
		  ADD	  SI,$M_ID_SZ			     ;;AN003;;	      Increment index
		  ADD	  DX,$M_ID_SZ			     ;;AN003;;	      Add offset of first header
		  DEC	  AX				     ;;AN003;;	      Decrement # of messages left
		$LEAVE	Z				     ;;AN003;;	      Have we exhausted all messages?
		  CMP	  SI,$M_TEMP_BUF_SZ-1		     ;;AN003;;	       No, Have we exhausted the buffer?
		$ENDLOOP A				     ;;AN003;;		No, Check next message (ZF=1)
		  STC					     ;;AN003;;	       Yes, (ZF=0) set error (ZF=0)
		$ENDSRCH				     ;;AN003;;
	      $ELSE					     ;;AN003;;	   No,
		XOR	CX,CX				     ;;AN003;;	     Set Zero flag to exit READ Loop
		STC					     ;;AN003;;	     Set Carry
	      $ENDIF					     ;;AN003;;
	    $ENDDO  Z					     ;;AN003;;	       Get next buffer full if needed
							     ;;AN003;; Error ?
	    $IF     NC					     ;;AN003;;	No,
	      MOV     AX,DOS_LSEEK_FILE 		     ;;AN003;;	 Prepare to LSEEK to the specific message
	      XOR     CX,CX				     ;;AN003;;	 Value has been set by COMMAND.COM
	      ADD     DX,$M_CLASS_ID_SZ 		     ;;AN003;;	 Add offset of first header
	      ADD     DX,WORD PTR $M_RT.$M_TEMP_BUF[SI]+2    ;;AN003;;	 Add offset from msg structure
	      INT     21H				     ;;AN003;;	 LSEEK the file
	      MOV     AH,DOS_READ_BYTE			     ;;AN003;;	   Read
	      MOV     CX,$M_TEMP_BUF_SZ 		     ;;AN003;;	     the message
	      LEA     DX,$M_RT.$M_TEMP_BUF		     ;;AN003;;	       into the temp buffer
	      INT     21H				     ;;AN003;;	   Read it
	      MOV     DI,DX				     ;;AN003;;	       into the temp buffer
	      PUSH    DS				     ;;AN003;;	       into the temp buffer
	      POP     ES				     ;;AN003;;	       into the temp buffer
	    $ENDIF					     ;;AN003;;
	  $ENDIF					     ;;AN003;;
	  PUSHF 					     ;;AN003;;	   Close file handle
	  MOV	  AH,DOS_CLOSE_FILE			     ;;AN003;;	   Close file handle
	  INT	  21H					     ;;AN003;;
	  $M_POPF					     ;;AN003;;
	$ENDIF						     ;;AN003;; Yes there was an error,
	POP	DS					     ;;AN003;;
	POP	BP					     ;;AN003;;
	POP	SI					     ;;AN003;;
	POP	DX					     ;;AN003;;
	POP	BX					     ;;AN003;;
	POP	AX					     ;;AN003;;
							     ;;AN003;;	     abort everything
	RET						     ;;AN003;;

READ_DISK_PROC ENDP					     ;;AN003;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      ENDIF						     ;;AN003;; END of include for DISK_PROC
;

      IF      SETSTDIO					     ;;AN000;;	 Is the request to include the code for SETSTDIO
	SETSTDIO = FALSE				     ;;AN000;;	 Yes, THEN include it and reset flag
	PAGE
	SUBTTL	DOS - Message Retriever - SETSTDIO Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: SETSTDIO
;;
;;	FUNCTION:
;;	INPUTS:
;;
;;	OUPUTS:
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF	FARmsg						     ;AN001;
	SETSTDINON PROC FAR				     ;AN001;
ELSE							     ;AN001;
	SETSTDINON PROC NEAR				     ;AN001;
ENDIF							     ;AN001;
	PUSH	AX					     ;AN002; Save changed regs
	PUSH	BX					     ;AN002;
	PUSH	DX					     ;AN002;
	MOV	AX,DOS_IOCTL_GET_INFO			     ;AN001; Get info using IOCTL
	MOV	BX,STDIN				     ;AN001;
	XOR	DX,DX					     ;AN001;
	INT	21H					     ;AN001;

	OR	DH,$M_CRIT_ERR_MASK			     ;AN001; Turn on bit
	MOV	AX,DOS_IOCTL_SET_INFO			     ;AN001; Set info using IOCTL
	INT	21H					     ;AN001;
	POP	DX					     ;AN002; Restore Regs
	POP	BX					     ;AN002;
	POP	AX					     ;AN002;

	RET						     ;AN001;
							     ;AN001;
	SETSTDINON ENDP 				     ;AN001;

IF	FARmsg						     ;AN001;
	SETSTDINOFF PROC FAR				     ;AN001;
ELSE							     ;AN001;
	SETSTDINOFF PROC NEAR				     ;AN001;
ENDIF							     ;AN001;

	PUSH	AX					     ;AN002; Save changed regs
	PUSH	BX					     ;AN002;
	PUSH	DX					     ;AN002;
	MOV	AX,DOS_IOCTL_GET_INFO			     ;AN001; Get info using IOCTL
	MOV	BX,STDIN				     ;AN001;
	XOR	DX,DX					     ;AN001;
	INT	21H					     ;AN001;

	AND	DH,NOT $M_CRIT_ERR_MASK 		     ;AN001; Turn off bit
	MOV	AX,DOS_IOCTL_SET_INFO			     ;AN001; Set info using IOCTL
	INT	21H					     ;AN001;
	POP	DX					     ;AN002; Restore Regs
	POP	BX					     ;AN002;
	POP	AX					     ;AN002;

	RET						     ;AN001;

	SETSTDINOFF ENDP				     ;AN001;

IF	FARmsg						     ;AN001;
	SETSTDOUTON PROC FAR				     ;AN001;
ELSE							     ;AN001;
	SETSTDOUTON PROC NEAR				     ;AN001;
ENDIF							     ;AN001;

	PUSH	AX					     ;AN002; Save changed regs
	PUSH	BX					     ;AN002;
	PUSH	DX					     ;AN002;
	MOV	AX,DOS_IOCTL_GET_INFO			     ;AN001; Get info using IOCTL
	MOV	BX,STDOUT				     ;AN001;
	XOR	DX,DX					     ;AN001;
	INT	21H					     ;AN001;

	OR	DH,$M_CRIT_ERR_MASK			     ;AN001; Turn on bit
	MOV	AX,DOS_IOCTL_SET_INFO			     ;AN001; Set info using IOCTL
	INT	21H					     ;AN001;
	POP	DX					     ;AN002; Restore Regs
	POP	BX					     ;AN002;
	POP	AX					     ;AN002;

	RET						     ;AN001;

	SETSTDOUTON ENDP				     ;AN001;

IF	FARmsg						     ;AN001;
	SETSTDOUTOFF PROC FAR				     ;AN001;
ELSE							     ;AN001;
	SETSTDOUTOFF PROC NEAR
ENDIF							     ;AN001;

	PUSH	AX					     ;AN002; Save changed regs
	PUSH	BX					     ;AN002;
	PUSH	DX					     ;AN002;
	MOV	AX,DOS_IOCTL_GET_INFO			     ;AN001; Get info using IOCTL
	MOV	BX,STDOUT				     ;AN001;
	XOR	DX,DX					     ;AN001;
	INT	21H					     ;AN001;

	AND	DH,NOT $M_CRIT_ERR_MASK 		     ;AN001; Turn off bit
	MOV	AX,DOS_IOCTL_SET_INFO			     ;AN001; Set info using IOCTL
	INT	21H					     ;AN001;
	POP	DX					     ;AN002; Restore Regs
	POP	BX					     ;AN002;
	POP	AX					     ;AN002;

	RET						     ;AN001;

	SETSTDOUTOFF ENDP				     ;AN001;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      ENDIF						     ;;AN000;; END of include for SETSTDIO
; 
      IF      LOADmsg					     ;;AN000;;	 Is the request to include the code for SYSLOADMSG ?
	IF	COMR					     ;;AN000;;
	  $M_RT   EQU		   $M_RT2		     ;;AN000;;
	ENDIF
	LOADmsg = FALSE 				     ;;AN000;;	 Yes, THEN include it and reset flag
	PAGE
	SUBTTL	DOS - Message Retriever - LOADMSG.ASM Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: SYSLOADMSG
;;
;;	FUNCTION:
;;	INPUTS:
;;
;;	OUPUTS:
;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF	FARmsg						     ;;AN000;;
	SYSLOADMSG PROC FAR				     ;;AN000;;
ELSE							     ;;AN000;;
	SYSLOADMSG PROC NEAR				     ;;AN000;;
ENDIF							     ;;AN000;;
	PUSH	AX					     ;;AN000;
	PUSH	BX					     ;;AN000;
	PUSH	DX					     ;;AN000;
	PUSH	ES					     ;;AN000;
	PUSH	DI					     ;;AN000;
	XOR	CX,CX					     ;;AN000;  Reset to zero
	MOV	ES,CX					     ;;AN000;
	XOR	DI,DI					     ;;AN000;
	MOV	AX,DOS_GET_EXT_PARSE_ADD		     ;;AN000;; 2FH Interface
	MOV	DL,DOS_GET_EXTENDED			     ;;AN000;; Where are the Extended errors in COMMAND.COM
	INT	2FH					     ;;AN000;; Private interface
	MOV	WORD PTR $M_RT.$M_EXT_COMMAND+2,ES	     ;;AN000;;	Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_EXT_COMMAND,DI	     ;;AN000;;
							     ;;
	MOV	AX,DOS_GET_EXT_PARSE_ADD		     ;;AN000;; 2FH Interface
	MOV	DL,DOS_GET_PARSE			     ;;AN000;; Where are the Parse errors in COMMAND.COM
	INT	2FH					     ;;AN000;; Private interface
	MOV	WORD PTR $M_RT.$M_PARSE_COMMAND+2,ES	     ;;AN000;;	Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_PARSE_COMMAND,DI	     ;;AN000;;
							     ;;
	MOV	AX,DOS_GET_EXT_PARSE_ADD		     ;;AN000;; 2FH Interface
	MOV	DL,DOS_GET_CRITICAL			     ;;AN000;; Where are the Critical errors in COMMAND.COM
	INT	2FH					     ;;AN000;; Private interface
	MOV	WORD PTR $M_RT.$M_CRIT_COMMAND+2,ES	     ;;AN000;;	Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_CRIT_COMMAND,DI	     ;;AN000;;

	MOV	AX,DOS_GET_EXT_PARSE_ADD		     ;;AN001;; 2FH Interface
	MOV	DL,DOS_GET_FILE 			     ;;AN001;; Where are the FILE dependant in IFSFUNC.EXE
	INT	2FH					     ;;AN001;; Private interface
	MOV	WORD PTR $M_RT.$M_EXT_FILE+2,ES 	     ;;AN001;;	Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_EXT_FILE,DI		     ;;AN001;;

IF	COMR						     ;;  ** Special case for RESIDENT COMMAND.COM
	IF2
	  IFNDEF  READ_DISK_INFO			     ;;AN003;;
	    Extrn   READ_DISK_PROC:Far			     ;;AN003;;
	  ENDIF 					     ;;AN003;;
	ENDIF						     ;;AN003;;
ELSE							     ;;
	IF	FARmsg					     ;;AN000;;
	  CALL	  FAR PTR $M_MSGSERV_1			     ;;AN000;; Get addressibilty to MSGSERV CLASS 1 (EXTENDED Errors)
	ELSE						     ;;AN000;;
	  CALL	  $M_MSGSERV_1				     ;;AN000;; Get addressibilty to MSGSERV CLASS 1 (EXTENDED Errors)
	ENDIF						     ;;AN000;;
	MOV	WORD PTR $M_RT.$M_EXT_ERR_ADDRS+2,ES	     ;;AN000;; Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_EXT_ERR_ADDRS,DI	     ;;AN000;;
	MOV	WORD PTR $M_RT.$M_CRIT_ADDRS+2,ES	     ;;AN000;; Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_CRIT_ADDRS,DI 	     ;;AN000;;
							     ;;
	IF	FARmsg					     ;;AN000;;
	  CALL	  FAR PTR $M_MSGSERV_2			     ;;AN000;; Get addressibilty to MSGSERV CLASS 2 (PARSE Errors)
	ELSE						     ;;AN000;;
	  CALL	  $M_MSGSERV_2				     ;;AN000;; Get addressibilty to MSGSERV CLASS 2 (PARSE Errors)
	ENDIF						     ;;AN000;;
	MOV	WORD PTR $M_RT.$M_PARSE_ADDRS+2,ES	     ;;AN000;; Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_PARSE_ADDRS,DI	     ;;AN000;;
ENDIF							     ;;
							     ;;
	MOV	AX,DOS_GET_EXT_PARSE_ADD		     ;;AN001;; 2FH Interface
	MOV	DL,DOS_GET_ADDR 			     ;;AN001;; Where is the READ_DISK_PROC in COMMAND.COM
	INT	2FH					     ;;AN001;; Private interface
	MOV	WORD PTR $M_RT.$M_DISK_PROC_ADDR+2,ES	     ;;AN001;;	Move into first avaliable table location
	MOV	WORD PTR $M_RT.$M_DISK_PROC_ADDR,DI	     ;;AN001;;

	$M_BUILD_PTRS %$M_NUM_CLS			     ;;AN000;; Build all utility classes
							     ;;AN000;;
	CALL	$M_GET_DBCS_VEC 			     ;;AN000;; Save the DBCS vector

IF	NOT	NOCHECKSTDIN				     ;;AN000;; IF EOF check is not to be suppressed
	CALL	$M_CHECKSTDIN				     ;;AN000;;	 Set EOF CHECK
ENDIF							     ;;AN000;;
							     ;;AN000;;
IF	NOT	NOCHECKSTDOUT				     ;;AN000;; IF Disk Full check is not to be suppressed
	CALL	$M_CHECKSTDOUT				     ;;AN000;;	 Set Disk Full CHECK
ENDIF							     ;;AN000;;
							     ;;AN000;;
IF	NOVERCHECKmsg					     ;;AN000;; IF version check is to be supressed
	CLC						     ;;AN000;;	 Make sure carry is clear
ELSE							     ;;AN000;; ELSE
	PUSH	CX					     ;;AN000;;
	CALL	$M_VERSION_CHECK			     ;;AN000;;	 Check Version
ENDIF							     ;;AN000;;
							     ;;        Error ?
	$IF	NC					     ;;AN000;; No.
IF	  NOT	  NOVERCHECKmsg 			     ;;AN000;;	IF version check was not supressed
	  POP	  CX					     ;;AN000;;	Reset stack
ENDIF							     ;;AN000;;
	  POP	  DI					     ;;AN000;;	Restore REGS
	  POP	  ES					     ;;AN000;;
	  POP	  DX					     ;;AN000;;
	  POP	  BX					     ;;AN000;;
	  POP	  AX					     ;;AN000;;
	$ELSE						     ;;AN000;; Yes,
IF	  NOVERCHECKmsg 				     ;;AN000;;	IF version check is to be supressed
	  ADD	  SP,10 				     ;;AN000;;
	  STC						     ;;AN000;;	Reset carry flag
ELSE							     ;;AN000;;	IF version check is to be supressed
	  ADD	  SP,12 				     ;;AN000;;
	  STC						     ;;AN000;;	Reset carry flag
ENDIF							     ;;AN000;;	IF version check is to be supressed
	$ENDIF						     ;;AN000;;
	RET						     ;;AN000;;
							     ;;
	SYSLOADMSG ENDP 				     ;;AN000;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	PAGE
	SUBTTL	DOS - Message Retriever - $M_VERSION_CHECK Proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Proc Name:	$M_GET_DBCS_VEC
;;
;;  Function:	Get the DBCS vector and save it for later use
;;
;;  Inputs:	None
;;
;;  Outputs:	None
;;
;;  Regs Changed:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_GET_DBCS_VEC PROC NEAR				     ;;AN000;;
							     ;;
	PUSH	AX					     ;;AN000;; Save character to check
	PUSH	SI					     ;;AN000;;
	PUSH	DS					     ;;AN000;;
	MOV	AX,DOS_GET_DBCS_INFO			     ;;AN000;; DOS function to get DBSC environment
	INT	21H					     ;;AN000;; Get environment pointer
	PUSH	DS					     ;;AN000;; Get environment pointer
	POP	ES					     ;;AN000;; Get environment pointer
	POP	DS					     ;;AN000;; Get environment pointer
	$IF	NC					     ;;AN000;;
	  MOV	  WORD PTR $M_RT.$M_DBCS_VEC,SI 	     ;;AN000;; Save DBCS Vector
	  MOV	  WORD PTR $M_RT.$M_DBCS_VEC+2,ES	     ;;AN000;;
	$ENDIF						     ;;AN000;;
	POP	SI					     ;;AN000;;
	POP	AX					     ;;AN000;; Retrieve character to check
	RET						     ;;AN000;; Return
							     ;;
$M_GET_DBCS_VEC ENDP					     ;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	IF	NOCHECKSTDIN				     ;AN001; Are we suppose to include the code for Checking EOF ?
	ELSE						     ;AN001; Yes, THEN include it
	  PAGE
	  SUBTTL  DOS - Message Retriever - $M_CHECKSTDIN Proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Proc Name:	$M_CHECKSTDIN
;;
;;  Function:
;;
;;  Inputs:	None
;;
;;  Outputs:
;;
;;  Regs Changed:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_CHECKSTDIN PROC NEAR 				     ;AN001;

	  MOV	  AX,DOS_IOCTL_GET_INFO 		     ;AN001; Get info using IOCTL
	  MOV	  BX,STDIN				     ;AN001;
	  XOR	  DX,DX 				     ;AN001;
	  INT	  21H					     ;AN001;

	  OR	  DH,$M_CRIT_ERR_MASK			     ;AN001; Turn on bit
	  MOV	  AX,DOS_IOCTL_SET_INFO 		     ;AN001; Set info using IOCTL
	  INT	  21H					     ;AN001;

	  RET						     ;AN001;

$M_CHECKSTDIN ENDP					     ;AN001;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ENDIF						     ;AN001; END of include for EOF Check
	IF	NOCHECKSTDOUT				     ;AN001; Are we suppose to include the code for Checking Disk Full?
	ELSE						     ;AN001; Yes, THEN include it
	  PAGE
	  SUBTTL  DOS - Message Retriever - $M_CHECKSTDOUT Proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Proc Name:	$M_CHECKSTDOUT
;;
;;  Function:
;;
;;  Inputs:	None
;;
;;  Outputs:
;;
;;  Regs Changed:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_CHECKSTDOUT PROC NEAR				     ;AN001;

	  MOV	  AX,DOS_IOCTL_GET_INFO 		     ;AN001; Get info using IOCTL
	  MOV	  BX,STDOUT				     ;AN001;
	  XOR	  DX,DX 				     ;AN001;
	  INT	  21H					     ;AN001;

	  OR	  DH,$M_CRIT_ERR_MASK			     ;AN001; Turn on bit
	  MOV	  AX,DOS_IOCTL_SET_INFO 		     ;AN001; Set info using IOCTL
	  INT	  21H					     ;AN001;

	  RET						     ;AN001;

$M_CHECKSTDOUT ENDP					     ;AN001;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ENDIF						     ;AN001;  END of include for Disk Full Check
	IF	NOVERCHECKmsg				     ;;AN000;; Are we suppose to include the code for DOS version check?
	ELSE						     ;;AN000;; Yes, THEN include it
	  PAGE
	  SUBTTL  DOS - Message Retriever - $M_VERSION_CHECK Proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Proc Name:	$M_VERSION_CHECK
;;
;;  Function:	Determine if DOS version is within allowable limits
;;
;;  Inputs:	None
;;
;;  Outputs:	CARRY_FLAG = 1 if Incorrect DOS version
;;		Registers set for SYSDISPMSG
;;		CARRY_FLAG = 0 if Correct DOS version
;;
;;  Regs Changed: AX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_VERSION_CHECK PROC NEAR				     ;;AN000;;
							     ;;
	  MOV	  AH,DOS_GET_VERSION			     ;;AN000;; Check that version matches VERSIONA.INC
	  INT	  21H					     ;;AN000;;
							     ;;
	  CMP	  AX,EXPECTED_VERSION			     ;;AN000;; IF DOS_MAJOR is correct
	  $IF	  E					     ;;AN000;;
	    CLC 					     ;;AN000;;	 Clear the carry flag
	  $ELSE 					     ;;AN000;; ELSE
IF	    NOT     COMR				     ;;  ** Special case for RESIDENT COMMAND.COM
	    CMP     AX,LOWEST_4CH_VERSION		     ;;AN000;; Does this version support AH = 4CH
	    $IF     B					     ;;AN000;; No,
	      MOV     BX,NO_HANDLE			     ;;AN000;;	 No handle (version doesn't support)
	    $ELSE					     ;;AN000;; Yes,
	      MOV     BX,STDERR 			     ;;AN000;;	 Standard Error
	    $ENDIF					     ;;AN000;;
ELSE
	    MOV     BX,NO_HANDLE			     ;;AN000;;	 No handle
ENDIF
	    MOV     AX,1				     ;;AN000;; Set message # 1
	    MOV     CX,NO_REPLACE			     ;;AN000;; No replacable parms
	    MOV     DL,NO_INPUT 			     ;;AN000;; No input
	    MOV     DH,UTILITY_MSG_CLASS		     ;;AN000;; Utility class message
	    STC 					     ;;AN000;; Set Carry Flag
	  $ENDIF					     ;;AN000;;
							     ;;
	  RET						     ;;AN000;; Return
							     ;;
$M_VERSION_CHECK ENDP					     ;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ENDIF						     ;;AN000;; END of include for DOS version check
      ENDIF						     ;;AN000;; END of include for SYSLOADMSG
; 
      IF      GETmsg					     ;;AN000;; Is the request to include the code for SYSGETMSG ?
	IF	COMR					     ;;AN000;;
	  $M_RT   EQU		   $M_RT2		     ;;AN000;;
	ENDIF						     ;;AN000;;
	GETmsg	=      FALSE				     ;;AN000;; Yes, THEN include it and reset flag
	PAGE
	SUBTTL	DOS - Message Retriever - GETMSG.ASM Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Proc Name:	SYSGETMSG
;;
;;  Function:	The GET service returns the segment, offset and size of the
;;		message text to the caller based on a message number.
;;		The GET function will not display the message thus assumes
;;		caller will handle replaceable parameters.
;;
;;  Inputs:
;;
;;  Outputs:
;;
;;  Psuedocode:
;;		Call $M_GET_MSG_ADDRESS
;;		IF MSG_NUM exists THEN
;;		   Set DS:SI = MSG_TXT_PTR + 1
;;		   CARRY_FLAG = 0
;;		ELSE
;;		   CARRY_FLAG = 1
;;		ENDIF
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF	FARmsg						     ;;AN000;;
	SYSGETMSG PROC	FAR				     ;;AN000;;
ELSE							     ;;AN000;;
	SYSGETMSG PROC	NEAR				     ;;AN000;;
ENDIF							     ;;AN000;;
							     ;;
;; Save registers needed later

	PUSH	AX					     ;;AN000;; Save changed regs
	PUSH	ES					     ;;AN000;;
	PUSH	DI					     ;;AN000;;
	PUSH	BP					     ;;AN000;;
							     ;;
IF	FARmsg						     ;;AN000;;
	CALL	FAR PTR $M_GET_MSG_ADDRESS		     ;;AN000;; Scan thru classes to find message
ELSE							     ;;AN000;;
	CALL	$M_GET_MSG_ADDRESS			     ;;AN000;; Scan thru classes to find message
ENDIF							     ;;AN000;; Return message in ES:DI
	$IF	NC					     ;;AN000;; Message found?
	  CMP	  DH,UTILITY_MSG_CLASS
	  CLC						     ;;AN000;;
	  $IF	  NE
	    PUSH    ES					     ;;AN000;;
	    POP     DS					     ;;AN000;;	   Return message in DS:SI
	  $ELSE
IF	    FARmsg					     ;;AN000;;	 Yes,
	    PUSH    ES					     ;;AN000;;
	    POP     DS					     ;;AN000;;	   Return message in DS:SI
ELSE							     ;;AN000;;
	    PUSH    CS					     ;;AN000;;	   Return message in DS:SI
	    POP     DS					     ;;AN000;;
ENDIF							     ;;AN000;;
	  $ENDIF					     ;;AN000;;
	  MOV	  SI,DI 				     ;;AN000;;	   Return message in DS:SI
	$ENDIF						     ;;AN000;;
							     ;;
	POP	BP					     ;;AN000;; Restore changed regs
	POP	DI					     ;;AN000;;
	POP	ES					     ;;AN000;;
	POP	AX					     ;;AN000;;
							     ;;
	RET						     ;;AN000;;	  Return
							     ;;
	SYSGETMSG ENDP					     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	IF	$M_SUBS 				     ;;AN000;; Include the common subroutines if they haven't yet
	  $M_SUBS = FALSE				     ;;AN000;; No, then include and reset the flag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_GET_MSG_ADDRESS
;;
;;	FUNCTION:  To scan thru classes to return pointer to the message header
;;	INPUTS:    Access to $M_RES_ADDRESSES
;;	OUPUTS:    IF CX = 0 THEN Message was not found
;;		   IF CX > 1 THEN ES:DI points to the specified message
;;	REGS CHANGED: ES,DI,CX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF	  FARmsg					     ;;AN000;;
	  $M_GET_MSG_ADDRESS PROC FAR			     ;;AN000;;
ELSE							     ;;AN000;;
	  $M_GET_MSG_ADDRESS PROC NEAR			     ;;AN000;;
ENDIF							     ;;AN000;;
							     ;;
	  PUSH	  SI					     ;;AN000;;
	  PUSH	  BX					     ;;AN000;;
	  XOR	  SI,SI 				     ;;AN000;; Use SI as an index
	  XOR	  CX,CX 				     ;;AN000;; Use CX as an size
	  $DO						     ;;AN000;;
	    CMP     DH,UTILITY_MSG_CLASS		     ;;AN000;; Were utility messages requested?
	    $IF     E					     ;;AN000;; Yes,
	      IF      FARmsg				     ;;AN000;;
		LES	DI,DWORD PTR $M_RT.$M_CLASS_ADDRS[SI] ;;AN000;;  Get address of class
		MOV	BX,ES				     ;;AN000;
	      ELSE					     ;;AN000;;
		MOV	DI,WORD PTR $M_RT.$M_CLASS_ADDRS[SI] ;;AN000;;	 Get address of class
		MOV	BX,DI				     ;;AN000;
	      ENDIF					     ;;AN000;;
	    $ELSE					     ;;AN000;; No,
	      TEST    DH,PARSE_ERR_CLASS		     ;;AN000;;	 Were parse errors requested?
	      $IF     NE				     ;;AN000;;	 Yes,
		LES	DI,DWORD PTR $M_RT.$M_PARSE_COMMAND[SI] ;;AN000;;   Get address of class
		MOV	BX,ES				     ;;AN000;
	      $ELSE					     ;;AN000;;	 No, extended errors were specified
		CMP	AX,$M_CRIT_LO			     ;;AN000;;	   Is this a critical error?
		$IF	AE,AND				     ;;AN000;;
		CMP	AX,$M_CRIT_HI			     ;;AN000;;
		$IF	BE				     ;;AN000;;	    Yes,
		  LES	  DI,DWORD PTR $M_RT.$M_CRIT_ADDRS[SI] ;;AN000;; Get address of class
		  MOV	  BX,ES 			     ;;AN000;
		$ELSE					     ;;AN000;;
		  LES	  DI,DWORD PTR $M_RT.$M_EXT_ERR_ADDRS[SI] ;;AN000;; Get address of class
		  MOV	  BX,ES 			     ;;AN000;
		$ENDIF					     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
							     ;;
	    CMP     BX,$M_TERMINATING_FLAG		     ;;AN000;; Are we finished all classes?
	    $IF     E					     ;;AN000;; Yes,
	      CMP     DH,UTILITY_MSG_CLASS		     ;;AN000;;	  Was it a UTILITY class?
	      $IF     E 				     ;;AN000;;	  Yes,
		STC					     ;;AN000;;	    Set the carry flag
	      $ELSE					     ;;AN000;;	  No,
		MOV	$M_RT.$M_MSG_NUM,AX		     ;;AN000;;	    Save message number
		MOV	AX,$M_SPECIAL_MSG_NUM		     ;;AN000;;	    Set special message number
		MOV	BP,$M_ONE_REPLACE		     ;;AN000;;	    Set one replace in message
		XOR	SI,SI				     ;;AN000;;	    Reset the SI index to start again
		CLC					     ;;AN000;;
	      $ENDIF					     ;;AN000;; No,
	    $ELSE					     ;;AN000;;
	      CMP     BX,$M_CLASS_NOT_EXIST		     ;;AN000;;	 Does this class exist?
	      $IF     NE				     ;;AN001;;	 Yes,
		CALL	$M_FIND_SPECIFIED_MSG		     ;;AN000;;	   Try to find the message
	      $ENDIF					     ;;AN000;;
	      ADD     SI,$M_ADDR_SZ_FAR 		     ;;AN000;;	     Get next class
	      CLC					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	  $LEAVE  C					     ;;AN000;;
	    OR	    CX,CX				     ;;AN000;;	   Was the message found?
	  $ENDDO  NZ,LONG				     ;;AN000;;

	  PUSHF 					     ;;AN006;; Save the flag state
	  CMP	  DH,EXT_ERR_CLASS			     ;;AN006;; Was an extended error requested?
	  $IF	  E					     ;;AN006;; Yes,
	    PUSH    DX					     ;;AN006;;	Save all needed registers
	    PUSH    BP					     ;;AN006;;
	    PUSH    CX					     ;;AN006;;
	    PUSH    ES					     ;;AN006;;
	    PUSH    DI					     ;;AN006;;
	    PUSH    AX					     ;;AN006;;

	    MOV     AX,IFSFUNC_INSTALL_CHECK		     ;;AN006;;	Check if IFSFUNC is installed
	    INT     2FH 				     ;;AN006;;
	    CMP     AL,IFSFUNC_INSTALLED		     ;;AN006;;	Is it installed?
	    POP     AX					     ;;AN006;;	Restore msg number
	    $IF     E					     ;;AN006;;	 Yes,
	      MOV     BX,AX				     ;;AN006;;	  BX is the extended error number
	      MOV     AX,IFS_GET_ERR_TEXT		     ;;AN006;;	  AX is the muliplex number
	      INT     2FH				     ;;AN006;;	  Call IFSFUNC
	    $ELSE					     ;;AN006;;	 No,
	      STC					     ;;AN006;;	  Carry conditon
	    $ENDIF					     ;;AN006;;

	    $IF     C					     ;;AN006;;	Was there an update?
	      POP     DI				     ;;AN006;;	No,
	      POP     ES				     ;;AN006;;	 Restore old pointer
	      POP     CX				     ;;AN006;;
	    $ELSE					     ;;AN006;;	Yes
	      ADD     SP,6				     ;;AN006;;	 Throw away old pointer
	      CALL    $M_SET_LEN_IN_CX			     ;;AN006;;	 Get the length of the ASCIIZ string
	    $ENDIF					     ;;AN006;;
	    POP     BP					     ;;AN006;;	Restore other Regs
	    POP     DX					     ;;AN006;;
	  $ENDIF					     ;;AN006;;
	  $M_POPF					     ;;AN006;; Restore the flag state

	  POP	  BX					     ;;AN000;;
	  POP	  SI					     ;;AN000;;
	  RET						     ;;AN000;; Return ES:DI pointing to the message
							     ;;
$M_GET_MSG_ADDRESS ENDP 				     ;;
							     ;;
$M_SET_LEN_IN_CX PROC NEAR				     ;;
							     ;;
	  PUSH	  DI					     ;;AN006;; Save position
	  PUSH	  AX					     ;;AN006;;
	  MOV	  CX,-1 				     ;;AN006;; Set CX for decrements
	  XOR	  AL,AL 				     ;;AN006;; Prepare compare register
	  REPNE   SCASB 				     ;;AN006;; Scan for zero
	  NOT	  CX					     ;;AN006;; Change decrement into number
	  DEC	  CX					     ;;AN006;; Don't include the zero
	  POP	  AX					     ;;AN006;;
	  POP	  DI					     ;;AN006;; Restore position
	  RET						     ;;AN006;;
							     ;;
$M_SET_LEN_IN_CX ENDP					     ;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_FIND_SPECIFIED_MSG
;;
;;	FUNCTION:  To scan thru message headers until message is found
;;	INPUTS:    ES:DI points to beginning of msg headers
;;		   CX contains the number of messages in class
;;		   DH contains the message class
;;	OUPUTS:    IF CX = 0 THEN Message was not found
;;		   IF CX > 1 THEN ES:DI points to header of specified message
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_FIND_SPECIFIED_MSG PROC NEAR 			     ;;AN000;;
							     ;;
	  CMP	  BX,1					     ;;AN004;;	Do we have an address to CALL?
	  $IF	  E,AND 				     ;;AN004;;	Yes,
	  CMP	  WORD PTR $M_RT.$M_DISK_PROC_ADDR,-1	     ;;AN004;;	Do we have an address to CALL?
	  $IF	  NE					     ;;AN004;;	Yes,
	    CMP     AX,$M_SPECIAL_MSG_NUM		     ;;AN004;; Are we displaying a default Ext Err?
	    $IF     E					     ;;AN004;;	. . . and . . .
	      PUSH    AX				     ;;AN004;;	 Reset the special message number
	      MOV     AX,$M_RT.$M_MSG_NUM		     ;;AN004;;	 Get the old message number
	      CALL    DWORD PTR $M_RT.$M_DISK_PROC_ADDR      ;;AN004;;	 Call the READ_DISK_PROC to get error text
	      POP     AX				     ;;AN004;;	 Reset the special message number
	    $ELSE					     ;;AN004;;	 Get the old message number
	      CALL    DWORD PTR $M_RT.$M_DISK_PROC_ADDR      ;;AN004;;	 Call the READ_DISK_PROC to get error text
	    $ENDIF					     ;;AN004;;	 Get the old message number
	  $ELSE 					     ;;AN004;;
	    XOR     CX,CX				     ;;AN002;;	 CX = 0 will allow us to
	    CMP     DH,UTILITY_MSG_CLASS		     ;;AN001;;
	    $IF     NE					     ;;AN001;;
	      MOV     CL,BYTE PTR ES:[DI].$M_NUM_CLS_MSG     ;;AN001;;	 Get number of messages in class
	    $ELSE					     ;;AN001;;
IF	      FARmsg					     ;;AN001;;
	      CMP     BYTE PTR ES:[DI].$M_CLASS_ID,DH	     ;;AN002;; Check if class still exists at
ELSE
	      CMP     BYTE PTR CS:[DI].$M_CLASS_ID,DH	     ;;AN002;; Check if class still exists at
ENDIF
	      $IF     E 				     ;;AN002;;	pointer (hopefully)
IF		FARmsg					     ;;AN001;;
		MOV	CL,BYTE PTR ES:[DI].$M_NUM_CLS_MSG   ;;AN000;;	   Get number of messages in class
ELSE
		MOV	CL,BYTE PTR CS:[DI].$M_NUM_CLS_MSG   ;;AN000;;	   Get number of messages in class
ENDIF
	      $ENDIF					     ;;AN002;;	  go on to the next class
	    $ENDIF					     ;;AN001;;
	    ADD     DI,$M_CLASS_ID_SZ			     ;;AN000;;	   Point past the class header
	    STC 					     ;;AN004;;	 Flag that we haven't found anything yet
	  $ENDIF					     ;;AN004;;

	  $IF	  C					     ;;AN004;; Have we found anything yet?
	    CLC 					     ;;AN004;; No, reset carry
	    $SEARCH					     ;;AN000;;
	      OR      CX,CX				     ;;AN000;;	  Do we have any to check?
	    $LEAVE  Z					     ;;AN000;;	     No, return with CX = 0
	      CMP     DH,UTILITY_MSG_CLASS		     ;;AN001;;
	      $IF     NE				     ;;AN001;;
		CMP	AX,WORD PTR ES:[DI].$M_NUM	     ;;AN001;; Is this the message requested?
	      $ELSE					     ;;AN001;;
IF		FARmsg					     ;;AN001;;
		CMP	AX,WORD PTR ES:[DI].$M_NUM	     ;;AN000;; Is this the message requested?
ELSE
		CMP	AX,WORD PTR CS:[DI].$M_NUM	     ;;AN000;; Is this the message requested?
ENDIF
	      $ENDIF
	    $EXITIF E					     ;;AN000;;
	    $ORELSE					     ;;AN000;
	      DEC     CX				     ;;AN000;;	  No, well do we have more to check?
	    $LEAVE  Z					     ;;AN000;;	     No, return with CX = 0
	      ADD     DI,$M_ID_SZ			     ;;AN000;;	     Yes, skip past msg header
	    $ENDLOOP					     ;;AN000;;
	      STC					     ;;AN000;;
	    $ENDSRCH					     ;;AN000;;	     Check next message
	    $IF     NC					     ;;AN000;;	 Did we find the message?
	      CMP     DH,UTILITY_MSG_CLASS		     ;;AN001;;	 Yes, is it a utility message?
	      CLC					     ;;AN001;;
	      $IF     E 				     ;;AN001;;
IF		FARmsg					     ;;AN001;;
ELSE							     ;;AN000;;
		PUSH	CS				     ;;AN000;;
		POP	ES				     ;;AN000;;	 Return ES:DI pointing to the message
ENDIF
	      $ENDIF					     ;;AN001;;
	      ADD     DI,WORD PTR ES:[DI].$M_TXT_PTR	     ;;AN000;; Prepare ES:DI pointing to the message
	    $ENDIF					     ;;AN004;;
	  $ENDIF					     ;;AN004;;
							     ;; 	  Yes, great we can return with CX > 0

	  $IF	  NC					     ;;AN000;;	 Did we find the message?
	    XOR     CH,CH				     ;;AN000;;
	    MOV     CL,BYTE PTR ES:[DI] 		     ;;AN000;;	 Move size into CX
	    INC     DI					     ;;AN000;;	 Increment past length
	  $ENDIF					     ;;AN004;;

	  MOV	  $M_RT.$M_SIZE,$M_NULL 		     ;;AN004;; Reset variable
	  RET						     ;;AN000;; Return
							     ;;
$M_FIND_SPECIFIED_MSG ENDP				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ENDIF						     ;;AN000;; END of include of common subroutines
      ENDIF						     ;;AN000;; END of include of SYSGETMSG
; 
      IF      DISPLAYmsg				     ;;AN000;; Is the request to include the code for SYSGETMSG ?
	IF	COMR					     ;;AN000;;
	  $M_RT   EQU		   $M_RT2		     ;;AN000;;
	ENDIF						     ;;AN000;;
	DISPLAYmsg =  FALSE				     ;;AN000;; Yes, THEN include it and reset flag
	PAGE
	SUBTTL	DOS - Message Retriever - DISPMSG.ASM Module
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Proc Name:	SYSDISPMSG
;;
;;  Function:	The DISPLAY service will output a defined message to a handle
;;		requested by the caller. It also provides function to display
;;		messages when handles are not applicable (ie. DOS function calls
;;		00h to 0Ah) Replaceable parameters are allowed and are
;;		defined previous to entry.
;;
;;		It is assumes that a PRELOAD function has already determined
;;		the addressibilty internally to the message retriever services.
;;  Inputs:
;;
;;  Outputs:
;;
;;  Psuedocode:
;;		Save registers needed later
;;		Get address of the message requested
;;		IF Message number exists THEN
;;		  IF replacable parameters were specified THEN
;;		     Display message with replacable parms
;;		  ELSE
;;		     Display string without replacable parms
;;		  ENDIF
;;		  IF character input was requested THEN
;;		     Wait for character input
;;		  ENDIF
;;		  Clear CARRY FLAG
;;		ELSE
;;		   Set CARRY FLAG
;;		ENDIF
;;		Return
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF	FARmsg						     ;;AN000;;
	SYSDISPMSG PROC FAR				     ;;AN000;;
ELSE							     ;;AN000;;
	SYSDISPMSG PROC NEAR				     ;;AN000;;
ENDIF							     ;;AN000;;
							     ;;
;; Save registers and values needed later

	PUSH	AX					     ;;AN000;; Save changed REGs
	PUSH	BX					     ;;AN000;;
	PUSH	CX					     ;;AN000;;
	PUSH	BP					     ;;AN000;;
	PUSH	DI					     ;;AN000;; Save pointer to input buffer (offset)
	PUSH	ES					     ;;AN000;; Save pointer to input buffer (segment)
	PUSH	DX					     ;;AN000;; Save Input/Class request

	MOV	BP,CX					     ;;AN000;; Use BP to hold replace count
	MOV	WORD PTR $M_RT.$M_HANDLE,BX		     ;;AN000;; Save handle
	MOV	BYTE PTR $M_RT.$M_CLASS,DH		     ;;AN004;; Save class

;; Get address of the message requested

IF	FARmsg						     ;;AN000;;
	CALL	FAR PTR $M_GET_MSG_ADDRESS		     ;;AN000;; Scan thru classes to find message
ELSE							     ;;AN000;;
	CALL	$M_GET_MSG_ADDRESS			     ;;AN000;; Scan thru classes to find message
ENDIF							     ;;AN000;;
	OR	CX,CX					     ;;AN000;; Was message found?
	$IF	NZ					     ;;AN000;;	 YES, Message address in ES:DI

;; Test if replacable parameters were specified

	  OR	  BP,BP 				     ;;AN000;;	 Were replacable parameters requested
	  $IF	  Z					     ;;AN000;;

;; Display string without replacable parms

	    CALL    $M_DISPLAY_STRING			     ;;AN000;; No, great . . . Display message
	  $ELSE 					     ;;AN000;;
IF	    $M_REPLACE					     ;;AN000;;

;; Display message with replacable parms

	    CALL    $M_DISPLAY_MESSAGE			     ;;AN000;;	 Display the message with substitutions
ENDIF							     ;;AN000;;
	  $ENDIF					     ;;AN000;;
	  $IF	  NC

	    POP     DX					     ;;AN000;; Get Input/Class request

	    CALL    $M_ADD_CRLF 			     ;;AN004;; Check if we need to add the CR LF chars.

	    POP     ES					     ;;AN000;; Get location of input buffer (if specified)
	    POP     DI					     ;;AN000;;

;; Test if character input was requested

IF	    INPUTmsg					     ;;AN000;;
	    OR	    DL,DL				     ;;AN000;; Was Wait-For-Input requested?
	    $IF     NZ					     ;;AN000;;
	      CALL    $M_WAIT_FOR_INPUT 		     ;;AN000;;
	    $ENDIF					     ;;AN000;;
ENDIF							     ;;AN000;;
	  $ELSE 					     ;;AN000;;
	    ADD     SP,6				     ;;AN000;;
	    STC 					     ;;AN000;; Reset carry flag
	  $ENDIF					     ;;AN000;;
	$ELSE						     ;;AN000;; No,
	  POP	  ES					     ;;AN000;;	 Get pointer to input buffer (segment)
	  POP	  DI					     ;;AN000;;	 Get base pointer to first sublist (offset)
	  POP	  DX					     ;;AN000;;	 Get base pointer to first sublist (segment)
	  STC						     ;;AN000;;	 Set carry flag
	$ENDIF						     ;;AN000;;
							     ;;
	$IF	NC					     ;;AN000;; Was there an error?
	  POP	  BP					     ;;AN000;; No,
	  POP	  CX					     ;;AN000;;
	  POP	  BX					     ;;AN000;;
IF	  INPUTmsg					     ;;AN000;;
	  ADD	  SP,2					     ;;AN000;;
ELSE							     ;AN000;
	  POP	  AX					     ;;AN000;;
ENDIF							     ;;AN000;;
	$ELSE						     ;;AN000;;	Yes,
	  ADD	  SP,8					     ;;AN000;;	   Eliminate from stack
	  STC						     ;;AN000;;
	$ENDIF						     ;;AN000;;
							     ;;
	RET						     ;;AN000;; Return
							     ;;
	SYSDISPMSG ENDP 				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 
;;
;;	PROC NAME: $M_DISPLAY_STRING
;;
;;	FUNCTION:  Will display or write string
;;	INPUTS:    ES:DI points to beginning of message
;;		   CX contains the length of string to write (if applicable)
;;	OUTPUTS:   None
;;	REGS Revised: None
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_DISPLAY_STRING PROC NEAR				     ;;AN000;;
							     ;;
	PUSH	AX					     ;;AN000;;
	PUSH	BX					     ;;AN000;;
	PUSH	DX					     ;;AN000;;
							     ;;
	MOV	BX,$M_RT.$M_HANDLE			     ;;AN000;; Retrieve handle
							     ;;
IF	COMR						     ;;  ** Special case for RESIDENT COMMAND.COM
	CALL	$M_DISPLAY_$_STRING			     ;;AN000;; No, display $ terminated string
ELSE
	CMP	BX,$M_NO_HANDLE 			     ;;AN000;; Was there a handle specified?
	$IF	E					     ;;AN000;;
	  CALL	  $M_DISPLAY_$_STRING			     ;;AN000;; No, display $ terminated string
	$ELSE						     ;;AN000;;
	  CALL	  $M_DISPLAY_H_STRING			     ;;AN000;; Yes, display string to handle
	$ENDIF						     ;;AN000;;
							     ;AN001;
	$IF	C					     ;;AN000;;	Was there an error?
	  MOV	  AH,DOS_GET_EXT_ERROR			     ;;AN000;;	Yes,
	  MOV	  BX,DOS_GET_EXT_ERROR_BX		     ;;AN000;;	  Get extended error
	  INT	  21H					     ;;AN000;;
	  XOR	  AH,AH 				     ;;AN000;;	  Clear AH
	  ADD	  SP,6					     ;;AN000;;	  Clean up stack
	  STC						     ;;AN000;;	  Flag that there was an error
	$ELSE						     ;;AN000;;	No,
	  CMP	  BX,$M_NO_HANDLE			     ;;AN000;; Was there a handle specified?
	  $IF	  NE					     ;;AN000;;
	    CMP     AX,CX				     ;AN001;	 Was it ALL written?
	    $IF     NE					     ;AN001;	 No,
	      CALL    $M_GET_EXT_ERR_39 		     ;AN001;	   Set Extended error
	      ADD     SP,6				     ;AN001;	   Clean up stack
	      STC					     ;AN001;	   Flag that there was an error
	    $ENDIF					     ;AN001;
	  $ENDIF					     ;AN001;
	$ENDIF						     ;;AN000;;
ENDIF
	$IF	NC					     ;;AN000;;	Was there ANY error?
	  POP	  DX					     ;;AN000;;	Restore regs
	  POP	  BX					     ;;AN000;;
	  POP	  AX					     ;;AN000;;
	$ENDIF						     ;;AN000;;
	RET						     ;;AN000;; Return
							     ;;
$M_DISPLAY_STRING ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_DISPLAY_$_STRING
;;
;;	FUNCTION:  Will display a $ terminated string
;;	INPUTS:    ES:DI points to beginning of message text (not the length)
;;	OUPUTS:    None
;;	REGS USED: AX,DX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_DISPLAY_$_STRING PROC NEAR				     ;;AN000;;
							     ;;
	PUSH	DS					     ;;AN000;;
	PUSH	ES					     ;;AN000;;
	POP	DS					     ;;AN000;; Set DS to segment of message text
IF	NOT	COMR
	CMP	CX,$M_SINGLE_CHAR			     ;;AN000;; Is this a single character?
	$IF	E					     ;;AN000;; Yes,
	  MOV	  AH,DOS_DISP_CHAR			     ;;AN000;;	 DOS Function to display CHARACTER
	  MOV	  DL,BYTE PTR ES:[DI]			     ;;AN000;;	 Get the character
	  INT	  21H					     ;;AN000;;	 Write character
	  POP	  DS					     ;;AN000;; Set DS to segment of message text
	  MOV	  AL,DL 				     ;;AN000;;	 Get the character in AL
	  CALL	  $M_IS_IT_DBCS 			     ;;AN000;;	 Is this the first byte of a DB character
	  PUSH	  DS					     ;;AN000;;
	  PUSH	  ES					     ;;AN000;;
	  POP	  DS					     ;;AN000;; Set DS to segment of message text
	  $IF	  C					     ;;AN000;;	 Yes,
	    MOV     DL,BYTE PTR ES:[DI]+1		     ;;AN000;; Get the next character
	    INT     21H 				     ;;AN000;;	 Write character
	    CLC 					     ;;AN000;;	 Clear the DBCS indicator
	  $ENDIF					     ;;AN000;;
	$ELSE						     ;;AN000;; No,
ENDIF
	  MOV	  AH,DOS_DISP_CHAR			     ;;AN000;;	 DOS Function to display CHARACTER
	  $DO						     ;;AN002;; No,
	    OR	    CX,CX				     ;;AN002;;	 Are there any left to display?
	  $LEAVE  Z					     ;;AN002;;	 Yes,
	    MOV     DL,BYTE PTR ES:[DI] 		     ;;AN002;;	   Get the character
	    INT     21H 				     ;;AN002;;	   Display the character
	    INC     DI					     ;;AN002;;	   Set pointer to next character
	    DEC     CX					     ;;AN002;;	   Count this character
	  $ENDDO  Z					     ;;AN002;; No,
IF	  NOT	  COMR
	$ENDIF						     ;;AN000;;
ENDIF
	CLC						     ;;AN000;;	 Char functions used don't return carry as error
	POP	DS					     ;;AN000;;
	RET						     ;;AN000;;
							     ;;
$M_DISPLAY_$_STRING ENDP				     ;;AN000;;
							     ;;
IF	NOT	COMR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_DISPLAY_H_STRING
;;
;;	FUNCTION:  Will display a string to a specified handle
;;	INPUTS:    ES:DI points to beginning of message
;;		   CX contains the number of bytes to write
;;		   BX contains the handle to write to
;;	OUPUTS:    None
;;	REGS USED: AX,DX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_DISPLAY_H_STRING PROC NEAR				     ;;AN000;;
							     ;;
	XOR	AX,AX					     ;;AN002;; Set number of bytes written to 0
	OR	CX,CX					     ;;AN002;; For performance, don't write if not necessary
	$IF	NZ					     ;;AN002;; Any chars to write?
	  PUSH	  DS					     ;;AN000;; Yes,
	  PUSH	  ES					     ;;AN000;;
	  POP	  DS					     ;;AN000;;	 Set DS to segment of message text
	  MOV	  AH,DOS_WRITE_HANDLE			     ;;AN000;;	 DOS function to write to a handle
	  MOV	  DX,DI 				     ;;AN000;;	 Pointer to data to write
	  CMP	  CX,$M_SINGLE_CHAR			     ;;AN000;;	 Is this a single character?
	  $IF	  E					     ;;AN000;;	 Yes,
	    INT     21H 				     ;;AN000;;	   Write character
	    POP     DS					     ;;AN000;;	     Set DS to segment of message text
	    PUSH    AX					     ;;AN000;;
	    MOV     AL,BYTE PTR ES:[DI] 		     ;;AN000;;	     Get the character
	    CALL    $M_IS_IT_DBCS			     ;;AN000;;	     Is this the first byte of a DB character
	    POP     AX					     ;;AN000;;	     Set DS to segment of message text
	    PUSH    DS					     ;;AN000;;
	    PUSH    ES					     ;;AN000;;
	    POP     DS					     ;;AN000;;	     Set DS to segment of message text
	    $IF     C					     ;;AN000;;	     Yes,
	      CLC					     ;;AN000;;	      Clear the DBCS indicator
	      MOV     AH,DOS_WRITE_HANDLE		     ;;AN000;;	      DOS function to write to a handle
	      INC     DX				     ;;AN000;;	      Point to next character
	      INT     21H				     ;;AN000;;	      Write character
	    $ENDIF					     ;;AN000;;
	  $ELSE 					     ;;AN000;;	 No,
	    INT     21H 				     ;;AN000;;	   Write String at DS:SI to handle
	  $ENDIF					     ;;AN000;;
	  POP	  DS					     ;;AN000;;
	$ENDIF						     ;;AN002;;
							     ;;
	RET						     ;;AN000;;
							     ;;
$M_DISPLAY_H_STRING ENDP				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_GET_EXT_ERR_39
;;
;;	FUNCTION:  Will set registers for extended error #39
;;	INPUTS:    None
;;	OUPUTS:    AX,BX,CX set
;;	REGS USED:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_GET_EXT_ERR_39 PROC NEAR				     ;AN001;
							     ;;
	MOV	AX,EXT_ERR_39				     ;AN001; Set AX=39
	MOV	BX,(ERROR_CLASS_39 SHR 8) + ACTION_39	     ;AN001; Set BH=1 BL=4
	MOV	CH,LOCUS_39				     ;AN001; Set CH=1
							     ;AN001;
	RET						     ;AN001;
							     ;;
$M_GET_EXT_ERR_39 ENDP					     ;AN001;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ENDIF
;;
;;	PROC NAME: $M_ADD_CRLF
;;
;;	FUNCTION:  Will decide whether to display a CRLF
;;	INPUTS:    DX contains the Input/Class requested
;;	OUTPUTS:   None
;;	REGS Revised: CX,ES,DI
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_ADD_CRLF PROC NEAR					     ;;AN004;;
							     ;;
	CMP	DH,UTILITY_MSG_CLASS			     ;;AN004;; Is it a utility message?
	$IF	NE					     ;;AN004;; No,
	  TEST	  DH,$M_NO_CRLF_MASK			     ;;AN004;;	 Are we to supress the CR LF?
	  $IF	  Z					     ;;AN004;;	 No,
	    PUSH    DS					     ;;AN004;;
	    POP     ES					     ;;AN004;;	  Set ES to data segment
	    LEA     DI,$M_RT.$M_CRLF			     ;;AN004;;	  Point at CRLF message
	    MOV     CX,$M_CRLF_SIZE			     ;;AN004;;	  Set the message size
	    CALL    $M_DISPLAY_STRING			     ;;AN004;;	  Display the CRLF
	  $ENDIF					     ;;AN004;;
	$ENDIF						     ;;AN004;;
	RET						     ;;AN004;; Return
							     ;;
$M_ADD_CRLF ENDP					     ;;AN004;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_IS_IT_DBCS
;;
;;	FUNCTION:  Will decide whether character is Single or Double Byte
;;	INPUTS:    AL contains the byte to be checked
;;	OUPUTS:    Carry flag = 0 if byte is NOT in DBCS range
;;		   Carry flag = 1 if byte IS in DBCS range
;;	REGS USED: All restored
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_IS_IT_DBCS PROC NEAR 				     ;;AN000;;
							     ;;
	PUSH	ES					     ;;AN000;; Save Extra segment register
	PUSH	DI					     ;;AN000;; Save SI register
							     ;;
	LES	DI,$M_RT.$M_DBCS_VEC			     ;;AN000;;
	OR	DI,DI					     ;;AN000;; Was the DBCS vector set?
	$IF	NZ					     ;;AN000;;
	  $DO						     ;;AN000;;
	    CMP     WORD PTR ES:[DI],$M_DBCS_TERM	     ;;AN000;; Is this the terminating flag?
	    CLC 					     ;;AN000;;
	  $LEAVE  E					     ;;AN000;;
							     ;;        No,
	    CMP     AL,BYTE PTR ES:[DI] 		     ;;AN000;;	  Does the character fall in the DBCS range?
	    $IF     AE,AND				     ;;AN000;;
	    CMP     AL,BYTE PTR ES:[DI]+1		     ;;AN000;;	  Does the character fall in the DBCS range?
	    $IF     BE					     ;;AN000;;
	      STC					     ;;AN000;;	  Yes,
	    $ENDIF					     ;;AN000;;	     Set carry flag
	    INC     DI					     ;;AN000;;	  No,
	    INC     DI					     ;;AN000;;	     Go to next vector
	  $ENDDO					     ;;AN000;;
	$ENDIF						     ;;AN000;;

	POP	DI					     ;;AN000;;
	POP	ES					     ;;AN000;; Restore SI register
	RET						     ;;AN000;; Return
							     ;;
$M_IS_IT_DBCS ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_CONVERT2ASC
;;
;;	FUNCTION: Convert a binary number to a ASCII string
;;	INPUTS: DX:AX contains the number to be converted
;;		$M_RT_DIVISOR contains the divisor
;;	OUPUTS: CX contains the number of characters
;;		Top of stack  --> Last character
;;				     . . .
;;		Bot of stack  --> First character
;;	REGS USED:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_CONVERT2ASC PROC NEAR				     ;;AN000;;
							     ;;
	POP	[$M_RT.$M_RETURN_ADDR]			     ;;AN000;; Save Return Address
	XOR	BX,BX					     ;;AN000;; Use BP as a swapping register
							     ;;
	XCHG	BX,AX					     ;;AN000;; Initialize - Low Word in BP
	XCHG	AX,DX					     ;;AN000;;		  - High Word in AX
	$DO						     ;;AN000;; DO UNTIL Low Word becomes zero
	  DIV	  $M_RT.$M_DIVISOR			     ;;AN000;; Divide High Word by divisor
	  XCHG	  BX,AX 				     ;;AN000;; Setup to divide Low Word using remainder
							     ;; 	and save reduced High Word in BP
	  DIV	  $M_RT.$M_DIVISOR			     ;;AN000;; Divide Low Word by divisor
	  CMP	  DX,9					     ;;AN000;;	Make a digit of the remainder
	  $IF	  A					     ;;AN000;;	IF 10 to 15,
	    ADD     DL,55				     ;;AN000;;	   Make A to F ASCII
	  $ELSE 					     ;;AN000;;	IF 0 to 9,
	    ADD     DL,'0'				     ;;AN000;;	   Make 0 to 9 ASCII
	  $ENDIF					     ;;AN000;;
	  PUSH	  DX					     ;;AN000;; Save the digit on the stack
	  INC	  CX					     ;;AN000;; Count that digit
	  OR	  AX,AX 				     ;;AN000;; Are we done?
	$LEAVE	Z,AND					     ;;AN000;;
	  OR	  BX,BX 				     ;;AN000;; AX and BX must be ZERO!!
	$LEAVE	Z					     ;;AN000;; No,
IF	  NOT	  COMR
	  CMP	  CX,$M_FIRST_THOU			     ;;AN000;; Are we at the first thousands mark
	  $IF	  E					     ;;AN000;; Yes,
	    CMP     $M_SL.$M_S_PAD,$M_COMMA		     ;;AN000;; Is the pad character a comma?
	    $IF     E					     ;;AN000;; Yes,
	      PUSH    WORD PTR $M_RT.$M_THOU_SEPARA	     ;;AN000;; Insert a thousand separator
	      INC     CX				     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	  $ELSE 					     ;;AN000;; No,
	    CMP     CX,$M_SECOND_THOU			     ;;AN000;;	 Are we at the first thousands mark
	    $IF     E					     ;;AN000;;	      Yes,
	      CMP     $M_SL.$M_S_PAD,$M_COMMA		     ;;AN000;; Is the pad character a comma?
	      $IF     E 				     ;;AN000;; Yes,
		PUSH	WORD PTR $M_RT.$M_THOU_SEPARA	     ;;AN000;; Insert a thousand separator
		INC	CX				     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ELSE					     ;;AN000;;	      No,
	      CMP     CX,$M_THIRD_THOU			     ;;AN000;;	 Are we at the first thousands mark
	      $IF     E 				     ;;AN000;;		Yes,
		CMP	$M_SL.$M_S_PAD,$M_COMMA 	     ;;AN000;; Is the pad character a comma?
		$IF	E				     ;;AN000;; Yes,
		  PUSH	  WORD PTR $M_RT.$M_THOU_SEPARA      ;;AN000;; Insert a thousand separator
		  INC	  CX				     ;;AN000;;
		$ENDIF					     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;
ENDIF
	  XCHG	  AX,BX 				     ;;AN000;;	 Setup to divide the reduced High Word
							     ;;AN000;;	   and Revised Low Word
	  XOR	  DX,DX 				     ;;AN000;;	 Reset remainder
	$ENDDO						     ;;AN000;;	 NEXT
							     ;;AN000;; Yes,
	XOR	DX,DX					     ;;AN000;;	 Reset remainder
	XOR	AX,AX					     ;;AN000;;	 Reset remainder
	PUSH	[$M_RT.$M_RETURN_ADDR]			     ;;AN000;;	 Restore Return Address
	RET						     ;;AN000;;	 Return
							     ;;
$M_CONVERT2ASC ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_DISPLAY_MESSAGE
;;
;;	FUNCTION:  Will display or write entire message (with replacable parameters)
;;	INPUTS:    ES:DI points to beginning of message
;;		   DS:SI points to first sublist structure in chain
;;		   BX contains the handle to write to (if applicable)
;;		   CX contains the length of string to write (before substitutions)
;;		   BP contains the count of replacables
;;
;;	OUTPUTS:
;;	REGS USED: All
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_DISPLAY_MESSAGE PROC NEAR				     ;;AN000;;
							     ;;
	$DO						     ;;AN000;; Note: DS:SI -> message
	  XOR	  DX,DX 				     ;;AN000;; Set size = 0
	  OR	  CX,CX 				     ;;AN000;; Are we finished the message yet?
	  $IF	  NZ					     ;;AN000;; No,
	    MOV     AH,"%"				     ;;AN000;;	 Prepare to scan for %
	    MOV     AL,0				     ;;AN004;;
							     ;;
	    $DO 					     ;;AN000;;	 Scan through string until %
	      CMP     BYTE PTR ES:[DI],AH		     ;;AN000;;	 Is this character NOT a %
	    $LEAVE  E,AND				     ;;AN000;;	 No,
	      CMP     BYTE PTR ES:[DI+1],AH		     ;;AN000;;	   Is the next character also a %
	    $LEAVE  NE,AND				     ;;AN000;;	   No,
	      CMP     AL,AH				     ;;AN000;;	     Was the character before a %
	    $LEAVE  NE					     ;;AN000;;	     No, GREAT found it
	      MOV     AL,BYTE PTR ES:[DI]		     ;;AN004;;	 Yes, (to any of the above)
	      CALL    $M_IS_IT_DBCS			     ;;AN004;;	   Is this character the first part of a DBCS?
	      $IF     C 				     ;;AN004;;	   Yes,
		INC	DI				     ;;AN004;;	     Increment past second part
	      $ENDIF					     ;;AN004;;
	      INC     DI				     ;;AN000;;	     Next character in string
	      INC     DX				     ;;AN000;;	     Size = Size + 1
	      DEC     CX				     ;;AN000;;	     Decrement total size
	    $ENDDO  Z					     ;;AN000;;	 Exit scan if we're at the end of the line
	  $ENDIF					     ;;AN000;;
							     ;;
	  PUSH	  SI					     ;;AN000;; Save beginning of sublists
	  XCHG	  CX,DX 				     ;;AN000;; Get size of message to display (tot sz in DX)
	  OR	  BP,BP 				     ;;AN000;; Do we have any replacables to do?
	  $IF	  NZ					     ;;AN000;; Yes,
	    DEC     BP					     ;;AN000;;	 Decrement number of replacables

;; Search through sublists to find applicable one

	    CMP     $M_RT.$M_MSG_NUM,$M_NULL		     ;;AN000;; Is this an Extended/Parse case
	    $IF     E					     ;;AN000;; No,
	      $SEARCH					     ;;AN000;;
		MOV	AL,$M_SL.$M_S_ID		     ;;AN000;;	 Get ID byte
		ADD	AL,30H				     ;;AN000;;	 Convert to ASCII
		CMP	AL,BYTE PTR ES:[DI]+1		     ;;AN000;;	 Is this the right sublist?
	      $EXITIF E 				     ;;AN000;;
	      $ORELSE					     ;;AN000;;	 No,
		CMP	AL,$M_SPECIAL_CASE		     ;;AN000;;	   Does this sublist have ID = 0
	      $LEAVE  E,AND				     ;;AN000;;	   Yes,
		OR	DX,DX				     ;;AN000;;	   Are we at the end of the message?
	      $LEAVE  Z 				     ;;AN000;;	   No,
		ADD	SI,WORD PTR $M_SL.$M_S_SIZE	     ;;AN000;;	     Next SUBLIST
	      $ENDLOOP					     ;;AN000;;	   Yes,
		CMP	$M_RT.$M_CLASS,UTILITY_MSG_CLASS     ;;AN004;;	     Is it a utility message?
		$IF	E				     ;;AN004;;	     Yes,
		  INC	  DX				     ;;AN000;;	       Remember to display CR,LF
		  INC	  DX				     ;;AN000;;		 at the end of the message
		  DEC	  CX				     ;;AN000;;	       Adjust message length
		  DEC	  CX				     ;;AN000;;
		  DEC	  DI				     ;;AN000;;	       Adjust ending address of message
		  DEC	  DI				     ;;AN000;;
		$ELSE					     ;;AN004;;	     No,
		  MOV	  DX,-1 			     ;;AN004;;	       Set special case
		$ENDIF					     ;;AN004;;
	      $ENDSRCH					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;

;; Prepare and display this part of message

	  PUSH	  DI					     ;;AN000;; Save pointer to replace number
	  SUB	  DI,CX 				     ;;AN000;; Determine beginning of string
	  CALL	  $M_DISPLAY_STRING			     ;;AN000;; Display string until % (or end)
	  POP	  DI					     ;;AN000;; Get back pointer to replace number
	  POP	  CX					     ;;AN000;; Clean up stack in case error
	$LEAVE	C,LONG					     ;;AN000;; Fail if carry was set
	  PUSH	  CX					     ;;AN000;;

;; Save and reset pointer registers

	  MOV	  CX,DX 				     ;;AN000;; Get the size of the rest of the message
	  CMP	  $M_SL.$M_S_ID,$M_SPECIAL_CASE-30H	     ;;AN000;; Is this the %0 case?
	  $IF	  NE					     ;;AN000;; No,
	    OR	    CX,CX				     ;;AN000;;	Are we finished the whole message?
	    $IF     NZ					     ;;AN000;;	No,
	      DEC     CX				     ;;AN000;;	  Decrement total size (%)
	      DEC     CX				     ;;AN000;;	  Decrement total size (#)
	      INC     DI				     ;;AN000;;	  Go past %
	      INC     DI				     ;;AN000;;	  Go past replace number
	    $ELSE					     ;;AN000;;	Yes, (Note this will not leave because INC)
	      POP     SI				     ;;AN000;;	  Get back pointer to beginning of SUBLISTs
	    $ENDIF					     ;;AN000;; Yes, Note this will not leave because INC
	  $ELSE 					     ;;AN000;;
	    OR	    CX,CX				     ;;AN000;;	Are we finished the whole message?
	    $IF     Z					     ;;AN004;;	 No,
	      POP     SI				     ;;AN000;;	 Get back pointer to beginning of SUBLISTs
	    $ELSE					     ;;AN000;; No,
	      CMP     CX,-1				     ;;AN004;;	 Are we at the end of the message?
	      $IF     Z 				     ;;AN004;;	 No,
		XOR	CX,CX				     ;;AN004;;
	      $ENDIF					     ;;AN000;;
	      OR      DI,DI				     ;;AN004;;	Turn ZF off
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;; Note this will not leave because INC
	$LEAVE	Z					     ;;AN000;;
	  PUSH	  BP					     ;;AN000;;	 Save the replace count
	  PUSH	  DI					     ;;AN000;;	 Save location to complete message
	  PUSH	  ES					     ;;AN000;;
	  PUSH	  CX					     ;;AN000;;	 Save size of the rest of the message
	  XOR	  CX,CX 				     ;;AN000;;	 Reset CX used for character count

;; Determine what action is required on parameter

	  CMP	  $M_RT.$M_MSG_NUM,$M_NULL		     ;;AN000;; Is this an Extended/Parse case
	  $IF	  E					     ;;AN000;;

IF	    CHARmsg					     ;;AN000;; Was Char specified?
	    TEST    BYTE PTR $M_SL.$M_S_FLAG,NOT Char_Type AND $M_TYPE_MASK ;;AN000;;
	    $IF     Z					     ;;AN000;;

;; Character type requested
							     ;;AN000;;
	      LES     DI,DWORD PTR $M_SL.$M_S_VALUE	     ;;AN000;; Load pointer to replacing parameter
	      CALL    $M_CHAR_REPLACE			     ;;AN000;;
	    $ELSE					     ;;AN000;;	 Get the rest of the message to display
ENDIF							     ;;AN000;;
IF	      NUMmsg					     ;;AN000;; Was Nnmeric type specified?
	      TEST    BYTE PTR $M_SL.$M_S_FLAG,NOT Sgn_Bin_Type AND $M_TYPE_MASK ;;AN000;;
	      $IF     Z,OR				     ;;AN000;;
	      TEST    BYTE PTR $M_SL.$M_S_FLAG,NOT Unsgn_Bin_Type AND $M_TYPE_MASK ;;AN000;;
	      $IF     Z,OR				     ;;AN000;;
	      TEST    BYTE PTR $M_SL.$M_S_FLAG,NOT Bin_Hex_Type AND $M_TYPE_MASK ;;AN000;;
	      $IF     Z 				     ;;AN000;;

;; Numeric type requested

		LES	DI,DWORD PTR $M_SL.$M_S_VALUE	     ;;AN000;; Load pointer to replacing parameter
		CALL	$M_BIN2ASC_REPLACE		     ;;AN000;;
	      $ELSE					     ;;AN000;; Get the rest of the message to display
ENDIF							     ;;AN000;;
IF		DATEmsg 				     ;;AN000;; Was date specified?
		TEST	BYTE PTR $M_SL.$M_S_FLAG,NOT Date_Type AND $M_TYPE_MASK ;;AN000;;
		$IF	E				     ;;AN000;;

;; Date type requested

		  CALL	  $M_DATE_REPLACE		     ;;AN000;;
		$ELSE					     ;;AN000;; Get the rest of the message to display
ENDIF							     ;;AN000;;
IF		  TIMEmsg				     ;;AN000;;	Was time (12 hour format) specified?

;; Time type requested (Default if we have not matched until here)

		  CALL	  $M_TIME_REPLACE		     ;;AN000;;
ENDIF							     ;;AN000;;

IF		  DATEmsg				     ;;AN000;;
		$ENDIF					     ;;AN000;;
ENDIF							     ;;AN000;;
IF		NUMmsg					     ;;AN000;;
	      $ENDIF					     ;;AN000;;
ENDIF							     ;;AN000;;
IF	      CHARmsg					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
ENDIF							     ;;AN000;;

IF	    $M_REPLACE					     ;;AN000;;
;; With the replace information of the Stack, display the replaceable field

	    CALL    $M_DISPLAY_REPLACE			     ;;AN000;; Display the replace
ENDIF							     ;;AN000;;
;; None of the above - Extended/Parse replace
	  $ELSE 					     ;;AN000;;
IF	    NOT     COMR
	    CALL    $M_EXT_PAR_REPLACE			     ;;AN000;;
ENDIF
	  $ENDIF					     ;;AN000;;

;; We must go back and complete the message after the replacable parameter if there is any left

	  $IF	  NC					     ;;AN000;; IF there was an error displaying then EXIT
	    POP     CX					     ;;AN000;; Get size of the rest of the message
	    POP     ES					     ;;AN000;; Get address of the rest of the message
	    POP     DI					     ;;AN000;;
	    POP     BP					     ;;AN000;; Get replacment count
	    POP     SI					     ;;AN000;; ELSE get address of first sublist structure
	  $ELSE 					     ;;AN000;;
	    ADD     SP,10				     ;;AN000;; Clean up stack if error
	    STC 					     ;;AN000;;
	  $ENDIF					     ;;AN000;;
	  CMP	  $M_RT.$M_MSG_NUM,$M_NULL		     ;;AN000;; Is this an Extended/Parse case
	$ENDDO	NE,OR					     ;;AN000;;
	$ENDDO	C,LONG					     ;;AN000;; Go back and display the rest of the message
							     ;;        IF there was an error displaying then EXIT
	MOV	$M_RT.$M_MSG_NUM,0			     ;;AN000;; Reset message number to null
	RET						     ;;AN000;; Return
							     ;;
$M_DISPLAY_MESSAGE ENDP 				     ;;AN000;;
IF	NOT	COMR
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_EXT_PAR_REPLACE
;;
;;	FUNCTION:
;;	INPUTS:
;;	OUPUTS:
;;
;;	REGS USED:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_EXT_PAR_REPLACE PROC NEAR				     ;;AN000;;
							     ;;
	XOR	DX,DX					     ;;AN000;; Prepare for get binary value (HIGH)
	MOV	AX,$M_RT.$M_MSG_NUM			     ;;AN000;; Prepare for get binary value (LOW)
	MOV	$M_RT.$M_DIVISOR,$M_BASE10		     ;;AN000;; Set default divisor
							     ;;
	CALL	$M_CONVERT2ASC				     ;;AN000;;
							     ;;
	$DO						     ;;AN000;;
	  POP	  AX					     ;;AN000;;	 Get character in register
	  MOV	  BYTE PTR $M_RT.$M_TEMP_BUF[BX],AL	     ;;AN000;;	Move char into the buffer
	  INC	  BX					     ;;AN000;;	 Increase buffer count
	  CMP	  BX,$M_TEMP_BUF_SZ			     ;;AN000;;	 Is buffer full?
	  $IF	  E					     ;;AN000;;	 Yes,
	    CALL    $M_FLUSH_BUF			     ;;AN000;;	   Flush the buffer
	  $ENDIF					     ;;AN000;;
	  DEC	  CL					     ;;AN000;;	 Have we completed replace?
	$ENDDO	Z					     ;;AN000;;
							     ;;
	MOV	AX,$M_CR_LF				     ;;AN000;;	Move char into the buffer
	MOV	WORD PTR $M_RT.$M_TEMP_BUF[BX],AX	     ;;AN000;;	Move char into the buffer
	INC	BX					     ;;AN000;;	 Increase buffer count
	INC	BX					     ;;AN000;;	 Increase buffer count
	CALL	$M_FLUSH_BUF				     ;;AN000;;	   Flush the buffer
	RET						     ;;AN000::
							     ;;
$M_EXT_PAR_REPLACE ENDP 				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ENDIF
	IF	$M_SUBS 				     ;;AN000;; Include the common subroutines if they haven't yet
	  $M_SUBS = FALSE				     ;;AN000;; No, then include and reset the flag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_GET_MSG_ADDRESS
;;
;;	FUNCTION:  To scan thru classes to return pointer to the message header
;;	INPUTS:    Access to $M_RES_ADDRESSES
;;	OUPUTS:    IF CX = 0 THEN Message was not found
;;		   IF CX > 1 THEN DS:SI points to the specified message
;;	REGS CHANGED: ES,DI,CX,DS,SI
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
IF	  FARmsg					     ;;AN000;;
	  $M_GET_MSG_ADDRESS PROC FAR			     ;;AN000;;
ELSE							     ;;AN000;;
	  $M_GET_MSG_ADDRESS PROC NEAR			     ;;AN000;;
ENDIF							     ;;AN000;;
							     ;;
	  PUSH	  SI					     ;;AN000;;
	  PUSH	  BX					     ;;AN000;;
	  XOR	  SI,SI 				     ;;AN000;; Use SI as an index
	  XOR	  CX,CX 				     ;;AN000;; Use CX as an size
	  $DO						     ;;AN000;;
	    CMP     DH,UTILITY_MSG_CLASS		     ;;AN000;; Were utility messages requested?
	    $IF     E					     ;;AN000;; Yes,
	      IF      FARmsg				     ;;AN000;;
		LES	DI,DWORD PTR $M_RT.$M_CLASS_ADDRS[SI] ;;AN000;;  Get address of class
		MOV	BX,ES				     ;;AN000;
	      ELSE					     ;;AN000;;
		MOV	DI,WORD PTR $M_RT.$M_CLASS_ADDRS[SI] ;;AN000;;	 Get address of class
		MOV	BX,DI				     ;;AN000;
	      ENDIF					     ;;AN000;;
	    $ELSE					     ;;AN000;; No,
	      TEST    DH,PARSE_ERR_CLASS		     ;;AN000;;	 Were parse errors requested?
	      $IF     NE				     ;;AN000;;	 Yes,
		LES	DI,DWORD PTR $M_RT.$M_PARSE_COMMAND[SI] ;;AN000;;   Get address of class
		MOV	BX,ES				     ;;AN000;
	      $ELSE					     ;;AN000;;	 No, extended errors were specified
		CMP	AX,$M_CRIT_LO			     ;;AN000;;	   Is this a critical error?
		$IF	AE,AND				     ;;AN000;;
		CMP	AX,$M_CRIT_HI			     ;;AN000;;
		$IF	BE				     ;;AN000;;	    Yes,
		  LES	  DI,DWORD PTR $M_RT.$M_CRIT_ADDRS[SI] ;;AN000;; Get address of class
		  MOV	  BX,ES 			     ;;AN000;
		$ELSE					     ;;AN000;;
		  LES	  DI,DWORD PTR $M_RT.$M_EXT_ERR_ADDRS[SI] ;;AN000;; Get address of class
		  MOV	  BX,ES 			     ;;AN000;
		$ENDIF					     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
							     ;;
	    CMP     BX,$M_TERMINATING_FLAG		     ;;AN000;; Are we finished all classes?
	    $IF     E					     ;;AN000;; Yes,
	      CMP     DH,UTILITY_MSG_CLASS		     ;;AN000;;	  Was it a UTILITY class?
	      $IF     E 				     ;;AN000;;	  Yes,
		STC					     ;;AN000;;	    Set the carry flag
	      $ELSE					     ;;AN000;;	  No,
		MOV	$M_RT.$M_MSG_NUM,AX		     ;;AN000;;	    Save message number
		MOV	AX,$M_SPECIAL_MSG_NUM		     ;;AN000;;	    Set special message number
		MOV	BP,$M_ONE_REPLACE		     ;;AN000;;	    Set one replace in message
		XOR	SI,SI				     ;;AN000;;	    Reset the SI index to start again
		CLC					     ;;AN000;;
	      $ENDIF					     ;;AN000;; No,
	    $ELSE					     ;;AN000;;
	      CMP     BX,$M_CLASS_NOT_EXIST		     ;;AN000;;	 Does this class exist?
	      $IF     NE				     ;;AN001;;	 Yes,
		CALL	$M_FIND_SPECIFIED_MSG		     ;;AN000;;	   Try to find the message
	      $ENDIF					     ;;AN000;;
	      ADD     SI,$M_ADDR_SZ_FAR 		     ;;AN000;;	     Get next class
	      CLC					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	  $LEAVE  C					     ;;AN000;;
	    OR	    CX,CX				     ;;AN000;;	   Was the message found?
	  $ENDDO  NZ,LONG				     ;;AN000;;

	  PUSHF 					     ;;AN006;; Save the flag state
	  CMP	  DH,EXT_ERR_CLASS			     ;;AN006;; Was an extended error requested?
	  $IF	  E					     ;;AN006;; Yes,
	    PUSH    DX					     ;;AN006;;	Save all needed registers
	    PUSH    BP					     ;;AN006;;
	    PUSH    CX					     ;;AN006;;
	    PUSH    ES					     ;;AN006;;
	    PUSH    DI					     ;;AN006;;
	    PUSH    AX					     ;;AN006;;

	    MOV     AX,IFSFUNC_INSTALL_CHECK		     ;;AN006;;	Check if IFSFUNC is installed
	    INT     2FH 				     ;;AN006;;
	    CMP     AL,IFSFUNC_INSTALLED		     ;;AN006;;	Is it installed?
	    POP     AX					     ;;AN006;;	Restore msg number
	    $IF     E					     ;;AN006;;	 Yes,
	      MOV     BX,AX				     ;;AN006;;	  BX is the extended error number
	      MOV     AX,IFS_GET_ERR_TEXT		     ;;AN006;;	  AX is the muliplex number
	      INT     2FH				     ;;AN006;;	  Call IFSFUNC
	    $ELSE					     ;;AN006;;	 No,
	      STC					     ;;AN006;;	  Carry conditon
	    $ENDIF					     ;;AN006;;

	    $IF     C					     ;;AN006;;	Was there an update?
	      POP     DI				     ;;AN006;;	No,
	      POP     ES				     ;;AN006;;	 Restore old pointer
	      POP     CX				     ;;AN006;;
	    $ELSE					     ;;AN006;;	Yes
	      ADD     SP,6				     ;;AN006;;	 Throw away old pointer
	      CALL    $M_SET_LEN_IN_CX			     ;;AN006;;	 Get the length of the ASCIIZ string
	    $ENDIF					     ;;AN006;;
	    POP     BP					     ;;AN006;;	Restore other Regs
	    POP     DX					     ;;AN006;;
	  $ENDIF					     ;;AN006;;
	  $M_POPF					     ;;AN006;; Restore the flag state

	  POP	  BX					     ;;AN000;;
	  POP	  SI					     ;;AN000;;
	  RET						     ;;AN000;; Return ES:DI pointing to the message
							     ;;
$M_GET_MSG_ADDRESS ENDP 				     ;;
							     ;;
$M_SET_LEN_IN_CX PROC NEAR				     ;;
							     ;;
	  PUSH	  DI					     ;;AN006;; Save position
	  PUSH	  AX					     ;;AN006;;
	  MOV	  CX,-1 				     ;;AN006;; Set CX for decrements
	  XOR	  AL,AL 				     ;;AN006;; Prepare compare register
	  REPNE   SCASB 				     ;;AN006;; Scan for zero
	  NOT	  CX					     ;;AN006;; Change decrement into number
	  DEC	  CX					     ;;AN006;; Don't include the zero
	  POP	  AX					     ;;AN006;;
	  POP	  DI					     ;;AN006;; Restore position
	  RET						     ;;AN006;;
							     ;;
$M_SET_LEN_IN_CX ENDP					     ;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_FIND_SPECIFIED_MSG
;;
;;	FUNCTION:  To scan thru message headers until message is found
;;	INPUTS:    ES:DI points to beginning of msg headers
;;		   CX contains the number of messages in class
;;		   DH contains the message class
;;	OUPUTS:    IF CX = 0 THEN Message was not found
;;		   IF CX > 1 THEN ES:DI points to header of specified message
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_FIND_SPECIFIED_MSG PROC NEAR 			     ;;AN000;;
							     ;;
	  CMP	  BX,1					     ;;AN004;;	Do we have an address to CALL?
	  $IF	  E,AND 				     ;;AN004;;	Yes,
	  CMP	  WORD PTR $M_RT.$M_DISK_PROC_ADDR,-1	     ;;AN004;;	Do we have an address to CALL?
	  $IF	  NE					     ;;AN004;;	Yes,
	    CMP     AX,$M_SPECIAL_MSG_NUM		     ;;AN004;; Are we displaying a default Ext Err?
	    $IF     E					     ;;AN004;;	. . . and . . .
	      PUSH    AX				     ;;AN004;;	 Reset the special message number
	      MOV     AX,$M_RT.$M_MSG_NUM		     ;;AN004;;	 Get the old message number
	      CALL    DWORD PTR $M_RT.$M_DISK_PROC_ADDR      ;;AN004;;	 Call the READ_DISK_PROC to get error text
	      POP     AX				     ;;AN004;;	 Reset the special message number
	    $ELSE					     ;;AN004;;	 Get the old message number
	      CALL    DWORD PTR $M_RT.$M_DISK_PROC_ADDR      ;;AN004;;	 Call the READ_DISK_PROC to get error text
	    $ENDIF					     ;;AN004;;	 Get the old message number
	  $ELSE 					     ;;AN004;;
	    XOR     CX,CX				     ;;AN002;;	 CX = 0 will allow us to
	    CMP     DH,UTILITY_MSG_CLASS		     ;;AN001;;
	    $IF     NE					     ;;AN001;;
	      MOV     CL,BYTE PTR ES:[DI].$M_NUM_CLS_MSG     ;;AN001;;	 Get number of messages in class
	    $ELSE					     ;;AN001;;
IF	      FARmsg					     ;;AN001;;
	      CMP     BYTE PTR ES:[DI].$M_CLASS_ID,DH	     ;;AN002;; Check if class still exists at
ELSE
	      CMP     BYTE PTR CS:[DI].$M_CLASS_ID,DH	     ;;AN002;; Check if class still exists at
ENDIF
	      $IF     E 				     ;;AN002;;	pointer (hopefully)
IF		FARmsg					     ;;AN001;;
		MOV	CL,BYTE PTR ES:[DI].$M_NUM_CLS_MSG   ;;AN000;;	   Get number of messages in class
ELSE
		MOV	CL,BYTE PTR CS:[DI].$M_NUM_CLS_MSG   ;;AN000;;	   Get number of messages in class
ENDIF
	      $ENDIF					     ;;AN002;;	  go on to the next class
	    $ENDIF					     ;;AN001;;
	    ADD     DI,$M_CLASS_ID_SZ			     ;;AN000;;	   Point past the class header
	    STC 					     ;;AN004;;	 Flag that we haven't found anything yet
	  $ENDIF					     ;;AN004;;

	  $IF	  C					     ;;AN004;; Have we found anything yet?
	    CLC 					     ;;AN004;; No, reset carry
	    $SEARCH					     ;;AN000;;
	      OR      CX,CX				     ;;AN000;;	  Do we have any to check?
	    $LEAVE  Z					     ;;AN000;;	     No, return with CX = 0
	      CMP     DH,UTILITY_MSG_CLASS		     ;;AN001;;
	      $IF     NE				     ;;AN001;;
		CMP	AX,WORD PTR ES:[DI].$M_NUM	     ;;AN001;; Is this the message requested?
	      $ELSE					     ;;AN001;;
IF		FARmsg					     ;;AN001;;
		CMP	AX,WORD PTR ES:[DI].$M_NUM	     ;;AN000;; Is this the message requested?
ELSE
		CMP	AX,WORD PTR CS:[DI].$M_NUM	     ;;AN000;; Is this the message requested?
ENDIF
	      $ENDIF
	    $EXITIF E					     ;;AN000;;
	    $ORELSE					     ;;AN000;
	      DEC     CX				     ;;AN000;;	  No, well do we have more to check?
	    $LEAVE  Z					     ;;AN000;;	     No, return with CX = 0
	      ADD     DI,$M_ID_SZ			     ;;AN000;;	     Yes, skip past msg header
	    $ENDLOOP					     ;;AN000;;
	      STC					     ;;AN000;;
	    $ENDSRCH					     ;;AN000;;	     Check next message
	    $IF     NC					     ;;AN000;;	 Did we find the message?
	      CMP     DH,UTILITY_MSG_CLASS		     ;;AN001;;	 Yes, is it a utility message?
	      CLC					     ;;AN001;;
	      $IF     E 				     ;;AN001;;
IF		FARmsg					     ;;AN001;;
ELSE							     ;;AN000;;
		PUSH	CS				     ;;AN000;;
		POP	ES				     ;;AN000;;	 Return ES:DI pointing to the message
ENDIF
	      $ENDIF					     ;;AN001;;
	      ADD     DI,WORD PTR ES:[DI].$M_TXT_PTR	     ;;AN000;; Prepare ES:DI pointing to the message
	    $ENDIF					     ;;AN004;;
	  $ENDIF					     ;;AN004;;
							     ;; 	  Yes, great we can return with CX > 0

	  $IF	  NC					     ;;AN000;;	 Did we find the message?
	    XOR     CH,CH				     ;;AN000;;
	    MOV     CL,BYTE PTR ES:[DI] 		     ;;AN000;;	 Move size into CX
	    INC     DI					     ;;AN000;;	 Increment past length
	  $ENDIF					     ;;AN004;;

	  MOV	  $M_RT.$M_SIZE,$M_NULL 		     ;;AN004;; Reset variable
	  RET						     ;;AN000;; Return
							     ;;
$M_FIND_SPECIFIED_MSG ENDP				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ENDIF						     ;;AN000;; END of include of common subroutines
; 
	IF	$M_REPLACE				     ;;AN000;; Is the request to include the code for replaceable parms
	  $M_REPLACE = FALSE				     ;;AN000;;	   Tell the assembler we did
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$M_DISPLAY_REPLACE PROC NEAR				     ;;AN000;;
							     ;;
	  XOR	  BX,BX 				     ;;AN000;; Use BX for buffer count
IF	  NOT	  COMR
	  CMP	  $M_SL.$M_S_ID,$M_SPECIAL_CASE-30H	     ;;AN000;; Is this the special case (convert to ASCII)
	  $IF	  E					     ;;AN000;; Yes,
	    MOV     WORD PTR $M_RT.$M_TEMP_BUF[BX],$M_SPACE_HYP ;;AN000;; Move in a " -"
	    INC     BX					     ;;AN000;;	   Increment count
	    INC     BX					     ;;AN000;;	   Increment count
	    MOV     BYTE PTR $M_RT.$M_TEMP_BUF[BX],$M_SPACE  ;;AN000;;	   Move in a " "
	    INC     BX					     ;;AN000;;	   Increment count
	    CALL    $M_FLUSH_BUF			     ;;AN000;;	   Write out " - " to prepare for special case
	  $ENDIF					     ;;AN000;;	   If it fails we will catch it later
ENDIF

	  POP	  BP					     ;;AN000;; Remember the return address
	  XOR	  BX,BX 				     ;;AN000;; Use BX for buffer count
	  XOR	  DX,DX 				     ;;AN000;; Use DX for count of parms taken off the stack

	  MOV	  $M_RT.$M_SIZE,CL			     ;;AN000;; Save size to later clear stack
	  MOV	  AL,BYTE PTR $M_SL.$M_S_MINW		     ;;AN000;; Get the minimum width
							     ;;
	  CMP	  AL,CL 				     ;;AN000;; Do we need pad chars added?
	  $IF	  A					     ;;AN000;; Yes,
	    SUB     AL,CL				     ;;AN000;;	 Calculate how many pad chars are needed.
	    MOV     DH,AL				     ;;AN000;;	 Save the number of pad characters
	    TEST    BYTE PTR $M_SL.$M_S_FLAG,Right_Align     ;;AN000;;	 Was replaceable parm to be right aligned?
	    $IF     NZ					     ;;AN000;;	 Yes,
	      $DO					     ;;AN000;;	   Begin filling buffer with pad chars
		MOV	AL,BYTE PTR $M_SL.$M_S_PAD	     ;;AN000;;
		MOV	BYTE PTR $M_RT.$M_TEMP_BUF[BX],AL    ;;AN000;;	   Move in a pad char
		INC	BX				     ;;AN000;;
		CMP	BX,$M_TEMP_BUF_SZ		     ;;AN000;;	   Is buffer full?
		$IF	E				     ;;AN000;;	   Yes,
		  CALL	  $M_FLUSH_BUF			     ;;AN000;;	     Flush the buffer
		$ENDIF					     ;;AN000;;
		DEC	DH				     ;;AN000;;	   Have we filled with enough pad chars?
	      $ENDDO  Z 				     ;;AN000;;	   No, next pad character
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;	   Yes,
							     ;;
	  CMP	  BYTE PTR $M_SL.$M_S_MAXW,$M_UNLIM_W	     ;;AN000;; Is maximum width unlimited?
	  $IF	  NE					     ;;AN000;;
	    CMP     BYTE PTR $M_SL.$M_S_MAXW,CL 	     ;;AN000;; Will we exceed maximum width?
	    $IF     B					     ;;AN000;; Yes,
	      SUB     CL,BYTE PTR $M_SL.$M_S_MAXW	     ;;AN000;;	 Calculate how many extra chars
	      MOV     DL,CL				     ;;AN000;;	 Remember how many chars to pop off
	      MOV     CL,BYTE PTR $M_SL.$M_S_MAXW	     ;;AN000;;	 Set new string length
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;
	  OR	  CX,CX 				     ;;AN000;;
	  $IF	  NZ					     ;;AN000;;
	    $DO 					     ;;AN000;; Begin filling buffer with string
	      TEST    BYTE PTR $M_SL.$M_S_FLAG,NOT Char_Type AND $M_TYPE_MASK ;;AN000;;
	      $IF     Z,AND				     ;;AN000;;
	      TEST    $M_SL.$M_S_FLAG,Char_field_ASCIIZ AND $M_SIZE_MASK ;  Is this replace a ASCIIZ string?
	      $IF     NZ				     ;;AN000;; Yes,
		MOV	AL,BYTE PTR ES:[DI]		     ;;AN000;;	 Get first character from string
		INC	DI				     ;;AN000;;	 Next character in string
	      $ELSE					     ;;AN000;; No,
		POP	AX				     ;;AN000;;	 Get character in register
	      $ENDIF					     ;;AN000;;
	      MOV     BYTE PTR $M_RT.$M_TEMP_BUF[BX],AL      ;;AN000;;	Move char into the buffer
	      INC     BX				     ;;AN000;;	 Increase buffer count
	      CMP     BX,$M_TEMP_BUF_SZ 		     ;;AN000;;	 Is buffer full?
	      $IF     E 				     ;;AN000;;	 Yes,
		CALL	$M_FLUSH_BUF			     ;;AN000;;	   Flush the buffer
	      $ENDIF					     ;;AN000;;
	      DEC     CL				     ;;AN000;;	 Have we completed replace?
	    $ENDDO  Z					     ;;AN000;;	   Test again
	  $ENDIF					     ;;AN000;;
							     ;;
	  TEST	  BYTE PTR $M_SL.$M_S_FLAG,Right_Align	     ;;AN000;;	 Was replaceable parm to be left aligned?
	  $IF	  Z					     ;;AN000;; Yes,
	    OR	    DH,DH				     ;;AN000;;	 Do we need pad chars added?
	    $IF     NZ					     ;;AN000;;	 Yes,
	      $DO					     ;;AN000;;	   Begin filling buffer with pad chars
		MOV	AL,BYTE PTR $M_SL.$M_S_PAD	     ;;AN000;;
		MOV	BYTE PTR $M_RT.$M_TEMP_BUF[BX],AL    ;;AN000;;	   Move in a pad char
		INC	BX				     ;;AN000;;
		CMP	BX,$M_TEMP_BUF_SZ		     ;;AN000;;	   Is buffer full?
		$IF	E				     ;;AN000;;	   Yes,
		  CALL	  $M_FLUSH_BUF			     ;;AN000;;	     Flush the buffer
		$ENDIF					     ;;AN000;;
		DEC	DH				     ;;AN000;;	   Have we filled with enough pad chars?
	      $ENDDO  Z 				     ;;AN000;;	     Test again
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;
							     ;;
	  TEST	  BYTE PTR $M_SL.$M_S_FLAG,NOT Char_Type AND $M_TYPE_MASK ;;AN000;;
	  $IF	  Z,AND 				     ;;AN000;;
	  TEST	  $M_SL.$M_S_FLAG,Char_field_ASCIIZ AND $M_SIZE_MASK ;;AN000;;	Is this replace a ASCIIZ string?
	  $IF	  NZ					     ;;AN000;; Yes,
	  $ELSE 					     ;;AN000;;
	    OR	    DL,DL				     ;;AN000;;
	    $IF     NE					     ;;AN000;;
	      $DO					     ;;AN000;;
		POP	[$M_RT.$M_RETURN_ADDR]		     ;;AN000;;	 Clean Up stack using spare variable
		DEC	DL				     ;;AN000;;	 Are we done?
	      $ENDDO  Z 				     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;
	  CALL	  $M_FLUSH_BUF				     ;;AN000;;	     Flush the buffer for the final time
	  PUSH	  BP					     ;;AN000;; Restore the return address
							     ;;
	  RET						     ;;AN000;;
							     ;;
$M_DISPLAY_REPLACE ENDP 				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_FLUSH_BUFFER
;;
;;	FUNCTION: Display the contents of the temporary buffer
;;	INPUTS: DI contains the number of bytes to display
;;	OUTPUTS: BX reset to zero
;;
;;	REGS USED:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_FLUSH_BUF PROC NEAR					     ;;AN000;;
							     ;;
	  PUSH	  CX					     ;;AN000;; Save changed regs
	  PUSH	  ES					     ;;AN000;;
	  PUSH	  DI					     ;;AN000;;
	  PUSH	  DS					     ;;AN000;; Set ES pointing to buffer
	  POP	  ES					     ;;AN000;;
							     ;;
	  MOV	  CX,BX 				     ;;AN000;; Set number of bytes to display
	  XOR	  BX,BX 				     ;;AN000;; Reset buffer counter
	  LEA	  DI,$M_RT.$M_TEMP_BUF			     ;;AN000;; Reset buffer location pointer
	  CALL	  $M_DISPLAY_STRING			     ;;AN000;; Display the buffer
							     ;;
	  $IF	  NC					     ;;AN000;; Error?
	    POP     DI					     ;;AN000;; No, Restore changed regs
	    POP     ES					     ;;AN000;;
	    POP     CX					     ;;AN000;;
	  $ELSE 					     ;;AN000;; Yes,
	    ADD     SP,6				     ;;AN000;;	Fix stack
	    STC 					     ;;AN000;;
	  $ENDIF					     ;;AN000;; Error?
							     ;;
	  RET						     ;;AN000;; Return
							     ;;
$M_FLUSH_BUF ENDP					     ;;AN000;;
							     ;;
							     ;;
	  IF	  CHARmsg				     ;;AN000;; Is the request to include the code for CHAR replace?
	    $M_REPLACE =  TRUE				     ;;AN000;; Yes, THEN include it and flag that we will need common
	    $M_CHAR_ONLY = TRUE 			     ;;AN000;;	 replacement code later
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_CHAR_REPLACE
;;
;;	FUNCTION: Will prepare a single char or ASCIIZ string for replace
;;	INPUTS: DS:SI points at corresponding SUBLIST
;;		ES:DI contains the VALUE from SUBLIST
;;	OUTPUTS: CX contains number of characters on stack
;;		 Top of stack  --> Last character
;;					. . .
;;		 Bot of stack  --> First character
;;
;;	OTHER REGS Revised: AX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_CHAR_REPLACE PROC NEAR				     ;;AN000;;
							     ;;
	    POP     BP					     ;;AN000;; Save return address
	    TEST    $M_SL.$M_S_FLAG,NOT Char_Field_Char AND $M_SIZE_MASK ;;AN000;; Was Character specified?
	    $IF     Z					     ;;AN000;; Yes,
	      MOV     AL,BYTE PTR ES:[DI]		     ;;AN000;;	 Get the character
	      PUSH    AX				     ;;AN000;;	 Put it on the stack
	      INC     CX				     ;;AN000;;	 Increase the count
	      CALL    $M_IS_IT_DBCS			     ;;AN000;;	 Is this the first byte of a DB character
	      $IF     C 				     ;;AN000;;	 Yes,
		MOV	AL,BYTE PTR ES:[DI]+1		     ;;AN000;;	   Get the next character
		PUSH	AX				     ;;AN000;;	   Put it on the stack
		CLC					     ;;AN000;;	   Clear the carry
	      $ENDIF					     ;;AN000;;
	    $ELSE					     ;;AN000;; No, it was an ASCIIZ string
	      $DO					     ;;AN000;;
		MOV	AL,BYTE PTR ES:[DI]		     ;;AN000;;	 Get the character
		OR	AL,AL				     ;;AN000;;	 Is it the NULL?
	      $LEAVE  Z 				     ;;AN000;;	 No,
		INC	DI				     ;;AN000;;	   Next character
		INC	CX				     ;;AN000;;	   Increment the count
	      $ENDDO					     ;;AN000;;	 Yes,
	      SUB     DI,CX				     ;;AN000;;	 Set SI at the beginning of the string
	    $ENDIF					     ;;AN000;;
							     ;;AN000;;
	    PUSH    BP					     ;;AN000;; Restore return address
	    RET 					     ;;AN000;; Return
							     ;;
$M_CHAR_REPLACE ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	  ENDIF 					     ;;AN000;; END of include of CHAR replace code
; 
	  IF	  NUMmsg				     ;;AN000;; Is the request to include the code for NUM replace?
	    $M_REPLACE =  TRUE				     ;;AN000;; Yes, THEN include it and flag that we will need common
	    $M_CHAR_ONLY = FALSE			     ;;AN000;;	 replacement code later
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_BIN2ASC_REPLACE
;;
;;	FUNCTION: Convert a signed or unsigned binary number to an ASCII string
;;		  and prepare to display
;;	INPUTS: DS:SI points at corresponding SUBLIST
;;		ES:DI contains the VALUE from SUBLIST
;;	OUTPUTS: CX contains number of characters on stack
;;		 Top of stack  --> Last character
;;					. . .
;;		 Bot of stack  --> First character
;;	OTHER REGS Revised: BX,DX,AX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_BIN2ASC_REPLACE PROC NEAR				     ;;AN000;;
							     ;;
	    POP     BP					     ;;AN000;; Save return address
							     ;;
	    XOR     DX,DX				     ;;AN000;; Prepare for get binary value (HIGH)
	    XOR     AX,AX				     ;;AN000;; Prepare for get binary value (LOW)
	    MOV     $M_RT.$M_DIVISOR,$M_BASE16		     ;;AN000;; Set default divisor
	    XOR     BX,BX				     ;;AN000;; Use BP as the NEG flag (if applicable)
IF	    NOT     COMR
	    TEST    $M_SL.$M_S_FLAG,NOT $M_BYTE AND $M_SIZE_MASK ;;AN000;; Was BYTE specified?
	    $IF     Z					     ;;AN000;;
	      MOV     AL, BYTE PTR ES:[DI]		     ;;AN000;; Setup byte in AL
	      TEST    $M_SL.$M_S_FLAG,NOT Sgn_Bin_Type AND $M_TYPE_MASK ;;AN000;; Was Signed binary specified?
	      $IF     Z 				     ;;AN000;;
		TEST	AL,10000000b			     ;;AN000;; Is this number negative?
		$IF	NZ				     ;;AN000;;	 Yes,
		  INC	  BX				     ;;AN000;;	   Remember that it was negative
		  AND	  AL,01111111b			     ;;AN000;;	   Make it positive
		$ENDIF					     ;;AN000;;
		MOV	$M_RT.$M_DIVISOR,$M_BASE10	     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	      TEST    $M_SL.$M_S_FLAG,NOT Unsgn_Bin_Type AND $M_TYPE_MASK ;;AN000;; Was Signed binary specified?
	      $IF     Z 				     ;;AN000;;
		MOV	$M_RT.$M_DIVISOR,$M_BASE10	     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ELSE					     ;;AN000;;
ENDIF
	      TEST    $M_SL.$M_S_FLAG,NOT $M_WORD AND $M_SIZE_MASK ;;AN000;; Was WORD specified?
	      $IF     Z 				     ;;AN000;;
		MOV	AX, WORD PTR ES:[DI]		     ;;AN000;; Setup byte in AL
		TEST	$M_SL.$M_S_FLAG,NOT Sgn_Bin_Type AND $M_TYPE_MASK ;; AN000;; Was Signed binary specified?
		$IF	Z				     ;;AN000;;
		  TEST	  AH,10000000b			     ;;AN000;; Is this number negative?
		  $IF	  NZ				     ;;AN000;;	 Yes,
		    INC     BX				     ;;AN000;;	   Remember that it was negative
		    AND     AH,01111111b		     ;;AN000;;	   Make it positive
		  $ENDIF				     ;;AN000;;
		  MOV	  $M_RT.$M_DIVISOR,$M_BASE10	     ;;AN000;;
		$ENDIF					     ;;AN000;;
		TEST	$M_SL.$M_S_FLAG,NOT Unsgn_Bin_Type AND $M_TYPE_MASK ;;AN000;; Was Signed binary specified?
		$IF	Z				     ;;AN000;;
		  MOV	  $M_RT.$M_DIVISOR,$M_BASE10	     ;;AN000;;
		$ENDIF					     ;;AN000;;
	      $ELSE					     ;;AN000;;
IF		NOT	COMR
		MOV	AX, WORD PTR ES:[DI]		     ;;AN000;; Setup Double word in DX:AX
		MOV	DX, WORD PTR ES:[DI]+2		     ;;AN000;;
		TEST	$M_SL.$M_S_FLAG,NOT Sgn_Bin_Type AND $M_TYPE_MASK ;;AN000;; Was Signed binary specified?
		$IF	Z				     ;;AN000;;
		  TEST	  DH,10000000b			     ;;AN000;; Is this number negative?
		  $IF	  NZ				     ;;AN000;;	 Yes,
		    INC     BX				     ;;AN000;;	   Remember that it was negative
		    AND     DH,01111111b		     ;;AN000;;	   Make it positive
		  $ENDIF				     ;;AN000;;
		  MOV	  $M_RT.$M_DIVISOR,$M_BASE10	     ;;AN000;;
		$ENDIF					     ;;AN000;;
		TEST	$M_SL.$M_S_FLAG,NOT Unsgn_Bin_Type AND $M_TYPE_MASK ;;AN000;; Was Signed binary specified?
		$IF	Z				     ;;AN000;;
		  MOV	  $M_RT.$M_DIVISOR,$M_BASE10	     ;;AN000;;
		$ENDIF					     ;;AN000;;
ENDIF
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
							     ;;
	    CALL    $M_CONVERT2ASC			     ;;AN000;; Convert to ASCII string
IF	    NOT     COMR
	    OR	    BX,BX				     ;;AN000;;
	    $IF     NZ					     ;;AN000;; Was number negative?
	      XOR     DX,DX				     ;;AN000;; Yes,
	      MOV     DL,$M_NEG_SIGN			     ;;AN000;;	 Put "-" on the stack with the number
	      PUSH    DX				     ;;AN000;;
	    $ENDIF					     ;;AN000;; No,
ENDIF
							     ;;
	    PUSH    BP					     ;;AN000;; Restore return address
	    RET 					     ;;AN000;; Return
							     ;;
$M_BIN2ASC_REPLACE ENDP 				     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	  ENDIF 					     ;;AN000;; END of include of NUM replace code
; 
	  IF	  DATEmsg				     ;;AN000;; Is the request to include the code for DATE replace?
	    $M_REPLACE =  TRUE				     ;;AN000;; Yes, THEN include it and flag that we will need common
	    $M_CHAR_ONLY = FALSE			     ;;AN000;;	  replacement code later
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_DATE_REPLACE
;;
;;	FUNCTION: Convert a date to a decimal ASCII string using current
;;		  country format and prepare to display
;;	INPUTS: DS:SI points at corresponding SUBLIST
;;		ES:DI points at VALUE from SUBLIST
;;	OUTPUTS: CX contains number of characters on stack
;;		 Top of stack  --> Last character
;;					. . .
;;		 Bot of stack  --> First character
;;	OTHER REGS Revised: DX, AX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_DATE_REPLACE PROC NEAR				     ;;AN000;;
							     ;;
	    POP     BP					     ;;AN000;; Save return address
	    MOV     $M_RT.$M_DIVISOR,$M_BASE10		     ;;AN000;; Set default divisor
	    CALL    $M_GET_DATE 			     ;;AN000;; Set date format/separator in $M_RT
							     ;;AN000;; All O.K.?
	    XOR     DX,DX				     ;;AN000;; Reset DX value
	    XOR     AX,AX				     ;;AN000;; Reset AX value
	    CMP     WORD PTR $M_RT.$M_DATE_FORMAT,0	     ;;AN000;; USA Date Format
	    $IF     E					     ;;AN000;;	Beginning from end: (saved on the stack)
	      CALL    $M_YEAR				     ;;AN000;;	 Get Year
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	      PUSH    WORD PTR $M_RT.$M_DATE_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;; Increment count
	      XOR     AX,AX				     ;;AN000;; Reset AX value
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+3	     ;;AN000;;	Get Day
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	      PUSH    WORD PTR $M_RT.$M_DATE_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;; Increment count
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+2	     ;;AN000;;	Get Month
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	    $ENDIF					     ;;AN000;;
							     ;;
	    CMP     WORD PTR $M_RT.$M_DATE_FORMAT,1	     ;;AN000;; EUROPE Date Format
	    $IF     E					     ;;AN000;;	Beginning from end: (saved on the stack)
	      CALL    $M_YEAR				     ;;AN000;;	 Get Year
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	      PUSH    WORD PTR $M_RT.$M_DATE_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;;
	      XOR     AX,AX				     ;;AN000;; Reset AX
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+2	     ;;AN000;;	Get Month
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	      PUSH    WORD PTR $M_RT.$M_DATE_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;;
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+3	     ;;AN000;;	Get Day
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	    $ENDIF					     ;;AN000;;
							     ;;
	    CMP     WORD PTR $M_RT.$M_DATE_FORMAT,2	     ;;AN000;; JAPAN Date Format
	    $IF     E					     ;;AN000;;	Beginning from end: (saved on the stack)
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+3	     ;;AN000;;	Get Day
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	      PUSH    WORD PTR $M_RT.$M_DATE_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;;
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+2	     ;;AN000;;	Get Month
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	      PUSH    WORD PTR $M_RT.$M_DATE_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;;
	      CALL    $M_YEAR				     ;;AN000;;	 Get Year
	      CALL    $M_CONVERTDATE			     ;;AN000;;	Convert it to an ASCII string
	    $ENDIF					     ;;AN000;;
							     ;;
	    PUSH    BP					     ;;AN000;; Restore return address
	    RET 					     ;;AN000;; Return
							     ;;
$M_DATE_REPLACE ENDP					     ;;AN000;;
							     ;;
$M_GET_DATE PROC    NEAR				     ;;AN000;;
	    MOV     AH,DOS_GET_COUNTRY			     ;;AN000;; Call DOS for country dependant info
	    MOV     AL,0				     ;;AN000;; Get current country info
	    LEA     DX,$M_RT.$M_TEMP_BUF		     ;;AN000;; Set up addressibility to buffer
	    INT     21H 				     ;;AN000;;
	    $IF     C					     ;;AN000;; No,
	      MOV     WORD PTR $M_RT.$M_DATE_FORMAT,$M_DEF_DATE_FORM ;;AN000;;	 Set default date format    (BH)
	      MOV     BYTE PTR $M_RT.$M_DATE_SEPARA,$M_DEF_DATE_SEP ;;AN000;;	Set default date separator (BL)
	    $ENDIF					     ;;AN000;;
	    RET 					     ;;AN000;;
$M_GET_DATE ENDP					     ;;AN000;;
							     ;;
$M_YEAR     PROC    NEAR				     ;;AN000;;
	    MOV     AX,WORD PTR $M_SL.$M_S_VALUE	     ;;AN000;;	Get Year
	    TEST    $M_SL.$M_S_FLAG,Date_MDY_4 AND $M_DATE_MASK ;;AN000;; Was Month/Day/Year (2 Digits) specified?
	    $IF     Z					     ;;AN000;;
	      CMP     AX,$M_MAX_2_YEAR			     ;;AN000;;	Get Year
	      $IF     A 				     ;;AN000;;
		MOV	AX,$M_MAX_2_YEAR		     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	    RET 					     ;;AN000;;
$M_YEAR     ENDP					     ;;AN000;;
							     ;;
$M_CONVERTDATE PROC NEAR				     ;;AN000;;
	    POP     WORD PTR $M_RT.$M_TEMP_BUF		     ;;AN000;; Save return address
	    MOV     $M_RT.$M_SIZE,CL			     ;;AN000;; Save the size before conversion
	    CALL    $M_CONVERT2ASC			     ;;AN000;; Convert it to an ASCII string
	    DEC     CX					     ;;AN000;; Test if size only grew by 1
	    CMP     CL,$M_RT.$M_SIZE			     ;;AN000;; Did size only grow by one
	    $IF     E					     ;;AN000;; Yes,
	      MOV     AX,$M_TIMEDATE_PAD		     ;;AN000;;	 Get a pad character (0)
	      PUSH    AX				     ;;AN000;;	 Save it
	      INC     CX				     ;;AN000;;	 Count it
	    $ENDIF					     ;;AN000;;
	    INC     CX					     ;;AN000;; Restore CX
	    PUSH    WORD PTR $M_RT.$M_TEMP_BUF		     ;;AN000;; Save return address
	    RET 					     ;;AN000;;
$M_CONVERTDATE ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	  ENDIF 					     ;;AN000;; END of include of DATE replace code
; 
	  IF	  TIMEmsg				     ;;AN000;; Is the request to include the code for TIME replace?
	    $M_REPLACE =  TRUE				     ;;AN000;; Yes, THEN include it and flag that we will need common
	    $M_CHAR_ONLY = FALSE			     ;;AN000;;	  replacement code later
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_TIME_REPLACE
;;
;;	FUNCTION: Convert a time to a decimal ASCII string
;;		  and prepare to display
;;	INPUTS: DS:SI points at corresponding SUBLIST
;;		ES:DI points at VALUE from SUBLIST
;;	OUTPUTS: CX contains number of characters on stack
;;		 Top of stack  --> Last character
;;					. . .
;;		 Bot of stack  --> First character
;;	REGS USED: BP,CX,AX
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_TIME_REPLACE PROC NEAR				     ;;AN000;;
							     ;;
	    POP     BP					     ;;AN000;; Save return address
	    MOV     $M_RT.$M_DIVISOR,$M_BASE10		     ;;AN000;; Set default divisor
	    CALL    $M_GET_TIME 			     ;;AN000;; All O.K.?
	    TEST    $M_SL.$M_S_FLAG,Time_Cty_Type AND $M_TIME_MASK ;;AN000;; Is this a request for current country info?
	    $IF     NZ					     ;;AN000;; Yes,
	      CMP     BYTE PTR $M_RT.$M_TIME_FORMAT,0	     ;;AN000;; Is the current country format 12 Hour?
	      $IF     E 				     ;;AN000;; Yes,
		MOV	AL,BYTE PTR $M_SL.$M_S_VALUE	     ;;AN000;;	Get Hours
		CMP	AL,12				     ;;AN000;;	Is hour 12 or less?
		$IF	L,OR				     ;;AN000;;	 or
		CMP	AL,23				     ;;AN000;;	  Is hour 24 or greater?
		$IF	G				     ;;AN000;;	Yes,
		  MOV	  AL,$M_AM			     ;;AN000;;
		  PUSH	  AX				     ;;AN000;;	  Push an "a" to represent AM.
		  INC	  CX				     ;;AN000;;
		$ELSE					     ;;AN000;;	No,
		  MOV	  AL,$M_PM			     ;;AN000;;
		  PUSH	  AX				     ;;AN000;;	  Push an "p" to represent PM.
		  INC	  CX				     ;;AN000;;
		$ENDIF					     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
							     ;;
	    XOR     AX,AX				     ;;AN000;;
	    XOR     DX,DX				     ;;AN000;;
	    TEST    $M_SL.$M_S_FLAG,Time_HHMMSSHH_Cty AND $M_SIZE_MASK ;;AN000;; Was Hour/Min/Sec/Hunds (12 Hour) specified?
	    $IF     NZ					     ;;AN000;;
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+3	     ;;AN000;;	Get Hundreds
	      CALL    $M_CONVERTTIME			     ;;AN000;;
	      PUSH    WORD PTR $M_RT.$M_DECI_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	    TEST    $M_SL.$M_S_FLAG,Time_HHMMSSHH_Cty AND $M_SIZE_MASK ;;AN000;; Was Hour/Min/Sec/Hunds (12 Hour) specified?
	    $IF     NZ,OR				     ;;AN000;;
	    TEST    $M_SL.$M_S_FLAG,Time_HHMMSS_Cty AND $M_SIZE_MASK ;;AN000;; Was Hour/Min/Sec (12 Hour) specified?
	    $IF     NZ					     ;;AN000;;
	      MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+2	     ;;AN000;;	Get Seconds
	      CALL    $M_CONVERTTIME			     ;;AN000;;
	      PUSH    WORD PTR $M_RT.$M_TIME_SEPARA	     ;;AN000;;
	      INC     CX				     ;;AN000;;
	    $ENDIF					     ;;AN000;;
							     ;;        Do Hour/Min (12 Hour)
	    MOV     AL,BYTE PTR $M_SL.$M_S_VALUE+1	     ;;AN000;;	Get Minutes
	    CALL    $M_CONVERTTIME			     ;;AN000;;
	    PUSH    WORD PTR $M_RT.$M_TIME_SEPARA	     ;;AN000;;
	    INC     CX					     ;;AN000;;
							     ;;
	    MOV     AL,BYTE PTR $M_SL.$M_S_VALUE	     ;;AN000;;	Get Hours
	    TEST    $M_SL.$M_S_FLAG,Time_Cty_Type AND $M_TIME_MASK ;;AN000;; Is this a request for current country info?
	    $IF     NZ					     ;;AN000;; Yes,
	      CMP     BYTE PTR $M_RT.$M_TIME_FORMAT,0	     ;;AN000;; Is the current country format 12 Hour?
	      $IF     E 				     ;;AN000;; Yes,
		CMP	AL,13				     ;;AN000;;	Is hour less than 12?
		$IF	GE				     ;;AN000;;	Yes,
		  SUB	  AL,12 			     ;;AN000;;	  Set to a 12 hour value
		$ENDIF					     ;;AN000;;
		CMP	AL,0				     ;;AN000;;	Is hour less than 12?
		$IF	E				     ;;AN000;;	Yes,
		  MOV	  AL,12 			     ;;AN000;;	  Set to a 12 hour value
		$ENDIF					     ;;AN000;;
	      $ENDIF					     ;;AN000;;
	    $ENDIF					     ;;AN000;;
	    CALL    $M_CONVERT2ASC			     ;;AN000;; Convert it to ASCII
							     ;;
	    PUSH    BP					     ;;AN000;; Restore return address
	    RET 					     ;;AN000;; Return
							     ;;
$M_TIME_REPLACE ENDP					     ;;AN000;;
							     ;;
$M_GET_TIME PROC    NEAR				     ;;AN000;;
	    MOV     AH,DOS_GET_COUNTRY			     ;;AN000;; Call DOS for country dependant info
	    MOV     AL,0				     ;;AN000;; Get current country info
	    LEA     DX,$M_RT.$M_TEMP_BUF		     ;;AN000;; Set up addressibility to buffer
	    INT     21H 				     ;;AN000;;
	    $IF     C					     ;;AN000;; No,
	      MOV     WORD PTR $M_RT.$M_TIME_FORMAT,$M_DEF_TIME_FORM ;;AN000;;	 Set default time format    (BH)
	      MOV     BYTE PTR $M_RT.$M_TIME_SEPARA,$M_DEF_TIME_SEP ;;AN000;;	Set default time separator (BL)
	      MOV     BYTE PTR $M_RT.$M_DECI_SEPARA,$M_DEF_DECI_SEP ;;AN000;;	Set default time separator (BL)
	    $ENDIF					     ;;AN000;;
	    RET 					     ;;AN000;;
$M_GET_TIME ENDP					     ;;AN000;;
							     ;;
$M_CONVERTTIME PROC NEAR				     ;;AN000;;
	    POP     WORD PTR $M_RT.$M_TEMP_BUF		     ;;AN000;; Save return address
	    MOV     $M_RT.$M_SIZE,CL			     ;;AN000;; Save the size before conversion
	    CALL    $M_CONVERT2ASC			     ;;AN000;; Convert it to an ASCII string
	    DEC     CX					     ;;AN000;; Test if size only grew by 1
	    CMP     CL,$M_RT.$M_SIZE			     ;;AN000;; Did size only grow by one
	    $IF     E					     ;;AN000;; Yes,
	      MOV     AX,$M_TIMEDATE_PAD		     ;;AN000;;	 Get a pad character (0)
	      PUSH    AX				     ;;AN000;;	 Save it
	      INC     CX				     ;;AN000;;	 Count it
	    $ENDIF					     ;;AN000;;
	    INC     CX					     ;;AN000;; Restore CX
	    PUSH    WORD PTR $M_RT.$M_TEMP_BUF		     ;;AN000;; Save return address
	    RET 					     ;;AN000;;
$M_CONVERTTIME ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	  ENDIF 					     ;;AN000;; END of include of TIME replace
	ENDIF						     ;;AN000;; END of include of Replacement common code
; 
	IF	INPUTmsg				     ;;AN000;; Is the request to include the code for NUM replace?
	  INPUTmsg =	FALSE				     ;;AN000;; Yes, THEN include it and reset the flag
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;	PROC NAME: $M_WAIT_FOR_INPUT
;;
;;	FUNCTION:  To accept keyed input and return extended key value
;;		   in AX register
;;	INPUTS:    DL contains the DOS function requested for input
;;	OUPUTS:    AX contains the extended key value that was read
;;	REGS USED:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
							     ;;
$M_WAIT_FOR_INPUT PROC NEAR				     ;;AN000;;
							     ;;
	  PUSH	  CX					     ;;AN000;; Save CX
	  PUSH	  DX					     ;;AN000;; Save DX
	  PUSH	  DS					     ;;AN000;; Save Data segment
							     ;;
	  CMP	  DL,DOS_CLR_KEYB_BUF_MASK		     ;;AN001;; Are we to clear the keyboard buffer?
	  $IF	  A					     ;;AN001;; Yes,
	    MOV     AL,DL				     ;;AN001;;	 Mov function into AL
	    AND     AL,LOW_NIB_MASK			     ;;AN001;;	 Mask out the C in high nibble
	    MOV     AH,DOS_CLR_KEYB_BUF 		     ;;AN001;;	 Set input function
	  $ELSE 					     ;;AN001;; No,
	    MOV     AH,DL				     ;;AN000;;	 Put DOS function in AH
	  $ENDIF					     ;;AN001;;
	  PUSH	  ES					     ;;AN000;; Get output buffer segment
	  POP	  DS					     ;;AN000;;
	  MOV	  DX,DI 				     ;;AN000;;	 Get output buffer offset in case needed
	  INT	  21H					     ;;AN000;; Get keyboard input
	  POP	  DS					     ;;AN000;;

	  CMP	  DL,DOS_BUF_KEYB_INP			     ;;AN000;;
	  CLC						     ;;AN000;;
	  $IF	  NE					     ;;AN000;; If character input
	    CALL    $M_IS_IT_DBCS			     ;;AN000;;	Is this character DBCS?
	    $IF     C					     ;;AN000;;
	      MOV     CL,AL				     ;;AN000;; Save first character
	      MOV     AH,DL				     ;;AN001;; Get back function
	      INT     21H				     ;;AN000;; Get keyboard input
	      MOV     AH,CL				     ;;AN000;; Retreive first character  AX = xxxx
	      CLC					     ;;AN000;; Clear carry condition
	    $ELSE					     ;;AN000;;
	      MOV     AH,0				     ;;AN000;; AX = 00xx where xx is SBCS
	    $ENDIF					     ;;AN000;;
	  $ENDIF					     ;;AN000;;
							     ;;
	  $IF	  NC					     ;;AN000;;
	    POP     DX					     ;;AN000;;
	    POP     CX					     ;;AN000;;
	  $ELSE 					     ;;AN000;;
	    ADD     SP,4				     ;;AN000;;
	    STC 					     ;;AN000;; Reset carry flag
	  $ENDIF					     ;;AN000;;
	  RET						     ;;AN000;; Return
							     ;;
$M_WAIT_FOR_INPUT ENDP					     ;;AN000;;
							     ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	ENDIF						     ;;AN000;; END of include of Wait for Input
      ENDIF						     ;;AN000;; END of include of SYSDISPMSG
    ENDIF						     ;;AN000;; END of include of MSG_DATA_ONLY
ENDIF							     ;;AN000;; END of include of Structure only
