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
initcolor(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 = -1;
34 int first = 1;
35
36 char backup[80];
37
38 void
drawbar(void)39 drawbar(void)
40 {
41 int i, j;
42 int p;
43 char buf[200], bar[100];
44 static char lastbar[100];
45
46 if(n > d || n < 0 || d <= 0)
47 return;
48
49 i = (Dx(rbar)*n)/d;
50 p = (n*100LL)/d;
51
52 if(textmode){
53 bar[0] = '|';
54 for(j=0; j<i; j++)
55 bar[j+1] = '#';
56 for(; j<60; j++)
57 bar[j+1] = '-';
58 bar[61] = '|';
59 bar[62] = ' ';
60 sprint(bar+63, "%3d%% ", p);
61 for(i=0; bar[i]==lastbar[i] && bar[i]; i++)
62 ;
63 memset(buf, '\b', strlen(lastbar)-i);
64 strcpy(buf+strlen(lastbar)-i, bar+i);
65 if(buf[0])
66 write(1, buf, strlen(buf));
67 strcpy(lastbar, bar);
68 return;
69 }
70
71 if(lastp == p && last == i)
72 return;
73
74 if(lastp != p){
75 sprint(buf, "%d%%", p);
76
77 stringbg(screen, addpt(screen->r.min, Pt(Dx(rbar)-30, 4)), text, ZP, display->defaultfont, buf, light, ZP);
78 lastp = p;
79 }
80
81 if(last != i){
82 draw(screen, Rect(rbar.min.x+last, rbar.min.y, rbar.min.x+i, rbar.max.y),
83 dark, nil, ZP);
84 last = i;
85 }
86 flushimage(display, 1);
87 }
88
89 void
eresized(int new)90 eresized(int new)
91 {
92 Point p, q;
93 Rectangle r;
94
95 if(new && getwindow(display, Refnone) < 0)
96 fprint(2,"can't reattach to window");
97
98 r = screen->r;
99 draw(screen, r, light, nil, ZP);
100 p = string(screen, addpt(r.min, Pt(4,4)), text, ZP,
101 display->defaultfont, title);
102
103 p.x = r.min.x+4;
104 p.y += display->defaultfont->height+4;
105
106 q = subpt(r.max, Pt(4,4));
107 rbar = Rpt(p, q);
108
109 ptext = Pt(r.max.x-4-stringwidth(display->defaultfont, "100%"), r.min.x+4);
110 border(screen, rbar, -2, dark, ZP);
111 last = 0;
112 lastp = -1;
113
114 drawbar();
115 }
116
117 void
bar(Biobuf * b)118 bar(Biobuf *b)
119 {
120 char *p, *f[2];
121 Event e;
122 int k, die, parent, child;
123
124 parent = getpid();
125
126 die = 0;
127 if(textmode)
128 child = -1;
129 else
130 switch(child = rfork(RFMEM|RFPROC)) {
131 case 0:
132 sleep(1000);
133 while(!die && (k = eread(Ekeyboard|Emouse, &e))) {
134 if(nokill==0 && k == Ekeyboard && (e.kbdc == 0x7F || e.kbdc == 0x03)) { /* del, ctl-c */
135 die = 1;
136 postnote(PNPROC, parent, "interrupt");
137 _exits("interrupt");
138 }
139 }
140 _exits(0);
141 }
142
143 while(!die && (p = Brdline(b, '\n'))) {
144 p[Blinelen(b)-1] = '\0';
145 if(tokenize(p, f, 2) != 2)
146 continue;
147 n = strtoll(f[0], 0, 0);
148 d = strtoll(f[1], 0, 0);
149 drawbar();
150 }
151 postnote(PNCTL, child, "kill");
152 }
153
154
155 void
usage(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
main(int argc,char ** argv)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*
rdenv(char * name)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, "%s: can't malloc: %r\n", argv0);
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
newwin(char * win)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 USED(pid);
262 srvfd = open(srv, ORDWR);
263 free(srv);
264 if(srvfd == -1){
265 fprint(2, "bargraph: can't open %s: %r\n", srv);
266 return -1;
267 }
268 sprint(spec, "new -r %s", win);
269 if(mount(srvfd, -1, "/mnt/wsys", 0, spec) == -1){
270 fprint(2, "bargraph: can't mount /mnt/wsys: %r (spec=%s)\n", spec);
271 return -1;
272 }
273 close(srvfd);
274 unmount("/mnt/acme", "/dev");
275 bind("/mnt/wsys", "/dev", MBEFORE);
276 cons = open("/dev/cons", OREAD);
277 if(cons==-1){
278 NoCons:
279 fprint(2, "bargraph: can't open /dev/cons: %r");
280 return -1;
281 }
282 dup(cons, 0);
283 close(cons);
284 cons = open("/dev/cons", OWRITE);
285 if(cons==-1)
286 goto NoCons;
287 dup(cons, 1);
288 dup(cons, 2);
289 close(cons);
290 // wctlfd = open("/dev/wctl", OWRITE);
291 return 0;
292 }
293
294 Rectangle
screenrect(void)295 screenrect(void)
296 {
297 int fd;
298 char buf[12*5];
299
300 fd = open("/dev/screen", OREAD);
301 if(fd == -1)
302 fd=open("/mnt/term/dev/screen", OREAD);
303 if(fd == -1){
304 fprint(2, "%s: can't open /dev/screen: %r\n", argv0);
305 exits("window read");
306 }
307 if(read(fd, buf, sizeof buf) != sizeof buf){
308 fprint(2, "%s: can't read /dev/screen: %r\n", argv0);
309 exits("screen read");
310 }
311 close(fd);
312 return Rect(atoi(buf+12), atoi(buf+24), atoi(buf+36), atoi(buf+48));
313 }
314
315 int
postnote(int group,int pid,char * note)316 postnote(int group, int pid, char *note)
317 {
318 char file[128];
319 int f, r;
320
321 switch(group) {
322 case PNPROC:
323 sprint(file, "/proc/%d/note", pid);
324 break;
325 case PNGROUP:
326 sprint(file, "/proc/%d/notepg", pid);
327 break;
328 case PNCTL:
329 sprint(file, "/proc/%d/ctl", pid);
330 break;
331 default:
332 return -1;
333 }
334
335 f = open(file, OWRITE);
336 if(f < 0)
337 return -1;
338
339 r = strlen(note);
340 if(write(f, note, r) != r) {
341 close(f);
342 return -1;
343 }
344 close(f);
345 return 0;
346 }
347