📄 filename.asm
字号:
INC DI ; pretend there's another "\" on the end
CALL PROCESS_SLASH ; and process as if there is a slash char,
; removing the dots.
CheckDir:
CMP DL,SLASH_SEEN ; does it end with a '\'?
JNE ADD_NULL ; brif not -- just add the null byte
OR DH,FN_IS_DIR ; set directory flag so B$ADD_EXT won't
; try to add an extension to directory name
ADD_NULL:
XCHG AX,CX ; set AX = 0, since CX will always = 0 here
STOSB ; store terminating null byte
; complete null-terminated pathname without "\." or "\.." is now in buffer.
MOV CX,DI ; one past the last position (past null byte)
POP DI ; restore DI to point to the processed pathname
SUB CX,DI ; and set CX to the count of chars in pathname
; (including the null)
MOV AL,DH ; return flags in AL
cEnd
ERBFN: ; centrally located
jmp B$ERR_BFN ; give bad filename error
CHK_BAD_CHAR: ; Check if char is a valid filename character.
CMP AL,' ' ; control character?
JB ERBFN ; brif so -- bad filename
; search table of invalid chars for current char
PUSH DI ; save registers
PUSH CX
MOV DI,OFFSET DGROUP:BAD_CHAR_TBL ; table to search
MOV CX,b$BadCharCnt ; number of chars to search (changes)
REPNE SCASB ; search for char in table
JZ ERBFN ; brif char found -- bad filename
POP CX ; restore registers
POP DI
JMP VALID_CHAR ; valid char -- continue processing
;***
;PROCESS_SLASH -- perform processing for a "\" in the pathname
;
;Purpose:
; Eliminates "\.\" and "\dir\..\" from pathname string, and checks
; for underflow (".." at the root directory level).
;
;Entry: (same conditions as within pathname processing loop)
; ES:DI = pointer to next char in processed pathname
; DH = flags:
; FN_WILD -- name portion of pathname contains a wildcard
; FN_HAS_EXT -- name portion of pathname has extension
; DL = last char(s) flag:
; SLASH_SEEN -- last char in path is "\"
; SLASHDOT_SEEN -- last chars in path are "\."
; SLASHDOTDOT_SEEN - last chars in path are "\.."
;Exit:
; DI updated
; DH = NOT FN_WILD and NOT FN_HAS_EXT
; DL = SLASH_SEEN
; b$PN_NAME = address of last "\" in pathname.
;
;Uses:
; AL
;
;Preserves:
;
;Exceptions:
; Bad File Name
;
;******************************************************************************
PROCESS_SLASH: ;Transform "\.\" or "\dir_name\..\" to "\"
CMP DL,SLASHDOT_SEEN ; seen "\.\"?
JNE CHK_SLASHDOTDOT ; brif not -- check for "\..\"
DEC DI ; remove the last "\"
DEC DI ; remove the "."
JMP SHORT SLASH_END ; indicate slash char seen
CHK_SLASHDOTDOT:
CMP DL,SLASHDOTDOT_SEEN ; seen "\..\"?
JNE SLASH_END ; brif not -- indicate slash char seen
SUB DI,4 ; get rid of the "\..\"
; [DI] = addr of the first "\"
REMOVE_SLASHES:
DEC DI ; remove another char
MOV AL,[DI] ; get deleted char
CALL CHK_FOR_SLASH ; just removed a previous "\"?
JE REMOVE_SLASHES ; remove another char
CMP DI,FIRST_SLASH ; have we deleted the first "\"?
JB ERBFN ; brif so -- underflow -- too many "\..\"'s
REMOVE_NAME:
DEC DI ; remove another char of the name
MOV AL,[DI] ; get deleted char
CALL CHK_FOR_SLASH ; just removed a previous "\"?
JNE REMOVE_NAME ; brif not -- delete another character
INC DI ; put back the last "\"
SLASH_END:
MOV DX,SLASH_SEEN ; indicate slash character seen, no wildcards,
; and no extension
MOV b$PN_NAME,DI ; set address of name.ext in pathname
RET ; return to caller
;***
; CHK_FOR_SLASH -- check if char is "\" or "/"
;
;Purpose:
; Since we're to allow both forward and backwards slashes in the
; pathname, check if char is "\" or "/". Extracted to save code.
;
;Entry:
; AL = char to check.
;Exit:
; ZF if AL = "\" or "/", NZ otherwise.
;Uses:
; None
;Preserves:
; All
;Exceptions:
; None
;
;******************************************************************************
CHK_FOR_SLASH: ; check for forward slash and back slash
CMP AL,'\' ; is it a back slash?
JE CHK_SLASH_EXIT ; brif so -- return to caller
CMP AL,'/' ; is it a forward slash?
CHK_SLASH_EXIT:
RET ; return to caller
;***
; B$ADD_EXT -- add extension to pathname
;
;Purpose:
; Adds a 4-byte extension to a name, updating the count and checking
; for overflow. It first checks to see that there is not already an
; extension on the last name of the file.
;
;Entry:
; ES:DI = address of null-terminated pathname to append extension to
; CX = index into the pathname of the char past the char to overwrite
; (usually the pathname length returned from B$GET_PATHNAME)
; DS:SI = address of 4-bytes to be appended to name
; AL = flags returned from B$GET_PATHNAME
;
;Exit:
; if not already an extension
; extension appended to name at ES:DI
; CX = new length of name (INCLUDING the NULL)
;
;Uses:
; SI,AX
;
;Preserves:
; BX,DX
;
;Exceptions:
; Bad file name
;
;******************************************************************************
cProc B$ADD_EXT,<NEAR,PUBLIC>,<DI>
cBegin
TEST AL,FN_HAS_EXT or FN_IS_DIR ; does the filename already have
; an extension (or end with a '\')?
JNZ NO_EXTENSION ; brif so -- don't add an extension
DEC CX ; CX = # chars w/o the null
ADD DI,CX ; set destination pointer to point to null byte
NextChar:
INC cx ; advance count
CMP CX,FILNAML ; will we overflow with this char?
JA ERBFN ; brif so -- Bad file name error
LODSB ; get char
STOSB ; store it
OR AL,AL ; got the null yet?
JNZ NextChar
NO_EXTENSION:
cEnd
;***
; B$GET_CUR_DRIVE -- get current drive letter and number
;
;Purpose:
;
; get current drive number (1-26) and letter (A-Z) from DOS
;
;Entry:
; none
;
;Exit:
; AL = current drive letter (A-Z)
; AH = ':'
;
;Uses:
; DX
;
;Preserves:
; BX,CX
;
;Exceptions:
; None
;
;******************************************************************************
cProc B$GET_CUR_DRIVE,<NEAR,PUBLIC>
cBegin
CALLOS GDRV ; AL = default drive (A=0, B=1, etc)
CBW ; clear high byte
ADD AX,':' SHL 8 + 'A' ; return drive letter in AL and ':' in AH
cEnd
;***
; B$GET_CUR_DIR -- return current directory for a given drive number.
;
;Purpose:
;
;Algorithm:
; Add "\" to string
; Get current directory from DOS into string
;
;Entry:
; ES:DI = address of area to place current directory
; DX = drive number (1-26)
; ES=DS
;
; Note: IF FV_FARSTR, DS is not necessarily DGROUP on entry.
;
;Exit:
; current directory (null-terminated) loaded into buffer
;
;Uses:
; AX,DX
;
;Preserves:
; BX,CX
;
;Exceptions:
; Device not available
;
;******************************************************************************
cProc B$GET_CUR_DIR,<NEAR,PUBLIC>,<CX>
cBegin
MOV AL,'\' ; add a beginning "\"
STOSB
PUSH SI ; save register
MOV SI,DI ; set SI to current location in buffer
CALLOS CURDIR,ERDNA ; load current directory into DS:SI
POP SI ; restore register
cEnd
ERDNA:
jmp B$ERR_DNA ; give Device unavailable error
;***
; B$GET_DEV_NUM
;
;Purpose:
; Checks if the first 5 chars of a string are equal to some BASIC
; device, and if so, returns the device number for that device.
; Accepts names of the form "XXXX:yyyyyy" as a valid devices, and
; copies the options string for valid devices into the specified buffer.
;
;Entry:
; BX = pointer to filename string descriptor
;
;Exit:
; AL = device number if device, or 0 if not a valid BASIC device
; FLAGS = result of "OR AL,AL"
;
;Uses:
; None
;
;Preserves:
; BX,CX,DX
;
;Exceptions:
; none
;
;******************************************************************************
cProc B$GET_DEV_NUM,<NEAR,PUBLIC>,<ES,SI,DI,CX>
cBegin
MOV SI,[BX+2] ; [DS:SI] = pointer to string data
CMP WORD PTR [BX],5 ; length < 5?
JB NOT_DEV ; brif so -- not a valid BASIC device
CMP BYTE PTR [SI+4],':' ; name of the form "xxxx:" ?
JNZ NOT_DEV ; brif not -- not a BASIC device
; No checks will need to be done for KANJI characters, because there are
; none in our tables. The call to B$UPCASE will not matter, as it can not
; do anything to make a match succeed. (The first byte of a KANJI character
; will not be converted, nor will it be in the table.)
MOV DI,OFFSET DEVICE_NAME_TABLE
PUSH CS ; set ES = CS for table reference
POP ES
DEV_LOOP: ; for each device in table
CMP BYTE PTR ES:[DI],0 ; end of table?
JZ NOT_DEV ; brif so -- not a valid BASIC device
PUSH SI ; save start of name
MOV CX,4 ; compare 4 chars
CMP_LOOP:
LODSB ; get character from the name into AL
CALL B$UPCASE ; convert to upper case
SCASB ; does it match char in the device table?
JE NEXT_CHAR ; brif so -- try next char
ADD DI,CX ; skip over remaining chars and dev # in table
POP SI ; retrieve start of name
JMP SHORT DEV_LOOP ; and try to match the next entry
NEXT_CHAR:
LOOP CMP_LOOP ; falls through if device matched
POP SI ; clean off stack
MOV AL,ES:[DI] ; return device number in AL
OR AL,AL ; set flags for calling routine
JMP SHORT DEV_EXIT
NOT_DEV:
XOR AL,AL ; not a device -- clear AL and flags
DEV_EXIT:
cEnd
sEnd DK_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -