home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sampler0
/
touche.asm
< prev
next >
Wrap
Assembly Source File
|
1986-06-01
|
19KB
|
653 lines
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