;	SCCSID = @(#)ramfind.asm	6.2 91/03/26
;	SCCSID = @(#)ramfind.asm	6.2 91/03/26
PAGE	60,132
;********************************************************************
;   Modification history
;
;4-24	delete ramfind from end statement
;5-20	rem out skipping component id in tblsrch routine
;5-20	save SI in msgcomp routine
;6-6	make fixes to support FamilyAPI (3X BOX)
;6-23	un-comment skipping component ID field in tblsrch routine (ptm 871)
;9-2	add code to save component ID. Change input parm passing to stack frame.
;9-3	fix Family API version, to use RealEnter macro to setup stack frame
;9-5	fix FNSRCH to save DI (pointer to input asciiz filename) when searching
;	to allow multiple file names
;1-22-87 fix FNSRCH to AND ah,al to test for end of filename. (ptm1253)
;2-04-87 fix FNSRCH to compare filenames correctly (cmp chars, then check
;	 for end of file.
;
;11-15-89 SDD added dcr361 support
;04-03-90 SDD @1 if the machine has a codepage of zero then they do not have
;	      any codepages prepared so give them anything we find.  This
;	      eliminates problems where a message file has a code page of
;	      437 but we reject it since the machine is looking for CP 0.
;********************************************************************
IFNDEF	FamilyAPI
	.286p
ENDIF	;FamilyAPI

.XLIST
	INCLUDE basemaca.inc		;DOS MACROS
	include dc1segs.inc					; DCR 704
.LIST
	INCLUDE msgfequ.inc		;msg equates
	INCLUDE msgfmac.inc		;msg macros

;structure of addition 361 info that is bound
SUBFILE_HDR STRUC				    ;MSG FILE EXTENDED HEADER
	HDR_pNEXT	DW	?
	HDR_CPTYPE	DB	?		;SBCS or DSCS messages
	HDR_CNTY_ID	DW	?		;COUNTRY ID
	HDR_LANG_ID	DW	?		;LANGUAGE FAMILY ID
	HDR_LANG_VERID	DW	?		;LANGUAGE VERSION ID
;;;???? count should become a byte
	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


IFNDEF	FamilyAPI
iseg	SEGMENT
ELSE
iseg	SEGMENT 		para public 'data'
ENDIF	;FamilyAPI
extrn	ram_file_found : byte
iseg	ENDS

CODE	SEGMENT 						; DCR 704
	ASSUME	CS:CODE
	PROCEDURE	RAMFIND,NEAR
; -------------------------------------------------------
;	EQUATES
; -------------------------------------------------------
SIGOFF	EQU	0
VEROFF	EQU	10
RESRVD	EQU	12
MSGDATA EQU	14
NFILES	EQU	0
COMPLEN EQU	3

; -------------------------------------------------------
;	FIND MESSAGE IN RAM SEGMENT
;
; INPUT:	compid		pointer to component id field (dword)
;		filename	pointer to filename (dword)
;		msgnumber	message id requested (word)
;		msgsegment	message segment (MSGSEG) (word)
;		cp_ptr		pointer to current code page
;
;
;
;
;		OUTPUT - CFL = 1, MESSAGE NOT IN RAM
;			 CFL = 0, DS:SI --> MESSAGE
;				  CX = MESSAGE LENGTH
; -------------------------------------------------------
;***********************************************************************
; create mask for parameters passed on the stack
;***********************************************************************
	ARGVAR	cp_ptr,DWORD		;pointer to code page info   DCR361
	ARGVAR	msgnumber,WORD		;message number requested
	ARGVAR	msgsegment,DWORD	;segment:offset pointer to message segment
	ARGVAR	filename,DWORD		;segment:offset pointer to filename
	ARGVAR	compid,DWORD		;segment:offset pointer to component id
;***********************************************************************
;  Area for local vars
	LOCALVAR START_HEADER,WORD	;POINTER TO START OF EXTENDED HEADER
	LOCALVAR IS_ROOT,WORD		;is current file a root      DCR361
	LOCALVAR FNSRCH_BX,WORD 	;save return code of fnsrch  DCR361
;***********************************************************************
IFNDEF	FamilyAPI
	ENTERPROC			;SETUP BP
ELSE
	RealEnter			;setup bp
ENDIF	;FamilyAPI

	PUSH	AX
	PUSH	BX
	PUSH	DX
	PUSH	ES
	PUSH	DI
;
;	setup registers
;
	lds	si,msgsegment		;get message segment pointer
	mov	ax,msgnumber		;get message id
	les	di,filename		;get filename pointer

	CMP	WORD PTR [SI+MSGDATA],0 ; TEST FOR MESSAGE SEGMENT OFFSET
	JNE	MSG_SEG 		; MESSAGE SEGMENT EXISTS
	STC
	JMP	DONE			; EXIT IF NO MESSAGE SEGMENT
MSG_SEG:
	MOV	BL, BYTE PTR [SI+VEROFF]; GET VERSION NUMBER
	CMP	BL,1			; TEST FOR VERSION NUMBER
	JNZ	TRYVER2 		; LOOK FOR A DCR361 HEADER

	MOV	SI,WORD PTR [SI+MSGDATA] ; GET MESSAGE DATA OFFSET
	CALL	FNSRCH			; SEARCH FOR FILE NAME
	JNC	short TRYVER1
	JMP	DONE			; JUMP IF NOT FOUND
TRYVER1:
	MOV	DX,[SI] 		; GET COUNT
	INC	SI			; BUMP PAST
	INC	SI			; COUNT
	SHL	DX,1			; CONVERT TO BYTE COUNT
	ADD	SI,DX			; BUMP PAST ALL MSG FILE POINTERS
	SHL	BX,1			; CONVERT INDEX TO BYTE COUNT
	ADD	SI,BX			; POINT TO MESSAGE TABLE POINTER
	CALL	TBLSRCH 		; SEARCH MESSAGE TABLE
	JMP	DONE			; exit ramfind



TRYVER2:
	JGE	VERSION2		; YES
	STC				; NO-- SET ERROR
	JMP	DONE			;      AND LEAVE
VERSION2:
	LDS	SI,msgsegment
	MOV	SI,WORD PTR [SI+MSGDATA] ; GET MESSAGE DATA OFFSET
	CALL	FNSRCH			; LOOK FOR ROOTFILENAME
	MOV	IS_ROOT,1		; we are currently searching root
	MOV	FNSRCH_BX,bx		; save return code
	JC	DONE			; ROOT FILE NOT FOUND
	INC	CX			; skip past length of languate data
	INC	CX			; area
	MOV	SI,CX			; SI POINTS TO THE ZERO BYTE OF FILENAME
;ADD	SI,3			; MOVE CX TO POINT TO OFFSET_PTR IN
					; THE FILE HEADER EXTENSION RECORD
;???	MOV	SI, WORD PTR [SI]	; INDIRECT SI (IT NOW POINTS TO ROOTS
					; EXTENDED HEADER INFORMATION )


REPEAT:
	LES	di,CP_PTR		; es:di points to code page info
	MOV	AX,es:WORD PTR [di]	; AX contains current process CP
	MOV	START_HEADER,SI 	; SAVE THE START OF THIS HEADER

	CMP	ax,0			; If the systems codepage = 0 then
	JZ	CP_FND			; they don't have codepages set up
					; so give them anything

	MOV	BX,WORD PTR [SI].HDR_CNT_CP; GET CODE PAGE COUNT
	SHL	bx,1
	JZ	CP_FND			; No CP data, use this file
COMP_CP:
	JZ	CP_NOT_FND		; CODE PAGE NOT FOUND
	CMP	AX,WORD PTR [SI + BX].HDR_CP_ID - 2 ; IS OUR CP THIS ITEM
	JZ	CP_FND			; YES IT MATCHED
	DEC	BX			; NO DECREMENT COUNT
	DEC	BX
	JMP	COMP_CP 		; THIS MUST IMMEDIATLY FOLLOW THE DECREMENT

CP_FND:
;  some added efficiency can be gained here.  If the root file has the correct
;  code page then we don't really need to look up the root file again.  If
;  you store the bx return code of fnsrch and can recognize that the current
;  file is the root then skip calling FNSRCH again

	 CMP	 IS_ROOT,0		 ; IF BX <> 0 THEN IT CONTAINS A FILENAME INDEX
	 JE	 LOOK_IT_UP		 ;LOOK_UP_A_NEW_FILENAME

;  At this point the filename that was passed in was a root file that was of
;  the correct code page.  Now we could process it normally , but since we
;  already have looked it up, we can bypass looking it up again.
	 LDS	 SI,msgsegment
	 MOV	 SI,WORD PTR [SI+MSGDATA]  ;GET MESSAGE DATA OFFSET
	 CLC				 ;FAKE OUT OLD FNSRCH RETURN CODE
	 mov	 bx,FNSRCH_BX		 ;restore bx return code of fnsrch
	 MOV	 AX,MSGNUMBER		 ;load ax with msg number
	 JMP	 short FILE_FND1	 ;

LOOK_IT_UP:
;  Prepare parameters to pass to fnsrch es:di points to filename
;					ds:si points to # of bound files

	LEA	AX,[si].HDR_FILENAME
	MOV	DI,ax			;make es:di point to sub-filename
	MOV	AX,DS
	MOV	ES,AX
	MOV	AX,MSGNUMBER		;load ax with msg number
	LDS	SI, msgsegment
	MOV	SI,WORD PTR [SI+MSGDATA] ; GET MESSAGE DATA OFFSET
	CALL	FNSRCH
	JC	FILE_NOT_FND
FILE_FND1:
	MOV	DX,[SI] 		; GET COUNT
	INC	SI			; BUMP PAST
	INC	SI			;  COUNT
	SHL	DX,1			; CONVERT TO BYTE COUNT
	ADD	SI,DX			; BUMP PAST ALL MSG FILE POINTERS
	SHL	BX,1			; CONVERT INDEX TO BYTE COUNT
	ADD	SI,BX			; POINT TO MESSAGE TABLE POINTER
	CALL	TBLSRCH 		; SEARCH MESSAGE TABLE
	JC	short MESSAGE_NOT_FND	; the correct message # wasn't in this
					; file.  look through the rest of the
					; subfiles.
	JMP	DONE			; exit ramfind


MESSAGE_NOT_FND:
CP_NOT_FND:
FILE_NOT_FND:

;  Now the current file either was of the wrong cp or it was not bound
;  continue searching the rest of the subfile tree.

	MOV	IS_ROOT,0		; CLEAR ROOT FILE INDICATOR
	MOV	SI,START_HEADER 	;SI POINTS TO A MESSAGE FILE DEFINITION.PNEXT
	MOV	si,[si] 		;move to next file definition
	or	si,si
	JNZ	REPEAT			;
	STC


DONE:

;
	POP	DI
	POP	ES
	POP	DX
	POP	BX
	POP	AX

IFNDEF	FamilyAPI
	LEAVEPROC
ELSE
	mov	sp,bp
	pop	bp
ENDIF	;FamilyAPI

	RET	18		;pop 18 bytes off on return
RAMFIND ENDP
;
	PAGE
; -------------------------------------------------------
;	FILE NAME SEARCH
;		INPUT:	DS: MESSAGE DATA SEGMENT
;			ES:DI --> ASCIIZ FILE NAME
;		OUTPUT: CFL = 1, FILE NOT FOUND
;			CFL = 0, FILE FOUND
;			      BX = INDEX
;			      CX = POINTER TO NULL BYTE OF FILENAME
; -------------------------------------------------------
PUBLIC	FNSRCH
FNSRCH	PROC	NEAR
	PUSH	AX
	PUSH	DX
	PUSH	DI
	PUSH	SI
;
; GET NUMBER OF FILE NAMES IN SEGMENT
;
	MOV	CX,WORD PTR [SI]	; GET NUMBER OF FILES
;
;  POINT TO FIRST FILE NAME
;
	INC	SI			; BUMP PAST
	INC	SI			;  NUMBER OF FILES
	XOR	BX,BX			; CLEAR BX FOR USE AS INDEX
FSLOOP:
	OR	CX,CX			; TEST FOR NO FILES
	JZ	FN_NOTFND		; JUMP IF NONE LEFT
	PUSH	SI			; SAVE FILE NAME POINTER
	push	di			; save input filename pointer
	MOV	SI,WORD PTR [SI]	; GET FILE NAME POINTER
FCLOOP:
	LODSB				; FETCH SEGMENT BYTE
	MOV	AH,BYTE PTR ES:[DI]	; FETCH CALLERS BYTE
	INC	DI			; BUMP POINTER

	CMP	AH,AL			; ARE THEY THE SAME?
	jnz	fn_nomatch		; no, so retry with next filename

	or	AH,AL			; TEST FOR END
	JZ	FILE_FND		; JUMP IF TRUE (MATCH)
	jmp	FCLOOP			; get next character to compare
;
; FILE NAME DID NOT MATCH, DO NEXT
;
FN_NOMATCH:
	pop	di			; restore input filename pointer
	POP	SI			; RESTORE FILE NAME POINTER
	INC	SI			; BUMP TO
	INC	SI			;  NEXT POINTER
	DEC	CX			; SUBTRACT 1 FROM COUNT
	INC	BX			; BUMP INDEX
	JMP	FSLOOP			; DO NEXT PASS
;
; FILE NAME MATCHED,
;
FILE_FND:
	pop	di			; restore input filename pointer
	MOV	CX,SI			; DCR361 CX POINTS TO END OF FILENAME

	push	es			;DCR361 Tell everybody we found it
	mov	ax,iseg 		;DCR361 Tell everybody we found it
	mov	es,ax			;DCR361 Tell everybody we found it
	mov	es:byte ptr ram_file_found,1	 ;DCR361 Tell everybody we found it ;error
	pop	es			;DCR361 Tell everybody we found it

	POP	SI			; RESTORE FILE NAME POINTER
	CLC				; INDICATE FILE NAME FOUND
	JMP	FNS_RET 		; EXIT THIS ROUTINE
FN_NOTFND:
	STC
FNS_RET:
	POP	SI
	POP	DI
	POP	    DX
	POP	AX
	RET
FNSRCH	ENDP
	PAGE
; -------------------------------------------------------
;	SEARCH MESSAGE TABLE FOR MESSAGE
;		INPUT:	DS:SI --> MESSAGE TABLE POINTER
;			AX = MESSAGE ID
;		OUTPUT: CFL = 1, MESSAGE NOT FOUND
;			CFL = 0, MESSAGE FOUND
;				 DS:SI --> MESSAGE
;				 CX = MESSAGE LENGTH
; -------------------------------------------------------
TBLSRCH PROC	NEAR
	MOV	SI,WORD PTR [SI]	; GET POINTER TO MESSAGE TABLE
;
;  **	save component ID  **
;
	push	ax			;save msg id
	les	di,compid		;get pointer to component id
	mov	cx,component_length	;get length of component id field
save_compid:
	lodsb				;get char
	stosb				;store char
	loop	save_compid
	pop	ax			;restore msg id
;
;
	MOV	CX,WORD PTR [SI]	; GET NUMBER OF MESSAGES
	INC	SI			; BUMP PAST
	INC	SI			;  NUMBER OF MESSAGES FIELD
TSLOOP:
	OR	CX,CX			; CHECK FOR NO MORE MESSAGES
	JZ	MSG_NTFND
	CALL	MSGCOMP 		; CHECK MESSAGE ID IN MESSAGE STRUC
	JC	NEXT_MSG		; DO NEXT MESSAGE IF NOT FOUND
	JMP	TS_RET			; ELSE RETURN TO CALLER
NEXT_MSG:
	INC	SI			; BUMP PAST
	INC	SI			;  CURRENT MESSAGE POINTER
	DEC	CX			; SUBTRACT 1 FROM COUNT
	JMP	TSLOOP
MSG_NTFND:
	STC
TS_RET:
	RET
TBLSRCH ENDP
;
; -------------------------------------------------------
;	MESSAGE ID COMPARE
;		INPUT:	AX = INPUT MESSAGE ID
;			DS:SI --> MESSAGE POINTER
;
;		OUTPUT: CFL = 1, MESSAGE NOT FOUND
;			CFL = 0, MESSAGE FOUND
;				 DS:SI --> MESSAGE
;				 CX = MESSAGE LENGTH
; -------------------------------------------------------
MSGCOMP PROC	    NEAR
	PUSH	AX
	push	bx
	mov	bx,si			; save msg offset
	MOV	SI,WORD PTR [SI]	; GET MESSAGE POINTER
	CMP	WORD PTR [SI],AX	; DO MESSAGE ID' MATCH
	JNZ	MC_NOMATCH		; JUMP IF NOT
	INC	SI			; BUMP PAST
	INC	SI			;  MESSAGE NUMBER
	LODSW				; FETCH THE LENGTH OF THE MESSAGE
	MOV	CX,AX			; MOVE IT TO CX
	DEC	CX			; SUBTRACT MESSAGE CLASS BYTE FROM LENGTH
	INC	SI			; BUMP PAST MESSAGE CLASS
	CLC				; INDICATE MESSAGE FOUND
	JMP	   MC_RET	     ; EXIT THIS ROUTINE
MC_NOMATCH:
	mov	si,bx			; restore msg offset
	STC				; INDICATE MESSAGE NOT FOUND
MC_RET:
	pop	bx
	POP	AX
	RET
MSGCOMP ENDP
CODE	   ENDS
;
	END
