home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / borland / jnfb88.arc / EXPWLD.ARC / SETARGV.ASM < prev    next >
Assembly Source File  |  1987-08-18  |  14KB  |  412 lines

  1.         NAME    setargv
  2.         PAGE    60,132
  3. ;[]------------------------------------------------------------[]
  4. ;|      SETARGV.ASM -- Parse Command Line                       |
  5. ;|                                                              |
  6. ;|      Turbo-C Run Time Library        version 1.0             |
  7. ;|                                                              |
  8. ;|      Copyright (c) 1987 by Borland International Inc.        |
  9. ;|      All Rights Reserved.                                    |
  10. ;[]------------------------------------------------------------[]
  11.  
  12.         INCLUDE RULES.ASI
  13.  
  14. ;       Segment and Group declarations
  15.  
  16. Header@
  17.  
  18. ;       External references
  19.  
  20. ExtSym@         __argc, WORD, __CDECL__
  21. dPtrExt@        __argv, __CDECL__
  22. ExtSym@         _psp, WORD, __CDECL__
  23. ExtSym@         _envseg, WORD, __CDECL__
  24. ExtSym@         _envLng, WORD, __CDECL__
  25. ExtSym@         _osmajor, BYTE, __CDECL__
  26. ExtProc@        abort, __CDECL__
  27.  
  28. ;*** Begin addition
  29. ; Here we declare our new C routine, expwild, as well as the fact 
  30. ; that we will use the library routine sbrk (for memory allocation). 
  31. ; We also need to know the size of the stack, and so access it.  
  32. ; The macros ExtProc and ExtSym are defined in RULES.ASI.
  33. ;
  34. ExtProc@        expwild, __CDECL__
  35. ExtProc@        sbrk, __CDECL__
  36. ExtSym@         _stklen, WORD, __CDECL__
  37. ;
  38. ;*** End addition
  39.  
  40.  
  41.         SUBTTL  Parse Command Line
  42.         PAGE
  43. ;/*                                                     */
  44. ;/*-----------------------------------------------------*/
  45. ;/*                                                     */
  46. ;/*     Parse Command Line                              */
  47. ;/*     ------------------                              */
  48. ;/*                                                     */
  49. ;/*-----------------------------------------------------*/
  50. ;/*                                                     */
  51. PSPCmd          equ     00080h
  52.  
  53.  
  54. CSeg@
  55.  
  56. IF      LPROG
  57. SavedReturn     dd      ?
  58. ELSE
  59. SavedReturn     dw      ?
  60. ENDIF
  61. SavedDS         dw      ?
  62. SavedBP         dw      ?
  63.  
  64. ;*** Begin addition
  65. ; Here we declare a double word pointer to hold the address of our 
  66. ; command line string and a word to hold the string's size.  We 
  67. ; do not initialize either one.  
  68. ;
  69. NewCmdLn        dd      ?
  70. NewCmdSz        dw      ?
  71. ;
  72. ;*** End addition
  73.  
  74. PubProc@        _setargv, __CDECL__
  75.  
  76. ;       First, save caller context and Return Address
  77.  
  78.         pop     word ptr SavedReturn
  79. IF      LPROG
  80.         pop     word ptr SavedReturn+2
  81. ENDIF
  82.         mov     SavedDS, ds
  83.  
  84. ;*** Begin deletion
  85. ; This block of code got the address of the command line, zeroed 
  86. ; the registers, got the command line's length, appended a null to 
  87. ; the command line, and set up the registers for later.  cx ended 
  88. ; up containing the size of the command line string, including the 
  89. ; null, and other registers were set to zero.  The code we give 
  90. ; below to replace this code will end up in the same state, but will 
  91. ; first call our routine expwild to preprocess the command line.  
  92. ;
  93. ;       cld
  94. ;       mov     es, _psp@
  95. ;       mov     si, PSPCmd      ; ES: SI = Command Line address
  96. ;       xor     ax, ax
  97. ;       mov     bx, ax
  98. ;       mov     dx, ax          ; AX = BX = CX = DX = 0
  99. ;       mov     cx, ax          ; AX = BX = CX = DX = 0
  100. ;       lods    byte ptr es:[si]
  101. ;       mov     di, si
  102. ;       xchg    ax, bx
  103. ;       mov     es:[di+bx], al  ; Append a \0 at the end
  104. ;       inc     bx
  105. ;       xchg    bx, cx          ; CX = Command Line size including \0
  106. ;
  107. ;*** End deletion
  108.  
  109. ;*** Begin addition
  110. ; Preprocess the command line for wild card expansion
  111. ;
  112. ; First, we get the stack size to see how large the expanded text 
  113. ; can be.  We limit ourselves to one-half of the available stack.  
  114.  
  115. IFDEF   __HUGE__
  116.         mov     ax, seg _stklen@   ; if we are using the huge model,
  117.         mov     es, ax             ; we need the segment that holds 
  118.         mov     ax, es:_stklen@    ; the stack data
  119. ELSE
  120.         mov     ax, _stklen@       ; here we need only the stack's 
  121.                                    ; length, as all data in one seg
  122. ENDIF
  123.         sar     ax, 1           ; Divide by two to leave room
  124.  
  125.         mov     NewCmdSz, ax    ; Save the maximum command size
  126.  
  127. ; Now we call sbrk to allocate the desired memory.  We push the 
  128. ; amount we need, which was in ax, onto the stack and do the call.  
  129.  
  130.         push    ax
  131.         call    sbrk@           ; Get some memory
  132.  
  133. ; After a call we must restore the stack to its previous state.  
  134. ; Rather than popping the argument we just adjust the stack pointer.
  135. ; Also, because we called a C routine, which could have messed up 
  136. ; our data segment, we restore it to the segment value saved earlier 
  137. ; by the existing code.  Finally, we save the address of the new 
  138. ; command line buffer we allocated, which was returned in ax.  
  139.  
  140.         add     sp, 2           ; Clean up the stack
  141.         mov     ds, SavedDS     ; Necessary?
  142.         mov     word ptr NewCmdLn, ax   ; Save the pointer offset
  143.  
  144. ; sbrk returns the segment in dx for large memory model code. 
  145. ; So, if we're not using that model, set dx to our segment so that 
  146. ; the following code will work.  
  147.  
  148. IFE     LDATA
  149.         mov     dx, ds          ; Get our own segment if not returned
  150. ENDIF
  151.         mov     word ptr NewCmdLn+2, dx ; Save the pointer offset 
  152.                                         ; segment just after the 
  153.                                         ; pointer offset
  154.         cld                     ; tell it to increment pointers 
  155.                                 ; after string operations
  156.  
  157. ; Now we do basically what the earlier deleted code did.  We get 
  158. ; the command line address and append a null to the command line. 
  159.  
  160.         mov     es, _psp@       ; Get the DOS command line
  161.         mov     si, PSPCmd      ;  address
  162.         xor     ax, ax          ; Zero AX and BX
  163.         mov     bx, ax
  164.         lods    byte ptr es:[si]
  165.         xchg    ax, bx
  166.         mov     es:[si+bx], al  ; Append a \0 at the end
  167.  
  168. ; Here we push the arguments for expwild and then make the call.  
  169. ; The third arg, and so the first to be pushed, is the maximum 
  170. ; command line size.
  171.  
  172.         mov     ax, NewCmdSz    ; Get the maximum command size
  173.         push    ax
  174.  
  175. ; The second arg is the destination string.  We push first its 
  176. ; segment if we are in large model.  In any case, we then push its 
  177. ; offset.  
  178.  
  179. IF LDATA
  180.         mov     ax, word ptr NewCmdLn+2 ; Segment for large data
  181.         push    ax
  182. ENDIF
  183.         mov     ax, word ptr NewCmdLn   ; Destination offset
  184.         push    ax
  185.  
  186. ; The first arg is the source command line string.  We push both its 
  187. ; segment and offset in all cases because expwild expects a far ptr
  188. ; for this arg.  
  189.  
  190.         mov     ax, _psp@       ; Segment of DOS command line
  191.         push    ax
  192.         mov     ax, PSPCmd+1    ; Offset (+ 1 to pass the count byte)
  193.         push    ax
  194.         call    expwild@        ; Finally, call expwild to expand 
  195.                                 ; the command line
  196.  
  197. ; Clean up the stack after the call.  We adjust by 10 if in large 
  198. ; model because of the extra segment id we pushed.  
  199.  
  200. IF LDATA
  201.         add     sp, 10          ; Clean up the stack
  202. ELSE
  203.         add     sp, 8           ; Clean up the stack
  204. ENDIF
  205.         mov     ds, SavedDS     ; Restore our data segment
  206.  
  207. ; Then, process the command line.  We put the size in cx and the 
  208. ; string itself in es:[si], just as their code did.  Finally, we 
  209. ; zero the same registers as the original (now deleted) code.  
  210.  
  211.         mov     cx, ax          ; Put size in CX
  212.         mov     es, word ptr NewCmdLn+2
  213.         mov     si, word ptr NewCmdLn   ; Get the address of the 
  214.                                         ; expanded string
  215.         mov     di, si          ; Set up the registers correctly
  216.         xor     ax, ax          ; AX = BX = CX = DX = 0
  217.         mov     bx, ax
  218.         mov     dx, ax
  219. ;
  220. ;*** End addition
  221.  
  222. Processing      label   near
  223.         call    NextChar
  224.         ja      NotQuote        ; Not a quote and there are more
  225. InString        label   near
  226.         jb      GetArg0Lgth     ; Command line is empty now
  227.         call    NextChar
  228.         ja      InString        ; Not a quote and there are more
  229. NotQuote        label   near
  230.         cmp     al, ' '
  231.         je      EndArgument     ; Space is an argument separator
  232.         cmp     al, 9
  233.         jne     Processing      ; TAB   is an argument separator
  234. EndArgument     label   near
  235.         xor     al, al          ; Space and TAB are argument separators
  236.         jmp     short Processing
  237.  
  238. ;       Character test function used in SetArgs
  239. ;               On entry AL holds the previous character
  240. ;               On exit  AL holds the next character
  241. ;                        ZF on if the next character is quote (") and AL = 0
  242. ;                        CF on if end of command line and AL = 0
  243.  
  244. NextChar        PROC    NEAR
  245.         or      ax, ax
  246.         jz      NextChar0
  247.         inc     dx              ; DX = Actual length of CmdLine
  248.         stosb
  249.         or      al, al
  250.         jnz     NextChar0
  251.         inc     bx              ; BX = Number of parameters
  252. NextChar0       label   near
  253.         xchg    ah, al
  254.         xor     al, al
  255.         stc
  256.         jcxz    NextChar2       ; End of command line --> CF ON
  257.         lods    byte ptr es:[si]
  258.         dec     cx
  259.         sub     al, '"'
  260.         jz      NextChar2       ; Quote found --> AL = 0 and ZF ON
  261.         add     al, '"'
  262.         cmp     al,'\'
  263.         jne     NextChar1       ; It is not a \
  264.         cmp     byte ptr es:[si], '"'
  265.         jne     NextChar1       ; Only " is transparent after \
  266.         lods    byte ptr es:[si]
  267.         dec     cx
  268. NextChar1       label   near
  269.         or      si, si          ; Be sure both CF & ZF are OFF
  270. NextChar2       label   near
  271.         ret
  272. NextChar        ENDP
  273.  
  274. ;       Invalid program name
  275.  
  276. BadProgName     label   near
  277.         jmp     abort@
  278.  
  279. ;       Now, Compute Argv[0] length
  280.  
  281. GetArg0Lgth     label   near
  282.         mov     bp, es          ; BP = Program Segment Prefix address
  283.         mov     si, _envLng@
  284.         add     si, 2           ; SI = Program name offset
  285.         mov     cx, 1           ; CX = Filename size (includes \0)
  286.         cmp     _osmajor@, 3
  287.         jb      NoProgramName
  288.         mov     es, _envseg@
  289.         mov     di, si          ; SI = argv[0] address
  290.         mov     cl, 07fh
  291.         repnz   scasb
  292.         jcxz    BadProgName
  293.         xor     cl, 07fh        ; CX = Filename size (includes \0)
  294. NoProgramName   label   near
  295.  
  296. ;       Now, reserve space for the arguments
  297.  
  298. ReserveSpace    label   near
  299.         inc     bx              ; argv[0] = PgmName
  300.         mov     __argc@, bx
  301.         inc     bx              ; argv ends with NULL
  302.         mov     ax, cx          ; Size = PgmNameLgth +
  303.         add     ax, dx          ;        CmdLineLgth +
  304.         add     bx, bx          ;        argc * 2       (LDATA = 0)
  305. IF      LDATA
  306.         add     bx, bx          ;        argc * 4       (LDATA = 1)
  307. ENDIF
  308.         add     ax, 1
  309.         and     ax, not 1       ; Keep stack word aligned
  310.         add     bx, ax
  311.         mov     di, sp
  312.         sub     di, ax          ; SS:DI = DestAddr for PgmName
  313.         sub     sp, bx          ; SS:SP = &argv[0]
  314.         xchg    bx, bp          ; BX = Program Segment Prefix address
  315.         mov     bp, sp          ; BP = &argv[0]
  316.         mov     word ptr __argv@, sp
  317. IF      LDATA
  318.         mov     word ptr __argv@+2, ss
  319. ENDIF
  320.         mov     ax, ss
  321.         mov     es, ax          ; ES:DI = Argument's area
  322.  
  323. ;       Copy program name
  324.  
  325. CopyArg0        label   near
  326.         mov     [bp], di        ; Set argv[n]
  327. IF      LDATA
  328.         mov     [bp+2], es
  329.         add     bp, 4
  330. ELSE
  331.         add     bp, 2
  332. ENDIF
  333.         mov     ds, _envseg@
  334.         dec     cx
  335.         rep     movsb
  336.         xor     al, al
  337.         stosb
  338.  
  339. ;       Copy the command line
  340.  
  341. ;*** Begin deletion
  342. ; This code used to ready the command line size and address.  
  343. ; Because we have changed these two, however, we must delete this 
  344. ; code and replace it with our own.  
  345. ;
  346. ;       mov     ds, bx
  347. ;       xchg    cx, dx          ; CX     = Command Line size
  348. ;       mov     si, PSPCmd + 1  ; DS: SI = Command Line address
  349. ;
  350. ;*** End deletion
  351.  
  352. ;*** Begin addition
  353. ; We ready the size and address of our newly expanded command line.  
  354. ; The code below ours puts all of the arguments on the stack.  It
  355. ; uses the stack pointer that previous code has already adjusted 
  356. ; to be in the correct position to hold all of the arguments.  
  357.  
  358.         xchg    cx, dx          ; CX     = Command Line size
  359.         push    ax              ; Save AX
  360.         mov     ax, word ptr NewCmdLn+2 ; Use expanded command line
  361.         mov     ds, ax
  362.         mov     si, word ptr NewCmdLn   ; DS: SI = Command Line address
  363.         pop     ax
  364. ;
  365. ;*** End addition
  366.  
  367. CopyArgs        label   near
  368.         jcxz    SetLastArg
  369.         mov     [bp], di        ; Set argv[n]
  370. IF      LDATA
  371.         mov     [bp+2], es
  372.         add     bp, 4
  373. ELSE
  374.         add     bp, 2
  375. ENDIF
  376. CopyArg         label   near
  377.         lodsb
  378.         or      al, al
  379.         stosb
  380.         loopnz  CopyArg
  381.         jz      CopyArgs
  382. SetLastArg      label   near
  383.         xor     ax, ax
  384.         mov     [bp], ax
  385. IF      LDATA
  386.         mov     [bp+2], ax
  387. ENDIF
  388.  
  389. ;       Restore caller context and exit
  390.  
  391. ;*** Begin addition
  392. ; We are finished.  We call sbrk with the negative of the amount 
  393. ; of memory it gave us, which causes that memory to be freed. 
  394.  
  395.         mov     ax, NewCmdSz    ; Get the command size
  396.         neg     ax              ; Negate
  397.         push    ax
  398.         call    sbrk@           ; Free up any storage we use
  399.         add     sp, 2           ; Clean up the stack after the call
  400. ;
  401. ;*** End addition
  402.  
  403.         mov     ds, SavedDS
  404. IF      LPROG
  405.         jmp     dword ptr SavedReturn
  406. ELSE
  407.         jmp     word ptr SavedReturn
  408. ENDIF
  409. EndProc@        _setargv, __CDECL__
  410. CSegEnd@
  411.         END
  412.