1implement Ckproto; 2 3include "sys.m"; 4 sys: Sys; 5include "draw.m"; 6include "bufio.m"; 7 bufio: Bufio; 8 Iobuf: import bufio; 9include "arg.m"; 10 arg: Arg; 11include "readdir.m"; 12 readdir : Readdir; 13include "proto.m"; 14 proto : Proto; 15include "protocaller.m"; 16 protocaller : Protocaller; 17 18WARN, ERROR, FATAL : import Protocaller; 19 20Ckproto: module{ 21 init: fn(nil: ref Draw->Context, nil: list of string); 22 protofile: fn(new : string, old : string, d : ref Sys->Dir); 23 protoerr: fn(lev : int, line : int, err : string); 24}; 25 26Dir : adt { 27 name : string; 28 proto : string; 29 parent : cyclic ref Dir; 30 child : cyclic ref Dir; 31 sibling : cyclic ref Dir; 32}; 33 34root := "/"; 35droot : ref Dir; 36protof : string; 37stderr : ref Sys->FD; 38omitgen := 0; # forget generated files 39verbose : int; 40ckmode: int; 41 42init(nil: ref Draw->Context, args: list of string) 43{ 44 sys = load Sys Sys->PATH; 45 bufio = load Bufio Bufio->PATH; 46 arg = load Arg Arg->PATH; 47 readdir = load Readdir Readdir->PATH; 48 proto = load Proto Proto->PATH; 49 protocaller = load Protocaller "$self"; 50 51 stderr = sys->fildes(2); 52 sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->FORKFD, nil); 53 arg->init(args); 54 while ((c := arg->opt()) != 0) { 55 case c { 56 'r' => 57 root = arg->arg(); 58 if (root == nil) 59 fatal("missing argument to -r"); 60 'o' => 61 omitgen = 1; 62 'v' => 63 verbose = 1; 64 'm' => 65 ckmode = 1; 66 * => 67 fatal("usage: install/ckproto [-o] [-v] [-m] [-r root] protofile ...."); 68 } 69 } 70 droot = ref Dir("/", nil, nil, nil, nil); 71 droot.parent = droot; 72 args = arg->argv(); 73 while (args != nil) { 74 protof = hd args; 75 proto->rdproto(hd args, root, protocaller); 76 args = tl args; 77 } 78 if (verbose) 79 prtree(droot, -1); 80 ckdir(root, droot); 81} 82 83protofile(new : string, old : string, nil : ref Sys->Dir) 84{ 85 if (verbose) { 86 if (old == new) 87 sys->print("%s\n", new); 88 else 89 sys->print("%s %s\n", new, old); 90 } 91 addfile(droot, old); 92 if (new != old) 93 addfile(droot, new); 94} 95 96protoerr(lev : int, line : int, err : string) 97{ 98 s := "line " + string line + " : " + err; 99 case lev { 100 WARN => warn(s); 101 ERROR => error(s); 102 FATAL => fatal(s); 103 } 104} 105 106ckdir(d : string, dird : ref Dir) 107{ 108 (dir, n) := readdir->init(d, Readdir->NAME|Readdir->COMPACT); 109 for (i := 0; i < n; i++) { 110 dire := lookup(dird, dir[i].name); 111 if(omitgen && generated(dir[i].name)) 112 continue; 113 if (dire == nil){ 114 sys->print("%s missing\n", mkpath(d, dir[i].name)); 115 continue; 116 } 117 if(ckmode){ 118 if(dir[i].mode & Sys->DMDIR){ 119 if((dir[i].mode & 8r775) != 8r775) 120 sys->print("directory %s not 775 at least\n", mkpath(d, dir[i].name)); 121 } 122 else{ 123 if((dir[i].mode & 8r664) != 8r664) 124 sys->print("file %s not 664 at least\n", mkpath(d, dir[i].name)); 125 } 126 } 127 if (dir[i].mode & Sys->DMDIR) 128 ckdir(mkpath(d, dir[i].name), dire); 129 } 130} 131 132addfile(root : ref Dir, path : string) 133{ 134 elem : string; 135 136 # ckexists(path); 137 138 curd := root; 139 opath := path; 140 while (path != nil) { 141 (elem, path) = split(path); 142 d := lookup(curd, elem); 143 if (d == nil) { 144 d = ref Dir(elem, protof, curd, nil, nil); 145 if (curd.child == nil) 146 curd.child = d; 147 else { 148 prev, this : ref Dir; 149 150 for (this = curd.child; this != nil; this = this.sibling) { 151 if (elem < this.name) { 152 d.sibling = this; 153 if (prev == nil) 154 curd.child = d; 155 else 156 prev.sibling = d; 157 break; 158 } 159 prev = this; 160 } 161 if (this == nil) 162 prev.sibling = d; 163 } 164 } 165 else if (path == nil && d.proto == protof) 166 sys->print("%s repeated in proto %s\n", opath, protof); 167 curd = d; 168 } 169} 170 171lookup(p : ref Dir, f : string) : ref Dir 172{ 173 if (f == ".") 174 return p; 175 if (f == "..") 176 return p.parent; 177 for (d := p.child; d != nil; d = d.sibling) { 178 if (d.name == f) 179 return d; 180 if (d.name > f) 181 return nil; 182 } 183 return nil; 184} 185 186prtree(root : ref Dir, indent : int) 187{ 188 if (indent >= 0) 189 sys->print("%s%s\n", string array[indent] of { * => byte '\t' }, root.name); 190 for (s := root.child; s != nil; s = s.sibling) 191 prtree(s, indent+1); 192} 193 194mkpath(prefix, elem: string): string 195{ 196 slash1 := slash2 := 0; 197 if (len prefix > 0) 198 slash1 = prefix[len prefix - 1] == '/'; 199 if (len elem > 0) 200 slash2 = elem[0] == '/'; 201 if (slash1 && slash2) 202 return prefix+elem[1:]; 203 if (!slash1 && !slash2) 204 return prefix+"/"+elem; 205 return prefix+elem; 206} 207 208split(p : string) : (string, string) 209{ 210 if (p == nil) 211 fatal("nil string in split"); 212 if (p[0] != '/') 213 fatal("p0 notg / in split"); 214 while (p[0] == '/') 215 p = p[1:]; 216 i := 0; 217 while (i < len p && p[i] != '/') 218 i++; 219 if (i == len p) 220 return (p, nil); 221 else 222 return (p[0:i], p[i:]); 223} 224 225 226gens := array[] of { 227 "dis", "sbl", "out", "0", "1", "2", "5", "8", "k", "q", "v", "t" 228}; 229 230generated(f : string) : int 231{ 232 for (i := len f -1; i >= 0; i--) 233 if (f[i] == '.') 234 break; 235 if (i < 0) 236 return 0; 237 suff := f[i+1:]; 238 for (i = 0; i < len gens; i++) 239 if (suff == gens[i]) 240 return 1; 241 return 0; 242} 243 244warn(s: string) 245{ 246 sys->print("%s: %s\n", protof, s); 247} 248 249error(s: string) 250{ 251 sys->fprint(stderr, "%s: %s\n", protof, s); 252 exit;; 253} 254 255fatal(s: string) 256{ 257 sys->fprint(stderr, "fatal: %s\n", s); 258 exit; 259} 260 261ckexists(path: string) 262{ 263 s := mkpath(root, path); 264 (ok, nil) := sys->stat(s); 265 if(ok < 0) 266 sys->print("%s does not exist\n", s); 267} 268