summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/COMMAND/PARSE2.ASM
diff options
context:
space:
mode:
authorGravatar Mark Zbikowski2024-04-25 21:24:10 +0100
committerGravatar Microsoft Open Source2024-04-25 22:32:27 +0000
commit2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch)
tree80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/CMD/COMMAND/PARSE2.ASM
parentMerge pull request #430 from jpbaltazar/typoptbr (diff)
downloadms-dos-main.tar.gz
ms-dos-main.tar.xz
ms-dos-main.zip
MZ is back!HEADmain
Diffstat (limited to 'v4.0/src/CMD/COMMAND/PARSE2.ASM')
-rw-r--r--v4.0/src/CMD/COMMAND/PARSE2.ASM422
1 files changed, 422 insertions, 0 deletions
diff --git a/v4.0/src/CMD/COMMAND/PARSE2.ASM b/v4.0/src/CMD/COMMAND/PARSE2.ASM
new file mode 100644
index 0000000..2695927
--- /dev/null
+++ b/v4.0/src/CMD/COMMAND/PARSE2.ASM
@@ -0,0 +1,422 @@
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
16break <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
50DATARES SEGMENT PUBLIC BYTE
51 EXTRN FORFLAG:BYTE
52DATARES ENDS
53
54TRANSPACE 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
60TRANSPACE ENDS
61
62TRANCODE SEGMENT PUBLIC BYTE ;AC000;
63 PUBLIC argv_calc ; convert array index into address
64 PUBLIC parseline
65
66
67assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
68
69
70break <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
127TRANSPACE 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
133TRANSPACE ENDS
134
135;---------------
136parseline:
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
181pcont:
182 mov DI, OFFSET TRANGROUP:tpbuf ; destination is temporary token buffer
183 mov BL, ' ' ; no special delimiter, for now
184
185parseloop:
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
201More_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
207parsedone: ; successful completion of parseline
208 popf
209 clc
210 jmp short parse_exit
211
212parse_error: ; error entry (er, exit) point
213 popf
214 stc
215parse_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
229break <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;---------------
247newarg:
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
290newarg_done:
291 popf
292 clc
293 jmp short newarg_exit
294
295too_many_args:
296 mov AX, arg_cnt_error
297 jmp short newarg_error
298
299buf_ovflow:
300 mov AX, arg_buf_ovflow
301
302newarg_error:
303 popf
304 stc
305
306newarg_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
319break <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
344TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
345 extrn switch_list:byte
346 switch_count EQU $-switch_list
347transpace ends
348
349;---------------
350Arg_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
368arg_yes_switch: ; ah, sweet success...
369 popf
370 stc
371 jmp short arg_switch_exit
372
373arg_no_switch0:
374 mov AX, arg.argvcnt ; future switches should then affect
375 mov [LAST_ARG], AX ; this argument
376
377arg_no_switch1: ; wasn't a switch, or we're pretending
378 popf
379 clc
380
381arg_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
393break <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
405argv_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
421trancode ends
422 end