# FSET(1) # # Perform set operations on file specifications # # Thomas R. Hicks # # Last modified 8/14/84 # procedure main(args) local i, fyls, arglist if not find("sets",&options) then stop("Set extensions must be enabled to run this program.") if *args = 0 then return if *args > 1 then every i := 2 to *args do args[1] ||:= (" " || args[i]) (arglist := parse(args[1])) | stop("Invalid file specification expression") case type(arglist) of { "string" : fyls := mkfset(arglist) "list" : fyls := exec(arglist) default : stop("Main: bad type -can't happen") } fyls := sort(fyls) every write(!fyls," ") end procedure Exp() # file spec expression parser local a suspend (a := [Factor(),=Op(),Factor()] & [a[2],a[1],a[3]]) | Factor() | (a := [="(",Exp(),=")"] & .a[2]) end procedure Factor() # file spec expression parser local a suspend (a := [Term(),=Op(),Term()] & [a[2],a[1],a[3]]) | Term() | (a := [="(",Factor(),=")"] & .a[2]) end procedure Name() # file spec name matcher static valid initial valid := ~'()' suspend (any(~valid) || fail) | tab(find(Op()) | many(valid)) end procedure Non() # file spec expression parser local a suspend a := [Name(),=Op(),Name()] & [a[2],a[1],a[3]] end procedure Op() # file spec operation matcher suspend !["++","--","&&"] end procedure Term() # file spec expression parser local a suspend (a := [="(",Non(),=")"] & .a[2]) | Name() end procedure bldfset(arg) # build file set, excluding . and .. local line static dotfiles initial dotfiles := set([".",".."]) line := read(open("echo " || arg,"rp")) return str2set(line,' ') -- dotfiles end procedure exec(lst) # process file spec list recursively return setops(lst[1])(exec2(lst[2]),exec2(lst[3])) end procedure exec2(arg) # helping procedure for exec case type(arg) of { "string" : return mkfset(arg) "list" : return exec(arg) default : stop("exec2: can't happen") } end procedure mkfset(fspec) # make file list from specification if fspec == "*" then fspec := "* .*" return bldfset(fspec) end procedure parse(str) # top level of parsing procedures local res str ? (res := Exp() & pos(0)) | fail return res end procedure sdiff(f1,f2) # set difference return f1 -- f2 end procedure setops(op) # return correct set operaton case op of { "++" : return sunion "&&" : return sinter "--" : return sdiff } end procedure sinter(f1,f2) # set intersection return f1 ** f2 end procedure str2set(str,delim) # convert delimited string into a set local fset, f fset := set([]) str ? { while f := (tab(upto(delim))) do { insert(fset,f) move(1) } if "" ~== (f := tab(0)) then insert(fset,f) } return fset end procedure sunion(f1,f2) # set union return f1 ++ f2 end