Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
13 KiB

  1. page ,132
  2. ;/*
  3. ; * Microsoft Confidential
  4. ; * Copyright (C) Microsoft Corporation 1991
  5. ; * All Rights Reserved.
  6. ; */
  7. ; SCCSID = @(#)parse.asm 1.1 85/05/14
  8. ; SCCSID = @(#)parse.asm 1.1 85/05/14
  9. .sall
  10. .xlist
  11. .xcref
  12. INCLUDE DOSSYM.INC
  13. INCLUDE DEVSYM.INC
  14. include comsw.asm
  15. include comseg.asm
  16. include comequ.asm
  17. .list
  18. .cref
  19. break <Parse.Asm>
  20. ;----------------------------------------------------------------------------
  21. ; PARSE.ASM contains the routines to perform command line parsing.
  22. ; Parse and Path share a buffer and argv[] definitions.
  23. ; Invoking <Parseline> maps the unparsed command line in COMBUF into an
  24. ; array of pointers to the parsed tokens. The resulting array, argv[],
  25. ; also contains extra information provided by cparse about each token
  26. ; <Parseline> should be executed prior to <Path_Search>
  27. ;
  28. ; Alan L, OS/MSDOS August 15, 1983
  29. ;
  30. ;
  31. ; ENTRY:
  32. ; <Parseline>: command line in COMTAB.
  33. ; EXIT:
  34. ; <Parseline>: success flag, argcnt (number of args), argv[].
  35. ; NOTE(S):
  36. ; * <Argv_calc> handily turns an array index into an absolute pointer.
  37. ; The computation depends on the size of an argv[] element (arg_ele).
  38. ; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
  39. ; does not function as specified; see <Parseline> for more details.
  40. ; * <Parseline> now knows about the flags the internals of COMMAND.COM
  41. ; need to know about. This extra information is stored in a switch_flag
  42. ; word with each command-line argument; the switches themselves will not
  43. ; appear in the resulting arg structure.
  44. ; * With the exception of CARRY, flags are generally preserved across calls.
  45. ;---------------
  46. ; CONSTANTS:
  47. ;---------------
  48. DEBUGx equ FALSE ; prints out debug info
  49. ;---------------
  50. ; DATA:
  51. ;---------------
  52. DATARES SEGMENT PUBLIC BYTE
  53. EXTRN FORFLAG:BYTE
  54. DATARES ENDS
  55. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  56. EXTRN combuf:byte
  57. EXTRN cpyflag:byte
  58. EXTRN expand_star:byte
  59. EXTRN RESSEG:word
  60. EXTRN STARTEL:word
  61. TRANSPACE ENDS
  62. TRANCODE SEGMENT PUBLIC BYTE ;AC000;
  63. PUBLIC argv_calc ; convert array index into address
  64. PUBLIC parseline
  65. assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
  66. break <Parseline: Munch on the command line>
  67. ;----------------------------------------------------------------------------
  68. ; PARSELINE takes an MSDOS command line and maps it into a UNIX-style
  69. ; argv[argvcnt] array. The most important difference between this array and
  70. ; the tradition UNIX format is the extra cparse information included with
  71. ; each argument element.
  72. ;---------------
  73. ; ENTRY:
  74. ; (BL special delimiter for cparse -- not implemented)
  75. ;---------------
  76. ; EXIT:
  77. ; CF set if error
  78. ; AL error code (carry set). Note AH clobbered in any event.
  79. ; argv[] array of cparse flags and pointers to arguments
  80. ; argvcnt argument count
  81. ;---------------
  82. ; NOTE(S):
  83. ; * BL (special delimiter) is ignored, for now (set to space).
  84. ; * Parseflags record contains cparse flags, as follows:
  85. ; sw_flag -- was this arg a switch?
  86. ; wildcard -- whether or not it contained a * or ?
  87. ; path_sep -- maybe it was a pathname
  88. ; unused -- for future expansion
  89. ; special_delim -- was there an initial special delimiter?
  90. ; * argv[] and argvcnt are undefined if CF/AL indicates an error.
  91. ; * Relationship between input, cparse output, and comtail can be
  92. ; found in the following chart. Despite the claim of the cparse
  93. ; documentation that, "Token buffer always starts d: for non switch
  94. ; tokens", such is not the case (see column two, row two).
  95. ; Similarly, [STARTEL] is not null when the command line is one of
  96. ; the forms, "d:", "d:\", or "d:/". In fact, *STARTEL (i.e., what
  97. ; STARTEL addresses) will be null. This is clearly just a
  98. ; documentation error.
  99. ; * cparse also returns a switch code in BP for each switch it
  100. ; recognizes on the command line.
  101. ; * arglen for each token does NOT include the terminating null.
  102. ; * Finally, note that interesting constructions like 'foodir/*.exe'
  103. ; parse as three separate tokens, and the asterisk is NOT a wildcard.
  104. ; For example, 'for %i in (foodir/*.exe) do echo %i' will first
  105. ; echo 'foodir', then '*', then '.exe'. Using cparse for command-
  106. ; line parsing may result in slightly different behavior than
  107. ; previously observed with the old COMMAND.COM command-line parser.
  108. ;
  109. ; Input Cparse Command Line (80H)
  110. ; \alan\foo.bat c:\alan\foo.bat \alan\foo.bat
  111. ; alan\foo.bat alan\foo.bat alan\foo.bat
  112. ; foo.bat foo.bat foo.bat
  113. ; c:\alan\foo.bat c:\alan\foo.bat c:\alan\foo.bat
  114. ; c:alan\foo.bat c:alan\foo.bat c:alan\foo.bat
  115. ; c:foo.bat c:foo.bat c:foo.bat
  116. ;---------------
  117. ; CONSTANTS:
  118. ;---------------
  119. ;---------------
  120. ; DATA:
  121. ;---------------
  122. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  123. EXTRN arg:byte
  124. EXTRN argbufptr:word
  125. EXTRN comptr:word
  126. EXTRN last_arg:word
  127. EXTRN tpbuf:byte
  128. TRANSPACE ENDS
  129. ;---------------
  130. parseline:
  131. ;---------------
  132. push AX ; most of these are clobbered
  133. push BX ; by cparse...
  134. push CX
  135. push DX
  136. push DI
  137. push SI
  138. pushf
  139. mov cpyflag,0 ; Turn "CPARSE called from COPY flag" off
  140. mov [LAST_ARG], -1 ; last argument at which to accumulate
  141. xor ax,ax
  142. mov cx,SIZE arg_unit
  143. mov di,offset trangroup:arg
  144. rep stosb
  145. mov argbufptr,offset trangroup:arg.argbuf
  146. mov arg.argswinfo, 0 ; switch information, and info to date
  147. mov arg.argvcnt, 0 ; initialize argvcnt/argv[]
  148. mov SI, OFFSET TRANGROUP:combuf+2 ; prescan leaves cooked input in combuf
  149. ; This next section of code (up to pcont:) makes sure that si is set up for
  150. ; parsing. It should point at COMBUF if FORFLAG is set and arg.argforcombuf
  151. ; otherwise. This is done so that commands can get arg pointers into their
  152. ; original command line (or an exact copy of it) in arg_ocomptr.
  153. ; Arg.argforcombuf is used so that the for loop processor will always be able
  154. ; to get a hold of its original command line; even after COMBUF is blasted by
  155. ; the command to be repeated or the transient part of command has been
  156. ; reloaded.
  157. push ds
  158. mov ds,[RESSEG]
  159. assume ds:resgroup
  160. cmp FORFLAG,0
  161. pop ds
  162. assume ds:trangroup
  163. jnz pcont
  164. mov di,OFFSET TRANGROUP:arg.argforcombuf
  165. xor ch,ch
  166. mov cl,[COMBUF+1]
  167. inc cl
  168. rep movsb
  169. mov si,OFFSET TRANGROUP:arg.argforcombuf
  170. pcont:
  171. mov DI, OFFSET TRANGROUP:tpbuf ; destination is temporary token buffer
  172. mov BL, ' ' ; no special delimiter, for now
  173. parseloop:
  174. mov comptr,si ; save ptr into original command buffer
  175. xor BP, BP ; switch information put here by cparse
  176. mov byte ptr [expand_star],0 ; don't expand *'s to ?'s
  177. invoke scanoff ; skip leading blanks...
  178. invoke cparse ; byte off a token (args in SI, DI, BL)
  179. jnc More_prse
  180. or BP,BP ; Check for trailing switch character
  181. jz parsedone
  182. call newarg ; We hit CR but BP is non-zero. The
  183. ; typical cause of this is that a
  184. ; switch char IMMEDIATELY preceeds
  185. ; the CR. We have an argument, but it
  186. ; is sort of an error.
  187. jmp short parsedone ; We're done (found the CR).
  188. More_prse:
  189. mov cpyflag,2 ; tell CPARSE that 1st token is done
  190. call newarg ; add to argv array (CX has char count)
  191. jnc parseloop ; was everything OK?
  192. jmp short parse_error ; NO, it wasn't -- bug out (CF set)
  193. parsedone: ; successful completion of parseline
  194. popf
  195. clc
  196. jmp short parse_exit
  197. parse_error: ; error entry (er, exit) point
  198. popf
  199. stc
  200. parse_exit: ; depend on not changing CF
  201. pop SI
  202. pop DI
  203. pop DX
  204. pop CX
  205. pop BX
  206. pop AX
  207. ret
  208. ;---------------
  209. ; parseline ends
  210. ;----------------------------------------------------------------------------
  211. break <NewArg>
  212. ;----------------------------------------------------------------------------
  213. ; NEWARG adds the supplied argstring and cparse data to arg.argv[].
  214. ; ENTRY:
  215. ; BH argflags
  216. ; CX character count in argstring
  217. ; DI pointer to argstring
  218. ; comptr ptr to starting loc of current token in original command
  219. ; [STARTEL] cparse's answer to where the last element starts
  220. ; EXIT:
  221. ; argbufptr points to next free section of argbuffer
  222. ; arg.argbuf contains null-terminated argument strings
  223. ; arg.argvcnt argument count
  224. ; arg.argv[] array of flags and pointers
  225. ; arg.arg_ocomptr ptr to starting loc of current token in original command
  226. ; CF set if error
  227. ; AL carry set: error code; otherwise, zero
  228. ;---------------
  229. newarg:
  230. ;---------------
  231. push BX
  232. push CX
  233. push DX ; one never knows, do one?
  234. push DI
  235. push SI
  236. pushf
  237. call arg_switch ; if it's a switch, record switch info
  238. ; LEAVE SWITCH ON COMMAND LINE!!
  239. ;;; jc newarg_done ; previous arg's switches -- and leave
  240. cmp arg.argvcnt, ARGMAX ; check to ensure we've not
  241. jge too_many_args ; exceeded array limits
  242. mov DH, BH ; save argflags
  243. mov BX, arg.argvcnt ; argv[argvcnt++] = arg data
  244. inc arg.argvcnt
  245. mov AX, OFFSET TRANGROUP:arg.argv
  246. call argv_calc ; convert offset to pointer
  247. mov [BX].argsw_word, 0 ; no switch information, yet...
  248. mov [BX].arglen, CX ; argv[argvcnt].arglen = arg length
  249. mov [BX].argflags, DH ; argv[argvcnt].argflags = cparse flags
  250. mov SI, argbufptr
  251. mov [BX].argpointer, SI ; argv[argvcnt].argpointer = [argbufptr]
  252. add SI, [STARTEL] ; save startel from new location
  253. sub SI, DI ; form pointer into argbuf
  254. mov [BX].argstartel, SI ; argv[argvcnt].argstartel = new [STARTEL]
  255. mov si,[comptr]
  256. mov [BX].arg_ocomptr,si ; arg_ocomptr=ptr into original com line
  257. mov SI, DI ; now save argstring in argbuffer
  258. mov DI, argbufptr ; load the argbuf pointer and make
  259. add DI, CX ; sure we're not about to run off
  260. cmp DI, OFFSET TRANGROUP:arg.argbuf+ARGBLEN-1
  261. jge buf_ovflow ; the end of the buffer (plus null byte)
  262. sub DI, CX ; adjust the pointer
  263. cld
  264. rep movsb ; and save the string in argbuffer
  265. mov AL, ANULL ; tack a null byte on the end
  266. stosb
  267. mov argbufptr, DI ; update argbufptr after copy
  268. newarg_done:
  269. popf
  270. clc
  271. jmp short newarg_exit
  272. too_many_args:
  273. mov AX, arg_cnt_error
  274. jmp short newarg_error
  275. buf_ovflow:
  276. mov AX, arg_buf_ovflow
  277. newarg_error:
  278. popf
  279. stc
  280. newarg_exit:
  281. pop SI
  282. pop DI
  283. pop DX
  284. pop CX
  285. pop BX
  286. ret
  287. ;---------------
  288. ; NewArg ends
  289. ;----------------------------------------------------------------------------
  290. break <Arg_Switch>
  291. ;----------------------------------------------------------------------------
  292. ; ARG_SWITCH decides if an argument might really be a switch. In the
  293. ; event that it is, and we can recognize
  294. ; ENTRY:
  295. ; As in <newarg>.
  296. ; EXIT:
  297. ; CF -- clear (wasn't a switch); set (was a switch)
  298. ; NOTE(S):
  299. ; * The mechanism mapping a switch into a bit-value depends entirely
  300. ; on the order of definition in the <switch_list> variable and the
  301. ; values chosen to define the bits in CMDT:COMEQU.ASM. Change either
  302. ; <switch_list> or the definitions in CMDT:COMEQU.ASM -- and rewrite
  303. ; this mechanism. This code taken from CMDT:TCODE.ASM.
  304. ; * The <switch_list> declared below is redundant to one declared in
  305. ; TDATA.ASM, and used in TCODE.ASM.
  306. ; * An ugly routine.
  307. ;---------------
  308. ; CONSTANTS:
  309. ;---------------
  310. ; Constants come from the definitions in CMDT:COMEQU.ASM.
  311. ;---------------
  312. ; DATA:
  313. ;---------------
  314. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  315. extrn switch_list:byte
  316. switch_count EQU $-switch_list
  317. transpace ends
  318. ;---------------
  319. Arg_Switch:
  320. ;---------------
  321. push AX
  322. push BX
  323. push CX
  324. push DI
  325. pushf
  326. test BH, MASK sw_flag ; is it a switch? (preserve flag word)
  327. jz arg_no_switch0
  328. cmp [LAST_ARG], -1 ; have we encountered any REAL args yet?
  329. je arg_no_switch1 ; no, so leading switches don't matter
  330. mov BX, [LAST_ARG] ; yes, add switch info to last REAL arg
  331. mov AX, OFFSET TRANGROUP:arg.argv
  332. call argv_calc
  333. or [BX].argsw_word, BP
  334. or arg.argswinfo, BP
  335. arg_yes_switch: ; ah, sweet success...
  336. popf
  337. stc
  338. jmp short arg_switch_exit
  339. arg_no_switch0:
  340. mov AX, arg.argvcnt ; future switches should then affect
  341. mov [LAST_ARG], AX ; this argument
  342. arg_no_switch1: ; wasn't a switch, or we're pretending
  343. popf
  344. clc
  345. arg_switch_exit:
  346. pop DI
  347. pop CX
  348. pop BX
  349. pop AX
  350. ret
  351. ;---------------
  352. ; Arg_Switch ends
  353. ;----------------------------------------------------------------------------
  354. break <Argv_calc>
  355. ;----------------------------------------------------------------------------
  356. ; ARGV_CALC maps an array index into a byte-offset from the base of
  357. ; the supplied array. Method used for computing the address is:
  358. ; Array Index * Array Elt Size + Base Addr = Elt Addr
  359. ; ENTRY:
  360. ; AX -- base of array
  361. ; BX -- array index
  362. ; EXIT:
  363. ; BX -- byte offset
  364. ;---------------
  365. argv_calc:
  366. push ax ; Save base
  367. mov al,bl ; al = array index
  368. mov bl,SIZE argv_ele ; bl = size of an argv element
  369. mul bl ; ax = base offset
  370. pop bx ; Get base
  371. add ax,bx ; Add in base offset
  372. xchg ax,bx ; Restore ax and put byte offset in bx
  373. ret
  374. ;---------------
  375. ; argv_calc ends
  376. ;----------------------------------------------------------------------------
  377. trancode ends
  378. end
  379.