; ; FCB management routines for MSDOS ; INCLUDE DOSSEG.ASM IFNDEF KANJI KANJI EQU 0 ;FALSE ENDIF CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME SS:DOSGROUP,CS:DOSGROUP .xlist .xcref INCLUDE DOSSYM.ASM INCLUDE DEVSYM.ASM .cref .list i_need Name1,BYTE i_need NumIO,BYTE i_need DevFCB,BYTE i_need Creating,BYTE i_need ExtFCB,BYTE i_need Attrib,BYTE i_need SpaceFlag,BYTE i_need Current_Country,WORD procedure MakeFcb,NEAR DRVBIT EQU 2 NAMBIT EQU 4 EXTBIT EQU 8 MOV BYTE PTR [SpaceFlag],0 XOR DL,DL ; Flag--not ambiguous file name TEST AL,DRVBIT ; Use current drive field if default? JNZ DEFDRV MOV BYTE PTR ES:[DI],0 ; No - use default drive DEFDRV: INC DI MOV CX,8 TEST AL,NAMBIT ; Use current name fields as defualt? XCHG AX,BX ; Save bits in BX MOV AL," " JZ FILLB ; If not, go fill with blanks ADD DI,CX XOR CX,CX ; Don't fill any FILLB: REP STOSB MOV CL,3 TEST BL,EXTBIT ; Use current extension as default JZ FILLB2 ADD DI,CX XOR CX,CX FILLB2: REP STOSB XCHG AX,CX ; Put zero in AX STOSW STOSW ; Initialize two words after to zero SUB DI,16 ; Point back at start TEST BL,1 ; Scan off separators if not zero JZ SKPSPC CALL SCANB ; Peel off blanks and tabs CALL DELIM ; Is it a one-time-only delimiter? JNZ NOSCAN INC SI ; Skip over the delimiter SKPSPC: CALL SCANB ; Always kill preceding blanks and tabs NOSCAN: CALL GETLET JBE NODRV ; Quit if termination character CMP BYTE PTR[SI],":" ; Check for potential drive specifier JNZ NODRV INC SI ; Skip over colon SUB AL,"@" ; Convert drive letter to binary drive number JBE BADDRV ; Valid drive numbers are <= NUMIO CMP AL,BYTE PTR [NUMIO] JBE HAVDRV BADDRV: MOV DL,-1 HAVDRV: STOSB ; Put drive specifier in first byte INC SI DEC DI ; Counteract next two instructions NODRV: DEC SI ; Back up INC DI ; Skip drive byte NORMSCAN: MOV CX,8 CALL GETWORD ; Get 8-letter file name CMP BYTE PTR [SI],"." JNZ NODOT INC SI ; Skip over dot if present MOV CX,3 ; Get 3-letter extension CALL MUSTGETWORD NODOT: MOV AL,DL return NONAM: ADD DI,CX DEC SI return GETWORD: CALL GETLET JBE NONAM ; Exit if invalid character DEC SI ; ; UGH!!! Horrible bug here that should be fixed at some point: ; If the name we are scanning is longer than CX, we keep on reading! ; MUSTGETWORD: CALL GETLET ; ; If spaceFlag is set then we allow spaces in a pathname ; JB FILLNAM JNZ MustCheckCX TEST BYTE PTR [SpaceFlag],0FFh JZ FILLNAM CMP AL," " JNZ FILLNAM MustCheckCX: JCXZ MUSTGETWORD DEC CX CMP AL,"*" ; Check for ambiguous file specifier JNZ NOSTAR MOV AL,"?" REP STOSB NOSTAR: STOSB IF KANJI CALL TESTKANJ JZ NOTDUAL3 JCXZ BNDERR ; Attempt to straddle boundry MOVSB ; Transfer second byte DEC CX JMP SHORT NOTDUAL3 BNDERR: MOV BYTE PTR ES:[DI-1]," " ; patch up that space JMP MustGetWord ; go back and scan until delim NOTDUAL3: ENDIF CMP AL,"?" JNZ MUSTGETWORD OR DL,1 ; Flag ambiguous file name JMP MUSTGETWORD FILLNAM: MOV AL," " REP STOSB DEC SI return SCANB: LODSB CALL SPCHK JZ SCANB DEC SI return MakeFCB ENDP ; ; NameTrans is used by FindPath to scan off an element ; of a path. We must allow spaces in pathnames ; Inputs: SS - DOSGROUP ; DS:SI name ; Outputs: DS:SI advanced over spot ; ES:DI point to after Name1 ; registers modified: AX, BX, CX, DX procedure NameTrans,near MOV BYTE PTR [SpaceFlag],1 PUSH SS POP ES MOV DI,OFFSET DOSGROUP:NAME1 PUSH DI MOV AL,' ' MOV CX,11 REP STOSB XOR AL,AL MOV DL,AL STOSB POP DI CMP BYTE PTR [SI],'.' IF KANJI JZ FOOBAR CALL NORMSCAN CMP [NAME1],0E5H retnz MOV [NAME1],5 return FOOBAR: ELSE JNZ NORMSCAN ENDIF MOVSB LODSB CALL PATHCHRCMP JZ GOTDOTNAME OR AL,AL JZ GOTDOTNAME CMP AL,'.' JNZ BADDOTS STOSB LODSB CALL PATHCHRCMP JZ GOTDOTNAME OR AL,AL JZ GOTDOTNAME DEC SI BADDOTS: DEC SI GOTDOTNAME: DEC SI XOR AL,AL return nametrans ENDP SUBTTL BUILDFCB -- MAKE A BLANK FCB FOR A DEVICE PAGE procedure BuildFCB,near ASSUME DS:DOSGROUP,ES:DOSGROUP ; Function: ; Build a blank FCB for I/O to a device ; Outputs: ; Same as GETNAME MOV AX," " MOV DI,OFFSET DOSGROUP:DEVFCB+8 ; Point to extent field STOSW STOSB ; Blank out extent field XOR AX,AX MOV CX,10 REP STOSW ; Fill FCB with zeros STOSB invoke DATE16 MOV DI,OFFSET DOSGROUP:DEVFCB+22 XCHG AX,DX STOSW XCHG AX,DX STOSW XCHG AX,BX ; But device number in AH MOV BX,OFFSET DOSGROUP:DEVFCB MOV SI,DI XOR AL,AL ; Set zero, clear carry return BuildFCB ENDP SUBTTL MOVENAME, LODNAME -- EXAMINE FCB AND SETUP PAGE procedure FCB_move,NEAR entry MOVNAMENOSET MOV DI,1 JMP SHORT MOVSTART entry MOVNAME ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS, DX point to FCB or extended FCB ; Outputs: ; DS:DX point to normal FCB ; DS:SI point after end of NAME/EXT in FCB ; ES = DOSGROUP ; If file name OK: ; [NAME1] has name in upper case ; All registers destroyed ; Carry set if bad file name or drive XOR DI,DI MOVSTART: MOV WORD PTR [CREATING],0E500H ; Not creating, not DEL *.* MOV SI,DX LODSB MOV [EXTFCB],AL ; Set flag if extended FCB in use XOR AH,AH ; Set default attributes CMP AL,-1 ; Is it an extended FCB? JNZ HAVATTRB ADD DX,7 ; Adjust to point to normal FCB ADD SI,6 MOV AH,[SI-1] ; Attribute byte LODSB ; Get drive select byte HAVATTRB: invoke GETTHISDRV retc PUSH DS PUSH DX PUSH SI PUSH AX ; ; DS:DX is pointer to good FCB ; DS:SI is same ; ; Move the file into Name1 and UCASE it ; PUSH DI context ES MOV DI,OFFSET DOSGROUP:NAME1 CALL LodName POP DI JC DrvNoSet ; ; are we setting current dir info? ; OR DI,DI JNZ DrvNoSet ; do not set dir info ; ; check for device name first, eliminating drive hits on devices ; context DS invoke DEVNAME JNC DrvNoSet ; we have a device ; ; make sure that everything is current ; invoke FATREAD ASSUME DS:NOTHING,ES:NOTHING MOV BYTE PTR [ATTRIB],attr_directory+attr_hidden+attr_system invoke GETCURRDIR DrvNoSet: POP AX MOV BYTE PTR [ATTRIB],AH POP SI POP DX POP DS context ES MOV DI,OFFSET DOSGROUP:NAME1 entry LODNAME ; Inputs: DS:SI point to an FCB ; ES:DI point to an FCB ; Outputs: DS:SI point to after FCB ; ES:DI point to after FCB ; FCB from DS:SI copied and ucased to ES:DI ; Carry set if there was an error. ; Destroys AX,CX CMP BYTE PTR [SI]," " ; Don't allow blank as first letter STC ; In case of error retz IF KANJI MOV CX,8 CMP BYTE PTR [SI],0E5H JNZ MOVCHK INC SI MOV AL,5 STOSB MOVSB MOV CX,6 MOVCHK: CALL GETLET JB RET6 JNZ STOLET ; Is it a delimiter? CMP AL," " ; This is the only delimiter allowed STC ; In case of error JNZ RET6 STOLET: STOSB CALL TESTKANJ JZ MOVLP ;No LODSB ;Get second byte DEC CX JZ BOUNDERR ;Attempt to cross boundry STOSB MOVLP: LOOP MOVCHK MOV CX,3 MOVCHK2: CALL GETLET JB RET6 JNZ STOLET2 ; Is it a delimiter? CMP AL," " ; This is the only delimiter allowed STC ; In case of error retnz STOLET2: STOSB CALL TESTKANJ JZ MOVLP2 ;No LODSB ;Get second byte DEC CX JNZ DOSTORE BOUNDERR: ;Attempt to cross boundry STC return DOSTORE: STOSB MOVLP2: LOOP MOVCHK2 ELSE MOV CX,11 MOVCHK: CALL GETLET JB RET6 JNZ STOLET ; Is it a delimiter? CMP AL," " ; This is the only delimiter allowed STC ; In case of error retnz STOLET: STOSB LOOP MOVCHK ENDIF CLC ; Got through whole name - no error RET6: return FCB_Move ENDP SUBTTL GETLET, DELIM -- CHECK CHARACTERS AND CONVERT PAGE procedure GetLet,NEAR ; Get a byte from [SI], convert it to upper case, and compare for delimiter. ; ZF set if a delimiter, CY set if a control character (other than TAB). LODSB CMP AL,"a" JB CHK1 CMP AL,"z" JA CHK1 SUB AL,20H ; Convert to upper case CHK1: PUSH SI MOV SI,[Current_Country] ADD SI,Map_call PUSH CS ; CS for long return CALL WORD PTR CS:[SI] POP SI entry CHK CMP AL,"." retz CMP AL,'"' retz CALL PATHCHRCMP retz CMP AL,"[" retz CMP AL,"]" retz DELIM: CMP AL,":" ; Allow ":" as separator in IBM version retz CMP AL,"<" retz CMP AL,"|" retz CMP AL,">" retz CMP AL,"+" retz CMP AL,"=" retz CMP AL,";" retz CMP AL,"," retz SPCHK: CMP AL,9 ; Filter out tabs too retz ; WARNING! " " MUST be the last compare CMP AL," " return GetLet ENDP procedure PATHCHRCMP,NEAR CMP AL,'/' retz CMP AL,'\' return PathChrCMP ENDP IF KANJI procedure TESTKANJ,NEAR CMP AL,81H JB NOTLEAD CMP AL,9FH JBE ISLEAD CMP AL,0E0H JB NOTLEAD CMP AL,0FCH JBE ISLEAD NOTLEAD: PUSH AX XOR AX,AX ;Set zero POP AX return ISLEAD: PUSH AX XOR AX,AX ;Set zero INC AX ;Reset zero POP AX return TESTKANJ ENDP ENDIF do_ext CODE ENDS END