1implement Readdir; 2 3include "sys.m"; 4 sys: Sys; 5 Dir: import sys; 6include "readdir.m"; 7 8init(path: string, sortkey: int): (array of ref Dir, int) 9{ 10 sys = load Sys Sys->PATH; 11 fd := sys->open(path, Sys->OREAD); 12 if(fd == nil) 13 return (nil, -1); 14 return readall(fd, sortkey); 15} 16 17readall(fd: ref Sys->FD, sortkey: int): (array of ref Dir, int) 18{ 19 sys = load Sys Sys->PATH; 20 dl: list of array of Dir; 21 n := 0; 22 for(;;){ 23 (nr, b) := sys->dirread(fd); 24 if(nr <= 0){ 25 # any error makes the whole directory unreadable 26 if(nr < 0) 27 return (nil, -1); 28 break; 29 } 30 dl = b :: dl; 31 n += nr; 32 } 33 rl := dl; 34 for(dl = nil; rl != nil; rl = tl rl) 35 dl = hd rl :: dl; 36 a := makerefs(dl, n, sortkey & COMPACT); 37 sortkey &= ~COMPACT; 38 if((sortkey & ~DESCENDING) == NONE) 39 return (a, len a); 40 return sortdir(a, sortkey); 41} 42 43makerefs(dl: list of array of Dir, n: int, compact: int): array of ref Dir 44{ 45 a := array[n] of ref Dir; 46 ht: array of list of string; 47 if(compact) 48 ht = array[41] of list of string; 49 j := 0; 50 for(; dl != nil; dl = tl dl){ 51 d := hd dl; 52 for(i := 0; i < len d; i++) 53 if(ht == nil || hashadd(ht, d[i].name)) 54 a[j++] = ref d[i]; 55 } 56 if(j != n) 57 a = a[0:j]; 58 return a; 59} 60 61sortdir(a: array of ref Dir, key: int): (array of ref Dir, int) 62{ 63 mergesort(a, array[len a] of ref Dir, key); 64 return (a, len a); 65} 66 67# mergesort because it's stable. 68mergesort(a, b: array of ref Dir, key: int) 69{ 70 r := len a; 71 if (r > 1) { 72 m := (r-1)/2 + 1; 73 mergesort(a[0:m], b[0:m], key); 74 mergesort(a[m:], b[m:], key); 75 b[0:] = a; 76 for ((i, j, k) := (0, m, 0); i < m && j < r; k++) { 77 if (greater(b[i], b[j], key)) 78 a[k] = b[j++]; 79 else 80 a[k] = b[i++]; 81 } 82 if (i < m) 83 a[k:] = b[i:m]; 84 else if (j < r) 85 a[k:] = b[j:r]; 86 } 87} 88 89greater(x, y: ref Dir, sortkey: int): int 90{ 91 case (sortkey) { 92 NAME => return(x.name > y.name); 93 ATIME => return(x.atime < y.atime); 94 MTIME => return(x.mtime < y.mtime); 95 SIZE => return(x.length > y.length); 96 NAME|DESCENDING => return(x.name < y.name); 97 ATIME|DESCENDING => return(x.atime > y.atime); 98 MTIME|DESCENDING => return(x.mtime > y.mtime); 99 SIZE|DESCENDING => return(x.length < y.length); 100 } 101 return 0; 102} 103 104# from tcl_strhash.b 105hashfn(key: string, n : int): int 106{ 107 h := 0; 108 for(i := 0; i < len key; i++){ 109 h = 10*h + key[i]; 110 h = h%n; 111 } 112 return h%n; 113} 114 115hashadd(ht: array of list of string, nm: string): int 116{ 117 idx := hashfn(nm, len ht); 118 for (ent := ht[idx]; ent != nil; ent = tl ent) 119 if (hd ent == nm) 120 return 0; 121 ht[idx] = nm :: ht[idx]; 122 return 1; 123} 124