]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/COMMAND/PARSE2.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / CMD / COMMAND / PARSE2.ASM
1 page 80,132
2 ; SCCSID = @(#)parse.asm 1.1 85/05/14
3 ; SCCSID = @(#)parse.asm 1.1 85/05/14
4 .sall
5 .xlist
6 .xcref
7 INCLUDE DOSSYM.INC
8 INCLUDE DEVSYM.INC
9 include comsw.asm
10 include comseg.asm
11 include comequ.asm
12 .list
13 .cref
14
15
16 break <Parse.Asm>
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>
24 ;
25 ; Alan L, OS/MSDOS August 15, 1983
26 ;
27 ;
28 ; ENTRY:
29 ; <Parseline>: command line in COMTAB.
30 ; EXIT:
31 ; <Parseline>: success flag, argcnt (number of args), argv[].
32 ; NOTE(S):
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.
42 ;---------------
43 ; CONSTANTS:
44 ;---------------
45 DEBUGx equ FALSE ; prints out debug info
46 ;---------------
47 ; DATA:
48 ;---------------
49
50 DATARES SEGMENT PUBLIC BYTE
51 EXTRN FORFLAG:BYTE
52 DATARES ENDS
53
54 TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
55 EXTRN combuf:byte
56 EXTRN cpyflag:byte
57 EXTRN expand_star:byte
58 EXTRN RESSEG:word
59 EXTRN STARTEL:word
60 TRANSPACE ENDS
61
62 TRANCODE SEGMENT PUBLIC BYTE ;AC000;
63 PUBLIC argv_calc ; convert array index into address
64 PUBLIC parseline
65
66
67 assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
68
69
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.
76 ;---------------
77 ; ENTRY:
78 ; (BL special delimiter for cparse -- not implemented)
79 ;---------------
80 ; EXIT:
81 ; CF set if error
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
85 ;---------------
86 ; NOTE(S):
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.
112 ;
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
120 ;---------------
121 ; CONSTANTS:
122 ;---------------
123 ;---------------
124 ; DATA:
125 ;---------------
126
127 TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
128 EXTRN arg:byte
129 EXTRN argbufptr:word
130 EXTRN comptr:word
131 EXTRN last_arg:word
132 EXTRN tpbuf:byte
133 TRANSPACE ENDS
134
135 ;---------------
136 parseline:
137 ;---------------
138
139 push AX ; most of these are clobbered
140 push BX ; by cparse...
141 push CX
142 push DX
143 push DI
144 push SI
145 pushf
146 mov cpyflag,0 ; Turn "CPARSE called from COPY flag" off
147
148 mov [LAST_ARG], -1 ; last argument at which to accumulate
149 xor ax,ax
150 mov cx,SIZE arg_unit
151 mov di,offset trangroup:arg
152 rep stosb
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
157
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
165 ; reloaded.
166
167 push ds
168 mov ds,[RESSEG]
169 assume ds:resgroup
170 cmp FORFLAG,0
171 pop ds
172 assume ds:trangroup
173 jnz pcont
174 mov di,OFFSET TRANGROUP:arg.argforcombuf
175 xor ch,ch
176 mov cl,[COMBUF+1]
177 inc cl
178 rep movsb
179 mov si,OFFSET TRANGROUP:arg.argforcombuf
180
181 pcont:
182 mov DI, OFFSET TRANGROUP:tpbuf ; destination is temporary token buffer
183 mov BL, ' ' ; no special delimiter, for now
184
185 parseloop:
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)
191 jnc More_prse
192 or BP,BP ; Check for trailing switch character
193 jz parsedone
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).
200
201 More_prse:
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)
206
207 parsedone: ; successful completion of parseline
208 popf
209 clc
210 jmp short parse_exit
211
212 parse_error: ; error entry (er, exit) point
213 popf
214 stc
215 parse_exit: ; depend on not changing CF
216 pop SI
217 pop DI
218 pop DX
219 pop CX
220 pop BX
221 pop AX
222 ret
223
224 ;---------------
225 ; parseline ends
226 ;----------------------------------------------------------------------------
227
228
229 break <NewArg>
230 ;----------------------------------------------------------------------------
231 ; NEWARG adds the supplied argstring and cparse data to arg.argv[].
232 ; ENTRY:
233 ; BH argflags
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
238 ; EXIT:
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
244 ; CF set if error
245 ; AL carry set: error code; otherwise, zero
246 ;---------------
247 newarg:
248 ;---------------
249
250 push BX
251 push CX
252 push DX ; one never knows, do one?
253 push DI
254 push SI
255 pushf
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
259
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
264 inc arg.argvcnt
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
270 mov SI, argbufptr
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]
275 mov si,[comptr]
276 mov [BX].arg_ocomptr,si ; arg_ocomptr=ptr into original com line
277
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
284 cld
285 rep movsb ; and save the string in argbuffer
286 mov AL, ANULL ; tack a null byte on the end
287 stosb
288 mov argbufptr, DI ; update argbufptr after copy
289
290 newarg_done:
291 popf
292 clc
293 jmp short newarg_exit
294
295 too_many_args:
296 mov AX, arg_cnt_error
297 jmp short newarg_error
298
299 buf_ovflow:
300 mov AX, arg_buf_ovflow
301
302 newarg_error:
303 popf
304 stc
305
306 newarg_exit:
307 pop SI
308 pop DI
309 pop DX
310 pop CX
311 pop BX
312 ret
313
314 ;---------------
315 ; NewArg ends
316 ;----------------------------------------------------------------------------
317
318
319 break <Arg_Switch>
320 ;----------------------------------------------------------------------------
321 ; ARG_SWITCH decides if an argument might really be a switch. In the
322 ; event that it is, and we can recognize
323 ; ENTRY:
324 ; As in <newarg>.
325 ; EXIT:
326 ; CF -- clear (wasn't a switch); set (was a switch)
327 ; NOTE(S):
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.
335 ; * An ugly routine.
336 ;---------------
337 ; CONSTANTS:
338 ;---------------
339 ; Constants come from the definitions in CMDT:COMEQU.ASM.
340 ;---------------
341 ; DATA:
342 ;---------------
343
344 TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
345 extrn switch_list:byte
346 switch_count EQU $-switch_list
347 transpace ends
348
349 ;---------------
350 Arg_Switch:
351 ;---------------
352
353 push AX
354 push BX
355 push CX
356 push DI
357 pushf
358 test BH, MASK sw_flag ; is it a switch? (preserve flag word)
359 jz arg_no_switch0
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
364 call argv_calc
365 or [BX].argsw_word, BP
366 or arg.argswinfo, BP
367
368 arg_yes_switch: ; ah, sweet success...
369 popf
370 stc
371 jmp short arg_switch_exit
372
373 arg_no_switch0:
374 mov AX, arg.argvcnt ; future switches should then affect
375 mov [LAST_ARG], AX ; this argument
376
377 arg_no_switch1: ; wasn't a switch, or we're pretending
378 popf
379 clc
380
381 arg_switch_exit:
382 pop DI
383 pop CX
384 pop BX
385 pop AX
386 ret
387
388 ;---------------
389 ; Arg_Switch ends
390 ;----------------------------------------------------------------------------
391
392
393 break <Argv_calc>
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
398 ; ENTRY:
399 ; AX -- base of array
400 ; BX -- array index
401 ; EXIT:
402 ; BX -- byte offset
403 ;---------------
404
405 argv_calc:
406 push ax ; Save base
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
410 pop bx ; Get base
411 add ax,bx ; Add in base offset
412 xchg ax,bx ; Restore ax and put byte offset in bx
413 ret
414
415 ;---------------
416 ; argv_calc ends
417 ;----------------------------------------------------------------------------
418
419
420
421 trancode ends
422 end