[net.sources] PC-DOS/MS-DOS `touch' command

gino@voder.UUCP (Gino Bloch) (10/01/84)

[don't touch this line]

A while back someone asked how to touch(*) a file under PC-DOS.  Since I
had a need for that capability, I wrote a program to do that; here it is.

* ie, change its date & time fields to the current time without any
    other changes - useful with a `make' facility, for instance.

...................... tear on the dotted line .........................

	title	"touch files"

	page	,132

; Touch changes the date & time of directory entries to the current
; date & time.  It requires one argument (and ignores extra arguments).
; The argument is the full path name of a file.  You can also specify
; a set of files by using wild card characters in the file name portion,
; but not the path name portion, of the argument.  In the absence of path
; name specifiers, only the default directory is searched.  In the absence
; of a drive name specifier, only the default drive is searched.  Thus there
; are four ways to invoke touch; `d:\dd' means the default drive and its
; default directory, and `x:\xd' means some other drive and its default
; directory:
;	touch file.ext		affects d:\dd\file.ext
;	touch x:file.ext	affects x:\xd\file.ext
;	touch \path\file.ext	affects d:\path\file.ext
;	touch x:\path\file.ext	affects x:\path\file.ext
; In all four cases, `file.ext' can contain  `?' and `*' characters by the
; usual rules.

; Copyright (C) 1984 by Gene E. Bloch

	assume	ds:dseg,ss:sseg

sseg	segment	stack 'stack'
	db	512 dup (?)
stk	equ	$
sseg	ends

dseg	segment	'data'
no_file	  db	'touch: file not found',0dh,0ah,'$'
no_tail	  db	'syntax: touch file_descriptor (may be ambiguous)',0dh,0ah,'$'
unopen	  db	" (can't be opened)$"
crlf	  db	0dh,0ah,'$'

clk_time  dw	2 dup (?)
clk_date  dw	2 dup (?)
file_time dw	?
file_date dw	?
handle	  dw	?
file_name db	80h dup (?),'$'
name_end  equ	$
name_tail dw	file_name

dseg	ends

cseg	segment	'code'

	assume	cs:cseg

; main

touch:
	mov	ax,dseg		; set up ds
	mov	ds,ax

	call	read_clok	; set up current date & time
	call	set_date
	call	set_time


	call	find_first	; get first file name
	jnz	short err_out		; no file, analyze error

more:
	call	make_name	; make up the full path name
	call	show_name	; print the full path name
	call	open		; open the file
	jnc	short open_ok	; successful
	mov	dx,offset unopen ; unsuccessful, report it
	mov	ah,9
	int	21h
	jmp	short finder	; and skip the rest
open_ok:
	call	touch_it	; re-date & -time the file
	call	close		; close it
finder:
	mov	dx,offset crlf	; newline
	mov	ah,9
	int	21h
	call	find_next	; try to get next file
	je	short more	; got one, touch it

done:
	mov	ah,4ch		; exit
	mov	al,0
	int	21h

err_out:
	mov	dx,offset no_file ; get `no file found' message
	jg	short print_it
	mov	dx,offset no_tail ; get `no command tail' message
print_it:
	mov	ah,9		; print string
	int	21h
	jmp	done		; bye


; subroutines

read_clok:
	mov	ah,2ch		; get clock time
	int	21h
	mov	clk_time,cx
	mov	clk_time[2],dx

	mov	ah,2ah		; get clock date
	int	21h
	mov	clk_date,cx
	mov	clk_date[2],dx
	ret

set_date:
	mov	ax,clk_date	; convert date to directory fmt
	sub	ax,1980		; year first
	mov	cl,9
	shl	ax,cl
	mov	bx,clk_date[2]	; month next
	mov	cl,3
	shr	bx,cl
	or	ax,bx
	and	ax,0ffe0h
	mov	bx,clk_date[2]	; finally day
	and	bl,1fh
	or	al,bl
	mov	file_date,ax	; that's it
	ret

set_time:
	mov	ax,clk_time	; convert time to directory format
	mov	cl,3		; hours
	shl	ax,cl
	and	ax,0f800h
	mov	bh,byte ptr clk_time	; minutes
	mov	cl,3
	shr	bx,cl
	or	ax,bx
	and	ax,0ffe0h
	mov	bl,byte ptr clk_time[3] ; seconds
	shr	bl,1
	or	al,bl
	mov	file_time,ax	; done
	ret

printable:
	cmp	al,'!'		; see if legal
	jb	short p_done	; no
	cmp	al,7fh		; more legality
	ja	short p_done	; no printable
	cmp	al,al		; set flag 0 == ok
p_done: ret

to_upper:
	cmp	al,'a'		; convert to UC
	jb	short uc_end	; this isn't lc
	cmp	al,'z'
	ja	short uc_end	; nor is this
	xor	al,'a' xor 'A'	; this one was
uc_end:	ret

file_delim:
	cmp	al,':'		; could be drive designator
	je	short set_mark	; if so, make a mark
	cmp	al,'\'		; could be subdirectory
	je	short set_mark	; yeah
	cmp	al,'/'		; even this kind of subdirectory
	jne	short fd_end	; no
set_mark:
	mov	bx,di		; remember this place
	mov	es:name_tail,bx
fd_end:	ret

find_first:
	cld			; copy filename from parameter block
	mov	ch,0		; set up count
	mov	cl,es:[80h]	; get the arg length for loops below
	push	ds		; save ds
	push	es		; save es
	push	es		; point ds & si to command tail in PSP
	pop	ds
	mov	si,81h
	mov	ax,dseg		; point es & di to file_name buffer
	mov	es,ax
	mov	di,offset file_name
blank_loop:
	jcxz	short no_arg	; still trucking?
	dec	cx		; loop counter
	lodsb			; skip white space
	cmp	al,' '		; space
	je	blank_loop
	cmp	al,9		; tab
	je	blank_loop
	or	al,al		; look out for spacy args
	jz	short no_arg
	dec	si		; get last (nonblank) char back
	inc	cx		; and count it
copy_loop:
	lodsb			; get next char
	call	printable	; see if printable
	jnz	short copy_end	; not printable
	call	to_upper	; all letters to UPPERCASE
	stosb			; good character, save it
	call	file_delim	; remember the last tree delimiter
cl_end:
	loop	copy_loop	; continue
copy_end:
	xor	al,al		; add the terminating null
	stosb
	pop	es		; restore extra seg
	pop	ds		; restore data seg

	mov	dx,offset file_name ; set up find_first call
	mov	cx,0		; attribute: normal files only
	mov	ah,4eh
	int	21h
	or	ax,ax		; set condition code
	ret

no_arg:
	pop	es		; restore extra seg
	pop	ds		; restore data seg
	mov	ax,-1		; set an error flag
	or	ax,ax
	ret

make_name:
	push	es		; save the hummers
	push	ds

	mov	ah,2fh		; find the DTA
	int	21h
	push	es		; we'll need this value in just a mo'

	mov	ax,name_tail	; this is where new name will go
	mov	di,ax
	mov	ax,dseg
	mov	es,ax

	add	bx,30		; point to file name field of DTA
	mov	si,bx		; source of the copy
	pop	ds		; this was pushed right after int 21/2f

	cld
	mov	cx,13		; max size of filename
name_loop:
	lodsb			; copy name to path prefix
	stosb
	or	al,al		; quit on '\0'
	loopnz	name_loop

name_done:
	mov	al,'$'		; terminate the print command
	stosb
	pop	ds		; restore segments
	pop	es
	ret

show_name:
	mov	dx,offset file_name ; get file name string
	mov	ah,9		; print string
	int	21h
	ret

open:
	mov	dx,offset file_name ; going to open this one
	mov	al,2		; open for append
	mov	ah,3dh
	int	21h
	mov	handle,ax	; save it
	ret

touch_it:
	mov	dx,file_date	; set file's date & time
	mov	cx,file_time
	mov	bx,handle
	mov	ah,57h
	mov	al,1
	int 21h
	ret

close:
	mov	bx,handle	; close this one
	mov	ah,3eh
	int	21h
	ret

find_next:
	mov	ah,4fh		; set up find_next call
	int	21h
	or	ax,ax		; set condition code
	ret

cseg	ends

	end	touch
-- 
Gene E. Bloch (...!nsc!voder!gino)

ali@bradley.UUCP (10/08/84)

[]

 Whats wrong with:
 
     >COPY  filename+,,