home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 11.ddi / WHEREIS.ZIP / IPARAM.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-10-27  |  13.1 KB  |  393 lines

  1.  
  2. ;   FILENAME: IPARAM.ASM
  3. ;
  4. ;   Copyright (c) 1988, 1992 by Borland International, Inc.
  5. ;
  6. ;   DESCRIPTION: This module implements two routines that manage the
  7. ;   command line parameters passed to the program. The routine ParamCount
  8. ;   returns the number of parameters passed to the program while the
  9. ;   routine ParamString returns a pointer to the referenced parameter
  10. ;   string. This module uses ideal mode syntax.
  11. ;
  12. ;   ASSEMBLY INSTRUCTIONS: To assemble this module use the following
  13. ;   TASM command line.
  14. ;
  15. ;       TASM /m /dMDL=memorymodel iparam
  16. ;
  17. ;   /m in the above command line allows TASM to resolve jumps and other
  18. ;   operations to their shortest form and get rid of extra NOPs.
  19. ;   'memorymodel' in the above command line may be replaced by TINY, SMALL,
  20. ;   MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
  21. ;   a 286/386 machine, turn on the P286 directive in order to take advantage of
  22. ;   286/386 specific instructions. I.E.
  23. ;
  24. ;       TASM /m /dMDL=memorymodel /jP286 iparam
  25. ;
  26. ;   NOTE: This module requires that the main program declare and initialize
  27. ;   the global variable PspAddress.
  28.  
  29. %tabsize 4
  30.  
  31. ifndef  MDL
  32.     display "Error: This module requires that you provide a memory model"
  33.     display "       definition on the command line. I.E. /dMDL=SMALL."
  34.     err ; Force a fatal error
  35. else
  36.  
  37.     ideal                           ; Use TASM's Ideal mode
  38. %   model   MDL,pascal              ; Define the memory model
  39.  
  40.     include "dos.inc"
  41.     include "idos.inc"
  42.     include "kbd.inc"
  43.     include "iwhglobl.inc"
  44.  
  45.     NotCalled  equ 0FFh ; ParamCount was already called once
  46.  
  47.     dataseg
  48.         ; Declare variables to store the parsed parameters and parameter
  49.         ; count.
  50.  
  51.         ParmCount   DB  NotCalled       ; ParamCount initializes this variable
  52.                                         ; the first time it is called.
  53.         ParmList    DB  7Fh DUP (0)     ; Allocate enough space for a 127
  54.                                         ; character command line
  55. ;        global  PspAddress:word         ; Define extrn variable
  56.  
  57.     codeseg
  58.  
  59. ;    global  ParamCount:proc             ; Public procs
  60. ;    global  ParamString:proc
  61.  
  62. ;    global  LocateString:proc           ; Declare external procs
  63. ;    global  FindBytePos:proc
  64. ;    global  FindAndReplace:proc
  65. ;    global  ByteCopy:proc
  66. ;    global  SkipSpaces:proc
  67.  
  68.     proc    IsDelimiter
  69.     ;   This routine checks the character in AL to see if it is a delimiter.
  70.     ;   Valid delimiters are   ''  ""  []
  71.     ;
  72.     ;   Input
  73.     ;       al - Character to check
  74.     ;   Output
  75.     ;       al contained a delimiter:
  76.     ;            al - matching delimiter
  77.     ;            Carry set
  78.     ;       al did not contain a delimiter
  79.     ;            Carry not set
  80.     ;   Calling conventions
  81.     ;       NA
  82.     ;   Registers modified
  83.     ;       al
  84.  
  85.         cmp     al,'"'
  86.         je      ItIs
  87.         cmp     al,"'"
  88.         je      ItIs
  89.         cmp     al,"]"
  90.         je      ItIs
  91.         cmp     al,"["
  92.         je      ItIsSquare
  93.         jmp     IsNot
  94.     ItIsSquare:
  95.         mov     al,"]"
  96.     ItIs:
  97.         stc
  98.         ret
  99.     IsNot:
  100.         clc
  101.         ret
  102.     endp    IsDelimiter
  103.  
  104.  
  105.  
  106.     ; Use the following pattern to look for trailing spaces.
  107.     label TrailingSpace word
  108.         db " ",0dh
  109.  
  110.  
  111.     proc    ParamCount
  112.  
  113.     ;   This routine returns the number of command line parameters passed to
  114.     ;   the program. Parameters are delimited by spaces or tabs. Double or
  115.     ;   single quotes can enclose parameters that include spaces or tabs
  116.     ;   inside them.
  117.     ;
  118.     ;   While the function is parsing the command line it stores copies of
  119.     ;   each of the parameters in the modules data segment. The strings are
  120.     ;   stored in Turbo Pascal format. That is they are stored with a
  121.     ;   preceeding length byte. The first time the routine is called it also
  122.     ;   stores the result in the variable ParmCount in the modules data
  123.     ;   segment. Any subsequent calls simply return the contents of
  124.     ;   ParmCount.
  125.     ;
  126.     ;   Input
  127.     ;       none
  128.     ;   Output
  129.     ;       al - Number of parameters
  130.     ;   Calling conventions
  131.     ;       NA
  132.     ;   Registers modified
  133.     ;       ax, bx, cx, DX, di, si, es, Flags
  134.  
  135.     local   SearchChar:byte=LocalSymbolSize ; Declare local variables
  136.  
  137.         ; Point es:di to location where the parsed parameters will be stored
  138.  
  139.         mov     ax, @data       ; Using near data model
  140.         mov     es, ax
  141.  
  142.         ; Check if the function was called previously. If it was we
  143.         ; don't want to parse the command line again.
  144.  
  145.         cmp     [es:ParmCount], NotCalled
  146.         je      FirstCall
  147.         jmp     AlreadyCalled
  148.  
  149.     FirstCall:
  150.         mov     di, offset ParmList ; es:di now points to modules storage
  151.         push    ds
  152.  
  153.         ; Note that we don't actually allocate any memory to store the
  154.         ; DOS Psp. We simply use the STRUC declaration to determine
  155.         ; the offsets of the fields in the memory allocated by DOS.
  156.  
  157.         mov     ds, [PspAddress]    ; Load the segment address of the Psp
  158.         mov     si, offset (Psp).CommandTail + 1
  159.  
  160.         xor     cx, cx              ; Initialize cx
  161.         xor     bx, bx              ; Store # of parameters in bx
  162.  
  163.  
  164.         ; Get the length of the DOS command line from the Psp.
  165.  
  166.         mov     cl, [ds:Psp.CommandTail.LengthByte]
  167.  
  168.         ; Check if the command line is empty and leave if it is.
  169.  
  170.         cmp     cl, 0
  171.         jne     ReplaceTabs
  172.         jmp     InitParmCount
  173.  
  174.     ReplaceTabs:
  175.  
  176.         ; Convert any tabs in the command line to spaces in order to
  177.         ; make the parsing simpler.
  178.  
  179.         push    cx  ; Store value of cx & es:di because call to
  180.         push    es  ; FindAndReplace modifies them.
  181.         push    di
  182.  
  183.         ; Push the address of the DOS command line
  184.  
  185.         push    ds
  186.         if (@Cpu and 100b) eq 100b
  187.             push    offset (Psp).CommandTail + 1
  188.         else
  189.             mov     ax, offset (Psp).CommandTail + 1
  190.             push    ax
  191.         endif
  192.  
  193.         ; Define the bytes to search/replace
  194.  
  195.         mov     ax, (SPACE shl 8) + TAB
  196.         call    FindAndReplace          ; Replace all tabs with spaces
  197.         pop     di es
  198.                                         ; Restore previous values of cx & es:di
  199.         pop     cx
  200.  
  201.  
  202.         ; Now we need to trim the end of the string
  203.  
  204.         mov     ax,[TrailingSpace]
  205.         mov     bx,cx
  206.  
  207.     CheckForTrailing:
  208.         cmp     ax,[si+bx-1]
  209.         jne     StringTrimmed           ; String trimmed, but some still left
  210.  
  211.         ; Space found at end, move the carriage return forward a byte
  212.         mov     [byte ptr si+bx-1],0dh
  213.         dec     cx
  214.         dec     bx
  215.         cmp     cl, 0
  216.         jne     CheckForTrailing
  217.  
  218.     StringTrimmed:
  219.         mov     bx,0                    ; Set it back to zero for counting
  220.                                         ; parameters
  221.  
  222.         jz      InitParmCount           ; If CL=0, then Z set.
  223.                                         ; If end of string, Z not set!
  224.  
  225.  
  226.         ; Skip any spaces at the beginning of the parameter list.
  227.  
  228.         push    es di                   ; Save registers that will be modified
  229.  
  230.         push    ds si                   ; Pass the address of the string
  231.         call    SkipSpaces
  232.         pop     si ds                   ; Update ds:si with start of next
  233.                                         ; parameter
  234.         pop     di es                   ; Restore es:di to point to location
  235.                                         ; to store the next parameter
  236.  
  237.         ; Now parse the command line. Note that after each iteration of
  238.         ; this loop ds:si points to the beginning of the next parameter
  239.         ; and es:di points to location in the modules data segment where
  240.         ; the next parameter will be stored.
  241.  
  242.     ParseCmdLine:
  243.         inc     bx                      ; Increment the parameter count
  244.         mov     al,[si]
  245.         call    IsDelimiter
  246.         jc      HandleDelimiter
  247.         jmp     WhiteSpace
  248.  
  249.     HandleDelimiter:
  250.         mov     [SearchChar], al
  251.         inc     si  ; Point to the next character in the parameter list
  252.         dec     cx  ; Adjust number of bytes left to check
  253.         jmp     FindDelimiter
  254.  
  255.     WhiteSpace:
  256.         mov     al, SPACE
  257.         mov     [SearchChar], al         ; Use space, tab or eoln as delimiter
  258.  
  259.     FindDelimiter:
  260.         push    bx es di                 ; Store bx, es:di
  261.  
  262.         ; Push the address of the start of the next parameter for the call
  263.         ; to FindBytePos
  264.  
  265.         push    ds
  266.         push    si
  267.  
  268.         ; Find the end of the parameter. After the call to FindBytePos
  269.         ; ax = the number of bytes searched and es:di is pointing to
  270.         ; the byte after the last one checked. cx=# of bytes left to
  271.         ; check in the command line string.
  272.  
  273.         call    FindBytePos
  274.         push    es                      ; Move the pointer returned by
  275.         pop     ds                      ; FindBytePos into ds:si
  276.         mov     si, di
  277.  
  278.         pop     di es bx                ; Restore es:di, bx
  279.  
  280.  
  281.     ; Now copy the parameter into its storage location
  282.  
  283.     CopyParameter:
  284.         mov     dx, si                  ; Calculate the offset of the source
  285.         sub     dx, ax                  ; string
  286.         dec     dx
  287.  
  288.         ; If there was a delimiter other than a space, we want to make
  289.         ; sure that we get the trailing delimiter too.
  290.         cmp     [SearchChar],SPACE
  291.         jne     BumpCopyCount
  292.  
  293.         or      cx,cx                   ; Check if CX=0 (If at end of arguments)
  294.         jnz     StoreLength
  295.  
  296.     BumpCopyCount:
  297.         inc     al   ; We need to copy and extra character
  298.  
  299.     StoreLength:
  300.         push    cx bx es si di          ; Save the values of registers
  301.                                         ; modified by the call to ByteCopy
  302.         mov     [byte es:di], al        ; Store length of parameter in
  303.         inc     di                      ; the length byte
  304.  
  305.         ; Copy the array of characters
  306.         call    ByteCopy,ds,dx,\  ; Source string
  307.                          es,di    ; Destination string
  308.  
  309.         pop     di si es bx cx          ; Restore the previous values of the
  310.                                         ; registers modified by ByteCopy
  311.         add     di, ax                  ; Move pointer past end of parameter
  312.         inc     di
  313.  
  314.         cmp     [byte ds:si], SPACE
  315.         jne     NoWhiteSpace
  316.  
  317.         ; Now find the first character of the next parameter.
  318.  
  319.         push    es di                   ; Save registers that will be modified
  320.  
  321.         push    ds si                   ; Pass the address of the string
  322.         call    SkipSpaces
  323.  
  324.         pop     si ds                   ; Update ds:si with start of next
  325.                                         ; parameter
  326.         pop     di es                   ; Restore es:di to point to location
  327.                                         ; to store the next parameter
  328.  
  329.     NoWhiteSpace:
  330.         jcxz    InitParmCount
  331.         jmp     ParseCmdLine            ; Get the next parameter on the
  332.                                         ; command line.
  333.     InitParmCount:
  334.  
  335.         ; Initialize ParmCount so the routine doesn't have to parse the
  336.         ; command line more than once.
  337.  
  338.         mov     [byte es:ParmCount], bl
  339.         pop     ds                      ; Restore the programs data segment
  340.  
  341.     AlreadyCalled:
  342.         mov     al, [byte es:ParmCount] ; Return the previously determined
  343.         ret
  344.     endp    ParamCount
  345.  
  346.     proc    ParamString
  347.  
  348.     ;   This routine returns a far pointer to the parameter referenced in
  349.     ;   al. Before looking for the parameter, the function calls ParamCount
  350.     ;   to assure that the parameter exists. This has the side-affect of
  351.     ;   assuring that ParamCount parses and copies the parameters into the
  352.     ;   modules data segment.
  353.     ;
  354.     ;   Input
  355.     ;       al - Parameter to return
  356.     ;   Output
  357.     ;       al = Desired Parameter
  358.     ;           es:di - Far pointer to parameter
  359.     ;       al = 0 - Parameter doesn't exist
  360.     ;   Calling conventions
  361.     ;       NA
  362.     ;   Registers modified
  363.     ;       ax, bx, cx, di, si, es, Flags
  364.  
  365.         ; First check if the parameter exists
  366.  
  367.         push    ax                  ; Save index to desired parameter
  368.         call    ParamCount
  369.         pop     bx                  ; Restore index to desired parameter
  370.         cmp     bl, al              ; Check if the parameter exists
  371.         jg      InvalidParameter
  372.         mov     al, bl              ; Pass parameter index in al
  373.  
  374.         ; Point to modules data segment
  375.         mov     bx, @data       ; Using near data model
  376.         mov     es, bx              ; Make es:si point to the data area
  377.         mov     di, offset ParmList
  378.  
  379.         call    LocateString        ; Determine the address of the string
  380.         jmp     Exit
  381.  
  382.     InvalidParameter:
  383.         xor     al, al
  384.  
  385.     Exit:
  386.         ret
  387.     endp    ParamString
  388.  
  389. endif   ; ifndef MDL
  390.  
  391. end
  392.  
  393.