1# 2# Copyright © 2001 Vita Nuova (Holdings) Limited. All rights reserved. 3# 4 5implement Proto2list; 6 7# make a version list suitable for SDS from a series of proto files 8 9include "sys.m"; 10 sys : Sys; 11include "draw.m"; 12include "bufio.m"; 13 bufio : Bufio; 14 Iobuf : import bufio; 15include "crc.m"; 16 crcm : Crc; 17include "proto.m"; 18 proto : Proto; 19include "protocaller.m"; 20 protocaller : Protocaller; 21 22WARN, ERROR, FATAL : import Protocaller; 23 24Proto2list: module 25{ 26 init : fn(ctxt: ref Draw->Context, argv: list of string); 27 protofile: fn(new : string, old : string, d : ref Sys->Dir); 28 protoerr: fn(lev : int, line : int, err : string); 29}; 30 31stderr: ref Sys->FD; 32protof: string; 33 34Element: type (string, string); 35 36List: adt{ 37 as: array of Element; 38 n: int; 39 init: fn(l: self ref List); 40 add: fn(l: self ref List, e: Element); 41 end: fn(l: self ref List): array of Element; 42}; 43 44flist: ref List; 45 46List.init(l: self ref List) 47{ 48 l.as = array[1024] of Element; 49 l.n = 0; 50} 51 52List.add(l: self ref List, e: Element) 53{ 54 if(l.n == len l.as) 55 l.as = (array[2*l.n] of Element)[0:] = l.as; 56 l.as[l.n++] = e; 57} 58 59List.end(l: self ref List): array of Element 60{ 61 return l.as[0: l.n]; 62} 63 64usage() 65{ 66 sys->fprint(stderr, "Usage: proto2list protofile ...\n"); 67 exit; 68} 69 70init(nil: ref Draw->Context, argv: list of string) 71{ 72 sys = load Sys Sys->PATH; 73 bufio = load Bufio Bufio->PATH; 74 crcm = load Crc Crc->PATH; 75 proto = load Proto Proto->PATH; 76 protocaller = load Protocaller "$self"; 77 stderr = sys->fildes(2); 78 root := "/"; 79 flist = ref List; 80 flist.init(); 81 for(argv = tl argv; argv != nil; argv = tl argv){ 82 protof = hd argv; 83 proto->rdproto(hd argv, root, protocaller); 84 } 85 fs := flist.end(); 86 sort(fs); 87 fs = uniq(fs); 88 out(fs); 89} 90 91protofile(new : string, old : string, nil : ref Sys->Dir) 92{ 93 if(new == old) 94 new = "-"; 95 flist.add((old, new)); 96} 97 98out(fs: array of Element) 99{ 100 nf := len fs; 101 for(i := 0; i < nf; i++){ 102 (f, g) := fs[i]; 103 (ok, d) := sys->stat(f); 104 if (ok < 0) { 105 sys->fprint(stderr, "cannot open %s\n", f); 106 continue; 107 } 108 if (d.mode & Sys->DMDIR) 109 d.length = big 0; 110 sys->print("%s %s %d %d %d %d %d\n", f, g, int d.length, d.mode, d.mtime, crc(f, d), 0); 111 } 112} 113 114protoerr(lev : int, line : int, err : string) 115{ 116 s := "line " + string line + " : " + err; 117 case lev { 118 WARN => warn(s); 119 ERROR => error(s); 120 FATAL => fatal(s); 121 } 122} 123 124crc(f : string, d: Sys->Dir) : int 125{ 126 crcs := crcm->init(0, int 16rffffffff); 127 if (d.mode & Sys->DMDIR) 128 return 0; 129 fd := sys->open(f, Sys->OREAD); 130 if (fd == nil) { 131 sys->fprint(stderr, "cannot open %s\n", f); 132 return 0; 133 } 134 crc := 0; 135 buf := array[Sys->ATOMICIO] of byte; 136 for (;;) { 137 nr := sys->read(fd, buf, len buf); 138 if (nr < 0) { 139 sys->fprint(stderr, "bad read on %s : %r\n", f); 140 return 0; 141 } 142 if (nr <= 0) 143 break; 144 crc = crcm->crc(crcs, buf, nr); 145 } 146 crcm->reset(crcs); 147 return crc; 148} 149 150sort(a: array of Element) 151{ 152 mergesort(a, array[len a] of Element); 153} 154 155mergesort(a, b: array of Element) 156{ 157 r := len a; 158 if (r > 1) { 159 m := (r-1)/2 + 1; 160 mergesort(a[0:m], b[0:m]); 161 mergesort(a[m:], b[m:]); 162 b[0:] = a; 163 for ((i, j, k) := (0, m, 0); i < m && j < r; k++) { 164 if (b[i].t0 > b[j].t0) 165 a[k] = b[j++]; 166 else 167 a[k] = b[i++]; 168 } 169 if (i < m) 170 a[k:] = b[i:m]; 171 else if (j < r) 172 a[k:] = b[j:r]; 173 } 174} 175 176 177uniq(a: array of Element): array of Element 178{ 179 m := n := len a; 180 for(i := 0; i < n-1; ){ 181 if(a[i].t0 == a[i+1].t0){ 182 if(a[i].t1 != a[i+1].t1) 183 warn(sys->sprint("duplicate %s(%s %s)", a[i].t0, a[i].t1, a[i+1].t1)); 184 a[i+1:] = a[i+2: n--]; 185 } 186 else 187 i++; 188 } 189 if(n == m) 190 return a; 191 return a[0: n]; 192} 193 194error(s: string) 195{ 196 sys->fprint(stderr, "%s: %s\n", protof, s); 197 exit; 198} 199 200fatal(s: string) 201{ 202 sys->fprint(stderr, "fatal: %s\n", s); 203 exit; 204} 205 206warn(s: string) 207{ 208 sys->fprint(stderr, "%s: %s\n", protof, s); 209} 210