1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <bio.h> 5 #include <event.h> 6 7 enum {PNCTL=3}; 8 9 static char* rdenv(char*); 10 int newwin(char*); 11 Rectangle screenrect(void); 12 13 int nokill; 14 int textmode; 15 char *title; 16 17 Image *light; 18 Image *dark; 19 Image *text; 20 21 void 22 initcolor(void) 23 { 24 text = display->black; 25 light = allocimagemix(display, DPalegreen, DWhite); 26 dark = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DDarkgreen); 27 } 28 29 Rectangle rbar; 30 Point ptext; 31 vlong n, d; 32 int last; 33 int lastp; 34 int first = 1; 35 36 char backup[80]; 37 38 void 39 drawbar(void) 40 { 41 int i, j; 42 int p; 43 char buf[10], bar[100]; 44 45 if(n > d || n < 0 || d <= 0) 46 return; 47 48 i = (Dx(rbar)*n)/d; 49 p = (n*100LL)/d; 50 51 if(lastp == p && last == i) 52 return; 53 54 if(textmode){ 55 bar[0] = '|'; 56 for(j=0; j<i; j++) 57 bar[j+1] = '#'; 58 for(; j<60; j++) 59 bar[j+1] = '-'; 60 bar[61] = '|'; 61 bar[62] = ' '; 62 sprint(bar+63, "%3d%%", p); 63 if(first) 64 first = 0; 65 else{ 66 for(i=0; i<strlen(bar); i++) 67 backup[i] = '\b'; 68 write(1, backup, i); 69 } 70 write(1, bar, strlen(bar)); 71 lastp = p; 72 last = i; 73 return; 74 } 75 76 if(lastp != p){ 77 sprint(buf, "%d%%", p); 78 79 stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP); 80 lastp = p; 81 } 82 83 if(last != i){ 84 draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y), 85 dark, nil, ZP); 86 last = i; 87 } 88 flushimage(display, 1); 89 } 90 91 void 92 eresized(int new) 93 { 94 Point p, q; 95 Rectangle r; 96 97 if(new && getwindow(display, Refnone) < 0) 98 fprint(2,"can't reattach to window"); 99 100 r = screen->r; 101 draw(screen, r, light, nil, ZP); 102 p = string(screen, addpt(r.min, Pt(4,4)), text, ZP, 103 display->defaultfont, title); 104 105 p.x = r.min.x+4; 106 p.y += display->defaultfont->height+4; 107 108 q = subpt(r.max, Pt(4,4)); 109 rbar = Rpt(p, q); 110 111 ptext = Pt(r.max.x-4-stringwidth(display->defaultfont, "100%"), r.min.x+4); 112 border(screen, rbar, -2, dark, ZP); 113 last = 0; 114 lastp = -1; 115 116 drawbar(); 117 } 118 119 void 120 bar(Biobuf *b) 121 { 122 char *p, *f[2]; 123 Event e; 124 int k, die, parent, child; 125 126 parent = getpid(); 127 128 die = 0; 129 if(!textmode) switch(child = rfork(RFMEM|RFPROC)) { 130 case 0: 131 sleep(1000); 132 while(!die && (k = eread(Ekeyboard|Emouse, &e))) { 133 if(nokill==0 && k == Ekeyboard && (e.kbdc == 0x7F || e.kbdc == 0x03)) { /* del, ctl-c */ 134 die = 1; 135 postnote(PNPROC, parent, "interrupt"); 136 _exits("interrupt"); 137 } 138 } 139 _exits(0); 140 } 141 142 while(!die && (p = Brdline(b, '\n'))) { 143 p[Blinelen(b)-1] = '\0'; 144 if(tokenize(p, f, 2) != 2) 145 continue; 146 n = strtoll(f[0], 0, 0); 147 d = strtoll(f[1], 0, 0); 148 drawbar(); 149 } 150 postnote(PNCTL, child, "kill"); 151 die = 1; 152 } 153 154 155 void 156 usage(void) 157 { 158 fprint(2, "usage: bargraph [-kt] [-w minx,miny,maxx,maxy] 'title'\n"); 159 exits("usage"); 160 } 161 162 void 163 main(int argc, char **argv) 164 { 165 Biobuf b; 166 char *p, *q; 167 int lfd; 168 169 p = "0,0,200,60"; 170 171 ARGBEGIN{ 172 case 'w': 173 p = ARGF(); 174 break; 175 case 't': 176 textmode = 1; 177 break; 178 case 'k': 179 nokill = 1; 180 break; 181 default: 182 usage(); 183 }ARGEND; 184 185 if(argc != 1) 186 usage(); 187 188 title = argv[0]; 189 190 lfd = dup(0, -1); 191 192 while(q = strchr(p, ',')) 193 *q = ' '; 194 Binit(&b, lfd, OREAD); 195 if(textmode || newwin(p) < 0){ 196 textmode = 1; 197 rbar = Rect(0, 0, 60, 1); 198 }else{ 199 initdraw(0, 0, "bar"); 200 initcolor(); 201 einit(Emouse|Ekeyboard); 202 eresized(0); 203 } 204 bar(&b); 205 } 206 207 208 /* all code below this line should be in the library, but is stolen from colors instead */ 209 static char* 210 rdenv(char *name) 211 { 212 char *v; 213 int fd, size; 214 215 fd = open(name, OREAD); 216 if(fd < 0) 217 return 0; 218 size = seek(fd, 0, 2); 219 v = malloc(size+1); 220 if(v == 0){ 221 fprint(2, "page: can't malloc: %r\n"); 222 exits("no mem"); 223 } 224 seek(fd, 0, 0); 225 read(fd, v, size); 226 v[size] = 0; 227 close(fd); 228 return v; 229 } 230 231 int 232 newwin(char *win) 233 { 234 char *srv, *mntsrv; 235 char spec[100]; 236 int srvfd, cons, pid; 237 238 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ 239 case -1: 240 fprint(2, "bargraph: can't fork: %r\n"); 241 return -1; 242 case 0: 243 break; 244 default: 245 exits(0); 246 } 247 248 srv = rdenv("/env/wsys"); 249 if(srv == 0){ 250 mntsrv = rdenv("/mnt/term/env/wsys"); 251 if(mntsrv == 0){ 252 fprint(2, "bargraph: can't find $wsys\n"); 253 return -1; 254 } 255 srv = malloc(strlen(mntsrv)+10); 256 sprint(srv, "/mnt/term%s", mntsrv); 257 free(mntsrv); 258 pid = 0; /* can't send notes to remote processes! */ 259 }else 260 pid = getpid(); 261 srvfd = open(srv, ORDWR); 262 free(srv); 263 if(srvfd == -1){ 264 fprint(2, "bargraph: can't open %s: %r\n", srv); 265 return -1; 266 } 267 sprint(spec, "new -r %s", win); 268 if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){ 269 fprint(2, "bargraph: can't mount /mnt/wsys: %r (spec=%s)\n", spec); 270 return -1; 271 } 272 close(srvfd); 273 unmount("/mnt/acme", "/dev"); 274 bind("/mnt/wsys", "/dev", MBEFORE); 275 cons = open("/dev/cons", OREAD); 276 if(cons==-1){ 277 NoCons: 278 fprint(2, "bargraph: can't open /dev/cons: %r"); 279 return -1; 280 } 281 dup(cons, 0); 282 close(cons); 283 cons = open("/dev/cons", OWRITE); 284 if(cons==-1) 285 goto NoCons; 286 dup(cons, 1); 287 dup(cons, 2); 288 close(cons); 289 // wctlfd = open("/dev/wctl", OWRITE); 290 return 0; 291 } 292 293 Rectangle 294 screenrect(void) 295 { 296 int fd; 297 char buf[12*5]; 298 299 fd = open("/dev/screen", OREAD); 300 if(fd == -1) 301 fd=open("/mnt/term/dev/screen", OREAD); 302 if(fd == -1){ 303 fprint(2, "page: can't open /dev/screen: %r\n"); 304 exits("window read"); 305 } 306 if(read(fd, buf, sizeof buf) != sizeof buf){ 307 fprint(2, "page: can't read /dev/screen: %r\n"); 308 exits("screen read"); 309 } 310 close(fd); 311 return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); 312 } 313 314 int 315 postnote(int group, int pid, char *note) 316 { 317 char file[128]; 318 int f, r; 319 320 switch(group) { 321 case PNPROC: 322 sprint(file, "/proc/%d/note", pid); 323 break; 324 case PNGROUP: 325 sprint(file, "/proc/%d/notepg", pid); 326 break; 327 case PNCTL: 328 sprint(file, "/proc/%d/ctl", pid); 329 break; 330 default: 331 return -1; 332 } 333 334 f = open(file, OWRITE); 335 if(f < 0) 336 return -1; 337 338 r = strlen(note); 339 if(write(f, note, r) != r) { 340 close(f); 341 return -1; 342 } 343 close(f); 344 return 0; 345 } 346