home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / DIR / PUSH_POP.ZIP / PUSHD12.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-07-25  |  24.0 KB  |  841 lines

  1. ;*************************  PUSHD.ASM  *************************************
  2. ;
  3. ;    PUSHD.ASM version 1.2
  4. ;
  5. ;    Usage:
  6. ;        PUSHD directory
  7. ;         Will push the current directory onto the directory stack
  8. ;         if there is a location available and changes to the current
  9. ;         directory to the specified parameter.
  10. ;        PUSHD 
  11. ;         Will change the current directory to the directory stored
  12. ;         in the top of the stack and will place the current directory
  13. ;         on the top of the stack.
  14. ;        PUSHD +n
  15. ;         Will change the current directory to the directory stored
  16. ;         in stack location n, with 1 being the bottom of the stack
  17. ;          and 6 being the top.  The stack will be compressed to remove
  18. ;         any empty space and the current directory will be stored 
  19. ;         on top of the stack.
  20. ;    Purpose: This program will store directories in a memory-resident
  21. ;        area and change to a specified directory, so that the
  22. ;        user may switch back to a previous directory without having
  23. ;        to either know or to type in the required directory.  If the 
  24. ;        program terminates abnormally an error message will be
  25. ;        printed to the standard error.
  26. ;    Preconditions:
  27. ;        (The first seven conditions are required for functionality
  28. ;         with POPD and DIRS.)
  29. ;        1) PUSHD must be hooked to interrupt 13.
  30. ;        2) PUSHD must have the same commands from beginning
  31. ;         to after definition of push6d, so that it knows how
  32. ;         to access the resident code of PUSHD.  (This includes
  33. ;         the fact that there are 6 locations for directory storage
  34. ;         which are 67 bytes in size.)
  35. ;        3) PUSHD must have the signature "PUSHD VERSION 1.1".
  36. ;        4) PUSHD must look for 7788 in ax and 7789 in bx for
  37. ;         a call to int 13.
  38. ;        5) PUSHD must put the value of 7789 into ax and 7788
  39. ;         into bx upon calling int 13 by DIRS, if PUSHD is installed.
  40. ;        6) PUSHD will set the data segment to be equal to the data
  41. ;         segment that PUSHD used to install itself.
  42. ;        7) DS:[nextpush] (DS of PUSHD installation) must hold
  43. ;         the location of the next empty directory stack location.
  44. ;        8) For the last two usages PUSHD must already be installed,
  45. ;         otherwise an error condition is generated.
  46. ;        9) Enough memory space must be available for the directory
  47. ;         stack and other resident code (new interrupt, etc.)
  48. ;    Postconditions:
  49. ;        1) An appropriate error message will be printed OR
  50. ;        2) The parameter directory will become the current directory
  51. ;         and the current directory will be saved on the stack (usage
  52. ;         #1), with DS:[nextpush] being incremented to the next
  53. ;         storage position OR
  54. ;        3) The directory on the top of the stack will become the
  55. ;         current directory and the current directory will be placed
  56. ;         in the top position on the stack (usage #2) OR
  57. ;        4) The directory stored in location "n" (starting with 1 as
  58. ;         the bottom and six as the top) will become the current 
  59. ;         directory with the contents of the stack storage above the
  60. ;         the targeted directory shifting downward one to effectively
  61. ;         eliminate the "gap" left by the targeted directory.  Also,
  62. ;         the current directory will be placed on top of the directory
  63. ;         stack (usage #3)
  64. ;        5) If PUSHD was not previously loaded into memory, due to
  65. ;         not use or abnormal termination, the program will now be 
  66. ;         loaded with a reduction of memory of 1024 bytes.  This
  67. ;         includes the storage space required for the stack and
  68. ;         the new interrupt 13 handler.
  69. ;        6) An error code will be generated.
  70. ;    Error Codes:
  71. ;        0) Successful completion.
  72. ;          249) Error popping directory off stack.
  73. ;          250) Error pushing current directory.
  74. ;          251) Directory Stack is full.
  75. ;          252) Error changing to directory given on command line.
  76. ;          253) Command Line parameter exceeds Directory Stack depth.
  77. ;          254) Illegal Characters on the Command Line.
  78. ;          255) Command Line parameter not in valid directory range (1-6).
  79. ;    Version changes:
  80. ;        PUSHD v. 1.2:    July 21, 1990.
  81. ;            coded in Toad Hall tweaks and suggestions (much 
  82. ;             thanks to David Kirschbaum).
  83. ;        PUSHD v. 1.1:    July 14, 1990.
  84. ;            added "+n" option.
  85. ;            added change to parameter option.
  86. ;            changed no parameter option to switch current and
  87. ;             top directories.
  88. ;            changed hooked interrupt to 13 from 16.
  89. ;            added error codes for abnormal termination.
  90. ;            changed writes from vector 9 to vector 40h of 
  91. ;             int 21h.
  92. ;            changed program termination from int 20h to vector
  93. ;             4Cxxh int 21h, where xx represents the error code
  94. ;             generated.
  95. ;            removed stack wrap around.
  96. ;        PUSHDIR v. 1.0: Copyright 1986, Ziff-Davis Publishing Co.
  97. ;            From PC Magazine, May 27, 1986
  98. ;            No changes.
  99. ;    Future Enhancements:
  100. ;        1) Change the "n" parameters so that it refers to the
  101. ;         top of the stack, not the bottom (RELATIVE from the top
  102. ;         NOT ABSOLUTE from the bottom).
  103. ;        2) Make program an .EXE file.
  104. ;        3) Remove extra push/pop commands.
  105. ;        4) Fix up various hacks.
  106. ;        5) Correct error caused by 3 or more blanks at end of
  107. ;         command line tail.
  108. ;        6) Add a help option, ?, from the command line.
  109. ;        7) have "signature" loaded into memory so that programs such
  110. ;         as "POPDROP" can identify the stack as resident.
  111. ;
  112. ;    Created by:
  113. ;      (from ideas based in UNIX and from PC Magazine's POPDIR.COM)
  114. ;        William P. Sarra
  115. ;            CIS:71041,347
  116. ;            arpa: sarra@TOPAZ.RUTGERS.EDU
  117. ;    uucp: ...{ames,cbosgd, harvard, moss}!rutgers!topaz.rutgers.edu!sarra
  118. ;
  119. ;*****************************************************************************
  120.  
  121.  
  122. MAIN    group    CSEG
  123. CSEG    segment    public    para    'code'
  124.     assume    CS:MAIN,DS:MAIN,ES:MAIN,SS:MAIN
  125.  
  126. org    2CH            ;v1.2
  127. envseg     label    word            ;Environment Segment in PSP    v1.2
  128.  
  129. org    80h
  130. cmd_line    label    byte
  131.  
  132. org    100h                ;.COM file
  133.  
  134. Begin:    jmp    Start            ;program starts here
  135.  
  136. signature    db    'PUSHD VERSION 1.1'
  137. SIG_LEN        equ    $-signature
  138.  
  139. savedint13    dd    ?        ;old int 13h vector
  140.  
  141. nextpush    dw    offset MAIN:push1d    ;next place to save a dir
  142.  
  143. push1d    db    67 dup (0)        ;storage for a saved dir
  144. push2d    db    67 dup (0)        ;more storage
  145. push3d    db    67 dup (0)        ;more storage
  146. push4d    db    67 dup (0)        ;more storage
  147. push5d    db    67 dup (0)        ;more storage
  148. push6d    db    67 dup (0)        ;last storage
  149.  
  150. ;up to here must be EXACTLY identical in PUSHD, POPD, and DIRS so that
  151. ;POPD and DIRS can know how to access the memory space reserved by the first
  152. ;PUSHD.
  153.  
  154. ;**************************************************************************
  155. ;
  156. ;    PROCEDURE:    MYINT13
  157. ;
  158. ;    Purpose: myint13 is an interrupt handler chained onto the existing
  159. ;        interrupt handler.  It is used to find out if PUSHD is 
  160. ;        already  installed and if it is, where it located.  It works
  161. ;        by adding another function to int 13h.  To use it ax = 7788h,
  162. ;        bx = 7789h, and DS:si points to the signature string.  If any
  163. ;        one of these conditions are not true, then the int 13h call 
  164. ;        is passed onto the old routine without doing anything.  If 
  165. ;        they are all true, then we switch ax and bx and return DS = 
  166. ;        code segment (CS) of the interrupt handler.
  167. ;    Preconditions:
  168. ;        For a check to see if PUSHD is installed, ax = 7788h and bx
  169. ;         = 7789h DS:si points to the string "PUSHD VERSION 1.1".
  170. ;    Postconditons:
  171. ;        If PUSHD is installed, ax = 7789h and bx = 7788h, DS = CS of
  172. ;         the interrupt handler.
  173. ;         If PUSHD was not installed, a new function is added to 
  174. ;         interrupt 13h which is checked before any other functions.
  175. ;
  176. ;****************************************************************************
  177.  
  178. myint13    proc    far
  179.  
  180.     pushf                    ;save flags
  181.     cmp    ax,7788h            ;possible signature request ?
  182.     je    CHECKSIG            ;yes
  183. NOTSIG:
  184.     popf                ;no - recover flags
  185.     jmp    CS:[savedint13]        ;go to old routine as normal
  186.  
  187. CHECKSIG:
  188.     cmp    bx,7789h        ;possible signature request ?
  189.     jne    NOTSIG            ;no
  190.  
  191.     ;ax and bx were correct for a signature request.
  192.     ;Now see if DS:si was pointing to the signature string.
  193.     ;Signature string MUST be unique from any other programs.
  194.  
  195.     push    ES            ;save the registers we will use
  196.     push    di
  197.     push    cx 
  198.     mov    di,offset main:signature    ;address of the signature
  199.     mov    cx,sig_len            ;length of the signature
  200.     repe    cmpsb            ;does string at DS:si match ES:di ?
  201.     pop    cx            ;recover all registers we used
  202.     pop    di
  203.     pop    ES
  204.     jne    NOTSIG            ;no, not correct signature
  205.  
  206.     ;Signature request: return DS equal to the current code segment so 
  207.     ; subsequent PUSHD's, POPD's and DIRS know where the original
  208.     ; is located.
  209.  
  210.     push    CS
  211.     pop    DS            ;set DS = CS
  212.     xchg    ax,bx            ;flip these two so we know that
  213.                     ;DS is being returned
  214.     popf                ;recover original flags
  215.     iret                ;return back to the program
  216.                     ;that called the int 13h
  217.  
  218. myint13    endp
  219.  
  220. ENDRESIDENT    label    byte  
  221. ;ENDRESIDENT    EQU    (OFFSET CSEG - $) + 0FH        ;v1.2
  222.  
  223. ;code after here will not remain resident
  224.  
  225.  
  226. ;**********************************************************************
  227. ;
  228. ;    PROCEDURE:    Push_Dir
  229. ;
  230. ;    Purpose: This procedure will put the current directory into
  231. ;        the storage location specified si.  It will store 
  232. ;        the whole path to the current directory and will add
  233. ;        the drive and root specification as well.
  234. ;    Preconditions:
  235. ;        DS = segment of the storage pointed to by si.
  236. ;        si points to the storage location.
  237. ;        The storage location is 67 bytes wide.
  238. ;        The error message "abortmsg" is defined and it's length
  239. ;         has been determined.
  240. ;    Postconditions:
  241. ;        si will be three more than the si passed into the 
  242. ;         procedure.
  243. ;        si - 3 will point to beginning of the current directory,
  244. ;         starting with the drive specification.
  245. ;        OR an error message will be generated on stderr and the
  246. ;         program will terminate with an error code.
  247. ;
  248. ;**************************************************************************
  249.  
  250. Push_Dir    proc
  251.  
  252.     ;DS = segment of the directory storage in si
  253.     
  254.     ASSUME    DS:CSEG            ;assume TSR        v1.2
  255.  
  256.     ;store the current directory, including disk drive letter
  257.  
  258.     add    si,3    
  259.     xor    dl,dl            ;default drive        v1.2
  260.     mov    ah,47h            ;dos function number
  261.     int    21h            ;get current directory
  262.     sub     si,3
  263.     jc    ABORTERR        ;error message if carry set
  264.  
  265.     mov    ah,19h            ;dos function number
  266.     int    21h            ;get the current drive
  267.     add    al,'A'            ;convert to ascii
  268.     mov    [si],al            ;add the "D:\" in front of path    v1.2
  269.     mov    word ptr [SI+1],'\:'    ;type them in backwards..    v1.2
  270.     ret
  271.  
  272. ABORTERR:
  273.  
  274.     ;error in getting current directory -- generate error message
  275.     ; and exit with an error code
  276.  
  277.     mov    dx,offset MAIN:abortmsg        ;address of error message
  278.     mov    cx,ABORTMSG_LN
  279.  
  280.     mov    al,0FAH            ;ERRORLEVEL        v1.2
  281.     jmp    Msg_Term        ;display, terminate    v1.2
  282.  
  283. Push_Dir    endp
  284.  
  285.  
  286. ;********************************************************************
  287. ;
  288. ;    PROCEDURE:    Pop_Dir
  289. ;
  290. ;    Purpose:  This procedure will change the current directory to
  291. ;        the one specified in the location pointed to by
  292. ;        bp.  It will also change the current drive specification,
  293. ;        if necessary.
  294. ;    Preconditions:
  295. ;        bp points to the location of the directory to change to.
  296. ;        ES is equal to the segment that holds the targeted
  297. ;         directory.
  298. ;        The error message "errpop1" is defined and it's length
  299. ;         has been determined.
  300. ;    Postconditions:
  301. ;        The current drive and directory are those specified in
  302. ;         in the parameter pointed to by bp, if valid.
  303. ;        Otherwise, an error message is printed and a specific
  304. ;         error code is generated.
  305. ;
  306. ;**************************************************************************
  307.  
  308. Pop_Dir    proc
  309.  
  310.     ;bp holds location of directory to pop off stack
  311.     
  312.     ;set the current directory 
  313.  
  314.     mov    dx,bp            ;load DS:dx with directory to set
  315.     mov    ah,3bh            ;dos function number
  316.     int    21h            ;set current dir back
  317.     jc    ERRPOP            ;branch on error
  318.  
  319.     mov    dl,DS:[bp]        ;v1.2
  320.     sub    dl,'A'                ;convert to binary (0=A, 1=B)
  321.     mov    ah,0eh                ;dos function number
  322.     int    21h                ;set drive
  323.     jc    ERRPOP
  324.  
  325.     ret
  326.  
  327. ERRPOP:
  328.  
  329.     ;Error in changing to the desired directory -- print an
  330.     ; error message and exit with error code.
  331.  
  332.     mov    dx,offset MAIN:errpop1        ;error message
  333.     mov    cx,ERRPOP1_LN
  334.     mov    al,0F9H            ;ERRORLEVEL        v1.2
  335.     jmp    Msg_Term        ;display, terminate    v1.2
  336.  
  337. Pop_Dir    endp
  338.  
  339.  
  340. ;*****************************************************************
  341. ;
  342. ;    DATA SECTION
  343. ;
  344. ;*****************************************************************
  345.  
  346. install        db    1    ;0 = already installed, 1 = not installed
  347.  
  348. abortmsg    db    'Error reading the directory.',13,10
  349. ABORTMSG_LN    equ    $-abortmsg
  350. installmsg    db    'PUSHD installed.'
  351. INSTALLMSG_LN    equ    $-installmsg
  352.  
  353. in_dir_msg    db    'Valid Directories range between 1 and 6.',13,10
  354. IN_DIR_MSG_LN    equ    $-in_dir_msg
  355. bs_online    db    'Invalid Command Line Parameters.',13,10
  356. BS_ONLINE_LN    equ    $-bs_online
  357. not_pushed    db    'Parameter exceeds Directory Stack depth.',13,10
  358. NOT_PUSHED_LN    equ    $-not_pushed
  359. full_stack    db    'Cannot push Directory -- STACK FULL.',13,10
  360. FULL_STACK_LN    equ    $-full_stack
  361. errpop1        db    'Error popping requested directory.',13,10
  362. ERRPOP1_LN    equ    $-errpop1
  363.  
  364. BLANK        equ    20h    ;' '
  365. DELIMITER    equ    2Bh    ;'+'
  366. UP_LIMIT    equ    36h    ;'6'
  367. LOW_LIMIT    equ    31h    ;'1'
  368.  
  369. DRIVE_DELIM    equ    3Ah    ;':'
  370.  
  371. params        db    ?    ;Command line tail
  372. params_ln    dw    ?    ;Length of command line tail
  373. targ_dir    dw    ?    ;location of storage of targeted directory
  374.  
  375. temp_dir    db    67 dup (0)    ;temporaray directory storage
  376.  
  377. ;***********************************************************************
  378. ;
  379. ;    CODE STARTS
  380. ;
  381. ;***********************************************************************
  382.  
  383. Start:
  384.  
  385.     ;get command line tail
  386.  
  387.     cld
  388.  
  389. ;v1.2    I entirely rewrote this section.  What a kludge!
  390.  
  391.     mov    si,offset cmd_line        ;command line tail
  392.     lodsb                    ;snarf length byte, bump SI
  393.  
  394.     ;SI -> first char (probably a space!)
  395.  
  396.     xor    ah,ah                ;clear msb
  397.     mov    cx,ax                ;into CX
  398.     mov    params_ln,ax            ;save for later
  399.     push    ax                ;save length on stack for later
  400.     jcxz    INST_CHK            ;CX is 0, branch
  401.  
  402.     ;We have a non-null command line
  403.  
  404.     mov    di,offset MAIN:params        ;store since it may get
  405.     rep    movsb                ;destroyed
  406.  
  407. INST_CHK:
  408.  
  409.     ;first check to see if PUSHD is already installed
  410.  
  411.     mov    ax,7788h            ;signature request
  412.     mov    bx,7789h            ;signature request
  413.     mov    si,offset main:signature    ;point to signature
  414.     int    13h                ;is it installed ?
  415.     
  416.     ASSUME    DS:CSEG            ;assume TSR's DS        v1.2    
  417.  
  418.     cmp    bx,7788h            ;were ax and bx switched ?
  419.     jne    NOTINSTALLED            ;no
  420.     cmp    ax,7789h            ;were ax and bx switched ?
  421.     jne    NOTINSTALLED            ;no
  422.     
  423.     ;yes it is installed already
  424.  
  425.     mov    CS:[install],0        ;don't install it again
  426.  
  427. NOTINSTALLED:
  428.     
  429.     ; check for command line parameters
  430.  
  431.     pop    cx            ;get saved cx
  432.     push    DS            ;store current DS
  433.  
  434.     mov    ax,CS            ;v1.2
  435.     mov    DS,ax            ;v1.2
  436.     ASSUME    DS:MAIN            ;reminder            v1.2
  437.  
  438.     or    cx,cx            ;check for no parameters
  439.     jnz    ERR1            ;no parameters
  440.     jmp    CHK_STACK
  441.  
  442. ERR1:    mov    di,offset MAIN:params
  443.     mov    al,BLANK        ;remove leading blanks
  444.     repe    scasb
  445.     dec    di
  446.     inc    cx
  447.     mov    si,di            ;save position
  448.     lodsb                ;snarf first char, bump SI    v1.2
  449.     cmp    al,BLANK        ;space?                v1.2
  450.     jne    ERR2
  451.     jmp    CHK_STACK        ;only blanks on tail
  452.  
  453. ERR2:    
  454.     cmp    al,DELIMITER        ;is it '+' delimiter?        v1.2
  455.     je    CHK_VALUE
  456.     jmp    CHK_STACK_DIR    ;directory on command line
  457.  
  458.  
  459. CHK_VALUE:
  460.  
  461.     ;check parameter values
  462.  
  463.     dec    cx            ;decr for last LODSB
  464.  
  465. ;v1.2    Recoded
  466.     lodsb                ;snarf digit after '+', bump SI
  467.     cmp    al,UP_LIMIT        ;above '6'?
  468.     ja    INVALID_DIR        ;yep, bogus
  469.     cmp    al,LOW_LIMIT        ;below '1'?'
  470.     jnb    FINISH_CHK        ;nope, in range ['1'..'6']
  471.  
  472.  
  473. INVALID_DIR:
  474.     
  475.     ;Invalid directory number -- print error message and exit
  476.     ; with error code
  477.  
  478.     mov    dx,offset MAIN:in_dir_msg    ;error message
  479.     mov    cx,IN_DIR_MSG_LN
  480.     mov    al,0FFH            ;ERRORLEVEL        v1.2
  481.     jmp    Msg_Term        ;display, terminate    v1.2
  482.  
  483. FINISH_CHK:
  484.  
  485.     ;check for illegal characters on the command line
  486.  
  487.     dec    cx            ;decr cmdline count for digit    v1.2
  488.     jcxz    VALID_DIR
  489.  
  490.     mov    ah,al            ;save digit            v1.2
  491.     mov    al,BLANK         ;check for following nonblank
  492.     repne    scasb            ;characters
  493.     mov    al,ah            ;replace digit            v1.2
  494.  
  495.     jcxz    VALID_DIR
  496.  
  497.     ;illegal characters found on the command line -- print error
  498.     ; message and exit with and error code
  499.  
  500.     mov    dx,offset MAIN:bs_online    ;error message
  501.     mov    cx,BS_ONLINE_LN
  502.     mov    al,0FEH            ;ERRORLEVEL            v1.2
  503.     jmp    Msg_Term        ;display, terminate    v1.2
  504.  
  505.  
  506. VALID_DIR:
  507.  
  508.     ;get targeted pushed directory location
  509.  
  510.     xor    ah,ah            ;clear ah    v1.2
  511.     mov    cx,67            ;multiplier    v1.2
  512.     sub    al,'1'            ;'0'..'5' range
  513.     mul    cx            ;directory offset    v1.2
  514.     add    ax,offset MAIN:push1d    ;base directory buffer    v1.2
  515.     mov    targ_dir,ax        ;save it    v1.2
  516.  
  517.     ;check for validly pushed directory
  518.  
  519.     ;CONDITIONS coming into here:
  520.     ; DS = CS = ES = SS
  521.     ; DS (installed) on stack
  522.  
  523.     pop    ax            ;TSR's CSEG        v1.2
  524.     mov    DS,ax            ;load DS        v1.2
  525.     mov    ES,ax            ;and ES            v1.2
  526.     ASSUME    DS:CSEG,ES:CSEG        ;assume TSR's        v1.2
  527.  
  528.     mov    bp,DS:[nextpush]
  529.     sub    bp,67                ;get top of stack location
  530.  
  531.     cmp    bp,CS:[targ_dir]        ;make sure directory stack
  532.     jge    PROCESS_DIRS            ;is deep enough for params
  533.  
  534.     ;The directory stack is not deep enough for the specified command
  535.     ; line parameter -- print an error message and exit with error code
  536.  
  537.     mov    dx,offset MAIN:not_pushed    ;error message
  538.     mov    cx,NOT_PUSHED_LN
  539.     mov    al,0FDH            ;ERRORLEVEL        v1.2
  540.     jmp    Msg_Term        ;display, terminate    v1.2
  541.  
  542. PROCESS_DIRS:
  543.  
  544.     ;We have got a valid target directory here, now check to see
  545.     ; if we are working with the top of the stack.
  546.  
  547.     jne    NOT_TOP
  548.     push    DS        ;put DS (installation) on stack
  549.     jmp    SHORT NEW_CHK_STACK
  550.  
  551. CHK_STACK:
  552.  
  553.     ;CONDITIONS coming into here:
  554.     ;coming from no parameters section of parameter check (NOTINSTALLED)
  555.     ;CS = DS = SS = ES, DS (installation) on stack
  556.     
  557.     pop    DS            ;set ES = DS = DS (installation)
  558.     mov    ax,DS            ;v1.2
  559.     mov    ES,ax            ;v1.2
  560.     ASSUME    DS:CSEG,ES:CSEG        ;reminder            v1.2
  561.  
  562.     push    DS            ;put DS (installation) on stack
  563.     mov    bp,DS:[nextpush]
  564.     sub    bp,67            ;set bp to be top of the stack
  565.  
  566. NEW_CHK_STACK:                ;common code here        v1.2
  567.     mov    ax,CS            ;v1.2
  568.     mov    DS,ax            ;v1.2
  569.  
  570.     ;CONDITIONS coming into here:
  571.     ; from PROCESS_DIRS and from fall-through of CHK_STACK
  572.     ; ES = DS (installation), DS = CS = SS, DS (installation) on stack
  573.  
  574.     ;handle the pushing and popping of directories on and off of the
  575.     ; top of the stack
  576.  
  577.     mov    si,offset MAIN:temp_dir
  578.     call    Push_Dir        ;store current dir in temp_dir
  579.     pop    DS
  580.     ASSUME    DS:CSEG        ;assume TSR    v1.2
  581.  
  582.     call    Pop_Dir            ;pop directory in bp
  583.     push    DS
  584.     mov    ax,CS            ;v1.2
  585.     mov    DS,ax            ;v1.2
  586.     ASSUME    DS:MAIN        ;reminder    v1.2
  587.  
  588.     mov    di,bp            ;copy temp_dir into top of stack
  589.     mov    cx,67            ;stack position
  590.     rep    movsb
  591.     mov    ES,ax            ;AX is still CSEG from above    v1.2
  592.     jmp    GOTNEXTPUSH
  593.  
  594. NOT_TOP:
  595.  
  596.     ;CONDITIONS coming into here:
  597.     ;DS = ES = installation DS, CS = SS, nothing on stack
  598.  
  599.     push    DS            ;store DS
  600.     mov    ax,CS            ;v1.2
  601.     mov    DS,ax            ;v1.2
  602.     ASSUME    DS:MAIN            ;reminder    v1.2
  603.  
  604.     mov    si,offset MAIN:temp_dir
  605.     call    Push_Dir        ;store current dir in temp_dir
  606.     mov    bp,targ_dir
  607.     pop    DS
  608.     ASSUME    DS:CSEG            ;probably TSR's        v1.2
  609.  
  610.     call    Pop_Dir            ;pop targeted directory
  611.     mov    dx,DS:[nextpush]
  612.  
  613.     mov    ax,67            ;handy constant            v1.2
  614.     sub    dx,ax    ;67        ;set dx to point to top of stack v1.2
  615.     mov    bx,CS:[targ_dir]    ;handle variable here        v1.2
  616.  
  617. STACK_LOOP:
  618.  
  619.     ;loop through the directory stack, shifting the the directories
  620.     ; downward to eliminate the space left by popping a directory
  621.     ; in the middle of the stack.
  622.  
  623.     add    bp,ax            ;v1.2
  624.     cmp    bp,dx
  625.     je    LAST_DIR        ;found the last directory
  626.     mov    si,bp            ;copy contents pointed to by bp
  627.     mov    di,bx            ;to targ_dir    v1.2
  628.     mov    cx,ax            ;v1.2
  629.     rep    movsb
  630.     add    bx,ax            ;targ_dir,67    v1.2
  631.     jmp    SHORT STACK_LOOP    ;continue
  632.  
  633. LAST_DIR:
  634.  
  635.     ;process last directory on stack
  636.  
  637.     mov    si,bp            ;otherwise simply copy
  638.     mov    di,bx            ;curr_dir    v1.2
  639.     mov    cx,ax            ;67        v1.2
  640.     rep    movsb
  641.     mov    targ_dir,bx        ;update        v1.2
  642.  
  643.     mov    di,bp            ;copy temp_dir to top of stack
  644.     mov    bx,CS            ;v1.2
  645.     mov    DS,bx            ;v1.2
  646.     ASSUME    DS:MAIN            ;v1.2
  647.  
  648.     mov    si,offset MAIN:temp_dir
  649.     mov    cx,ax            ;67    v1.2
  650.     rep    movsb
  651.     mov    ES,bx            ;BX is still CSEG from above    v1.2
  652.     jmp    SHORT GOTNEXTPUSH
  653.  
  654. CHK_STACK_DIR:
  655.     
  656.     ;push current directory and change to parameter directory
  657.  
  658.     ;CONDITIONS upon entering here:
  659.     ;CS = DS = ES = SS, DS (installed) on stack
  660.  
  661.     pop    DS
  662.     ASSUME    DS:CSEG            ;assume TSR's            v1.2
  663.  
  664.     cmp    DS:[nextpush],offset MAIN:push6d    ;check for full stack
  665.     jg    STACK_FULL
  666.     mov    si,DS:[nextpush]
  667.     call    Push_Dir            ;push current onto stack
  668.     push    DS
  669.     mov    ax,CS            ;v1.2
  670.     mov    DS,ax            ;v1.2
  671.     ASSUME    DS:MAIN            ;reminder    v1.2
  672.  
  673.     mov    bp,1 + offset MAIN:params    ;one after blank space
  674.  
  675.     ;change to specified directory
  676.  
  677.     mov    dx,bp            ;load DS:dx with directory to set
  678.     mov    ah,3bh            ;dos function number
  679.     int    21h            ;set current dir back
  680.     jc    POP_ERR
  681.  
  682.     ;check and set default drive
  683.  
  684.     mov    cx,[params_ln]        ;parameter length v1.2
  685.     cmp    cx,3            ;if cmdline is less than 3    v1.2
  686.     jb    NO_DRIVE        ;can't have drive spec D:\    v1.2
  687.  
  688.     cmp    byte ptr DS:[bp+1],DRIVE_DELIM    ;drive spec?        v1.2
  689.     jne    NO_DRIVE
  690.  
  691.     mov    al,DS:[bp]        ;v1.2    
  692.     sub    al,'A'            ;convert to binary (0=A, 1=B)    v1.2
  693.     cmp    al,1Ah            ;'26' == Z as last drive    v1.2
  694.     jle    ACTION
  695.     sub    al,20h            ;conversion for lower case drive spec
  696.                     ;v1.2
  697. ACTION:
  698.     mov    dl,al            ;NOW put it in DL    v1.2
  699.     mov    ah,0eh                ;dos function number
  700.     int    21h                ;set drive
  701.     jc    POP_ERR
  702. NO_DRIVE:
  703.     jmp    SHORT OK_DIR
  704.  
  705. POP_ERR:
  706.  
  707.     ;Error occcurred while trying to change to specified directory
  708.     ; print error message and exit with error.
  709.  
  710.     mov    dx,offset MAIN:errpop1
  711.     mov    cx,ERRPOP1_LN
  712.     mov    al,0FCH            ;ERRORLEVEL        v1.2
  713.     jmp    Msg_Term        ;display, terminate    v1.2
  714.  
  715. OK_DIR:
  716.  
  717.     ;Increment the location of the nextpush and set DS as
  718.     ; required by section GOTNEXTPUSH.
  719.  
  720.     pop    DS
  721.     add    DS:[nextpush],67
  722.     mov    ax,CS            ;v1.2
  723.     mov    DS,ax            ;v1.2
  724.     ASSUME    DS:MAIN            ;reminder    v1.2
  725.  
  726.     jmp    SHORT GOTNEXTPUSH
  727.  
  728. STACK_FULL:
  729.  
  730.     ;The directory stack is full -- print error message and
  731.     ; exit with error.
  732.  
  733.     mov    dx,offset MAIN:full_stack    ;error message
  734.     mov    cx,FULL_STACK_LN
  735.     mov    al,0FBH            ;ERRORLEVEL        v1.2
  736.     jmp    Msg_Term        ;display, terminate    v1.2
  737.  
  738.  
  739. GOTNEXTPUSH:
  740.  
  741.     ;CONDITIONS coming into this section:
  742.     ; CS = DS = SS = ES 
  743.     ASSUME    DS:MAIN,ES:MAIN        ;reminder    v1.2
  744.  
  745.     cmp    [install],1            ;should we install it    v1.2
  746.     je    DOINSTALL                ;yes
  747.  
  748.     ;PUSHD is already installed, exit successfully.
  749.  
  750.     mov    ax,4c00h
  751.     int    21h                ;no, we are done
  752.  
  753.  
  754. DOINSTALL:
  755.  
  756.     ;PUSHD is not installed, install it by making part of it
  757.     ; memory resident.
  758.  
  759. assume    DS:MAIN
  760.  
  761.     ;Save the current int 13h vector.
  762.  
  763.     mov    ax,3513h            ;dos function 35h, vector 13h
  764.     int    21h            ;get the existing vector into ES:bx
  765.     mov    word ptr [savedint13],bx    ;save ES:bx
  766.     mov    word ptr [savedint13+2],ES    ;save ES:bx
  767.  
  768.     ;Set the new int 13h vector to point to routine myint13.
  769.  
  770.     mov    dx,offset MAIN:myint13        ;point to new routine
  771.     mov    ax,2513h            ;dos function 25h, vector 13h
  772.     int    21h                ;set new vector to DS:dx
  773.  
  774.     ;Show an installation message on the screen.
  775.     ; This message can be suppressed by redirecting output to NUL.
  776.  
  777.     mov    dx,offset MAIN:installmsg
  778.     mov    cx,INSTALLMSG_LN
  779.     mov    bx,1            ;write to stdout
  780.     mov    ah,40h
  781.     int    21h            ;show installation message
  782.  
  783.     ;Free up the memory occupied by the envirnoment so it is not
  784.     ; permanently wasted.
  785.  
  786.     mov    ES,envseg        ;load ES with env seg        v1.2
  787.     mov    ah,49h            ;dos function number
  788.     int    21h            ;free the environment memory
  789.  
  790.     ;Terminate resident protecting only the first part of this program.
  791.  
  792.     ;v1.2    Let the compiler do the computing!
  793.  
  794.     mov    dx,offset MAIN:ENDRESIDENT
  795.     add    dx,0FH
  796.     mov    cl,4
  797.     shr    dx,cl
  798. ;    mov    dx,ENDRESIDENT / 16    ;resident code in paragraphs    v1.2
  799.     mov    ax,3100h        ;dos function 31h, error code=0
  800.     int    21h            ;terminate and remain resident
  801.  
  802.  
  803.  
  804. ;*********************************************************************
  805. ;
  806. ;    PROCEDURE:    Msg_Term
  807. ;
  808. ;    Purpose: This procedure will handle the printing of error messages
  809. ;        and termination with the correct errorlevel.
  810. ;    Preconditions: 
  811. ;        DX = error message address.
  812. ;        CX = error message length.
  813. ;        AL = ERRORLEVEL.
  814. ;    Postconditions: 
  815. ;        The program will be terminated with the appropriate
  816. ;         error message printed on standard error and with the
  817. ;         the errorlevel stored in al.
  818. ;
  819. ;***************************************************************************
  820.  
  821. Msg_Term    PROC    NEAR
  822. ;v1.2    Common routine to display error messages and terminate.
  823.  
  824.     push    CS            ;insure this is so
  825.     pop    DS
  826.     ASSUME    DS:MAIN
  827.  
  828.     push    ax                ;save ERRORLEVEL in AL
  829.     mov    bx,2                ;write to stderr
  830.     mov    ah,40h                ;dos function number
  831.     int    21h                ;show error message
  832.     pop    ax                ;restore ERRORLEVEL in AL
  833.     mov    ah,4CH                ;terminate process
  834.     int    21h
  835.  
  836. Msg_Term    ENDP
  837.  
  838.  
  839. CSEG    ends
  840. end    Begin                ;start execution at Begin
  841.