summaryrefslogtreecommitdiff
path: root/system/dos/1.8.7/src/dir.dos
blob: 08456b5fc9a26cc6d64f65807fa6561075cb02a5 (plain)
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
PACKET dir DEFINES                            (* Copyright (c) 1986, 87 *)
                                              (* Frank Klapper          *)
  open dir,                                   (* 02.03.88               *)
  insert dir entry,
  delete dir entry,
  init dir ds,
  file info,
  format dir,

  dir list,
  file   exists,
  subdir exists,
  all files,
  all subdirs:
 
LET max dir entrys = 1000;

(*-------------------------------------------------------------------------*)

INITFLAG VAR dir block ds used := FALSE;
DATASPACE VAR dir block ds;
BOUND STRUCT (ALIGN dummy, ROW 64 REAL daten) VAR dir block;
REAL VAR last read dir block no;

PROC init dir block io:
  last read dir block no := -1.0;
  IF NOT initialized (dir block ds used)
    THEN dir block ds := nilspace;
         dir block := dir block ds
  FI.

END PROC init dir block io;

PROC read dir block (REAL CONST block nr):
  IF last read dir block no <> block nr
    THEN last read dir block no := -1.0;
         read disk block and close work if error (dir block ds, 2, block nr);
         last read dir block no := block nr
  FI.

END PROC read dir block;

PROC write dir block (REAL CONST block nr):
  write disk block and close work if error (dir block ds, 2, block nr);
  last read dir block no := block nr.

END PROC write dir block;

PROC write dir block:
  IF last read dir block no < 0.0
    THEN error stop ("Lesefehler")
  FI;
  write dir block (last read dir block no)

END PROC write dir block;

PROC get dir entry (TEXT VAR entry buffer, INT CONST block entry no):
  (* 0 <= block entry no <= 15 *)
  entry buffer := 32 * ".";
  INT CONST replace offset := 4 * block entry no;
  replace (entry buffer, 1, dir block.daten [replace offset + 1]);
  replace (entry buffer, 2, dir block.daten [replace offset + 2]);
  replace (entry buffer, 3, dir block.daten [replace offset + 3]);
  replace (entry buffer, 4, dir block.daten [replace offset + 4]).

END PROC get dir entry;

PROC put dir entry (TEXT CONST entry buffer, INT CONST block entry no):
  (* 0 <= block entry no <= 15 *)
  INT CONST offset := 4 * block entry no;
  dir block.daten [offset + 1] := entry buffer RSUB 1;
  dir block.daten [offset + 2] := entry buffer RSUB 2;
  dir block.daten [offset + 3] := entry buffer RSUB 3;
  dir block.daten [offset + 4] := entry buffer RSUB 4.

END PROC put dir entry;

(*-------------------------------------------------------------------------*)

LET DIRPOS = REAL;                  (* 16.0 * msdos block nr + entry no *)
                                    (* 0 <= entry no <= 15              *)

DIRPOS PROC dirpos (REAL CONST block nr, INT CONST entry nr):
  block nr * 16.0 + real (entry nr).

END PROC dir pos;

REAL PROC block no (DIRPOS CONST p):
  floor (p / 16.0)

END PROC block no;

INT PROC entry no (DIRPOS CONST p):
  int (p MOD 16.0)

END PROC entry no;

PROC incr (DIRPOS VAR p):
  p INCR 1.0.

END PROC incr;

(*-------------------------------------------------------------------------*)

LET FREELIST = STRUCT (ROW max dir entrys DIRPOS stack,
                       INT stacktop,
                       DIRPOS begin of free area,
                              end of dir,
                       REAL dir root);                  (* erste Clusterno, 0 für Main Dir *)
 
PROC init free list (FREELIST VAR flist, REAL CONST root):
  flist.stacktop           := 0;
  flist.begin of free area := dir pos (9.0e99, 0);
  flist.end of dir         := dir pos (-1.0, 0);
  flist.dir root           := root.

END PROC init free list;
 
PROC store (FREELIST VAR flist, DIRPOS CONST free pos):
  flist.stacktop INCR 1;
  flist.stack [flist.stack top] := free pos.

END PROC store;

PROC store begin of free area (FREELIST VAR flist, DIRPOS CONST begin):
  flist.begin of free area := begin

END PROC store begin of free area;

PROC store end of dir (FREELIST VAR flist, DIRPOS CONST end):
  flist.end of dir := end

END PROC store end of dir;

DIRPOS PROC free dirpos (FREELIST VAR flist):
  enable stop;
  DIRPOS VAR result;
  IF flist.stacktop > 0
    THEN pop
    ELIF NOT free area empty
    THEN first of free area
    ELIF expansion alloweded
    THEN allocate new dir cluster;
         result := free dirpos (flist)
    ELSE error stop ("Directory voll")
  FI;
  result.

pop:
  result := flist.stack [flist.stacktop];
  flist.stacktop DECR 1.

free area empty:
  flist.begin of free area > flist.end of dir.

first of free area:
  result := flist.begin of free area;
  incr (flist.begin of free area).

expansion alloweded:
  flist.dir root >= 2.0.

allocate new dir cluster:
  REAL CONST new dir cluster :: available fat entry;
  REAL VAR last entry no;
  search last entry no of fat chain;
  fat entry (new dir cluster, last fat chain entry);
  fat entry (last entry no, new dir cluster);
  write fat;
  store begin of free area (flist, dir pos (first new block, 0));
  store end   of dir       (flist, dir pos (last  new block, 15));
  init new dir cluster.

search last entry no of fat chain:
  last entry no := flist.dir root;
  WHILE NOT is last fat chain entry (fat entry (last entry no)) REP
    last entry no := fat entry (last entry no)
  PER.

first new block:
  begin of cluster (new dir cluster).

last new block:
  begin of cluster (new dir cluster) + real (sectors per cluster - 1).

init new dir cluster:
  TEXT CONST empty dir entry :: 32 * ""0"";
  INT VAR i;
  FOR i FROM 0 UPTO 15 REP
    put dir entry (empty dir entry, i)
  PER;
  disable stop;
  REAL VAR block no := first new block;
  WHILE block no <= last new block REP
    write dir block (block no)
  PER.

END PROC free dirpos; 

(*-------------------------------------------------------------------------*)

LET FILEENTRY = STRUCT (TEXT date and time,
                        REAL size,
                             first cluster, 
                        DIRPOS dirpos),

    FILELIST = STRUCT (THESAURUS thes,
                       ROW max dir entrys FILEENTRY entry);

PROC init file list (FILELIST VAR flist):
  flist.thes := empty thesaurus.

END PROC init file list;

PROC store file entry (FILELIST VAR flist, TEXT CONST entry text, DIRPOS CONST position):
  INT VAR entry index;
  insert (flist.thes, file name, entry index);
  store file entry (flist.entry [entry index], entry text, position).
 
file name:
  TEXT CONST name pre  :: compress (subtext (entry text, 1, 8)),
             name post :: compress (subtext (entry text, 9, 11));
  IF name post <> ""
    THEN name pre + "." + name post
    ELSE name pre
  FI.

END PROC store file entry;

PROC store file entry (FILEENTRY VAR fentry, TEXT CONST entry text, DIRPOS CONST position):
  fentry.first cluster := real (entry text ISUB 14);
  fentry.date and time := dos date + "  " + dos time;
  fentry.size          := dint (entry text ISUB 15, entry text ISUB 16);
  fentry.dirpos        := position.

dos date:
  day + "." + month + "." + year. 
 
day: 
  text2 (code (entry text SUB 25) MOD 32).
 
month:
  text2 (code (entry text SUB 25) DIV 32 + 8 * (code (entry text SUB 26) MOD 2)).
 
year:
  text (80 + code (entry text SUB 26) DIV 2, 2).

dos time:
  hour + ":" + minute. 
 
hour: 
  text2 (code (entry text SUB 24) DIV 8).
 
minute: 
  text2 (code (entry text SUB 23) DIV 32 + 8 * (code (entry text SUB 24) MOD 8)).
 
END PROC store file entry;

TEXT PROC text2 (INT CONST intvalue):
  IF intvalue < 10
    THEN "0" + text (intvalue)
    ELSE text (int value)
  FI.

END PROC text2;

DIRPOS PROC file entry pos (FILELIST CONST flist, TEXT CONST file name):
  INT CONST link index :: link (flist.thes, file name);
  IF link index = 0
    THEN error stop ("Die Datei """ + file name + """ gibt es nicht")
  FI;
  flist.entry [link index].dir pos.

END PROC file entry pos;

PROC delete (FILELIST VAR flist, TEXT CONST file name):
  INT VAR dummy;
  delete (flist.thes, file name, dummy).

END PROC delete;

PROC file info (FILELIST CONST flist, TEXT CONST file name, REAL VAR first cluster no, storage):
  INT CONST link index :: link (flist.thes, file name);
  IF link index = 0
    THEN error stop ("Die Datei """ + file name + """ gibt es nicht")
  FI;
  first cluster no := flist.entry [link index].first cluster;
  storage          := flist.entry [link index].size

END PROC file info;

BOOL PROC contains (FILELIST VAR flist, TEXT CONST file name):
  flist.thes CONTAINS file name

END PROC contains;

PROC list (FILE VAR f, FILELIST CONST flist):
  INT VAR index := 0;
  TEXT VAR name;
  get (flist.thes, name, index);
  WHILE index > 0 REP
    list file;
    get (flist.thes, name, index)
  PER.

list file:
  write (f, centered name);
  write (f, "  ");
  write (f, text (flist.entry [index].size, 11, 0));
  write (f, " Bytes belegt      ");
  write (f, flist.entry [index].date and time); 
(*COND TEST*)
  write (f, "  +++  "); 
  write (f, text (flist.entry [index].first cluster)); 
(*ENDCOND*)
  line (f).

centered name:
  INT VAR point pos := pos (name, ".");
  IF point pos > 0
    THEN name pre + "." + name post
    ELSE text (name, 12)
  FI.

name pre:
  text (subtext (name, 1, point pos - 1), 8).

name post:
  text (subtext (name, point pos + 1, point pos + 4), 3).
 
END PROC list;

(*-------------------------------------------------------------------------*)
 
LET DIRENTRY = REAL,

    DIRLIST = STRUCT (THESAURUS thes,
                      ROW max dir entrys DIRENTRY entry);

PROC init dir list (DIRLIST VAR dlist):
  dlist.thes := empty thesaurus.

END PROC init dir list;

PROC store subdir entry (DIRLIST VAR dlist, TEXT CONST entry text):
  INT VAR entry index;
  insert (dlist.thes, subdir name, entry index);
  dlist.entry [entry index] := real (entry text ISUB 14).

subdir name:
  TEXT CONST name pre  :: compress (subtext (entry text, 1, 8)),
             name post :: compress (subtext (entry text, 9, 11));
  IF name post <> ""
    THEN name pre + "." + name post
    ELSE name pre
  FI.

END PROC store subdir entry;

REAL PROC first cluster of subdir (DIRLIST CONST dlist, TEXT CONST name):
  INT CONST link index := link (dlist.thes, name);
  IF link index = 0
    THEN error stop ("Das Unterverzeichnis """ + name + """ gibt es nicht")
  FI;
  dlist.entry [link index].

END PROC first cluster of subdir;

BOOL PROC contains (DIRLIST CONST dlist, TEXT CONST subdir name):
  dlist.thes CONTAINS subdir name

END PROC contains;

PROC list (FILE VAR f, DIRLIST CONST dlist):
  INT VAR index := 0;
  TEXT VAR name;
  get (dlist.thes, name, index);
  WHILE index > 0 REP
    list dir;
    get (dlist.thes, name, index)
  PER.

list dir:
  write (f, centered name);
  write (f, "   <DIR>");
(*COND TEST*)
  write (f, "  +++  ");                                 
  write (f, text (dlist.entry [index]));  
(*ENDCOND*)
  line (f).

centered name:
  INT VAR point pos := pos (name, ".");
  IF point pos > 0
    THEN name pre + "." + name post
    ELSE text (name, 12)
  FI.

name pre:
  text (subtext (name, 1, point pos - 1), 8).

name post:
  text (subtext (name, point pos + 1, point pos + 4), 3).
 
END PROC list;

(*-------------------------------------------------------------------------*)

LET DIR = BOUND STRUCT (FILELIST filelist,
                        DIRLIST dirlist, 
                        FREELIST freelist,
                        TEXT path);
 
DIR VAR dir;
DATASPACE VAR dir ds;
INITFLAG VAR dir ds used := FALSE;

PROC open dir (TEXT CONST path string):
  init dir block io;
  init dir ds;
  dir.path := path string;
  load main dir;
  TEXT VAR rest path := path string;
  WHILE rest path <> "" REP
    TEXT CONST sub dir name := next sub dir name (rest path);
    load sub dir
  PER.

load main dir:
  init file list (dir.filelist);
  init dir  list (dir.dirlist);
  init free list (dir.free list, 0.0);
  store end of dir (dir.freelist, dirpos (last main dir sector, 15));
  BOOL VAR was last dir sector := FALSE;
  REAL VAR block no := first main dir sector;
  INT VAR i;
  FOR i FROM 1 UPTO dir sectors REP
      load dir block (block no, was last dir sector);
      block no INCR 1.0
      UNTIL was last dir sector
  PER. 

first main dir sector:
  real (begin of dir).

last main dir sector:
  real (begin of dir + dir sectors - 1).

load sub dir:
  REAL VAR cluster no := first cluster of sub dir (dir.dirlist, sub dir name);
  was last dir sector := FALSE;
  init file list (dir.filelist);
  init dir  list (dir.dirlist);
  init free list (dir.free list, cluster no);
  WHILE NOT is last fat chain entry (cluster no) REP
    load sub dir entrys of cluster;
    cluster no := fat entry (cluster no)
    UNTIL was last dir sector
  PER.

load sub dir entrys of cluster:
  store end of dir (dir.freelist, dirpos (last block no of cluster, 15));
  block no := begin of cluster (cluster no);
  FOR i FROM 1 UPTO sectors per cluster REP
    load dir block (block no, was last dir sector);
    block no INCR 1.0
    UNTIL was last dir sector
  PER.

last block no of cluster:
  begin of cluster (cluster no) + real (sectors per cluster - 1).

END PROC open dir;

PROC load dir block (REAL CONST block no, BOOL VAR was last block): 
  was last block := FALSE;
  read dir block (block no);
  INT VAR entry no;
  TEXT VAR entry;
  FOR entry no FROM 0 UPTO 15 REP 
    get dir entry (entry, entry no);
    process entry
    UNTIL was last block
  PER.

process entry:
  SELECT pos (""0"."229"", entry SUB 1) OF
    CASE 1: end of dir search
    CASE 2: (* root des aktuellen directorys oder des übergeordneten, also nichts tun *)
    CASE 3: free entry
    OTHERWISE volume label or file entry or subdir entry
  END SELECT.

end of dir search:
  was last block := TRUE;
  store begin of free area (dir.freelist, dir pos (block no, entry no)).

free entry:
  store (dir.freelist, dir pos (block no, entry no)).

volume label or file entry or subdir entry:
  INT CONST byte 11 :: code (entry SUB 12);
  IF (byte 11 AND 8) > 0
    THEN (* volume label *)
  ELIF (byte 11 AND 16) > 0
    THEN sub dir entry
    ELSE file entry
  FI.

sub dir entry:
  store subdir entry (dir.dir list, entry).

file entry:
  store file entry (dir.file list, entry, dir pos (block no, entry no)).

END PROC load dir block; 
 
TEXT PROC next subdir name (TEXT VAR path string):
  TEXT VAR subdir name;
  IF (path string SUB 1) <> "\"
    THEN error stop ("ungültige Pfadbezeichnung")
  FI;
  INT CONST backslash pos :: pos (path string, "\", 2);
  IF backslash pos = 0
    THEN subdir name := subtext (path string, 2);
         path string := ""
    ELSE subdir name := subtext (path string, 2, backslash pos - 1);
         path string := subtext (path string, backslash pos)
  FI;
  dos name (subdir name, read modus).

END PROC next subdir name;

PROC init dir ds:
  IF initialized (dir ds used)
    THEN forget (dir ds)
  FI;
  dir ds := nilspace;
  dir := dir ds.

END PROC init dir ds;

PROC insert dir entry (TEXT CONST name, REAL CONST start cluster, storage):
  DIRPOS CONST ins pos :: free dirpos (dir.free list);
  TEXT CONST entry string :: entry name + ""32"" + (10 * ""0"") + dos time +
                             dos date + entry start cluster + entry storage;
  write entry on disk;
  write entry in dir ds.

entry name:
  INT CONST point pos := pos (name, ".");
  IF point pos > 0
    THEN subtext (name, 1, point pos - 1) + (9 - point pos) * " " +
         subtext (name, point pos + 1) + (3 - LENGTH name + point pos) * " "
    ELSE name + (11 - LENGTH name) * " "
  FI.
 
dos time:
  TEXT CONST akt time :: time of day (clock (1));
  code ((minute MOD 8) * 32) + code (8 * hour + minute DIV 8).

hour:
  int (subtext (akt time, 1, 2)).

minute:
  int (subtext (akt time, 4, 5)).

dos date:
  TEXT CONST akt date :: date (clock (1));
  code (32 * (month MOD 8) + day) + code ((year - 80) * 2 + month DIV 8).

day: 
  int (subtext (akt date, 1, 2)).

month:
  int (subtext (akt date, 4, 5)).

year:
  int (subtext (akt date, 7, 8)).

entry start cluster:
  TEXT VAR buffer2 := "12";
  replace (buffer2, 1, low word (start cluster));
  buffer2.

entry storage:
  TEXT VAR buffer4 := "1234";
  replace (buffer4, 1, low  word (storage));
  replace (buffer4, 2, high word (storage));
  buffer4.

write entry on disk:
  read dir block (block no (ins pos));
  put dir entry (entry string, entry no (ins pos));
  write dir block.

write entry in dir ds:
  store file entry (dir.file list, entry string, ins pos).

END PROC insert dir entry;

PROC delete dir entry (TEXT CONST name):
  TEXT VAR entry;
  DIRPOS CONST del pos :: file entry pos (dir.filelist, name);
  read dir block (block no (del pos));
  get dir entry (entry, entry no (del pos));
  put dir entry (""229"" + subtext (entry, 2, 32), entry no (del pos));
  write dir block;
  delete (dir.filelist, name);
  store (dir.freelist, del pos).

END PROC delete dir entry;

PROC format dir:
  init dir block io;
  init dir ds;
  build empty dir block;
  REAL VAR block no := real (begin of dir);
  disable stop;
  FOR i FROM 1 UPTO dir sectors REP
    write dir block (block no);
    block no INCR 1.0
  PER;
  enable stop;
  dir.path := "";
  init file list (dir.file list);
  init dir  list (dir.dir  list);
  init free list (dir.free list, 0.0);
  store begin of free area (dir.free list, dir pos (real (begin of dir), 0));
  store end of dir (dir.free list, dir pos (last main dir sector, 15)).

build empty dir block:
  INT VAR i;
  FOR i FROM 0 UPTO 15 REP
    put dir entry (32 * ""0"",  i)
  PER.

last main dir sector:
  real (begin of dir + dir sectors - 1).

END PROC format dir;
 
PROC file info (TEXT CONST file name, REAL VAR start cluster, size):
  file info (dir.file list, file name, start cluster, size)

END PROC file info;

THESAURUS PROC all files:
  THESAURUS VAR t := dir.filelist.thes;
  t

END PROC all files;

THESAURUS PROC all subdirs:
  dir.dirlist.thes

END PROC all subdirs;

BOOL PROC file exists (TEXT CONST file name):
  contains (dir.filelist, file name)

END PROC file exists;

BOOL PROC subdir exists (TEXT CONST subdir name):
  contains (dir.dirlist, subdir name)

END PROC subdir exists;

PROC dir list (DATASPACE VAR ds):
  open list file;
  head line (list file, list file head);
  list (list file, dir.file list);
  list (list file, dir.dir list).

open list file:
  forget (ds);
  ds := nilspace;
  FILE VAR list file := sequential file (output, ds);
  putline (list file, "").
 
list file head:
  "DOS" + path string.

path string:
  IF dir.path <> ""
    THEN "     PATH: " + dir.path
    ELSE ""
  FI.

END PROC dir list;

END PACKET dir;