;	SCCSID = @(#)qmsgcp.asm	6.3 91/04/01
;	SCCSID = @(#)qmsgcp.asm	6.3 91/04/01

;***********************************************************************
; QMSGCP.ASM:  Message query (retreive code pages & language IDs)
;***********************************************************************
;   Modification history
;
;B001 PB717389 Add TRACE support for DosQueryMessage
;***********************************************************************

;***********************************************************************
; INCLUDES
;***********************************************************************
	INCL_DOSMEMMGR	 EQU 1
	INCL_DOSFILEMGR  EQU 1
.xlist
	INCLUDE MSGFEQU.INC
	INCLUDE MSGFMAC.INC
	INCLUDE ERROR.INC
	INCLUDE ERROR2.INC
	INCLUDE BASEMACA.INC
	include dc1segs.inc					; DCR 704
.list

MSGSEG_HEADER  STRUC
  SEG_SIGNATURE  DB  10 DUP(?)
  SEG_VERSION	 DB  ?
  SEG_FLAGS	 DB  ?
  SEG_TYPE	 DW  ?
  SEG_pMSGDATA	 DW  ?
MSGSEG_HEADER ENDS

SUBFILE_HDR STRUC				    ;MSG FILE EXTENDED HEADER
	HDR_pNEXT	DW	?
	HDR_CPTYPE	DB	?		;dbcs or sbcs characters
	HDR_CNTY_ID	DW	?		;COUNTRY ID
	HDR_LANG_ID	DW	?		;LANGUAGE FAMILY ID
	HDR_LANG_VERID	DW	?		;LANGUAGE VERSION ID
	HDR_CNT_CP	DW	?		;CODE PAGE COUNT
	HDR_CP_ID	DW	16 dup (0)	;CODE PAGE IDs
	HDR_FILENAME	DB	ASCIIZ_LEN+1 dup(?) ;file name
SUBFILE_HDR  ENDS

SEG_SIZE   EQU	4096h

;***********************************************************************
; EXTERNALS
;***********************************************************************
;
IFNDEF FamilyAPI
	EXTRN	DOSFSRAMSEMREQUEST: FAR
	EXTRN	DOSFSRAMSEMCLEAR:   FAR
	EXTRN	MSGTRACE:	    NEAR	;BN001;
ENDIF ;FamilyApi

	EXTRN	DOSFREESEG : FAR
	EXTRN	DOSALLOCSEG : FAR
	EXTRN	DOSCASEMAP :FAR
	EXTRN	DOSREAD   : FAR
	EXTRN	DOSCLOSE  : FAR
	EXTRN	DOSCHGFILEPTR : FAR
	EXTRN	CHECK_DBCS: near
	EXTRN	FNSRCH	  : near
	EXTRN	FIND_FILE : NEAR
	EXTRN	FILENAME_STRIP : NEAR
; EXTERNALS IN ISEG

IFNDEF	FamilyAPI
iseg	SEGMENT
ELSE
iseg	SEGMENT 		para public 'data'
ENDIF	;FamilyAPI
	extrn	SIGNATURE_MSGF:BYTE
IFNDEF FamilyAPI
	extrn	GetFSRamSem :  WORD
ENDIF	;FamilyAPU
	extrn	ram_file_found	: byte
iseg	ENDS


PAGE 60,132
IFNDEF	FamilyAPI
	.286p
ENDIF	;FamilyAPI
TITLE Message Retriever - DosTrueGetMessage - IBM CONFIDENTIAL
COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: DOSIQUERYMESSAGECP 				    */
/*									    */
/*  DESCRIPTION NAME: Return code pages and language IDs.		    */
/*									    */
/*  FUNCTION: Retrieves all the code pages and language IDs to the	    */
/*	      user given buffer.					    */
/*									    */
/*  NOTE: The filename input parameter can be of the form pathname\	    */
/*	  filename.							    */
/*									    */
/*  ENTRY POINT: DOSIQUERYMESSAGECP  (PROTECT MODE ONLY)		    */
/*									    */
/*  INPUT: DATAAREA : Message buffer address(double word)		    */
/*	   DATALENGTH : Message buffer length(word)			    */
/*	   FILENAME : Root message file name(double word)		    */
/*	   CPLENGTH : Actual message length returned(word)		    */
/*	   MSG_SEG  : SEG:OFFS of bound message segment(double word)	    */
/*									    */
/*  EXIT-NORMAL: DATAAREA points to message buffer which contains	    */
/*		 the retrieved code pages and language IDs.		    */
/*									    */
/*		 CPLENGTH contains the actual length of the		    */
/*		 returned code pages and language IDs.			    */
/*									    */
/*  EXIT-ERROR:  Error setup and returned,				    */
/*		   . Message file not found				    */
/*		   . ERROR_BUFFER_OVERFLOW				    */
/*		   . ERROR_MR_MID_NOT_FOUND				    */
/*		   . ERROR_MR_UN_ACC_MSGF				    */
/*		   . ERROR_MR_INV_MSGF_FORMAT				    */
/*		   . ERROR_MR_UN_PERFORM				    */
/*									    */
/*  SIDE EFFECTS: None. 						    */
/*									    */
/*  INTERNAL REFERENCES: TRY_RAM     : check for message in ram 	    */
/*			 TRY_DISK	  : check for the file on disk	    */
/*									    */
/*  EXTERNAL REFERENCES: CHECK_DBCS,					    */
/*			 DosFSSemRequest,				    */
/*			 DosClose,					    */
/*			 DosFSSemClear. 				    */
/*									    */
/*  PSEUDO CODE:							    */
/*									    */
/*  BEGIN								    */
/*    EnterPROC(protect mode linkage setup)				    */
/*    Save caller's environment                                             */
/*    Trace hook up							    */
/*    Call DosFSSemRequest requesting indefinite wait			    */
/*    Call check_DBCS							    */
/*    If DBCS								    */
/*    then								    */
/*	Set DBCS flag on						    */
/*    CALL TRY_RAM							    */
/*    if not found then 						    */
/*	 CALL TRY_DISK							    */
/*    if data was found in ram or disk					    */
/*	 transfer data from temp segment to users buffer		    */
/*    move length of transfered data into users variable CPLENGTH	    */
/*    If message file handle is NOT saved				    */
/*    then								    */
/*	Call DosClose							    */
/*    If return code is NOT OK and error code <> message too long	    */
/*    then								    */
/*	Call copyretmsg(return error message to user buffer)		    */
/*	    If return code is NOT OK					    */
/*	then								    */
/*	  Restore the old return code					    */
/*    Call DosSemClear							    */
/*    Trace hook up							    */
/*    Restore caller's environment                                          */
/*  END 								    */
/*									    */
/****************************************************************************/
ENDCOMMENT $


code	SEGMENT
	ASSUME	CS:code, ES:iseg

PROCEDURE  DOSIQUERYMESSAGECP ,FAR

	ARGVAR MSG_SEG,DWORD
	ARGVAR CPLENGTH,DWORD
	ARGVAR FILENAME,DWORD
	ARGVAR DATALENGTH,WORD
	ARGVAR DATAAREA,DWORD

;*****************************************************************
; LOCAL STACK VARIABLES
;*****************************************************************

	LOCALVAR IS_DBCS,WORD		;are we dealing with DBCS stuff
	LOCALVAR TEMP_SEG,WORD		;selector of temp seg
	LOCALVAR LTEMP_SEG,WORD 	;length of temp. segement


IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

;-----------------------------------------------------------------
; SAVE CALLERS ENVIRONMENT
;-----------------------------------------------------------------
;
	SAVE_CALLER
;
	CLD				;CLEAR DIRECTION FLAG

	PUBLIC PREQMSGCP
PREQMSGCP:

IFNDEF	FamilyAPI				;BN001;
;****************************			;BN001;
;	Trace hook				;BN001;
;	PreInvocation - DosQrymessage		;BN001;
						;BN001;
	push	TraceCode_PreQryMessage 	;BN001;
	push	0				;BN001;
	push	0				;BN001;
	push	0				;BN001;
	call	MSGTRACE			;BN001;
;						;BN001;
;****************************			;BN001;
ENDIF	;FamilyAPI				;BN001;

;
;Call DosAllocSeg to get temp seg to store data
;
IFNDEF FamilyAPI
	PUSH   SEG_SIZE 	       ; size
ELSE
	MOV    ax,seg_size
	PUSH   ax
ENDIF	 ;Family

	PUSH   SS
	LEA	AX,TEMP_SEG
	PUSH	ax			   ; address of temp seg

IFNDEF FamilyAPI
	PUSH	0			  ; allocation flags
ELSE
	xor	ax,ax
	push	ax
ENDIF

	CALL	DOSALLOCSEG		   ; get temp seg
	OR	AX,AX
	JZ	GOT_SEG
	MOV	AX,ERROR_NOT_ENOUGH_MEMORY  ;NOT_ENOUGH_MEMORY
	JMP	DONE_MAIN

GOT_SEG:

;*************************************************************************
;  SUPPORT FOR DBCS
;
	MOV	IS_DBCS,0		      ;0 = NOT DBCS
;
; CALL DOSGETDBCSEV - GET DBCS ENVIRONMENT VECTOR;
;
	CALL	CHECK_DBCS		;GET DBCS ENVIRONMENT VECTOR
	jnc	GET_PARMS		;if not carry, SINGLE BYTE
	MOV	IS_DBCS,1		;ELSE DOUBLE BYTE

GET_PARMS:

;*************************************************************************
;  Call TRY_RAM to look for bound messages
;
	LEA    AX, LTEMP_SEG		; Push address of length of temp seg
	push   AX

	push   TEMP_SEG 		; Push selector of temp seg

	PUSH   msg_segh
	PUSH   MSG_SEGL 		; Push address of message segment
	PUSH   FILENAMEh		; Push address of filename
	PUSH   FILENAMEl

	CALL   TRY_RAM			; Look for data in the bound segment

	OR     AX,AX			; is rc == 0
	JZ     XFER_DATA		; Yes

;**************************************************************
; Call TRY_DISK to look for file on disk

	LEA    AX, LTEMP_SEG
	PUSH   AX			; push adddress to store length of temp seg

	PUSH   TEMP_SEG 		; push selector of temp seg

	PUSH   MSG_SEGh 		; Push address of message segment
	PUSH   MSG_SEGl
	PUSH   FILENAMEh		; push far address of filename
	PUSH   FILENAMEl

	CALL   TRY_DISK
	OR     AX,AX			; check return code
	JNE    DONE_MAIN		; leave with bad error code in ax

XFER_DATA:
	MOV    CX, LTEMP_SEG
	MOV    AX, DATALENGTH
	CMP    AX,CX			; is users buffer large enough?
	JAE    BUFFER_OK		; yes

	MOV    CX,AX			; Transfer only the size of the users buffer
	MOV    AX,ERROR_BUFFER_OVERFLOW
	JMP    short BUFFER_SMALL

BUFFER_OK:
	MOV    AX,0

BUFFER_SMALL:
	mov    dx,cx
	LES    DI,CPLENGTH		; In either case tell user how much they got
	MOV    ES:[DI],dX

	LES    DI, DATAAREA		; ES:DI points to users buffer

	MOV    DX, TEMP_SEG
	MOV    DS, DX
	XOR    SI,SI			; DS:SI points to our temp buffer

	REP    MOVSB			; ES:DI <- DS:SI till cx = 0

	mov    cx,ax			; save our error code
	PUSH   dx			; Push temp segment selector

	CALL   DOSFREESEG		; give up temp segment
	mov    ax,cx			; get return code back

DONE_MAIN:

IFNDEF	FamilyAPI				;BN001;
;****************************			;BN001;
;	Trace hook				;BN001;
;	PostInvocation - DosQrymessage		;BN001;
						;BN001;
	push	TraceCode_PostQryMessage	;BN001;
	push	0				;BN001;
	push	0				;BN001;
	push	ax				;BN001;
	call	MSGTRACE			;BN001;
;						;BN001;
;****************************			;BN001;
ENDIF	;FamilyAPI				;BN001;

	RESTORE_CALLER 18

ENDPROC DOSIQUERYMESSAGECP


COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: TRY_RAM						    */
/*									    */
/*  DESCRIPTION NAME: Searches for code page info in the bound message	    */
/*			  segment.					    */
/*									    */
/*  FUNCTION:  Searches the root and subfile headers for codepage info.     */
/*									    */
/*									    */
/*  NOTE: None. 							    */
/*									    */
/*  ENTRY POINT: TRY_RAM						    */
/*									    */
/*  INPUT:  ARGVAR @FILENAME,DWORD (input )  - far ptr to filename	    */
/*	    ARGVAR @MSG_SEG,DWORD  (input )	- segment ptr to message seg*/
/*	    ARGVAR @TEMP_SEG,WORD  (output)	- selector of temp seg.     */
/*	    ARGVAR @LTEMP_SEG,WORD (output)	- len of data in temp seg.  */
/*									    */
/*									    */
/*  EXIT-NORMAL: AX = 0  (file found and cpdata retrived)		    */
/*									    */
/*  EXIT-ERROR: Error setup and returned.				    */
/*		 . Msg segment doesn't exist                                */
/*		 . insufficient memory to allocate temp buffer		    */
/*		 . incorrect version number				    */
/*		 . file not found					    */
/*									    */
/*  SIDE EFFECTS: None. 						    */
/*									    */
/*  INTERNAL REFERENCES: None.						    */
/*									    */
/*  EXTERNAL REFERENCES: FNSRCH:  search for filename in bound data segment */
/*									    */
/*  PSEUDO CODE:							    */
/*									    */
/*  BEGIN								    */
/*    ENTERPROC (protect mode linkage setup)				    */
/*    IF a message segment exists					    */
/*	 IF version field of header = 1  then	 ;this is an old header     */
/*	    rc =  error wrong version					    */
/*	  ELSE		   ; this is a valid header			    */
/*	    prepare parameters to pass to FNSRCH			    */
/*	    CALL FNSRCH  (in ramfind.asm)				    */
/*	    IF the filename was found	 ;file was found in ram 	    */
/*		  use return code from FNSRCH to create ptr to filename strc*/
/*	       move ptr to code page info				    */
/*	       CALL DOSALLOCSEG to create 4k temp segment		    */
/*		    (this should allow for 200 sub-files per root)	    */
/*	       if no error then 					    */
/*		 copy cp count into temp segment			    */
/*		 while there are cp's left                                  */
/*		   copy cp info into temp segment			    */
/*		 copy language family and id into temp segment		    */
/*		 move file ptr to point to first extended header (if exists)*/
/*		 while there are sub files to process			    */
/*		     transfer cp count to temp seg			    */
/*		     while there is cp data to transfer 		    */
/*			 transfer cp id's to temp seg                       */
/*		     transfer lang family/id into temp seg		    */
/*		 end while						    */
/*		 return no error					    */
/*	      else rc = error insufficient memory			    */
/*	    endif ; the filename was found				    */
/*	 endelse  ; version number correct				    */
/*    endif	  ; message segment exists				    */
/*  END 	  ; procedure try ram					    */
/****************************************************************************/
ENDCOMMENT $

PROCEDURE  TRY_RAM,NEAR

	ARGVAR	   FILENAME,DWORD	;SEL:OFFSET OF FILENAME
	ARGVAR	   MSG_SEG,DWORD	;sel:offset of message seg
	ARGVAR	   TEMP_SEG,WORD	;TEMP SEGMENT selector
	ARGVAR	   LTEMP_SEG,WORD	;PTR TO LENGTH OF TEMP SEGMENT
	LOCALVAR   FNAME_COPY, ASCIIZ_LEN +1;buffer to hold copy of filename
	LOCALVAR   COUNTRY_AND_CP ,DWORD ;structure to hold country and codepage

;-----------------------------------------------------------------
; SAVE CALLERS ENVIRONMENT
IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI
;
	SAVE_CALLER
;
	ASSUME	DS:NOTHING, ES:NOTHING
	LDS	SI,MSG_SEG
	MOV	CX,[si].SEG_pMSGDATA
	OR	CX,CX
	JNZ	MSGSEG_EXISTS
	MOV	AX,ERROR_FILE_NOT_FOUND
	JMP	DONE_RAM

MSGSEG_EXISTS:
	CMP	[SI].SEG_VERSION,2	    ;Is this a version 2 header ??
	JGE	VERSION2		    ;yes
	MOV	AX,ERROR_MR_INV_MSGF_FORMAT ;invalid msgfile format
	JMP	DONE_RAM

VERSION2:

copy_fname:
	lds    si,filename	    ; ds:si --> filename with path
; make our own copy of the file name that we can uppercase
	mov    ax,ss
	mov    es,ax
	lea    di,FNAME_COPY
	mov    cx,ASCIIZ_LEN + 1
TOP_COPY:
	lodsb			       ;es:di  <-- ds:si  till Null or cx = 0
	stosb
	or     al,al
	loopnz TOP_COPY
	mov    bx,ASCIIZ_LEN + 1       ; calculate length
	sub    bx,cx

; call cc_filename_strip to find the last \ in the input filename (in ...src\cmd\comsub)

	mov    ax,ss
	mov    es,ax
	lea    dx,FNAME_COPY	    ;filename strips wants filename in es:dx
	MOV	ax,is_dbcs
	CALL	cc_filename_strip   ; find it (returns in filename is es:di)

; uppercase it cause  FNSRCH is case sensitive	(call doscasemap)
	push   bx		       ; push length of filename
	xor    ax,ax
	mov    COUNTRY_AND_CPh,ax      ; initialize both to 0,0
	mov	COUNTRY_AND_CPl,ax	; initialize both to 0,0
	push	ss
	lea	ax, COUNTRY_AND_CP
	push	ax
	push	es			   ; es:di points to our copy of filename
	push	di

	CALL	DOSCASEMAP

; prepare parameters to pass to fnsrch
					   ; es:di already points to filename
	LDS	SI,MSG_SEG
	MOV	si,[si].SEG_pMSGDATA	; DS:SI points to number of files

	CALL	FNSRCH
	JNC	FILE_FOUND
	MOV	AX,ERROR_FILE_NOT_FOUND ; FILE_NOT_FOUND
	JMP	short DONE_RAM

FILE_FOUND:
	MOV    SI,CX		       ; si points to null byte of filename
	ADD    SI,2		       ; skip past length of header

	MOV    DI, TEMP_SEG	       ; DI now points to temp seg selector
	MOV    ES,DI		       ; ES: is now temp seg
	XOR    DI,DI		       ; ES:DI points to temp segment

;	mOV	SI, WORD PTR [SI]	; indirect SI (it not points to roots
					; extended header information)

COPY_DATA:
	MOV	DX,SI			; save pointer to start of language data area
	ADD	SI,9			; mov si to code page count
	MOV	cx,word ptr [si]	; cx contains count
	INC	CX			; INC so that CPCOUNT is also transferred
	REP	MOVSW			; copy CP count and all code page into

	MOV	SI,DX			; si points to start of header
	add	SI,5			; skip pointer to next,cptype, and
					; country info

	MOVSW				; move language family to temp seg
	MOVSW				; move language ID to temp seg

TRY_NEXT_SUB:
	MOV	SI,DX			; SI points to start of header
	MOV	SI, WORD PTR [SI]	; move to next pointer
	MOV	DX,SI			; save new pointer
	OR	SI,SI			; is it null?
	JZ	DONE_RAM		; Yes leave

	PUSH	DS			; push far pointer to filename
	lea	ax,[si]+HDR_FILENAME	;  "               "
	PUSH	ax			;  "               "
	PUSH	MSG_SEGh		; pass pointer to msg segment
	PUSH	MSG_SEGl

	CALL	LOOK_FOR_SUB		; see if file exists
	or	ax,ax			; set flags
	JZ	COPY_DATA		; no problem, copy the data
	xor	ax,ax			; clear any error code Look for sub set
	JMP	short TRY_NEXT_SUB


DONE_RAM:
	mov	 si,LTEMP_SEG		;si points to area to store length
	mov	 ss:[si],di		;store length of temp seg
	RESTORE_CALLER 12
ENDPROC  TRY_RAM

;********************************************************************
; We now must look through the sub headers to look for additional
; codepages.  If a sub-file is specified, call find_file to see if
; it  exists.

PROCEDURE LOOK_FOR_SUB,NEAR

	ARGVAR MSG_SEG,DWORD	     ;PTR TO MESSAGE SEGMENT
	ARGVAR FNAME ,DWORD	     ;PTR TO FILE NAME
	LOCALVAR HANDLE,WORD	     ;handle of the sub file
	LOCALVAR RAM_FILE_FLAG,WORD  ;flag to see if the file was found in ram

IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

	SAVE_CALLER		     ;SAVE CALLERS ENVIRONMENT

;	PREPARE PARAMETERS TO CALL FIND_FILE

	lea	ax,RAM_FILE_FLAG
	push	ax
	lea	ax,handle
	push	ax
	PUSH	FNAMEh
	PUSH	FNAMEl
	PUSH	MSG_SEGh
	PUSH	MSG_SEGl

IFNDEF FamilyAPI
	PUSH	0
ELSE
	xor	ax,ax
	push	ax
ENDIF

	CALL	CC_FIND_FILE	    ; SEE IF THE FILE EXISTS

; RETURN CODE IS IN AX

	mov	dx,iseg 	    ; get iseg (find_file) might change it
	mov	es,dx
	or	ax,ax		    ; check return code
	jnz	check_ram
	PUSH	HANDLE

	CALL	DOSCLOSE
	xor	ax,ax		    ; clear error code
	jmp	short END_LOOK

check_ram:
	MOV	CX,RAM_FILE_FLAG
	OR	CX,CX		    ; IF FILE WAS FOUND IN RAM (BUT MESSAGE
	jz	END_LOOK	    ; 0 WASN'T FOUND) SET FLAG ON
	xor	ax,ax		    ; File was found in ram:Clear error flag



END_LOOK:
       RESTORE_CALLER 8 	     ;RESTORE EVERYTHING EXCEPT AX
ENDPROC  LOOK_FOR_SUB


COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: TRY_DISK						    */
/*									    */
/*  DESCRIPTION NAME:  get CP info from disk				    */
/*									    */
/*  FUNCTION: searches the disk to find the file.  If the file is found     */
/*		 The codepage info is returned to the caller.		    */
/*									    */
/*  NOTE: NONE								    */
/*									    */
/*  ENTRY POINT: TRY_DISK						    */
/*									    */
/*  INPUT:  ARGVAR  @FILENAME,DWORD   (input)  -filename to look for	    */
/*	    ARGVAR  @TEMP_SEG,WORD    (output) -selector of temp seg	    */
/*	    ARGVAR  @LTEMP_SEG,WORD   (output) -len of data in temp segment */
/*									    */
/*									    */
/*  EXIT-NORMAL: AX = 0.						    */
/*									    */
/*  EXIT-ERROR:  AX = file not found					    */
/*		      invalid message file format			    */
/*		      insufficient memory				    */
/*									    */
/*									    */
/*  SIDE EFFECTS: The call to VAL_FORMAT will cause the messsage file to be */
/*		  opened permanently for the current process.		    */
/*									    */
/*  INTERNAL REFERENCES: None.						    */
/*									    */
/*  EXTERNAL REFERENCES: FIND_FILE  searches the disk for the file and	    */
/*					  returns a handle.		    */
/*			 VAl_FORMAT Checks the validity of the msg file     */
/*					  header and stores the header	    */
/*					  information in ram		    */
/*			 DOSALLOCSEG					    */
/*									    */
/*									    */
/*  PSEUDO CODE:							    */
/*									    */
/*									    */
/*    prepare paramters to pass to FIND_FILE				    */
/*    CALL FIND_FILE							    */
/*    if file is found							    */
/*	 CALL VAL_FORMAT						    */
/*	 if file is found and no errors 				    */
/*	    CALL DOSALLOCSEG to create a 4k temp segment		    */
/*	    if memory allocated 					    */
/*		 transfer cp count into temp segment			    */
/*		 while there are code pages left			    */
/*		 copy codepage info into temp segment			    */
/*		 copy language family and language id into temp segment     */
/*		 get handle to file from MSGF_HEADER			    */
/*		 get index of extended headers from MSGF_HEADER 	    */
/*		 get count of extended headers from MSGF_HEADER 	    */
/*	      seek to first extended header				    */
/*	      while there are extended headers to process		    */
/*		 copy number of codepages into temp segment		    */
/*		 while there are codepages to transfer			    */
/*		   copy codepage info into temp segment 		    */
/*		 copy lang family and id into temp segment		    */
/*		 seek to next header					    */
/*		 endwhile						    */
/*	    else return code = insufficient memory			    */
/*	 else								    */
/*	return invalid file format					    */
/*    else return file not found					    */
/****************************************************************************/
ENDCOMMENT $

PROCEDURE TRY_DISK NEAR

	ARGVAR	FILENAME,DWORD	       ;address of filename to look for
	ARGVAR	MSG_SEG,DWORD	       ;sel:offset of message segment
	ARGVAR	TEMP_SEG,WORD	       ;temp seg selector
	ARGVAR	LTEMP_SEG,WORD	       ;address where to store length of seg.
	LOCALVAR BYTES_READ,WORD       ;bytes read by dos read
	LOCALVAR DISK_BUFFER, <SIZE HEADER> ; buffer for the message file header
	LOCALVAR SUB_BUFFER, <SIZE EXTREC>  ; buffer to hold subfile header info
	LOCALVAR FILE_POS,DWORD        ;position in file
	LOCALVAR NEW_FILE_POS,DWORD    ;file position after seeking
	LOCALVAR handle,WORD	       ;return code from dosread
	LOCALVAR EXT_REC_SIZE,WORD     ;size of extended records
	LOCALVAR SUBFILES_LEFT,WORD    ;number of subfiles left to sprocess
	LOCALVAR RAM_FILE_FLAG,WORD    ;was file found in ram
;
;-----------------------------------------------------------------
; SAVE CALLERS ENVIRONMENT
;-----------------------------------------------------------------
;

IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI
	SAVE_CALLER
;
	CLD				;CLEAR DIRECTION FLAG

;******************************************************************
; prepare parameters to call find file
	lea	ax,RAM_FILE_FLAG
	push	ax
	lea	ax,handle
	push	ax
	PUSH	FILENAMEh
	PUSH	FILENAMEl
	xor	ax,ax
	PUSH	ax	  ;msg_segh	   don't look for a message segment
	PUSH	ax	  ;msg_segl	   (we already know our file isn't there)
	PUSH	ax	  ;msgnumber	   look for message 0

	CALL	CC_FIND_FILE		; SEE IF THE FILE EXISTS

	or	ax,ax
	jz	FILE_FOUND2
	MOV	AX,ERROR_FILE_NOT_FOUND
	MOV	DI,0
	JMP	DONE_DISK

					;set up error codes here

FILE_FOUND2:

; Now set up parameters for dos read

	PUSH	HANDLE			   ; handle of message file
	PUSH	SS			   ; far pointer to our disk buffer
	LEA	AX,DISK_BUFFER
	PUSH	AX
IFNDEF FamilyAPI
	PUSH	SIZE HEADER		   ; PUSH BUFFER SIZE
ELSE
	mov	ax,size header
	push	ax
ENDIF
	LEA	AX,BYTES_READ
	PUSH	SS
	PUSH	AX			   ; pointer to bytes read
	CALL	DOSREAD 		   ; read the header

; validate the header information
	OR	ax,ax			   ; check return code
	JNZ	READ_ERROR
	CMP	BYTES_READ,size header	   ;see if we got it all
	JNZ	short read_error
	JMP	short read_ok
READ_ERROR:
	mov	ax,ERROR_MR_UN_PERFORM
	xor	di,di
	JMP	DONE_DISK

READ_OK:
	LEA	si , disk_buffer
	mov	ax , ss:[si].VERSION	   ; get version number
	CMP	AX,2			   ; is this a version 2 header
	JE	VER_2			   ; yes, continue
	xor	di,di			   ;no return data
	MOV	AX,ERROR_MR_INV_MSGF_FORMAT
	JMP	DONE_DISK
VER_2:
; see if the signature is correct
	mov	ax,ss
	mov	es,ax
	lea	di,SS:[si].SEG_signature  ;es:di points to the files signature

	mov	ax,iseg
	mov	ds,ax
	lea	si,SIGNATURE_MSGF	  ;ds:si points to correct signature

	mov	cx,size SIGNATURE_H
	repz	CMPSB
	jz	valid_signature
	xor	di,di			  ;no return data
	MOV	AX,ERROR_MR_INV_MSGF_FORMAT
	JMP	DONE_DISK
valid_signature:

;set es:di to point to temp segment
	mov	 ax,temp_seg		 ;ax now has selector of temp seg
	mov	 es,ax			 ;es --> temp_seg
	xor	 di,di			 ;es:di points to start of temp seg
;set ds to ss
	mov	 ax,ss
	mov	 ds,ax
	mov	 ext_rec_size,size extrec ;we must assume this first record is
					  ;of normal length

	lea	 si, disk_buffer
	mov	 FILE_POSh,0		 ;set up file position
	mov	 ax,ss:[si].CP_DATA	 ;get offset in file of codepage data
	mov	 FILE_POSl,ax		 ;move our pointer

	lea	 si,sub_buffer		 ;ds:si --> sub  buffer (on stack)

	CALL	 SEEK_READ		 ;read header

	or	 ax,ax
	JNZ	 READ_ERROR1
	CMP	 BYTES_READ,size extrec
	JNZ	 READ_ERROR1
	JMP	 short COPY_DATA1
READ_ERROR1:
	mov	 ax,ERROR_MR_UN_PERFORM
	JMP	 DONE_DISK

COPY_DATA1:

	CALL	 COPY_CPDATA		 ;copy info to temp seg

;seek to file header definition record
	lea	 si,disk_buffer
	mov	 dx,word ptr ss:[si].EXT_HEADER + 2  ; get offset from the
	mov	 FILE_POSh,dx				  ; ext_header field in
	mov	 ax,word ptr ss:[si].EXT_HEADER   ; the root_header
	mov	 FILE_POSl,ax
	or	 ax,dx					   ; was this pointer null
	jnz	 short read_ext_hdr
	jmp	 DONE_DISK			     ; yes: leave  ax = 0
read_ext_hdr:
	lea	 si,sub_buffer				   ; switch to sub-file buffer
;read the number of extended header definitions and the size of them
	mov	 ext_rec_size,size ext_hdr	     ; set number of bytes to read
	call	 seek_read			     ; read them
	or	 ax,ax				     ; check error
	jnz	 read_error2			     ; error --> leave
	cmp	 bytes_read,size ext_hdr	     ; read everything???
	JNZ	 read_error2			     ; no    --> leave
	mov	 ax,ss:[si].EXT_HDR_LNG       ;the length of each extended header
	mov	 ext_rec_size,ax
	mov	 ax,ss:[si].EXT_NUM_DEF_REC   ;the number of headers
	mov	 subfiles_left,ax
	or	 ax,ax			      ; is this just a root file?
	jz	 DONE_DISK		      ;
	add	 FILE_POSl,size ext_hdr ;move file positoin pointer past ext_hdr
	jnc	 short READ_EXT_HEADER
	inc	 FILE_POSh


READ_EXT_HEADER:
	call	 SEEK_READ		    ;read the extended header
	or	 ax,ax				 ; error??
	JNZ	 READ_ERROR2		    ; yes, get outta dodge
	mov	 ax, ext_rec_size	    ; complete read??
	CMP	 BYTES_READ,ax			 ; "             "
	JNZ	 READ_ERROR2		    ; read error --> leave
	JMP	 short COPY_DATA2	    ; good data , copy it
READ_ERROR2:
	mov	 ax,ERROR_MR_UN_PERFORM
	JMP	 DONE_DISK

COPY_DATA2:
; call look for sub to see if this file is either bound or on disk
	push	 ss			 ;pass far pointer to filename
	lea	  ax,[si].REC_FILENAME	  ;   "                     "
	push	 ax			 ;   "                     "
	push	 msg_segh		 ;pass seg:off of message segment
	push	 msg_segl

	CALL	 LOOK_FOR_SUB		 ;see if the sub exists

	or	 ax,ax			 ;check rc
	jne	 LOOK4_NEXT_SUB 	 ;file not found so skip it
	CALL	 COPY_CPDATA		 ;other wise copy cp data for it
					 ;from the root files info
LOOK4_NEXT_SUB:
	mov	 ax,subfiles_left	 ;get the length of this field
	dec	 ax
	mov	 subfiles_left,ax
	je	 DONE_DISK		 ;we're through so quit
	mov	ax,ext_rec_size
	add	 file_posl,ax		 ;move file pointer to next record
	JNC	 NO_CARRY		 ; "                            "
	inc	 file_posh		 ; "                            "
NO_CARRY:
	jmp	 short READ_EXT_HEADER	 ;process another sub


; give up handle to root file
       push	handle
       CALL	DOSCLOSE
DONE_DISK:
	mov	 si,LTEMP_SEG		;si points to area to store length
	mov	 ss:[si],di		;store length of temp seg

	RESTORE_CALLER 12
ENDPROC TRY_DISK


SEEK_READ	PROC	NEAR

; SEEK_READ seeks to a given offset in a file and then reads a sub_file
; header worth of information.
; INPUT:
;   FILE_POS,  DWORD (GLOBAL) : offset from start of file to seek to
;   SS:SI  -->sub file buffer
;   cx	   -->number of bytes to read

	push	handle
	push	FILE_POSh
	push	FILE_POSl

IFNDEF FamilyAPI
	push	0
ELSE
	xor	ax,ax
	push	ax
ENDIF

	push	ss
	lea	ax,new_file_pos
	push	ax
	call	DOSCHGFILEPTR
	or	ax,ax
	jnz	END_SEEK_READ

	push	handle
	push	ss
	lea	ax,sub_buffer
	push	ax
	push	ext_rec_size
	push	ss
	lea	ax,bytes_read
	push	ax
	call	DOSREAD


END_SEEK_READ:
	ret
SEEK_READ  ENDP


COPY_CPDATA	PROC	NEAR

; This subroutine copys data from the subfile buffer on the stack to the
; temp seg.
; INPUT :  es:di  -> first availiable position in temp seg
;	   ds:si  -> points to extrec structure (on the stack)

	mov	 ax,si			;store pointer to start of buffer
	mov	 cx,[si].REC_CNT_CP	;load cx with the number of code pages
	inc	 cx			;add one to cx so that the code page
					;count will also be transferred
	lea	 si,[si].REC_CNT_CP	;si --> code page count
	rep	 movsw			;copy count and all code page info
	mov	 si,ax			;restore si to start of buffer
	lea	 si,[si].REC_LANG_ID	;move si to point to lang fam/id pair
	mov	 cx,2			;two words worth
	rep	  movsw 		 ;movem over
	mov	 si,ax			;restore si
	ret				;go home


COPY_CPDATA  ENDP

COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: CC_find_file
/*
/*  DESCRIPTION NAME: Call :  Call_find_file
/*
/*  FUNCTION: This function calls the function call find file.
/*
/*  WHY?: I need to call two functions in MSGFIN.ASM (find_file and
	  filname_strip.  The problem is that these two functions use global
	  variables that are defined on

/*  ENTRY POINT:
/*
/*  INPUT:  ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*
/*
/*  EXIT-NORMAL:
/*
/*  EXIT-ERROR:
/*
/*
/*  SIDE EFFECTS:
/*
/*  INTERNAL REFERENCES: None.
/*
/*  EXTERNAL REFERENCES:
/*
/**************************************************************************
ENDCOMMENT $

PROCEDURE  cc_FIND_FILE  near	    ;CALL_CALL_FIND_FILE

      ARGVAR  MSG_NUM,WORD
      ARGVAR  MSG_SEG,DWORD
      ARGVAR  FILENAME,DWORD
      ARGVAR  HANDLE,WORD	      ; near pointer to handle
      ARGVAR  RAM_FILE_FLAG,WORD      ; near pointer to flag
      localvar MSG_LEN,word

IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

      SAVE_CALLER
      CLD

      XOR	ax,ax
      push	ax	   ;push null for IVTABLE seg
      push	ax	   ;push null for IVTABLE off
      push	ax	   ;push zero for IVCOUNT
      push	ax		 ;push null for area to store message- seg
      push	ax		 ;push null for area to store message- off
      push	ax		 ;push zero for length of buffer
      push	msg_num    ;push number of the message wanted
      push	filenameh  ;push seg. of the filename
      push	filenamel  ;push off. of the filename
      push	ss		 ;length of message (returned)	seg
      lea	ax,msg_len
      push	ax	   ;length of message (returned)  off
      push	msg_segh   ;segment where messages are to be found
      push	msg_segl   ;segment where messages are to be found

      CALL	far ptr c_FIND_FILE

      MOV	SI,HANDLE
      mov	SS:[SI],cx
      MOV	SI,RAM_FILE_FLAG
      mov	SS:[SI],bx

      restore_caller 14
ENDPROC  CC_FIND_FILE


COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: CC_
/*
/*  DESCRIPTION NAME:
/*
/*
/*  FUNCTION:
/*
/*
/*  NOTE:
/*
/*  ENTRY POINT:
/*
/*  INPUT:  ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*
/*
/*  EXIT-NORMAL:
/*
/*  EXIT-ERROR:
/*
/*
/*  SIDE EFFECTS:
/*
/*  INTERNAL REFERENCES: None.
/*
/*  EXTERNAL REFERENCES:
/*
/**************************************************************************
ENDCOMMENT $

;  procedure cc_filename_strip
;  this procedure calls c_filename strip
;  input  es:di points to start of path/filename string
;	  bx	length of string
;	   AX	 0  filename not dbcs
;	   AX	 1  filename is dbcs
;  output es:di points to filename only
;

PROCEDURE  cc_FILENAME_STRIP  near	 ;CALL_CALL_FIND_FILE

IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

      CLD

      PUSH    DS
      PUSH    BX
      PUSH    CX
      PUSH    DX
      PUSH    SI
;     push	ax	   ;push null for IVTABLE seg
;     push	ax	   ;push null for IVTABLE off
;     push	ax	   ;push zero for IVCOUNT
;     push	ax		 ;push null for area to store message- seg
;     push	ax		 ;push null for area to store message- off
;     push	ax		 ;push zero for length of buffer
;     push	ax		 ;push number of the message wanted
;     push	ax	   ;push seg. of the filename
;     push	ax	   ;push off. of the filename
;     push	ax	   ;length of message (returned)  seg
;     push	ax	   ;length of message (returned)  off
;     push	ax	   ;msg_seg hi
;     push	ax	   ;msg_seg lo

; since I don't care about any of those variables , why bother actually pushing them

      sub	sp,26
      call	far ptr c_filename_strip

       POP     SI
       POP     DX
       POP     CX
       POP     BX
       POP     DS
IFDEF FamilyAPI 	; exitproc doesn't restore bp in real mode
	mov	sp,bp
	pop	bp
ENDIF
      exitproc
ENDPROC  CC_FILENAME_STRIP



COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: CC_
/*
/*  DESCRIPTION NAME:
/*
/*
/*  FUNCTION:
/*
/*
/*  NOTE:
/*
/*  ENTRY POINT:
/*
/*  INPUT:  ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*
/*
/*  EXIT-NORMAL:
/*
/*  EXIT-ERROR:
/*
/*
/*  SIDE EFFECTS:
/*
/*  INTERNAL REFERENCES: None.
/*
/*  EXTERNAL REFERENCES:
/*
/**************************************************************************
ENDCOMMENT $

PROCEDURE  c_filename_strip FAR 	  ;CALL_filename_strip

	ARGVAR	MSGSEGMENT,DWORD	;ADDRESS OF MESSAGE SEGMENT
	ARGVAR	MSGLENGTH,DWORD 	;ADDRESS OF LENGTH OF MESSAGE RETURNED
	ARGVAR	FILENAME,DWORD		;ADDRESS OF MESSAGE FILE NAME
	ARGVAR	MSGNUMBER,WORD		;MESSAGE NUMBER REQUESTED
	ARGVAR	DATALENGTH,WORD 	;MESSAGE BUFFER LENGTH
	ARGVAR	DATAAREA,DWORD		;MESSAGE BUFFER ADDRESS
	ARGVAR	IVCOUNT,WORD		;VARIABLE TEXT COUNT
	ARGVAR	IVTABLE,DWORD		;VARIABLE TEXT TABLE ADDRESS
include  vars.inc

IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

;***********************************************************************
;   Get the dostruegetmessage semaphore

IFNDEF FamilyAPI
	PUSH	iseg			; segment of GetFSRamSem
	PUSH	offset GetFSRamSem	;pass FSRAM semaphore data

	mov	ax , 0FFFFh		;
	push	ax			; Indefinite wait (-1 high word)
	push	ax			; Indefinite wait (-1 low word )
	call	DOSFSRAMSEMREQUEST	; OBTAIN FSRAM SEMAPHORE
					;
ENDIF

;;**********************************************************************
;???  need to clear sub_file flag for bens changes
	mov  IS_DBCS,al

	call FILENAME_STRIP

;**************************************************************
;	CALL DOSFSRAMSEMCLEAR - RELEASE RAM SEMAPHORE;
;**************************************************************

IFNDEF FamilyAPI
	PUSH	iseg			; segment of GetFSRamSem
	PUSH	offset GetFSRamSem	;pass FSRAM semaphore data
	CALL	DOSFSRAMSEMCLEAR	;clear semaphore
ENDIF

IFDEF FamilyAPI 	; exitproc doesn't restore bp in real mode
	mov	sp,bp
	pop	bp
ENDIF

	EXITPROC     ;DONT USE RESTORE_CALLER CAUSE IT WILL NUKE ES:DI
endproc c_FILENAME_STRIP

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


COMMENT $
/****************************************************************************/
/*  SUBROUTINE NAME: CC_
/*
/*  DESCRIPTION NAME:
/*
/*
/*  FUNCTION:
/*
/*
/*  NOTE:
/*
/*  ENTRY POINT:
/*
/*  INPUT:  ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*	    ARGVAR
/*
/*
/*  EXIT-NORMAL:
/*
/*  EXIT-ERROR:
/*
/*
/*  SIDE EFFECTS:
/*
/*  INTERNAL REFERENCES: None.
/*
/*  EXTERNAL REFERENCES:
/*
/**************************************************************************
ENDCOMMENT $

PROCEDURE  c_FIND_FILE,FAR		  ;CALL_FIND_FILE

	ARGVAR	MSGSEGMENT,DWORD	;ADDRESS OF MESSAGE SEGMENT
	ARGVAR	MSGLENGTH,DWORD 	;ADDRESS OF LENGTH OF MESSAGE RETURNED
	ARGVAR	FILENAME,DWORD		;ADDRESS OF MESSAGE FILE NAME
	ARGVAR	MSGNUMBER,WORD		;MESSAGE NUMBER REQUESTED
	ARGVAR	DATALENGTH,WORD 	;MESSAGE BUFFER LENGTH
	ARGVAR	DATAAREA,DWORD		;MESSAGE BUFFER ADDRESS
	ARGVAR	IVCOUNT,WORD		;VARIABLE TEXT COUNT
	ARGVAR	IVTABLE,DWORD		;VARIABLE TEXT TABLE ADDRESS

include  vars.inc

IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

;***********************************************************************
;   Get the dostruegetmessage semaphore

IFNDEF FamilyAPI
	push	iseg			; selector of GetFSRamSem
	push	offset GetFSRamSem	; offset of GetFSRamSem
	mov	ax , 0FFFFh		;
	push	ax			; Indefinite wait (-1 high word)
	push	ax			; Indefinite wait (-1 low word )
	call	DOSFSRAMSEMREQUEST     ; OBTAIN FSRAM SEMAPHORE
ENDIF

;;**********************************************************************
	mov  subfile_flag,0
	mov  sub_handle,0
	mov  handle,0

	push	es
	mov	ax,iseg 	     ; CLEAR RAM_FILE_FOUND FLAG
	mov	es,ax
	MOV	es:RAM_FILE_FOUND,0
	pop	es

	call FIND_FILE

	push es 		    ; see if the file was found in ram
	mov  ax,iseg		    ; save this flag in bx
	mov  es,ax
	xor  bx,bx
	mov  bl,es:RAM_FILE_FOUND
	pop  es

	mov  dx,sys_error	    ; save sys_error in dx
	or   dx,dx
	jne  not_found		    ; save handle in cx
	mov  cx, handle
not_found:

RELEASE_SEM:
;**************************************************************
;	CALL DOSFSRAMSEMCLEAR - RELEASE RAM SEMAPHORE;
;**************************************************************

IFNDEF FamilyAPI
	PUSH	iseg			; segment of GetFSRamSem
	PUSH	offset GetFSRamSem	;pass FSRAM semaphore data
	CALL	DOSFSRAMSEMCLEAR	;clear semaphore
ENDIF

	mov	ax,dx			;move return code to ax
IFDEF FamilyAPI 	; exitproc doesn't restore bp in real mode
	mov	sp,bp
	pop	bp
ENDIF
	EXITPROC     ;DONT USE RESTORE_CALLER CAUSE IT WILL NUKE CX,BX
endproc c_find_file

code   ends
      END
