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
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
|
;
; xenix file calls for MSDOS
;
INCLUDE DOSSEG.ASM
IFNDEF KANJI
KANJI EQU 0 ;FALSE
ENDIF
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.xlist
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE XENIX - IO system to mimic UNIX
NAME XENIX
i_need NoSetDir,BYTE
i_need CURDRV,BYTE
i_need IOCALL,BYTE
i_need IOMED,BYTE
i_need IOSCNT,WORD
i_need IOXAD,DWORD
i_need DIRSTART,WORD
i_need ATTRIB,BYTE
i_need THISFCB,DWORD
i_need AuxStack,BYTE
i_need Creating,BYTE
i_need ThisDRV,BYTE
i_need NAME1,BYTE
i_need LastEnt,WORD
i_need ThisDPB,DWORD
i_need EntLast,WORD
i_need CurrentPDB,WORD
i_need sft_addr,DWORD ; pointer to head of table
i_need CURBUF,DWORD ; pointer to current buffer
i_need DMAADD,DWORD ; pointer to current dma address
BREAK <Local data>
CODE ENDS
DATA SEGMENT BYTE PUBLIC 'DATA'
open_name DW ?
DW ?
open_access DB ?
open_jfn DW ? ; accessed as DD
open_jfn_b DW ? ; accessed as DD with above
open_sfn DW ?
open_sfoff DW ? ; accessed as DD
open_sfn_b DW ? ; accessed as DD with above
open_devid DB ?
Cr_read_only DB ?
rename_source DD ?
rename_dest DD ?
DATA ENDS
CODE SEGMENT BYTE PUBLIC 'CODE'
BREAK <Validate_path - check to see if there are meta characters in path>
;
; Input: DS:DX is an ASCIZ path
; Output: Carry set if meta-characters present or path malformed and
; Zero is set if the only problem is that meta-characters
; are present in the last element of the path
procedure Validate_path,near
ASSUME DS:NOTHING,ES:NOTHING
PUSH AX
PUSH CX
PUSH SI
MOV SI,DX
MOV CX,0FFH ;No path seps yet
MOV AX,[SI] ; Get first two bytes
OR AL,AL
JZ validate_malformed ; NUL path
CMP AH,':'
JNZ validate_loop ; OK so far
CMP BYTE PTR [SI+2],0
JZ validate_malformed ; NUL path (just d:)
validate_loop:
LODSB
validate_loop1:
IF KANJI
invoke TESTKANJ
JZ NOTKANJ6
INC SI
JMP validate_loop
NOTKANJ6:
ENDIF
OR AL,AL
JZ validate_end
CMP AL,"?"
JZ validate_error
CMP AL,"*"
JZ validate_error
invoke PathChrCmp
JNZ validate_loop
JCXZ validate_malformed ;If path sep, cannot have meta yet
LODSB ;Look ahead one char
OR AL,AL
JZ validate_checktslsh ;Trailing path sep
invoke PathChrCmp
JNZ validate_loop1 ;Double path sep?
validate_malformed:
INC CX
OR CX,CX ;Reset zero
JMP SHORT validate_set_carry
validate_error:
XOR CX,CX ;Flag metas found
JMP validate_loop
validate_checktslsh:
;A bizarre case, "/" is OK, "d:/" is OK, anything else is an error
SUB SI,DX
CMP SI,2
JZ validate_end ;Two chars, the '/' and the NUL
CMP SI,4
JNZ validate_malformed ;Four chars, "D:/<NUL>"
MOV SI,DX
CMP BYTE PTR [SI+1],':'
JNZ validate_malformed ;Second char must be a ':'
validate_end:
OR CX,CX ;Clears carry
JNZ validate_ok ;No metas found, leave carry clear
validate_set_carry:
STC
validate_ok:
POP SI
POP CX
POP AX
return
validate_path ENDP
BREAK <Access_path - determine if file found>
;
; Input: DS:DX point to a path
; Output: Carry reset - outputs of GetPath
; carry set - AL has error code
;
procedure Access_path,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CALL Validate_path
JC access_no_path
MOV SI,DX
invoke GetPath
retnc
MOV AL,error_file_not_found
OR CL,CL
JNZ access_ret
access_no_path:
MOV AL,error_path_not_found
access_ret:
STC
return
access_path ENDP
BREAK <Find_free_jfn - return a free jfn in users PDB>
;
; system file table data
;
;
; The system file table is two linear tables. The first table is the
; DOS initialization table containing a default number of FCBs. The
; first word in the table is a link to the second table, which
; SYSINIT sets up, the second word is the number of FCBs in the table.
;
;
; find_free_jfn
; input: none
; output: JNC <found>
; ES:DI is pointer to free JFN
; JC <no free jfns>
; ES,DI indeterminate
;
procedure Find_free_jfn,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH AX
PUSH CX
MOV AL,0FFh
MOV ES,[CurrentPDB]
MOV DI,PDB_JFN_Table
MOV CX,FilPerProc
REPNE SCASB
STC
JNZ Find_jfn_ret
DEC DI
CLC
Find_jfn_ret:
POP CX
POP AX
return
Find_free_jfn ENDP
BREAK <find_free_sfn - return a free sfn and sf pointer>
;
; find_free_sfn
; input: none
; output: JNC <found>
; ES:DI is free sf entry
; SI is sfn
; JC <not found>
; ES,DI,SI indeterminate
;
; sft_addr --> (link) count (fcbs)
; links = -1 means end of list
;
procedure Find_free_sfn,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH BX
PUSH CX
LES BX,sft_addr ; head of chain of tables
XOR SI,SI ; count of sfn
; ES:BX points to table... search through table
Find_sfn_in_table:
CMP BX,-1 ; end of chain
JZ Find_no_free_sfns
MOV DI,sft_table ; offset to sf entry
MOV CX,ES:[BX].sft_count ; count of fcbs in table
Find_sfn:
CMP ES:BYTE PTR [BX+DI].sf_ref_count,0h
JZ Find_got_sfn ; ref count is 0 -> free entry
ADD DI,SIZE sf_entry ; look to next entry
INC SI ; bump sfn
LOOP Find_sfn
LES BX,ES:[BX].sft_link ; link to next
JMP SHORT Find_sfn_in_table ; look for more
Find_no_free_sfns:
STC
JMP SHORT find_ret
Find_got_sfn:
ADD DI,BX
CLC
Find_ret:
POP CX
POP BX
RET
Find_free_sfn ENDP
BREAK <$Open - open a file handle>
;
; Assembler usage:
; LDS DX, Name
; MOV AH, Open
; MOV AL, access
; INT int_command
;
; ACCESS Function
; ------ --------
; open_for_read file is opened for reading
; open_for_write file is opened for writing
; open_for_both file is opened for both reading and writing.
;
; Error returns:
; AX = error_invalid_access
; = error_file_not_found
; = error_access_denied
; = error_too_many_open_files
;
procedure $Open,NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV [Cr_read_only],0
Open_create:
CMP AL,open_for_both ; validate access
JBE OPEN_get_jfn
error error_invalid_access
OPEN_get_jfn:
MOV [open_name+2],DS
context DS
MOV open_name,DX
MOV open_access,AL
invoke Find_free_jfn ; scan through user's area
; ES:DI is the jfn entry
JNC OPEN_get_sfn
OPEN_too_many:
error error_too_many_open_files
OPEN_get_sfn:
MOV OPEN_jfn_b,ES
MOV OPEN_jfn,DI
invoke Find_free_sfn ; get a free sft entry
; ES:DI is the SFT entry that's free, SI is the sfn
JC OPEN_too_many
OPEN_file:
MOV OPEN_sfn,SI
MOV OPEN_sfoff,DI
MOV OPEN_sfn_b,ES
;
; open the file
;
PUSH DS
LDS DX,DWORD PTR [open_name]
ASSUME DS:NOTHING
CALL access_path
POP DS
ASSUME DS:DOSGROUP
JNC open_check_access ; carry set -> error
transfer SYS_RET_ERR
open_check_access:
MOV ES,WORD PTR [CURBUF+2] ; get buffer location
MOV open_devid,AH
TEST AH,080h
JNZ open_set_FCB_dev ;is a device
MOV AL,ES:[BX].dir_attr
TEST AL,attr_directory ; can't open directories
JZ open_try_volid
open_bad_access:
error error_access_denied
open_try_volid:
TEST AL,attr_volume_id ; can't open volume ids
JNZ open_bad_access
TEST AL,attr_read_only ; check write on read only
JZ open_set_FCB
CMP [Cr_read_only],0
JNZ open_set_FCB ; ok if creating read only file
CMP open_access, open_for_read
JNZ open_bad_access ; writing on a read only file
JMP SHORT open_set_FCB
open_set_FCB_dev:
PUSH SS
POP ES ;Device opens are DOSGROUP relative
open_set_FCB:
MOV CX,11 ; copy name into FCB...
PUSH SI ; ES:BX is source, must change
MOV SI,BX ; ES:SI is source
MOV DI,open_sfoff ; ??:DI is dest
PUSH DS
PUSH ES
MOV ES,open_sfn_b ; ES:DI is dest
POP DS ; DS:SI is source
ASSUME DS:NOTHING
;
; need to save attribute for the close operation
;
MOV AH,DS:[BX.dir_attr] ; save attribute for close
MOV ES:[DI.sf_attr],AH
ADD DI,sf_fcb+1 ; point to name
IF KANJI
MOVSB
CMP BYTE PTR ES:[DI-1],5
JNZ NOTKTRAN
MOV BYTE PTR ES:[DI-1],0E5H
NOTKTRAN:
DEC CX
ENDIF
REP MOVSB ; move in parsed name
POP DS
ASSUME DS:DOSGROUP
POP SI
LES DI,DWORD PTR [open_sfoff]
ADD DI,sf_fcb ; offset on fcb in sf entry
MOV AH,open_devid
invoke DOOPEN ; let open code fill in blanks
context DS
LES DI,DWORD PTR [open_sfoff]
INC ES:[DI].sf_ref_count ; reference this FCB
MOV AL,open_access ; stash the access
MOV ES:BYTE PTR [DI].sf_mode,AL
XOR AX,AX
MOV ES:WORD PTR [DI.sf_FCB.fcb_RR],AX ; beginning of file
MOV ES:WORD PTR [DI.sf_FCB.fcb_RR+2],AX
INC AX
MOV ES:WORD PTR [DI.sf_FCB.fcb_RECSIZ],AX ; byte io only
LES DI,DWORD PTR [open_jfn]
MOV AX,open_sfn
MOV ES:BYTE PTR [DI],AL ; stash sfn in PDB
SUB DI,PDB_jfn_table ; get jfn for user
MOV AX,DI
transfer SYS_RET_OK
$Open ENDP
BREAK <$UNLINK - delete a file entry>
;
; Assembler usage:
; LDS DX, name
; MOV AH, Unlink
; INT 21h
;
; Error returns:
; AX = error_file_not_found
; = error_access_denied
;
procedure $UNLINK,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CALL access_path
JNC unlink_check_attr
transfer SYS_RET_ERR
unlink_check_attr:
JZ unlink_dir
LDS DI,DWORD PTR [CURBUF] ; get directory entry
TEST DS:[BX.dir_attr],attr_read_only
JZ unlink_doit
unlink_dir:
error error_access_denied
unlink_doit:
MOV BYTE PTR DS:[BX.dir_name],0E5h ; delete dir entry
MOV BYTE PTR DS:[DI.BUFDIRTY],1 ; dirty the buffer
LODSW
MOV BX,AX
AND BX,0FFFh
context DS
JZ unlink_flush
invoke RELEASE
unlink_flush:
MOV AL,BYTE PTR ES:[BP.DPB_drive]
invoke FLUSHBUF
transfer SYS_RET_OK
$UNLINK ENDP
BREAK <$CREAT - creat a new file and open him for input>
;
; Assembler usage:
; LDS DX, name
; MOV AH, Creat
; MOV CX, access
; INT 21h
; ; AX now has the handle
;
; Error returns:
; AX = error_access_denied
; = error_path_not_found
; = error_too_many_open_files
;
procedure $CREAT,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CALL Validate_path
JNC unlink_do_make
error error_path_not_found
unlink_do_make:
PUSH DX
PUSH DS
context DS
MOV WORD PTR [CREATING],0E5FFh
MOV WORD PTR [ThisFCB+2],SS
MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXSTACK-40
MOV SI,DX
MOV AL,CL
AND CL,attr_read_only
MOV [Cr_read_only],CL
POP DS
PUSH DS
ASSUME DS:NOTHING
invoke MakeNode
POP DS
POP DX
OR AL,AL
JZ creat_open
CMP AL,3
JZ creat_open
creat_no_access:
error error_access_denied
creat_open:
MOV AL,open_for_both
JMP Open_create
$CREAT ENDP
BREAK <$DUP - duplicate a jfn>
;
; Assembler usage:
; MOV BX, fh
; MOV AH, Dup
; INT int_command
; AX has the returned handle
; Errors:
; AX = dup_invalid_handle
; = dup_too_many_open_files
procedure $DUP,NEAR
ASSUME DS:NOTHING,ES:NOTHING
context DS
invoke Find_free_jfn
JC dup_no_free_handles
dup_force:
PUSH ES
PUSH DI
invoke Get_sf_from_jfn
POP SI
POP DS
JC dup_bad_handle
; ES:DI is pointer to sf entry
; DS:DI is pointer to jfn
INC ES:[DI].sf_ref_count ; another jfn reference...
MOV AL,[BX].PDB_JFN_table ; get old sfn
MOV [SI],AL ; store in new place
SUB SI,PDB_JFN_table ; get jfn
MOV AX,SI
transfer SYS_RET_OK
dup_no_free_handles:
error error_too_many_open_files
dup_bad_handle:
error error_invalid_handle
$DUP ENDP
BREAK <$DUP2 - force a dup on a particular jfn>
;
; Assembler usage:
; MOV BX, fh
; MOV CX, newfh
; MOV AH, Dup2
; INT int_command
; Error returns:
; AX = error_invalid_handle
;
procedure $DUP2,NEAR
ASSUME DS:NOTHING,ES:NOTHING
XCHG BX,CX ; BX < destination jfn
PUSH BX
PUSH CX
invoke $CLOSE ; close BX
context DS
POP CX
POP BX
invoke Get_jfn_pointer
XCHG BX,CX
JNC dup_force
lseek_bad_handle:
error error_invalid_handle
$DUP2 ENDP
BREAK <$CHMOD - change file attributes>
;
; Assembler usage:
; LDS DX, name
; MOV CX, attributes
; INT 21h
; Error returns:
; AX = error_path_not_found
; AX = error_access_denied
;
procedure $CHMOD,NEAR
ASSUME DS:NOTHING,ES:NOTHING
CMP AL,1
JBE chmod_save
error error_invalid_function
chmod_save:
JB chmod_try_file
MOV BX,CX
AND BX,NOT attr_changeable
JZ chmod_try_file
chmod_bad:
error error_access_denied
chmod_bye:
transfer SYS_RET_ERR
chmod_try_file:
PUSH CX
PUSH AX
CALL access_path
POP DX
POP CX
JC chmod_bye
LES DI,[CURBUF]
context DS
OR DL,DL
JZ chmod_fetch
AND BYTE PTR ES:[BX].dir_attr,NOT attr_changeable
OR BYTE PTR ES:[BX].dir_attr,CL
MOV ES:[DI.BUFDIRTY],1
MOV AL,-1
invoke FlushBuf
transfer SYS_RET_OK
chmod_fetch:
XOR CX,CX
MOV CL,BYTE PTR ES:[BX].dir_attr
invoke Get_user_stack
MOV [SI.user_CX],CX
transfer SYS_RET_OK
$chmod ENDP
BREAK <$CURRENT_DIR - dump the current directory into user space>
;
; Assembler usage:
; LDS SI,area
; MOV DL,drive
; INT 21h
; ; DS:SI is a pointer to 64 byte area that contains drive
; ; current directory.
; Error returns:
; AX = error_invalid_drive
;
procedure $CURRENT_DIR,NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH DS
PUSH BX
PUSH SI
invoke $get_DPB
;
; ES:BP points to DPB. DS:SI points to user stack, unless error
;
CMP AL,0FFh
JNZ current_copy
POP AX ; Clean Stack
POP AX
POP AX
error error_invalid_drive
current_copy:
POP DI ; where to move to
POP [SI.user_BX] ; restore old BX
POP BX
MOV [SI.user_DS],BX ; and restore old DS
;
; ES:BP is pointer to DPB. BX:DI is pointer to destination
;
CMP ES:[BP.dpb_current_dir],-1
JNZ current_ok
PUSH BX
PUSH DI
MOV [ATTRIB],attr_all
invoke GETCURRDIR
POP DI
POP BX
current_ok:
MOV SI,BP ; ES:SI is source
PUSH ES
POP DS ; DS:SI is source
MOV ES,BX ; ES:DI is destination
CMP [SI.dpb_current_dir],0
JNZ current_move
MOV BYTE PTR [SI.dpb_dir_text],0
current_move:
ADD SI,dpb_dir_text
MOV CX,DIRSTRLEN
current_loop:
LODSB
STOSB
OR AL,AL
LOOPNZ current_loop
transfer SYS_RET_OK
$CURRENT_DIR ENDP
BREAK <$RENAME - move directory entries around>
;
; Assembler usage:
; LDS DX, source
; LES DI, dest
; MOV AH, Rename
; INT 21h
;
; Error returns:
; AX = error_file_not_found
; = error_not_same_device
; = error_access_denied
procedure $RENAME,near
MOV WORD PTR [rename_source],DX
MOV WORD PTR [rename_source+2],DS
MOV WORD PTR [rename_dest],DI
MOV WORD PTR [rename_dest+2],ES
CALL Access_path
JNC rename_check_dir
transfer SYS_RET_ERR
rename_check_dir:
JZ rename_no_access
MOV DS,WORD PTR [CurBuf+2]
PUSH [BX.dir_date]
PUSH [BX.dir_first]
PUSH [BX.dir_size_h]
PUSH [BX.dir_size_l]
PUSH [BX.dir_time]
PUSH WORD PTR [BX.dir_attr]
PUSH WORD PTR [ThisDrv]
LDS SI,[rename_dest]
invoke GetPath
POP AX
JC rename_check_drives
rename_bad_access:
ADD SP,12
rename_no_access:
error error_access_denied
rename_check_drives:
CMP AL,[ThisDrv]
JZ rename_create
ADD SP,12
error error_not_same_device
rename_create:
LDS SI,[rename_dest]
POP AX
PUSH AX
MOV WORD PTR [Creating],0E5FFh
MOV WORD PTR [ThisFCB+2],SS
MOV WORD PTR [ThisFCB],OFFSET DOSGROUP:AUXStack-40
invoke MakeNode
JC rename_bad_access
LDS SI,[CurBuf]
POP AX
MOV [BX.dir_attr],AL
POP [BX.dir_time]
POP [BX.dir_size_l]
POP [BX.dir_size_h]
POP [BX.dir_first]
POP [BX.dir_date]
MOV [SI.BUFDIRTY],1
LDS SI,[rename_source]
invoke GetPath
LDS SI,[CurBuf]
MOV BYTE PTR [BX],0E5h
MOV [SI.BUFDIRTY],1
context DS
MOV AL,0FFh
invoke FlushBuf
transfer SYS_RET_OK
$RENAME ENDP
BREAK <$FIND_FIRST - find first matching xenix filename>
;
; Assembler usage:
; MOV AH, FindFirst
; LDS DX, name
; MOV CX, attr
; INT 21h
; ; DMA address has datablock
;
; Error Returns:
; AX = error_file_not_found
; = error_no_more_files
;
procedure $FIND_FIRST,near
ASSUME DS:NOTHING,ES:NOTHING
CALL Validate_path
JNC find_get
JZ find_get
error error_file_not_found
find_get:
MOV SI,DX
PUSH CX
INC BYTE PTR [NoSetDir] ; if we find a dir, don't change to it
MOV WORD PTR [Creating],0E500h
CALL GetPath
POP CX
MOV [Attrib],CL
find_check:
JNC find_check_attr
find_no_more:
error error_no_more_files
find_check_attr:
MOV DS,WORD PTR [CURBUF+2]
MOV CH,[BX.dir_attr]
invoke MatchAttributes
JZ found_it
PUSH [LastEnt]
MOV BX,[DirStart]
JMP find_it_next
found_it:
LES DI,[DMAADD]
MOV AL,[Attrib]
STOSB ; find_buf 0 = attribute in search
MOV AL,[ThisDrv]
STOSB ; find_buf 1 = drive
MOV CX,11
PUSH BX
MOV SI,OFFSET DOSGROUP:NAME1; find_buf 2 = formatted name
PUSH DS
PUSH SS
POP DS
IF KANJI
MOVSB
CMP BYTE PTR ES:[DI-1],5
JNZ NOTKANJB
MOV BYTE PTR ES:[DI-1],0E5H
NOTKANJB:
DEC CX
ENDIF
REP MOVSB
POP DS
MOV AX,[LastEnt]
STOSW ; find_buf 13 = LastEnt
MOV AX,WORD PTR [ThisDPB]
STOSW ; find_buf 15 = ThisDPB
MOV AX,WORD PTR [ThisDPB+2]
STOSW
MOV AX,[DirStart]
STOSW ; find_buf 19 = DirStart
MOV AL,[BX].dir_attr
STOSB ; find_buf 21 = attribute found
MOV AX,[BX].dir_time
STOSW ; find_buf 22 = time
MOV AX,[BX].dir_date
STOSW ; find_buf 24 = date
MOV AX,[BX].dir_size_l
STOSW ; find_buf 26 = low(size)
MOV AX,[BX].dir_size_h
STOSW ; find_buf 28 = high(size)
POP SI
MOV CX,8 ; find_buf 30 = packed name
find_loop_name:
LODSB
STOSB
CMP AL," "
LOOPNZ find_loop_name
JNZ find_check_dot
DEC DI
find_check_dot:
ADD SI,CX
CMP BYTE PTR [SI]," "
JZ find_done
MOV AL,"."
STOSB
MOV CX,3
find_loop_ext:
LODSB
STOSB
CMP AL," "
LOOPNZ find_loop_ext
JNZ find_done
DEC DI
find_done:
XOR AL,AL
STOSB
transfer SYS_RET_OK
$FIND_FIRST ENDP
BREAK <$FIND_NEXT - scan for match in directory>
;
; Assembler usage:
; ; dma points at area returned by find_first
; MOV AH, findnext
; INT 21h
; ; next entry is at dma
;
; Error Returns:
; AX = error_no_more_files
;
procedure $FIND_NEXT,near
ASSUME DS:NOTHING,ES:NOTHING
LDS SI,[DMAADD]
MOV DX,SI
INC DX
PUSH SI
invoke MOVNAMENOSET
POP SI
JNC find_load
findnext_no_more:
error error_no_more_files
find_load:
MOV AX,[SI.find_buf_LastEnt]
LES BP,[SI.find_buf_ThisDPB]
OR AX,AX
JS findnext_no_more
MOV BX,[SI.find_buf_DirStart]
MOV DL,[SI.find_buf_sattr]
MOV [Attrib],DL
PUSH AX
MOV WORD PTR [ThisDPB],BP
MOV WORD PTR [ThisDPB+2],ES
find_it_next:
invoke SetDirSrch
ASSUME DS:DOSGROUP
POP AX
MOV [ENTLAST],-1
invoke GetEnt
invoke NextEnt
JMP find_check
$find_next ENDP
do_ext
CODE ENDS
END
|