; *Not* the original file, but an edit to turn it into an includable slice. ; Changes include: ; * removal of RULES.ASI to eliminate redundancy ; * removal of external data and function references (and subsequent ; correction of their symbols in the code) ; * code for non-text segments being moved to separate slices ; * and two changes specific to the Japanese / PC-98 version. These are: ; * BadProgName moved in front of NextChar ; * and an additional section in NextChar to check for DBCS lead bytes ;[]-----------------------------------------------------------------[] ;| SETARGV.ASM -- Parse Command Line | ;[]-----------------------------------------------------------------[] ; ; C/C++ Run Time Library - Version 5.0 ; ; Copyright (c) 1987, 1992 by Borland International ; All Rights Reserved. ; SUBTTL Parse Command Line PAGE ;/* */ ;/*-----------------------------------------------------*/ ;/* */ ;/* Parse Command Line */ ;/* ------------------ */ ;/* */ ;/*-----------------------------------------------------*/ ;/* */ PSPCmd equ 00080h SavedDS dw ? ifdef WILD ;------------------------------------------------------------------------------ ; ; Not enough space on stack for the program name. ; BadProgName label near jmp abort@ public __wildargv __wildargv proc near else __setargv proc near endif ;============================================================================== ; First, save caller context and Return Address ; Please be aware that this code was hacked from TC 2.0 to work with the ; new startup/exit method. Since setargv tries to put the arguments on ; the stack it has to make an assumption about what is already on the ; stack. Under 2.0 all that was on the stack was the return address into ; the startup code. Under the new startup/exit method there is a return ; address (always near), a saved DS, and another near return address. ; setargv really needs to be rewritten but for now this hack is in place ; to make it work. If you change what is on the stack in any way you will ; have to change this code! pop word ptr SavedReturn pop word ptr SavedDS2 pop word ptr SavedReturn2 mov SavedDS, ds mov SavedSI, si mov SavedDI, di cld ; Compute Command Line size mov es, _psp@ mov si, PSPCmd ; ES: SI = Command Line address xor ah, ah lods byte ptr es:[si] inc ax ; AX = Command Line size including \r mov bp, es xchg dx, si ; BP:DX = Command Line address xchg bx, ax ; BX = Command line size ; Compute Program Name size mov si, _envLng@ inc si inc si ; SI = Program name offset mov cx, 1 ; CX = Filename size (includes \0) cmp _osmajor@, 3 jb NoProgramName mov es, _envseg@ mov di, si ; SI = argv[0] address mov cl, 07fh xor al, al repnz scasb jcxz BadProgName xor cl, 07fh ; CX = Filename size (includes \0) NoProgramName label near ; Reserve space for the arguments push ax ; To be sure nothing in SS:FFFF mov ax, cx ifndef WILD add ax, bx endif inc ax and ax, not 1 mov di, sp sub di, ax jb BadProgName mov sp, di ; SS:DI = Command Line storage address ; Copy ProgName to the stack push es pop ds push ss pop es ifndef WILD push cx endif dec cx rep movsb xor al, al stosb ; ASCIIZ string ; Process Command Line. ;============================================================================== ifdef WILD ;============================================================================== ; ; The value of "wild_attr" is used in the "findfirst" call as the file ; attribute. ; ; The default value is 0, which will only include "regular" files. ; ; Adding 10H to this value will include directories, 04h will include system ; files, and 02h will include hidden files. ; wild_attr equ 0 ; include only regular files ;------------------------------------------------------------------------------ ffblk struc ff_reserved db 21 dup (?) ff_attrib db ? ff_ftime dw ? ff_fdate dw ? ff_fsize dd ? ff_name db 14 dup (?) ffblk ends wild_init_space equ 128 ; initial buffer allocation wild_more_space equ 256 ; buffer size increment ;------------------------------------------------------------------------------ wild_buff_addr equ [bp] wild_buff_size equ [bp+4] wild_buff_max equ [bp+6] wild_arg_src equ [bp+8] wild_arg_dst equ [bp+10] wild_argument equ [bp+12] wild_destin equ [bp+16] wild_path_len equ [bp+20] wild_argc equ [bp+22] wild_DTA_save equ [bp+24] wild_ffblk equ [bp+28] wild_frame_size equ 28 + TYPE ffblk ;------------------------------------------------------------------------------ mov cx, bp ; save segment of command line dec bx ; don't need trailing \0 sub sp, wild_frame_size mov bp, sp ; bp points at local variables push dx ; save cmd line addr push cx ; save cmd line seg push bx ; save cmd line size mov ax, wild_init_space mov wild_buff_size, ax ; save initial size ifndef __HUGE__ mov ds, SavedDS endif push ax call sbrk@ pop cx ; toss parameter pop cx ; restore cmd line size pop ds ; restore cmd line seg pop si ; restore cmd line addr mov wild_buff_addr, ax ; save offset if LDATA mov wild_buff_addr+2, dx ; save segment and ax, dx else mov wild_buff_addr+2, ss ; seg = SS endif cmp ax, -1 je NoSbrkSpace ; abort if not enough space add ax, wild_buff_size mov wild_buff_max, ax ; save max offset mov ah, 2fh int 21h ; get current DTA mov wild_DTA_save, bx mov wild_DTA_save+2, es push ds push ss ; fflbk is on stack pop ds lea dx, wild_ffblk mov ah, 1ah int 21h ; switch DTA to ffblk pop ds les di, dword ptr wild_buff_addr xor dx, dx ; dx = # of arguments ; ; Start new argument. ; NewArg: mov wild_arg_dst, di xor bh, bh ; bh = wildcard flag ; ; Skip leading whitespace. ; ArgCopy: mov wild_arg_src, si ; save address of argument call GetChar jc ArgCopyDone ; jump if no more characters jz ArgCopyLoop cmp al, ' ' je ArgCopy ; skip whitespace cmp al, 9 je ArgCopy cmp al, 13 je ArgCopy cmp al, '"' je ArgQuote ; jump if quoted string ; ; Loop to copy unquoted argument. ; ArgCopyLoop: call ArgPushChar ; store character in destination call GetChar jc ArgComplete ; jump if end of line jz ArgCopyLoop ; jump if \" cmp al, ' ' je ArgComplete ; whitespace terminates cmp al, 9 je ArgComplete cmp al, 13 je ArgComplete ; whitespace terminates cmp al, '"' jne ArgCopyLoop ArgComplete: call ProcessArg ; copy or expand argument jmp SHORT NewArg NoSbrkSpace: jmp abort@ ; error jump ; ; Here if quoted argument. ; ArgQuote: call GetChar jc QuoteDone jz QuoteNext cmp al, '"' ; terminating quote ? je QuoteDone cmp al, 13 ; hit end of line (CR)? je QuoteDone QuoteNext: call ArgPushChar ; store character in destination jmp SHORT ArgQuote ; ; End of a quoted argument. Push terminating null, do not expand. ; QuoteDone: xor al, al call ArgPushChar ; push terminating null inc dx ; bump arg count jmp SHORT NewArg ; go get more ;------------------------------------------------------------------------------ ; ; Here when done expanding command line. Go build the argv array. ; ArgCopyDone: mov ax, di ; ax = unused space sub ax, wild_buff_max jz ArgNoWaste ; skip if all used push dx push di ifndef __HUGE__ mov ds, SavedDS endif push ax call sbrk@ ; release unused memory pop cx ; toss parameter pop di pop dx ArgNoWaste: lds si, dword ptr wild_buff_addr mov cx, di sub cx, si ; cx = number of bytes in expanded line inc dx ; count program name jmp BuildArgv ;------------------------------------------------------------------------------ ; ; Routine to retrieve the next character from the command line. ; Sets CF when end of line reached. ; Sets ZF when \ character found (i.e. \") ; ; bh.bit0 set if wildcard chars found (* or ?) ; bh.bit1 set if \ character found (\") ; GetChar proc near jcxz GchEnd ; jump if no more lodsb dec cx cmp al, '\' ; escape ? je GchEsc cmp al, '?' je GchWild cmp al, '*' je GchWild GchRet: or ah, 1 ; clear CF and ZF ret GchWild: test bh, bh jnz GchRet ; give up if \" has been found or bh, 1 ret GchEsc: jcxz GchRet ; check for \ at end of line cmp byte ptr [si],'"' jne GchRet ; only \" is special lodsb dec cx mov bh, 2 ; set \ flag xor ah, ah ; clear CF, set ZF ret GchEnd: stc ret GetChar endp ;------------------------------------------------------------------------------ ; ; Routine to expand a wildcard parameter. ; ; DS:SI = argument address ; ES:DI = destination ; Returns: ; CX = number of expanded arguments (0 = no match) ; WildExpand proc near push ds mov wild_argument, si mov wild_argument+2, ds mov wild_destin, di mov wild_destin+2, es mov word ptr wild_argc, 0 ; ; Find the length of the path prefix, if any. ; mov bx, si WildFindPath: lodsb and al, al jz WildEndPath cmp al, '\' je WildDelimiter cmp al, ':' je WildDelimiter cmp al, '\' jne WildFindPath WildDelimiter: mov bx, si ; save addr past last delimiter jmp SHORT WildFindPath WildEndPath: sub bx, wild_argument mov wild_path_len, bx mov ah, 4eh mov cx, wild_attr ; file attribute lds dx, dword ptr wild_argument int 21h ; find first matching file ... jc WildDone ; ; We have a matching file. Add it to the destination string (unless "." or "..") ; WildAddArg: ; ; If directories are included (10h set in wild_attr), ignore "." and ".." ; if wild_attr AND 16 push ss pop ds lea si,wild_ffblk.ff_name cmp byte ptr [si],'.' ; skip if doesn't start with "." jne WildNoDir cmp byte ptr [si+1],0 ; check for "." je WildNameNext cmp word ptr [si+1],'.' ; check for ".." je WildNameNext WildNoDir: endif inc word ptr wild_argc les di, dword ptr wild_destin mov cx, wild_path_len ; prefix filename with path jcxz WildCopyName lds si, dword ptr wild_argument WildCopyPath: lodsb call ArgPushChar loop WildCopyPath WildCopyName: lea si,wild_ffblk.ff_name ; copy filename from ffblk WildNameLoop: lods byte ptr ss:[si] push ax call ArgPushChar ; store char in destination pop ax and al, al ; continue until \0 jnz WildNameLoop mov wild_destin, di WildNameNext: mov ah, 4fh int 21h ; find next matching file jnc WildAddArg ; ; Done with expansion. Restore ES:DI, set CX, and return. ; WildDone: mov cx, wild_argc les di, dword ptr wild_destin pop ds ret WildExpand endp ;------------------------------------------------------------------------------ ; ; Routine to store a character in the destination string. ; ArgPushChar proc near cmp di, wild_buff_max ; space available ? jae ArgMoreSpace stosb ; yes --> store character ret ; ; No more argument space. Grab some more memory through sbrk. ; ArgMoreSpace: push ds push es push si push di push ax push bx push cx push dx ifndef __HUGE__ mov ds, SavedDS endif mov ax, wild_more_space add wild_buff_size, ax ; bump allocated size add wild_buff_max, ax ; bump end pointer push ax call sbrk@ pop cx if LDATA and ax, dx endif cmp ax, -1 je NoArgSpace ; abort if not enough space pop dx pop cx pop bx pop ax pop di pop si pop es pop ds stosb ; store character ret ArgPushChar endp ;------------------------------------------------------------------------------ ; ; Not enough space to process the command line .... abort. ; NoArgSpace: jmp abort@ ;------------------------------------------------------------------------------ ; ; Routine to process an argument. ; ProcessArg proc near push bx xor al, al call ArgPushChar ; null-terminate pop bx test bh, 1 ; wildcards present ? jnz ArgWild inc dx ; bump arg count ret ; ; We have a wildcard argument. Expand it. ; ArgWild: push cx push [si] ; save word following argument mov byte ptr [si],0 ; null-terminate argument xchg si, wild_arg_src ; si = argument address push di mov di, wild_arg_dst push dx call WildExpand pop dx pop bx and cx, cx ; see if any matched jnz ArgWildSome mov di, bx ; none ---> use unexpanded argument mov cx, 1 ; bump arg count by 1 ArgWildSome: add dx, cx mov si, wild_arg_src pop [si] ; restore word following argument pop cx ret ProcessArg endp ;------------------------------------------------------------------------------ ; ; Build the argv array. [DS:SI] is the expanded command line, CX its length. ; DX has the number of arguments (including the program name). ; BuildArgv: push ds push dx lds dx, dword ptr wild_DTA_save mov ah, 1ah int 21h ; switch to original DTA pop dx pop ds add sp, wild_frame_size ; remove local variables mov es,SavedDS mov es:[DGROUP:_argc@], dx inc dx ; argv ends with a NULL pointer shl dx, 1 ; argc * 2 (LDATA = 0) IF LDATA shl dx, 1 ; argc * 4 (LDATA = 1) ENDIF mov bx, sp ; point to program name mov bp, sp sub bp, dx jb NoArgSpace mov sp, bp ; SS:BP = argv array address mov word ptr es:[DGROUP:_argv@], bp IF LDATA mov word ptr es:[DGROUP:_argv@+2], ss ENDIF mov [bp], bx ; set argv[0] to program name IF LDATA mov [bp+2], ss ; program name is on the stack ENDIF add bp, dPtrSize SetArgvX label near jcxz SetLastArg mov [bp], si ; Set argv[n] IF LDATA mov [bp+2], ds ENDIF add bp, dPtrSize CopyArg label near lodsb or al, al loopnz CopyArg jz SetArgvX SetLastArg label near xor ax, ax mov [bp], ax IF LDATA mov [bp+2], ax ENDIF mov ds, SavedDS ;============================================================================== else ;============================================================================== mov ds, bp xchg si, dx ; DS: SI = Command Line address xchg bx, cx ; CX = Command Line size including \r mov ax, bx mov dx, ax ; AX = BX = DX = 0 inc bx ; BX = Nb of arguments (at least 1) Processing label near call NextChar ja NotQuote ; Not a quote and there are more InString label near jb BuildArgv ; Command line is empty now cmp al, 13 je EndArgument call NextChar ; \r is an argument separator ja InString ; Not a quote and there are more NotQuote label near cmp al, ' ' je EndArgument ; Space is an argument separator cmp al, 13 je EndArgument ; \r is an argument separator cmp al, 9 jne Processing ; \t is an argument separator EndArgument label near xor al, al ; Space and TAB are argument separators jmp short Processing ; Invalid program name BadProgName label near nop ; PC-98 / Japanese-specific nop ; PC-98 / Japanese-specific jmp __abort ; Character test function used in SetArgs ; On entry AL holds the previous character ; On exit AL holds the next character ; ZF on if the next character is quote (") and AL = 0 ; CF on if end of command line and AL = 0 NextChar PROC NEAR or ax, ax jz NextChar0 inc dx ; DX = Actual length of CmdLine stosb or al, al jnz NextChar0 inc bx ; BX = Number of parameters NextChar0 label near xchg ah, al xor al, al stc jcxz NextChar2 ; End of command line --> CF ON lodsb dec cx ; PC-98 / Japanese-specific code below... ; --- cmp dh, 1 jz NextCharSJIS0 xor dh, dh push ax push bx push cx push dx push ds push es mov ds, SavedDS push ax nopcall ___path_isdbcsleadbyte or ax, ax pop cx pop es pop ds pop dx pop cx pop bx pop ax jz NextCharSJIS1 NextCharSJIS0: inc dh NextCharSJIS1: cmp dh, 0 jnz NextChar1 ; --- sub al, '"' jz NextChar2 ; Quote found --> AL = 0 and ZF ON add al, '"' cmp al,'\' jne NextChar1 ; It is not a \ cmp byte ptr ds:[si], '"' jne NextChar1 ; Only " is transparent after \ lodsb dec cx NextChar1 label near or si, si ; Be sure both CF & ZF are OFF NextChar2 label near ret NextChar ENDP ; Now, build the argv array BuildArgv label near pop cx xor dh, dh ; PC-98 / Japanese-specific add cx, dx ; CX = Argument area size mov ds, SavedDS mov _argc@, bx inc bx ; argv ends with a NULL pointer add bx, bx ; argc * 2 (LDATA = 0) IF LDATA add bx, bx ; argc * 4 (LDATA = 1) ENDIF mov si, sp mov bp, sp sub bp, bx jb BadProgName mov sp, bp ; SS:BP = argv array address mov word ptr _argv@, bp IF LDATA mov word ptr _argv@+2, ss ENDIF SetArgvX label near jcxz SetLastArg mov [bp], si ; Set argv[n] IF LDATA mov [bp+2], ss ENDIF add bp, dPtrSize CopyArg label near lods byte ptr ss:[si] or al, al loopnz CopyArg jz SetArgvX SetLastArg label near xor ax, ax mov [bp], ax IF LDATA mov [bp+2], ax ENDIF ;============================================================================== endif ; ifdef WILD ;============================================================================== ; Restore caller context and exit mov ds,SavedDS mov si,SavedSI mov di,SavedDI push word ptr SavedReturn2 push word ptr SavedDS2 mov ax,__argc mov __C0argc,ax IF LDATA mov ax,word ptr __argv+2 mov word ptr __C0argv+2,ax ENDIF mov ax,word ptr __argv mov word ptr __C0argv,ax jmp word ptr SavedReturn endp