diff options
Diffstat (limited to 'v4.0/src/CMD/COMMAND/TBATCH.ASM')
| -rw-r--r-- | v4.0/src/CMD/COMMAND/TBATCH.ASM | 1045 |
1 files changed, 1045 insertions, 0 deletions
diff --git a/v4.0/src/CMD/COMMAND/TBATCH.ASM b/v4.0/src/CMD/COMMAND/TBATCH.ASM new file mode 100644 index 0000000..6ec51b5 --- /dev/null +++ b/v4.0/src/CMD/COMMAND/TBATCH.ASM | |||
| @@ -0,0 +1,1045 @@ | |||
| 1 | page 80,132 | ||
| 2 | ; SCCSID = @(#)tbatch.asm 4.5 85/10/01 | ||
| 3 | ; SCCSID = @(#)tbatch.asm 4.5 85/10/01 | ||
| 4 | TITLE Batch processing routines | ||
| 5 | |||
| 6 | |||
| 7 | .xlist | ||
| 8 | .xcref | ||
| 9 | INCLUDE comsw.asm | ||
| 10 | INCLUDE DOSSYM.INC | ||
| 11 | INCLUDE comseg.asm | ||
| 12 | INCLUDE comequ.asm | ||
| 13 | include doscntry.inc ;AN000; | ||
| 14 | include version.inc | ||
| 15 | .list | ||
| 16 | .cref | ||
| 17 | |||
| 18 | |||
| 19 | DATARES SEGMENT PUBLIC BYTE ;AC000; | ||
| 20 | EXTRN BATCH:WORD | ||
| 21 | EXTRN Batch_Abort:byte | ||
| 22 | EXTRN call_batch_flag:byte | ||
| 23 | EXTRN ECHOFLAG:BYTE | ||
| 24 | EXTRN forflag:byte | ||
| 25 | EXTRN forptr:word | ||
| 26 | EXTRN IFFlag:BYTE | ||
| 27 | EXTRN In_Batch:byte | ||
| 28 | EXTRN LTPA:WORD | ||
| 29 | EXTRN Nest:word | ||
| 30 | EXTRN next_batch:word | ||
| 31 | EXTRN nullflag:byte | ||
| 32 | EXTRN PIPEFLAG:BYTE | ||
| 33 | EXTRN RES_TPA:WORD | ||
| 34 | EXTRN SINGLECOM:WORD | ||
| 35 | EXTRN SUPPRESS:BYTE ;AC000; | ||
| 36 | DATARES ENDS | ||
| 37 | |||
| 38 | TRANDATA SEGMENT PUBLIC BYTE ;AC000; | ||
| 39 | EXTRN BADBAT_PTR:WORD | ||
| 40 | EXTRN Extend_buf_ptr:word ;AC000; | ||
| 41 | EXTRN Extend_buf_sub:byte ;AN022; | ||
| 42 | EXTRN msg_disp_class:byte ;AC000; | ||
| 43 | EXTRN NEEDBAT_PTR:WORD | ||
| 44 | EXTRN pausemes_ptr:word ;AC000; | ||
| 45 | TRANDATA ENDS | ||
| 46 | |||
| 47 | TRANSPACE SEGMENT PUBLIC BYTE ;AC000; | ||
| 48 | EXTRN BatBufPos:WORD | ||
| 49 | EXTRN BATHAND:WORD | ||
| 50 | EXTRN bwdbuf:byte ;AN022; | ||
| 51 | EXTRN BYTCNT:WORD | ||
| 52 | EXTRN COMBUF:BYTE | ||
| 53 | EXTRN EXECPATH:BYTE | ||
| 54 | EXTRN ID:BYTE | ||
| 55 | EXTRN RCH_ADDR:DWORD | ||
| 56 | EXTRN RESSEG:WORD | ||
| 57 | EXTRN string_ptr_2:word ;AC000; | ||
| 58 | EXTRN TPA:WORD | ||
| 59 | EXTRN TRAN_TPA:WORD | ||
| 60 | TRANSPACE ENDS | ||
| 61 | |||
| 62 | TRANCODE SEGMENT PUBLIC BYTE | ||
| 63 | |||
| 64 | ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING | ||
| 65 | |||
| 66 | EXTRN cerror:near | ||
| 67 | EXTRN tcommand:near | ||
| 68 | |||
| 69 | ;--------------- | ||
| 70 | |||
| 71 | TRANSPACE SEGMENT PUBLIC BYTE ;AC000; | ||
| 72 | extrn arg:byte ; the arg structure! | ||
| 73 | transpace ends | ||
| 74 | ;--------------- | ||
| 75 | |||
| 76 | Break <PromptBat - Open or wait for batch file> | ||
| 77 | |||
| 78 | ; | ||
| 79 | ; Open the batch file. If we cannot find the batch file. If the media is | ||
| 80 | ; changeable, we prompt for the change. Otherwise, we terminate the batch | ||
| 81 | ; file. Leave segment registers alone. | ||
| 82 | ; | ||
| 83 | |||
| 84 | Procedure PromptBat,NEAR | ||
| 85 | ASSUME DS:ResGroup,ES:NOTHING | ||
| 86 | invoke BATOPEN ; attempt to open batch file | ||
| 87 | retnc | ||
| 88 | cmp dx,error_file_not_found ;AN022; Ask for diskette if file not found | ||
| 89 | jz Bat_Remcheck ;AN022; | ||
| 90 | cmp dx,error_path_not_found ;AN022; Ask for diskette if path not found | ||
| 91 | jz Bat_Remcheck ;AN022; Otherwise, issue message and exit | ||
| 92 | invoke output_batch_name ;AN022; set up batch name in bwdbuf | ||
| 93 | jmp short BatDie ;AN022; | ||
| 94 | |||
| 95 | Bat_Remcheck: ;AN022; Go see if media is removable | ||
| 96 | CALL [RCH_ADDR] ; DX has error number | ||
| 97 | JZ AskForBat ; Media is removable | ||
| 98 | ; | ||
| 99 | ; The media is not changeable. Turn everything off. | ||
| 100 | ; | ||
| 101 | invoke ForOff | ||
| 102 | invoke PipeOff | ||
| 103 | MOV IfFlag,AL ; No If in progress. | ||
| 104 | MOV DX,OFFSET TRANGROUP:BADBAT_ptr | ||
| 105 | |||
| 106 | BatDie: | ||
| 107 | call BatchOff | ||
| 108 | PUSH CS | ||
| 109 | POP DS | ||
| 110 | ASSUME DS:TranGroup | ||
| 111 | invoke std_eprintf ;AC022; display message | ||
| 112 | |||
| 113 | ; | ||
| 114 | ; TCOMMAND resets the stack. This is the equivalent of a non-local goto. | ||
| 115 | ; | ||
| 116 | JMP TCOMMAND ; he cleans off stack | ||
| 117 | |||
| 118 | ; | ||
| 119 | ; Ask the user to reinsert the batch file | ||
| 120 | ; | ||
| 121 | ASKFORBAT: | ||
| 122 | ASSUME DS:ResGroup | ||
| 123 | PUSH DS | ||
| 124 | PUSH CS | ||
| 125 | POP DS | ||
| 126 | ASSUME DS:TranGroup | ||
| 127 | MOV DX,OFFSET TRANGROUP:NEEDBAT_ptr ;AN022; | ||
| 128 | invoke std_eprintf ;Prompt for batch file on stderr | ||
| 129 | mov dx,offset trangroup:pausemes_ptr ;AN000; get second part of message | ||
| 130 | invoke std_eprintf ;AN000; print it to stderr | ||
| 131 | CALL GetKeystroke | ||
| 132 | POP DS | ||
| 133 | ASSUME DS:ResGroup | ||
| 134 | jmp PromptBat | ||
| 135 | EndProc PromptBat | ||
| 136 | |||
| 137 | ;**************************************************************** | ||
| 138 | ;* | ||
| 139 | ;* ROUTINE: Output_batch_name | ||
| 140 | ;* | ||
| 141 | ;* FUNCTION: Sets up batch name to be printed on extended error | ||
| 142 | ;* | ||
| 143 | ;* INPUT: DX - extended error number | ||
| 144 | ;* | ||
| 145 | ;* OUTPUT: Ready to call print routine | ||
| 146 | ;* | ||
| 147 | ;**************************************************************** | ||
| 148 | |||
| 149 | public output_batch_name ;AN022; | ||
| 150 | |||
| 151 | Output_batch_name proc near ;AN022; | ||
| 152 | |||
| 153 | push ds ;AN022; save resident segment | ||
| 154 | mov ds,[batch] ;AN022; get batch file segment | ||
| 155 | assume DS:nothing ;AN022; | ||
| 156 | mov SI,BatFile ;AN022; get offset of batch file | ||
| 157 | invoke dstrlen ;AN022; get length of string | ||
| 158 | mov di,offset Trangroup:bwdbuf ;AN022; target for batch name | ||
| 159 | rep movsb ;AN022; move the name | ||
| 160 | |||
| 161 | push cs ;AN022; get local segment | ||
| 162 | pop ds ;AN022; | ||
| 163 | assume DS:trangroup ;AN022; | ||
| 164 | mov extend_buf_ptr,dx ;AN022; put message number in block | ||
| 165 | mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class | ||
| 166 | mov dx,offset TranGroup:Extend_Buf_ptr ;AN022; get extended message pointer | ||
| 167 | mov string_ptr_2,offset trangroup:bwdbuf ;AN022; point to substitution | ||
| 168 | mov extend_buf_sub,one_subst ;AN022; set up for one subst | ||
| 169 | pop ds ;AN022; restore data segment | ||
| 170 | |||
| 171 | ret ;AN022; return | ||
| 172 | |||
| 173 | Output_batch_name endp ;AN022; | ||
| 174 | |||
| 175 | Break <GetKeystroke - get a keystroke and flush queue> | ||
| 176 | |||
| 177 | ; | ||
| 178 | ; read the next keystroke. Since there may be several characters in the queue | ||
| 179 | ; after the one we ask for (function keys/Kanji), we need to flush the queue | ||
| 180 | ; AFTER waiting. | ||
| 181 | ; | ||
| 182 | Procedure GetKeyStroke,NEAR | ||
| 183 | ; | ||
| 184 | ; read any character at any mode, interim mode or not. | ||
| 185 | ; | ||
| 186 | |||
| 187 | PUSH DX ;AN000; 3/3/KK | ||
| 188 | MOV AX,(ECS_call SHL 8) OR GetInterimMode ;AN000; 3/3/KK | ||
| 189 | INT int_command ;AN000; 3/3/KK | ||
| 190 | PUSH DX ;AN000; save interim state 3/3/KK | ||
| 191 | MOV AX,(ECS_call SHL 8) OR SetInterimMode ;AN000; 3/3/KK | ||
| 192 | MOV DL,InterimMode ;AN000; 3/3/KK | ||
| 193 | INT int_command ;AN000; 3/3/KK | ||
| 194 | |||
| 195 | MOV AX,(STD_CON_INPUT_FLUSH SHL 8) OR STD_CON_INPUT_no_echo | ||
| 196 | INT int_command ; Get character with KB buffer flush | ||
| 197 | MOV AX,(STD_CON_INPUT_FLUSH SHL 8) + 0 | ||
| 198 | INT int_command | ||
| 199 | |||
| 200 | MOV AX,(ECS_call SHL 8) OR SetInterimMode ;AN000; 3/3/KK | ||
| 201 | POP DX ;AN000; restore interim state 3/3/KK | ||
| 202 | INT int_command ;AN000; 3/3/KK | ||
| 203 | POP DX ;AN000; 3/3/KK | ||
| 204 | |||
| 205 | return | ||
| 206 | EndProc GetKeyStroke | ||
| 207 | |||
| 208 | Break <ReadBat - read 1 line from batch file> | ||
| 209 | |||
| 210 | ; | ||
| 211 | ; ReadBat - read a single line from the batch file. Perform all substitutions | ||
| 212 | ; as appropriate | ||
| 213 | ; | ||
| 214 | |||
| 215 | Procedure ReadBat,NEAR | ||
| 216 | ASSUME DS:ResGroup,ES:TranGroup | ||
| 217 | mov suppress,yes_echo ;g initialize line suppress status | ||
| 218 | test byte ptr [Batch_Abort],-1 | ||
| 219 | jnz Trying_To_Abort | ||
| 220 | mov byte ptr [In_Batch],1 ; set flag to indicate batch job | ||
| 221 | CALL PromptBat | ||
| 222 | |||
| 223 | Trying_To_Abort: | ||
| 224 | MOV DI,OFFSET TRANGROUP:COMBUF+2 | ||
| 225 | |||
| 226 | ; | ||
| 227 | ; Save position and try to scan for first non delimiter. | ||
| 228 | ; | ||
| 229 | |||
| 230 | TESTNOP: | ||
| 231 | MOV AX,DS | ||
| 232 | MOV DS,Batch | ||
| 233 | ASSUME DS:NOTHING | ||
| 234 | PUSH WORD PTR DS:[BatSeek] | ||
| 235 | PUSH WORD PTR DS:[BatSeek+2] ; save current location. | ||
| 236 | MOV DS,AX | ||
| 237 | ASSUME DS:ResGroup | ||
| 238 | invoke SkipDelim ; skip to first non-delim | ||
| 239 | ; | ||
| 240 | ; If the first non-delimiter is not a : (label), we reseek back to the | ||
| 241 | ; beginning and read the line. | ||
| 242 | ; | ||
| 243 | CMP AL,':' ; is it a label? | ||
| 244 | POP CX | ||
| 245 | POP DX ; restore position in bat file | ||
| 246 | JZ NopLine ; yes, resync everything. | ||
| 247 | TEST [BATCH],-1 ; are we done with the batch file? | ||
| 248 | JZ RdBat | ||
| 249 | |||
| 250 | CMP AL, NO_ECHO_CHAR ;g see if user wants to suppress line | ||
| 251 | JNZ SET_BAT_POS ;g no - go and set batch file position | ||
| 252 | MOV SUPPRESS, NO_ECHO ;g yes set flag to indicate | ||
| 253 | jmp Rdbat ;g go read batch file | ||
| 254 | |||
| 255 | SET_BAT_POS: ;g | ||
| 256 | PUSH DS | ||
| 257 | MOV DS,Batch | ||
| 258 | ASSUME DS:NOTHING | ||
| 259 | MOV WORD PTR DS:[BatSeek],DX ; reseek back to beginning | ||
| 260 | MOV WORD PTR DS:[BatSeek+2],CX | ||
| 261 | POP DS | ||
| 262 | ASSUME DS:ResGroup | ||
| 263 | MOV AX,(LSEEK SHL 8) + 0 ; seek back | ||
| 264 | INT int_command | ||
| 265 | MOV BatBufPos,-1 ; nuke batch buffer position | ||
| 266 | xor cx,cx ; Initialize line length to zero | ||
| 267 | JMP RdBat | ||
| 268 | ; | ||
| 269 | ; The first non-delimiter is a :. This line is not echoed and is ignored. | ||
| 270 | ; We eat characters until a CR is seen. | ||
| 271 | ; | ||
| 272 | |||
| 273 | NOPLINE: | ||
| 274 | CALL SkipToEOL | ||
| 275 | invoke GetBatByt ; eat trailing LF | ||
| 276 | TEST [BATCH],-1 ; are we done with the batch file? | ||
| 277 | JNZ TESTNOP ; no, go get another line | ||
| 278 | return ; Hit EOF | ||
| 279 | |||
| 280 | ; | ||
| 281 | ; Read a line into the buffer pointed to by ES:DI. If any %s are seen in the | ||
| 282 | ; input, we are to consider two special cases: | ||
| 283 | ; | ||
| 284 | ; %0 to %9 These represent replaceable parameters from the batch segment | ||
| 285 | ; %sym% This is a symbol from the environment | ||
| 286 | ; | ||
| 287 | |||
| 288 | RDBAT: | ||
| 289 | invoke GetBatByt | ||
| 290 | inc cx ; Inc the line length | ||
| 291 | cmp cx,COMBUFLEN ; Is it too long? | ||
| 292 | jae TooLong ; Yes - handle it, handle it | ||
| 293 | ; | ||
| 294 | ; See if we have a parameter character. | ||
| 295 | ; | ||
| 296 | CMP AL,'%' ; Check for parameter | ||
| 297 | JZ NEEDPARM | ||
| 298 | ; | ||
| 299 | ; no parameter character. Store it as usual and see if we are done. | ||
| 300 | ; | ||
| 301 | |||
| 302 | SAVBATBYT: | ||
| 303 | STOSB | ||
| 304 | CMP AL,0DH ; End of line found? | ||
| 305 | JNZ RDBAT ; no, go for more | ||
| 306 | ; | ||
| 307 | ; We have read in an entire line. Decide whether we should echo the command | ||
| 308 | ; line or not. | ||
| 309 | ; | ||
| 310 | |||
| 311 | Found_EOL: | ||
| 312 | SUB DI,OFFSET TRANGROUP:COMBUF+3 | ||
| 313 | MOV AX,DI ; remember that we've not counted the CR | ||
| 314 | MOV ES:[COMBUF+1],AL ; Set length of line | ||
| 315 | invoke GetBatByt ; Eat linefeed | ||
| 316 | invoke BATCLOSE | ||
| 317 | CMP SUPPRESS, NO_ECHO ;G | ||
| 318 | JZ Reset ;G | ||
| 319 | test [echoflag],1 ; To echo or not to echo, that is the | ||
| 320 | jnz try_nextflag | ||
| 321 | |||
| 322 | Reset: | ||
| 323 | PUSH CS ; question. (Profound, huh?) | ||
| 324 | POP DS ; Go back to local segment | ||
| 325 | retz ; no echoing here... | ||
| 326 | ; | ||
| 327 | ; Echo the command line with appropriate CRLF... | ||
| 328 | ; | ||
| 329 | |||
| 330 | |||
| 331 | try_nextflag: | ||
| 332 | cmp nullflag,nullcommand ;G was there a command last time? | ||
| 333 | jz No_crlf_print ;G no - don't print crlf | ||
| 334 | invoke CRLF2 ;G Print out prompt | ||
| 335 | |||
| 336 | no_crlf_print: | ||
| 337 | invoke PRINT_PROMPT ;G | ||
| 338 | PUSH CS ;G change data segment | ||
| 339 | POP DS ;G | ||
| 340 | |||
| 341 | ASSUME DS:TRANGROUP | ||
| 342 | mov dx,OFFSET TRANGROUP:COMBUF+2 ; get command line for echoing | ||
| 343 | invoke CRPRINT | ||
| 344 | invoke CRLF2 | ||
| 345 | return | ||
| 346 | ; | ||
| 347 | ; The line was too long. Eat remainder of input text up until the CR | ||
| 348 | ; | ||
| 349 | TooLong: | ||
| 350 | ASSUME DS:ResGroup | ||
| 351 | cmp al,0dh ; Has the end of the line been reached? | ||
| 352 | jz Ltlcont ; Yes, continue | ||
| 353 | CALL SkipToEOL ; Eat remainder of line | ||
| 354 | |||
| 355 | Ltlcont: | ||
| 356 | stosb ; Terminate the command | ||
| 357 | jmp Found_EOL ; Go process the valid part of the line | ||
| 358 | ; | ||
| 359 | ; We have found a parameter lead-in character. Check for the 0-9 case first | ||
| 360 | ; | ||
| 361 | |||
| 362 | NEEDPARM: | ||
| 363 | invoke GetBatByt ; get next character | ||
| 364 | CMP AL,'%' ; Check for two consecutive % | ||
| 365 | JZ SAVBATBYT ; if so, replace with a single % | ||
| 366 | CMP AL,0Dh ; Check for end-of-line | ||
| 367 | JZ SAVBATBYT ; yes, treat it normally | ||
| 368 | ; | ||
| 369 | ; We have found %<something>. If the <something> is in the range 0-9, we | ||
| 370 | ; retrieve the appropriate parameter from the batch segment. Otherwise we | ||
| 371 | ; see if the <something> has a terminating % and then look up the contents | ||
| 372 | ; in the environment | ||
| 373 | ; | ||
| 374 | PAROK: | ||
| 375 | SUB AL,'0' | ||
| 376 | JB NEEDENV ; look for parameter in the environment | ||
| 377 | CMP AL,9 | ||
| 378 | JA NEEDENV | ||
| 379 | ; | ||
| 380 | ; We have found %<number>. This is taken from the parameters in the | ||
| 381 | ; allocated batch area. | ||
| 382 | ; | ||
| 383 | CBW | ||
| 384 | MOV BX,AX ; move index into AX | ||
| 385 | SHL BX,1 ; convert word index into byte ptr | ||
| 386 | SaveReg <ES> | ||
| 387 | MOV ES,Batch | ||
| 388 | ; | ||
| 389 | ; The structure of the batch area is: | ||
| 390 | ; | ||
| 391 | ; BYTE type of segment | ||
| 392 | ; DWORD offset for next line | ||
| 393 | ; 10 WORD pointers to parameters. -1 is empty parameter | ||
| 394 | ; ASCIZ file name (with . and ..) | ||
| 395 | ; BYTES CR-terminated parameters | ||
| 396 | ; BYTE 0 flag to indicate end of parameters | ||
| 397 | ; | ||
| 398 | ; Get pointer to BX'th argument | ||
| 399 | ; | ||
| 400 | MOV SI,ES:BatParm[BX] | ||
| 401 | RestoreReg <ES> | ||
| 402 | ; | ||
| 403 | ; Is there a parameter here? | ||
| 404 | ; | ||
| 405 | CMP SI,-1 ; Check if parameter exists | ||
| 406 | JNZ Yes_there_is ;G Yes go get it | ||
| 407 | JMP RDBAT ; Ignore if it doesn't | ||
| 408 | ; | ||
| 409 | ; Copy in the found parameter from batch segment | ||
| 410 | ; | ||
| 411 | |||
| 412 | Yes_there_is: | ||
| 413 | PUSH DS | ||
| 414 | MOV DS,Batch | ||
| 415 | ASSUME DS:NOTHING | ||
| 416 | dec cx ; Don't count '%' in line length | ||
| 417 | |||
| 418 | CopyParm: | ||
| 419 | LODSB ; From resident segment | ||
| 420 | CMP AL,0DH ; Check for end of parameter | ||
| 421 | JZ EndParam | ||
| 422 | inc cx ; Inc the line length | ||
| 423 | cmp cx,COMBUFLEN ; Is it too long? | ||
| 424 | jae LineTooL ; Yes - handle it, handle it | ||
| 425 | STOSB | ||
| 426 | JMP CopyParm | ||
| 427 | ; | ||
| 428 | ; We have copied up to the limit. Stop copying and eat remainder of batch | ||
| 429 | ; line. We need to make sure that the tooLong code isn't fooled into | ||
| 430 | ; believing that we are at EOL. Clobber AL too. | ||
| 431 | ; | ||
| 432 | |||
| 433 | LineTooL: | ||
| 434 | XOR AL,AL | ||
| 435 | POP DS | ||
| 436 | ASSUME DS:RESGROUP | ||
| 437 | JMP TooLong | ||
| 438 | ; | ||
| 439 | ; We have copied in an entire parameter. Go back for more | ||
| 440 | ; | ||
| 441 | |||
| 442 | EndParam: | ||
| 443 | POP DS | ||
| 444 | JMP RDBat | ||
| 445 | ; | ||
| 446 | ; We have found % followed by something other than 0-9. We presume that there | ||
| 447 | ; will be a following % character. In between is an environment variable that | ||
| 448 | ; we will fetch and replace in the batch line with its value. | ||
| 449 | ; | ||
| 450 | |||
| 451 | NEEDENV: | ||
| 452 | SaveReg <DS,DI> | ||
| 453 | MOV DI,OFFSET TRANGROUP:ID ; temp spot for name | ||
| 454 | ADD AL,'0' ; reconvert character | ||
| 455 | STOSB ; store it in appropriate place | ||
| 456 | ; | ||
| 457 | ; loop getting characters until the next % is found or until EOL | ||
| 458 | ; | ||
| 459 | |||
| 460 | GETENV1: | ||
| 461 | invoke GetBatByt ; get the byte | ||
| 462 | STOSB ; store it | ||
| 463 | CMP AL,0Dh ; EOL? | ||
| 464 | JNZ GETENV15 ; no, see if it the term char | ||
| 465 | ; | ||
| 466 | ; The user entered a string with a % but no trailing %. We copy the string. | ||
| 467 | ; | ||
| 468 | mov byte ptr es:[di-1],0 ; nul terminate the string | ||
| 469 | mov si,offset TranGroup:ID ; point to buffer | ||
| 470 | pop di ; point to line buffer | ||
| 471 | push cs | ||
| 472 | pop ds | ||
| 473 | call StrCpy | ||
| 474 | IF IBMCOPYRIGHT | ||
| 475 | dec di | ||
| 476 | pop ds | ||
| 477 | ELSE | ||
| 478 | pop ds | ||
| 479 | jc LineTooL | ||
| 480 | ENDIF | ||
| 481 | jmp SavBatByt | ||
| 482 | |||
| 483 | getenv15: | ||
| 484 | CMP AL,'%' ; terminating %? | ||
| 485 | JNZ GETENV1 ; no, go suck out more characters | ||
| 486 | mov al,'=' ; terminate with = | ||
| 487 | MOV ES:[DI-1],al | ||
| 488 | ; | ||
| 489 | ; ID now either has a =-terminated string which we are to find in the | ||
| 490 | ; environment or a non =-terminated string which will not be found in the | ||
| 491 | ; environment. | ||
| 492 | ; | ||
| 493 | GETENV2: | ||
| 494 | MOV SI,OFFSET TRANGROUP:ID | ||
| 495 | PUSH CS | ||
| 496 | POP DS ; DS:SI POINTS TO NAME | ||
| 497 | ASSUME DS:TRANGROUP | ||
| 498 | PUSH CX | ||
| 499 | INVOKE FIND_NAME_IN_environment | ||
| 500 | ASSUME ES:RESGROUP | ||
| 501 | POP CX | ||
| 502 | PUSH ES | ||
| 503 | POP DS | ||
| 504 | assume ds:resgroup | ||
| 505 | PUSH CS | ||
| 506 | POP ES | ||
| 507 | ASSUME ES:TRANGROUP | ||
| 508 | MOV SI,DI | ||
| 509 | POP DI ; get back pointer to command line | ||
| 510 | ; | ||
| 511 | ; If the parameter was not found, there is no need to perform any replacement. | ||
| 512 | ; We merely pretend that we've copied the parameter. | ||
| 513 | ; | ||
| 514 | IF IBMCOPYRIGHT | ||
| 515 | JC GETENV6 | ||
| 516 | ELSE | ||
| 517 | jnc GETENV4 | ||
| 518 | pop ds | ||
| 519 | jmp rdbat | ||
| 520 | ENDIF | ||
| 521 | ; | ||
| 522 | ; ES:DI points to command line being built | ||
| 523 | ; DS:SI points either to nul-terminated environment object AFTER = | ||
| 524 | ; | ||
| 525 | |||
| 526 | GETENV4: | ||
| 527 | ASSUME ES:NOTHING | ||
| 528 | call StrCpy | ||
| 529 | |||
| 530 | IF IBMCOPYRIGHT | ||
| 531 | dec di | ||
| 532 | |||
| 533 | GETENV6: | ||
| 534 | POP DS ; restore pointer to resgroup | ||
| 535 | ELSE | ||
| 536 | pop ds | ||
| 537 | jc LineTooL | ||
| 538 | ENDIF | ||
| 539 | JMP RDBAT ; no, go back to batch file | ||
| 540 | |||
| 541 | EndProc ReadBat | ||
| 542 | |||
| 543 | ; | ||
| 544 | ; SkipToEOL - read from batch file until end of line | ||
| 545 | ; | ||
| 546 | |||
| 547 | Procedure SkipToEOL,NEAR | ||
| 548 | |||
| 549 | ASSUME DS:ResGroup,ES:NOTHING | ||
| 550 | |||
| 551 | TEST Batch,-1 | ||
| 552 | retz ; no batch file in effect | ||
| 553 | invoke GetBatByt | ||
| 554 | CMP AL,0Dh ; eol character? | ||
| 555 | JNZ SkipToEOL ; no, go eat another | ||
| 556 | return | ||
| 557 | |||
| 558 | EndProc SkipToEOL | ||
| 559 | |||
| 560 | Break <Allocate and deallocate the transient portion> | ||
| 561 | |||
| 562 | ; | ||
| 563 | ; Free Transient. Modify ES,AX,flags | ||
| 564 | ; | ||
| 565 | |||
| 566 | Procedure Free_TPA,NEAR | ||
| 567 | |||
| 568 | ASSUME DS:TRANGROUP,ES:RESGROUP | ||
| 569 | |||
| 570 | PUSH ES | ||
| 571 | MOV ES,[RESSEG] | ||
| 572 | MOV ES,[RES_TPA] | ||
| 573 | MOV AH,DEALLOC | ||
| 574 | INT int_command ; Make lots of free memory | ||
| 575 | POP ES | ||
| 576 | |||
| 577 | return | ||
| 578 | |||
| 579 | EndProc Free_TPA | ||
| 580 | |||
| 581 | ; | ||
| 582 | ; Allocate transient. Modify AX,BX,DX,flags | ||
| 583 | ; | ||
| 584 | |||
| 585 | Procedure Alloc_TPA,NEAR | ||
| 586 | |||
| 587 | ASSUME DS:TRANGROUP,ES:RESGROUP | ||
| 588 | |||
| 589 | PUSH ES | ||
| 590 | MOV ES,[RESSEG] | ||
| 591 | MOV BX,0FFFFH ; Re-allocate the transient | ||
| 592 | MOV AH,ALLOC | ||
| 593 | INT int_command | ||
| 594 | PUSH BX ; Save size of block | ||
| 595 | MOV AH,ALLOC | ||
| 596 | INT int_command | ||
| 597 | ; | ||
| 598 | ; Attempt to align TPA on 64K boundary | ||
| 599 | ; | ||
| 600 | POP BX ; Restore size of block | ||
| 601 | MOV [RES_TPA], AX ; Save segment to beginning of block | ||
| 602 | MOV [TRAN_TPA], AX | ||
| 603 | ; | ||
| 604 | ; Is the segment already aligned on a 64K boundary | ||
| 605 | ; | ||
| 606 | MOV DX, AX ; Save segment | ||
| 607 | AND AX, 0FFFH ; Test if above boundary | ||
| 608 | JNZ Calc_TPA | ||
| 609 | MOV AX, DX | ||
| 610 | AND AX, 0F000H ; Test if multiple of 64K | ||
| 611 | JNZ NOROUND | ||
| 612 | |||
| 613 | Calc_TPA: | ||
| 614 | MOV AX, DX | ||
| 615 | AND AX, 0F000H | ||
| 616 | ADD AX, 01000H ; Round up to next 64K boundary | ||
| 617 | JC NOROUND ; Memory wrap if carry set | ||
| 618 | ; | ||
| 619 | ; Make sure that new boundary is within allocated range | ||
| 620 | ; | ||
| 621 | MOV DX, [RES_TPA] | ||
| 622 | ADD DX, BX ; Compute maximum address | ||
| 623 | CMP DX, AX ; Is 64K address out of range? | ||
| 624 | JB NOROUND | ||
| 625 | ; | ||
| 626 | ; Make sure that we won't overwrite the transient | ||
| 627 | ; | ||
| 628 | MOV BX, CS ; CS is beginning of transient | ||
| 629 | CMP BX, AX | ||
| 630 | JB NOROUND | ||
| 631 | ; | ||
| 632 | ; The area from the 64K boundary to the beginning of the transient must | ||
| 633 | ; be at least 64K. | ||
| 634 | ; | ||
| 635 | SUB BX, AX | ||
| 636 | CMP BX, 4096 ; Size greater than 64K? | ||
| 637 | JAE ROUNDDONE | ||
| 638 | |||
| 639 | NOROUND: | ||
| 640 | MOV AX, [RES_TPA] | ||
| 641 | |||
| 642 | ROUNDDONE: | ||
| 643 | MOV [LTPA],AX ; Re-compute everything | ||
| 644 | MOV [TPA],AX | ||
| 645 | MOV BX,AX | ||
| 646 | MOV AX,CS | ||
| 647 | SUB AX,BX | ||
| 648 | PUSH BX | ||
| 649 | MOV BX,16 | ||
| 650 | MUL BX | ||
| 651 | POP BX | ||
| 652 | OR DX,DX | ||
| 653 | JZ SAVSIZ2 | ||
| 654 | MOV AX,-1 | ||
| 655 | |||
| 656 | SAVSIZ2: | ||
| 657 | ; | ||
| 658 | ; AX is the number of bytes free in the buffer between the resident and the | ||
| 659 | ; transient with a maximum of 64K-1. We round this down to a multiple of 512. | ||
| 660 | ; | ||
| 661 | CMP AX,512 | ||
| 662 | JBE GotSize | ||
| 663 | AND AX,0FE00h ; NOT 511 = NOT 1FF | ||
| 664 | |||
| 665 | GotSize: | ||
| 666 | MOV [BYTCNT],AX | ||
| 667 | POP ES | ||
| 668 | |||
| 669 | return | ||
| 670 | |||
| 671 | EndProc Alloc_TPA | ||
| 672 | |||
| 673 | Break <BatCom - enter a batch file> | ||
| 674 | |||
| 675 | ; | ||
| 676 | ; The exec search has determined that the user has requested a batch file for | ||
| 677 | ; execution. We parse the arguments, create the batch segment, and signal | ||
| 678 | ; batch processing. | ||
| 679 | ; | ||
| 680 | Procedure BatCom,NEAR | ||
| 681 | |||
| 682 | ASSUME DS:TRANGROUP, ES:NOTHING | ||
| 683 | |||
| 684 | ; | ||
| 685 | ; Batch parameters are read with ES set to segment of resident part | ||
| 686 | ; | ||
| 687 | |||
| 688 | MOV ES,[RESSEG] | ||
| 689 | ASSUME ES:RESGROUP | ||
| 690 | cmp es:[call_batch_flag],call_in_progress ;AN043; If in CALL, | ||
| 691 | jz skip_ioset ;AN043; redirection was already set up | ||
| 692 | invoke IOSET ; Set up any redirection | ||
| 693 | |||
| 694 | skip_ioset: ;AN043; | ||
| 695 | CALL FREE_TPA ; G | ||
| 696 | cmp es:[call_batch_flag],call_in_progress ;G | ||
| 697 | jz getecho ; G if we're in a call, don't execute | ||
| 698 | ; | ||
| 699 | ; Since BATCH has lower precedence than PIPE or FOR. If a new BATCH file is | ||
| 700 | ; being started it MUST be true that no FOR or PIPE is currently in progress. | ||
| 701 | ; Don't execute if in call | ||
| 702 | ; | ||
| 703 | invoke ForOff | ||
| 704 | |||
| 705 | getecho: | ||
| 706 | invoke PipeOff | ||
| 707 | mov al,EchoFlag ; preserve echo state for chaining | ||
| 708 | |||
| 709 | and al, 1 ; Save current echo state | ||
| 710 | push ax | ||
| 711 | |||
| 712 | xor ax,ax ;G | ||
| 713 | test es:[batch],-1 ;G Are we in a batch file? | ||
| 714 | jz leavebat ;G No, nothing to save | ||
| 715 | mov ax,es:[batch] ;G get current batch segment | ||
| 716 | cmp es:[call_batch_flag],call_in_progress ;G | ||
| 717 | jz leavebat ;G | ||
| 718 | ; | ||
| 719 | ; We are in a chained batch file, save batlast from previous batch segment | ||
| 720 | ; so that if we're in a CALL, we will return to the correct batch file. | ||
| 721 | ; | ||
| 722 | push es ;G | ||
| 723 | mov es,ax ;G get current batch segment | ||
| 724 | mov ax,es:[batlast] ;G get previous batch segment | ||
| 725 | pop es ;G | ||
| 726 | |||
| 727 | leavebat: ;G | ||
| 728 | push ax ;G keep segment until new one created | ||
| 729 | cmp es:[call_batch_flag],call_in_progress ;G are we in a CALL? | ||
| 730 | jz startbat ;G Yes, keep current batch segment | ||
| 731 | call BatchOff ;G No, deallocate old batch segment | ||
| 732 | |||
| 733 | ; | ||
| 734 | ; Find length of batch file | ||
| 735 | ; | ||
| 736 | |||
| 737 | startbat: ;G | ||
| 738 | ASSUME ES:RESGROUP | ||
| 739 | MOV es:[CALL_BATCH_FLAG], 0 ;G reset call flag | ||
| 740 | mov SI, OFFSET TRANGROUP:EXECPATH | ||
| 741 | |||
| 742 | mov ax,AppendTruename ;AN042; Get the real path where the batch file | ||
| 743 | int 2fh ;AN042; was found with APPEND | ||
| 744 | mov ah,Find_First ;AN042; The find_first will return it | ||
| 745 | mov dx,si ;AN042; Get the string | ||
| 746 | mov cx,search_attr ;AN042; filetypes to search for | ||
| 747 | int int_command ;AN042; | ||
| 748 | |||
| 749 | invoke DStrLen | ||
| 750 | ; | ||
| 751 | ; Allocate batch area: | ||
| 752 | ; BYTE type of segment | ||
| 753 | ; WORD segment of last batch file | ||
| 754 | ; WORD segment for FOR command | ||
| 755 | ; BYTE FOR flag state on entry to batch file | ||
| 756 | ; DWORD offset for next line | ||
| 757 | ; 10 WORD pointers to parameters. -1 is empty parameter | ||
| 758 | ; ASCIZ file name (with . and ..) | ||
| 759 | ; BYTES CR-terminated parameters | ||
| 760 | ; BYTE 0 flag to indicate end of parameters | ||
| 761 | ; | ||
| 762 | ; We allocate the maximum size for the command line and use setblock to shrink | ||
| 763 | ; later when we've squeezed out the extra | ||
| 764 | ; | ||
| 765 | |||
| 766 | MOV BX,CX ; length of file name. | ||
| 767 | ADD BX,0Fh + (SIZE BatchSegment) + COMBUFLEN + 0Fh | ||
| 768 | ; structure + max len + round up | ||
| 769 | SaveReg <CX> | ||
| 770 | MOV CL,4 | ||
| 771 | SHR BX,CL ; convert to paragraphs | ||
| 772 | PUSH BX ;G save size of batch segment | ||
| 773 | MOV AH,ALLOC | ||
| 774 | INT int_command ; Allocate batch segment | ||
| 775 | POP BX ;G get size of batch segment | ||
| 776 | ; | ||
| 777 | ; This should *NEVER* return an error. The transient is MUCH bigger than | ||
| 778 | ; the batch segment. This may not be true, however, in a multitasking system. | ||
| 779 | ; G This error will occur with nesting of batch files. We also need to | ||
| 780 | ; G make sure that we don't overlay the transient. | ||
| 781 | ; | ||
| 782 | jc mem_error ;G not enough memory - exit | ||
| 783 | push ax ;G save batch segment | ||
| 784 | add ax,bx ;G get end of batch segment | ||
| 785 | add ax,20h ;G add some tpa work area | ||
| 786 | mov bx,cs ;G get the transient segment | ||
| 787 | cmp ax,bx ;G do we end before the transient | ||
| 788 | pop ax ;G get batch segment back | ||
| 789 | jb enough_mem ;G we have enough memory - continue | ||
| 790 | push es ;G no we're hitting the transient | ||
| 791 | mov es,ax | ||
| 792 | mov ax,DEALLOC SHL 8 ;G deallocate the batch segment | ||
| 793 | int int_command | ||
| 794 | pop es | ||
| 795 | |||
| 796 | mem_error: | ||
| 797 | jmp no_memory ;G Set up for message and exit | ||
| 798 | |||
| 799 | enough_mem: | ||
| 800 | MOV [BATCH],AX | ||
| 801 | CALL ALLOC_TPA | ||
| 802 | ; | ||
| 803 | ; Initialize batch segment | ||
| 804 | ; | ||
| 805 | RestoreReg <DX> ; length of name | ||
| 806 | POP AX ;G get saved batch segment back | ||
| 807 | inc es:nest ;G increment # batch files in progress | ||
| 808 | PUSH ES | ||
| 809 | MOV ES,[BATCH] | ||
| 810 | ASSUME ES:NOTHING | ||
| 811 | MOV ES:[BatType],BatchType ; signal batch file type | ||
| 812 | MOV ES:[batlast],ax ;G save segment of last batch file | ||
| 813 | push DS ;G | ||
| 814 | mov DS,[resseg] ;G set to resident data | ||
| 815 | ASSUME DS:RESGROUP | ||
| 816 | xor ax,ax ;G | ||
| 817 | mov bl,forflag ;G get the current FOR state | ||
| 818 | mov ES:[batforflag],bl ;G save it in the batch segment | ||
| 819 | test bl,-1 ;G are we in a FOR? | ||
| 820 | jz for_not_on ;G no, for segment set to 0 | ||
| 821 | mov ax,forptr ;G yes, get current FOR segment | ||
| 822 | mov forflag,0 ;G reset forflag | ||
| 823 | |||
| 824 | for_not_on: | ||
| 825 | mov ES:[batforptr],ax ;G save FOR segment in batch segment | ||
| 826 | XOR AX,AX | ||
| 827 | mov forptr,ax ;G make sure for segment is not active | ||
| 828 | mov bl,echoflag ;G | ||
| 829 | pop DS ;G | ||
| 830 | |||
| 831 | mov byte ptr es:[Batechoflag],bl ;G save echo state of parent | ||
| 832 | MOV WORD PTR ES:[BatSeek],AX ; point to beginning of file | ||
| 833 | MOV WORD PTR ES:[BatSeek+2],AX | ||
| 834 | ; | ||
| 835 | ; Initialize pointers | ||
| 836 | ; | ||
| 837 | DEC AX ; put -1 into AX | ||
| 838 | MOV DI,BatParm ; point to parm area | ||
| 839 | MOV BX,DI | ||
| 840 | MOV CX,10 | ||
| 841 | REP STOSW ; Init to no parms | ||
| 842 | ; | ||
| 843 | ; Move in batch file name | ||
| 844 | ; | ||
| 845 | MOV CX,DX | ||
| 846 | rep movsb ; including NUL. | ||
| 847 | ; | ||
| 848 | ; Now copy the command line into batch segment, parsing the arguments along | ||
| 849 | ; the way. Segment will look like this: | ||
| 850 | ; | ||
| 851 | ; <arg0>CR<arg1>CR...<arg9>CR<arg10>CR...<ARGn>CR 0 | ||
| 852 | ; | ||
| 853 | ; or, in the case of fewer arguments: | ||
| 854 | ; | ||
| 855 | ; <arg0>CR<arg1>CR...<arg6>CR CR CR ... CR 0 | ||
| 856 | ; | ||
| 857 | MOV SI,OFFSET TRANGROUP:COMBUF+2 | ||
| 858 | MOV CX,10 ; at most 10 arguments | ||
| 859 | ; | ||
| 860 | ; Look for beginning of next argument | ||
| 861 | ; | ||
| 862 | EACHPARM: | ||
| 863 | invoke SCANOFF ; skip to argument | ||
| 864 | ; | ||
| 865 | ; AL is first non-delimiter. DS:SI points to char = AL | ||
| 866 | ; | ||
| 867 | CMP AL,0DH ; end of road? | ||
| 868 | JZ HAVPARM ; yes, no more arguments | ||
| 869 | ; | ||
| 870 | ; If CX = 0 then we have stored the most parm we can. Skip store | ||
| 871 | ; | ||
| 872 | JCXZ MOVPARM ; Only first 10 parms get pointers | ||
| 873 | ; | ||
| 874 | ; Go into allocated piece and stick in new argument pointer. | ||
| 875 | ; | ||
| 876 | MOV ES:[BX],DI ; store batch pointer | ||
| 877 | ADD BX,2 ; advance arg counter | ||
| 878 | ; | ||
| 879 | ; Move the parameter into batch segment | ||
| 880 | ; | ||
| 881 | MOVPARM: | ||
| 882 | LODSB ; get byte | ||
| 883 | INVOKE DELIM ; if delimiter | ||
| 884 | JZ ENDPARM ; then done with parm | ||
| 885 | STOSB ; store byte | ||
| 886 | CMP AL,0DH ; if CR then not delimiter | ||
| 887 | JZ HAVPARM ; but end of parm list, finish | ||
| 888 | JMP SHORT MOVPARM | ||
| 889 | ; | ||
| 890 | ; We have copied a parameter up until the first separator. Terminate it with | ||
| 891 | ; CR | ||
| 892 | ; | ||
| 893 | |||
| 894 | ENDPARM: | ||
| 895 | MOV AL,0DH | ||
| 896 | STOSB | ||
| 897 | JCXZ EACHPARM ; if no parameters, don't dec | ||
| 898 | DEC CX ; remember that we've seen one. | ||
| 899 | JMP SHORT EACHPARM | ||
| 900 | ; | ||
| 901 | ; We have parsed the entire line. Terminate the arg list | ||
| 902 | ; | ||
| 903 | |||
| 904 | HAVPARM: | ||
| 905 | XOR AL,AL | ||
| 906 | STOSB ; Nul terminate the parms | ||
| 907 | ; | ||
| 908 | ; Now we know EXACTLY how big the BATCH segment is. Round up size (from DI) | ||
| 909 | ; into paragraphs and setblock to the appropriate size | ||
| 910 | ; | ||
| 911 | LEA BX,[DI+15] | ||
| 912 | MOV CL,4 | ||
| 913 | SHR BX,CL | ||
| 914 | MOV AH,SetBlock | ||
| 915 | INT int_command | ||
| 916 | |||
| 917 | POP ES | ||
| 918 | ASSUME ES:RESGROUP | ||
| 919 | PUSH ES | ||
| 920 | POP DS ; Simply batch FCB setup | ||
| 921 | ASSUME DS:RESGROUP | ||
| 922 | CMP [SINGLECOM],-1 | ||
| 923 | JNZ NOBATSING | ||
| 924 | MOV [SINGLECOM],0FFF0H ; Flag single command BATCH job | ||
| 925 | |||
| 926 | NOBATSING: | ||
| 927 | ; | ||
| 928 | ; Enter the batch file with the current echo state | ||
| 929 | ; | ||
| 930 | pop ax ; Get original echo state | ||
| 931 | mov echoflag,al ;g restore it | ||
| 932 | JMP TCOMMAND | ||
| 933 | |||
| 934 | ; | ||
| 935 | ; The following is executed if there isn't enough memory for batch segment | ||
| 936 | ; | ||
| 937 | |||
| 938 | NO_MEMORY: | ||
| 939 | assume ds:trangroup,es:resgroup | ||
| 940 | pop dx ;g even up our stack | ||
| 941 | pop ax ;g | ||
| 942 | pop ax ;g | ||
| 943 | call Alloc_tpa ;g reallocate memory | ||
| 944 | mov msg_disp_class,ext_msg_class ;AN000; set up extended error msg class | ||
| 945 | mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer | ||
| 946 | mov Extend_Buf_ptr,error_not_enough_memory ;AN000; get message number in control block | ||
| 947 | jmp cerror ;g print error message and go... | ||
| 948 | |||
| 949 | EndProc BatCom | ||
| 950 | |||
| 951 | Procedure BatchOff | ||
| 952 | |||
| 953 | ASSUME DS:NOTHING,ES:NOTHING | ||
| 954 | |||
| 955 | SaveReg <AX,ES> | ||
| 956 | PUSH DS ;G | ||
| 957 | PUSH BX ;G | ||
| 958 | MOV ES,ResSeg | ||
| 959 | MOV DS,ResSeg ;G | ||
| 960 | ASSUME ES:ResGroup,DS:Resgroup ;G | ||
| 961 | MOV AX,Batch ; Free the batch segment | ||
| 962 | OR AX,AX | ||
| 963 | JZ nofree | ||
| 964 | |||
| 965 | PUSH ES | ||
| 966 | MOV ES,AX | ||
| 967 | test [echoflag],1 ;G Is echo on? | ||
| 968 | jnz echo_last_line ;G Yes - echo last line in file | ||
| 969 | mov suppress,no_echo ;G no - don't echo last line in file | ||
| 970 | |||
| 971 | echo_last_line: | ||
| 972 | MOV BL,ES:[BATECHOFLAG] ;G Get echo state | ||
| 973 | mov [echoflag],bl ;G and restore it | ||
| 974 | MOV BX,ES:[BATFORPTR] ;G Get FOR segment | ||
| 975 | MOV FORPTR,BX ;G and restore it | ||
| 976 | MOV BL,ES:[BATFORFLAG] ;G Get FOR flag | ||
| 977 | MOV FORFLAG,BL ;G and restore it | ||
| 978 | MOV BX,es:[batlast] ;G get old batch segment | ||
| 979 | MOV AH,DEALLOC | ||
| 980 | INT int_command | ||
| 981 | POP ES | ||
| 982 | MOV Next_BATCH,BX ;G reset batch segment | ||
| 983 | DEC es:NEST ;G | ||
| 984 | |||
| 985 | XOR AX,AX | ||
| 986 | MOV Batch,AX ; No batch in progress | ||
| 987 | |||
| 988 | NoFree: | ||
| 989 | POP BX ;G | ||
| 990 | pop ds ;G | ||
| 991 | RestoreReg <ES,AX> | ||
| 992 | |||
| 993 | return | ||
| 994 | |||
| 995 | EndProc BatchOff | ||
| 996 | |||
| 997 | |||
| 998 | IF IBMCOPYRIGHT | ||
| 999 | |||
| 1000 | Procedure StrCpy,near | ||
| 1001 | |||
| 1002 | push ax | ||
| 1003 | cycle: | ||
| 1004 | lodsb | ||
| 1005 | stosb | ||
| 1006 | or al,al | ||
| 1007 | jnz cycle | ||
| 1008 | pop ax | ||
| 1009 | |||
| 1010 | return | ||
| 1011 | |||
| 1012 | EndProc StrCpy | ||
| 1013 | |||
| 1014 | ELSE | ||
| 1015 | ; StrCpy - copy string, checking count in CX against COMBUFLEN | ||
| 1016 | ; Entry : DS:SI ==> source string | ||
| 1017 | ; ES:DI ==> destination string | ||
| 1018 | ; CX = current length of destination string | ||
| 1019 | ; Exit : string copied, CX updated, Carry set if length limit exceeded | ||
| 1020 | Procedure StrCpy,NEAR | ||
| 1021 | push ax | ||
| 1022 | ccycle: | ||
| 1023 | lodsb | ||
| 1024 | inc cx | ||
| 1025 | cmp cx,COMBUFLEN | ||
| 1026 | jb ccopy | ||
| 1027 | stc ; set carry to signal error | ||
| 1028 | jmp short ccend | ||
| 1029 | ccopy: | ||
| 1030 | stosb | ||
| 1031 | or al,al | ||
| 1032 | jnz ccycle | ||
| 1033 | |||
| 1034 | ccend: | ||
| 1035 | dec cx ; discount extra byte | ||
| 1036 | dec di ; back up pointer | ||
| 1037 | pop ax | ||
| 1038 | return ; return carry clear | ||
| 1039 | EndProc StrCpy | ||
| 1040 | |||
| 1041 | ENDIF | ||
| 1042 | |||
| 1043 | TRANCODE ENDS | ||
| 1044 | END | ||
| 1045 | |||