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) 130 child = -1; 131 else 132 switch(child = rfork(RFMEM|RFPROC)) { 133 case 0: 134 sleep(1000); 135 while(!die && (k = eread(Ekeyboard|Emouse, &e))) { 136 if(nokill==0 && k == Ekeyboard && (e.kbdc == 0x7F || e.kbdc == 0x03)) { /* del, ctl-c */ 137 die = 1; 138 postnote(PNPROC, parent, "interrupt"); 139 _exits("interrupt"); 140 } 141 } 142 _exits(0); 143 } 144 145 while(!die && (p = Brdline(b, '\n'))) { 146 p[Blinelen(b)-1] = '\0'; 147 if(tokenize(p, f, 2) != 2) 148 continue; 149 n = strtoll(f[0], 0, 0); 150 d = strtoll(f[1], 0, 0); 151 drawbar(); 152 } 153 postnote(PNCTL, child, "kill"); 154 } 155 156 157 void 158 usage(void) 159 { 160 fprint(2, "usage: bargraph [-kt] [-w minx,miny,maxx,maxy] 'title'\n"); 161 exits("usage"); 162 } 163 164 void 165 main(int argc, char **argv) 166 { 167 Biobuf b; 168 char *p, *q; 169 int lfd; 170 171 p = "0,0,200,60"; 172 173 ARGBEGIN{ 174 case 'w': 175 p = ARGF(); 176 break; 177 case 't': 178 textmode = 1; 179 break; 180 case 'k': 181 nokill = 1; 182 break; 183 default: 184 usage(); 185 }ARGEND; 186 187 if(argc != 1) 188 usage(); 189 190 title = argv[0]; 191 192 lfd = dup(0, -1); 193 194 while(q = strchr(p, ',')) 195 *q = ' '; 196 Binit(&b, lfd, OREAD); 197 if(textmode || newwin(p) < 0){ 198 textmode = 1; 199 rbar = Rect(0, 0, 60, 1); 200 }else{ 201 initdraw(0, 0, "bar"); 202 initcolor(); 203 einit(Emouse|Ekeyboard); 204 eresized(0); 205 } 206 bar(&b); 207 } 208 209 210 /* all code below this line should be in the library, but is stolen from colors instead */ 211 static char* 212 rdenv(char *name) 213 { 214 char *v; 215 int fd, size; 216 217 fd = open(name, OREAD); 218 if(fd < 0) 219 return 0; 220 size = seek(fd, 0, 2); 221 v = malloc(size+1); 222 if(v == 0){ 223 fprint(2, "page: can't malloc: %r\n"); 224 exits("no mem"); 225 } 226 seek(fd, 0, 0); 227 read(fd, v, size); 228 v[size] = 0; 229 close(fd); 230 return v; 231 } 232 233 int 234 newwin(char *win) 235 { 236 char *srv, *mntsrv; 237 char spec[100]; 238 int srvfd, cons, pid; 239 240 switch(rfork(RFFDG|RFPROC|RFNAMEG|RFENVG|RFNOTEG|RFNOWAIT)){ 241 case -1: 242 fprint(2, "bargraph: can't fork: %r\n"); 243 return -1; 244 case 0: 245 break; 246 default: 247 exits(0); 248 } 249 250 srv = rdenv("/env/wsys"); 251 if(srv == 0){ 252 mntsrv = rdenv("/mnt/term/env/wsys"); 253 if(mntsrv == 0){ 254 fprint(2, "bargraph: can't find $wsys\n"); 255 return -1; 256 } 257 srv = malloc(strlen(mntsrv)+10); 258 sprint(srv, "/mnt/term%s", mntsrv); 259 free(mntsrv); 260 pid = 0; /* can't send notes to remote processes! */ 261 }else 262 pid = getpid(); 263 USED(pid); 264 srvfd = open(srv, ORDWR); 265 free(srv); 266 if(srvfd == -1){ 267 fprint(2, "bargraph: can't open %s: %r\n", srv); 268 return -1; 269 } 270 sprint(spec, "new -r %s", win); 271 if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){ 272 fprint(2, "bargraph: can't mount /mnt/wsys: %r (spec=%s)\n", spec); 273 return -1; 274 } 275 close(srvfd); 276 unmount("/mnt/acme", "/dev"); 277 bind("/mnt/wsys", "/dev", MBEFORE); 278 cons = open("/dev/cons", OREAD); 279 if(cons==-1){ 280 NoCons: 281 fprint(2, "bargraph: can't open /dev/cons: %r"); 282 return -1; 283 } 284 dup(cons, 0); 285 close(cons); 286 cons = open("/dev/cons", OWRITE); 287 if(cons==-1) 288 goto NoCons; 289 dup(cons, 1); 290 dup(cons, 2); 291 close(cons); 292 // wctlfd = open("/dev/wctl", OWRITE); 293 return 0; 294 } 295 296 Rectangle 297 screenrect(void) 298 { 299 int fd; 300 char buf[12*5]; 301 302 fd = open("/dev/screen", OREAD); 303 if(fd == -1) 304 fd=open("/mnt/term/dev/screen", OREAD); 305 if(fd == -1){ 306 fprint(2, "page: can't open /dev/screen: %r\n"); 307 exits("window read"); 308 } 309 if(read(fd, buf, sizeof buf) != sizeof buf){ 310 fprint(2, "page: can't read /dev/screen: %r\n"); 311 exits("screen read"); 312 } 313 close(fd); 314 return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48)); 315 } 316 317 int 318 postnote(int group, int pid, char *note) 319 { 320 char file[128]; 321 int f, r; 322 323 switch(group) { 324 case PNPROC: 325 sprint(file, "/proc/%d/note", pid); 326 break; 327 case PNGROUP: 328 sprint(file, "/proc/%d/notepg", pid); 329 break; 330 case PNCTL: 331 sprint(file, "/proc/%d/ctl", pid); 332 break; 333 default: 334 return -1; 335 } 336 337 f = open(file, OWRITE); 338 if(f < 0) 339 return -1; 340 341 r = strlen(note); 342 if(write(f, note, r) != r) { 343 close(f); 344 return -1; 345 } 346 close(f); 347 return 0; 348 } 349