home *** CD-ROM | disk | FTP | other *** search
- TITLE TOUCH
- Page 60,132
- ;--------------------------------------------------------------------
- ; TOUCH - Set the time/date entry for a file.
- ; PC Magazine - Michael J. Mefford
- ;--------------------------------------------------------------------
- _TEXT SEGMENT PUBLIC 'CODE' ;********************************;
- ASSUME CS:_TEXT,DS:_TEXT ;* *;
- ;* Requires MASM 2.0 or later *;
- ORG 80H + 22 ;* Remember to EXE2BIN *;
- FILE_TIME DW ? ;* *;
- FILE_DATE DW ? ;********************************;
- FILE_SIZE_LOW DW ?
- FILE_SIZE_HIGH DW ?
- FILE_NAME DB ?
-
- ORG 100H
- START: JMP MAIN
-
- CR EQU 13
- LF EQU 10
- CTRL_Z EQU 26
- SPACE EQU 32
-
- ; DATA AREA
- ; ---------
- DB CR,SPACE,SPACE,SPACE,CR,LF
- COPYRIGHT DB "TOUCH 1.0 (c) 1988 Ziff Communications Co.",CR,LF
- PROGRAMMER DB "PC Magazine ",254," Michael J. Mefford",CR,LF,"$"
-
- SYNTAX DB CR,LF
- DB CR,LF,"Syntax: TOUCH filespec [/D date] [/T time]"
- DB CR,LF,"date = month-day-year"
- DB CR,LF,"time = hour[:minutes[:seconds]]"
- DB CR,LF,"Default is system date and time."
- CR_LF DB CR,LF,"$"
- DB CTRL_Z
-
-
- DATE_FLAG EQU 1
- TIME_FLAG EQU 2
-
- CURRENT_DISK DB ?
- PATH_END DW ?
-
- SWITCH_FLAG DB 0
- SWITCH_DATE DW 0
- SWITCH_TIME DW 0
- SYSTEM_DATE DW ?
- SYSTEM_TIME DW ?
- TOUCH_DATE DW ?
- TOUCH_TIME DW ?
-
- SYNTAX_MSG DB "Invalid parameter$"
- NOT_FOUND_MSG DB "File not found$"
-
-
- DELIMITERS DB ":-/"
-
-
- ; CODE AREA
- ; ---------
-
- ;------------------------------------------------------------------------;
- ; First task is to save the current drive and directory defaults. ;
- ; We will be changing the defaults and wish to restore them on exit. ;
- ; The system date and time is retrieved, compressed, and stored to stamp ;
- ; the file if no switch request found. Carriage return linefeed combo ;
- ; sent to display to put air between DOS prompt and TOUCH's messages. ;
- ;------------------------------------------------------------------------;
-
- MAIN PROC NEAR
-
- CLD ;String moves forward.
-
- MOV AH,9
- MOV DX,OFFSET COPYRIGHT
- INT 21H
-
- MOV AH,19H ;Get current drive
- INT 21H
- MOV CURRENT_DISK,AL ; and save.
- MOV BYTE PTR CURRENT_DIR,"\" ;DOS doesn't preface directory
- MOV SI,OFFSET CURRENT_DIR + 1 ; with slash so we must.
- XOR DL,DL
- MOV AH,47H ;Get current directory.
- INT 21H
-
- MOV AH,2AH ;Get current date
- INT 21H
- CALL CONVERT_DATE ; compress
- MOV SYSTEM_DATE,DX ; and store.
- MOV AH,2CH ;Get current time and do same.
- INT 21H
- CALL CONVERT_TIME
- MOV SYSTEM_TIME,DX
-
- MOV DX,OFFSET CR_LF ;Send carriage return linefeed
- MOV AH,9 ; to display just to make our
- INT 21H ; output pretty.
-
- ;-----------------------------------------------------------------------;
- ; Parse the command line for date or time switches. If found, compress ;
- ; decimal number to hex format required by DOS to set date and time. ;
- ;-----------------------------------------------------------------------;
-
- MOV SI,81H ;Point to command line parameter.
- FIND_SWITCH: LODSB ;Get a byte.
- CMP AL,CR ;Carriage return marks end.
- JZ FILESPEC ;If end, done here.
- CMP AL,"/" ;Is it a switch character?
- JNZ FIND_SWITCH ;If no, next byte.
- LODSB ;Else, retrieve switch.
- CMP AL,CR ;Did user omit character?
- JZ FILESPEC ;If yes, done here.
- AND AL,5FH ;Else, capitalize.
- CMP AL,"D" ;Is it date switch?
- JNZ CK_TIME ;If no, check if time.
- OR SWITCH_FLAG,DATE_FLAG ;Else, flag that date included.
- CALL PARSE_LEADING ;Parse off leading delimiters.
- CALL GET_NUMBER ;Get first number.
- JZ BAD_PARAMETER ;Was it a zero or no number?
- MOV DH,BL ;If yes, exit, else store month.
- CALL GET_NUMBER ;Get next number.
- JZ BAD_PARAMETER ;Was it zero?
- MOV DL,BL ;If yes, exit, else store day.
- CALL GET_NUMBER ;Get last number.
- JZ BAD_PARAMETER ;Was it zero?
- MOV CX,BX ;If yes, exit, else store year.
- CALL CONVERT_DATE ;Convert decimal to compressed
- MOV SWITCH_DATE,DX ; hex number and store.
- JMP SHORT FIND_SWITCH ;Check for another switch.
-
- CK_TIME: CMP AL,"T" ;Is there a time switch?
- JNZ FIND_SWITCH ;If no, check next byte.
- OR SWITCH_FLAG,TIME_FLAG ;Else, flag that time included.
- CALL PARSE_LEADING ;Handle same as date.
- CALL GET_NUMBER
- MOV DH,BL ;Store hour in DH.
- CALL GET_NUMBER
- MOV DL,BL ;Store minutes in DL.
- CALL GET_NUMBER
- MOV CX,DX ;Store hour and minutes in CX.
- MOV DH,BL ;Store seconds in DH.
- CALL CONVERT_TIME ;Convert
- MOV SWITCH_TIME,DX ; and store.
-
- JMP SHORT FIND_SWITCH ;Check for next switch.
-
- ;-----------------------------------------;
- ; Lily pad for short jumps to error exit. ;
- ;-----------------------------------------;
-
- BAD_PARAMETER: JMP SYNTAX_EXIT ;Error jumping address.
-
- ;------------------------------------------------------------------;
- ; Parse drive and/or path delimiters. Convert filespec to ASCIIZ. ;
- ; If drive delimiter found (:), change to requested drive. ;
- ;------------------------------------------------------------------;
-
- FILESPEC: MOV SI,81H ;Point to command line parameter.
- CALL PARSE_LEADING ;Parse off leading delimiters.
- PUSH SI ;Save start of filename.
- XOR BX,BX ;Use BX as path specifier flag.
- FIND_END: LODSB ;Get a byte.
- CMP AL,":" ;Is it a drive delimiter?
- JNZ CK_PATH ;If no, check if path delimiter.
- MOV DL,[SI-2] ;Else, retrieve drive specifier.
- AND DL,5FH ;Capitalize.
- SUB DL,"A" ;Convert to DOS format.
- MOV AH,0EH ;Change drive.
- INT 21H
- MOV BX,SI ;Save as possible filename start.
- JMP SHORT FIND_END
-
- CK_PATH: CMP AL,"\" ;Is it a path delimiter?
- JNZ CK_DELIMITER ;If no, check switch character.
- MOV BX,SI ;Else, save as possible filename.
- CK_DELIMITER: CMP AL,"/" ;Is it a switch delimiter?
- JZ FOUND_END ;If yes, end of filespec.
- CMP AL,SPACE ;Is it above space character?
- JA FIND_END ;If yes, continue until find end.
- FOUND_END: MOV BYTE PTR [SI-1],0 ;Else, convert to ASCIIZ.
-
- ;------------------------------------------------------------------;
- ; Save the working default directory so we can restore it on exit. ;
- ; If path was found, change to requested directory. ;
- ;------------------------------------------------------------------;
-
- MOV BYTE PTR WORKING_DIR,"\" ;DOS doesn't preface directory
- MOV SI,OFFSET WORKING_DIR + 1 ; with slash so we must.
- XOR DL,DL
- MOV AH,47H ;Get current directory
- INT 21H ; of working drive.
-
- POP DX ;Retrieve filespec start.
- OR BX,BX ;Was there a path specifier?
- JZ FIND_FILE ;If no, done here.
- CMP BYTE PTR [BX-1],":" ;Was it a drive specifier only?
- JZ FIND_FILE ;If yes, done here.
- PUSH BX ;Else, save as filename start.
- CMP BYTE PTR [BX-2],":" ;Was it "d:\"?
- JZ CHANGE_DIR ;If yes, no adjust.
- CMP BYTE PTR [BX-2],SPACE ;Was it plain root "\"?
- JBE CHANGE_DIR ;If yes, no adjust.
- DEC BX ;Else point to path delimiter.
- CHANGE_DIR: PUSH [BX] ;Save first byte of filename.
- MOV BYTE PTR [BX],0 ;Temporary zero so ASCIIZ path.
- MOV AH,3BH ;Change directory.
- INT 21H
- POP [BX] ;Restore first byte of filename.
- POP DX ;Retrieve filename pointer.
-
- ;------------------------------------------------------------------------;
- ; Ready for business. Find the file and get a filehandle by opening the ;
- ; file for reading. If no matching filename is found, exit with error ;
- ; message. If no switch characters were found, then update file with ;
- ; system date and time. Else, touch with requested value. If only one ;
- ; switch request was made, don't change the other. Display results. ;
- ;------------------------------------------------------------------------;
-
- FIND_FILE: MOV CX,7 ;Attribute of all files.
- MOV AH,4EH ;Find first matching file.
- INT 21H
- JNC TOUCH_FILE ;If found, change date/time.
- MOV DX,OFFSET NOT_FOUND_MSG ;Else, display error message
- JMP SHORT MESSAGE_EXIT ; and exit.
-
- FIND_NEXT: MOV AH,4FH ;Find next matching file.
- INT 21H
- JC GOOD_EXIT ;If failed, we're done.
- TOUCH_FILE: MOV DX,OFFSET FILE_NAME ;Else, open file for reading
- MOV AX,3D00H ; to get a filehandle.
- INT 21H
- MOV BX,AX ;Filehandle needs to be in BX.
-
- MOV CX,SYSTEM_TIME ;Assume request to update
- MOV DX,SYSTEM_DATE ; to system date and time.
- MOV AL,SWITCH_FLAG ;Retrieve the switch flag.
- CMP AL,0 ;Was there a switch?
- JZ SET_DATE_TIME ;If no, assumed right.
- MOV CX,SWITCH_TIME ;Else, assume it a time request.
- TEST AL,TIME_FLAG ;Was there a time switch?
- JNZ DO_DATE ;If yes, assumed right.
- MOV CX,FILE_TIME ;Else, use file's time.
-
- DO_DATE: MOV DX,SWITCH_DATE ;Assume there was a date request.
- TEST AL,DATE_FLAG ;Was there a date switch?
- JNZ SET_DATE_TIME ;If yes, assumed right.
- MOV DX,FILE_DATE ;Else, use file's date.
-
- SET_DATE_TIME: MOV TOUCH_TIME,CX ;Save date and time for
- MOV TOUCH_DATE,DX ; display purposes.
- MOV AX,5701H ;Set file's date and time.
- INT 21H
- JC SYNTAX_EXIT ;If failed, exit with message.
-
- CLOSE_FILE: MOV AH,3EH ;Close the file.
- INT 21H
- CALL DISPLAY_NAME ;Display complete stats of file.
- JMP SHORT FIND_NEXT ;Find next file.
-
- ;--------------------------------------------------------------------;
- ; Display error message and TOUCH syntax if necessary. Restore ;
- ; working directory and default drive and directory. Exit with ;
- ; error code of one if problem; error code of zero if all went well. ;
- ;--------------------------------------------------------------------;
-
- SYNTAX_EXIT: MOV DX,OFFSET SYNTAX_MSG ;Display "Invalid parameters".
- MESSAGE_EXIT: MOV AH,9
- INT 21H
- MOV DX,OFFSET SYNTAX ;Display TOUCH syntax message.
- MOV AH,9
- INT 21H
- MOV AL,1 ;Exit with error code of 1.
- JMP SHORT EXIT
-
- GOOD_EXIT: XOR AL,AL ;Exit with error code of 0.
- EXIT: PUSH AX ;Save error code.
- MOV DX,OFFSET WORKING_DIR ;Restore working directory.
- MOV AH,3BH
- INT 21H
- MOV DL,CURRENT_DISK ;Restore default drive.
- MOV AH,0EH
- INT 21H
- MOV DX,OFFSET CURRENT_DIR ;Restore default drive directory.
- MOV AH,3BH
- INT 21H
- POP AX ;Retrieve error code.
- MOV AH,4CH
- INT 21H ;Terminate.
-
- MAIN ENDP
-
- ;***************;
- ;* SUBROUTINES *;
- ;***************;
-
- ;---------------------------------------------------;
- ; INPUT ;
- ; CX = Year (1980 - 2099) ;
- ; DH = Month (1 - 12) ;
- ; DL = Day (1 - 31) ;
- ; ;
- ; OUTPUT ;
- ; DX = compressed date in directory entry format. ;
- ; ;
- ; < DH > < DL > ;
- ; y y y y y y y m m m m d d d d d ;
- ; ;
- ; y = year (0 - 119) ;
- ; m = month (1 - 12) ;
- ; d = day (1 - 31) ;
- ; ;
- ; BX, CX destroyed. ;
- ;---------------------------------------------------;
-
- CONVERT_DATE PROC NEAR
-
- SUB CX,80 ;Compress year.
- CMP CX,1900 ;Did user abbreviate year?
- JB SAVE_MONTH ;If yes, OK.
- SUB CX,1900 ;Else, subtract century part.
- SAVE_MONTH: MOV BL,DH ;Store month in BL.
- XOR BH,BH ;Zero in high half.
- SHL CL,1 ;Right justify year.
- MOV DH,CL ;Store in DH.
- MOV CL,5 ;Shift month left 5 bits.
- SHL BX,CL
- OR DX,BX ;Add year and month to days.
- RET
-
- CONVERT_DATE ENDP
-
- ;---------------------------------------------------;
- ; INPUT ;
- ; CH = Hour (0 - 23) ;
- ; CL = Minutes (0 - 59) ;
- ; DH = Seconds (0 - 59) ;
- ; ;
- ; OUTPUT ;
- ; DX = compressed time in directory entry format. ;
- ; ;
- ; < DH > < DL > ;
- ; h h h h h m m m m m m x x x x x ;
- ; ;
- ; h = hour (0 - 23) ;
- ; m = minutes (0 - 59) ;
- ; x = two-second increments (0 - 28) ;
- ; ;
- ; BX, CX destroyed. ;
- ;---------------------------------------------------;
-
- CONVERT_TIME PROC NEAR
-
- MOV BX,CX ;Store hour and min. in BX so we
- MOV CL,9 ; can use CL as shift register.
- SHR DX,CL ;Right justify; divide secs by 2.
- MOV CL,3 ;Justify left hour.
- SHL BH,CL
- MOV DH,BH ;Store hour in DH.
- MOV CL,5
- SHL BX,CL ;Justify minutes.
- OR DX,BX ;Add minutes to hour and seconds.
- RET
-
- CONVERT_TIME ENDP
-
- ;----------------------------------------;
- ; INPUT ;
- ; DS:SI points to ASCII number string. ;
- ; ;
- ; OUTPUT ;
- ; BX = hexidecimal number. ;
- ; DS:SI points to byte after string. ;
- ; If (ZF) = 1 -- BX = 0 ;
- ; If (ZF) = 0 -- BX <> 0 ;
- ; ;
- ; AX, BX, CX, DI destroyed. ;
- ;----------------------------------------;
-
- GET_NUMBER PROC NEAR
-
- XOR BX,BX ;Start with zero.
- PARSE_DELIMIT: LODSB ;Get a byte.
- MOV DI,OFFSET DELIMITERS ;Is it a delimiter?
- MOV CX,3
- REPNZ SCASB
- JZ PARSE_DELIMIT ;If yes, get next byte.
-
- MOV CL,10
- NEXT_NUMBER: XOR AH,AH ;Zero in high half.
- CMP AL,CR ;Is byte a carriage return?
- JZ NUMBER_END ;If yes, done.
- CMP AL,"0" ;Is byte a number?
- JB NUMBER_END
- CMP AL,"9"
- JA NUMBER_END ;If no, done.
- SUB AL,"0" ;Else, convert to hex.
- XCHG AX,BX ;Store in BX.
- MUL CL ;Multiply accumulated by 10.
- ADD BX,AX ;Add new number.
- LODSB ;Next byte.
- JMP SHORT NEXT_NUMBER
-
- NUMBER_END: DEC SI ;Adjust pointer to delimiter.
- OR BX,BX ;Set zero flag if results zero.
- RET
-
- GET_NUMBER ENDP
-
- ;--------------------------------------------------------;
- ; Parses off leading string delimiters. ;
- ; If carriage return encountered, jump directly to exit. ;
- ; ;
- ; INPUT ;
- ; DS:SI points to ASCII string. ;
- ; ;
- ; OUTPUT ;
- ; DS:SI points to first non-delimiting byte in string. ;
- ; ;
- ; All registers preserved. ;
- ;--------------------------------------------------------;
-
- PARSE_LEADING PROC NEAR
-
- LODSB ;Get a byte.
- CMP AL,SPACE ;Is it a space char or below?
- JA LEADING_END ;If no, done here.
- CMP AL,CR ;Is it carriage return?
- JNZ PARSE_LEADING ;If no, get next byte.
- JMP SYNTAX_EXIT ;Else, immediate error exit.
- LEADING_END: DEC SI ;Adjust pointer to string start.
- RET
-
- PARSE_LEADING ENDP
-
- ;------------------------------------------;
- ; Stores a filename in DOS DIR format. ;
- ; That is, filename, bytes, date and time. ;
- ; Results are printed to display. ;
- ; ;
- ; USES ;
- ; FILE_NAME TOUCH_DATE ;
- ; FILE_SIZE_LOW TOUCH_TIME ;
- ; FILE_SIZE_HIGH CR_LF ;
- ; ;
- ; CALLS ;
- ; STORE_WORD ;
- ; ;
- ; OUTPUT ;
- ; RESULTS = filename DIR style format. ;
- ; ;
- ; AX, BX, CX, DX, SI, DI destroyed. ;
- ;------------------------------------------;
-
- DISPLAY_NAME PROC NEAR
-
- MOV SI,OFFSET FILE_NAME ;Point to filename.
- MOV DI,OFFSET RESULTS ;And storage area.
- MOV AL,SPACE ;Initiate storage with spaces.
- MOV CX,40
- REP STOSB
- MOV DI,OFFSET RESULTS ;Point to start of storage again.
- MOV CX,12 ;Store 12 bytes of filename.
- NEXT_STORE: LODSB ;Get a byte.
- CMP AL,0 ;End of filename?
- JZ END_STORE ;If yes, finish with blanks.
- CMP AL,"." ;Is it the period?
- JNZ STORE_BYTE ;If no, store.
- SUB CX,3 ;Else store 3 spaces.
- MOV AL,SPACE
- REP STOSB
- ADD CX,3
- JMP SHORT NEXT_STORE ;Get next byte.
-
- STORE_BYTE: STOSB ;Store byte.
- LOOP NEXT_STORE ;Get next byte.
- END_STORE: MOV AL,SPACE ;Pad balance with spaces.
- REP STOSB
-
- PUSH DI ;Save pointer.
- ADD DI,8 ;Move to end of bytes field.
- MOV DX,FILE_SIZE_LOW ;Retrieve high and low words
- MOV AX,FILE_SIZE_HIGH ; of bytes.
- MOV BX,10 ;Convert to decimal.
- STD ;Reverse direction.
-
- NEXT_SIZE: MOV CX,DX ;Low word in CX.
- XOR DX,DX ;Zero in high half.
- DIV BX ;Convert to decimal.
- XCHG AX,CX ;Retrieve low word.
- DIV BX
- XCHG AX,DX ;Retrieve remainder.
- ADD AL,"0" ;Convert to ASCII.
- STOSB ;Store it.
- MOV AX,CX ;Are we done?
- OR CX,DX
- JNZ NEXT_SIZE ;If no, divide again.
-
- CLD ;Back to forward direction.
- POP DI ;Retrieve pointer.
- ADD DI,11 ;Move to date field.
- DATE: MOV DX,TOUCH_DATE ;Retrieve date.
- MOV AX,DX
- MOV CL,5 ;Shift to lowest bits.
- SHR AX,CL
- AND AX,1111B ;Mask off all but month.
- MOV CL,0FFH ;Flag as no leading zeros.
- MOV CH,"-" ;Delimiting character.
- CALL STORE_WORD ;Store it.
-
- MOV AX,DX ;Retrieve date.
- AND AX,11111B ;Mask off all but day.
- XOR CL,CL ;Flag include leading zeros.
- MOV CH,"-"
- CALL STORE_WORD ;Store it.
-
- MOV AX,DX ;Retrieve date for last time.
- MOV CL,9
- SHR AX,CL ;Mask off all but year.
- ADD AX,80 ;Adjust to ASCII.
- CMP AX,100 ;Past year 2000?
- JB DISPLAY_DATE ;If no, display. Else, adjust for
- SUB AX,100 ; next century. (Planning ahead!)
- DISPLAY_DATE: XOR CL,CL ;Display leading zeros.
- MOV CH,SPACE
- CALL STORE_WORD ;Store it.
-
- TIME: INC DI ;Move to time field.
- MOV DX,TOUCH_TIME ;Retrieve time.
- MOV AX,DX
- MOV CL,11 ;Shift to hours bits.
- SHR AX,CL
- PUSH AX
- CMP AX,12 ;Past noon?
- JBE MERIDIAN
- SUB AX,12 ;If yes, adjust.
- MERIDIAN: CMP AX,0 ;Midnight?
- JNZ NOT_MIDNIGHT
- MOV AX,12 ;If yes, adjust.
- NOT_MIDNIGHT: MOV CL,0FFH ;Suppress leading zeros.
- MOV CH,":"
- CALL STORE_WORD ;Store it.
-
- MOV AX,DX ;Retrieve time.
- MOV CL,5 ;Shift to minutes bits.
- SHR AX,CL
- AND AX,111111B ;Mask off all but minutes.
- XOR CL,CL
- POP DX ;Retrieve hours.
- MOV CH,"p" ;Assume PM.
- CMP DX,12 ;Is it PM?
- JAE PM
- MOV CH,"a" ;If no, AM.
-
- PM: CALL STORE_WORD ;Store it.
- MOV SI,OFFSET CR_LF ;Tack on carriage return
- MOVSW ; linefeed.
- MOVSB
- MOV DX,OFFSET RESULTS ;Display results.
- MOV AH,9
- INT 21H
- RET ;Done here.
-
- DISPLAY_NAME ENDP
-
- ;----------------------------------------------;
- ; Converts a two byte hex number to decimal ;
- ; and stores the word followed by a delimiter. ;
- ; ;
- ; INPUT ;
- ; AX = hex number ;
- ; BL = 10 ;
- ; CH = delimiter character to store. ;
- ; CL = 0 if zeros are to be stored. ;
- ; CL = -1 if leading zeros ignored. ;
- ; ES:DI points to storage. ;
- ; ;
- ; OUTPUT ;
- ; ES:DI points to next storage location. ;
- ; ;
- ; AX destroyed. ;
- ;----------------------------------------------;
-
- STORE_WORD PROC NEAR
-
- DIV BL ;Divide by ten.
- ADD AX,"00" ;Convert to ASCII.
- CMP CL,0 ;Are we to display leading zero?
- JZ STORE_IT ;If yes, store as is.
- CMP AL,"0" ;Is it a leading zero?
- JNZ STORE_IT ;If no, store it.
- MOV AL,SPACE ;Else, store a space.
- STORE_IT: STOSW
- MOV AL,CH ;Store delimiter character also.
- STOSB
- RET
-
- STORE_WORD ENDP
-
- ;--------------------------------------------------------------------------;
- ; String storage at end of code to avoid all those zeros in Basic listing. ;
- ;--------------------------------------------------------------------------;
-
- CURRENT_DIR LABEL BYTE
- WORKING_DIR EQU CURRENT_DIR + 68
- RESULTS EQU WORKING_DIR + 68
-
- _TEXT ENDS
- END START
-