home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
dirutl
/
pushdir.asm
< prev
next >
Wrap
Assembly Source File
|
1986-07-15
|
10KB
|
343 lines
Greetings,
You have requested a copy of the PUSHDIR/POPDIR utilities.
Here they are! I have not put them into shar format, so to take them
apart, seach for 10 dashs at the beginning of a line. This is my
file-break. Three files are included:
PPDIR.USE Basic instructions
PUSHDIR.ASM PUSHDIR source
POPDIR.ASM POPDIR source
I make these routines available on an as-is basis, without any
support. (I MIGHT be able to answer a few simple questions about
them, though.)
- BRENT W. BACCALA -
Aerospace Engineering Department
U.S. Naval Academy
Annapolis, MD
<baccala@usna.arpa>
"I do graphics work on an SGI Iris, fun work on a VAX 11/780,
grunge work on an IBM XT"
---------- PPDIR.USE ----------
PUSHDIR and POPDIR, by John Friend, PC Magazine, Vol.5 Num.10, p.243
USING PUSHDIR AND POPDIR
Compile each utility with an assembler of your choice. Linking each
file will give you a `NO STACK SEGMENT' error, which should be ignored
because these are .COM files. Use EXE2BIN to convert them into .COM
format.
PUSHDIR will push the current drive and working directory onto a stack
capable of holding 6 directories (this can be expanded by changing the
source and re-compiling). POPDIR will pop the last directory pushed
by PUSHDIR. It checks first to see if PUSHDIR has been run, and if
not, gives an error message.
BUG: These utilities use a circular stack. POPDIR will check to see
if PUSHDIR has been run, but does not check to see if the next directory
is in fact a valid one. Ex: Running PUSHDIR once and POPDIR twice will
NOT generate an error from POPDIR and WILL cause unpredictable results.
NOTE: PUSHDIR will save the current drive and the working directory on
the current drive. So if you use multiple drives (as I do), there is a
"hole" in the program that you have to be careful of. If your shell
script runs PUSHDIR, changes drives, changes directories, does <your
application here>, and then run POPDIR, you will wind up back on your
original disk, in your original directory. But the working directory
on the other disk may not necessarily be the same! To get around this,
you have to run the programs several time, once to save the drive
letter, and then once on each drive to save the working directory. My
feeling is that this problem is not so much with the PUSHDIR/POPDIR
programs then with DOS for not allowing one drive to be mounted on
another (similiar to UNIX mountable file systems).
-bwb
---------- PUSHDIR ----------
main group code
code segment public para 'code'
assume cs:main
org 100h ;.COM file
BEGIN: jmp START ;program starts here
db "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
signature db 'PUSHDIR VERSION 1.0'
lengthsignature = $ - signature
savedint16 dd ? ;old int 16h vector
nextpush dw offset main:push1dir ;next place to save a dir
push1dir db 67 dup (0) ;storage for a saved dir
push2dir db 67 dup (0) ;more storage
push3dir db 67 dup (0) ;more storage
push4dir db 67 dup (0) ;more storage
push5dir db 67 dup (0) ;more storage
push6dir db 67 dup (0) ;last storage
;up to here must be EXACTLY identical in both PUSHDIR and POPDIR so that
;popdir can know how to access the memory space reserved by the first
;pushdir.
;myint16 in an interrupt handler chained onto the existing interrupt handler.
;it is used to find out if PUSHDIR is already installed and if it is, where
;is it located? It works by adding another function to int 16h. To use it
;ax = 7788h, bx=7789h, and ds:si points to the signature string. If any one
;of these conditions is not true, then the int 16h call is passed onto the
;old routine without doing anything. If they are all true, then we switch
;ax and bx and return ds = code segment (cs) of the interrupt handler.
myint16 proc far
pushf ;save flags
cmp ax,7788h ;possible signature request ?
je CHECKSIG ;yes
NOTSIG:
popf ;no - recover flags
jmp cs:[savedint16] ;go to old routine as normal
CHECKSIG:
cmp bx,7789h ;possible signature request ?
jne NOTSIG ;no
;ax and bx were both correct for a signature request
;now see if ds:si was pointing to the signature string
;the whole idea of the signature is that is has to be
;totally unique so no other program could possible use the same one.
push es ;save the registers we will use
push di
push cx
mov di,offset main:signature ;address of the signature
mov cx,lengthsignature ;length of the signature
repe cmpsb ;does string at ds:si match es:di?
pop cx ;recover all registers we used
pop di
pop es
jne NOTSIG ;no, not correct signature
;yes, it was a signature request so return ds equal to the current code
;segment so subsequent pushdir's and popdir's know where the original
;is located.
push cs
pop ds ;set ds = cs
xchg ax,bx ;flip these two so we know that
;ds is being returned
popf ;recover original flags
iret ;return back to the program
;that called int int 16h
myint16 endp
endresident label byte ;label marking the end of the
;code to remain resident
;code after here will not remain resident
install db 1 ;0 = already installed, 1 = not installed
abortmsg db 'Error reading the current directory.$'
START:
sti ;turn interrupts on
;first check to see if PUSHDIR is already installed
mov ax,7788h ;signature request
mov bx,7789h ;signature request
mov si,offset main:signature ;point to signature
int 16h ;is it installed ?
assume ds:nothing
cmp bx,7788h ;were ax and bx switched ?
jne NOTINSTALLED ;no
cmp ax,7789h ;were ax and bx switched ?
jne NOTINSTALLED ;no
;yes it is installed already
mov cs:[install],0 ;don't install it again
NOTINSTALLED:
;ds = segment of the installation
;store the current directory, including disk drive letter
mov si,ds:[nextpush] ;get storage address for next push
add si,3 ;make room for d:\
mov dl,0 ;default drive
mov ah,47h ;dos function number
int 21h ;get current directory
jc ABORTERR ;error message if carry set
mov ah,19h ;dos function number
int 21h ;get the current drive
add al,'A' ;convert to ascii
mov byte ptr ds:[si-3],al ;add the "D:\" in front of path
mov byte ptr ds:[si-2],':'
mov byte ptr ds:[si-1],'\'
;now update [nextpush] for the next PUSHDIR
cmp ds:[nextpush],offset main:push6dir ;time to wrap around ?
je WRAPPUSH ;yes
add ds:[nextpush],67 ;no, point to next one
jmp short GOTNEXTPUSH
WRAPPUSH:
mov ds:[nextpush],offset main:push1dir ;wrap back to beginning
GOTNEXTPUSH:
cmp cs:[install],1 ;should we install it ?
je DOINSTALL ;yes
int 20h ;no, we are done
ABORTERR:
mov dx,offset main:abortmsg ;address of error message
mov ah,9 ;dos function number
int 21h ;show error message
int 20h ;end program on error
;if we got to here, then pushdir is not already installed,
;so we need to install it by making part of it resident.
DOINSTALL:
push cs
pop ds ;set ds = cs
assume ds:main
;save the current int 16h vector
push es ;save es
mov ax,3516h ;dos function 35h, vector 16h
int 21h ;get the existing vector into es:bx
mov word ptr [savedint16],bx ;save es:bx
mov word ptr [savedint16+2],es ;save es:bx
pop es ;recover es
;now set the new int 16h vector to point to my routine
mov dx,offset main:myint16 ;point to my new routine
mov ax,2516h ;dos function 25h, vector 16h
int 21h ;set new vector to ds:dx
;now free up the memory occupied by the environment so it is not
;permantently wasted
mov ax,ds:[2ch] ;get segment of environment
mov es,ax ;load environment segment into es
mov ah,49h ;dos function number
int 21h ;free the environment memory
;now terminate resident protecting only the first part of this program
mov dx,offset main:endresident ;point to end of resident code
add dx,0fh ;round up
mov cl,4
shr dx,cl ;convert to paragraphs (divide by 16)
mov ax,3100h ;dos function 31h, error code=0
int 21h ;terminate and remain resident
code ends
end begin ;start execution at BEGIN
---------- POPDIR ----------
main group code
code segment public para 'code'
assume cs:main
org 100h ;.COM file
BEGIN: jmp START ;prorgam starts here
db "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
signature db 'PUSHDIR VERSION 1.0'
lengthsignature = $ - signature
savedint16 dd ? ;used to be identical to pushdir
nextpush dw offset main:push1dir ;next place to save a dir
push1dir db 67 dup (0)
push2dir db 67 dup (0)
push3dir db 67 dup (0)
push4dir db 67 dup (0)
push5dir db 67 dup (0)
push6dir db 67 dup (0)
;up to here must be EXACTLY identical in both PUSHDIR and POPDIR.
notinstalled1 db 'Must run PUSHDIR.COM before POPDIR.COM'
db ' will do anything.',13,10,10,'$'
errpop1 db 'Error popping the current directory',13,10,10,'$'
START:
sti ;interrupts on
;is PUSHDIR already installed ?
mov ax,7788h ;signature request
mov bx,7789h ;signature request
mov si,offset main:signature ;point ds:si to signature
int 16h ;is it installed?
assume ds:nothing
cmp bx,7788h ;were ax and bx switched ?
jne NOTINSTALLED ;no
cmp ax,7789h ;were ax and bx switched ?
jne NOTINSTALLED ;no
jmp short ISINSTALLED ;yes - continue, no error
NOTINSTALLED:
;here PUSHDIR was not previously installed so POPDIR can't do anything
;useful so we just terminate with an error message.
mov dx,offset main:notinstalled1 ;error message
mov ah,9
int 21h
int 20h ;exit
ISINSTALLED:
;get the address of the directory previously saved by pushdir
mov bp,ds:[nextpush] ;get the next push location
sub bp,67 ;back up one to the last push
cmp ds:[nextpush],offset main:push1dir ;need to wrap back ?
jne NOWRAPBACK ;no
mov bp,offset main:push6dir ;yes, wrap back
NOWRAPBACK:
;set the current directory
mov dx,bp ;load ds:dx with directory to set
mov ah,3bh ;dos function number
int 21h ;set current dir back
jc ERRPOP ;branch on error
mov ds:[nextpush],bp ;update [nextpush] if successful
;set the current drive also
mov dl,ds:[bp] ;get drive letter from path
sub dl,'A' ;convert to binary (0=A, 1=B)
mov ah,0eh ;dos function number
int 21h ;set drive
;exit successfully with no message
int 20h ;exit
ERRPOP:
push cs
pop ds ;set ds = cs
mov dx,offset main:errpop1 ;error message
mov ah,9 ;dos function number
int 21h ;show the message
int 20h ;terminate
code ends
end BEGIN ;start execution at BEGIN
---------- END ----------