summaryrefslogtreecommitdiff
path: root/v2.0/source/XENIX.ASM
blob: dd20b50ee1b9b28a867bd58a66f103cbad3534c7 (plain) (blame)
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