home *** CD-ROM | disk | FTP | other *** search
- ; File......: _WHEREIS.ASM
- ; Author....: Steve Larsen
- ; CIS ID....: 76370,1532
- ; Date......: $Date: 15 Aug 1991 23:08:08 $
- ; Revision..: $Revision: 1.1 $
- ; Log file..: $Logfile: E:/nanfor/src/_whereis.asv $
- ;
- ; This is an original work by K. Stephan Larsen and is placed in
- ; the public domain.
- ;
- ; Modification history:
- ; ---------------------
- ;
- ; $Log: E:/nanfor/src/_whereis.asv $
- ;
- ; Rev 1.1 15 Aug 1991 23:08:08 GLENN
- ; Forest Belt proofread/edited/cleaned up doc
- ;
- ; Rev 1.0 07 Jun 1991 21:56:10 GLENN
- ; Initial revision.
- ;
- ;
-
- PUBLIC __ft_where, __ft_tree
-
- EXTRN __storc:far, __retni:far, __parinfo:far, __parclen:far
- EXTRN __parc:far, __xfree:far, __xalloc:far
-
- ;
- ; Create offsets to mvars and DTA buffering area. The segment "DATASG"
- ; is culled from the free pool, therefore goes away when these functions
- ; are not active. All mvar initialization must take place at
- ; runtime, rather than compiletime.
- ;
- DATASG SEGMENT 'DATA'
-
- filename db 13 dup(?), ? ; passed filename
- olddrive db ? ; our current drive
- eop dw ? ; pointer to end-of-path string
- count dw ? ; current element
- is_array dw ? ; parm No., if array was passed
- a_count db ? ; array length
- dirname db 4 dup(?) ; '*.*' mask for directories
- dir_nest db ? ; directory level
- dta_ptr db ? ; pointer to current dir dta
- path db ?, 20 * 14 dup(?) ; buffer for current path
- dta_buff db 20 * 43 dup(?) ; DTA for directories
- std_dta db 128 DUP(?) ; DTA for files
-
- dta_file_offset equ 1Eh ; offset to filename within DTA
- dta_attr_offset equ 15h ; offset to file type within DTA
- dta_len equ 43 ; length of DTA that we're interested in
- segsize equ $ - filename ; amount of free pool memory req'd
-
- DATASG ends
-
- ; local vars go on stack, this is necessary since we cannot access data
- ; within our data seg until it is allocated
-
- oldsegloc equ <ss:[bp-02h]> ; Clipper's DS
- newsegloc equ <ss:[bp-04h]> ; our data area's Segment
- newoffset equ <ss:[bp-06h]> ; our data area's Offset
- newsegment equ <ss:[bp-08h]> ; after adjusting to the first
- ; paragraph within our data
- ; area, this is the "Segment"
- ; value of our data seg
-
- _NANFOR segment word public 'CODE'
- ASSUME CS:_NANFOR
-
- __ft_where PROC FAR
- push ds ; save Clipper's environment
- push es
- push di
- push si
- push bp
- mov bp, sp
- sub sp, 08h ; make room on stack for locals
-
- w_1: call GetParms ; fetch parms, set up our data seg
- mov ds, newsegloc ; now point DS to our data seg
- assume ds:datasg
- mov ax, offset path ; point to the current path (starts
- inc ax
- mov eop, ax ; first EOP is 1 past "\"
- call HuntMDown ; look for files in root directory
-
- w_2: call FirstDir ; find first subdirectory
- jc w_4 ; no subdir, set DTA back 1 dir lvl
-
- w_3: call IsParent ; found dir, check for DOS signature
- jc w_5 ; nope, go to next directory
-
- call HuntMDown ; OK, now look for files in directory
-
- w_6: call UpDir ; move DTA up a level for subdirs
- jmp w_2 ; and do it all over again
-
- w_4: call DownDir ; go back one level, look for another
- w_5: call NextDir ; subdir. If CY returns set, no more
- jc w_4 ; subdirs, back up another level...
- jmp w_3 ; subdir was found, continue
-
- HuntMDown: ; requires EOP in BL, DTA set
- call FindFile ; set up to look for files
- ; DI points to EOP
- call FindFirst ; find first matching file in dir
- h_1: jc h_3 ; if not found, return to calling routine
-
- inc count ; file was found, increment count
-
- mov si, offset std_dta + dta_file_offset ; and point SI to
- ; file's name within current DTA
-
- call File2Path ; add filename to end of current path
- call Save2Array ; copy full path/filename to array
-
- h_2: call FindNext ; set up DOS to find next file/dir
- jmp h_1
-
- h_3: clc ; clear carry if set by parent dir
- retn ; endp HuntMDown
-
- FirstDir: ; locates first subdir in a level
- call FindDir ; set up DOS search parms for a dir
- call MakePath ; create the path
- mov si, offset dirname ; add the "*.*" to the path
- call File2Path
- mov cx, 10h ; directory attribute to search for
- call FindFirst ; go do it
- retn
-
- IsParent: ; checks for "." or ".."
- mov ah, 2Fh ; fetch current DTA in ES:BX
- int 21h
- mov si, bx ; point SI to DTA
- add si, dta_file_offset ; point SI to dirname within DTA
- lodsb ; fetch first char of dirname
- clc
- cmp al, '.' ; check if parent directory
- jne ip_1 ; yep, this is a legit directory
- stc ; nope, set CY to inform calling
- ip_1: retn ; routine
-
- NextDir: ; finds next subdir in current level
- call FindDir ; select directory DTA
- mov cx, 10h ; directory attribute to look for
- call FindNext ; go a'lookin
- retn
-
- FindDir: ; sets DTA to current directory DTA
- mov dx, offset dta_buff ; returns with carry set upon failure
- xor cx ,cx
- mov cl, dta_ptr ; get current dir level, test for
- cmp cx, 0 ; bottom
- je fd_1 ;
- fd_2: add dx, dta_len ; if not, increment DX to proper level
- loop fd_2
- fd_1: mov ah, 1Ah ; set DTA
- int 21h
- retn
-
- FindFile: ; sets DTA to file DTA
- mov dx, offset std_dta ; point to file DTA
- mov ah, 1Ah
- int 21h ; set it
-
- call MakePath ; construct current path
- mov si, offset filename ; add the filespec
- call File2Path
- xor cx, cx ; set attribute for normal files
- ff_1: retn
-
- UpDir:
- inc dta_ptr ; inc the nest and segment pointers
- inc dir_nest
- retn
-
- DownDir: ; clears last DTA for reuse
- mov di, offset dta_buff + dta_file_offset ; point DI to last
- xor cx, cx ; dirname searched by multiplying
- mov cl, dta_ptr ; length of DTA times No of DTA's
- cmp cx, 0
- je mm_2 ; if at root skip the multiply part
- mm_1: add di, dta_len ; do the multiplication
- loop mm_1
-
- mm_2: mov al, 0 ; poke a null to clear any data here
- stosb
-
- dec dta_ptr ; dec the dir seg pointer and
- dec dir_nest ; the nest level pointer
-
- jns mm_3
- jmp Done ; ptr < 0 when finished in the root
- mm_3: retn
-
- FindFirst: ; finds first matching file/dir
- push es ; sets carry if no match found
- push bx ; current DTA and file attrib was
- push di ; set by calling routine
- mov ah, 2Fh ; get DTA in ES:BX for func 4Eh call
- int 21h
- mov dx, offset path ; point to filespec to search for
- mov ah, 4Eh ; find first matching file
- int 21h
- jc fr_2 ; carry set, no find
- fr_1: call IsMatch ; test if we stopped at a parent dir
- jnc fr_2 ; nope, all's well so return
- mov ah, 4Fh ; otherwise, find next dir
- int 21h
- jc fr_2 ; no more dirs, we've failed
- jmp fr_1
- fr_2: pop di
- pop bx
- pop es
- retn
-
- FindNext: ; looks for next occurance of file/dir
- push es ; last found in current DTA
- push bx ; sets CY if no matching file found
- mov ah, 2Fh ; fetch DTA in ES:BX
- int 21h
- mov ah, 4Fh ; find next matching file
- int 21h
- jc fn_2 ; no find, return with CY set
- fn_1: call IsMatch ; found, test attribute
- jnc fn_2
- mov ah, 4Fh ; if no match, find next file
- int 21h
- jc fn_2 ; exit on no more files
- jmp fn_1
- fn_2: pop bx
- pop es
- retn
-
- IsMatch:clc ; sets carry if attr does not match
- cmp cl, 0 ; if attribute is zero, skip test
- je im_1
- test cl, es:[bx + dta_attr_offset] ; AND attribute with file's
- jnz im_1
- stc ; AND unsuccessful, set carry for no match
- im_1: retn
-
- MakePath: ; builds path and exits with DI
- push es ; pointing to EOP (0)
- push si
- mov di, offset path
- mov dl, dta_ptr
- mov cx, offset dta_buff + dta_file_offset ; point to first dir.
- m_1: mov al, '\'
- stosb
- m_2: mov si, cx ; point to directory name
- lodsb
- cmp al, 0 ; first character of dirname is null
- je m_4 ; if new segment
- m_3: stosb
- lodsb
- cmp al, 0 ; end of directory name?
- jne m_3
- mov al, '\' ; yes, add trailing backslash
- stosb
- cmp dl, 0 ; check for last directory segment
- je m_4
- add cl, dta_len ; point to next directory name
- dec dl ; decrement segment number
- jmp m_2 ; do it again
- m_4: mov eop, di ; save end of path marker
- mov al, 0 ; terminate path with a null
- stosb
- pop si
- pop es ; point ES:SI to filename
- retn
-
- File2Path: ; appends file/dirname to end-of-path
- mov di, eop ; requires DS:SI pointing to filename
- mov cx, 14 ; and ES:DI pointing to end-of-path
- rep movsb
- retn
-
-
- Done: ; global return to Clipper routine
- mov cx, count ; save return code for later
- mov ds, newsegloc ; restore ourselves to original drive
- mov dl, olddrive
- mov ah, 0Eh
- int 21h
-
- mov ds, oldsegloc ; point DS to Clipper's DS
- mov dx, newsegloc ; return our dataseg to free pool
- mov ax, newoffset
- push dx
- push ax
- call __xfree
-
- mov sp, bp ; skip SP back to beginning of
- ; local vars. This method is
- ; necessary because we don't know
- ; how we got here, whether via a
- ; JMP or a CALL, so the stack could
- ; contain just about anything
-
- pop bp ; restore Clipper's environment
- pop si
- pop di
- pop es
- pop ds
-
- push cx ; send error code (or # hits) to Clippie
- call __retni
- add sp, 2
- retf ; and we're outta here!
-
- ;------------------------------------------------------------
- ; GetParms - Local procedure to read in command line & set locals
- ;------------------------------------------------------------
- GetParms:
-
- mov oldsegloc, ds ; save Clipper's DS
- call MakeMem ; get some memory in free pool
- mov ds, newsegloc ; point DS and ES to our dataseg
- mov es, newsegloc
-
- mov word ptr count, 0 ; initialize variables
- mov byte ptr path, '\' ; starting path is at the root
- mov byte ptr eop, offset path + 1 ; starting end-of-path
- mov byte ptr is_array, 0 ; default is no array passed
- mov word ptr dirname[0], '.*' ; dir pattern is *.*
- mov word ptr dirname[2], 0 + '*'
- mov word ptr filename[0], '.*' ; default filespec is *.*
- mov word ptr filename[2], 0 + '*'
- mov byte ptr dir_nest, 0 ; initial nesting level is 0 (duh)
- mov byte ptr dta_ptr, 0
-
- mov cx, 10 * 43 ; fill DTA buffer areas with nulls
- xor ax, ax
- cld
- mov di, offset dta_buff
- repne stosw
-
- mov ah, 19h ; fetch current drive and save
- int 21h
- mov olddrive, al
-
- mov ds, oldsegloc ; restore Clipper's DS for PARxx funcs
-
- xor ax,ax ; fetch no. of parms passed
- push ax
- call __parinfo
- add sp,2
-
- or ax, ax ; if no parms use defaults
- jz gp_Done
-
- push ax ; save parm count
- mov ax, 1 ; test first parm type
- call gp_array ; for array
- cmp byte ptr es:is_array, 0 ; is it an array?
- ja gp_done ; yes, we're done (ignore remaining
- ; parms)
- push ax
- call __parclen ; get len of drive/filespec
- mov cx, ax ; put length in cx
- pop ax ; retrieve parm number
- cmp cx, 0 ; test for no file/drive spec passed
- je gp_next ; nothing there, get next parm
- push cx ; otherwise save length
- push ax ; then parm no.
- call __parc ; fetch parm addr in DX:AX
- add sp, 2
- pop cx ; retrieve length in CX
- mov es, newsegloc ; point ES:DI to filename
- mov di, offset filename
- push dx ; point DS:SI to passed parm
- pop ds
- push ax
- pop si
- cmp cx, 2 ; if a only a single char was passed
- jae gp_isdrive ; assume it to be a filespec
- movsb ; filespec is now ?.*
- jmp gp_next ; go after next parm
-
- gp_isdrive: ; test if passed parm contains a drivespec
- push cx ; save length
- mov al, [si+1] ; look at 2nd char for colon
- cmp al, ":"
- jne gp_strcopy ; nope, must just be a filespec
- lodsw ; yep, fetch the drive letter
- pop cx ; subtract drive + colon from length
- sub cx, 2
- push cx ; save revise length for later
- and al, 5Fh ; capitialize the drive letter
- sub al, 41h ; convert from char to numeric, A:=0
-
- mov dx, ax ; test if this is a valid drive
- mov ah, 0Eh ; by attempting to change to it
- int 21h
- cmp al, dl ; check if spec'd drive is out of range
- jae gp_strcopy
- jmp Done ; no drive there, go back to Clippie
-
- gp_strcopy:
- pop cx ; retrieve filespec len
- or cx, cx ; if len = 0,
- jz gp_next ; leave *.* as default search string
- repne movsb ; otherwise save filespec
- xor al, al
- stosb ; and add a null terminator
-
- gp_next:
- mov ds, oldsegloc ; restore Clipper's DS for PARxx funcs
- pop ax ; now check for second parm
- cmp ax, 2 ; check if 2nd parm passed
- jb gp_done ; no, we're done
- mov ax, 2 ; otherwise, check second parm
- call gp_array ; for arrayness, then we're done
- gp_Done:
- retn
-
- gp_array:
- push ax ; test parm for arrayness
- call __parinfo
- mov es, newsegloc ; restore ES after __parinfo
- mov bx, ax
- pop ax
- test bx, 512 ; is it an array?
- je gpar1 ; if yes, save array's parm No.
- mov es:is_array, ax ; is_array = 0 if no parm, else 1 or 2
- gpar1: retn
-
- MakeMem: ; creates a temp dataseg
- mov ax, segsize ; get some memory
- add ax, 16 ; account for paragraph boundary
- push ax
- call __xalloc ; request some space
- add sp, 2
- mov newoffset, ax ; save address for later release
- mov newsegment,dx ; upon return to Clipper
- or dx, ax ; oh yeah, check if we even got some
- jnz gpmm_1 ; memory, if not, time to bomb by
- jmp Done ; jumping directly to exit routine
-
- gpmm_1: mov dx, newsegment ; restore mem segment to DX
- add ax, 15 ; force ax to next page boundary
- shr ax, 1 ; drop low byte (ax/16)
- shr ax, 1
- shr ax, 1
- shr ax, 1
- add dx, ax ; convert to an even segment boundary
- mov newsegloc, dx ; and save. We now our own dataseg
- retn ; from the free pool
-
- Save2Array:
- cmp word ptr is_array, 0 ; don't attempt to save if no array
- je sta1
- push es ; __STORC destroys ES so save it
- push word ptr count ; array ordinal number
- push word ptr is_array ; parm number
- push ds ; segment of string
- mov ax, offset path ; offset of string
- push ax
- mov ds, oldsegloc ; restore Clippie's DS befo the call
- call __storc ; save to the array
- add sp, 8
- pop es ; get back our ES
- mov ds, newsegloc ; restore DS to our area
- or ax, ax ; error if AX is 0
- jnz sta1
- mov is_array, ax ; if error disable further attempts
- sta1: retn
-
- __ft_where endp
-
- __ft_tree proc far
- push ds ; save Clipper's environment
- push es
- push di
- push si
- push bp
- mov bp, sp
- sub sp, 08h
-
- t_1: call GetParms ; init vars and setup our dataseg
- mov ds, newsegloc
- assume ds:datasg
- call FirstDir ; try to find anything in root
- jc t_1a ; no files, find out why
- call save_root ; found something, root exists
- mov di, offset dta_buff + dta_file_offset ; clear name of found file
- xor al, al
- stosb
- jmp t_2
-
- t_1a: cmp al, 12h ; test for no more files
- jne t_1b
- call save_root ; no files, save root then exit
- mov count, 1
- t_1b: jmp Done
-
- t_2: call FirstDir ; find first subdirectory
- jc t_4 ; no subdir, set DTA back one directory area
-
- t_3: call IsParent ; check for DOS signature
- jc t_5
-
- mov ax, count ; got one, increment count
- inc ax
- mov count, ax
-
- call MakePath
-
- call Save2Array ; do the save
-
- t_6: call UpDir ; move DTA up a level for subdirs
- jmp t_2
-
- t_4: call DownDir ; go back one level
- t_5: call NextDir ; if CY bad path, look again
- jc t_4 ; if not found, go back again
- jmp t_3 ; if found, continue
-
- save_root:
- mov ax, 1 ; no files, insert the root then quit
- mov count, ax
- mov di, eop ; put null terminator after last \
- xor al, al
- stosb
- call Save2Array ; save the root
- retn
- __ft_tree endp
-
- _NANFOR ends
- end
-