Repository navigation
Expand file tree
/
Copy pathdos.sol
More file actions
1915 lines (1832 loc) · 51.7 KB
/
Copy pathdos.sol
File metadata and controls
1915 lines (1832 loc) · 51.7 KB
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
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# CPT32 DOS - a small DSFS / floppy shell for the CPT32 fantasy console.
#
# Features: file list, create, rename, delete, cross-drive copy, a line
# editor, a hex editor, DSFS format and free-space reporting. Text is
# rendered through the PCG console (sol/cpt32/pcg.sol) and the keyboard is
# read from the PeC event FIFO with IRQC source 3: the shell HALT s until
# the PeC input IRQ arrives (fn irq3), then drains the FIFO.
#
# Build (from the repository root):
# python3 tools/solc/solc.py compile dos.sol -o dos.sol.a
# python3 tools/asm/asm.py dos.sol.a -o dos.bin
#
# Run it with a DSFS volume in a disk slot, e.g.
# python3 tools/dsfs/dsfs.py mkfs disk0.img --sectors 2880
# python3 tools/dsfs/dsfs.py put disk0.img HELLO.TXT hello.txt
# then boot dos.bin (src32_testbench run from a directory whose config.yaml
# has no `bios` section, or the GUI with the image attached to slot 0).
#
# Commands (case insensitive, NAME.EXT or N:NAME.EXT for drive N):
# DIR list files with size and block count
# TYPE NAME print a file as text
# RUN NAME load and execute a WAX v2 program
# NEW NAME create an empty file
# REN OLD NEW rename (name only, timestamps kept)
# DEL NAME delete a file
# COPY SRC DST copy between drives (COPY 0:A.TXT 1:A.TXT)
# EDIT NAME line editor: L list, <n> text replace, I n text insert,
# D n delete, A text append, W save, Q quit
# HEX NAME hex editor (N/P/G/E/W/Q)
# FORMAT [N] format drive N as DSFS
# DRV N select the current drive
# MODE 40 / MODE 80 select text width
# CLS / HELP / EXIT
#
# Buffers live in main RAM: the DSFS directory needs 8192 bytes and file
# operations are limited to 64 KiB per file (DOS_MAX_FILE).
#
# Modules: every function lives in a sol namespace named after its section
# banner, and calls that cross a namespace are written qualified so the
# module boundary is visible at the call site.
# con console output kbd keyboard input
# names names and words disk DSFS access
# cmds typed commands edit line editor
# hex hex editor shell REPL and dispatch
# wax WAX validation/loading
# irq3 and main stay in the global namespace: solc only builds the IRQ
# dispatcher and the entry call for globally named functions.
!include "sol/cpt32/pcg.sol"
!include "sol/cpt32/idc.sol"
!include "sol/cpt32/dsfs.sol"
!include "sol/cpt32/wax.sol"
!include "sol/cpt32/irqc.sol"
!rodata_base 0x00040000
# PeC input / RTC and the VDP display enable bit.
!const DOS_PEC_DATA 0x80040030
!const DOS_PEC_STATUS 0x80040034
!const DOS_PEC_POP 0x80040038
!const DOS_RTC_SECONDS 0x80040208
!const DOS_VDP_ENABLE 0x80000000
# Scratch and file buffers in main RAM.
!const DOS_DIR_BUF 0x00300000
!const DOS_BM_BUF 0x00302000
!const DOS_FILE_BUF 0x00310000
!const DOS_EDIT_IDX 0x00320000
!const DOS_EDIT_TMP 0x00330000
!const DOS_CMD_BUF 0x00200000
!const DOS_WORD_BUF 0x00200100
!const DOS_NAME_A 0x00200200
!const DOS_NAME_B 0x00200210
!const DOS_HEX_RAW 0x00200220
!const DOS_HEX_TXT 0x00200230
!const DOS_EDIT_RAW 0x00200240
!const DOS_EDIT_TXT 0x00200250
!const DOS_TMP_TXT 0x00200260
!const DOS_MSGBUF 0x00200280
!const DOS_CMD_CAP 120
!const DOS_WORD_CAP 32
!const DOS_MAX_WORDS 5
!const DOS_MAX_LINES 1024
!const DOS_MAX_FILE 65536
!const DOS_EDIT_MAX 60000
!const DOS_TEXT_ROWS 2400
# Current drive and input state.
!var dos_drv 0
!var dos_caps 0
!var dos_shift 0
!var dos_spec_drv 0
!var dos_quit 0
!var dos_key 0
# Editor message pending display (0 = none); shown under the editor header
# so that errors and save results survive the next screen clear.
!var dos_msg 0
# File sizes / editor state.
!var dos_text_len 0
!var dos_lines 0
!var dos_hex_len 0
!var dos_hex_pos 0
!var dos_hex_dirty 0
# ---------------- IRQ ----------------
# IRQC source 3 is the PeC input FIFO. Acknowledge the latched IRQC
# pending bit so the next event latches a fresh rising edge; the shell
# drains the FIFO after IRET, which deasserts the source level.
fn irq3 () :
8 irqc.IRQC_PENDING sth
retn
;
# ---------------- console ----------------
!namespace con -
# Clear the whole 80x30 PCG window and home the cursor.
fn dos_cls () :
local i 0
0 >pcg.pcg_scroll_y
0 >pcg.pcg_vram_row
0 0x8000f00e stb
0 0x8000f00f stb
while
i DOS_TEXT_ROWS lt
if
32 0x10000000 i add stb
0x3f 0x10001000 i add stb
0 0x10002000 i add stb
i 1 add >i
0
else
1
end
end
0 0 pcg.locate
;
fn dos_newline () :
10 dos_putc
;
# Console character output: CR is dropped, LF scrolls, BS erases.
fn dos_putc (ch) :
ch 13 eq if retn end
ch 10 eq if pcg._pcg_ln retn end
ch 8 eq if
pcg.pcg_cur_x 0 gt if
pcg.pcg_cur_x 1 sub pcg.pcg_cur_y pcg.locate
32 pcg.putcscr
pcg.pcg_cur_x 1 sub pcg.pcg_cur_y pcg.locate
end
retn
end
ch pcg.putcscr
;
fn dos_puts (ptr) :
local i 0
local ch 0
while
ptr i add ldb >ch
ch 0 neq
if
ch dos_putc
i 1 add >i
0
else
1
end
end
;
fn dos_putsln (ptr) :
ptr dos_puts
dos_newline
;
fn dos_pad (n) :
local i 0
while
i n lt
if
32 dos_putc
i 1 add >i
0
else
1
end
end
;
fn dos_putnum (number) :
local value 0
number >value
value 0 lt if
45 dos_putc
value neg >value
end
value 10 ge if
value 10 div dos_putnum
end
value 10 mod 48 add dos_putc
;
# Decimal text of `value` at `dest`; returns the number of bytes written.
fn dos_num_text (value dest) :
local v 0
local n 0
value >v
v 0 lt if
45 dest stb
v neg dest 1 add dos_num_text 1 add ret
end
v 10 ge if
v 10 div dest dos_num_text >n
v 10 mod 48 add dest n add stb
n 1 add ret
end
v 48 add dest stb
1 ret
;
fn dos_hexdigit (v) :
v 10 lt if
v 48 add ret
end
v 55 add ret
;
# Print the low `digits` nibbles of `v` in uppercase hex.
fn dos_puthex (v digits) :
local i 0
local x 0
v >x
digits 1 sub >i
while
i 0 ge
if
x i 4 mul shr 15 and dos_hexdigit dos_putc
i 1 sub >i
0
else
1
end
end
;
fn dos_err (ptr) :
"ERROR: " dos_puts
ptr dos_putsln
;
# Paged output: print the marker and wait for a key.
fn dos_more () :
" -- MORE --" dos_puts
kbd.dos_waitkey drop
dos_newline
;
fn dos_strlen (ptr) :
local i 0
while
ptr i add ldb 0 neq
if
i 1 add >i
0
else
1
end
end
i ret
;
# Copy the NUL-terminated string at src to dst; returns the length.
fn dos_strcpy (src dst) :
local i 0
local ch 0
while
src i add ldb >ch
ch 0 neq
if
ch dst i add stb
i 1 add >i
0
else
1
end
end
i ret
;
# 0 when the NUL-terminated strings are equal (sol truth).
fn dos_streq (a b) :
local i 0
local ca 0
local cb 0
while
a i add ldb >ca
b i add ldb >cb
ca cb eq
if
ca 0 eq if 0 ret end
i 1 add >i
0
else
1
end
end
1 ret
;
fn dos_memcpy (src dst len) :
local i 0
while
i len lt
if
src i add ldb dst i add stb
i 1 add >i
0
else
1
end
end
;
fn dos_memzero (dst len) :
local i 0
while
i len lt
if
0 dst i add stb
i 1 add >i
0
else
1
end
end
;
fn dos_memfill (dst len val) :
local i 0
while
i len lt
if
val dst i add stb
i 1 add >i
0
else
1
end
end
;
fn dos_upper (ch) :
local c 0
ch >c
c 97 ge c 122 le or if
c 32 sub >c
end
c ret
;
!end
# ---------------- keyboard ----------------
!namespace kbd -
# Consume PeC keyboard events until Enter; echoes and returns the length.
# HALT s while the FIFO is empty so IRQ3 wakes the shell on the next event.
fn dos_read_line (dest cap) :
local count 0
local event 0
local usage 0
local value 0
local ch 0
0 >count
while
DOS_PEC_STATUS ld 1 and 0 gt
if
DOS_PEC_DATA ld >event
event 28 shr 15 and 0 eq if
event 24 shr 15 and 0 eq if
event 16 shr 255 and >usage
event 1 and >value
usage 225 eq usage 229 eq and if
value >dos_shift
else
usage 57 eq value 1 eq or if
dos_caps 0 eq if 1 >dos_caps else 0 >dos_caps end
else
value 1 eq if
usage dos_shift dos_caps dos_key_ascii >ch
ch 13 eq if
1 DOS_PEC_POP st
0 dest count add stb
con.dos_newline
count ret
end
ch 8 eq if
count 0 gt if
count 1 sub >count
0 dest count add stb
8 con.dos_putc
end
else
ch 0 neq count cap 1 sub lt or if
ch dest count add stb
count 1 add >count
ch con.dos_putc
end
end
end
end
end
end
end
1 DOS_PEC_POP st
else
halt
end
0
end
count ret
;
# Wait for a key press without echoing; the usage id is in dos_key.
fn dos_waitkey () :
local event 0
local usage 0
local value 0
local done 0
0 >done
0 >dos_key
while
done 0 eq
if
DOS_PEC_STATUS ld 1 and 0 gt
if
DOS_PEC_DATA ld >event
event 28 shr 15 and 0 eq if
event 24 shr 15 and 0 eq if
event 16 shr 255 and >usage
event 1 and >value
value 1 eq usage 0 neq or if
usage >dos_key
1 >done
end
end
end
1 DOS_PEC_POP st
0
else
halt
0
end
else
1
end
end
dos_key ret
;
# US keyboard HID usage -> ASCII (0 means the key is ignored).
fn dos_key_ascii (usage shifted caps) :
local ch 0
local upper 0
usage 4 ge usage 29 le or if
usage 97 add 4 sub >ch
shifted caps xor >upper
upper 0 neq if ch 32 sub >ch end
ch ret
end
usage 30 ge usage 39 le or if
usage 30 eq if 49 >ch end
usage 31 eq if 50 >ch end
usage 32 eq if 51 >ch end
usage 33 eq if 52 >ch end
usage 34 eq if 53 >ch end
usage 35 eq if 54 >ch end
usage 36 eq if 55 >ch end
usage 37 eq if 56 >ch end
usage 38 eq if 57 >ch end
usage 39 eq if 48 >ch end
shifted 0 neq if
ch 49 eq if 33 >ch end
ch 50 eq if 64 >ch end
ch 51 eq if 35 >ch end
ch 52 eq if 36 >ch end
ch 53 eq if 37 >ch end
ch 54 eq if 94 >ch end
ch 55 eq if 38 >ch end
ch 56 eq if 42 >ch end
ch 57 eq if 40 >ch end
ch 48 eq if 41 >ch end
end
ch ret
end
usage 40 eq if 13 ret end
usage 42 eq if 8 ret end
usage 44 eq if 32 ret end
usage 45 eq if shifted 0 eq if 45 ret else 95 ret end end
usage 46 eq if shifted 0 eq if 61 ret else 43 ret end end
usage 47 eq if shifted 0 eq if 91 ret else 123 ret end end
usage 48 eq if shifted 0 eq if 93 ret else 125 ret end end
usage 49 eq if shifted 0 eq if 92 ret else 124 ret end end
usage 51 eq if shifted 0 eq if 59 ret else 58 ret end end
usage 52 eq if shifted 0 eq if 39 ret else 34 ret end end
usage 53 eq if shifted 0 eq if 96 ret else 126 ret end end
usage 54 eq if shifted 0 eq if 44 ret else 60 ret end end
usage 55 eq if shifted 0 eq if 46 ret else 62 ret end end
usage 56 eq if shifted 0 eq if 47 ret else 63 ret end end
0 ret
;
!end
# ---------------- names and words ----------------
!namespace names -
fn dos_name_char_ok (ch) :
local c 0
ch >c
c 65 ge c 90 le or if 0 ret end
c 48 ge c 57 le or if 0 ret end
c 95 eq if 0 ret end
c 45 eq if 0 ret end
1 ret
;
# "NAME.EXT" (or "NAME") -> 11 space-padded on-disk bytes. 0 = ok.
fn dos_name_build (src len dest) :
local i 0
local dot -1
local ch 0
local c 0
local base_len 0
local ext_len 0
len 0 le if 1 ret end
-1 >dot
0 >i
while
i len lt
if
src i add ldb 46 eq if
i >dot
end
i 1 add >i
0
else
1
end
end
len >base_len
0 >ext_len
dot 0 ge if
dot >base_len
len dot 1 add sub >ext_len
end
base_len 1 lt if 1 ret end
base_len 8 gt if 1 ret end
ext_len 3 gt if 1 ret end
dest 11 32 con.dos_memfill
0 >i
while
i base_len lt
if
src i add ldb >ch
ch con.dos_upper >c
c dos_name_char_ok 0 neq if 1 ret end
c dest i add stb
i 1 add >i
0
else
1
end
end
dot 0 ge if
0 >i
while
i ext_len lt
if
src dot 1 add add i add ldb >ch
ch con.dos_upper >c
c dos_name_char_ok 0 neq if 1 ret end
c dest 8 add i add stb
i 1 add >i
0
else
1
end
end
end
0 ret
;
# 11 on-disk name bytes -> "NAME.EXT" (NUL terminated) at dest.
fn dos_name_text (name dest) :
local i 0
local ch 0
local out 0
local has 0
0 >out
0 >i
while
i 8 lt
if
name i add ldb >ch
ch 32 neq if
ch dest out add stb
out 1 add >out
end
i 1 add >i
0
else
1
end
end
0 >has
0 >i
while
i 3 lt
if
name 8 add i add ldb 32 neq if
1 >has
end
i 1 add >i
0
else
1
end
end
has 0 neq if
46 dest out add stb
out 1 add >out
0 >i
while
i 3 lt
if
name 8 add i add ldb >ch
ch 32 neq if
ch dest out add stb
out 1 add >out
end
i 1 add >i
0
else
1
end
end
end
0 dest out add stb
;
# Typed word -> 11-byte name in DOS_NAME_A; 0 = ok.
fn dos_name_from_word (w) :
local len 0
w con.dos_strlen >len
w len DOS_NAME_A dos_name_build ret
;
# "[N:]NAME.EXT" -> dos_spec_drv plus DOS_NAME_A; returns the name length
# or -1 when the name is malformed.
fn dos_parse_spec (src len) :
local off 0
local nlen 0
local ch 0
dos_drv >dos_spec_drv
0 >off
len 2 ge if
src 1 add ldb 58 eq if
src ldb >ch
ch 48 ge ch 51 le or if
ch 48 sub >dos_spec_drv
2 >off
else
-1 ret
end
end
end
len off sub >nlen
src off add nlen DOS_NAME_A dos_name_build 0 neq if -1 ret end
nlen ret
;
# Split the command line into uppercase words in DOS_WORD_BUF; returns the
# word count (at most DOS_MAX_WORDS).
fn dos_words (ptr len) :
local i 0
local w 0
local n 0
local ch 0
local started 0
0 >n
0 >w
0 >started
while
i len lt
if
ptr i add ldb >ch
ch 32 eq ch 9 eq and if
started 0 neq if
0 DOS_WORD_BUF w DOS_WORD_CAP mul add n add stb
w 1 add >w
0 >n
0 >started
end
else
w DOS_MAX_WORDS lt n 31 lt or if
ch con.dos_upper DOS_WORD_BUF w DOS_WORD_CAP mul add n add stb
n 1 add >n
1 >started
end
end
i 1 add >i
0
else
1
end
end
started 0 neq if
0 DOS_WORD_BUF w DOS_WORD_CAP mul add n add stb
w 1 add >w
end
w ret
;
# Address of the remainder of the command line after `count` words.
fn dos_tail (ptr count) :
local i 0
local w 0
local ch 0
0 >i
0 >w
while
w count lt
if
while
ptr i add ldb 32 eq
if
i 1 add >i
0
else
1
end
end
while
ptr i add ldb 0 neq ptr i add ldb 32 neq or ptr i add ldb 9 neq or
if
i 1 add >i
0
else
1
end
end
w 1 add >w
0
else
1
end
end
while
ptr i add ldb 32 eq
if
i 1 add >i
0
else
1
end
end
ptr i add ret
;
fn dos_parse_dec (ptr) :
local i 0
local ch 0
local v 0
local n 0
0 >v
0 >n
while
ptr i add ldb >ch
ch 0 neq
if
ch 48 lt ch 57 gt or if -1 ret end
v 10 mul ch 48 sub add >v
i 1 add >i
n 1 add >n
0
else
1
end
end
n 0 eq if -1 ret end
v ret
;
fn dos_hexval (ch) :
local c 0
ch con.dos_upper >c
c 48 ge c 57 le or if c 48 sub ret end
c 65 ge c 70 le or if c 55 sub ret end
-1 ret
;
fn dos_parse_hex (ptr) :
local i 0
local ch 0
local v 0
local d 0
local n 0
0 >v
0 >n
while
ptr i add ldb >ch
ch 0 neq
if
ch dos_hexval >d
d 0 lt if -1 ret end
v 4 shl d add >v
i 1 add >i
n 1 add >n
0
else
1
end
end
n 0 eq if -1 ret end
v ret
;
!end
# ---------------- disk ----------------
!namespace disk -
# Seconds since the Unix epoch from the PeC RTC (0 when it is not wired).
fn dos_time () :
DOS_RTC_SECONDS ld ret
;
fn dos_mount (drv) :
drv DOS_DIR_BUF dsfs.dsfs_mount ret
;
# 0 when the current drive is mounted; prints an error otherwise.
fn dos_ensure () :
dos_drv dos_mount 0 eq if 0 ret end
"DRIVE NOT MOUNTED - FORMAT IT FIRST" con.dos_err
1 ret
;
# Size of `name` (11-byte on-disk form) in the current volume, or -1.
fn dos_file_size (name) :
local idx 0
DOS_DIR_BUF dsfs.dsfs_dir_load 0 neq if -1 ret end
DOS_DIR_BUF name dsfs.dsfs_find >idx
idx 0 lt if -1 ret end
DOS_DIR_BUF idx 5 shl add 20 add ld ret
;
!end
# ---------------- commands ----------------
!namespace cmds -
fn dos_cmd_dir () :
local i 0
local addr 0
local rows 0
local size 0
local digits 0
local used 0
disk.dos_ensure 0 neq if retn end
DOS_DIR_BUF dsfs.dsfs_dir_load 0 neq if "DIRECTORY READ ERROR" con.dos_err retn end
DOS_DIR_BUF dsfs.dsfs_count >used
"DRIVE " con.dos_puts
dos_drv con.dos_putnum
" " con.dos_puts
dsfs.dsfs_total con.dos_putnum
" BLOCKS " con.dos_puts
used con.dos_putnum
" FILE(S)" con.dos_putsln
" # NAME SIZE BLOCKS" con.dos_putsln
1 >rows
0 >i
while
i 256 lt
if
DOS_DIR_BUF i 5 shl add >addr
addr ldb 1 eq if
" " con.dos_puts
i 2 con.dos_puthex
" " con.dos_puts
addr 1 add DOS_TMP_TXT names.dos_name_text
DOS_TMP_TXT con.dos_puts
DOS_TMP_TXT con.dos_strlen 17 lt if
17 DOS_TMP_TXT con.dos_strlen sub con.dos_pad
end
addr 20 add ld >size
size DOS_TMP_TXT con.dos_num_text >digits
0 DOS_TMP_TXT digits add stb
DOS_TMP_TXT con.dos_puts
8 digits sub con.dos_pad
size 0 eq if
0 con.dos_putnum
else
size 511 add 9 shr con.dos_putnum
end
con.dos_newline
rows 1 add >rows
rows 26 ge if
0 >rows
con.dos_more
end
end
i 1 add >i
0
else
1
end
end
;
fn dos_cmd_type (name) :
local i 0
local rows 0
local size 0
local ch 0
disk.dos_ensure 0 neq if retn end
name disk.dos_file_size >size
size 0 lt if "NOT FOUND" con.dos_err retn end
size DOS_MAX_FILE gt if "FILE TOO LARGE" con.dos_err retn end
DOS_DIR_BUF name DOS_FILE_BUF dsfs.dsfs_read_file 0 neq if "READ ERROR" con.dos_err retn end
0 >i
0 >rows
while
i size lt
if
DOS_FILE_BUF i add ldb >ch
ch 10 eq if
con.dos_newline
rows 1 add >rows
rows 24 ge if
0 >rows
con.dos_more
end
else
ch con.dos_putc
end
i 1 add >i
0
else
1
end
end
con.dos_newline
;
fn dos_cmd_run (name) :
local size 0
local err 0
disk.dos_ensure 0 neq if retn end
name disk.dos_file_size >size
size 0 lt if "NOT FOUND" con.dos_err retn end
size DOS_MAX_FILE gt if "FILE TOO LARGE" con.dos_err retn end
DOS_DIR_BUF name DOS_FILE_BUF dsfs.dsfs_read_file 0 neq if "READ ERROR" con.dos_err retn end
"STARTING " con.dos_puts
name DOS_TMP_TXT names.dos_name_text
DOS_TMP_TXT con.dos_putsln
DOS_FILE_BUF size wax.wax_load >err
err wax.WAX_ERR_HEADER eq if "INVALID WAX HEADER" con.dos_err retn end
err wax.WAX_ERR_LAYOUT eq if "INVALID WAX LAYOUT" con.dos_err retn end
err wax.WAX_ERR_RANGE eq if "INVALID WAX RANGE" con.dos_err retn end
err wax.WAX_ERR_OVERLAP eq if "OVERLAPPING WAX DATA" con.dos_err retn end
err wax.WAX_ERR_ENTRY eq if "INVALID WAX ENTRY" con.dos_err retn end
err wax.WAX_ERR_RESERVED eq if "WAX USES RESERVED RAM" con.dos_err retn end
err wax.WAX_ERR_BUFFER eq if "INVALID WAX BUFFER" con.dos_err retn end
"WAX LOAD ERROR" con.dos_err
;
fn dos_cmd_new (name) :
disk.dos_ensure 0 neq if retn end
name disk.dos_file_size 0 ge if "ALREADY EXISTS" con.dos_err retn end
disk.dos_time dsfs.dsfs_set_time
DOS_DIR_BUF DOS_BM_BUF name DOS_FILE_BUF 0 dsfs.dsfs_write_file 0 neq if "CREATE FAILED" con.dos_err retn end
"CREATED " con.dos_puts
name DOS_TMP_TXT names.dos_name_text
DOS_TMP_TXT con.dos_putsln
;
fn dos_cmd_delete (name) :
disk.dos_ensure 0 neq if retn end
name disk.dos_file_size 0 lt if "NOT FOUND" con.dos_err retn end
DOS_DIR_BUF DOS_BM_BUF name dsfs.dsfs_delete_file 0 neq if "DELETE FAILED" con.dos_err retn end
"DELETED " con.dos_puts
name DOS_TMP_TXT names.dos_name_text
DOS_TMP_TXT con.dos_putsln
;
fn dos_cmd_rename (old new) :
local idx 0
local addr 0