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