2025-04-27 07:49:33 -04:00

711 lines
18 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

page ,132
; SCCSID = @(#)tenv2.asm 1.1 85/05/14
; SCCSID = @(#)tenv2.asm 1.1 85/05/14
TITLE Part6 COMMAND Transient routines.
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
; Environment utilities and misc. routines
.xlist
.xcref
include comsw.asm
include dossym.inc
include syscall.inc
include find.inc
include comseg.asm
include comequ.asm
.list
.cref
DATARES SEGMENT PUBLIC BYTE ;AC000;
EXTRN pipeflag:byte
DATARES ENDS
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
EXTRN ACRLF_PTR:WORD
EXTRN BadCD_Ptr:WORD
EXTRN Badmkd_ptr:word
EXTRN BADRMD_PTR:WORD
EXTRN Extend_buf_ptr:word ;AN000;
EXTRN Extend_buf_sub:byte ;AN022;
EXTRN MD_exists_ptr:word ;AN006;
EXTRN msg_disp_class:byte ;AC000;
EXTRN NOSPACE_PTR:WORD
EXTRN parse_chdir:byte ;AC000;
EXTRN parse_mrdir:byte ;AC000;
EXTRN PIPEEMES_PTR:WORD
EXTRN string_buf_ptr:word
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN CURDRV:BYTE
EXTRN DESTINFO:BYTE
EXTRN DESTTAIL:WORD
EXTRN DIRCHAR:BYTE
EXTRN dirflag:byte ;AN015;
EXTRN KPARSE:BYTE ;AC000; 3/3/KK
EXTRN msg_numb:word ;AN022;
EXTRN parse1_addr:dword ;AC000;
EXTRN parse1_type:byte ;AC000;
EXTRN PATHPOS:WORD
EXTRN RESSEG:WORD
EXTRN srcxname:byte ;AC000;
EXTRN string_ptr_2:word
EXTRN SWITCHAR:BYTE
EXTRN USERDIR1:BYTE
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC byte
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN cerror:near
PUBLIC $chdir
PUBLIC $mkdir
PUBLIC $rmdir
PUBLIC crlf2
PUBLIC crprint
PUBLIC delim
PUBLIC error_output
PUBLIC fcb_to_ascz
PUBLIC pathchrcmp
PUBLIC pathcrunch
PUBLIC savudir
PUBLIC savudir1
PUBLIC scanoff
PUBLIC strcomp
break $Chdir
; ****************************************************************
; *
; * ROUTINE: $CHDIR
; *
; * FUNCTION: Entry point for CHDIR command. Parse the command
; * line. If path is found, CHDIR to path. If a drive
; * letter is found, get and display the current dir
; * of the specified drive. If nothing is found, get
; * and display the current dir of the default drive.
; *
; * INPUT: command line at offset 81H
; *
; * OUTPUT: none
; *
; ****************************************************************
assume ds:trangroup,es:trangroup
$CHDIR:
mov si,81H
mov di,offset trangroup:parse_chdir ;AN000; Get adderss of PARSE_CHDIR
xor cx,cx ;AN000; clear cx,dx
xor dx,dx ;AN000;
invoke parse_with_msg ;AC018; call parser
cmp ax,end_of_line ;AC000; are we at end of line?
jz bwdJ ; No args
cmp ax,result_no_error ;AC000; did we have an error?
jnz ChDirErr ;AC018; yes - exit
cmp parse1_type,result_drive ;AC000; was a drive entered?
jnz REALCD ; no
;
; D: was found. See if there is anything more.
;
mov di,offset trangroup:parse_chdir ;AC000; get address of parse_chdir
xor dx,dx ;AC000;
invoke parse_check_eol ;AC000; call parser
jnz ChDirErr ;AC000;
bwdJ:
invoke build_dir_for_chdir ; Drive only specified
call crlf2
return
REALCD:
push si ;AN000; save position in line
lds si,parse1_addr ;AN000; get address of filespec
invoke move_to_srcbuf ;AN000; move to srcbuf
pop si ;AN000; restore position in line
mov di,offset trangroup:parse_chdir ;AC000; get address of parse_chdir
xor dx,dx ;AC000;
invoke parse_check_eol ;AC000; call parser
jnz ChDirErr ;AC000;
invoke SETPATH
TEST [DESTINFO],2
JNZ BadChdir
MOV AH,CHDIR
INT 21h
retnc
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; see if path not found
jz BadChDir ;AN022; yes - issue old message
;SR;
; We want to issue "Invalid Directory" message even if the path is valid
;but is not a directory. The extended error returns "Access denied" which
;is kind of confusing. Issue the old message if access denied error is
;returned
;
cmp ax,error_access_denied
jz BadChDir
call Set_Ext_Error_Subst ;AN022;
jmp short chdirerr ;AN022;
BadChDir:
MOV DX,OFFSET TRANGROUP:BADCD_ptr
ChDirErr:
invoke Std_Eprintf
return
break $Mkdir
assume ds:trangroup,es:trangroup
$MKDIR:
CALL SETRMMK
JC MkDirErr
MOV AH,MKDIR
INT 21h
retnc
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; see if path not found
jz MD_other_err ;AN022; yes - issue old message
cmp ax,error_access_denied ;AN022; access denied?
jz badmderr ;AN022; yes - see if file exists
call Set_Ext_Error_Subst ;AN022;
jmp short MkDirerr ;AC022; yes - go print it
BADMDERR:
mov dx,offset trangroup:srcxname ;AN006; Set Disk transfer address
mov ah,Set_DMA ;AN006;
int 21h ;AN006;
MOV AH,Find_First ;AN006; see if file/dir exists
mov cx,attr_directory ;AN006; search for directory
INT 21h ;AN006;
jc MD_other_err ;AN006; doesn't exist - must be something else
mov dl,srcxname.find_buf_attr ;AN006; we found a file/dir
test dl,attr_directory ;AN006; was it a directory?
jz MD_other_err ;AN006; no - must have been a file
mov dx,offset trangroup:MD_exists_ptr ;AN006; set up already exists error
jmp short MkDirErr ;AN006; make sure we didn't have network error
MD_other_err: ;AN006;
MOV DX,OFFSET TRANGROUP:BADMKD_ptr
MkDirErr:
invoke Std_Eprintf
return
Break <Common MkDir/RmDir set up code>
;****************************************************************
;*
;* ROUTINE: SETRMMK
;*
;* FUNCTION: Parse routine for the internal MKDIR and RMDIR
;* commands. Parses the command line for a required
;* filespec.
;*
;* INPUT: command line at offset 81H
;*
;* OUTPUT: carry clear
;* DS:DX points to ASCIIZ argument
;* carry set
;* DS:DX has error message pointer
;*
;****************************************************************
SETRMMK:
mov si,81H
mov di,offset trangroup:parse_mrdir ;AN000; Get adderss of PARSE_MRDIR
xor cx,cx ;AN000; clear cx,dx
xor dx,dx ;AN000;
invoke parse_with_msg ;AC000; call parser
cmp ax,result_no_error ;AC000; did we have an error?
jnz NOARGERR ;AC000; yes - exit
mov di,offset trangroup:srcxname ;AN000; get address of srcxname
push di ;AN000; save address
push si ;AN000; save position in line
lds si,parse1_addr ;AN000; get address of path
mrdir_move_filename: ;AN000; put filespec in srcxname
lodsb ;get a char from buffer
stosb ;AN000; store in srcxname
cmp al,end_of_line_out ;AC000; it char a terminator?
jnz mrdir_move_filename ;AC000; no - keep moving
pop si ;AN000; get line position back
;
; we have scanned an argument. See if any args beyond.
;
mov di,offset trangroup:parse_mrdir ;AC000; get address of parse_mrdir
invoke parse_check_eol ;AC000; are we at end of line?
pop dx ;AC000; get address of SRCXNAME
retz ;yes - return no error
NOARGERR:
mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
XOR AX,AX
STC
return
break $Rmdir
assume ds:trangroup,es:trangroup
$RMDIR:
CALL SETRMMK
JC RmDirErr
JNZ BADRDERR
MOV AH,RMDIR
INT 21h
retnc
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; see if path not found
jz badrderr ;AN022; yes - issue old message
cmp ax,error_access_denied ;AN022; access denied?
jz badrderr ;AN022; yes - issue old message
call Set_Ext_Error_Subst ;AN022;
jmp short RmDirerr ;AC022; yes - go print it
BADRDERR:
MOV DX,OFFSET TRANGROUP:BADRMD_ptr
RmDirErr:
invoke STD_Eprintf
return
;****************************************************************
;*
;* ROUTINE: Set_ext_error_subst
;*
;* FUNCTION: Sets up substitution for extended error
;*
;* INPUT: AX - extended error number
;* DX - offset of string
;*
;* OUTPUT: Extend_Buf_Ptr set up for STD_EPRINTF
;*
;****************************************************************
Set_ext_error_subst proc near ;AN022;
mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class
mov string_ptr_2,dx ;AN022; get address of failed string
mov Extend_buf_sub,one_subst ;AN022; put number of subst in control block
mov dx,offset TranGroup:Extend_Buf_ptr ;AN022; get extended message pointer
mov Extend_Buf_ptr,ax ;AN022; get message number in control block
ret ;AN022; return
Set_ext_error_subst endp ;AN022;
Break <SavUDir - preserve the users current directory on a particular drive>
;
; SavUDir - move the user's current directory on a drive into UserDir1
; SavUDir1 - move the user's current directory on a drive into a specified
; buffer
;
; Inputs: DL has 1-based drive number
; ES:DI has destination buffer (SavUDir1 only)
; Outputs: Carry Clear
; DS = TranGroup
; Carry Set
; AX has error code
; Registers Modified: AX, SI
;
SAVUDIR:
MOV DI,OFFSET TRANGROUP:USERDIR1
SAVUDIR1:
MOV AL,DL
ADD AL,'@'
CMP AL,'@'
JNZ GOTUDRV
ADD AL,[CURDRV]
INC AL ; A = 1
GOTUDRV:
STOSB
MOV AH,[DIRCHAR]
MOV AL,':'
STOSW
PUSH ES
POP DS
ASSUME DS:NOTHING
MOV SI,DI
MOV AH,CURRENT_DIR ; Get the Directory Text
INT 21h
retc
PUSH CS
POP DS
ASSUME DS:TRANGROUP
return
CRLF2:
PUSH DX
MOV DX,OFFSET TRANGROUP:ACRLF_ptr
PR:
PUSH DS
PUSH CS
POP DS
invoke std_printf
POP DS
POP DX
return
;
; These routines (SCANOFF, DELIM) are called in batch processing when DS
; may NOT be TRANGROUP
;
ASSUME DS:NOTHING,ES:NOTHING
SCANOFF:
LODSB
CALL DELIM
JZ SCANOFF
DEC SI ; Point to first non-delimiter
return
;
; Input: AL is character to classify
; Output: Z set if delimiter
; NZ set otherwise
; Registers modified: none
;
DELIM:
CMP AL,' '
retz
CMP AL,'='
retz
CMP AL,','
retz
CMP AL,';'
retz
CMP AL,9 ; Check for TAB character
retz
CMP AL,0ah ; Check for line feed character - BAS
return
ASSUME DS:TRANGROUP,ES:TRANGROUP
FCB_TO_ASCZ: ; Convert DS:SI to ASCIZ ES:DI
MOV CX,8
MAINNAME:
LODSB
CMP AL,' '
JZ SKIPSPC
STOSB
SKIPSPC:
LOOP MAINNAME
LODSB
CMP AL,' '
JZ GOTNAME
MOV AH,AL
MOV AL,dot_chr
STOSB
XCHG AL,AH
STOSB
MOV CL,2
EXTNAME:
LODSB
CMP AL,' '
JZ GOTNAME
STOSB
LOOP EXTNAME
GOTNAME:
XOR AL,AL
STOSB
return
STRCOMP:
;
; Compare ASCIZ DS:SI with ES:DI.
; SI,DI destroyed.
;
CMPSB
retnz ; Strings not equal
cmp byte ptr [SI-1],0 ; Hit NUL terminator?
retz ; Yes, strings equal
jmp short STRCOMP ; Equal so far, keep going
CRPRINT:
PUSH AX
MOV AL,13
PUSH CX
PUSH DI
MOV DI,DX
MOV CX,-1
PUSH ES
PUSH DS
POP ES
REPNZ SCASB ; LOOK FOR TERMINATOR
mov byte ptr [di-1],0 ; nul terminate the string
POP ES
mov string_ptr_2,dx
mov dx,offset trangroup:string_buf_ptr
invoke std_printf
mov ds:byte ptr [di-1],13 ; now put the CR back
JC ERROR_OUTPUT
POP DI
POP CX
POP AX
return
ERROR_OUTPUT:
PUSH CS
POP DS
ASSUME DS:TRANGROUP
MOV ES,[RESSEG]
ASSUME ES:RESGROUP
MOV DX,OFFSET TRANGROUP:NOSPACE_ptr
CMP [PIPEFLAG],0
JZ GO_TO_ERROR
invoke PipeOff
MOV DX,OFFSET TRANGROUP:PIPEEMES_ptr
GO_TO_ERROR:
JMP CERROR
ASSUME DS:TRANGROUP,ES:TRANGROUP
PATHCHRCMP:
;---- Mod for path invocation ----
PUBLIC pathchrcmp
;----
push ax
mov ah,'/'
CMP [SWITCHAR],ah
JZ NOSLASHT
CMP AL,'/'
jz pccont
NOSLASHT:
CMP AL,'\'
pccont:
pop ax
return
;
; PATHCRUNCH -
;
; ENTRY FCB (in PSP) contains drive # to crunch on
; PathPos = ptr to string with pathname in it
; PathCnt = length of string
;
; EXIT PathPos = ptr after pathname (w/ NULL) in string
; PathCnt = length left in string
; DestIsDir = nonzero if pathname delimiter char's found in pathname
; DestInfo<bit1> = set if wildcard char's found in pathname
; If path crunched successfully,
; CY = clear
; Current directory is changed to directory in pathname
; UserDir1 contains previous directory for use by RestUDir
; RestDir = nonzero to flag later restoration of user's dir
; DestTail = ptr to beginning of filename
; If filename found in pathname,
; ZR = clear
; FCB filename fields contain filename
; If filename not found (pure directory path),
; ZR = set
; FCB filename fields are wildcarded with ?'s
; If pathcrunch failed (no ChDir's worked),
; CY = set
; Msg_Numb = extended error code
;
; NOTE DIR asks PathCrunch to forego parsing the filename into the
; FCB by setting DirFlag. In this case, the FCB is returned
; with the filename wildcarded.
;
PATHCRUNCH:
mov [msg_numb],0 ;AN022; Set up message flag
MOV DL,DS:[FCB] ; DL = drive # (1 = A)
CALL SAVUDIR ; save current directory in UserDir1
jc pcrunch_cderrJ ;AN022; if error on current dir - report
invoke SETPATH ; scan past switches, whitespace
; DX = ptr to pathname, NULL-terminated
; PathPos = ptr to byte after NULL at end of pathname
TEST [DESTINFO],2 ; test if wildcards (? or *) seen
JNZ TRYPEEL ; wildcard seen, peel filename
MOV AH,CHDIR ; AH = DOS ChDir function code
INT 21h ; call DOS
jnc chdir_worked ;AN022; no error - continue
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; if path not found
jz trypeel ;AC022; keep trying
cmp ax,error_access_denied ;AN022; if access denied
jz trypeel ;AC022; keep trying
mov [msg_numb],ax ;AN022; set up message flag
jmp peelfail ;AN022; exit with other error
chdir_worked:
invoke SETREST1 ; set 'Restore Directory' flag true
MOV AL,'?' ; if pure dir, wildcard filename in FCB
MOV DI,5DH
MOV CX,11
REP STOSB
XOR AL,AL ; return carry clear, zero set
return
pcrunch_cderrj: ;AN022; need this for long jmp
jmp pcrunch_cderr ;AN022;
TRYPEEL:
MOV SI,[PATHPOS]
DEC SI ; SI = ptr to NULL at end of pathname
MOV AL,[SI-1] ; AL = last char of pathname
CMP [KPARSE],0
JNZ DELSTRT ; Last char is second KANJI byte, might be '\'
CALL PATHCHRCMP
JZ PEELFAIL ; Trailing '/'
DELSTRT:
MOV CX,SI ; CX = ptr to NULL at end of pathname
MOV SI,DX ; SI = ptr to start of pathname
PUSH DX ; save ptr to pathname
DELLOOP:
CMP SI,CX
JZ GOTDELE ; no char's left, we have what we have
LODSB ; AL = next char of pathname
invoke TESTKANJ
JZ NOTKANJ8 ; not Kanji, move along
INC SI
JMP DELLOOP
NOTKANJ8:
CALL PATHCHRCMP
JNZ DELLOOP ; not a path delimiter, keep looking
MOV DX,SI
DEC DX ; DX = ptr to last delimiter found
JMP DELLOOP ; go look for more
GOTDELE:
MOV SI,DX ; SI = ptr to pathname or last delim
POP DX ; DX = ptr to pathname
CMP SI,DX
JZ BADRET ; didn't find path delim
MOV CX,SI ; CX = ptr to last path delimiter
MOV SI,DX ; SI = ptr to pathname
DELLOOP2: ; Set value of KPARSE
CMP SI,CX
JZ TRYCD ; roll up till SI meets CX
MOV [KPARSE],0
LODSB
INVOKE TESTKANJ
JZ DELLOOP2
INC SI
INC [KPARSE]
JMP DELLOOP2
TRYCD:
push ax
mov al,dot_chr ; AL = '.'
CMP BYTE PTR [SI+1],al ; check for '.' after path delim
;M019; allow continuation if '. ' or
;M019; '..' is not found.
jnz @F ;M019; '.' not found
cmp BYTE PTR [SI+2],al ;M019; check for '..'
jz @F ;M019; found '..'
cmp BYTE PTR [SI+2],0 ;M019; check for '. ' (null terminated)
@@: pop ax
JZ PEELFAIL ; if . or .., pure cd should have worked
mov al,[si-1]
CMP al,':' ; Special case d:\file
JZ BADRET
CMP [KPARSE],0
JNZ NOTDOUBLESL ; Last char is second KANJI byte, might be '\'
CALL PATHCHRCMP
JNZ NOTDOUBLESL
PEELFAIL:
STC ; //
return
NOTDOUBLESL:
MOV BYTE PTR [SI],0
MOV AH,CHDIR
INT 21h
JNC CDSUCC
pcrunch_cderr:
invoke get_ext_error_number ;AN022; get the extended error
mov [msg_numb],ax ;AN022; set up message flag
or si,si ;AN022; set up zero flag to not zero
stc ;AN022; set up carry flag
return
BADRET:
MOV AL,[SI]
CALL PATHCHRCMP ; Special case 'DIRCHAR'file
STC
retnz
XOR BL,BL
XCHG BL,[SI+1]
MOV AH,CHDIR
INT 21h
jc pcrunch_cderr ;AN022; go to error exit
MOV [SI+1],BL
CDSUCC:
invoke SETREST1
INC SI ; Reset zero
MOV [DESTTAIL],SI
pushf ;AN015; save flags
cmp dirflag,-1 ;AN015; don't do parse if in DIR
jz pcrunch_end ;AN015;
MOV DI,FCB
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 02H ; Parse with default drive
INT 21h
pcrunch_end:
popf ;AN015; get flags back
return
trancode ends
end