home *** CD-ROM | disk | FTP | other *** search
- 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 ----------
-