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