1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
|
page 80,132
; SCCSID = @(#)tenv2.asm 1.1 85/05/14
; SCCSID = @(#)tenv2.asm 1.1 85/05/14
TITLE Part6 COMMAND Transient routines.
; Environment utilities and misc. routines
INCLUDE comsw.asm
.xlist
.xcref
INCLUDE DOSSYM.INC
INCLUDE comseg.asm
INCLUDE comequ.asm
.list
.cref
DATARES SEGMENT PUBLIC BYTE ;AC000;
EXTRN pipeflag:byte
DATARES ENDS
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
EXTRN ACRLF_PTR:WORD
EXTRN BadCD_Ptr:WORD
EXTRN Badmkd_ptr:word
EXTRN BADRMD_PTR:WORD
EXTRN Extend_buf_ptr:word ;AN000;
EXTRN Extend_buf_sub:byte ;AN022;
EXTRN MD_exists_ptr:word ;AN006;
EXTRN msg_disp_class:byte ;AC000;
EXTRN NOSPACE_PTR:WORD
EXTRN parse_chdir:byte ;AC000;
EXTRN parse_mrdir:byte ;AC000;
EXTRN PIPEEMES_PTR:WORD
EXTRN string_buf_ptr:word
TRANDATA ENDS
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
EXTRN CURDRV:BYTE
EXTRN DESTINFO:BYTE
EXTRN DESTTAIL:WORD
EXTRN DIRCHAR:BYTE
EXTRN dirflag:byte ;AN015;
EXTRN KPARSE:BYTE ;AC000; 3/3/KK
EXTRN msg_numb:word ;AN022;
EXTRN parse1_addr:dword ;AC000;
EXTRN parse1_type:byte ;AC000;
EXTRN PATHPOS:WORD
EXTRN RESSEG:WORD
EXTRN srcxname:byte ;AC000;
EXTRN string_ptr_2:word
EXTRN SWITCHAR:BYTE
EXTRN USERDIR1:BYTE
TRANSPACE ENDS
TRANCODE SEGMENT PUBLIC byte
ASSUME CS:TRANGROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
EXTRN cerror:near
PUBLIC $chdir
PUBLIC $mkdir
PUBLIC $rmdir
PUBLIC crlf2
PUBLIC crprint
PUBLIC delim
PUBLIC error_output
PUBLIC fcb_to_ascz
PUBLIC pathchrcmp
PUBLIC pathcrunch
PUBLIC savudir
PUBLIC savudir1
PUBLIC scanoff
PUBLIC strcomp
break $Chdir
; ****************************************************************
; *
; * ROUTINE: $CHDIR
; *
; * FUNCTION: Entry point for CHDIR command. Parse the command
; * line. If path is found, CHDIR to path. If a drive
; * letter is found, get and display the current dir
; * of the specified drive. If nothing is found, get
; * and display the current dir of the default drive.
; *
; * INPUT: command line at offset 81H
; *
; * OUTPUT: none
; *
; ****************************************************************
assume ds:trangroup,es:trangroup
$CHDIR:
mov si,81H
mov di,offset trangroup:parse_chdir ;AN000; Get adderss of PARSE_CHDIR
xor cx,cx ;AN000; clear cx,dx
xor dx,dx ;AN000;
invoke parse_with_msg ;AC018; call parser
cmp ax,end_of_line ;AC000; are we at end of line?
jz bwdJ ; No args
cmp ax,result_no_error ;AC000; did we have an error?
jnz ChDirErr ;AC018; yes - exit
cmp parse1_type,result_drive ;AC000; was a drive entered?
jnz REALCD ; no
;
; D: was found. See if there is anything more.
;
mov di,offset trangroup:parse_chdir ;AC000; get address of parse_chdir
xor dx,dx ;AC000;
invoke parse_check_eol ;AC000; call parser
jnz ChDirErr ;AC000;
bwdJ:
invoke build_dir_for_chdir ; Drive only specified
call crlf2
return
REALCD:
push si ;AN000; save position in line
lds si,parse1_addr ;AN000; get address of filespec
invoke move_to_srcbuf ;AN000; move to srcbuf
pop si ;AN000; restore position in line
mov di,offset trangroup:parse_chdir ;AC000; get address of parse_chdir
xor dx,dx ;AC000;
invoke parse_check_eol ;AC000; call parser
jnz ChDirErr ;AC000;
invoke SETPATH
TEST [DESTINFO],2
JNZ BadChdir
MOV AH,CHDIR
INT int_command
retnc
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; see if path not found
jz BadChDir ;AN022; yes - issue old message
call Set_Ext_Error_Subst ;AN022;
jmp short chdirerr ;AN022;
BadChDir:
MOV DX,OFFSET TRANGROUP:BADCD_ptr
ChDirErr:
invoke Std_Eprintf
return
break $Mkdir
assume ds:trangroup,es:trangroup
$MKDIR:
CALL SETRMMK
JC MkDirErr
MOV AH,MKDIR
INT int_command
retnc
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; see if path not found
jz MD_other_err ;AN022; yes - issue old message
cmp ax,error_access_denied ;AN022; access denied?
jz badmderr ;AN022; yes - see if file exists
call Set_Ext_Error_Subst ;AN022;
jmp short MkDirerr ;AC022; yes - go print it
BADMDERR:
mov dx,offset trangroup:srcxname ;AN006; Set Disk transfer address
mov ah,Set_DMA ;AN006;
int int_command ;AN006;
MOV AH,Find_First ;AN006; see if file/dir exists
mov cx,attr_directory ;AN006; search for directory
INT int_command ;AN006;
jc MD_other_err ;AN006; doesn't exist - must be something else
mov dl,srcxname.find_buf_attr ;AN006; we found a file/dir
test dl,attr_directory ;AN006; was it a directory?
jz MD_other_err ;AN006; no - must have been a file
mov dx,offset trangroup:MD_exists_ptr ;AN006; set up already exists error
jmp short MkDirErr ;AN006; make sure we didn't have network error
MD_other_err: ;AN006;
MOV DX,OFFSET TRANGROUP:BADMKD_ptr
MkDirErr:
invoke Std_Eprintf
return
Break <Common MkDir/RmDir set up code>
;****************************************************************
;*
;* ROUTINE: SETRMMK
;*
;* FUNCTION: Parse routine for the internal MKDIR and RMDIR
;* commands. Parses the command line for a required
;* filespec.
;*
;* INPUT: command line at offset 81H
;*
;* OUTPUT: carry clear
;* DS:DX points to ASCIIZ argument
;* carry set
;* DS:DX has error message pointer
;*
;****************************************************************
SETRMMK:
mov si,81H
mov di,offset trangroup:parse_mrdir ;AN000; Get adderss of PARSE_MRDIR
xor cx,cx ;AN000; clear cx,dx
xor dx,dx ;AN000;
invoke parse_with_msg ;AC000; call parser
cmp ax,result_no_error ;AC000; did we have an error?
jnz NOARGERR ;AC000; yes - exit
mov di,offset trangroup:srcxname ;AN000; get address of srcxname
push di ;AN000; save address
push si ;AN000; save position in line
lds si,parse1_addr ;AN000; get address of path
mrdir_move_filename: ;AN000; put filespec in srcxname
lodsb ;get a char from buffer
stosb ;AN000; store in srcxname
cmp al,end_of_line_out ;AC000; it char a terminator?
jnz mrdir_move_filename ;AC000; no - keep moving
pop si ;AN000; get line position back
;
; we have scanned an argument. See if any args beyond.
;
mov di,offset trangroup:parse_mrdir ;AC000; get address of parse_mrdir
invoke parse_check_eol ;AC000; are we at end of line?
pop dx ;AC000; get address of SRCXNAME
retz ;yes - return no error
NOARGERR:
mov dx,offset TranGroup:Extend_Buf_ptr ;AC000; get extended message pointer
XOR AX,AX
STC
return
break $Rmdir
assume ds:trangroup,es:trangroup
$RMDIR:
CALL SETRMMK
JC RmDirErr
JNZ BADRDERR
MOV AH,RMDIR
INT int_command
retnc
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; see if path not found
jz badrderr ;AN022; yes - issue old message
cmp ax,error_access_denied ;AN022; access denied?
jz badrderr ;AN022; yes - issue old message
call Set_Ext_Error_Subst ;AN022;
jmp short RmDirerr ;AC022; yes - go print it
BADRDERR:
MOV DX,OFFSET TRANGROUP:BADRMD_ptr
RmDirErr:
invoke STD_Eprintf
return
;****************************************************************
;*
;* ROUTINE: Set_ext_error_subst
;*
;* FUNCTION: Sets up substitution for extended error
;*
;* INPUT: AX - extended error number
;* DX - offset of string
;*
;* OUTPUT: Extend_Buf_Ptr set up for STD_EPRINTF
;*
;****************************************************************
Set_ext_error_subst proc near ;AN022;
mov msg_disp_class,ext_msg_class ;AN022; set up extended error msg class
mov string_ptr_2,dx ;AN022; get address of failed string
mov Extend_buf_sub,one_subst ;AN022; put number of subst in control block
mov dx,offset TranGroup:Extend_Buf_ptr ;AN022; get extended message pointer
mov Extend_Buf_ptr,ax ;AN022; get message number in control block
ret ;AN022; return
Set_ext_error_subst endp ;AN022;
Break <SavUDir - preserve the users current directory on a particular drive>
;
; SavUDir - move the user's current directory on a drive into UserDir1
; SavUDir1 - move the user's current directory on a drive into a specified
; buffer
;
; Inputs: DL has 1-based drive number
; ES:DI has destination buffer (SavUDir1 only)
; Outputs: Carry Clear
; DS = TranGroup
; Carry Set
; AX has error code
; Registers Modified: AX, SI
;
SAVUDIR:
MOV DI,OFFSET TRANGROUP:USERDIR1
SAVUDIR1:
MOV AL,DL
ADD AL,'@'
CMP AL,'@'
JNZ GOTUDRV
ADD AL,[CURDRV]
INC AL ; A = 1
GOTUDRV:
STOSB
MOV AH,[DIRCHAR]
MOV AL,':'
STOSW
PUSH ES
POP DS
ASSUME DS:NOTHING
MOV SI,DI
MOV AH,CURRENT_DIR ; Get the Directory Text
INT int_command
retc
PUSH CS
POP DS
ASSUME DS:TRANGROUP
return
CRLF2:
PUSH DX
MOV DX,OFFSET TRANGROUP:ACRLF_ptr
PR:
PUSH DS
PUSH CS
POP DS
invoke std_printf
POP DS
POP DX
return
;
; These routines (SCANOFF, DELIM) are called in batch processing when DS
; may NOT be TRANGROUP
;
ASSUME DS:NOTHING,ES:NOTHING
SCANOFF:
LODSB
CALL DELIM
JZ SCANOFF
DEC SI ; Point to first non-delimiter
return
;
; Input: AL is character to classify
; Output: Z set if delimiter
; NZ set otherwise
; Registers modified: none
;
DELIM:
CMP AL,' '
retz
CMP AL,'='
retz
CMP AL,','
retz
CMP AL,';'
retz
CMP AL,9 ; Check for TAB character
retz
CMP AL,0ah ; Check for line feed character - BAS
return
ASSUME DS:TRANGROUP,ES:TRANGROUP
FCB_TO_ASCZ: ; Convert DS:SI to ASCIZ ES:DI
MOV CX,8
MAINNAME:
LODSB
CMP AL,' '
JZ SKIPSPC
STOSB
SKIPSPC:
LOOP MAINNAME
LODSB
CMP AL,' '
JZ GOTNAME
MOV AH,AL
MOV AL,dot_chr
STOSB
XCHG AL,AH
STOSB
MOV CL,2
EXTNAME:
LODSB
CMP AL,' '
JZ GOTNAME
STOSB
LOOP EXTNAME
GOTNAME:
XOR AL,AL
STOSB
return
STRCOMP:
;
; Compare ASCIZ DS:SI with ES:DI.
; SI,DI destroyed.
;
CMPSB
retnz ; Strings not equal
cmp byte ptr [SI-1],0 ; Hit NUL terminator?
retz ; Yes, strings equal
jmp short STRCOMP ; Equal so far, keep going
CRPRINT:
PUSH AX
MOV AL,13
PUSH CX
PUSH DI
MOV DI,DX
MOV CX,-1
PUSH ES
PUSH DS
POP ES
REPNZ SCASB ; LOOK FOR TERMINATOR
mov byte ptr [di-1],0 ; nul terminate the string
POP ES
mov string_ptr_2,dx
mov dx,offset trangroup:string_buf_ptr
invoke std_printf
mov ds:byte ptr [di-1],13 ; now put the CR back
JC ERROR_OUTPUT
POP DI
POP CX
POP AX
return
ERROR_OUTPUT:
PUSH CS
POP DS
ASSUME DS:TRANGROUP
MOV ES,[RESSEG]
ASSUME ES:RESGROUP
MOV DX,OFFSET TRANGROUP:NOSPACE_ptr
CMP [PIPEFLAG],0
JZ GO_TO_ERROR
invoke PipeOff
MOV DX,OFFSET TRANGROUP:PIPEEMES_ptr
GO_TO_ERROR:
JMP CERROR
ASSUME DS:TRANGROUP,ES:TRANGROUP
PATHCHRCMP:
;---- Mod for path invocation ----
PUBLIC pathchrcmp
;----
push ax
mov ah,'/'
CMP [SWITCHAR],ah
JZ NOSLASHT
CMP AL,'/'
jz pccont
NOSLASHT:
CMP AL,'\'
pccont:
pop ax
return
; Drive taken from FCB
; User dir saved in userdir1
;
; Zero set if path dir, CHDIR to this dir, FCB filled with ?
; NZ set if path/file, CHDIR to file, FCB has file (parsed fill ' ')
; [DESTTAIL] points to parse point
; Carry set if no CHDIRs worked, FCB not altered.
; DESTISDIR set non zero if PATHCHRs in path (via SETPATH)
;
PATHCRUNCH:
mov [msg_numb],0 ;AN022; Set up message flag
MOV DL,DS:[FCB]
CALL SAVUDIR
jc pcrunch_cderrJ ;AN022; if error on current dir - report
invoke SETPATH
TEST [DESTINFO],2
JNZ TRYPEEL ; If ? or * cannot be pure dir
MOV AH,CHDIR
INT int_command
jnc chdir_worked ;AN022; no error - continue
invoke get_ext_error_number ;AN022; get the extended error
cmp ax,error_path_not_found ;AN022; if path not found
jz trypeel ;AC022; keep trying
cmp ax,error_access_denied ;AN022; if access denied
jz trypeel ;AC022; keep trying
mov [msg_numb],ax ;AN022; set up message flag
jmp peelfail ;AN022; exit with other error
chdir_worked:
invoke SETREST1
MOV AL,'?' ; *.* is default file spec if pure dir
MOV DI,5DH
MOV CX,11
REP STOSB
XOR AL,AL ; Set zero
return
pcrunch_cderrj: ;AN022; need this for long jmp
jmp pcrunch_cderr ;AN022;
TRYPEEL:
MOV SI,[PATHPOS]
DEC SI ; Point at NUL
MOV AL,[SI-1]
CMP [KPARSE],0
JNZ DELSTRT ; Last char is second KANJI byte, might be '\'
CALL PATHCHRCMP
JZ PEELFAIL ; Trailing '/'
DELSTRT:
MOV CX,SI
MOV SI,DX
PUSH DX
DELLOOP:
CMP SI,CX
JZ GOTDELE
LODSB
invoke TESTKANJ
JZ NOTKANJ8
INC SI
JMP DELLOOP
NOTKANJ8:
CALL PATHCHRCMP
JNZ DELLOOP
MOV DX,SI
DEC DX
JMP DELLOOP
GOTDELE:
MOV SI,DX
POP DX
CMP SI,DX
JZ BADRET
MOV CX,SI
MOV SI,DX
DELLOOP2: ; Set value of KPARSE
CMP SI,CX
JZ TRYCD
MOV [KPARSE],0
LODSB
INVOKE TESTKANJ
JZ DELLOOP2
INC SI
INC [KPARSE]
JMP DELLOOP2
TRYCD:
push ax
mov al,dot_chr
CMP BYTE PTR [SI+1],al
pop ax
JZ PEELFAIL ; If . or .., pure cd should have worked
mov al,[si-1]
CMP al,':' ; Special case d:\file
JZ BADRET
CMP [KPARSE],0
JNZ NOTDOUBLESL ; Last char is second KANJI byte, might be '\'
CALL PATHCHRCMP
JNZ NOTDOUBLESL
PEELFAIL:
STC ; //
return
NOTDOUBLESL:
MOV BYTE PTR [SI],0
MOV AH,CHDIR
INT int_command
JNC CDSUCC
pcrunch_cderr:
invoke get_ext_error_number ;AN022; get the extended error
mov [msg_numb],ax ;AN022; set up message flag
or si,si ;AN022; set up zero flag to not zero
stc ;AN022; set up carry flag
return
BADRET:
MOV AL,[SI]
CALL PATHCHRCMP ; Special case 'DIRCHAR'file
STC
retnz
XOR BL,BL
XCHG BL,[SI+1]
MOV AH,CHDIR
INT int_command
jc pcrunch_cderr ;AN022; go to error exit
MOV [SI+1],BL
CDSUCC:
invoke SETREST1
INC SI ; Reset zero
MOV [DESTTAIL],SI
pushf ;AN015; save flags
cmp dirflag,-1 ;AN015; don't do parse if in DIR
jz pcrunch_end ;AN015;
MOV DI,FCB
MOV AX,(PARSE_FILE_DESCRIPTOR SHL 8) OR 02H ; Parse with default drive
INT int_command
pcrunch_end:
popf ;AN015; get flags back
return
trancode ends
end
|