xref: /plan9/sys/lib/dist/cmd/bargraph.c (revision ff8c3af2f44d95267f67219afa20ba82ff6cf7e4)
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