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.

586 lines
16 KiB

  1. page ,132
  2. ; SCCSID = @(#)tfor.asm 4.1 85/09/17
  3. ; SCCSID = @(#)tfor.asm 4.1 85/09/17
  4. TITLE Part3 COMMAND Transient Routines
  5. ;/*
  6. ; * Microsoft Confidential
  7. ; * Copyright (C) Microsoft Corporation 1991
  8. ; * All Rights Reserved.
  9. ; */
  10. ; For loop processing routines
  11. .xlist
  12. .xcref
  13. include comsw.asm
  14. include dossym.inc
  15. include syscall.inc
  16. include find.inc
  17. include devsym.inc
  18. include comseg.asm
  19. include comequ.asm
  20. .list
  21. .cref
  22. DATARES SEGMENT PUBLIC BYTE ;AC000;
  23. EXTRN BATCH:WORD
  24. EXTRN ECHOFLAG:BYTE
  25. EXTRN FORFLAG:BYTE
  26. EXTRN FORPTR:WORD
  27. EXTRN NEST:WORD
  28. EXTRN NULLFLAG:BYTE
  29. EXTRN PIPEFILES:BYTE
  30. EXTRN SINGLECOM:WORD
  31. DATARES ENDS
  32. TRANDATA SEGMENT PUBLIC BYTE ;AC000;
  33. EXTRN Extend_buf_ptr:word ;AN000;
  34. extrn fornestmes_ptr:word
  35. EXTRN msg_disp_class:byte ;AN000;
  36. extrn string_buf_ptr:word
  37. TRANDATA ENDS
  38. TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
  39. extrn arg:byte ; the arg structure!
  40. EXTRN COMBUF:BYTE
  41. EXTRN RESSEG:WORD
  42. EXTRN string_ptr_2:word
  43. TRANSPACE ENDS
  44. TRANCODE SEGMENT PUBLIC BYTE
  45. ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
  46. EXTRN cerror:near
  47. EXTRN docom:near
  48. EXTRN docom1:near
  49. EXTRN forerror:near
  50. EXTRN tcommand:near
  51. PUBLIC $for
  52. PUBLIC forproc
  53. ; All batch proccessing has DS set to segment of resident portion
  54. ASSUME DS:RESGROUP,ES:TRANGROUP
  55. FORTERM:
  56. push cs ;AN037; Get local segment into
  57. pop ds ;AN037; DS, ES
  58. push cs ;AN037;
  59. pop es ;AN037;
  60. call ForOff
  61. mov ds,ResSeg
  62. ASSUME DS:RESGROUP
  63. CMP [SINGLECOM],0FF00H
  64. JNZ BATCRLF
  65. CMP NEST,0 ;G See if we have nested batch files
  66. JNZ BATCRLF ;G Yes - don't exit just yet
  67. MOV [SINGLECOM],-1 ; Cause a terminate
  68. JMP SHORT NOFORP2
  69. BATCRLF:
  70. test [ECHOFLAG],1 ;G Is echo on?
  71. JZ NOFORP2 ;G no - exit
  72. TEST [BATCH], -1 ;G print CRLF if in batch
  73. JZ NOFORP2 ;G
  74. invoke CRLF2
  75. NOFORP2:
  76. JMP TCOMMAND
  77. ;------
  78. ; For-loop processing. For loops are of the form:
  79. ; for %<loop-variable> in (<list>) do <command>
  80. ; where <command> may contain references of the form %<variable>, which are
  81. ; later substituted with the items in <list>. The for-loop structure is
  82. ; set-up by the procedure '$for'; successive calls to 'forproc' execute
  83. ; <command> once for each item in <list>. All of the information needed for
  84. ; loop processing is stored on a piece of memory gotten from 'alloc'. This
  85. ; structure is actually fairly large, on the order of 700 bytes, and includes
  86. ; a complete copy of the original command-line structure as parsed by
  87. ; 'parseline', loop control variables, and a dma buffer for the
  88. ; 'FindFirst/FindNext' expansion of wildcard filenames in <list>. When loop
  89. ; processing has completed, this chunk of memory is returned to the system.
  90. ;
  91. ; All of the previously defined variables, in 'datares', used for loop
  92. ; processing may be erased. Only one, (DW) ForPtr, need be allocated.
  93. ;
  94. ; The error message, 'for_alloc_mes', should be moved into the file
  95. ; containing all of the other error messages.
  96. ;
  97. ; Referencing the allocated for-loop structure is a little tricky.
  98. ; At the moment, a byte is defined as part of a new segment, 'for_segment'.
  99. ; When 'forproc' actually runs, ES and DS are set to point to the base of the
  100. ; new chunk of memory. References to this byte, 'f', thus assemble correctly
  101. ; as offsets of ES or DS. 'f' would not be necessary, except that the
  102. ; assembler translates an instruction such as 'mov AX, [for_minarg]' as an
  103. ; immediate move of the offset of 'for_minarg' into AX. In other words, in
  104. ; terms of PDP-11 mnemonics, the assembler ACTUALLY assembles
  105. ; mov AX, #for_minarg ; AX := 02CA (for example)
  106. ; instead of
  107. ; mov AX, for_minarg ; AX := [02CA] (contents of 02CA)
  108. ; By using 'f', we pretend that we are actually referencing an allocated
  109. ; structure, and the assembler coughs up the code we want. Notice that it
  110. ; doesn't matter whether we put brackets around the location or not -- the
  111. ; assembler is "smart" enough to know that we want an address instead of the
  112. ; contents of that location.
  113. ;
  114. ; Finally, there now exists the potential to easily implement nested loops.
  115. ; One method would be to have a link field in each for-structure pointing to
  116. ; its parent. Variable references that couldn't be resolved in the local
  117. ; frame would cause a search of prior frames. For-structures would still be
  118. ; allocated and released in exactly the same fashion. The only limit on the
  119. ; number of nested loops would be memory size (although at 700 bytes a pop,
  120. ; memory wouldn't last THAT long). Alternately, a small structure could be
  121. ; maintained in the resident data area. This structure would be an array of
  122. ; control-variable names and pointers to for-structure blocks. This would
  123. ; greatly speed up the resolution of non-local variable references. However,
  124. ; since space in the resident is precious, we would have to compromise on a
  125. ; "reasonable" level of nesting -- 10, 16, 32 levels, whatever. For-structure
  126. ; allocation and de-allocation would have to be modified slightly to take this
  127. ; new structure into account.
  128. ;
  129. ; Oops, just one more thing. Forbuf need not be a part of the for-structure.
  130. ; It could just as well be one structure allocated in 'transpace'. Actually,
  131. ; it may be easier to allocate it as part of 'for_segment'.
  132. ;------
  133. include fordata.asm
  134. $for_exit:
  135. jmp forterm ; exceeding maxarg means all done
  136. forproc:
  137. assume DS:resgroup
  138. mov AX, [ForPtr]
  139. mov DS, AX
  140. mov ES, AX ; operate in for-info area
  141. assume DS:for_segment, ES:for_segment
  142. mov DX, fordma
  143. trap Set_Dma
  144. for_begin:
  145. cmp f.for_expand, 0 ; non-zero for_expand equals FALSE
  146. je for_begin1
  147. inc f.for_minarg
  148. for_begin1:
  149. mov BX, f.for_minarg ; current item in <list> to examine
  150. cmp BX, f.for_maxarg
  151. jg $for_exit ; exceeding maxarg means all done
  152. mov AX, for_args.argv
  153. invoke argv_calc ; compute argv[x] address
  154. mov CX, [BX].argstartel
  155. mov DX, [BX].argpointer
  156. test [bx].argflags,00000100b ; Is there a path separator in this arg?
  157. jnz forsub ; Yes, argstartel should be correct
  158. mov si, [BX].argpointer
  159. mov al,lparen
  160. cmp byte ptr [si-1],al ; If the current token is the first
  161. jnz forsub ; one in the list and originally had
  162. inc cx ; the opening paren as its first char,
  163. ; the argstartel ptr needs to be
  164. ; advanced passed it before the prefix
  165. ; length is computed.
  166. mov al,':'
  167. cmp byte ptr [si+1],al ; If the token begins with "(d:",
  168. jnz forsub ; argstartel has to be moved over the
  169. add cx,2 ; rest of the prefix as well.
  170. forsub:
  171. sub CX, DX ; compute length of pathname prefix
  172. cmp f.for_expand, 0 ; are we still expanding a name?
  173. je for_find_next ; if so, get next matching filename
  174. test [BX].argflags, MASK wildcard
  175. jnz for_find_first ; should we expand THIS (new) arg?
  176. mov CX, [BX].arglen ; else, just copy all of it directly
  177. jmp short for_smoosh
  178. for_find_first:
  179. PUSH CX
  180. XOR CX,CX
  181. trap Find_First ; and search for first filename match
  182. POP CX
  183. jmp short for_result
  184. for_find_next:
  185. trap Find_Next ; search for next filename match
  186. for_result:
  187. mov AX, -1 ; assume worst case
  188. jc forCheck
  189. mov ax,0
  190. forCheck: ; Find* returns 0 for SUCCESS
  191. mov f.FOR_EXPAND, AX ; record success of findfirst/next
  192. or AX, AX ; anything out there?
  193. jnz for_begin ; if not, try next arg
  194. for_smoosh:
  195. mov SI, [BX].argpointer ; copy argv[arg][0,CX] into destbuf
  196. mov DI, forbuf ; some days this will be the entire
  197. rep movsb ; arg, some days just the path prefix
  198. cmp f.FOR_EXPAND, 0 ; if we're not expanding, we can
  199. jnz for_make_com ; skip the following
  200. mov SI, fordma.find_buf_pname
  201. for_more: ; tack on matching filename
  202. cmp BYTE PTR [SI], 0
  203. je for_make_com
  204. movsb
  205. jnz for_more
  206. for_make_com:
  207. xor AL, AL ; tack a null byte onto the end
  208. stosb ; of the substitute string
  209. xor CX, CX ; character count for command line
  210. not CX ; negate it -- take advantage of loopnz
  211. xor BX, BX ; argpointer
  212. mov DI, OFFSET TRANGROUP:COMBUF+2
  213. mov bl, f.FOR_COM_START ; argindex
  214. mov DH, f.FOR_VAR ; %<for-var> is replaced by [forbuf]
  215. ; time to form the <command> string
  216. push CS
  217. pop ES
  218. assume ES:trangroup
  219. mov AX, for_args ; translate offset to pointer
  220. invoke argv_calc
  221. mov si,[bx].arg_ocomptr
  222. inc si ; mov ptr passed beginning space
  223. for_make_loop:
  224. mov al,[si] ; the <command> arg, byte by byte
  225. inc si
  226. cmp AL,'%' ; looking for %<control-variable>
  227. jne for_stosb ; no % ... add byte to string
  228. cmp BYTE PTR [SI], DH ; got the right <variable>?
  229. jne for_stosb ; got a %, but wrong <variable>
  230. inc SI ; skip over <for-variable>
  231. push SI
  232. mov SI, forbuf ; substitute the <item> for <variable>
  233. ; to make a final <command> to execute
  234. sloop:
  235. lodsb ; grab all those <item> bytes, and
  236. stosb ; add 'em to the <command> string,
  237. or AL, AL ; until we run into a null
  238. loopnz sloop
  239. dec DI ; adjust length and <command> pointer
  240. inc CX ; so we can overwrite the null
  241. pop SI
  242. jmp for_make_loop ; got back for more <command> bytes
  243. for_stosb:
  244. stosb ; take a byte from the <command> arg
  245. dec CX ; and put it into the <command> to be
  246. ; executed (and note length, too)
  247. cmp al,0dh ; If not done, loop.
  248. jne for_make_loop
  249. for_made_com: ; finished all the <command> args
  250. not CL ; compute and record command length
  251. mov [COMBUF+1], CL
  252. mov DS, [RESSEG]
  253. assume DS:resgroup
  254. test [ECHOFLAG],1 ; shall we echo this <command>, dearie?
  255. jz noecho3
  256. cmp nullflag,nullcommand ;G was there a command last time?
  257. jz No_crlf_pr ;G no - don't print crlf
  258. invoke CRLF2 ;G Print out prompt
  259. no_crlf_pr:
  260. mov nullflag,0 ;G reset no command flag
  261. push CS
  262. pop DS
  263. assume DS:trangroup
  264. push di
  265. invoke PRINT_PROMPT ;G Prompt the user
  266. pop di
  267. mov BYTE PTR ES:[DI-1],0 ; yeah, PRINT it out...
  268. mov string_ptr_2,OFFSET TRANGROUP:COMBUF+2
  269. mov dx,offset trangroup:string_buf_ptr
  270. invoke std_printf
  271. mov BYTE PTR ES:[DI-1], 0DH
  272. jmp DoCom
  273. noecho3: ; run silent, run deep...
  274. assume DS:resgroup
  275. mov nullflag,0 ;G reset no command flag
  276. push CS
  277. pop DS
  278. assume DS:trangroup
  279. jmp docom1
  280. fornesterrj: ; no multi-loop processing... yet!
  281. assume ES:resgroup
  282. call ForOff
  283. jmp fornesterr
  284. forerrorj:
  285. jmp forerror
  286. break $For
  287. assume ds:trangroup,es:trangroup
  288. $for:
  289. mov ES, [RESSEG]
  290. assume ES:resgroup
  291. cmp ForFlag,0 ; is another one already running?
  292. jnz fornesterrj ; if flag is set.... boom!
  293. ;
  294. ; Turn off any pipes in progress.
  295. ;
  296. cmp [PIPEFILES],0 ; Only turn off if present.
  297. jz NoPipe
  298. invoke PipeDel
  299. NoPipe:
  300. xor DX, DX ; counter (0 <= DX < argvcnt)
  301. call nextarg ; move to next argv[n]
  302. jc forerrorj ; no more args -- bad forloop
  303. cmp AL,'%' ; next arg MUST start with '%'...
  304. jne forerrorj
  305. mov BP, AX ; save forloop variable
  306. lodsb
  307. or AL, AL ; and MUST end immediately...
  308. jne forerrorj
  309. call nextarg ; let's make sure the next arg is 'in'
  310. jc forerrorj
  311. and AX, NOT 2020H ; uppercase the letters
  312. cmp AX, in_word
  313. jne forerrorj
  314. lodsb
  315. or AL, AL ; it, too, must end right away
  316. ; Compaq bug fix -- exit from this loop on error
  317. ifndef NEC_98
  318. jne forerrorj ; jump on error
  319. ;; je CheckLParen
  320. else ;NEC_98
  321. ;; jne forerrorj ; jump on error ;NEC00
  322. je CheckLParen
  323. endif ;NEC_98
  324. ;
  325. ; Not null. Perhaps there are no spaces between this and the (:
  326. ; FOR %i in(foo bar...
  327. ; Check for the Lparen here
  328. ;
  329. ifndef NEC_98
  330. ;; CMP AL,lparen
  331. ;; JNZ forerrorj
  332. else ;NEC_98
  333. CMP AL,lparen
  334. JNZ forerrorj
  335. endif ;NEC_98
  336. ;
  337. ; The token was in(... We strip off the "in" part to simulate a separator
  338. ; being there in the first place.
  339. ;
  340. ifndef NEC_98
  341. ;; ADD [BX].argpointer,2 ; advance source pointer
  342. ;; ADD [BX].arg_ocomptr,2 ; advance original string
  343. ;; SUB [BX].arglen,2 ; decrement the appropriate length
  344. else ;NEC_98
  345. ADD [BX].argpointer,2 ; advance source pointer
  346. ADD [BX].arg_ocomptr,2 ; advance original string
  347. SUB [BX].arglen,2 ; decrement the appropriate length
  348. endif ;NEC_98
  349. ;
  350. ; SI now points past the in(. Simulate a nextarg call that results in the
  351. ; current value.
  352. ;
  353. ifndef NEC_98
  354. ;; MOV ax,[si-1] ; get lparen and next char
  355. ;; jmp short lpcheck
  356. else ;NEC_98
  357. MOV ax,[si-1] ; get lparen and next char
  358. jmp short lpcheck
  359. endif ;NEC_98
  360. ;
  361. ;; end of Compaq bug fix
  362. CheckLParen:
  363. call nextarg ; lparen delimits beginning of <list>
  364. jc forerrorj
  365. lpcheck:
  366. cmp al, lparen
  367. jne forerrorj
  368. cmp ah,0
  369. je for_paren_token
  370. cmp ah, rparen ; special case: null list
  371. jne for_list_not_empty
  372. jmp forterm
  373. for_list_not_empty:
  374. inc [bx].argpointer ; Advance ptr past "("
  375. ; Adjust the rest of this argv entry
  376. dec [bx].arglen ; to agree.
  377. inc si ; Inc si so check for ")" works
  378. jmp short for_list
  379. for_paren_token:
  380. call nextarg ; what have we in our <list>?
  381. jc forerrorj
  382. cmp ax, nullrparen ; special case: null list
  383. jne for_list
  384. jmp forterm
  385. forerrorjj:
  386. jmp forerror
  387. for_list: ; skip over rest of <list>
  388. mov CX, DX ; first arg of <list>
  389. skip_list:
  390. add si,[bx].arglen
  391. sub si,3 ; si = ptr to last char of token
  392. mov al,rparen
  393. cmp byte ptr [si],al ; Is this the last element in <list>
  394. je for_end_list ; Yes, exit loop.
  395. call nextarg ; No, get next arg <list>
  396. jc forerrorjj ; If no more and no rparen, error.
  397. jmp skip_list
  398. for_end_list:
  399. mov DI, DX ; record position of last arg in <list>
  400. mov byte ptr [si],0 ; Zap the rparen
  401. cmp ax,nullrparen ; Was this token only a rparen
  402. jz for_do ; Yes, continue
  403. inc di ; No, inc position of last arg
  404. for_do:
  405. call nextarg ; now we had BETTER find a 'do'...
  406. jc forerrorjj
  407. and AX, NOT 2020H ; uppercase the letters
  408. cmp AX, do_word
  409. jne forerrorjj
  410. lodsb
  411. or AL, AL ; and it had BETTER be ONLY a 'do'...
  412. jne forerrorjj
  413. call nextarg ; on to the beginning of <command>
  414. jc forerrorjj ; null <command> not legal
  415. push AX
  416. push BX
  417. push CX
  418. push DX ; preserve registers against disaster
  419. push DI
  420. push SI
  421. push BP
  422. invoke FREE_TPA ; need to make free memory, first
  423. ASSUME ES:RESGROUP
  424. call ForOff
  425. mov BX, SIZE for_info - SIZE arg_unit
  426. invoke Save_Args ; extra bytes needed for for-info
  427. pushf
  428. mov [ForPtr], AX
  429. invoke ALLOC_TPA ; ALLOC_TPA clobbers registers...
  430. popf
  431. pop BP
  432. pop SI
  433. pop DI
  434. pop DX
  435. pop CX
  436. pop BX
  437. pop AX
  438. jc for_alloc_err
  439. push ES ; save resgroup seg...
  440. push [ForPtr]
  441. pop ES
  442. assume ES:for_segment ; make references to for-info segment
  443. dec CX ; forproc wants min pointing before
  444. dec DI ; first arg, max right at last one
  445. mov f.for_minarg, CX
  446. mov f.for_maxarg, DI
  447. mov f.for_com_start, DL
  448. mov f.for_expand, -1 ; non-zero means FALSE
  449. mov AX, BP
  450. mov f.for_var, AH
  451. pop ES
  452. assume ES:resgroup
  453. inc [FORFLAG]
  454. cmp [SINGLECOM], -1
  455. jnz for_ret
  456. mov [SINGLECOM], 0FF00H
  457. for_ret:
  458. ret
  459. for_alloc_err:
  460. mov msg_disp_class,ext_msg_class ;AN000; set up extended error msg class
  461. mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
  462. mov Extend_Buf_ptr,error_not_enough_memory ;AN000; get message number in control block
  463. jmp cerror
  464. nextarg:
  465. inc DX ; next argv[n]
  466. cmp DX, arg.argvcnt ; make sure we don't run off end
  467. jge nextarg_err ; of argv[]...
  468. mov BX, DX
  469. mov AX, OFFSET TRANGROUP:arg.argv
  470. invoke argv_calc ; convert array index to pointer
  471. mov SI, [BX].argpointer ; load pointer to argstring
  472. lodsw ; and load first two chars
  473. clc
  474. ret
  475. nextarg_err:
  476. stc
  477. ret
  478. ASSUME DS:TRANGROUP,ES:TRANGROUP
  479. FORNESTERR:
  480. PUSH DS
  481. MOV DS,[RESSEG]
  482. ASSUME DS:RESGROUP
  483. MOV DX,OFFSET TRANGROUP:FORNESTMES_ptr
  484. CMP [SINGLECOM],0FF00H
  485. JNZ NOFORP3
  486. MOV [SINGLECOM],-1 ; Cause termination
  487. NOFORP3:
  488. POP DS
  489. ASSUME DS:TRANGROUP
  490. JMP CERROR
  491. ;
  492. ; General routine called to free the for segment. We also clear the forflag
  493. ; too. Change no registers.
  494. ;
  495. PUBLIC ForOff
  496. ForOff:
  497. assume DS:NOTHING,ES:NOTHING
  498. SaveReg <AX,ES>
  499. mov es,ResSeg
  500. assume es:ResGroup
  501. mov AX,ForPtr
  502. or ax,ax
  503. jz FreeDone
  504. push es
  505. mov es,ax
  506. mov ah,dealloc
  507. int 21h
  508. pop es
  509. FreeDone:
  510. mov ForPtr,0
  511. mov ForFlag,0
  512. RestoreReg <ES,AX>
  513. return
  514. trancode ends
  515. end
  516.