]>
wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/COMMAND/PARSE2.ASM
2 ; SCCSID = @(#)parse.asm 1.1 85/05/14
3 ; SCCSID = @(#)parse.asm 1.1 85/05/14
17 ;----------------------------------------------------------------------------
18 ; PARSE.ASM contains the routines to perform command line parsing.
19 ; Parse and Path share a buffer and argv[] definitions.
20 ; Invoking <Parseline> maps the unparsed command line in COMBUF into an
21 ; array of pointers to the parsed tokens. The resulting array, argv[],
22 ; also contains extra information provided by cparse about each token
23 ; <Parseline> should be executed prior to <Path_Search>
25 ; Alan L, OS/MSDOS August 15, 1983
29 ; <Parseline>: command line in COMTAB.
31 ; <Parseline>: success flag, argcnt (number of args), argv[].
33 ; * <Argv_calc> handily turns an array index into an absolute pointer.
34 ; The computation depends on the size of an argv[] element (arg_ele).
35 ; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
36 ; does not function as specified; see <Parseline> for more details.
37 ; * <Parseline> now knows about the flags the internals of COMMAND.COM
38 ; need to know about. This extra information is stored in a switch_flag
39 ; word with each command-line argument; the switches themselves will not
40 ; appear in the resulting arg structure.
41 ; * With the exception of CARRY, flags are generally preserved across calls.
45 DEBUGx equ FALSE
; prints out debug info
50 DATARES
SEGMENT PUBLIC BYTE
54 TRANSPACE
SEGMENT PUBLIC BYTE ;AC000;
57 EXTRN expand_star
:byte
62 TRANCODE
SEGMENT PUBLIC BYTE ;AC000;
63 PUBLIC argv_calc
; convert array index into address
67 assume
cs:trangroup
, ds:trangroup
, es:trangroup
, ss:nothing
70 break <Parseline
: Munch
on the command line
>
71 ;----------------------------------------------------------------------------
72 ; PARSELINE takes an MSDOS command line and maps it into a UNIX-style
73 ; argv[argvcnt] array. The most important difference between this array and
74 ; the tradition UNIX format is the extra cparse information included with
75 ; each argument element.
78 ; (BL special delimiter for cparse -- not implemented)
82 ; AL error code (carry set). Note AH clobbered in any event.
83 ; argv[] array of cparse flags and pointers to arguments
84 ; argvcnt argument count
87 ; * BL (special delimiter) is ignored, for now (set to space).
88 ; * Parseflags record contains cparse flags, as follows:
89 ; sw_flag -- was this arg a switch?
90 ; wildcard -- whether or not it contained a * or ?
91 ; path_sep -- maybe it was a pathname
92 ; unused -- for future expansion
93 ; special_delim -- was there an initial special delimiter?
94 ; * argv[] and argvcnt are undefined if CF/AL indicates an error.
95 ; * Relationship between input, cparse output, and comtail can be
96 ; found in the following chart. Despite the claim of the cparse
97 ; documentation that, "Token buffer always starts d: for non switch
98 ; tokens", such is not the case (see column two, row two).
99 ; Similarly, [STARTEL] is not null when the command line is one of
100 ; the forms, "d:", "d:\", or "d:/". In fact, *STARTEL (i.e., what
101 ; STARTEL addresses) will be null. This is clearly just a
102 ; documentation error.
103 ; * cparse also returns a switch code in BP for each switch it
104 ; recognizes on the command line.
105 ; * arglen for each token does NOT include the terminating null.
106 ; * Finally, note that interesting constructions like 'foodir/*.exe'
107 ; parse as three separate tokens, and the asterisk is NOT a wildcard.
108 ; For example, 'for %i in (foodir/*.exe) do echo %i' will first
109 ; echo 'foodir', then '*', then '.exe'. Using cparse for command-
110 ; line parsing may result in slightly different behavior than
111 ; previously observed with the old COMMAND.COM command-line parser.
113 ; Input Cparse Command Line (80H)
114 ; \alan\foo.bat c:\alan\foo.bat \alan\foo.bat
115 ; alan\foo.bat alan\foo.bat alan\foo.bat
116 ; foo.bat foo.bat foo.bat
117 ; c:\alan\foo.bat c:\alan\foo.bat c:\alan\foo.bat
118 ; c:alan\foo.bat c:alan\foo.bat c:alan\foo.bat
119 ; c:foo.bat c:foo.bat c:foo.bat
127 TRANSPACE
SEGMENT PUBLIC BYTE ;AC000;
139 push AX ; most of these are clobbered
140 push BX ; by cparse...
146 mov cpyflag
,0 ; Turn "CPARSE called from COPY flag" off
148 mov [LAST_ARG
], -1 ; last argument at which to accumulate
151 mov di,offset trangroup
:arg
153 mov argbufptr
,offset trangroup
:arg
.argbuf
154 mov arg
.argswinfo
, 0 ; switch information, and info to date
155 mov arg
.argvcnt
, 0 ; initialize argvcnt/argv[]
156 mov SI, OFFSET TRANGROUP
:combuf
+2 ; prescan leaves cooked input in combuf
158 ; This next section of code (up to pcont:) makes sure that si is set up for
159 ; parsing. It should point at COMBUF if FORFLAG is set and arg.argforcombuf
160 ; otherwise. This is done so that commands can get arg pointers into their
161 ; original command line (or an exact copy of it) in arg_ocomptr.
162 ; Arg.argforcombuf is used so that the for loop processor will always be able
163 ; to get a hold of its original command line; even after COMBUF is blasted by
164 ; the command to be repeated or the transient part of command has been
174 mov di,OFFSET TRANGROUP
:arg
.argforcombuf
179 mov si,OFFSET TRANGROUP
:arg
.argforcombuf
182 mov DI, OFFSET TRANGROUP
:tpbuf
; destination is temporary token buffer
183 mov BL, ' ' ; no special delimiter, for now
186 mov comptr
,si ; save ptr into original command buffer
187 xor BP, BP ; switch information put here by cparse
188 mov byte ptr [expand_star
],0 ; don't expand *'s to ?'s
189 invoke scanoff
; skip leading blanks...
190 invoke cparse
; byte off a token (args in SI, DI, BL)
192 or BP,BP ; Check for trailing switch character
194 call newarg
; We hit CR but BP is non-zero. The
195 ; typical cause of this is that a
196 ; switch char IMMEDIATELY preceeds
197 ; the CR. We have an argument, but it
198 ; is sort of an error.
199 jmp short parsedone
; We're done (found the CR).
202 mov cpyflag
,2 ; tell CPARSE that 1st token is done
203 call newarg
; add to argv array (CX has char count)
204 jnc parseloop
; was everything OK?
205 jmp short parse_error
; NO, it wasn't -- bug out (CF set)
207 parsedone: ; successful completion of parseline
212 parse_error: ; error entry (er, exit) point
215 parse_exit: ; depend on not changing CF
226 ;----------------------------------------------------------------------------
230 ;----------------------------------------------------------------------------
231 ; NEWARG adds the supplied argstring and cparse data to arg.argv[].
234 ; CX character count in argstring
235 ; DI pointer to argstring
236 ; comptr ptr to starting loc of current token in original command
237 ; [STARTEL] cparse's answer to where the last element starts
239 ; argbufptr points to next free section of argbuffer
240 ; arg.argbuf contains null-terminated argument strings
241 ; arg.argvcnt argument count
242 ; arg.argv[] array of flags and pointers
243 ; arg.arg_ocomptr ptr to starting loc of current token in original command
245 ; AL carry set: error code; otherwise, zero
252 push DX ; one never knows, do one?
256 call arg_switch
; if it's a switch, record switch info
257 ; LEAVE SWITCH ON COMMAND LINE!!
258 ;;; jc newarg_done ; previous arg's switches -- and leave
260 cmp arg
.argvcnt
, ARGMAX
; check to ensure we've not
261 jge too_many_args
; exceeded array limits
262 mov DH, BH ; save argflags
263 mov BX, arg
.argvcnt
; argv[argvcnt++] = arg data
265 mov AX, OFFSET TRANGROUP
:arg
.argv
266 call argv_calc
; convert offset to pointer
267 mov [BX].argsw_word
, 0 ; no switch information, yet...
268 mov [BX].arglen
, CX ; argv[argvcnt].arglen = arg length
269 mov [BX].argflags
, DH ; argv[argvcnt].argflags = cparse flags
271 mov [BX].argpointer
, SI ; argv[argvcnt].argpointer = [argbufptr]
272 add SI, [STARTEL
] ; save startel from new location
273 sub SI, DI ; form pointer into argbuf
274 mov [BX].argstartel
, SI ; argv[argvcnt].argstartel = new [STARTEL]
276 mov [BX].arg_ocomptr
,si ; arg_ocomptr=ptr into original com line
278 mov SI, DI ; now save argstring in argbuffer
279 mov DI, argbufptr
; load the argbuf pointer and make
280 add DI, CX ; sure we're not about to run off
281 cmp DI, OFFSET TRANGROUP
:arg
.argbuf
+ARGBLEN
-1
282 jge buf_ovflow
; the end of the buffer (plus null byte)
283 sub DI, CX ; adjust the pointer
285 rep movsb ; and save the string in argbuffer
286 mov AL, ANULL
; tack a null byte on the end
288 mov argbufptr
, DI ; update argbufptr after copy
293 jmp short newarg_exit
296 mov AX, arg_cnt_error
297 jmp short newarg_error
300 mov AX, arg_buf_ovflow
316 ;----------------------------------------------------------------------------
320 ;----------------------------------------------------------------------------
321 ; ARG_SWITCH decides if an argument might really be a switch. In the
322 ; event that it is, and we can recognize
326 ; CF -- clear (wasn't a switch); set (was a switch)
328 ; * The mechanism mapping a switch into a bit-value depends entirely
329 ; on the order of definition in the <switch_list> variable and the
330 ; values chosen to define the bits in CMDT:COMEQU.ASM. Change either
331 ; <switch_list> or the definitions in CMDT:COMEQU.ASM -- and rewrite
332 ; this mechanism. This code taken from CMDT:TCODE.ASM.
333 ; * The <switch_list> declared below is redundant to one declared in
334 ; TDATA.ASM, and used in TCODE.ASM.
339 ; Constants come from the definitions in CMDT:COMEQU.ASM.
344 TRANSPACE
SEGMENT PUBLIC BYTE ;AC000;
345 extrn switch_list
:byte
346 switch_count EQU
$-switch_list
358 test BH, MASK sw_flag
; is it a switch? (preserve flag word)
360 cmp [LAST_ARG
], -1 ; have we encountered any REAL args yet?
361 je arg_no_switch1
; no, so leading switches don't matter
362 mov BX, [LAST_ARG
] ; yes, add switch info to last REAL arg
363 mov AX, OFFSET TRANGROUP
:arg
.argv
365 or [BX].argsw_word
, BP
368 arg_yes_switch: ; ah, sweet success...
371 jmp short arg_switch_exit
374 mov AX, arg
.argvcnt
; future switches should then affect
375 mov [LAST_ARG
], AX ; this argument
377 arg_no_switch1: ; wasn't a switch, or we're pretending
390 ;----------------------------------------------------------------------------
394 ;----------------------------------------------------------------------------
395 ; ARGV_CALC maps an array index into a byte-offset from the base of
396 ; the supplied array. Method used for computing the address is:
397 ; Array Index * Array Elt Size + Base Addr = Elt Addr
399 ; AX -- base of array
407 mov al,bl ; al = array index
408 mov bl,SIZE argv_ele
; bl = size of an argv element
409 mul bl ; ax = base offset
411 add ax,bx ; Add in base offset
412 xchg ax,bx ; Restore ax and put byte offset in bx
417 ;----------------------------------------------------------------------------