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 "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 , 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 ---------- .