home *** CD-ROM | disk | FTP | other *** search
- page 58,132
- title TOUCHE -- A File Date Maintenance Utility
- name TOUCHE
-
- comment *
-
- This program will change the date/time stamp of all files on its
- command line to the current date and time.
-
- See TOUCHE.DOC for instructions on how to use this program.
-
- Copyright (c) 1986 Raymond Moon ALL RIGHTS RESERVED
-
- *
-
- ;----------------------------
- ; Define the various macros used in this program.
-
- @CLOSE macro FH ;; DOS 2.0+ Close File/Device Macro
- mov bx,FH ; Load File Handle into BX
- mov ah,3eh ; Request DOS close File Handle
- int 21h ; Call PC-DOS
- endm
-
- @ENTRY macro ;; Standard Procedure Entry Logic
- push bp ; Save BP
- mov bp,sp ; Establish stack addressability
- endm
-
- @EXIT macro RTNCODE ;; Terminate program with return code
- mov ax,4c&RTNCODE&h ; Request term with return code
- int 21h ; Call PC-DOS
- endm
-
- @GETDATE macro ;; Get Current Date Macro
- mov ah,2ah ; Request DOS get current date
- int 21h ; Call PC-DOS
- endm
-
- @GETTIME macro ;; Get Current Time Macro
- mov ah,2ch ; Request DOS get current time
- int 21h ; Call PC-DOS
- endm
-
- @OPEN macro FILESPEC,MODE ;; DOS 2.0+ Open File Macro
- lea dx,FILESPEC ; Load addr of FILESPEC in DX
- mov ax,3D0&MODE&h ; Request DOS open file with mode
- int 21h ; Call PC-DOS
- endm
-
- @WRITE macro STRING,FH ;; DOS 2.0+ Write to File Macro
- lea dx,STRING ; Load String addr in DX
- mov cx,STRING&_LEN ; Load String Length in CX
- mov bx,FH ; Load File Handle in BX
- mov ah,40h ; Request DOS write to file/device
- int 21h ; Call PC-DOS
- endm
-
- ;----------------------------
- ; Define various equates used in this program
-
- STDOUT equ 1
- STDERR equ 2
- TAB equ 9
- BLNK equ 20h
- LF equ 0ah
- CR equ 0dh
-
- ;----------------------------
- ; Define the group and segments so that all will reside in one 64K
- ; physical segment.
-
- GRP group CSEG,DTA,DSEGB,DSEGA ; All segments in same segment
- assume cs:GRP,ds:GRP,es:GRP,ss:GRP
-
- DSEGB segment byte public 'STRING'
-
- public LOGO, DOS_ERR, NOT_FOUND, TOUCHED, PROPER_USE, CANT
-
- LOGO db 'TOUCHE -- A File Date Maintenance Utility V1.00',CR,LF
- db 'Copyright 1986 - MoonWare',CR,LF,LF
- LOGO_LEN equ $ - LOGO
- DOS_ERR db CR,LF,LF,'TOUCHE: Need DOS 2.0+'
- NOT_FOUND db ' -- Not Found',CR,LF
- NOT_FOUND_LEN equ $ - NOT_FOUND
- TOUCHED db ' -- Touched',CR,LF
- TOUCHED_LEN equ $ - TOUCHED
- CANT db ' -- Cannot Touch',CR,LF
- CANT_LEN equ $ - CANT
- PROPER_USE db CR,LF,'TOUCHE: Nothing to do.',CR,LF,LF,'Use:',CR,LF,LF,TAB
- db 'touche file1.ext file2.ext . . . fileN.ext',CR,LF,LF,TAB
- db 'Drive, Path, and Wildcards allowed in file names.',CR,LF,LF
- PROPER_USE_LEN equ $ - PROPER_USE
- db '***** 30 May 1986 -- Raymond Moon *****'
- DSEGB ends
-
- DSEGA segment byte public 'DATA'
- public pDOS_ERR
- pDOS_ERR dw offset GRP:DOS_ERR
- DSEGA ends
-
- ;----------------------------
- ; Use 'Segment At' to create variable to access the information
- ; contained in the DTA after First Find/Next Find DOS Function
- ; call is used.
-
- DTA segment at 00h
- public FILENAME
-
- org 80h
-
- RESERVED_DOS db 21 dup (?)
- DTA_ATTRIB db ?
- DTA_TIME dw ?
- DTA_DATE dw ?
- DTA_SIZE_LO dw ?
- DTA_SIZE_HI dw ?
- FILENAME db 13 dup (?)
- DTA ends
-
- ;----------------------------
- ; Define structure to address argc and *argv[].
-
- STACK_PARMS struc
- dw ?,? ; Saved BP & Return Address
- ARGC dw ? ; Count of command line arguments
- ARGV dw ? ; Address to command line arguments
- STACK_PARMS ends
-
-
- CSEG segment para public 'CODE'
-
- ;-----------------------------
- ; Define all procedures as public for debugging
-
- public MAIN, TOUCH_FILES, NOTHING_TO_DO, ISDOS2, FPUTS, STRCPY, STRLEN
-
- ;-----------------------------
- ; Define Command Line arguments located in the PSP
-
- org 80h
- PARM_LEN db ?
- PARMS db 127 dup(?)
-
- ;-----------------------------
- ; MAIN procedure parses the Command Line
-
- org 100h ; .COM file format
- MAIN proc far
- push pDOS_ERR ; Pass addr of DOS_ERR
- call ISDOS2 ; Check to see if DOS is 2.0+
- add sp,2 ; Reset SP
- cmp PARM_LEN,0 ; Are there any Command Line arguments
- jne MN1 ; Yes, process them
- call NOTHING_TO_DO ; No, go to Nothing_to_do
- MN1: xor cx,cx ; Null CX
- push cx ; This ensures last *argv ends in NUL
- mov cl,PARM_LEN ; Get # of bytes in Command Line
- inc cl ; Increment CL to ensure round up
- and cx,0feh ; Force an even count
- mov ax,sp ; Get SP
- mov bp,sp ; Set BP to last byte of Cmd Ln
- sub ax,cx ; Subtract PARM_LEN
- mov sp,ax ; Reset SP, room on Stack
- lea si,PARMS ; Load source addr in SI
- mov di,sp ; Load destin addr in DI
- cld ; Ensure Direction Flag is up
- rep movsb ; Move Command Line onto the Stack
-
- ;-----------------------------
- ; Convert all blanks in the Command Line to Nul
-
- mov bx,bp ; BX points to last byte of Cmd Ln
- MN2: mov al,[bx] ; Get byte
- cmp al,BLNK ; Is it a blank?
- ja MN3 ; No, go set up to get another
- xor al,al ; Nul AX
- mov [bx],al ; Store Nul in [BX]
- MN3: dec bx ; BX point to next byte
- cmp bx,sp ; Are we through yet?
- jnb MN2 ; No, go one mo' 'gin
-
- ;-----------------------------
- ; Build *argv[]. argc kept in CX. DX used as IN_WORD flag
-
- xor cx,cx ; Set CX (argc) to 0
- xor dx,dx ; Set DX to NOT_INWORD
- mov bx,bp ; BX point to last byte
- mov bp,sp ; BP now points to Top of Stack
- MN4: mov al,[bx] ; Get byte
- cmp al,0 ; Is it Nul?
- jne MN5 ; No, it is a char
- cmp dx,0 ; Was the last byte not a char?
- je MN6 ; Yes, go on with the processing
- xor dx,dx ; No, it was a char. Clear INWORD.
- inc cx ; Increment argc
- inc bx ; BX points to Cmd Ln arg
- push bx ; Push addr onto stack
- dec bx ; Reset BX
- jmp short MN6 ; Go set up for another byte
- MN5: inc dx ; Set DX to INWORD
- MN6: dec bx ; BX point to next byte
- cmp bx,bp ; Are we at the 1st byte yet?
- jnb MN4 ; No, go process another
-
- ;-----------------------------
- ; Set up for and call TOUCH_FILES
-
- push cx ; Push ARGC onto stack
- call TOUCH_FILES ; Process files
- MAIN endp
-
- ;----------------------------
- ; This procedure prints the string PROPER_USE then terminates the
- ; program.
-
- NOTHING_TO_DO proc near
- @WRITE PROPER_USE,STDERR ; Tell the user how to use TOUCH
- @EXIT 01 ; Exit with return code of 1
- NOTHING_TO_DO endp
-
- ;----------------------------
- ; Process each filename one at a time.
-
- TOUCH_FILES proc near
- @ENTRY ; Std Entry Logic
- sub sp,75 ; Make room for automatic variables
-
- TF_BASE equ [bp - 75] ; Automatic variable addressing base
-
- TF_AUTO struc ; Automatic variable structure
- DATE dw ?
- TIME dw ?
- COUNT dw ?
- LENGTH dw ?
- FILE_HANDLE dw ?
- PATH_END dw ?
- FILESPEC db 63 dup (?)
- TF_AUTO ends
-
- ;----------------------------
- ; Display logo
-
- @WRITE LOGO,STDOUT
-
- ;----------------------------
- ; Get the time and date. Convert these into DOS file date/time stamp
- ; format.
-
- @GETDATE ; Get the DOS date
- xor ax,ax ; Nul AX
- sub cx,1980 ; Convert #years into DOS file format
- xchg ch,cl ; Move year into CH
- shl ch,1 ; Convert year into DOS file format
- or ah,ch ; Move it into AX
- xor bx,bx ; Nul BX
- mov bh,dh ; Month into BX
- shr bx,1
- shr bx,1
- shr bx,1 ; Convert month into DOS file format
- or ax,bx ; Move it into AX
- or al,dl ; Move seconds into AX
- mov TF_BASE.DATE,ax ; Save it
-
- ;----------------------------
- ; Get the time and convert it.
-
- @GETTIME ; Get the DOS time
- xor ax,ax ; Nul AX
- xor bx,bx ; Nul BX
- shl ch,1
- shl ch,1
- shl ch,1 ; Convert hour into DOS file format
- or ah,ch ; Move it into AX
- mov bh,cl ; Move minutes into BH
- shr bx,1
- shr bx,1
- shr bx,1 ; Convert minutes into DOS file format
- or ax,bx ; Move it into AX
- or al,dh ; Move seconds into AX
- mov TF_BASE.TIME,ax ; Save it
-
- ;----------------------------
- ; Set Count to zero.
-
- xor ax,ax ; Nul AX
- mov TF_BASE.COUNT,ax ; Set count to zero
-
- ;----------------------------
- ; Process next file in command line. Start by stripping off any drive
- ; and path and save it in filespec. Start by putting pointer to next
- ; into DI
-
- TF1: mov di,TF_BASE.COUNT ; Get next arg number
- shl di,1 ; Convert it to a word pointer
- mov di,[bp].ARGV[di] ; Load pointer to next filename in DI
-
- ;----------------------------
- ; Determine string length
-
- push di ; Pass address of string and save it
- push di
- call STRLEN ; Get string length
- add sp,2 ; Restore SP
- mov TF_BASE.LENGTH,ax ; Save length
- inc TF_BASE.LENGTH ; Ensure search goes far enough
-
- ;----------------------------
- ; Set up for reverse search
-
- std ; Set direction flag for reverse search
- pop di
- push di ; Restore address of filename
- add di,ax ; Add length
- mov TF_BASE.PATH_END,di ; Save end of string address
-
- ;----------------------------
- ; Search for last occurrance of '\'.
-
- mov cx,TF_BASE.LENGTH ; Length of search in CX
- mov al,'\' ; Load backslash in AL
- repne scasb ; Find it
- jcxz TF2 ; If not found, do not increment DI
- inc di ; DI => '\' or 1st char if not found
- TF2: mov si,di ; Save it
-
- ;----------------------------
- ; Search for last occurance of ':'
-
- mov cx,TF_BASE.LENGTH ; Length of search in CX
- mov di,TF_BASE.PATH_END ; Load addr of last char in filename
- mov al,':' ; Load colon in AL
- repne scasb ; Find it
- jcxz TF3 ; If not found, do not increment DI
- inc di ; DI => ':' or 1st char if not found
-
- ;----------------------------
- ; Compare the tow occurrances to find which occurred last. If equal,
- ; neither was found and DI => 1st char.
-
- TF3: cld ; Clear direction flag
- cmp di,si ; Is DI = backslach position?
- je TF5 ; Yes, neither found, continue.
- ja TF4 ; Is ':' > '\'?,
- mov di,si ; No, load '\' position into DI
-
- ;----------------------------
- ; Copy drive/path into FILESPEC. Then set PATH_END to path's end in
- ; FILESPEC.
-
- TF4: inc di ; DI => 1st char
- mov cx,di ; Move end of path in CX
- pop di
- push di ; Restore DI to address of filespec
- sub cx,di ; CX = length of drive/path info
- mov si,di ; Move address of filename into SI
- lea di,TF_BASE.FILESPEC ; Move address of FILESPEC into DI
- mov ax,cx ; Mov length of drive/path into into AX
- add ax,di ; Calculate new PATH_END
- mov TF_BASE.PATH_END,ax ; Save it
- rep movsb ; Move drive/path into filespec
- jmp short TF6 ; Jump to First Find code
-
- ;----------------------------
- ; Since ':' position = '\' position, neither was found. Set PATH_END
- ; to 1st char in FILESPEC
-
- TF5: lea di,TF_BASE.FILESPEC ; Get addr of FILESPEC
- mov TF_BASE.PATH_END,di ; Save it
- jmp short TF6 ; Skip drive/path processing code
-
- ;----------------------------
- ; Now FILESPEC contains any drive and path name. PATH_END points to
- ; first open position to load file names return from FIRST FIND/
- ; NEXT FIND DOS functions. Start performing searches.
-
- TF6: pop dx ; Load filename addr in DX
- push dx ; Save it again
- mov cl,03h ; Find all Normal, Read-Only, Hidden
- mov ah,4eh ; Request DOS start search
- int 21h ; Call PC-DOS
- jnc TF7 ; Something found, process it
-
- ;----------------------------
- ; If the program fell through here, no matching files found. Tell the
- ; user. Address of filename is still on the stack.
-
- mov ax,STDERR ; load STDERR file handle in AX
- push ax ; Pass it
- call FPUTS ; Display filename
- add sp,4 ; Reset stack
- @WRITE NOT_FOUND,STDERR ; Display what happened
- jmp TF12 ; Jump to End of Loop test logic
-
- ;----------------------------
- ; File found. Set up filespec for file opening DOS Call.
-
- TF7: add sp,2 ; Remove filename addr
- TF8: lea ax,FILENAME ; Load filename in AX
- push ax ; Pass it
- push TF_BASE.PATH_END ; Pass destination addr
- call STRCPY ; Copy it
- add sp,4 ; Restore stack
-
- ;----------------------------
- ; Now open file.
-
- @OPEN TF_BASE.FILESPEC,0 ; Open file for read-only
- jnc TF9 ; Opened successfully, continue
-
- ;----------------------------
- ; Tell user that file can't be touched.
-
- lea dx,TF_BASE.FILESPEC ; Load address of filespec in DX
- push dx ; Pass it
- mov ax, STDERR ; Load STDERR file handle in AX
- push ax ; Pass it
- call FPUTS ; Display filespec name
- add sp,4 ; Restore stack
- @WRITE CANT,STDERR ; Tell user what happened
- jmp short TF11 ; Go process another
-
- ;----------------------------
- ; Touch file.
-
- TF9: mov TF_BASE.FILE_HANDLE,ax ; Save file handle
- mov bx,ax ; Move file handle into BX
- mov cx,TF_BASE.TIME ; Load time stamp into CX
- mov dx,TF_BASE.DATE ; Load date stamp into DX
- mov ax,5701h ; Request DOS set file date/time stamp
- int 21h ; Call PC-DOS
- jnc TF10 ; successful, tell user
-
- ;----------------------------
- ; Tell user that file can't be touched.
-
- lea dx,TF_BASE.FILESPEC ; Load address of filespec in DX
- push dx ; Pass it
- mov ax, STDERR ; Load STDERR file handle in AX
- push ax ; Pass it
- call FPUTS ; Display filespec name
- add sp,4 ; Restore stack
- @WRITE CANT,STDERR ; Tell user what happened
- @CLOSE TF_BASE.FILE_HANDLE ; Close file
- jmp short TF11 ; Go process another
-
- ;----------------------------
- ; Tell user that file successfully touched.
-
- TF10: lea dx,TF_BASE.FILESPEC ; Load address of filespec in DX
- push dx ; Pass it
- mov ax, STDOUT ; Load STDOUT file handle in AX
- push ax ; Pass it
- call FPUTS ; Display filespec name
- add sp,4 ; Restore stack
- @WRITE TOUCHED,STDOUT ; Tell user what happened
- @CLOSE TF_BASE.FILE_HANDLE ; Close file
-
- ;----------------------------
- ; Try to find another file with same filespec
-
- TF11: mov ah,4fh ; Continue search
- int 21h ; Call PC-DOS
- jc TF12 ; No find, go see if any more
- jmp TF8 ; Process this find
-
- ;---------------------------
- ; When the programs falls through here, no further files were found,
- ; or no matching files were found on first search. Increment count
- ; and see if there are any other filenames left on the command line.
-
- TF12: inc TF_BASE.COUNT ; Increment count
- mov ax,TF_BASE.COUNT ; Get count of file processed
- cmp ax,[bp].ARGC ; Are there any more?
- jae TF13 ; Done
- jmp TF1 ; Not done, go process another
-
- ;----------------------------
- ; Done. Terminate program with a return code of zero.
-
- TF13: @EXIT 00 ; Terminate
-
- TOUCH_FILES endp
-
- ;-----------------------------
- ; Print ASCIIZ string to the passed file handle
-
- FPUTS_PARMS struc ; Passed parameters structure
- dw ?,? ; Saved BP, and return addr (IP)
- FILE_HAN dw ? ; File handle to be used
- OUTPUT dw ? ; Addr of ASCIIZ string
- FPUTS_PARMS ends
-
- FPUTS proc near
- @ENTRY ; Std entry logic
-
- ;-----------------------------
- ; Determine ASCIIZ string length
-
- mov dx,[bp].OUTPUT ; Load STRING addr in DX
- mov di,dx ; Load STRING addr in DI
- cld ; Set direction flag foward
- mov cx,-1 ; Set CX to -1
- xor al,al ; Nul AX
- repne scasb ; Find Terminating Nul
- not cx ; Convert CX to STRLEN
- dec cx ; Remove NUL from STRLEN
- push cx ; Save STRING length
-
- ;-----------------------------
- ; Set up for DOS Write to a file or device (Function 40h)
-
- mov bx,[bp].FILE_HAN ; Load file handle
- mov ah,40h ; Request DOS Device write
- int 21h ; Call PC-DOS
-
- ;-----------------------------
- ; Conduct error checking by (1) checking Carry Flag and (2) comparing
- ; number of characters sent with number of characters desired sent.
-
- jc FPTS1 ; Error return for PC-DOS?
- pop cx ; Recover STRING length
- cmp cx,ax ; Were all chars sent?
- je FPTS2 ; Yes, return normally
-
- ;-----------------------------
- ; Set up for return
-
- FPTS1: stc ; Error detected. Set CF
- jmp short FPTS3 ; Jump to return
- FPTS2: clc ; Normal return, ensure CF clear
- FPTS3: pop bp ; Modified return logic
- ret ; Return
- FPUTS endp
-
- ;-------------------
- ; Check to see if DOS is 2.0+. If not, display passed error message
- ; and terminate program.
-
- ISDOS2 proc near
-
- ;-------------------
- ; Request DOS version
-
- mov ah,30h ; Request DOS version
- int 21h ; Call PC-DOS
- cmp al,2 ; Is it DOS 2.0+
-
- ;-------------------
- ; If it is not, just to ERROR. If it is, return correcting stack
- ; for pushed Error Message address
-
- jb ID1 ; No, go print error msg/terminate
- ret ; Yes, return to calling procedure
-
- ;-------------------
- ; Print Error Message
-
- ID1: mov ah,9 ; Request DOS print to screen
- mov bp,sp ; Move stack ptr to BP
- mov dx,[bp + 2] ; Load Error Msg addr in DX
- int 21h ; Call PC-DOS
-
- ;-------------------
- ; Terminate Program
-
- int 20h ; Terminate program
-
- ;-------------------
- ; Put on ending amenities needed by MASM
-
- ISDOS2 endp
-
- ;----------------------------
- ; Copy one string into another.
-
- STRCPY_PARMS struc ;Passed argument structure
- dw ?,? ; Saved BP, and return addr IP
- DEST dw ? ; Addr of destination string
- SOURCE dw ? ; Addr of source string
- STRCPY_PARMS ends
-
- STRCPY proc near
- @ENTRY ; Std entry logic
-
- ;----------------------------
- ; Set up SI and DI registers with the addresses of the source and
- ; destination strings
-
- mov di,[bp].DEST ; Store dest string addr in DI
- mov si,[bp].SOURCE ; Store source string addr in SI
-
- ;----------------------------
- ; Copy the string
-
- STRP1: lodsb ; Get the next byte
- stosb ; Store it in destination string
- cmp al,0 ; Was it EOS?
- jne STRP1 ; No, continue transfer
-
- ;----------------------------
- ; Set up for return with addr of dest string in AX
-
- mov ax,[bp].DEST
- pop bp ; Restore BP
- ret ; Return
- STRCPY endp
-
- ;----------------------------
- ; Determine the length of the passed ASCIIZ string.
-
- STRLEN_PARMS struc ; STRUCTURE for passed arguments
- dw ? ; BP (saved by std entry logic)
- dw ? ; IP (return offset)
- ADDRESS dw ? ; Passed offset to string
- STRLEN_PARMS ends
-
- STRLEN proc near
- push bp ; Standard entry logic
- mov bp,sp
-
- ;----------------------------
- ; Load offset to string into DI and SI
-
- mov di,[bp].ADDRESS ; Load offset into DI
- mov si,di ; Dup offset in SI
-
- ;----------------------------
- ; Find EOS (Null byte).
-
- cld ; Clear direction flag
- mov cx,-1 ; Load -1 into CX so not to limit scabs
- xor al,al ; AL = EOS
- repne scasb ; Find EOS
- dec di ; DI => EOS
-
- ;----------------------------
- ; Calculate length in AX and leave for return.
-
- mov ax,di ; AX = EOS
- sub ax,si ; Subtract where string starts.
-
- ;----------------------------
- ; Set up for return.
-
- mov sp,bp ; Standard departure logic
- pop bp
- ret
-
- STRLEN endp
- CSEG ends
- end MAIN
-