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

782 lines
21 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 = @(#)tcmd1b.asm 1.1 85/05/14
; SCCSID = @(#)tcmd1b.asm 1.1 85/05/14
TITLE PART4 COMMAND Transient routines.
;/*
; * Microsoft Confidential
; * Copyright (C) Microsoft Corporation 1991
; * All Rights Reserved.
; */
; Internal commands DIR,PAUSE,ERASE,TYPE,VOL,VER
.xlist
.xcref
include dossym.inc
include bpb.inc
include syscall.inc
include filemode.inc
include sf.inc
include comseg.asm
include comsw.asm ;ac000;
include comequ.asm
include ioctl.inc ;an000;
.list
.cref
DATARES SEGMENT PUBLIC BYTE ;AN020;AC068;
EXTRN append_flag:byte ;AN020;AC068;
EXTRN append_state:word ;AN020;AC068;
EXTRN SCS_PAUSE:BYTE ; yst 4-5-93
DATARES ENDS ;AN020;AC068;
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
EXTRN badcpmes_ptr:word ;AC022;
EXTRN Extend_buf_ptr:word ;AC000;
EXTRN Extend_buf_sub:byte ;AN000;
EXTRN inornot_ptr:word
EXTRN msg_disp_class:byte ;AC000;
EXTRN parse_erase:byte ;AC000;
EXTRN parse_mrdir:byte ;AC000;
EXTRN parse_rename:byte ;AC000;
EXTRN parse_vol:byte ;AC000;
EXTRN PauseMes_ptr:word
EXTRN renerr_ptr:word
EXTRN slash_p_syn:word ;AC000;
EXTRN volmes_ptr:word ;AC000;
EXTRN volmes_ptr_2:word ;AC000;
EXTRN volsermes_ptr:word ;AC000;
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN bytcnt:word
EXTRN charbuf:byte
EXTRN comsw:word
EXTRN curdrv:byte
EXTRN destinfo:byte
EXTRN destisdir:byte
EXTRN dirbuf:byte
EXTRN msg_numb:word ;AN022;
EXTRN one_char_val:byte
EXTRN parse1_addr:dword ;AN000;
EXTRN parse1_syn:word ;AN000;
EXTRN resseg:word ;AN020;AC068;
EXTRN srcbuf:byte ;AN000;
EXTRN string_ptr_2:word ;AN000;
EXTRN TPA:word
EXTRN vol_drv:byte
EXTRN vol_ioctl_buf:byte ;AC000;
EXTRN vol_label:byte ;AC000;
EXTRN vol_serial:dword ;AC000;
EXTRN zflag:byte
extrn TypeFilSiz:dword
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC BYTE
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
;---------------
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN arg:byte ; the arg structure!
transpace ends
;---------------
EXTRN cerror:near
EXTRN error_output:near
EXTRN notest2:near
EXTRN slashp_erase:near ;AN000;
EXTRN std_printf:near
EXTRN tcommand:near
PUBLIC badpath_err ;AN022;
PUBLIC crename
PUBLIC DisAppend
PUBLIC erase
PUBLIC extend_setup ;AN022;
PUBLIC Get_ext_error_number ;AN022;
PUBLIC pause
PUBLIC Set_ext_error_msg ;AN000;
PUBLIC typefil
PUBLIC volume
break Pause
PAUSE:
push ds
mov ds, ResSeg
assume ds:resgroup
cmp SCS_PAUSE, 0
pop ds
jne pause_break
assume ds:trangroup,es:trangroup
mov dx,offset trangroup:pausemes_ptr
call std_printf
invoke GetKeystroke
invoke crlf2
pause_break:
return
break Erase
;****************************************************************
;*
;* ROUTINE: DEL/ERASE - erase file(s)
;*
;* FUNCTION: PARSE command line for file or path name and /P
;* and invoke PATHCRUNCH. If an error occurs, set
;* up an error message and transfer control to CERROR.
;* Otherwise, transfer control to NOTEST2 if /P not
;* entered or SLASHP_ERASE if /P entered.
;*
;* INPUT: command line at offset 81H
;*
;* OUTPUT: if no error:
;* FCB at 5ch set up with filename(s) entered
;* Current directory set to entered directory
;*
;****************************************************************
assume ds:trangroup,es:trangroup
ERASE:
mov si,81H ;AC000; get command line
mov comsw,0 ;AN000; clear switch indicator
mov di,offset trangroup:parse_erase ;AN000; Get adderss of PARSE_erase
xor cx,cx ;AN000; clear cx,dx
erase_scan:
xor dx,dx ;AN000;
invoke parse_with_msg ;AC018; call parser
cmp ax,end_of_line ;AN000; are we at end of line?
jz good_line ;AN000; yes - done parsing
cmp ax,result_no_error ;AC000; did we have an error?
jnz errj2 ;AC000; yes exit
cmp parse1_syn,offset trangroup:slash_p_syn ;AN000; was /P entered?
je set_erase_prompt ;AN000; yes - go set prompt
;
; Must be filespec since no other matches occurred. move filename to srcbuf
;
push si ;AC000; save position in line
lds si,parse1_addr ;AC000; get address of filespec
cmp byte ptr[si+1],colon_char ;AC000; drive specified?
jnz Erase_drive_ok ;AC000; no - continue
cmp byte ptr[si+2],end_of_line_out ;AC000; was only drive entered?
jnz erase_drive_ok ;AC000; no - continue
mov ax,error_file_not_found ;AN022; get message number in control block
jmp short extend_setup ;AC000; exit
erase_drive_ok:
invoke move_to_srcbuf ;AC000; move to srcbuf
pop si ;AC000; get position back
jmp short erase_scan ;AN000; continue parsing
set_erase_prompt:
cmp comsw,0 ;AN018; was /P already entered?
jz ok_to_set_erase_prompt ;AN018; no go set switch
mov ax,moreargs_ptr ;AN018; set up too many arguments
invoke setup_parse_error_msg ;AN018; set up an error message
jmp short errj2 ;AN018; exit
ok_to_set_erase_prompt: ;AN018;
inc comsw ;AN000; indicate /p specified
jmp short erase_scan ;AN000; continue parsing
good_line: ;G We know line is good
invoke pathcrunch
jnc checkdr
mov ax,[msg_numb] ;AN022; get message number
cmp ax,0 ;AN022; was message flag set?
jnz extend_setup ;AN022; yes - print out message
cmp [destisdir],0 ; No CHDIRs worked
jnz badpath_err ;AC022; see if they should have
checkdr:
cmp comsw,0 ;AN000; was /p specified
jz notest2j ;AN000; no - go to notest2
jmp slashp_erase ;AN000; yes - go to slashp_erase
notest2j:
jmp notest2
badpath_err: ;AN022; "Path not found" message
mov ax,error_path_not_found ;AN022; set up error number
extend_setup: ;AN022;
mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class
mov dx,offset TranGroup:Extend_Buf_ptr ;AC022; get extended message pointer
mov Extend_Buf_ptr,ax ;AN022; get message number in control block
errj2: ;AC022; exit jump
jmp Cerror ;AN022;
break Rename
; ****************************************************************
; *
; * ROUTINE: CRENAME - rename file(s)
; *
; * FUNCTION: PARSE command line for one full filespec and one
; * filename. Invoke PATHCRUNCH on the full filespec.
; * Make sure the second filespec only contains a
; * filename. If both openands are valid, attempt
; * to rename the file.
; *
; * INPUT: command line at offset 81H
; *
; * OUTPUT: none
; *
; ****************************************************************
assume ds:trangroup,es:trangroup
CRENAME:
mov si,81H ;AC000; Point to command line
mov di,offset trangroup:parse_rename;AN000; Get adderss of PARSE_RENAME
xor cx,cx ;AN000; clear cx,dx
xor dx,dx ;AN000;
invoke parse_with_msg ;AC018; call parser
cmp ax,result_no_error ;AC000; did we have an error?
;; jz crename_no_parse_error ;AC000; no - continue
jnz crename_parse_error ;AC000; Yes, fail. (need long jump)
;
; Get first file name returned from parse into our buffer
;
crename_no_parse_error:
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
xor dx,dx ;AN000; clear dx
invoke parse_with_msg ;AC018; call parser
cmp ax,result_no_error ;AN000; did we have an error?
JNZ crename_parse_error ;AN000; Yes, fail.
;
; Check the second file name for drive letter colon
;
push si ;AN000; save position in line
lds si,parse1_addr ;AC000; get address of path
mov al,':' ;AC000;
cmp [si+1],al ;AC000; Does the 2nd parm have a drive spec?
jnz ren_no_drive ;AN000; Yes, error
mov msg_disp_class,parse_msg_class ;AN000; set up parse error msg class
mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
mov Extend_Buf_ptr,BadParm_ptr ;AN000; get "Invalid parameter" message number
pop si ;AN000;
crename_parse_error: ;AC022;
jmp short errj ;AC000;
;
; Get second file name returned from parse into the fCB. Save
; character after file name so we can later check to make sure it
; isn't a path character.
;
ren_no_drive:
mov di,FCB+10H ;AC000; set up to parse second file name
mov ax,(Parse_File_Descriptor SHL 8) OR 01H ;AC000;
int 21h ;AC000; do the function
lodsb ;AC000; Load char after filename
mov one_char_val,al ;AN000; save char after filename
pop si ;AN000; get line position back
;
; We have source and target. See if any args beyond.
;
mov di,offset trangroup:parse_rename;AC000; get address of parse_rename
invoke parse_check_eol ;AC000; are we at end of line?
jnz crename_parse_error ;AN000; no, fail.
invoke pathcrunch
mov dx,offset trangroup:badcpmes_ptr
jz errj2 ; If 1st parm a dir, print error msg
jnc notest3
mov ax,[msg_numb] ;AN022; get message number
cmp ax,0 ;AN022; was message flag set?
jnz extend_setup ;AN022; yes - print out message
cmp [destisdir],0 ; No CHDIRs worked
jz notest3 ; see if they should have
Jmp badpath_err ;AC022; set up error
notest3:
mov al,one_char_val ;AN000; move char into AX
mov dx,offset trangroup:inornot_ptr ; Load invalid fname error ptr
invoke pathchrcmp ; Is the char in al a path sep?
jz errj ; Yes, error - 2nd arg must be
; filename only.
mov ah,FCB_Rename
mov dx,FCB
int 21h
cmp al, 0FFH ; Did an error occur??
jnz renameok
invoke get_ext_error_number ;AN022; get extended error
SaveReg <AX> ;AC022; Save results
mov al, 0FFH ; Restore original error state
renameok:
push ax
invoke restudir
pop ax
inc al
retnz
RestoreReg <AX> ;AC022; get the error number back
cmp ax,error_file_not_found ;AN022; error file not found?
jz use_renerr ;AN022; yes - use generic error message
cmp ax,error_access_denied ;AN022; error file not found?
jz use_renerr ;AN022; yes - use generic error message
jmp extend_setup ;AN022; need long jump - use extended error
use_renerr:
mov dx,offset trangroup:RenErr_ptr ;AC022;
ERRJ:
jmp Cerror
ret56: ret
break Type
;****************************************************************
;*
;* ROUTINE: TYPEFIL - Display the contents of a file to the
;* standard output device
;*
;* SYNTAX: TYPE filespec
;*
;* FUNCTION: If a valid filespec is found, read the file until
;* 1Ah and display the contents to STDOUT.
;*
;* INPUT: command line at offset 81H
;*
;* OUTPUT: none
;*
;****************************************************************
assume ds:trangroup,es:trangroup
TYPEFIL:
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 ;AC018; call parser
cmp ax,result_no_error ;AC000; did we have an error?
jnz typefil_parse_error ;AN000; yes - issue error message
push si ;AC000; save position in line
lds si,parse1_addr ;AC000; get address of filespec
invoke move_to_srcbuf ;AC000; move to srcbuf
pop si ;AC000; get position back
mov di,offset trangroup:parse_mrdir ;AC000; get address of parse_mrdir
invoke parse_check_eol ;AC000; are we at end of line?
jz gottarg ;AC000; yes - continue
typefil_parse_error: ;AN000; no - set up error message and exit
jmp Cerror
gottarg:
invoke setpath
test [destinfo],00000010b ; Does the filespec contain wildcards
jz nowilds ; No, continue processing
mov dx,offset trangroup:inornot_ptr ; Yes, report error
jmp Cerror
nowilds:
mov ax,ExtOpen SHL 8 ;AC000; open the file
mov bx,read_open_mode ;AN000; get open mode for TYPE
xor cx,cx ;AN000; no special files
mov dx,read_open_flag ;AN000; set up open flags
mov si,offset trangroup:srcbuf ;AN030; get file name
int 21h
jnc typecont ; If open worked, continue. Otherwise load
Typerr: ;AN022;
push cs ;AN022; make sure we have local segment
pop ds ;AN022;
invoke set_ext_error_msg ;AN022;
mov string_ptr_2,offset trangroup:srcbuf ;AC022; get address of failed string
mov Extend_buf_sub,one_subst ;AC022; put number of subst in control block
jmp cerror ;AC022; exit
typecont:
mov bx,ax ;AC000; get Handle
;M043
; We should do the LSEEK for filesize only if this handle belongs to a file
;and not if it belongs to a device. If device, set TypeFilSiz+2 to -1 to
;indicate it is a device.
;
mov ax,(IOCTL shl 8) or 0
int 21h
test dl,80h ;is it a device?
jz not_device ;no, a file
mov word ptr TypeFilSiz+2,-1 ;indicate it is a device
jmp short dotype
not_device:
;SR;
; Find the filesize by seeking to the end and then reset file pointer to
;start of file
;
mov ax,(LSEEK shl 8) or 2
xor dx,dx
mov cx,dx ;seek to end of file
int 21h
mov word ptr TypeFilSiz,ax
mov word ptr TypeFilSiz+2,dx ;store filesize
mov ax,(LSEEK shl 8) or 0
xor dx,dx
int 21h ;reset file pointer to start
dotype: ;M043
mov zflag,0 ; Reset ^Z flag
mov ds,[TPA]
xor dx,dx
ASSUME DS:NOTHING
typelp:
cmp cs:[zflag],0 ;AC050; Is the ^Z flag set?
retnz ; Yes, return
mov cx,cs:[bytcnt] ;AC056; No, continue
;
;Update the filesize left to read
;
cmp word ptr cs:TypeFilSiz+2,-1 ;is it a device? M043
je typ_read ;yes, just read from it; M043
cmp word ptr cs:TypeFilSiz+2,0 ;more than 64K left?
jz lt64k ;no, do word subtraction
sub word ptr cs:TypeFilSiz, cx
sbb word ptr cs:TypeFilSiz+2, 0 ;update filesize
jmp short typ_read ;do the read
lt64k:
cmp cx,word ptr cs:TypeFilSiz ;readsize <= buffer?
jbe gtbuf ;yes, just update readsize
;
;Buffer size is larger than bytes to read
;
mov cx,word ptr cs:TypeFilSiz
jcxz typelp_ret
mov word ptr cs:TypeFilSiz,0
jmp short typ_read
gtbuf:
sub word ptr cs:TypeFilSiz,cx ;update filesize remaining
typ_read:
mov ah,read
int 21h
jnc @f ;M043
jmp typerr ;M043
@@: ;M043
;M043; jc typerr ;AN022; Exit if error
mov cx,ax
jcxz typelp_ret ;AC000; exit if nothing read
push ds
pop es ; Check to see if a ^Z was read.
assume es:nothing
xor di,di
push ax
mov al,1ah
repnz scasb
pop ax
xchg ax,cx
cmp ax,0
jnz foundz ; Yes, handle it
cmp byte ptr [di-1],1ah ; No, double check
jnz typecont2 ; No ^Z, continue
foundz:
sub cx,ax ; Otherwise change cx so that only those
dec cx ; bytes up to but NOT including the ^Z
push cs ; will be typed.
pop es
assume es:trangroup
not zflag ; Turn on ^Z flag so that the routine
typecont2: ; will quit after this write.
push bx
mov bx,1
mov ah,write
int 21h
pop bx
jc Error_outputj
cmp ax,cx
jnz @f ;M043
jmp typelp ;M043
@@: ;M043
;M043; jz typelp
dec cx
cmp ax,cx
retz ; One less byte OK (^Z)
Error_outputj:
mov bx,1
mov ax,IOCTL SHL 8
int 21h
test dl,devid_ISDEV
retnz ; If device, no error message
jmp error_output
typelp_ret:
ret
break Volume
assume ds:trangroup,es:trangroup
;
; VOLUME command displays the volume ID on the specified drive
;
VOLUME:
mov si,81H
mov di,offset trangroup:parse_vol ;AN000; Get adderss of PARSE_VOL
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 OkVolArg ;AC000; Yes, display default volume ID
cmp ax,result_no_error ;AC000; did we have an error?
jnz BadVolArg ;AC000; Yes, fail.
;
; We have parsed off the drive. See if there are any more chars left
;
mov di,offset trangroup:parse_vol ;AC000; get address of parse_vol
xor dx,dx ;AC000;
invoke parse_check_eol ;AC000; call parser
jz OkVolArg ;AC000; yes, end of road
;
; The line was not interpretable. Report an error.
;
badvolarg:
jmp Cerror
;*** DisAppend - disable APPEND
;
; ENTRY nothing
;
; EXIT nothing
;
; USED AX,BX
;
; EFFECTS
;
; APPEND is disabled. If it was active, it will be re-enabled
; after the command finishes, by the HeadFix routine.
;
; NOTE
;
; This routine must not be called more than once during a single
; command cycle. The second call would permanently disable APPEND.
DisAppend proc
assume ds:TRANGROUP,es:NOTHING
push ds ; save DS
push es ; save ES
push di
mov ax,APPENDINSTALL ; AX = Append Installed Check code
int 2Fh ; talk to APPEND via multiplex
or al,al
jz daRet ; APPEND not installed, return
mov ax,APPENDDOS ; AX = Get Append Version code
int 2Fh ; talk to APPEND via multiplex
cmp ax,0FFFFh
jne daRet ; it's not a local version, return
mov ax,APPENDGETSTATE ; AX = Get Function State code
int 2Fh ; talk to APPEND via multiplex
mov ds,ResSeg ; DS = resident seg addr
assume ds:RESGROUP
mov Append_State,bx ; Append_State = saved APPEND state
mov Append_Flag,-1 ; Append_Flag = true, restore state
xor bx,bx ; BX = APPEND state = off
mov AX,APPENDSETSTATE ; AX = Set Append State code
int 2Fh ; talk to APPEND via multiplex
daRet: pop di
pop es ; restore ES
pop ds ; restore DS
assume ds:TRANGROUP
ret
DisAppend endp
;
; Find the Volume ID on the disk.
;
PUBLIC OkVolArg
OKVOLARG:
assume ds:TRANGROUP,es:TRANGROUP
call DisAppend ; disable APPEND
invoke crlf2
mov al,blank ;AN051; Print out a blank
invoke print_char ;AN051; before volume message
push ds
pop es
;
; Volume IDs are only findable via extended FCBs or find_first with attributes
; of volume_id ONLY.
;
mov di,FCB-7 ; Point to extended FCB beginning
mov al,-1 ; Tag to indicate Extention
stosb
xor ax,ax ; Zero padding to volume label
stosw
stosw
stosb
mov al,attr_volume_ID ; Look for volume label
stosb
inc di ; Skip drive byte; it is already set
mov cx,11 ; fill in remainder of file
mov al,'?'
rep stosb
;
; Set up transfer address (destination of search first information)
;
mov dx,offset trangroup:dirbuf
mov ah,set_DMA
int 21h
;
; Do the search
;
mov dx,FCB-7
mov ah,Dir_Search_First
int 21h
;********************************
; Print volume ID info
push ax ;AC000; AX return from SEARCH_FIRST for VOL ID
mov al,DS:[FCB] ;AC000; get drive letter
add al,'@'
cmp al,'@'
jnz drvok
mov al,[curdrv]
add al,capital_A
drvok:
mov vol_drv,al ;AC000; get drive letter into argument
pop ax ;AC000; get return code back
or al,al ;AC000; volume label found?
jz Get_vol_name ;AC000; volume label exists - go get it
mov dx,offset trangroup:VolMes_ptr_2 ;AC000; set up no volume message
jmp short print_serial ;AC000; go print it
Get_vol_name:
mov di,offset trangroup:charbuf
mov dx,di
mov si,offset trangroup:dirbuf + 8 ;AN000; 3/3/KK
mov cx,11 ;AN000; 3/3/KK
rep movsb ;AN000; 3/3/KK
xor al,al ;AC000; store a zero to terminate the string
stosb
mov dx,offset trangroup:VolMes_ptr ;AC000; set up message
PRINT_SERIAL:
;
; Attempt to get the volume serial number from the disk. If an error
; occurs, do not print volume serial number.
;
push dx ;AN000; save message offset
mov ax,(GetSetMediaID SHL 8) ;AC036; Get the volume serial info
mov bl,DS:[FCB] ;AN000; get drive number from FCB
mov dx,offset trangroup:vol_ioctl_buf ;AN000;target buffer
int 21h ;AN000; do the call
pop dx ;AN000; get message offset back
jc printvol_end ;AN000; if error, just go print label
call std_printf ;AC000; go print volume message
mov al,blank ;AN051; Print out a blank
invoke print_char ;AN051; before volume message
mov dx,offset trangroup:VolSerMes_ptr ;AN000; get serial number message
printvol_end:
jmp std_printf ;AC000; go print and exit
;****************************************************************
;*
;* ROUTINE: Set_ext_error_msg
;*
;* FUNCTION: Sets up extended error message for printing
;*
;* INPUT: return from INT 21
;*
;* OUTPUT: extended error message set up in extended error
;* buffer.
;*
;****************************************************************
Set_ext_error_msg proc near ;AN000;
call get_ext_error_number ;AC022; get the extended error
mov msg_disp_class,ext_msg_class ;AN000; set up extended error msg class
mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
mov Extend_Buf_ptr,ax ;AN000; get message number in control block
stc ;AN000; make sure carry is set
ret ;AN000; return
Set_ext_error_msg endp ;AN000;
;****************************************************************
;*
;* ROUTINE: Get_ext_error_number
;*
;* FUNCTION: Does get extended error function call
;*
;* INPUT: return from INT 21
;*
;* OUTPUT: AX - extended error number
;*
;****************************************************************
Get_ext_error_number proc near ;AN022;
SaveReg <BX,CX,DX,SI,DI,BP,ES,DS> ;AN022; save registers
mov ah,GetExtendedError ;AN022; get extended error
xor bx,bx ;AN022; clear BX
int 21h ;AN022;
RestoreReg <DS,ES,BP,DI,SI,DX,CX,BX> ;AN022; restore registers
ret ;AN022; return
Get_ext_error_number endp ;AN022;
trancode ends
end