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
|
; SCCSID = @(#)parse.asm 1.2 85/07/23
TITLE PARSE - Parsing system calls for MS-DOS
NAME PARSE
;
; System calls for parsing command lines
;
; $PARSE_FILE_DESCRIPTOR
;
; Modification history:
;
; Created: ARR 30 March 1983
; EE PathParse 10 Sept 1983
;
.xlist
;
; get the appropriate segment definitions
;
include dosseg.asm
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xcref
INCLUDE DOSSYM.INC
INCLUDE DEVSYM.INC
.cref
.list
BOGUS =FALSE
.lall
I_Need chSwitch,BYTE
BREAK <$Parse_File_Descriptor -- Parse an arbitrary string into an FCB>
; Inputs:
; DS:SI Points to a command line
; ES:DI Points to an empty FCB
; Bit 0 of AL = 1 At most one leading separator scanned off
; = 0 Parse stops if separator encountered
; Bit 1 of AL = 1 If drive field blank in command line - leave FCB
; = 0 " " " " " " - put 0 in FCB
; Bit 2 of AL = 1 If filename field blank - leave FCB
; = 0 " " " - put blanks in FCB
; Bit 3 of AL = 1 If extension field blank - leave FCB
; = 0 " " " - put blanks in FCB
; Function:
; Parse command line into FCB
; Returns:
; AL = 1 if '*' or '?' in filename or extension, 0 otherwise
; DS:SI points to first character after filename
procedure $PARSE_FILE_DESCRIPTOR,NEAR
ASSUME DS:NOTHING,ES:NOTHING
invoke MAKEFCB
PUSH SI
invoke get_user_stack
POP [SI.user_SI]
return
EndProc $PARSE_FILE_DESCRIPTOR
IF BOGUS
BREAK <$PathParse - Parse a string>
;------------------------------------------------------------------------------
;
; Parse is a string parser. It copies the next token into a buffer, updates
; the string pointer, and builds a flag word which describes the token.
;
; ENTRY
; DS:SI - Points to the beginning of the string to be parsed
; ES:DI - Points to the buffer which will hold the new token
;
; EXIT
; AX - Flag word
; DS:SI - String pointer updated to point past the token just found
; All other registers are unchanged.
;
; All of the isXXXX procedures called by the main routine test a character
; to see if it is of a particular type. If it is, they store the character
; and return with the ZF set.
;
; CALLS
; isswit issep ispchr ispsep isinval isdot ischrnull dirdot pasep
;
;
; INTERNAL REGISTER USAGE
; AH - FF/00 to indicate whether a path token can terminated with a
; slash or not.
; AL - Used with lodsb/stosb to transfer and test chars from DS:SI
; BX - Holds flag word
; CX - Used with loop/rep and as a work var
; DX - Used to test the length of names and extensions
;
; EFFECTS
; The memory pointed to by DI has the next token copied into it.
;
; WARNINGS
; It is the caller's responsibility to make sure DS:SI does not point
; to a null string. If it does, SI is incremented, a null byte is
; stored at ES:DI, and the routine returns.
;
;------------------------------------------------------------------------------
ParseClassMask equ 1110000000000000b ; Token class mask
ParseSwitch equ 1000000000000000b ; Switch class
ParseSeparators equ 0100000000000000b ; Separator class
ParsePathName equ 0010000000000000b ; Path class
ParsePathNameData equ 0000000000001111b ; Path token data mask
ParsePathSynErr equ 0000000000000001b ; Path has syntax error
ParsePathWild equ 0000000000000010b ; Path has wildcards
ParsePathSeparators equ 0000000000000100b ; Path has pseparators
ParseInvalidDrive equ 0000000000001000b ; Path has invald drive
; Sepchars is a string containing all of the token separator characters
; and is used to test for separators.
Table segment
Public PRS001S,PRS001E
PRS001S label byte
sepchrs db 9,10,13,' ','+',',',';','=' ; tab cr lf sp + , ; =
seplen equ $-sepchrs
PRS001E label byte
table ends
Procedure $PathParse,NEAR
assume ds:nothing,es:nothing
xor ah,ah ; initialize registers and flags
xor bx,bx
cld
lodsb ; used the first byte of the token to
call isswit ; determine its type and call the routine to
je switch ; parse it
call issep
je separ
call ispchr
je path
call ispsep
je path
call isdot
je path
call isinval
je inval
stosb
jmp done
inval: or bx,ParsePathName ; an invalid character/path token
or bx,ParsePathSynErr ; was found, set the appropriate
call issep ; flag bits and parse the rest of
jne icont ; the token
dec di
icont: dec si
jmp ptosep
switch: mov bx,ParseSwitch ; found a switch, set flag and parse
jmp ptosep ; the rest of it
separ: mov bx,ParseSeparators ; found separator, set flag and parse
seloop: lodsb ; everything up to the next non
call issep ; separator character
je seloop
jmp bksi
path: or bx,ParsePathName ; found path, set flag
mov cx,8 ; set up to parse a file name
mov dx,8
call pasep ; if the token began with a path
jne pcont1 ; separator or . call rcont which
not ah ; handles checksfor . and ..
jmp rcont
pcont1: cmp al,'.'
jne pcont2
dec si
dec di
jmp rcont
pcont2: cmp al,'A' ; if token may start with a drive
jge drive ; designator, go to drive. otherwise
jmp name1 ; parse a file name.
drive: cmp byte ptr [si],':' ; if there is a drive designator, parse
jne name1 ; and verify it. otherwise parse a file
not ah ; name.
cmp al,'Z'
jle dcont1
sub al,' '
dcont1: sub al,'@'
invoke GetthisDrv
lodsb
stosb
jc dcont2
jmp dcont3
dcont2: or bx,ParseInvalidDrive
dcont3: dec cx
lodsb
call ispsep
je rcont
dec si
repeat: mov al,byte ptr [si-2] ; repeat and rcont test for //, \\, .,
call pasep ; and .. and repeatedly calls name
jne rcont ; and ext until a path token has
inc si ; been completely parsed.
jmp inval
rcont: call dirdot
je done
jc inval
mov cx,8
mov dx,8
jmp name
name1: dec cx
name: lodsb ; parse and verify a file name
call ispchr
jne ncheck
xor ah,ah
nloop: loop name
lodsb
ncheck: cmp ah,0
jne ncont
cmp cx,dx
jne ncont
jmp inval
ncont: call isdot
je ext
jmp dcheck
ext: mov cx,3 ; parse and verify a file extension
mov dx,3
extl: lodsb
call ispchr
jne echeck
eloop: loop extl
lodsb
echeck: cmp cx,dx
jne dcheck
jmp inval
dcheck: call ispsep ; do the checks need to make sure
je repeat ; a file name or extension ended
call issep ; correctly and checks to see if
je bkboth ; we're done
call ischrnull
je done
jmp inval
ptosep: lodsb ; parse everything to the next separator
call issep
je bkboth
call ischrnull
je done
call isinval
jne ptcont
or bx,ParsePathSynErr
ptcont: stosb
jmp ptosep
bkboth: dec di ; clean up when the end of the token
bksi: dec si ; is found, stick a terminating null
done: xor al,al ; byte at the end of buf, and exit
stosb
push si
invoke Get_user_stack
mov [si].user_AX,bx
pop [si].user_SI
Transfer sys_ret_ok
Endproc $PathParse
; Is current character the beginning of a switch?
isswit proc near
cmp al,[chSwitch]
jne swret
stosb
swret: ret
isswit endp
; Is the current character a separator?
issep proc near
push cx
push di
push es
mov cx,cs
mov es,cx
mov cx,seplen
mov di,offset dosgroup:sepchrs
repne scasb
pop es
pop di
jne sepret
sepyes: stosb
sepret: pop cx
ret
issep endp
; Is the current character a path character? If it is a wildcard char too,
; set that flag.
ispchr proc near
cmp al,'!'
je pcyes
cmp al,'#'
jl pcret
cmp al,'*'
je pcwild
jl pcyes
cmp al,'-'
je pcyes
cmp al,'0'
jl pcret
cmp al,'9'
jle pcyes
cmp al,'?'
je pcwild
jl pcret
cmp al,'Z'
jle pcyes
cmp al,'^'
jl pcret
cmp al,'{'
jle pcyes
cmp al,'}'
je pcyes
cmp al,'~'
je pcyes
jmp pcret
pcwild: or bx,ParsePathWild
pcyes: stosb
cmp al,al
pcret: ret
ispchr endp
; Is the current character a path separator? If so, set that flag after
; storing the byte.
ispsep proc near
call pasep
jne psret
stosb
or bx,ParsePathSeparators
cmp al,al
psret: ret
ispsep endp
; Set ZF if the character in AL is a path separator.
pasep proc near
cmp chSwitch,'/'
je bkslash
cmp al,'/'
retz
bkslash:cmp al,'\'
ret
pasep endp
; Is the current character invalid?
isinval proc near
cmp al,1
jl inret
cmp al,8
jle inyes
cmp al,11
jl inret
cmp al,13
jne incont
cmp al,0
ret
incont: cmp al,31
jle inyes
cmp al,'['
je inyes
cmp al,']'
je inyes
ret
inyes: cmp al,al
inret: ret
isinval endp
; Is the current character a dot?
isdot proc near
cmp al,'.'
jne dotret
stosb
dotret: ret
isdot endp
; Is the current character null? If so, update SI for exiting.
ischrnull proc near
cmp al,0
jne nulret
dec si
cmp al,al
nulret: ret
ischrnull endp
; Check for . and .. Before returning, CF and ZF are set to indicate whether
; the token is invalid (found . or .. followed by an invalid char - CF on),
; we're done (found . or .. followed by null or a separator - ZF on), or the
; token continues (. and .. not found or found and followed by a path
; separator - both flags off).
dirdot proc near
cmp byte ptr [si], '.'
jne diretc
lodsb
stosb
cmp byte ptr [si],'.'
jne dicont
lodsb
stosb
dicont: lodsb
call ispsep
je diretc
call issep
je dibk
call ischrnull
je diretd
direti: stc ; Invalid return
ret
dibk: dec si
dec di
diretd: cmp al,al ; Done return
ret
diretc: cmp ah,1 ; Continue return
clc
ret
dirdot endp
ENDIF
CODE ENDS
END
|