Metropoli BBS
VIEWER: ucd.asm MODE: TEXT (CP437)
;  UCD.COM
;
;  Uwe H. Steinfeld, 12/07/89
;
;  Syntax:     UCD [drive:][directory]
;
;  Features:   - fully replaces and enhances DOS' CD
;	       - is able to change drive and directory simultaneously
;	       - does not need a complete path to the target directory,
;		 searches recursively through the directory tree
;
;  Limitation: - if two directories with the	  D:\
;		 same name in the tree exist	   │
;		 only the first will be found.	   ├─ STATS
;		 You have to give the name of	   │	├─ EXCEL
;		 the parent directory to go	   │	│   └──── DATA
;		 to the desired one, e.g.,	   │	└─ STATG
;		 to go to the second data	   │	    └──── DATA
;		 directory on drive D: use
;		     UCD D:STATG\DATA
;
;  Errorlevel:	0  success
;		1  directory not found
;		2  invalid drive


include dos.inc 			 ; MASM macros for better readable code

directory	equ	10000b		 ; directory attribute

text		segment
		assume cs:text, ds:text, es:text

		org	100h

start:		jmp	ucd

Copyright:	db	'(C) Uwe H. Steinfeld, 12/07/89'
SaveDrive	db	0, ':\'
SaveDir 	db	64 dup (0),'$'
search		db	64 dup (0)
root		db	'\', 0
parent		db	'..', 0
wild		db	'*.*', 0
msg1		db	'Invalid directory', 0Dh, 0Ah, '$'
msg2		db	'Invalid drive', 0Dh, 0Ah, '$'


ucd:		@GetDrv 			 ; save current drive and path
		mov	SaveDrive,al		 ;   to go back if the search
		@GetDir SaveDir 		 ;   is unsuccessful

		mov	si,81h			 ; start of command tail
		mov	di,offset search	 ; ASCIIZ path storage
Uc_1:		lodsb
		cmp	al,' '                   ; skip leading blanks and
		jz	Uc_1			 ;   tabs in the command tail
		cmp	al,9
		jz	Uc_1
		cmp	al,0Dh			 ; end of command line ?
		jnz	Uc_2

		add	cs:SaveDrive,'A'         ; no cmd line argument, just
		@DispStr SaveDrive		 ;    display current drive
		@Exit 0 			 ;    and path and terminate

Uc_2:		mov	dl,al			 ; save first letter
		lodsb				 ; get next
		cmp	al,':'                   ; drive specified ?
		jnz	Uc_5

;  set new drive

		and	dl,0DFh 		 ; adjust to uppercase
		sub	dl,'A'                   ; drive A=0, B=1, ...
		mov	ah,0Eh			 ; set new drive
		int	21h
		@GetDrv 			 ; get drive
		cmp	al,dl			 ; successful changed ?
		jz	Uc_3
		@DispStr msg2			 ; invalid drive specified
		@Exit	2			 ; exit with errorlevel 2

Uc_3:		lodsb				 ; get next character
		call	ChkEnd			 ; only new drive given ?
		jnz	Uc_4
		@Exit 0 			 ; done

Uc_4:		mov	dl,al			 ; save first letter
		lodsb

Uc_5:		xchg	dl,al			 ; no drive given, so
		stosb				 ;   store saved characters
		xchg	al,dl
		call	ChkEnd			 ; only 1 char on cmd line ?
		jnz	Uc_7

;  target directory only 1 character long, check for '\' and '.'

		cmp	dl,'.'                   ; was it 'current' dir ?
		jnz	Uc_6
		@Exit	0			 ; then we're done

Uc_6:		cmp	dl,'\'                   ; was it root dir ?
		jnz	Uc_8
		@ChDir	root			 ; then go to root dir
		@Exit	0			 ;   and quit

;  more than 1 directory letter so check for '..'

Uc_7:		cmp	al,'.'                   ; test first character
		jnz	Uc_8
		cmp	al,dl			 ; compare to second
		jnz	Uc_8
		@ChDir	parent			 ; change to parent directory
		@Exit  0			 ; and exit

; read rest of command tail

Uc_8:		stosb
		lodsb				 ; get the rest of the cmd tail
		call	ChkEnd			 ; don't care about what comes
		jnz	Uc_8			 ;   after the first word

;  search begins

		mov	di,offset DTAInit	 ; ptr to start of DTA area
		@ChDir	root			 ; start in the root directory
		call	tree			 ;   and call the subroutine
		mov	dl,SaveDrive		 ; if we return here then the
		mov	ah,0Eh			 ;   directory was not found,
		int	21h			 ;   so restore the starting
		@ChDir SaveDir			 ;   drive/dir and stop with
		@DispStr msg1			 ;   error message
		@Exit 1

;  tree search (recursively)

tree:		call	setDTA			 ; set DTA for GetFirst/Next
		@GetFirst search,directory	 ; is 'target' subdirectory
		jc	t1			 ;   of the current dir ?
		cmp	byte ptr[di+15h],directory
		jnz	t1
		@ChDir search			 ; then change to it and
		@Exit 0 			 ;   exit with success code

t1:		@GetFirst wild,directory	 ; look for subdirectories...
t2:		jc	t4
		cmp	byte ptr[di+15h],directory
		jnz	t3
		cmp	byte ptr[di+1Eh],'.'     ; ... but not '.' or '..'
		jz	t3
		mov	dx,di			 ; change directory to
		add	dx,1Eh			 ;   the one found
		mov	ah,3Bh
		int	21h
		add	di,43			 ; increase dta ptr
		call	tree			 ;    and start over
		@ChDir	parent			 ; come back if not found
		sub	di,43			 ; set dta ptr back
		call	setDTA
t3:		@GetNext			 ; find next subdirectory
		jmp	t2
t4:		ret

setDTA: 	mov	dx,di			 ; set new disk transfer area
		mov	ah,1Ah
		int	21h
		ret

ChkEnd: 	cmp	al,' '                   ; get byte from command line
		jz	ChkRet			 ;   and check for end of
		cmp	al,9			 ;   line condition
		jc	ChkRet
		cmp	al,0Dh
ChkRet: 	ret

DTAInit:					 ; start of first DTA

text		ends
		end	start
[ RETURN TO DIRECTORY ]