home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / dirutil / pushdir.asm < prev    next >
Assembly Source File  |  1994-03-04  |  10KB  |  343 lines

  1. Greetings,
  2.  
  3.     You have requested a copy of the PUSHDIR/POPDIR utilities.
  4. Here they are!  I have not put them into shar format, so to take them
  5. apart, seach for 10 dashs at the beginning of a line.  This is my
  6. file-break.  Three files are included:
  7.  
  8.     PPDIR.USE    Basic instructions
  9.     PUSHDIR.ASM    PUSHDIR source
  10.     POPDIR.ASM    POPDIR source
  11.  
  12. I make these routines available on an as-is basis, without any
  13. support.  (I MIGHT be able to answer a few simple questions about
  14. them, though.)
  15.  
  16.             - BRENT W. BACCALA -
  17.             Aerospace Engineering Department
  18.             U.S. Naval Academy
  19.             Annapolis, MD
  20.  
  21.             <baccala@usna.arpa>
  22.  
  23.     "I do graphics work on an SGI Iris, fun work on a VAX 11/780,
  24.         grunge work on an IBM XT"
  25.  
  26. ---------- PPDIR.USE ----------
  27.  
  28. PUSHDIR and POPDIR, by John Friend, PC Magazine, Vol.5 Num.10, p.243
  29.  
  30. USING PUSHDIR AND POPDIR
  31.  
  32. Compile each utility with an assembler of your choice.  Linking each
  33. file will give you a `NO STACK SEGMENT' error, which should be ignored
  34. because these are .COM files.  Use EXE2BIN to convert them into .COM
  35. format.
  36.  
  37. PUSHDIR will push the current drive and working directory onto a stack
  38. capable of holding 6 directories (this can be expanded by changing the
  39. source and re-compiling).  POPDIR will pop the last directory pushed
  40. by PUSHDIR.  It checks first to see if PUSHDIR has been run, and if
  41. not, gives an error message.
  42.  
  43. BUG: These utilities use a circular stack.  POPDIR will check to see
  44. if PUSHDIR has been run, but does not check to see if the next directory
  45. is in fact a valid one. Ex: Running PUSHDIR once and POPDIR twice will
  46. NOT generate an error from POPDIR and WILL cause unpredictable results.
  47.  
  48. NOTE: PUSHDIR will save the current drive and the working directory on
  49. the current drive.  So if you use multiple drives (as I do), there is a
  50. "hole" in the program that you have to be careful of.  If your shell
  51. script runs PUSHDIR, changes drives, changes directories, does <your
  52. application here>, and then run POPDIR, you will wind up back on your
  53. original disk, in your original directory.  But the working directory
  54. on the other disk may not necessarily be the same!  To get around this,
  55. you have to run the programs several time, once to save the drive
  56. letter, and then once on each drive to save the working directory.  My
  57. feeling is that this problem is not so much with the PUSHDIR/POPDIR
  58. programs then with DOS for not allowing one drive to be mounted on
  59. another (similiar to UNIX mountable file systems).
  60.  
  61.                     -bwb
  62. ---------- PUSHDIR ----------
  63. main    group    code
  64. code    segment    public    para    'code'
  65. assume    cs:main
  66.  
  67. org    100h                ;.COM file
  68.  
  69. BEGIN:    jmp    START            ;program starts here
  70.         db    "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
  71. signature    db    'PUSHDIR VERSION 1.0'
  72. lengthsignature = $ - signature
  73.  
  74. savedint16    dd    ?        ;old int 16h vector
  75.  
  76. nextpush    dw    offset main:push1dir    ;next place to save a dir
  77. push1dir    db    67 dup (0)        ;storage for a saved dir
  78. push2dir    db    67 dup (0)        ;more storage
  79. push3dir    db    67 dup (0)        ;more storage
  80. push4dir    db    67 dup (0)        ;more storage
  81. push5dir    db    67 dup (0)        ;more storage
  82. push6dir    db    67 dup (0)        ;last storage
  83.  
  84. ;up to here must be EXACTLY identical in both PUSHDIR and POPDIR so that
  85. ;popdir can know how to access the memory space reserved by the first
  86. ;pushdir.
  87.  
  88. ;myint16 in an interrupt handler chained onto the existing interrupt handler.
  89. ;it is used to find out if PUSHDIR is already installed and if it is, where
  90. ;is it located?  It works by adding another function to int 16h.  To use it
  91. ;ax = 7788h, bx=7789h, and ds:si points to the signature string.  If any one
  92. ;of these conditions is not true, then the int 16h call is passed onto the
  93. ;old routine without doing anything.  If they are all true, then we switch
  94. ;ax and bx and return ds = code segment (cs) of the interrupt handler.
  95.  
  96. myint16    proc    far
  97.  
  98.     pushf                ;save flags
  99.     cmp    ax,7788h            ;possible signature request ?
  100.     je    CHECKSIG            ;yes
  101. NOTSIG:
  102.     popf                ;no - recover flags
  103.     jmp    cs:[savedint16]        ;go to old routine as normal
  104.  
  105. CHECKSIG:
  106.     cmp    bx,7789h        ;possible signature request ?
  107.     jne    NOTSIG            ;no
  108.  
  109.     ;ax and bx were both correct for a signature request
  110.     ;now see if ds:si was pointing to the signature string
  111.     ;the whole idea of the signature is that is has to be
  112.     ;totally unique so no other program could possible use the same one.
  113.  
  114.     push    es            ;save the registers we will use
  115.     push    di
  116.     push    cx
  117.     mov    di,offset main:signature    ;address of the signature
  118.     mov    cx,lengthsignature        ;length of the signature
  119.     repe    cmpsb            ;does string at ds:si match es:di?
  120.     pop    cx            ;recover all registers we used
  121.     pop    di
  122.     pop    es
  123.     jne    NOTSIG            ;no, not correct signature
  124.  
  125. ;yes, it was a signature request so return ds equal to the current code
  126. ;segment so subsequent pushdir's and popdir's know where the original
  127. ;is located.
  128.  
  129.     push    cs
  130.     pop    ds            ;set ds = cs
  131.     xchg    ax,bx            ;flip these two so we know that
  132.                     ;ds is being returned
  133.     popf                ;recover original flags
  134.     iret                ;return back to the program
  135.                     ;that called int int 16h
  136.  
  137. myint16    endp
  138.  
  139. endresident    label    byte        ;label marking the end of the
  140.                     ;code to remain resident
  141.  
  142. ;code after here will not remain resident
  143.  
  144. install        db    1    ;0 = already installed, 1 = not installed
  145.  
  146. abortmsg    db    'Error reading the current directory.$'
  147.  
  148. START:
  149.     sti            ;turn interrupts on
  150.  
  151.     ;first check to see if PUSHDIR is already installed
  152.  
  153.     mov    ax,7788h            ;signature request
  154.     mov    bx,7789h            ;signature request
  155.     mov    si,offset main:signature    ;point to signature
  156.     int    16h            ;is it installed ?
  157.  
  158. assume    ds:nothing
  159.  
  160.     cmp    bx,7788h            ;were ax and bx switched ?
  161.     jne    NOTINSTALLED        ;no
  162.     cmp    ax,7789h            ;were ax and bx switched ?
  163.     jne    NOTINSTALLED        ;no
  164.  
  165.     ;yes it is installed already
  166.  
  167.     mov    cs:[install],0        ;don't install it again
  168. NOTINSTALLED:
  169.  
  170.     ;ds = segment of the installation
  171.     ;store the current directory, including disk drive letter
  172.  
  173.     mov    si,ds:[nextpush]    ;get storage address for next push
  174.     add    si,3            ;make room for d:\
  175.     mov    dl,0            ;default drive
  176.     mov    ah,47h            ;dos function number
  177.     int    21h            ;get current directory
  178.     jc    ABORTERR        ;error message if carry set
  179.     mov    ah,19h            ;dos function number
  180.     int    21h            ;get the current drive
  181.     add    al,'A'            ;convert to ascii
  182.     mov    byte ptr ds:[si-3],al    ;add the "D:\" in front of path
  183.     mov    byte ptr ds:[si-2],':'
  184.     mov    byte ptr ds:[si-1],'\'
  185.  
  186.     ;now update [nextpush] for the next PUSHDIR
  187.  
  188.     cmp    ds:[nextpush],offset main:push6dir    ;time to wrap around ?
  189.     je    WRAPPUSH                ;yes
  190.     add    ds:[nextpush],67            ;no, point to next one
  191.     jmp    short GOTNEXTPUSH
  192. WRAPPUSH:
  193.     mov    ds:[nextpush],offset main:push1dir    ;wrap back to beginning
  194. GOTNEXTPUSH:
  195.     cmp    cs:[install],1            ;should we install it ?
  196.     je    DOINSTALL                ;yes
  197.     int    20h                ;no, we are done
  198.  
  199. ABORTERR:
  200.     mov    dx,offset main:abortmsg        ;address of error message
  201.     mov    ah,9                ;dos function number
  202.     int    21h                ;show error message
  203.     int    20h                ;end program on error
  204.  
  205.     ;if we got to here, then pushdir is not already installed,
  206.     ;so we need to install it by making part of it resident.
  207.  
  208. DOINSTALL:
  209.     push    cs
  210.     pop    ds            ;set ds = cs
  211.  
  212. assume    ds:main
  213.  
  214.     ;save the current int 16h vector
  215.  
  216.     push    es            ;save es
  217.     mov    ax,3516h            ;dos function 35h, vector 16h
  218.     int    21h            ;get the existing vector into es:bx
  219.     mov    word ptr [savedint16],bx    ;save es:bx
  220.     mov    word ptr [savedint16+2],es    ;save es:bx
  221.     pop    es            ;recover es
  222.  
  223.     ;now set the new int 16h vector to point to my routine
  224.     mov    dx,offset main:myint16    ;point to my new routine
  225.     mov    ax,2516h            ;dos function 25h, vector 16h
  226.     int    21h            ;set new vector to ds:dx
  227.  
  228.     ;now free up the memory occupied by the environment so it is not
  229.     ;permantently wasted
  230.  
  231.     mov    ax,ds:[2ch]        ;get segment of environment
  232.     mov    es,ax            ;load environment segment into es
  233.     mov    ah,49h            ;dos function number
  234.     int    21h            ;free the environment memory
  235.  
  236.     ;now terminate resident protecting only the first part of this program
  237.  
  238.     mov    dx,offset main:endresident    ;point to end of resident code
  239.     add    dx,0fh            ;round up
  240.     mov    cl,4
  241.     shr    dx,cl            ;convert to paragraphs (divide by 16)
  242.     mov    ax,3100h        ;dos function 31h, error code=0
  243.     int    21h            ;terminate and remain resident
  244.  
  245. code    ends
  246. end    begin                ;start execution at BEGIN
  247.  
  248. ---------- POPDIR ----------
  249. main    group    code
  250. code    segment    public    para    'code'
  251. assume    cs:main
  252.  
  253. org    100h                ;.COM file
  254.  
  255. BEGIN:    jmp    START            ;prorgam starts here
  256.         db    "Copyright 1986 Ziff-Davis Publishing Co.",1Ah
  257. signature    db    'PUSHDIR VERSION 1.0'
  258. lengthsignature = $ - signature
  259.  
  260. savedint16    dd    ?        ;used to be identical to pushdir
  261.  
  262. nextpush    dw    offset main:push1dir    ;next place to save a dir
  263. push1dir    db    67 dup (0)
  264. push2dir    db    67 dup (0)
  265. push3dir    db    67 dup (0)
  266. push4dir    db    67 dup (0)
  267. push5dir    db    67 dup (0)
  268. push6dir    db    67 dup (0)
  269.  
  270. ;up to here must be EXACTLY identical in both PUSHDIR and POPDIR.
  271.  
  272. notinstalled1    db    'Must run PUSHDIR.COM before POPDIR.COM'
  273.         db    ' will do anything.',13,10,10,'$'
  274. errpop1        db    'Error popping the current directory',13,10,10,'$'
  275.  
  276. START:
  277.     sti                ;interrupts on
  278.  
  279.     ;is PUSHDIR already installed ?
  280.  
  281.     mov    ax,7788h            ;signature request
  282.     mov    bx,7789h            ;signature request
  283.     mov    si,offset main:signature    ;point ds:si to signature
  284.     int    16h            ;is it installed?
  285.  
  286. assume    ds:nothing
  287.  
  288.     cmp    bx,7788h            ;were ax and bx switched ?
  289.     jne    NOTINSTALLED        ;no
  290.     cmp    ax,7789h            ;were ax and bx switched ?
  291.     jne    NOTINSTALLED        ;no
  292.     jmp    short ISINSTALLED        ;yes - continue, no error
  293. NOTINSTALLED:
  294.  
  295.     ;here PUSHDIR was not previously installed so POPDIR can't do anything
  296.     ;useful so we just terminate with an error message.
  297.  
  298.     mov    dx,offset main:notinstalled1    ;error message
  299.     mov    ah,9
  300.     int    21h
  301.     int    20h            ;exit
  302. ISINSTALLED:
  303.  
  304.     ;get the address of the directory previously saved by pushdir
  305.  
  306.     mov    bp,ds:[nextpush]        ;get the next push location
  307.     sub    bp,67                ;back up one to the last push
  308.     cmp    ds:[nextpush],offset main:push1dir    ;need to wrap back ?
  309.     jne    NOWRAPBACK            ;no
  310.     mov    bp,offset main:push6dir        ;yes, wrap back
  311. NOWRAPBACK:
  312.  
  313.     ;set the current directory
  314.  
  315.     mov    dx,bp            ;load ds:dx with directory to set
  316.     mov    ah,3bh            ;dos function number
  317.     int    21h            ;set current dir back
  318.     jc    ERRPOP            ;branch on error
  319.     mov    ds:[nextpush],bp    ;update [nextpush] if successful
  320.  
  321.     ;set the current drive also
  322.  
  323.     mov    dl,ds:[bp]            ;get drive letter from path
  324.     sub    dl,'A'                ;convert to binary (0=A, 1=B)
  325.     mov    ah,0eh                ;dos function number
  326.     int    21h                ;set drive
  327.  
  328.     ;exit successfully with no message
  329.  
  330.     int    20h                ;exit
  331.  
  332. ERRPOP:
  333.     push    cs
  334.     pop    ds                ;set ds = cs
  335.     mov    dx,offset main:errpop1        ;error message
  336.     mov    ah,9                ;dos function number
  337.     int    21h                ;show the message
  338.     int    20h                ;terminate
  339.  
  340. code    ends
  341. end    BEGIN                ;start execution at BEGIN
  342. ---------- END ----------
  343.