summaryrefslogtreecommitdiff
path: root/appl/cmd/fs/merge.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/cmd/fs/merge.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/cmd/fs/merge.b')
-rw-r--r--appl/cmd/fs/merge.b187
1 files changed, 187 insertions, 0 deletions
diff --git a/appl/cmd/fs/merge.b b/appl/cmd/fs/merge.b
new file mode 100644
index 00000000..977102b2
--- /dev/null
+++ b/appl/cmd/fs/merge.b
@@ -0,0 +1,187 @@
+implement Fsmodule;
+include "sys.m";
+ sys: Sys;
+include "draw.m";
+include "sh.m";
+include "fslib.m";
+ fslib: Fslib;
+ Report, Value, type2s: import fslib;
+ Fschan, Fsdata, Entrychan, Cmpchan, Entry,
+ Gatechan, Gatequery, Nilentry, Option,
+ Next, Down, Skip, Quit: import Fslib;
+
+# e.g....
+# fs select {mode -d} {merge -c {compose -d AoutB} {filter {not {path /chan /dev /usr/rog /n/local /net}} /} {merge {proto FreeBSD} {proto Hp} {proto Irix} {proto Linux} {proto MacOSX} {proto Nt} {proto Nt.ti} {proto Nt.ti925} {proto Plan9} {proto Plan9.ti} {proto Plan9.ti925} {proto Solaris} {proto authsrv} {proto dl} {proto dlsrc} {proto ep7} {proto inferno} {proto inferno.ti} {proto ipaqfs} {proto minitel} {proto os} {proto scheduler.client} {proto scheduler.server} {proto sds} {proto src} {proto src.ti} {proto sword} {proto ti925.ti} {proto ti925bin} {proto tipaq} {proto umec} {proto utils} {proto utils.ti}}} >[2] /dev/null
+
+types(): string
+{
+ return "xxxx*-1-cm";
+}
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ fslib = load Fslib Fslib->PATH;
+ if(fslib == nil){
+ sys->fprint(sys->fildes(2), "fs: cannot load %s: %r\n", Fslib->PATH);
+ raise "fail:bad module";
+ }
+}
+
+run(nil: ref Draw->Context, nil: ref Report,
+ opts: list of Option, args: list of ref Value): ref Value
+{
+ recurse := 1;
+ cmp: Cmpchan;
+ for(; opts != nil; opts = tl opts){
+ case (hd opts).opt {
+ '1' =>
+ recurse = 0;
+ 'c' =>
+ cmp = (hd (hd opts).args).m().i;
+ }
+ }
+ dst := chan of (Fsdata, chan of int);
+ spawn mergeproc((hd args).x().i, (hd tl args).x().i, dst, recurse, cmp, tl tl args == nil);
+ for(args = tl tl args; args != nil; args = tl args){
+ dst1 := chan of (Fsdata, chan of int);
+ spawn mergeproc(dst, (hd args).x().i, dst1, recurse, cmp, tl args == nil);
+ dst = dst1;
+ }
+ return ref Value.X(dst);
+}
+
+# merge two trees; assume directories are alphabetically sorted.
+mergeproc(c0, c1, dst: Fschan, recurse: int, cmp: Cmpchan, killcmp: int)
+{
+ myreply := chan of int;
+ ((d0, nil), reply0) := <-c0;
+ ((d1, nil), reply1) := <-c1;
+
+ if(compare(cmp, d0, d1) == 2r10)
+ dst <-= ((d1, nil), myreply);
+ else
+ dst <-= ((d0, nil), myreply);
+ r := <-myreply;
+ reply0 <-= r;
+ reply1 <-= r;
+ if(r == Down){
+ {
+ mergedir(c0, c1, dst, recurse, cmp);
+ } exception {"exit" =>;}
+ }
+ if(cmp != nil && killcmp)
+ cmp <-= (nil, nil, nil);
+}
+
+mergedir(c0, c1, dst: Fschan, recurse: int, cmp: Cmpchan)
+{
+ myreply := chan of int;
+ reply0, reply1: chan of int;
+ d0, d1: ref Sys->Dir;
+ eof0 := eof1 := 0;
+ for(;;){
+ if(!eof0 && d0 == nil){
+ ((d0, nil), reply0) = <-c0;
+ if(d0 == nil){
+ reply0 <-= Next;
+ eof0 = 1;
+ }
+ }
+ if(!eof1 && d1 == nil){
+ ((d1, nil), reply1) = <-c1;
+ if(d1 == nil){
+ reply1 <-= Next;
+ eof1 = 1;
+ }
+ }
+ if(eof0 && eof1)
+ break;
+
+ (wd0, wd1) := (d0, d1);
+ if(d0 != nil && d1 != nil && d0.name != d1.name){
+ if(d0.name < d1.name)
+ wd1 = nil;
+ else
+ wd0 = nil;
+ }
+
+ wc0, wc1: Fschan;
+ wreply0, wreply1: chan of int;
+ weof0, weof1: int;
+
+ c := compare(cmp, wd0, wd1);
+ if(wd0 != nil && wd1 != nil){
+ if(c != 0 && recurse && (wd0.mode & wd1.mode & Sys->DMDIR) != 0){
+ dst <-= ((wd0, nil), myreply);
+ r := <-myreply;
+ reply0 <-= r;
+ reply1 <-= r;
+ d0 = d1 = nil;
+ case r {
+ Quit =>
+ raise "exit";
+ Skip =>
+ return;
+ Down =>
+ mergedir(c0, c1, dst, 1, cmp);
+ }
+ continue;
+ }
+ # when we can't merge and there's a clash, choose c0 over c1, unless cmp says otherwise
+ if(c == 2r10){
+ reply0 <-= Next;
+ d0 = nil;
+ }else{
+ reply1 <-= Next;
+ d1 = nil;
+ }
+ }
+ if(c & 2r01){
+ (wd0, wc0, wreply0, weof0) = (d0, c0, reply0, eof0);
+ (wd1, wc1, wreply1, weof1) = (d1, c1, reply1, eof1);
+ d0 = nil;
+ }else if(c & 2r10){
+ (wd0, wc0, wreply0, weof0) = (d1, c1, reply1, eof1);
+ (wd1, wc1, wreply1, weof1) = (d0, c0, reply0, eof0);
+ d1 = nil;
+ }else{
+ if(wd0 == nil){
+ reply1 <-= Next;
+ d1 = nil;
+ }else{
+ reply0 <-= Next;
+ d0 = nil;
+ }
+ continue;
+ }
+ dst <-= ((wd0, nil), myreply);
+ r := <-myreply;
+ wreply0 <-= r;
+ if(r == Down)
+ r = fslib->copy(wc0, dst); # XXX hmm, maybe this should be a mergedir()
+ case r {
+ Quit or
+ Skip =>
+ if(wd1 == nil && !weof1)
+ (nil, wreply1) = <-wc1;
+ wreply1 <-= r;
+ if(r == Quit)
+ raise "exit";
+ return;
+ }
+ }
+ dst <-= ((nil, nil), myreply);
+ if(<-myreply == Quit)
+ raise "exit";
+}
+
+compare(cmp: Cmpchan, d0, d1: ref Sys->Dir): int
+{
+ mask := (d0 != nil) | (d1 != nil) << 1;
+ if(cmp == nil)
+ return mask;
+ reply := chan of int;
+ cmp <-= (d0, d1, reply);
+ return <-reply & mask;
+}