ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/readdir.b/
implement Readdir;
include "sys.m";
sys: Sys;
Dir: import sys;
include "readdir.m";
init(path: string, sortkey: int): (array of ref Dir, int)
{
sys = load Sys Sys->PATH;
fd := sys->open(path, Sys->OREAD);
if(fd == nil)
return (nil, -1);
return readall(fd, sortkey);
}
readall(fd: ref Sys->FD, sortkey: int): (array of ref Dir, int)
{
sys = load Sys Sys->PATH;
dl: list of array of Dir;
n := 0;
for(;;){
(nr, b) := sys->dirread(fd);
if(nr <= 0){
# any error makes the whole directory unreadable
if(nr < 0)
return (nil, -1);
break;
}
dl = b :: dl;
n += nr;
}
rl := dl;
for(dl = nil; rl != nil; rl = tl rl)
dl = hd rl :: dl;
a := makerefs(dl, n, sortkey & COMPACT);
sortkey &= ~COMPACT;
if((sortkey & ~DESCENDING) == NONE)
return (a, len a);
return sortdir(a, sortkey);
}
makerefs(dl: list of array of Dir, n: int, compact: int): array of ref Dir
{
a := array[n] of ref Dir;
ht: array of list of string;
if(compact)
ht = array[41] of list of string;
j := 0;
for(; dl != nil; dl = tl dl){
d := hd dl;
for(i := 0; i < len d; i++)
if(ht == nil || hashadd(ht, d[i].name))
a[j++] = ref d[i];
}
if(j != n)
a = a[0:j];
return a;
}
sortdir(a: array of ref Dir, key: int): (array of ref Dir, int)
{
mergesort(a, array[len a] of ref Dir, key);
return (a, len a);
}
# mergesort because it's stable.
mergesort(a, b: array of ref Dir, key: int)
{
r := len a;
if (r > 1) {
m := (r-1)/2 + 1;
mergesort(a[0:m], b[0:m], key);
mergesort(a[m:], b[m:], key);
b[0:] = a;
for ((i, j, k) := (0, m, 0); i < m && j < r; k++) {
if (greater(b[i], b[j], key))
a[k] = b[j++];
else
a[k] = b[i++];
}
if (i < m)
a[k:] = b[i:m];
else if (j < r)
a[k:] = b[j:r];
}
}
greater(x, y: ref Dir, sortkey: int): int
{
case (sortkey) {
NAME => return(x.name > y.name);
ATIME => return(x.atime < y.atime);
MTIME => return(x.mtime < y.mtime);
SIZE => return(x.length > y.length);
NAME|DESCENDING => return(x.name < y.name);
ATIME|DESCENDING => return(x.atime > y.atime);
MTIME|DESCENDING => return(x.mtime > y.mtime);
SIZE|DESCENDING => return(x.length < y.length);
}
return 0;
}
# from tcl_strhash.b
hashfn(key: string, n : int): int
{
h := 0;
for(i := 0; i < len key; i++){
h = 10*h + key[i];
h = h%n;
}
return h%n;
}
hashadd(ht: array of list of string, nm: string): int
{
idx := hashfn(nm, len ht);
for (ent := ht[idx]; ent != nil; ent = tl ent)
if (hd ent == nm)
return 0;
ht[idx] = nm :: ht[idx];
return 1;
}