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