1 #include <stdio.h>
2 #include <ctype.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include <plot.h>
6 #include <string.h>
7 #define INF     INFINITY
8 #define F       .25
9 
10 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__bsdi__)
11 char	*progname = NULL;
12 #define setprogname(x) progname = x
13 #define getprogname() progname
14 #endif
15 
16 struct xy {
17 	int		xlbf;	/* flag:explicit lower bound */
18 	int		xubf;	/* flag:explicit upper bound */
19 	int		xqf;	/* flag:explicit quantum */
20 	double 		(*xf) ();	/* transform function, e.g. log */
21 	float		xa, xb;	/* scaling coefficients */
22 	float		xlb, xub;	/* lower and upper bound */
23 	float		xquant;	/* quantum */
24 	float		xoff;	/* screen offset fraction */
25 	float		xsize;	/* screen fraction */
26 	int		xbot, xtop;	/* screen coords of border */
27 	float		xmult;	/* scaling constant */
28 }		xd, yd;
29 
30 struct val {
31 	float		xv;
32 	float		yv;
33 	int		lblptr;
34 }	       *xx;
35 
36 int		xx_len;
37 
38 char	       *labs_;
39 int		labsiz;
40 int		tick = 50;
41 int		top = 4000;
42 int		bot = 200;
43 float		absbot;
44 int		n;
45 int		erasf = 1;
46 int		gridf = 2;
47 int		symbf = 0;
48 int		absf = 0;
49 int		transf;
50 int		brkf;
51 float		dx;
52 char	       *plotsymb;
53 
54 #define BSIZ 256
55 char		labbuf[BSIZ];
56 char		titlebuf[BSIZ];
57 
58 char	       *modes[] = {
59 	"disconnected",
60 	"solid",
61 	"dotted",
62 	"dotdashed",
63 	"shortdashed",
64 	"longdashed"
65 };
66 int		mode = 1;
67 
68 static double
ident(double x)69 ident(double x)
70 {
71 	return (x);
72 }
73 
74 static void	axes(void);
75 static void	transpose(void);
76 static void	readin(void);
77 static void	plot(void);
78 static void	limread(register struct xy *p, int *argcp, char ***argvp);
79 static void	title(void);
80 static void	badarg(void);
81 static void	badvalue(void);
82 static void	setopt(int argc, char *argv[]);
83 static void	axlab(char c, struct xy *p);
84 static int	conv(float xv, register struct xy *p, int *ip);
85 static void	scale(register struct xy *p, struct val *v);
86 static int	setmark(int *xmark, register struct xy *p);
87 static void	submark(int *xmark, int *pxn, float x, struct xy *p);
88 static void	init(struct xy *p);
89 static int	copystring(int k);
90 static int	symbol(int ix, int iy, int k);
91 static int	getfloat(float *p);
92 static int	getstring(void);
93 static int	numb(float *np, int *argcp, register char ***argvp);
94 
95 int
main(int argc,char * argv[])96 main(int argc, char *argv[])
97 {
98 	setprogname(argv[0]);
99 
100 	init(&xd);
101 	init(&yd);
102 	xd.xsize = yd.xsize = 1.;
103 	xx_len = 250;
104 	xx = (struct val *)malloc(xx_len * sizeof(struct val));
105 	labs_ = malloc(1);
106 	labs_[labsiz++] = 0;
107 
108 	setopt(argc, argv);
109 
110 	readin();
111 	transpose();
112 
113 	pl_space(0, 0, 4096, 4096);
114 
115 	if (erasf)
116 		pl_erase();
117 
118 	scale(&xd, (struct val *)&xx->xv);
119 	scale(&yd, (struct val *)&xx->yv);
120 	axes();
121 	title();
122 	plot();
123 	pl_move(1, 1);
124 	pl_closepl();
125 
126 	free(xx);
127 	free(labs_);
128 	return (0);
129 }
130 
131 static void
init(struct xy * p)132 init(struct xy *p)
133 {
134 	p->xf = ident;
135 	p->xmult = 1;
136 }
137 
138 static void
setopt(int argc,char * argv[])139 setopt(int argc, char *argv[])
140 {
141 	char	       *p1, *p2;
142 	float		temp;
143 
144 	xd.xlb = yd.xlb = INF;
145 	xd.xub = yd.xub = -INF;
146 	while (--argc > 0) {
147 		argv++;
148 again:		switch (argv[0][0]) {
149 		case '-':
150 			argv[0]++;
151 			goto again;
152 		case 'l':	/* label for plot */
153 			p1 = titlebuf;
154 			if (argc >= 2) {
155 				argv++;
156 				argc--;
157 				p2 = argv[0];
158 				while ((*p1++ = *p2++));
159 			}
160 			break;
161 
162 		case 'd':	/* disconnected,obsolete option */
163 		case 'm':	/* line mode */
164 			mode = 0;
165 			if (!numb(&temp, &argc, &argv))
166 				break;
167 			if (temp >= sizeof(modes) / sizeof(*modes))
168 				mode = 1;
169 			else if (temp >= 0)
170 				mode = temp;
171 			break;
172 
173 		case 'a':	/* automatic abscissas */
174 			absf = 1;
175 			dx = 1;
176 			if (!numb(&dx, &argc, &argv))
177 				break;
178 			if (numb(&absbot, &argc, &argv))
179 				absf = 2;
180 			break;
181 
182 		case 's':	/* save screen, overlay plot */
183 			erasf = 0;
184 			break;
185 
186 		case 'g':	/* grid style 0 none, 1 ticks, 2 full */
187 			gridf = 0;
188 			if (!numb(&temp, &argc, &argv))
189 				temp = argv[0][1] - '0';	/* for compatibility */
190 			if (temp >= 0 && temp <= 2)
191 				gridf = temp;
192 			break;
193 
194 		case 'c':	/* character(s) for plotting */
195 			if (argc >= 2) {
196 				symbf = 1;
197 				plotsymb = argv[1];
198 				argv++;
199 				argc--;
200 			}
201 			break;
202 
203 		case 't':	/* transpose */
204 			transf = 1;
205 			break;
206 		case 'b':	/* breaks */
207 			brkf = 1;
208 			break;
209 		case 'x':	/* x limits */
210 			limread(&xd, &argc, &argv);
211 			break;
212 		case 'y':
213 			limread(&yd, &argc, &argv);
214 			break;
215 		case 'h':	/* set height of plot */
216 			if (!numb(&yd.xsize, &argc, &argv))
217 				badarg();
218 			break;
219 		case 'w':	/* set width of plot */
220 			if (!numb(&xd.xsize, &argc, &argv))
221 				badarg();
222 			break;
223 		case 'r':	/* set offset to right */
224 			if (!numb(&xd.xoff, &argc, &argv))
225 				badarg();
226 			break;
227 		case 'u':	/* set offset up the screen */
228 			if (!numb(&yd.xoff, &argc, &argv))
229 				badarg();
230 			break;
231 		default:
232 			badarg();
233 		}
234 	}
235 }
236 
237 static void
limread(register struct xy * p,int * argcp,char *** argvp)238 limread(register struct xy *p, int *argcp, char ***argvp)
239 {
240 	if (*argcp > 1 && (*argvp)[1][0] == 'l') {
241 		(*argcp)--;
242 		(*argvp)++;
243 		p->xf = log10;
244 	}
245 	if (!numb(&p->xlb, argcp, argvp))
246 		return;
247 	p->xlbf = 1;
248 	if (!numb(&p->xub, argcp, argvp))
249 		return;
250 	p->xubf = 1;
251 	if (!numb(&p->xquant, argcp, argvp))
252 		return;
253 	p->xqf = 1;
254 }
255 
256 static int
numb(float * np,int * argcp,register char *** argvp)257 numb(float *np, int *argcp, register char ***argvp)
258 {
259 	register char	c;
260 
261 	if (*argcp <= 1)
262 		return (0);
263 	while ((c = (*argvp)[1][0]) == '+')
264 		(*argvp)[1]++;
265 	if (!(isdigit(c) || (c == '-' && (*argvp)[1][1] < 'A') || c == '.'))
266 		return (0);
267 	*np = atof((*argvp)[1]);
268 	(*argcp)--;
269 	(*argvp)++;
270 	return (1);
271 }
272 
273 static void
readin(void)274 readin(void)
275 {
276 	register int	t;
277 	struct val     *temp;
278 
279 	if (absf == 1) {
280 		if (xd.xlbf)
281 			absbot = xd.xlb;
282 		else if (xd.xf == log10)
283 			absbot = 1;
284 	}
285 	for (;;) {
286 		if (n > xx_len) {
287 			xx_len *= 2;
288 			temp = (struct val *)realloc((char *)xx, xx_len * sizeof(struct val));
289 			if (temp == 0)
290 				return;
291 			xx = temp;
292 		}
293 		if (absf)
294 			xx[n].xv = n * dx + absbot;
295 		else if (!getfloat(&xx[n].xv))
296 			badvalue();
297 
298 		if (!getfloat(&xx[n].yv))
299 			badvalue();
300 
301 		xx[n].lblptr = -1;
302 		t = getstring();
303 
304 		if (t > 0)
305 			xx[n].lblptr = copystring(t);
306 
307 		n++;
308 		if (t < 0)
309 			return;
310 	}
311 }
312 
313 static void
transpose(void)314 transpose(void)
315 {
316 	register int	i;
317 	float		f;
318 	struct xy	t;
319 	if (!transf)
320 		return;
321 	t = xd;
322 	xd = yd;
323 	yd = t;
324 	for (i = 0; i < n; i++) {
325 		f = xx[i].xv;
326 		xx[i].xv = xx[i].yv;
327 		xx[i].yv = f;
328 	}
329 }
330 
331 static int
copystring(int k)332 copystring(int k)
333 {
334 	register char  *temp;
335 	register int	i;
336 	int		q;
337 
338 	temp = realloc(labs_, (unsigned)(labsiz + 1 + k));
339 	if (temp == 0)
340 		return (0);
341 	labs_ = temp;
342 	q = labsiz;
343 	for (i = 0; i <= k; i++)
344 		labs_[labsiz++] = labbuf[i];
345 	return (q);
346 }
347 
348 static float
modceil(float f,float t)349 modceil(float f, float t)
350 {
351 	t = fabs(t);
352 	return (ceil(f / t) * t);
353 }
354 
355 static float
modfloor(float f,float t)356 modfloor(float f, float t)
357 {
358 	t = fabs(t);
359 	return (floor(f / t) * t);
360 }
361 
362 static void
getlim(register struct xy * p,struct val * v)363 getlim(register struct xy *p, struct val *v)
364 {
365 	register int	i;
366 
367 	i = 0;
368 	do {
369 		if (!p->xlbf && p->xlb > v[i].xv)
370 			p->xlb = v[i].xv;
371 		if (!p->xubf && p->xub < v[i].xv)
372 			p->xub = v[i].xv;
373 		i++;
374 	} while (i < n);
375 }
376 
377 struct z {
378 	float		lb, ub, mult, quant;
379 };
380 
381 static struct z	setloglim(int lbf, int ubf, float lb, float ub);
382 static struct z	setlinlim(int lbf, int ubf, float xlb, float xub);
383 
384 static void
setlim(register struct xy * p)385 setlim(register struct xy *p)
386 {
387 	float		t, delta, sign;
388 	struct z	z;
389 	int		mark[50];
390 	float		lb, ub;
391 	int		lbf, ubf;
392 
393 	lb = p->xlb;
394 	ub = p->xub;
395 	delta = ub - lb;
396 	if (p->xqf) {
397 		if (delta * p->xquant <= 0)
398 			badarg();
399 		return;
400 	}
401 	sign = 1;
402 	lbf = p->xlbf;
403 	ubf = p->xubf;
404 	if (delta < 0) {
405 		sign = -1;
406 		t = lb;
407 		lb = ub;
408 		ub = t;
409 		t = lbf;
410 		lbf = ubf;
411 		ubf = t;
412 	} else if (delta == 0) {
413 		if (ub > 0) {
414 			ub = 2 * ub;
415 			lb = 0;
416 		} else if (lb < 0) {
417 			lb = 2 * lb;
418 			ub = 0;
419 		} else {
420 			ub = 1;
421 			lb = -1;
422 		}
423 	}
424 	if (p->xf == log10 && lb > 0 && ub > lb) {
425 		z = setloglim(lbf, ubf, lb, ub);
426 		p->xlb = z.lb;
427 		p->xub = z.ub;
428 		p->xmult *= z.mult;
429 		p->xquant = z.quant;
430 		if (setmark(mark, p) < 2) {
431 			p->xqf = lbf = ubf = 1;
432 			lb = z.lb;
433 			ub = z.ub;
434 		} else
435 			return;
436 	}
437 	z = setlinlim(lbf, ubf, lb, ub);
438 	if (sign > 0) {
439 		p->xlb = z.lb;
440 		p->xub = z.ub;
441 	} else {
442 		p->xlb = z.ub;
443 		p->xub = z.lb;
444 	}
445 	p->xmult *= z.mult;
446 	p->xquant = sign * z.quant;
447 }
448 
449 static struct z
setloglim(int lbf,int ubf,float lb,float ub)450 setloglim(int lbf, int ubf, float lb, float ub)
451 {
452 	float		r, s, t;
453 	struct z	z;
454 
455 	for (s = 1; lb * s < 1; s *= 10);
456 	lb *= s;
457 	ub *= s;
458 	for (r = 1; 10 * r <= lb; r *= 10);
459 	for (t = 1; t < ub; t *= 10);
460 	z.lb = !lbf ? r : lb;
461 	z.ub = !ubf ? t : ub;
462 	if (ub / lb < 100) {
463 		if (!lbf) {
464 			if (lb >= 5 * z.lb)
465 				z.lb *= 5;
466 			else if (lb >= 2 * z.lb)
467 				z.lb *= 2;
468 		}
469 		if (!ubf) {
470 			if (ub * 5 <= z.ub)
471 				z.ub /= 5;
472 			else if (ub * 2 <= z.ub)
473 				z.ub /= 2;
474 		}
475 	}
476 	z.mult = s;
477 	z.quant = r;
478 	return (z);
479 }
480 
481 static struct z
setlinlim(int lbf,int ubf,float xlb,float xub)482 setlinlim(int lbf, int ubf, float xlb, float xub)
483 {
484 	struct z	z;
485 	float		r, s, delta;
486 	float		ub, lb;
487 
488 loop:
489 	ub = xub;
490 	lb = xlb;
491 	delta = ub - lb;
492 	/* scale up by s, a power of 10, so range (delta) exceeds 1 */
493 	/* find power of 10 quantum, r, such that delta/10<=r<delta */
494 	r = s = 1;
495 	while (delta * s < 10)
496 		s *= 10;
497 	delta *= s;
498 	while (10 * r < delta)
499 		r *= 10;
500 	lb *= s;
501 	ub *= s;
502 	/* set r=(1,2,5)*10**n so that 3-5 quanta cover range */
503 	if (r >= delta / 2)
504 		r /= 2;
505 	else if (r < delta / 5)
506 		r *= 2;
507 	z.ub = ubf ? ub : modceil(ub, r);
508 	z.lb = lbf ? lb : modfloor(lb, r);
509 	if (!lbf && z.lb <= r && z.lb > 0) {
510 		xlb = 0;
511 		goto loop;
512 	} else if (!ubf && z.ub >= -r && z.ub < 0) {
513 		xub = 0;
514 		goto loop;
515 	}
516 	z.quant = r;
517 	z.mult = s;
518 	return (z);
519 }
520 
521 static void
scale(register struct xy * p,struct val * v)522 scale(register struct xy *p, struct val *v)
523 {
524 	float		edge;
525 
526 	getlim(p, v);
527 	setlim(p);
528 	edge = top - bot;
529 	p->xa = p->xsize * edge / ((*p->xf) (p->xub) - (*p->xf) (p->xlb));
530 	p->xbot = bot + edge * p->xoff;
531 	p->xtop = p->xbot + (top - bot) * p->xsize;
532 	p->xb = p->xbot - (*p->xf) (p->xlb) * p->xa + .5;
533 }
534 
535 static void
axes(void)536 axes(void)
537 {
538 	register int	i;
539 	int		mark[50];
540 	int		xn, yn;
541 	if (gridf == 0)
542 		return;
543 
544 	pl_line(xd.xbot, yd.xbot, xd.xtop, yd.xbot);
545 	pl_cont(xd.xtop, yd.xtop);
546 	pl_cont(xd.xbot, yd.xtop);
547 	pl_cont(xd.xbot, yd.xbot);
548 
549 	xn = setmark(mark, &xd);
550 	for (i = 0; i < xn; i++) {
551 		if (gridf == 2)
552 			pl_line(mark[i], yd.xbot, mark[i], yd.xtop);
553 		if (gridf == 1) {
554 			pl_line(mark[i], yd.xbot, mark[i], yd.xbot + tick);
555 			pl_line(mark[i], yd.xtop - tick, mark[i], yd.xtop);
556 		}
557 	}
558 	yn = setmark(mark, &yd);
559 	for (i = 0; i < yn; i++) {
560 		if (gridf == 2)
561 			pl_line(xd.xbot, mark[i], xd.xtop, mark[i]);
562 		if (gridf == 1) {
563 			pl_line(xd.xbot, mark[i], xd.xbot + tick, mark[i]);
564 			pl_line(xd.xtop - tick, mark[i], xd.xtop, mark[i]);
565 		}
566 	}
567 }
568 
569 int
setmark(int * xmark,register struct xy * p)570 setmark(int *xmark, register struct xy *p)
571 {
572 	int		xn = 0;
573 	float		x, xl, xu;
574 	float		q;
575 	if (p->xf == log10 && !p->xqf) {
576 		for (x = p->xquant; x < p->xub; x *= 10) {
577 			submark(xmark, &xn, x, p);
578 			if (p->xub / p->xlb <= 100) {
579 				submark(xmark, &xn, 2 * x, p);
580 				submark(xmark, &xn, 5 * x, p);
581 			}
582 		}
583 	} else {
584 		xn = 0;
585 		q = p->xquant;
586 		if (q > 0) {
587 			xl = modceil(p->xlb + q / 6, q);
588 			xu = modfloor(p->xub - q / 6, q) + q / 2;
589 		} else {
590 			xl = modceil(p->xub - q / 6, q);
591 			xu = modfloor(p->xlb + q / 6, q) - q / 2;
592 		}
593 		for (x = xl; x <= xu; x += fabs(p->xquant))
594 			xmark[xn++] = (*p->xf) (x) * p->xa + p->xb;
595 	}
596 	return (xn);
597 }
598 
599 static void
submark(int * xmark,int * pxn,float x,struct xy * p)600 submark(int *xmark, int *pxn, float x, struct xy *p)
601 {
602 	if (1.001 * p->xlb < x && .999 * p->xub > x)
603 		xmark[(*pxn)++] = log10(x) * p->xa + p->xb;
604 }
605 
606 static void
plot(void)607 plot(void)
608 {
609 	int		ix, iy;
610 	int		i;
611 	int		conn;
612 
613 	conn = 0;
614 	if (mode != 0)
615 		pl_linemod(modes[mode]);
616 	for (i = 0; i < n; i++) {
617 		if (!conv(xx[i].xv, &xd, &ix) ||
618 		    !conv(xx[i].yv, &yd, &iy)) {
619 			conn = 0;
620 			continue;
621 		}
622 		if (mode != 0) {
623 			if (conn != 0)
624 				pl_cont(ix, iy);
625 			else
626 				pl_move(ix, iy);
627 			conn = 1;
628 		}
629 		conn &= symbol(ix, iy, xx[i].lblptr);
630 	}
631 	pl_linemod(modes[1]);
632 }
633 
634 static int
conv(float xv,register struct xy * p,int * ip)635 conv(float xv, register struct xy *p, int *ip)
636 {
637 	long		ix;
638 	ix = p->xa * (*p->xf) (xv * p->xmult) + p->xb;
639 	if (ix < p->xbot || ix > p->xtop)
640 		return (0);
641 	*ip = ix;
642 	return (1);
643 }
644 
645 static int
getfloat(float * p)646 getfloat(float *p)
647 {
648 	register int	i;
649 
650 	i = scanf("%f", p);
651 	return (i == 1);
652 }
653 
654 static int
getstring(void)655 getstring(void)
656 {
657 	register int	i;
658 	char		junk[20];
659 	i = scanf("%1s", labbuf);
660 	if (i == -1)
661 		return (-1);
662 	switch (*labbuf) {
663 	default:
664 		if (!isdigit(*labbuf)) {
665 			ungetc(*labbuf, stdin);
666 			i = scanf("%s", labbuf);
667 			break;
668 		}
669 	case '.':
670 	case '+':
671 	case '-':
672 		ungetc(*labbuf, stdin);
673 		return (0);
674 	case '"':
675 		i = scanf("%[^\"\n]", labbuf);
676 #ifdef __GNUC__
677 #endif
678 		scanf("%[\"]", junk);
679 #ifdef __GNUC__
680 #endif
681 		break;
682 	}
683 	if (i == -1)
684 		return (-1);
685 	return (strlen(labbuf));
686 }
687 
688 static int
symbol(int ix,int iy,int k)689 symbol(int ix, int iy, int k)
690 {
691 	if (symbf == 0 && k < 0) {
692 		if (mode == 0)
693 			pl_point(ix, iy);
694 		return (1);
695 	} else {
696 		pl_move(ix, iy);
697 		pl_label(k >= 0 ? labs_ + k : plotsymb);
698 		pl_move(ix, iy);
699 		return (!brkf | (k < 0));
700 	}
701 }
702 
703 static void
title(void)704 title(void)
705 {
706 	pl_move(xd.xbot, yd.xbot - 60);
707 	if (titlebuf[0]) {
708 		pl_label(titlebuf);
709 		pl_label("       ");
710 	}
711 	if (gridf) {
712 		axlab('x', &xd);
713 		pl_label("  ");
714 		axlab('y', &yd);
715 	}
716 }
717 
718 static void
axlab(char c,struct xy * p)719 axlab(char c, struct xy *p)
720 {
721 	char		buf[50];
722 	sprintf(buf, "%g -%s%c- %g", p->xlb / p->xmult,
723 		p->xf == log10 ? "log " : "", c, p->xub / p->xmult);
724 	pl_label(buf);
725 }
726 
727 static void
badarg(void)728 badarg(void)
729 {
730 	fprintf(stderr, "%s: error in arguments\n", getprogname());
731 	exit(1);
732 }
733 
734 static void
badvalue(void)735 badvalue(void)
736 {
737 	fprintf(stderr, "%s: malformed input\n", getprogname());
738 	exit(1);
739 }
740