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