home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / tasm / iparam.asm < prev    next >
Assembly Source File  |  1988-08-28  |  13KB  |  357 lines

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