home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l224 / 2.img / TAEXMPL1.ZIP / IPARAM.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-10-29  |  13.3 KB  |  402 lines

  1.  
  2. ;   FILENAME: IPARAM.ASM
  3. ;
  4. ;   Copyright (c) 1988, 1990 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.         if  @DataSize   eq  0
  140.             mov     ax, @data       ; Using near data model
  141.         else
  142.             mov     ax, @fardata    ; Using far data model
  143.         endif
  144.         mov     es, ax
  145.  
  146.         ; Check if the function was called previously. If it was we
  147.         ; don't want to parse the command line again.
  148.  
  149.         cmp     [es:ParmCount], NotCalled
  150.         je      FirstCall
  151.         jmp     AlreadyCalled
  152.  
  153.     FirstCall:
  154.         mov     di, offset ParmList ; es:di now points to modules storage
  155.         push    ds
  156.  
  157.         ; Note that we don't actually allocate any memory to store the
  158.         ; DOS Psp. We simply use the STRUC declaration to determine
  159.         ; the offsets of the fields in the memory allocated by DOS.
  160.  
  161.         mov     ds, [PspAddress]    ; Load the segment address of the Psp
  162.         mov     si, offset (Psp).CommandTail + 1
  163.  
  164.         xor     cx, cx              ; Initialize cx
  165.         xor     bx, bx              ; Store # of parameters in bx
  166.  
  167.  
  168.         ; Get the length of the DOS command line from the Psp.
  169.  
  170.         mov     cl, [ds:Psp.CommandTail.LengthByte]
  171.  
  172.         ; Check if the command line is empty and leave if it is.
  173.  
  174.         cmp     cl, 0
  175.         jne     ReplaceTabs
  176.         jmp     InitParmCount
  177.  
  178.     ReplaceTabs:
  179.  
  180.         ; Convert any tabs in the command line to spaces in order to
  181.         ; make the parsing simpler.
  182.  
  183.         push    cx  ; Store value of cx & es:di because call to
  184.         push    es  ; FindAndReplace modifies them.
  185.         push    di
  186.  
  187.         ; Push the address of the DOS command line
  188.  
  189.         push    ds
  190.         if (@Cpu and 100b) eq 100b
  191.             push    offset (Psp).CommandTail + 1
  192.         else
  193.             mov     ax, offset (Psp).CommandTail + 1
  194.             push    ax
  195.         endif
  196.  
  197.         ; Define the bytes to search/replace
  198.  
  199.         mov     ax, (SPACE shl 8) + TAB
  200.         call    FindAndReplace          ; Replace all tabs with spaces
  201.         pop     di es
  202.                                         ; Restore previous values of cx & es:di
  203.         pop     cx
  204.  
  205.  
  206.         ; Now we need to trim the end of the string
  207.  
  208.         mov     ax,[TrailingSpace]
  209.         mov     bx,cx
  210.  
  211.     CheckForTrailing:
  212.         cmp     ax,[si+bx-1]
  213.         jne     StringTrimmed           ; String trimmed, but some still left
  214.  
  215.         ; Space found at end, move the carriage return forward a byte
  216.         mov     [byte ptr si+bx-1],0dh
  217.         dec     cx
  218.         dec     bx
  219.         cmp     cl, 0
  220.         jne     CheckForTrailing
  221.  
  222.     StringTrimmed:
  223.         mov     bx,0                    ; Set it back to zero for counting
  224.                                         ; parameters
  225.  
  226.         jz      InitParmCount           ; If CL=0, then Z set.
  227.                                         ; If end of string, Z not set!
  228.  
  229.  
  230.         ; Skip any spaces at the beginning of the parameter list.
  231.  
  232.         push    es di                   ; Save registers that will be modified
  233.  
  234.         push    ds si                   ; Pass the address of the string
  235.         call    SkipSpaces
  236.         pop     si ds                   ; Update ds:si with start of next
  237.                                         ; parameter
  238.         pop     di es                   ; Restore es:di to point to location
  239.                                         ; to store the next parameter
  240.  
  241.         ; Now parse the command line. Note that after each iteration of
  242.         ; this loop ds:si points to the beginning of the next parameter
  243.         ; and es:di points to location in the modules data segment where
  244.         ; the next parameter will be stored.
  245.  
  246.     ParseCmdLine:
  247.         inc     bx                      ; Increment the parameter count
  248.         mov     al,[si]
  249.         call    IsDelimiter
  250.         jc      HandleDelimiter
  251.         jmp     WhiteSpace
  252.  
  253.     HandleDelimiter:
  254.         mov     [SearchChar], al
  255.         inc     si  ; Point to the next character in the parameter list
  256.         dec     cx  ; Adjust number of bytes left to check
  257.         jmp     FindDelimiter
  258.  
  259.     WhiteSpace:
  260.         mov     al, SPACE
  261.         mov     [SearchChar], al         ; Use space, tab or eoln as delimiter
  262.  
  263.     FindDelimiter:
  264.         push    bx es di                 ; Store bx, es:di
  265.  
  266.         ; Push the address of the start of the next parameter for the call
  267.         ; to FindBytePos
  268.  
  269.         push    ds
  270.         push    si
  271.  
  272.         ; Find the end of the parameter. After the call to FindBytePos
  273.         ; ax = the number of bytes searched and es:di is pointing to
  274.         ; the byte after the last one checked. cx=# of bytes left to
  275.         ; check in the command line string.
  276.  
  277.         call    FindBytePos
  278.         push    es                      ; Move the pointer returned by
  279.         pop     ds                      ; FindBytePos into ds:si
  280.         mov     si, di
  281.  
  282.         pop     di es bx                ; Restore es:di, bx
  283.  
  284.  
  285.     ; Now copy the parameter into its storage location
  286.  
  287.     CopyParameter:
  288.         mov     dx, si                  ; Calculate the offset of the source
  289.         sub     dx, ax                  ; string
  290.         dec     dx
  291.  
  292.         ; If there was a delimiter other than a space, we want to make
  293.         ; sure that we get the trailing delimiter too.
  294.         cmp     [SearchChar],SPACE
  295.         jne     BumpCopyCount
  296.  
  297.         or      cx,cx                   ; Check if CX=0 (If at end of arguments)
  298.         jnz     StoreLength
  299.  
  300.     BumpCopyCount:
  301.         inc     al   ; We need to copy and extra character
  302.  
  303.     StoreLength:
  304.         push    cx bx es si di          ; Save the values of registers
  305.                                         ; modified by the call to ByteCopy
  306.         mov     [byte es:di], al        ; Store length of parameter in
  307.         inc     di                      ; the length byte
  308.  
  309.         ; Copy the array of characters
  310.         call    ByteCopy,ds,dx,\  ; Source string
  311.                          es,di    ; Destination string
  312.  
  313.         pop     di si es bx cx          ; Restore the previous values of the
  314.                                         ; registers modified by ByteCopy
  315.         add     di, ax                  ; Move pointer past end of parameter
  316.         inc     di
  317.  
  318.         cmp     [byte ds:si], SPACE
  319.         jne     NoWhiteSpace
  320.  
  321.         ; Now find the first character of the next parameter.
  322.  
  323.         push    es di                   ; Save registers that will be modified
  324.  
  325.         push    ds si                   ; Pass the address of the string
  326.         call    SkipSpaces
  327.  
  328.         pop     si ds                   ; Update ds:si with start of next
  329.                                         ; parameter
  330.         pop     di es                   ; Restore es:di to point to location
  331.                                         ; to store the next parameter
  332.  
  333.     NoWhiteSpace:
  334.         jcxz    InitParmCount
  335.         jmp     ParseCmdLine            ; Get the next parameter on the
  336.                                         ; command line.
  337.     InitParmCount:
  338.  
  339.         ; Initialize ParmCount so the routine doesn't have to parse the
  340.         ; command line more than once.
  341.  
  342.         mov     [byte es:ParmCount], bl
  343.         pop     ds                      ; Restore the programs data segment
  344.  
  345.     AlreadyCalled:
  346.         mov     al, [byte es:ParmCount] ; Return the previously determined
  347.         ret
  348.     endp    ParamCount
  349.  
  350.     proc    ParamString
  351.  
  352.     ;   This routine returns a far pointer to the parameter referenced in
  353.     ;   al. Before looking for the parameter, the function calls ParamCount
  354.     ;   to assure that the parameter exists. This has the side-affect of
  355.     ;   assuring that ParamCount parses and copies the parameters into the
  356.     ;   modules data segment.
  357.     ;
  358.     ;   Input
  359.     ;       al - Parameter to return
  360.     ;   Output
  361.     ;       al = Desired Parameter
  362.     ;           es:di - Far pointer to parameter
  363.     ;       al = 0 - Parameter doesn't exist
  364.     ;   Calling conventions
  365.     ;       NA
  366.     ;   Registers modified
  367.     ;       ax, bx, cx, di, si, es, Flags
  368.  
  369.         ; First check if the parameter exists
  370.  
  371.         push    ax                  ; Save index to desired parameter
  372.         call    ParamCount
  373.         pop     bx                  ; Restore index to desired parameter
  374.         cmp     bl, al              ; Check if the parameter exists
  375.         jg      InvalidParameter
  376.         mov     al, bl              ; Pass parameter index in al
  377.  
  378.         ; Point to modules data segment
  379.  
  380.         if  @DataSize   eq  0
  381.             mov     bx, @data       ; Using near data model
  382.         else
  383.             mov     bx, @fardata    ; Using far data model
  384.         endif
  385.         mov     es, bx              ; Make es:si point to the data area
  386.         mov     di, offset ParmList
  387.  
  388.         call    LocateString        ; Determine the address of the string
  389.         jmp     Exit
  390.  
  391.     InvalidParameter:
  392.         xor     al, al
  393.  
  394.     Exit:
  395.         ret
  396.     endp    ParamString
  397.  
  398. endif   ; ifndef MDL
  399.  
  400. end
  401.  
  402.