implement Disdep; ## Copyright © 2000 Vita Nuova Limited. All rights reserved.# include "sys.m"; sys: Sys; print, sprint: import sys; include "bufio.m"; bufio: Bufio; Iobuf: import bufio; include "draw.m"; include "string.m"; str: String; include "arg.m"; arg: Arg; include "dis.m"; dis: Dis; Mod: import dis; include "hash.m"; hash: Hash; HashTable, HashVal: import hash; Disdep: module{ init: fn(ctxt: ref Draw->Context, argv: list of string);}; Item: adt { name: string; needs: cyclic list of ref Item; visited: int; find: fn(s: string): ref Item;}; bout: ref Iobuf;pending: list of ref Item;roots: list of ref Item;tab: ref HashTable;aflag := 0; # display all non-recursive dependenciesoflag := 0; # only list the immediate (outer) dependenciessflag := 0; # include $system modulespflag := 0; # show dependency sets as pairs, one per lineshowdepth := 0; # indent to show the dependency structure noload(mod: string){ sys->fprint(sys->fildes(2), "disdep: can't load %s: %r\n", mod); raise "fail:load";} usage(){ sys->fprint(sys->fildes(2), "Usage: disdep [-a] [-d] [-o] [-p] [-s] file.dis ...\n"); raise "fail:usage";} init(nil: ref Draw->Context, argv: list of string){ sys = load Sys Sys->PATH; bufio = load Bufio Bufio->PATH; if(bufio == nil) noload(Bufio->PATH); str = load String String->PATH; if(str == nil) noload(String->PATH); hash = load Hash Hash->PATH; if(hash == nil) noload(Hash->PATH); arg = load Arg Arg->PATH; if(arg == nil) noload(Arg->PATH); dis = load Dis Dis->PATH; if(dis == nil) noload(Dis->PATH); dis->init(); arg->init(argv); while((opt := arg->opt()) != 0) case opt { 'a' => aflag = 1; showdepth = 1; 'o' => oflag = 1; 's' => sflag = 1; 'd' => showdepth = 1; 'p' => pflag = 1; * => usage(); } argv = arg->argv(); if(argv == nil) usage(); tab = hash->new(521); bout = bufio->fopen(sys->fildes(1), Sys->OWRITE); for(l := rev(argv); l != nil; l = tl l) roots = Item.find(hd l) :: roots; pending = roots; while(pending != nil){ f := hd pending; pending = tl pending; (m, s) := dis->loadobj(f.name); if(s != nil){ sys->fprint(sys->fildes(2), "disdep: can't open %s: %s\n", f.name, s); continue; } f.needs = disfind(m); for(nl := f.needs; nl != nil; nl = tl nl){ n := hd nl; if(!n.visited){ n.visited = 1; if(!oflag && !isdol(n.name)) pending = n :: pending; } } } if(pflag){ for(i := 0; i < nextitem; i++){ f := items[i]; if(f.needs != nil){ for(nl := f.needs; nl != nil; nl = tl nl){ bout.puts(f.name); bout.putc(' '); bout.puts((hd nl).name); bout.putc('\n'); } }else{ bout.puts(f.name); bout.putc('\n'); } } }else{ unvisited(); for(; roots != nil; roots = tl roots){ if(aflag) unvisited(); f := hd roots; depth := 0; if(showdepth){ bout.puts(f.name); bout.putc('\n'); depth = 1; } prdep(hd roots, depth); } } bout.flush();} disfind(m: ref Mod): list of ref Item{ needs: list of ref Item; for(d := m.data; d != nil; d = tl d) { pick dat := hd d { String => if(isdisfile(dat.str) || sflag && isdol(dat.str)) needs = Item.find(dat.str) :: needs; } } return rev(needs);} prdep(f: ref Item, depth: int){ f.visited = 1; # short-circuit self-reference for(nl := f.needs; nl != nil; nl = tl nl){ n := hd nl; if(!n.visited){ n.visited = 1; name(n.name, depth); prdep(n, depth+1); }else if(aflag) name(n.name, depth); }} items := array[100] of ref Item;nextitem := 0; Item.find(name: string): ref Item{ k := tab.find(name); if(k != nil) return items[k.i]; if(nextitem >= len items){ a := array[len items + 100] of ref Item; a[0:] = items; items = a; } f := ref Item; f.name = name; f.visited = 0; items[nextitem] = f; tab.insert(name, HashVal(nextitem, 0.0, nil)); nextitem++; return f;} unvisited(){ for(i := 0; i < nextitem; i++) items[i].visited = 0;} name(s: string, depth: int){ if(showdepth) for(i:=0; i<depth; i++) bout.putc('\t'); bout.puts(s); bout.putc('\n');} isdisfile(s: string): int{ if(len s > 4 && s[len s-4:]==".dis"){ # worth a look for(i := 0; i < len s; i++) if(s[i] <= ' ' || s[i] == '%') return 0; return 1; } return 0;} isdol(s: string): int{ return len s > 1 && s[0] == '$' && s[1]>='A' && s[1]<='Z'; # reasonable guess} rev[T](l: list of T): list of T{ t: list of T; for(; l != nil; l = tl l) t = hd l :: t; return t;}
implement Disdep;
#
# Copyright © 2000 Vita Nuova Limited. All rights reserved.
#
include "sys.m";
sys: Sys;
print, sprint: import sys;
include "bufio.m";
bufio: Bufio;
Iobuf: import bufio;
include "draw.m";
include "string.m";
str: String;
include "arg.m";
arg: Arg;
include "dis.m";
dis: Dis;
Mod: import dis;
include "hash.m";
hash: Hash;
HashTable, HashVal: import hash;
Disdep: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
Item: adt {
name: string;
needs: cyclic list of ref Item;
visited: int;
find: fn(s: string): ref Item;
};
bout: ref Iobuf;
pending: list of ref Item;
roots: list of ref Item;
tab: ref HashTable;
aflag := 0; # display all non-recursive dependencies
oflag := 0; # only list the immediate (outer) dependencies
sflag := 0; # include $system modules
pflag := 0; # show dependency sets as pairs, one per line
showdepth := 0; # indent to show the dependency structure
noload(mod: string)
{
sys->fprint(sys->fildes(2), "disdep: can't load %s: %r\n", mod);
raise "fail:load";
}
usage()
{
sys->fprint(sys->fildes(2), "Usage: disdep [-a] [-d] [-o] [-p] [-s] file.dis ...\n");
raise "fail:usage";
}
init(nil: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
bufio = load Bufio Bufio->PATH;
if(bufio == nil)
noload(Bufio->PATH);
str = load String String->PATH;
if(str == nil)
noload(String->PATH);
hash = load Hash Hash->PATH;
if(hash == nil)
noload(Hash->PATH);
arg = load Arg Arg->PATH;
if(arg == nil)
noload(Arg->PATH);
dis = load Dis Dis->PATH;
if(dis == nil)
noload(Dis->PATH);
dis->init();
arg->init(argv);
while((opt := arg->opt()) != 0)
case opt {
'a' => aflag = 1; showdepth = 1;
'o' => oflag = 1;
's' => sflag = 1;
'd' => showdepth = 1;
'p' => pflag = 1;
* => usage();
}
argv = arg->argv();
if(argv == nil)
usage();
tab = hash->new(521);
bout = bufio->fopen(sys->fildes(1), Sys->OWRITE);
for(l := rev(argv); l != nil; l = tl l)
roots = Item.find(hd l) :: roots;
pending = roots;
while(pending != nil){
f := hd pending;
pending = tl pending;
(m, s) := dis->loadobj(f.name);
if(s != nil){
sys->fprint(sys->fildes(2), "disdep: can't open %s: %s\n", f.name, s);
continue;
}
f.needs = disfind(m);
for(nl := f.needs; nl != nil; nl = tl nl){
n := hd nl;
if(!n.visited){
n.visited = 1;
if(!oflag && !isdol(n.name))
pending = n :: pending;
}
}
}
if(pflag){
for(i := 0; i < nextitem; i++){
f := items[i];
if(f.needs != nil){
for(nl := f.needs; nl != nil; nl = tl nl){
bout.puts(f.name);
bout.putc(' ');
bout.puts((hd nl).name);
bout.putc('\n');
}
}else{
bout.puts(f.name);
bout.putc('\n');
}
}
}else{
unvisited();
for(; roots != nil; roots = tl roots){
if(aflag)
unvisited();
f := hd roots;
depth := 0;
if(showdepth){
bout.puts(f.name);
bout.putc('\n');
depth = 1;
}
prdep(hd roots, depth);
}
}
bout.flush();
}
disfind(m: ref Mod): list of ref Item
{
needs: list of ref Item;
for(d := m.data; d != nil; d = tl d) {
pick dat := hd d {
String =>
if(isdisfile(dat.str) || sflag && isdol(dat.str))
needs = Item.find(dat.str) :: needs;
}
}
return rev(needs);
}
prdep(f: ref Item, depth: int)
{
f.visited = 1; # short-circuit self-reference
for(nl := f.needs; nl != nil; nl = tl nl){
n := hd nl;
if(!n.visited){
n.visited = 1;
name(n.name, depth);
prdep(n, depth+1);
}else if(aflag)
name(n.name, depth);
}
}
items := array[100] of ref Item;
nextitem := 0;
Item.find(name: string): ref Item
{
k := tab.find(name);
if(k != nil)
return items[k.i];
if(nextitem >= len items){
a := array[len items + 100] of ref Item;
a[0:] = items;
items = a;
}
f := ref Item;
f.name = name;
f.visited = 0;
items[nextitem] = f;
tab.insert(name, HashVal(nextitem, 0.0, nil));
nextitem++;
return f;
}
unvisited()
{
for(i := 0; i < nextitem; i++)
items[i].visited = 0;
}
name(s: string, depth: int)
{
if(showdepth)
for(i:=0; i<depth; i++)
bout.putc('\t');
bout.puts(s);
bout.putc('\n');
}
isdisfile(s: string): int
{
if(len s > 4 && s[len s-4:]==".dis"){ # worth a look
for(i := 0; i < len s; i++)
if(s[i] <= ' ' || s[i] == '%')
return 0;
return 1;
}
return 0;
}
isdol(s: string): int
{
return len s > 1 && s[0] == '$' && s[1]>='A' && s[1]<='Z'; # reasonable guess
}
rev[T](l: list of T): list of T
{
t: list of T;
for(; l != nil; l = tl l)
t = hd l :: t;
return t;
}