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