]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/COMMAND/TENV.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / CMD / COMMAND / TENV.ASM
1 page 80,132
2 ; SCCSID = @(#)tenv.asm 4.2 85/08/16
3 ; SCCSID = @(#)tenv.asm 4.2 85/08/16
4 TITLE Part6 COMMAND Transient routines.
5
6 ; Environment utilities and misc. routines
7
8 INCLUDE comsw.asm
9
10 .xlist
11 .xcref
12 INCLUDE DOSSYM.INC
13 INCLUDE comseg.asm
14 INCLUDE comequ.asm
15 INCLUDE DOSCNTRY.INC ;AN000;
16 .list
17 .cref
18
19
20 DATARES SEGMENT PUBLIC BYTE ;AC000;
21 EXTRN comdrv:byte
22 EXTRN comspec_end:word
23 EXTRN comspec_print:word
24 EXTRN cpdrv:byte
25 EXTRN dbcs_vector_addr:dword ;AN000;
26 EXTRN ENVIRSEG:WORD
27 EXTRN fucase_addr:word ;AC000;
28 EXTRN RESTDIR:BYTE
29 DATARES ENDS
30
31 TRANDATA SEGMENT PUBLIC BYTE ;AC000;
32 EXTRN arg_buf_ptr:word
33 EXTRN comspec:byte
34 EXTRN comspec_flag:byte
35 EXTRN comspecstr:byte
36 EXTRN ENVERR_PTR:WORD
37 EXTRN PATH_TEXT:byte
38 EXTRN PROMPT_TEXT:byte
39 EXTRN SYNTMES_PTR:WORD
40 TRANDATA ENDS
41
42 TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
43 EXTRN Arg_Buf:BYTE
44 EXTRN RESSEG:WORD
45 EXTRN USERDIR1:BYTE
46 TRANSPACE ENDS
47
48 TRANCODE SEGMENT PUBLIC byte
49
50 ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
51
52 EXTRN cerror:near
53
54 PUBLIC add_name_to_environment
55 PUBLIC add_prompt
56 PUBLIC delete_path
57 PUBLIC find_name_in_environment
58 PUBLIC find_path
59 PUBLIC find_prompt
60 PUBLIC move_name
61 PUBLIC restudir
62 PUBLIC restudir1
63 PUBLIC scan_double_null
64 PUBLIC scasb2
65 PUBLIC store_char
66 PUBLIC Testkanj ;AN000; 3/3/KK
67 PUBLIC upconv
68
69 BREAK <Environment utilities>
70 ASSUME DS:TRANGROUP
71
72 break Prompt command
73 assume ds:trangroup,es:trangroup
74
75 ADD_PROMPT:
76 CALL DELETE_PROMPT ; DELETE ANY EXISTING PROMPT
77 CALL SCAN_DOUBLE_NULL
78
79 ADD_PROMPT2:
80 PUSH SI
81 CALL GETARG
82 POP SI
83 retz ; PRE SCAN FOR ARGUMENTS
84 CALL MOVE_NAME ; MOVE IN NAME
85 CALL GETARG
86 PUSH SI
87 JMP SHORT ADD_NAME
88
89
90 break The SET command
91 assume ds:trangroup,es:trangroup
92
93 ;
94 ; Input: DS:SI points to a CR terminated string
95 ; Output: carry flag is set if no room
96 ; otherwise name is added to environment
97 ;
98
99 DISP_ENVj:
100 jmp DISP_ENV
101
102 ADD_NAME_TO_ENVIRONMENT:
103 CALL GETARG
104 JZ DISP_ENVj
105 ;
106 ; check if line contains exactly one equals sign
107 ;
108 XOR BX,BX ;= COUNT IS 0
109 PUSH SI ;SAVE POINTER TO BEGINNING OF LINE
110
111 EQLP:
112 LODSB ;GET A CHAR
113 CMP AL,13 ;IF CR WE'RE ALL DONE
114 JZ QUEQ
115 CMP AL,'=' ;LOOK FOR = SIGN
116 JNZ EQLP ;NOT THERE, GET NEXT CHAR
117 INC BL ;OTHERWISE INCREMENT EQ COUNT
118 CMP BYTE PTR [SI],13 ;LOOK FOR CR FOLLOWING = SIGN
119 JNZ EQLP
120 INC BH ;SET BH=1 MEANS NO PARAMETERS
121 JMP EQLP ;AND LOOK FOR MORE
122
123 QUEQ:
124 POP SI ;RESTORE BEGINNING OF LINE
125 DEC BL ;ZERO FLAG MEANS ONLY ONE EQ
126 JZ ONEQ ;GOOD LINE
127 MOV DX,OFFSET TRANGROUP:SYNTMES_ptr
128 JMP CERROR
129
130 ONEQ:
131 PUSH BX
132 CALL DELETE_NAME_IN_ENVIRONMENT
133 POP BX
134 DEC BH
135 retz
136
137 CALL SCAN_DOUBLE_NULL
138 mov bx,di ; Save ptr to beginning of env var name
139 CALL MOVE_NAME
140 push si
141 xchg bx,di ; Switch ptrs to beginning and end of
142 ; env var name
143 ;
144 ; We want to special-case COMSPEC. This is to reduce the amount of code
145 ; necessary in the resident for re-reading the transient. Let's look for
146 ; COMSPEC=
147 ;
148 mov si,offset trangroup:comspecstr ; Load ptr to string "COMSPEC"
149 mov cx,4 ; If the new env var is comspec, set
150 repz cmpsw ; the comspec_flag
151 ;
152 ; Zero set => exact match
153 ;
154 jnz not_comspec
155 mov comspec_flag,1
156
157 not_comspec:
158 mov di,bx ; Load ptr to end of env var name
159
160 ADD_NAME: ; Add the value of the new env var
161 pop si ; to the environment.
162 push si
163
164 add_name1:
165 LODSB
166 CMP AL,13
167 jz add_name_ret
168 CALL STORE_CHAR
169 JMP ADD_NAME1
170
171 add_name_ret:
172 pop si
173 cmp comspec_flag,0 ; If the new env var is comspec,
174 retz ; copy the value into the
175 ;
176 ; We have changed the COMSPEC variable. We need to update the resident
177 ; pieces necessary to reread in the info. First, skip all delimiters
178 ;
179 invoke ScanOff
180 mov es,[resseg] ; comspec var in the resident
181 assume es:resgroup
182 ;
183 ; Make sure that the printer knows where the beginning of the string is
184 ;
185 mov di,offset resgroup:comspec
186 mov bx,di
187 ;
188 ; Generate drive letter for display
189 ;
190 xor ax,ax ;g assume no drive first
191 mov comdrv,al ;g
192 push ax ;AN000; 3/3/KK
193 mov al,[si] ;AN000; 3/3/KK
194 call testkanj ;AN000; 3/3/KK
195 pop ax ;AN000; 3/3/KK
196 jnz GotDrive
197 cmp byte ptr [si+1],':' ; drive specified?
198 jnz GotDrive
199 mov al,[si] ; get his specified drive
200 call UpConv ; convert to uppercase
201 sub al,'A' ; convert to 0-based
202 add di,2
203 inc al ; convert to 1-based number
204 mov comdrv,al
205 ;
206 ; Stick the drive letter in the prompt message. Nothing special needs to be
207 ; done here..
208 ;
209
210 add al,'A'-1
211
212 GotDrive: ;g
213 mov comspec_print,di ;g point to beginning of name after drive
214 mov es:cpdrv,al
215 ;
216 ; Copy chars until delim
217 ;
218
219 mov di,bx
220
221 copy_comspec:
222 lodsb
223 invoke Delim
224 jz CopyDone
225 cmp al,13
226 jz CopyDone
227 stosb
228 jmp short copy_comspec
229
230 CopyDone:
231 xor al,al ; Null terminate the string and quit
232 stosb
233 mov comspec_flag,0
234 dec di
235 mov comspec_end,di
236
237 ret
238
239 DISP_ENV:
240 MOV DS,[RESSEG]
241 ASSUME DS:RESGROUP
242 MOV DS,[ENVIRSEG]
243 ASSUME DS:NOTHING
244 XOR SI,SI
245
246 PENVLP:
247 CMP BYTE PTR [SI],0
248 retz
249 mov di,offset trangroup:arg_buf
250
251 PENVLP2:
252 LODSB
253 stosb
254 OR AL,AL
255 JNZ PENVLP2
256 mov dx,offset trangroup:arg_buf_ptr
257 push ds
258 push es
259 pop ds
260 invoke printf_crlf
261 pop ds
262 JMP PENVLP
263
264 ASSUME DS:TRANGROUP
265
266 DELETE_PATH:
267 MOV SI,OFFSET TRANGROUP:PATH_TEXT
268 JMP SHORT DELETE_NAME_IN_environment
269
270 DELETE_PROMPT:
271 MOV SI,OFFSET TRANGROUP:PROMPT_TEXT
272
273 DELETE_NAME_IN_environment:
274 ;
275 ; Input: DS:SI points to a "=" terminated string
276 ; Output: carry flag is set if name not found
277 ; otherwise name is deleted
278 ;
279 PUSH SI
280 PUSH DS
281 CALL FIND ; ES:DI POINTS TO NAME
282 JC DEL1
283 MOV SI,DI ; SAVE IT
284 CALL SCASB2 ; SCAN FOR THE NUL
285 XCHG SI,DI
286 CALL GETENVSIZ
287 SUB CX,SI
288 PUSH ES
289 POP DS ; ES:DI POINTS TO NAME, DS:SI POINTS TO NEXT NAME
290 REP MOVSB ; DELETE THE NAME
291
292 DEL1:
293 POP DS
294 POP SI
295 return
296
297 FIND_PATH:
298 MOV SI,OFFSET TRANGROUP:PATH_TEXT
299 JMP SHORT FIND_NAME_IN_environment
300
301 FIND_PROMPT:
302 MOV SI,OFFSET TRANGROUP:PROMPT_TEXT
303
304 FIND_NAME_IN_environment:
305 ;
306 ; Input: DS:SI points to a "=" terminated string
307 ; Output: ES:DI points to the arguments in the environment
308 ; zero is set if name not found
309 ; carry flag is set if name not valid format
310 ;
311 CALL FIND ; FIND THE NAME
312 retc ; CARRY MEANS NOT FOUND
313 JMP SCASB1 ; SCAN FOR = SIGN
314 ;
315 ; On return of FIND1, ES:DI points to beginning of name
316 ;
317 FIND:
318 CLD
319 CALL COUNT0 ; CX = LENGTH OF NAME
320 MOV ES,[RESSEG]
321 ASSUME ES:RESGROUP
322 MOV ES,[ENVIRSEG]
323 ASSUME ES:NOTHING
324 XOR DI,DI
325
326 FIND1:
327 PUSH CX
328 PUSH SI
329 PUSH DI
330
331 FIND11:
332 LODSB
333 CALL TESTKANJ
334 JZ NOTKANJ3
335 DEC SI
336 LODSW
337 INC DI
338 INC DI
339 CMP AX,ES:[DI-2]
340 JNZ FIND12
341 DEC CX
342 LOOP FIND11
343 JMP SHORT FIND12
344
345 NOTKANJ3:
346 CALL UPCONV
347 INC DI
348 CMP AL,ES:[DI-1]
349 JNZ FIND12
350 LOOP FIND11
351
352 FIND12:
353 POP DI
354 POP SI
355 POP CX
356 retz
357 PUSH CX
358 CALL SCASB2 ; SCAN FOR A NUL
359 POP CX
360 CMP BYTE PTR ES:[DI],0
361 JNZ FIND1
362 STC ; INDICATE NOT FOUND
363 return
364
365 COUNT0:
366 PUSH DS
367 POP ES
368 MOV DI,SI
369
370 COUNT1:
371 PUSH DI ; COUNT NUMBER OF CHARS UNTIL "="
372 CALL SCASB1
373 JMP SHORT COUNTX
374
375 COUNT2:
376 PUSH DI ; COUNT NUMBER OF CHARS UNTIL NUL
377 CALL SCASB2
378
379 COUNTX:
380 POP CX
381 SUB DI,CX
382 XCHG DI,CX
383 return
384
385 MOVE_NAME:
386 CMP BYTE PTR DS:[SI],13
387 retz
388 LODSB
389
390 ;;;; IF KANJI 3/3/KK
391 CALL TESTKANJ
392 JZ NOTKANJ1
393 CALL STORE_CHAR
394 LODSB
395 CALL STORE_CHAR
396 JMP SHORT MOVE_NAME
397
398 NOTKANJ1:
399 ;;;; ENDIF 3/3/KK
400
401 CALL UPCONV
402 CALL STORE_CHAR
403 CMP AL,'='
404 JNZ MOVE_NAME
405 return
406
407 GETARG:
408 MOV SI,80H
409 LODSB
410 OR AL,AL
411 retz
412 invoke SCANOFF
413 CMP AL,13
414 return
415
416 ;
417 ; Point ES:DI to the final NULL string. Note that in an empty environment,
418 ; there is NO double NULL, merely a string that is empty.
419 ;
420 SCAN_DOUBLE_NULL:
421 MOV ES,[RESSEG]
422 ASSUME ES:RESGROUP
423 MOV ES,[ENVIRSEG]
424 ASSUME ES:NOTHING
425 XOR DI,DI
426 ;
427 ; Top cycle-point. If the string here is empty, then we are done
428 ;
429 SDN1:
430 cmp byte ptr es:[di],0 ; nul string?
431 retz ; yep, all done
432 CALL SCASB2
433 JMP SDN1
434
435 SCASB1:
436 MOV AL,'=' ; SCAN FOR AN =
437 JMP SHORT SCASBX
438 SCASB2:
439 XOR AL,AL ; SCAN FOR A NUL
440 SCASBX:
441 MOV CX,100H
442 REPNZ SCASB
443 return
444
445 TESTKANJ:
446 push ds ;AN000; 3/3/KK
447 push si ;AN000; 3/3/KK
448 push ax ;AN000; 3/3/KK
449 mov ds,cs:[resseg] ;AN000; Get resident segment
450 assume ds:resgroup ;AN000;
451 lds si,dbcs_vector_addr ;AN000; get DBCS vector
452 ktlop: ;AN000; 3/3/KK
453 cmp word ptr ds:[si],0 ;AN000; end of Table 3/3/KK
454 je notlead ;AN000; 3/3/KK
455 pop ax ;AN000; 3/3/KK
456 push ax ;AN000; 3/3/KK
457 cmp al, byte ptr ds:[si] ;AN000; 3/3/KK
458 jb notlead ;AN000; 3/3/KK
459 inc si ;AN000; 3/3/KK
460 cmp al, byte ptr ds:[si] ;AN000; 3/3/KK
461 jbe islead ;AN000; 3/3/KK
462 inc si ;AN000; 3/3/KK
463 jmp short ktlop ;AN000; try another range ; 3/3/KK
464 Notlead: ;AN000; 3/3/KK
465 xor ax,ax ;AN000; set zero 3/3/KK
466 jmp short ktret ;AN000; 3/3/KK
467 Islead: ;AN000; 3/3/KK
468 xor ax,ax ;AN000; reset zero 3/3/KK
469 inc ax ;AN000; 3/3/KK
470 ktret: ;AN000; 3/3/KK
471 pop ax ;AN000; 3/3/KK
472 pop si ;AN000; 3/3/KK
473 pop ds ;AN000; 3/3/KK
474 return ;AN000; 3/3/KK
475 ;------------------------------------- ;3/3/KK
476
477
478 ; ****************************************************************
479 ; *
480 ; * ROUTINE: UPCONV (ADDED BY EMG 4.00)
481 ; *
482 ; * FUNCTION: This routine returns the upper case equivalent of
483 ; * the character in AL from the file upper case table
484 ; * in DOS if character if above ascii 128, else
485 ; * subtracts 20H if between "a" and "z".
486 ; *
487 ; * INPUT: AL char to be upper cased
488 ; * FUCASE_ADDR set to the file upper case table
489 ; *
490 ; * OUTPUT: AL upper cased character
491 ; *
492 ; ****************************************************************
493
494 assume ds:trangroup ;AN000;
495
496 upconv proc near ;AN000;
497
498 cmp al,80h ;AN000; see if char is > ascii 128
499 jb oth_fucase ;AN000; no - upper case math
500 sub al,80h ;AN000; only upper 128 chars in table
501 push ds ;AN000;
502 push bx ;AN000;
503 mov ds,[resseg] ;AN000; get resident data segment
504 assume ds:resgroup ;AN000;
505 lds bx,dword ptr fucase_addr+1 ;AN000; get table address
506 add bx,2 ;AN000; skip over first word
507 xlat ds:byte ptr [bx] ;AN000; convert to upper case
508 pop bx ;AN000;
509 pop ds ;AN000;
510 assume ds:trangroup ;AN000;
511 jmp short upconv_end ;AN000; we finished - exit
512
513 oth_fucase: ;AN000;
514 cmp al,small_a ;AC000; if between "a" and "z",
515 jb upconv_end ;AC000; subtract 20h to get
516 cmp al,small_z ;AC000; upper case equivalent.
517 ja upconv_end ;AC000;
518 sub al,20h ;AC000; Change lower-case to upper
519
520 upconv_end: ;AN000;
521 ret
522
523 upconv endp ;AN000;
524
525
526 ;
527 ; STORE A CHAR IN environment, GROWING IT IF NECESSARY
528 ;
529 STORE_CHAR:
530 PUSH CX
531 PUSH BX
532 PUSH ES ;AN056;
533 PUSH DS ;AN056; Save local DS
534 MOV DS,[RESSEG] ;AN056; Get resident segment
535 ASSUME DS:RESGROUP ;AN056;
536 MOV ES,[ENVIRSEG] ;AN056; Get environment segment
537 ASSUME ES:NOTHING ;AN056;
538 POP DS ;AN056; Get local segment back
539 ASSUME DS:TRANGROUP ;AN056;
540 CALL GETENVSIZ
541 MOV BX,CX
542 SUB BX,2 ; SAVE ROOM FOR DOUBLE NULL
543 CMP DI,BX
544 JB STORE1
545
546 PUSH AX
547 PUSH CX
548 PUSH BX ; Save Size of environment
549 invoke FREE_TPA
550 POP BX
551 ADD BX,2 ; Recover true environment size
552
553 CMP BX, 8000H ; Don't let environment grow > 32K
554 JB ENVSIZ_OK
555 BAD_ENV_SIZE: ;AN056;
556 STC
557 JMP ENVNOSET
558 ENVSIZ_OK:
559
560 MOV CL,4
561 SHR BX,CL ; Convert back to paragraphs
562 INC BX ; Try to grow environment by one para
563 MOV CX,ES ;AN056; Get environment segment
564 ADD CX,BX ;AN056; Add in size of environment
565 ADD CX,020H ;AN056; Add in some TPA
566 MOV AX,CS ;AN056; Get the transient segment
567 CMP CX,AX ;AN056; Are we hitting the transient?
568 JNB BAD_ENV_SIZE ;AN056; Yes - don't do it!!!
569 MOV AH,SETBLOCK
570 INT int_command
571 ENVNOSET:
572 PUSHF
573 PUSH ES
574 MOV ES,[RESSEG]
575 invoke ALLOC_TPA
576 POP ES
577 POPF
578 POP CX
579 POP AX
580 JNC STORE1
581 POP ES ;AN056;
582 MOV DX,OFFSET TRANGROUP:ENVERR_ptr
583 JMP CERROR
584 STORE1:
585 STOSB
586 MOV WORD PTR ES:[DI],0 ; NULL IS AT END
587 POP ES ;AN056;
588 POP BX
589 POP CX
590 return
591
592 GETENVSIZ:
593 ;Get size of environment in bytes, rounded up to paragraph boundry
594 ;ES has environment segment
595 ;Size returned in CX, all other registers preserved
596
597 PUSH ES
598 PUSH AX
599 MOV AX,ES
600 DEC AX ;Point at arena
601 MOV ES,AX
602 MOV AX,ES:[arena_size]
603 MOV CL,4
604 SHL AX,CL ;Convert to bytes
605 MOV CX,AX
606 POP AX
607 POP ES
608 return
609
610
611 ASSUME DS:TRANGROUP
612
613
614 RESTUDIR1:
615 PUSH DS
616 MOV DS,[RESSEG]
617 ASSUME DS:RESGROUP
618 CMP [RESTDIR],0
619 POP DS
620 ASSUME DS:TRANGROUP
621 retz
622
623 RESTUDIR:
624 MOV DX,OFFSET TRANGROUP:USERDIR1
625 MOV AH,CHDIR
626 INT int_command ; Restore users DIR
627 XOR AL,AL
628 invoke SETREST
629 RET56:
630 return
631
632 trancode ends
633 end