home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / psgraph / part01 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-06  |  15.1 KB  |  663 lines

  1. /* $Header: main.c,v 1.9 92/08/04 17:55:08 mogul Exp $ */
  2. /*
  3.  *               Copyright 1989, 1992 Digital Equipment Corporation
  4.  *                          All Rights Reserved
  5.  * 
  6.  * 
  7.  * Permission to use, copy, and modify this software and its documentation
  8.  * is hereby granted only under the following terms and conditions.  Both
  9.  * the above copyright notice and this permission notice must appear in
  10.  * all copies of the software, derivative works or modified versions, and
  11.  * any portions threof, and both notices must appear in supporting
  12.  * documentation.
  13.  * 
  14.  * Users of this software agree to the terms and conditions set forth
  15.  * herein, and hereby grant back to Digital a non-exclusive, unrestricted,
  16.  * royalty-free right and license under any changes, enhancements or
  17.  * extensions made to the core functions of the software, including but
  18.  * not limited to those affording compatibility with other hardware or
  19.  * software environments, but excluding applications which incorporate
  20.  * this software.  Users further agree to use their best efforts to return
  21.  * to Digital any such changes, enhancements or extensions that they make
  22.  * and inform Digital of noteworthy uses of this software.  Correspondence
  23.  * should be provided to Digital at:
  24.  * 
  25.  *                       Director of Licensing
  26.  *                       Western Research Laboratory
  27.  *                       Digital Equipment Corporation
  28.  *                       250 University Avenue
  29.  *                       Palo Alto, California  94301  
  30.  * 
  31.  * This software may be distributed (but not offered for sale or
  32.  * transferred for compensation) to third parties, provided such third
  33.  * parties agree to abide by the terms and conditions of this notice.
  34.  * 
  35.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS
  36.  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  37.  * WARRANTIES OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL
  38.  * EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
  39.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  40.  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  41.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  42.  * PERFORMANCE OF THIS SOFTWARE.
  43.  */
  44.  
  45. /* 
  46.  * main.c - produce PostScript graphs
  47.  * 
  48.  * Author:    Christopher A. Kent
  49.  *         Western Research Laboratory
  50.  *         Digital Equipment Corporation
  51.  * Date:    Wed Jan  4 1989
  52.  */
  53.  
  54. /*
  55.  * $Log:    main.c,v $
  56.  * Revision 1.9  92/08/04  17:55:08  mogul
  57.  * undo RCS botch
  58.  * 
  59.  * Revision 1.8  1992/06/17  22:14:41  kent
  60.  * Make axis specs with max < min work, fix some bugs with centering
  61.  * and multiple args.
  62.  *
  63.  * Revision 1.7  1992/04/03  23:55:47  kent
  64.  * Fixed a problem where "include" reset the world.
  65.  *
  66.  * Revision 1.6  1992/04/01  23:27:34  kent
  67.  * Added datalabel verb, fixed a bug in handling blank input lines.
  68.  *
  69.  * Revision 1.5  1992/04/01  00:38:24  kent
  70.  * Fixed a problem with half grids specified with -g.
  71.  *
  72.  * Revision 1.4  1992/03/31  02:31:34  kent
  73.  * Added markergray verb and fixed inverted gray values.
  74.  *
  75.  * Revision 1.3  1992/03/31  00:21:29  kent
  76.  * Added "include" verb
  77.  *
  78.  * Revision 1.2  1992/03/30  23:33:47  kent
  79.  * Added halfopen, halfticks grid styles, range frames, and gray.
  80.  *
  81.  * Revision 1.1  1992/03/20  21:25:43  kent
  82.  * Initial revision
  83.  *
  84.  * Revision 1.12  92/02/21  17:13:22  mogul
  85.  * Added Digital license info
  86.  * 
  87.  * Revision 1.11  91/12/19  16:00:52  mogul
  88.  * Avoid an infinite loop if the graph is a horizontal or vertical
  89.  * line.
  90.  * 
  91.  * Revision 1.10  91/02/04  16:48:01  mogul
  92.  * Fixed text, marker colors
  93.  * 
  94.  * Revision 1.9  90/12/11  20:39:42  reid
  95.  * Added default values for LineColor and LineWidth
  96.  * 
  97.  * Revision 1.8  89/02/03  09:33:06  kent
  98.  * Use floor in calculating log limits.
  99.  * 
  100.  * Revision 1.7  89/01/10  18:19:59  kent
  101.  * Moved marker code to prolog, added error checking and messages.
  102.  * 
  103.  * Revision 1.6  89/01/09  22:18:43  kent
  104.  * Added log scales.
  105.  * 
  106.  * Revision 1.5  89/01/04  18:12:19  kent
  107.  * Added -p flag to specify alternate prologue file.
  108.  * 
  109.  * Revision 1.4  89/01/04  17:57:36  kent
  110.  * Moved font stuff from main.c to output.c.
  111.  * newfont() sets PS fontsize variable so white background is the right size.
  112.  * 
  113.  * Revision 1.3  89/01/04  17:30:29  kent
  114.  * Made command line arguments override compiled-in defaults for
  115.  * all plots in a run, not just the first one. 
  116.  * 
  117.  * Revision 1.2  89/01/04  15:22:05  kent
  118.  * Massive renaming. No functional change.
  119.  * 
  120.  * Revision 1.1  89/01/04  13:57:54  kent
  121.  * Initial revision
  122.  * 
  123.  */
  124.  
  125. static char rcs_ident[] = "$Header: main.c,v 1.9 92/08/04 17:55:08 mogul Exp $";
  126.  
  127. /*
  128.  * This program has a long history. It started out as a program to take
  129.  * graph(1) input and produce pic/troff output. That was done by Bob Brown. In
  130.  * the process, he added to the input language to make it a lot more useful.
  131.  * Chris Kent then took it and made it produce PostScript. As it got more use,
  132.  * Chris' users didn't care about troff, so that code all went away, but they
  133.  * wanted even more features.
  134.  *
  135.  * This incarnation was started when Chris was asked to add "one more feature"
  136.  * and the single-file version just got to be too much to handle. Now it's
  137.  * broken into several files, and the effects of time and feeping creaturism
  138.  * have been cleaned up. But it almost certainly retains some code from some of
  139.  * these versions:
  140.  *
  141.  *  Bob Brown/RIACS/NASA Ames
  142.  *  Mostly untested. 3/86
  143.  *  Converted to emit PostScript instead of Pic
  144.  *        Chris Kent, DECWRL, 5/87
  145.  *  More PostScript cleanup -- cak 11/87
  146.  *  A few new options, made it use a private dictionary, attacked some
  147.  *    roundoff problems -- cak 2/88
  148.  *
  149.  */
  150.  
  151. #include <stdio.h>
  152. #include <pwd.h>
  153. #include <sys/file.h>
  154.  
  155. #include "psgraph.h"
  156.  
  157. main(argc,argv)
  158. char *argv[];
  159. {
  160.     int    i;
  161.     long    clock;
  162.     char    hostname[256];
  163.     struct passwd    *pwd;
  164.     fontName_t    *fp;
  165.     
  166.     MinX = MinY = MaxX = MaxY = 0.0;
  167.     Token = (token_t *) calloc(TOKENINC, sizeof(token_t));
  168.     SizeofToken = TOKENINC;
  169.     procargs(argc,argv);
  170.  
  171.     FontList = (fontName_t *) malloc(sizeof (fontName_t));
  172.     FontList->name = newstr("Times-Roman");
  173.     FontList->next = (fontName_t *) NULL;
  174.  
  175.     /* put out comment header */
  176.     printf("%%!PS-Adobe-1.0\n");
  177.     pwd = getpwuid(getuid());
  178.     gethostname(hostname, sizeof hostname);
  179.     printf("%%%%Creator: %s:%s (%s)\n",hostname,
  180.         pwd->pw_name, pwd->pw_gecos);
  181.     printf("%%%%Title: PostScript graph file\n");
  182.     printf("%%%%CreationDate: %s",(time(&clock), ctime(&clock)));
  183.     printf("%%%%DocumentFonts: (atend)\n");
  184.     printf("%%%%Pages: (atend)\n");
  185.     printf("%%%%BoundingBox: (atend)\n");
  186.     printf("%%%%EndComments\n");
  187.     
  188.     /* interpolate prolog and fixed header routines */
  189.     
  190.     if (copyFile(Prolog, stdout) < 0) {
  191.         perror(Prolog);
  192.         exit(1);
  193.     }
  194.     printf("%%%%EndProlog\n");
  195.     
  196.     if ( Files==0 ) {
  197.         process();
  198.     } else {
  199.         for ( i=0 ; i<Files ; i++ ) {
  200.             if ( freopen(File[i],"r", stdin)==NULL )
  201.                 perror(File[i]);
  202.             else
  203.                 process();
  204.         }
  205.     }
  206.     printf("%%%%Trailer\n");
  207.     printf("EndPSGraph\n");
  208.     printf("%%%%DocumentFonts: %s", FontList->name);
  209.     for (fp = FontList->next; fp; fp = fp->next)
  210.         printf(", %s", fp->name);
  211.     printf("\n");
  212.     printf("%%%%Pages: %d\n", CurrentPage);
  213.     printf("%%%%BoundingBox: %d %d %d %d\n",
  214.         (int) (MinX * 72), (int) (MinY * 72),
  215.         (int) (MaxX * 72), (int) (MaxY * 72));
  216.     exit(0);
  217. }
  218.  
  219. copyFile(fileName, stream)
  220. char    *fileName;
  221. FILE    *stream;
  222. {
  223.     int    fd, fo;
  224.     char    buf[BUFSIZ];
  225.     int    cnt;
  226.  
  227.     fflush(stream);
  228.     fo = fileno(stream);
  229.     if ((fd = open(fileName, O_RDONLY, 0)) < 0) 
  230.         return -1;
  231.     do if (cnt = read(fd, buf, sizeof(buf)))
  232.         if (write(fo, buf, cnt) != cnt) return -2;
  233.     while (cnt == sizeof(buf));
  234.     close(fd);
  235.     fflush(stream);
  236.     return 0;
  237. }
  238.  
  239. process()
  240. {
  241.     /* reset everything */
  242.     init(&Xaxis);
  243.     init(&Yaxis);
  244.  
  245.     /* copy command line defaults into place... */
  246.     BreakAfterLabel = Args.breakAfterLabel;
  247.     Xcenter = Args.center;
  248.     Xaxis.size = Width;
  249.     Yaxis.size = Height;
  250.     Xaxis.offset = Xoffset;
  251.     Yaxis.offset = Yoffset;
  252.     copyLimit(&Xaxis, &Xlim);
  253.     copyLimit(&Yaxis, &Ylim);
  254.  
  255.     /* reset state */
  256.     DoAxisLabels = TRUE;
  257.     TransparentLabels = FALSE;
  258.     UseSpline = FALSE;
  259.     NumTokens = 0;
  260.     ClipDist = 0.05;
  261.     LineType = "solid";
  262.     LineColor = "black";
  263.     LineWidth = "0.6";
  264.     TickLen = 0.1;
  265.     Tick2Len = 0.05;
  266.     UseMarker = NULL;
  267.     TextColor = "black";
  268.     MarkColor = "black";
  269.     NumTokens = 0;
  270.     doinput(stdin);
  271.     if ( numpnts() > 0 ) {
  272.         transpose();
  273.         dolimits(0);
  274.         dolimits(1);
  275.         doplot();
  276.     }
  277. }
  278.  
  279. init(p)
  280. axis_t *p;
  281. {
  282.     p->tickflag = FALSE;
  283.     p->label = NULL;
  284.     p->gridtype = GridType;
  285.     p->tickgray = 0.0;
  286.     p->axisgray = 0.0;
  287.     p->datatick = FALSE;
  288.     p->datalabel = FALSE;
  289.     p->halfgrid = HalfGrid;
  290.     p->rangeframe = FALSE;
  291.     p->intervals = 0;
  292. }
  293.  
  294. initLimit(l)
  295. limit_t    *l;
  296. {
  297.     l->minflag = FALSE;
  298.     l->maxflag = FALSE;
  299.     l->distf = FALSE;
  300.     l->tform = IDENT;
  301. }
  302.  
  303. copyLimit(a, l)
  304. axis_t    *a;
  305. limit_t    *l;
  306. {
  307.     a->tform   = l->tform;
  308.     a->minflag = l->minflag;
  309.     a->maxflag = l->maxflag;
  310.     a->distf   = l->distf;
  311.     a->min     = l->min;
  312.     a->max     = l->max;
  313.     a->dist    = l->dist;
  314. }
  315.  
  316. procargs(argc, argv)
  317. int argc;
  318. char *argv[];
  319. {
  320.     int arg, more;
  321.     char *swptr;
  322.  
  323.     Files = 0;
  324.     File = (char **)calloc(argc, sizeof (char *));
  325.     Args.breakAfterLabel = FALSE;
  326.     Args.center = 0.0;
  327.     GridType = FULL;
  328.     HalfGrid = FALSE;
  329.     Height = 6.5;
  330.     Width = 6.5;
  331.     Prolog = PROLOG;
  332.     Title.title = NULL;
  333.     Title.font = NULL;
  334.     Xoffset = 0.0;
  335.     Yoffset = 0.0;
  336.     TransposeAxes = FALSE;
  337.  
  338.     for ( arg=1 ; arg<argc ; arg++ ) {
  339.         if ( argv[arg][0] == '-' ) {
  340.             more = 1;
  341.             swptr = &argv[arg][1];
  342.             while ( more && *swptr!='\0' ) {
  343.                 switch ( *swptr++ ) {
  344.                 case 'b':    /*breaks*/
  345.                     Args.breakAfterLabel = TRUE;
  346.                     break;
  347.                 case 'c':
  348.                     if (isfloat(argv[arg+1]))
  349.                         Args.center = 
  350.                             atof(argv[++arg]);
  351.                     else
  352.                         usagexit(argv[0]);
  353.                     break;
  354.                 case 'g':
  355.                     if ( arg+1 >= argc )
  356.                         usagexit(argv[0]);
  357.                     GridType = gridval(argv[++arg]);
  358.                     if (GridType == HALFOPEN) {
  359.                         GridType = OPEN;
  360.                         HalfGrid = TRUE;
  361.                     }
  362.                     if (GridType == HALFTICKS) {
  363.                         GridType = TICKS;
  364.                         HalfGrid = TRUE;
  365.                     }
  366.                     break;
  367.                 case 'h':
  368.                     if ( isfloat(argv[arg+1]) )
  369.                         Height = atof(argv[++arg]);
  370.                     else
  371.                         usagexit(argv[0]);
  372.                     break;
  373.                 case 'l':
  374.                     Title.title = newstr(argv[++arg]);
  375.                     break;
  376.                 case 'p':
  377.                     if (arg+1 >= argc)
  378.                         usagexit(argv[0]);
  379.                     Prolog = argv[++arg];
  380.                     break;
  381.                 case 'P':
  382.                     Preview = TRUE;
  383.                     break;
  384.                 case 'r':
  385.                     if ( isfloat(argv[arg+1]) )
  386.                         Xoffset = atof(argv[++arg]);
  387.                     else
  388.                         usagexit(argv[0]);
  389.                     break;
  390.                 case 't':
  391.                     TransposeAxes = TRUE;
  392.                     break;
  393.                 case 'u':
  394.                     if ( isfloat(argv[arg+1]) )
  395.                         Yoffset = atof(argv[++arg]);
  396.                     else
  397.                         usagexit(argv[0]);
  398.                     break;
  399.                 case 'w':
  400.                     if ( isfloat(argv[arg+1]) )
  401.                         Width = atof(argv[++arg]);
  402.                     else
  403.                         usagexit(argv[0]);
  404.                     break;
  405.                 case 'x':
  406.                     arg = limargs(&Xlim,argc,argv,arg+1)-1;
  407.                     break;
  408.                 case 'y':
  409.                     arg = limargs(&Ylim,argc,argv,arg+1)-1;
  410.                     break;
  411.                 default:
  412.                     usagexit(argv[0]);
  413.                 }
  414.             }
  415.         } else { /* there's no dash in front */
  416.             File[Files++] = argv[arg];
  417.         }
  418.     }
  419. }
  420. usagexit(pgm)
  421. char *pgm;
  422. {
  423.     fprintf(stderr,"usage: %s \n",pgm);
  424.     exit(1);
  425. }
  426.  
  427. /*
  428.  * numpnts - returns the number of actual data points
  429.  */
  430.  
  431. numpnts()
  432. {
  433.     int i, cnt;
  434.     cnt = 0;
  435.     for ( i=0 ; i<NumTokens ; i++ )
  436.         if ( Token[i].type == POINT )
  437.             cnt++;
  438.     return cnt;
  439. }
  440.  
  441. transpose()
  442. {
  443.     register int    i;
  444.     float        f;
  445.     axis_t        t;
  446.  
  447.     if(!TransposeAxes)
  448.         return;
  449.     t = Xaxis; 
  450.     Xaxis = Yaxis; 
  451.     Yaxis = t;
  452.     for(i= 0; i < NumTokens; i++) {
  453.         if ( Token[i].type != POINT ) continue;
  454.         f = Token[i].xval; 
  455.         Token[i].xval = Token[i].yval; 
  456.         Token[i].yval = f;
  457.     }
  458. }
  459.  
  460. char *newstr(s)
  461. char *s;
  462. {
  463.     char *t;
  464.     t = (char *)malloc((unsigned)(strlen(s)+1));
  465.     strcpy(t,s);
  466.     return t;
  467. }
  468.  
  469. /*
  470.  * isfloat - returns TRUE if the argument is a floating point number
  471.  */
  472.  
  473. isfloat(cp)
  474. char *cp;
  475. {
  476.     while ( *cp && isspace(*cp) )
  477.         cp++;
  478.     if ( *cp == '-' )
  479.         cp++;
  480.     if ( isdigit(*cp) || *cp=='.' )
  481.         return TRUE;
  482.     return FALSE;
  483. }
  484.  
  485. /*
  486.  * dolimits - compute the minimum and maximum of the data points.
  487.  *          compute the minimum and maximum to plot on the grid.
  488.  */
  489.  
  490. dolimits(v)
  491. {
  492.  
  493.     if (AxisArgs[v].tform == IDENT)
  494.         doLinearLimits(v);
  495.     else
  496.         doLogLimits(v);
  497. }
  498.  
  499. doLinearLimits(v)
  500. register int    v;
  501. {
  502.     register axis_t *argp;
  503.     register int i;
  504.     float min, max;
  505.  
  506.     argp = &AxisArgs[v];
  507.     argp->min = HUGE;
  508.     for ( i=0; i<NumTokens ; i++ )
  509.         if ( Token[i].type == POINT )
  510.         argp->min = MIN(argp->min, Token[i].val[v]);
  511.  
  512.     argp->max = -HUGE;
  513.     for ( i=0; i<NumTokens ; i++ )
  514.         if ( Token[i].type == POINT )
  515.         argp->max = MAX(argp->max, Token[i].val[v]);
  516.  
  517.     if (argp->minflag)
  518.         min = argp->gmin;
  519.     else
  520.         min = argp->min;
  521.     if (argp->maxflag)
  522.         max = argp->gmax;
  523.     else
  524.         max = argp->max;
  525.  
  526.     scale1(min, max, 5,
  527.         &argp->pmin, &argp->pmax, &argp->distp);
  528.     if ( !argp->minflag )
  529.         argp->gmin = argp->pmin;
  530.     if ( !argp->maxflag )
  531.         argp->gmax = argp->pmax;
  532.     if ( argp->distf )
  533.         argp->distg = argp->dist;
  534.     else
  535.         argp->distg = argp->distp;
  536.  
  537.     /* avoid infinite loops */
  538.     if (argp->gmax == argp->gmin) {
  539.         if (argp->gmin > 0.0)
  540.         argp->gmin = 0.0;
  541.         else
  542.         argp->gmax += 1.0;
  543.     }
  544. }
  545.  
  546. doLogLimits(v)
  547. register int    v;
  548. {
  549.     register axis_t *argp;
  550.     register int i;
  551.  
  552.     argp = &AxisArgs[v];
  553.  
  554.     argp->min = HUGE;
  555.     for ( i=0; i<NumTokens ; i++ )
  556.         if ( Token[i].type == POINT ) {
  557.         if (Token[i].val[v] <= 0.0) {
  558.             fprintf(stderr, 
  559.                 "Bad log point (%g, %g)\n", 
  560.                 Token[i].val[0], 
  561.                 Token[i].val[1]);
  562.             Token[i].type = IGNORE;
  563.             continue;
  564.         }
  565.         argp->min = MIN(argp->min, Token[i].val[v]);
  566.         }
  567.     if (argp->min <= 0.0) {
  568.         fprintf(stderr, "Illegal log minimum %g\n", argp->min);
  569.         exit(-1);
  570.     }
  571.     argp->max = -HUGE;
  572.     for ( i=0; i<NumTokens ; i++ )
  573.         if ( Token[i].type == POINT )
  574.         argp->max = MAX(argp->max, Token[i].val[v]);
  575.  
  576.     argp->pmin = ipow(10.0, (int)floor(log10(argp->min)));
  577.     argp->pmax = ipow(10.0, (int)floor(log10(argp->max)) + 1);
  578.     argp->distp = copysign(2.0, (argp->gmax - argp->gmin)) ;
  579.     
  580. /*    scale3(argp->min, argp->max, argp->intervals,
  581.         &argp->pmin, &argp->pmax, &argp->distp);
  582. */
  583.     if ( !argp->minflag )
  584.         argp->gmin = argp->pmin;
  585.     if ( !argp->maxflag )
  586.         argp->gmax = argp->pmax;
  587.     if ( argp->distf )
  588.         argp->distg = argp->dist;
  589.     else
  590.         argp->distg = argp->distp;
  591.     argp->lgmin = log10(argp->gmin);
  592.     argp->lgmax = log10(argp->gmax);
  593. }
  594.  
  595. /*
  596.  *----------------------------------------------------------------------
  597.  *
  598.  * TEXT PARSING ROUTINES
  599.  *
  600.  * parse - break a string into substrings
  601.  */
  602.  
  603. parse(line, argc, argv)
  604. char *line;
  605. int *argc;
  606. char *argv[];
  607. {
  608.     char *ptr, *nextarg();
  609.  
  610.     ptr = line;
  611.     *argc = 0;
  612.     while ((ptr=nextarg(ptr,&argv[*argc])) != NULL )
  613.         (*argc)++;
  614.     argv[*argc] = NULL;
  615. }
  616. char *
  617. nextarg(line, start)
  618. register char *line, **start;
  619. {
  620.     bool esc;
  621.     register char *out;
  622.     char delim;
  623.     while ( isspace(*line) && *line != EOS )
  624.         line++;
  625.     if ( *line == EOS )
  626.         return NULL;
  627.     *start = line;
  628.     if ( *line=='\'' || *line=='"' ) {
  629.         delim = *line;
  630.         out = ++line;
  631.         (*start)++;
  632.         esc = FALSE;
  633.         while(TRUE) {
  634.             if ( *line == '\\' ) {
  635.                 if ( esc ) {
  636.                     out--;
  637.                     esc = FALSE;
  638.                 } else
  639.                     esc = TRUE;
  640.             } else if ( *line == delim ) {
  641.                 if ( esc ) {
  642.                     out--;
  643.                     esc = FALSE;
  644.                 } else
  645.                     break;
  646.             } else if ( *line == EOS ) {
  647.                 line--;
  648.                 break;
  649.             } else
  650.                 esc = FALSE;
  651.             *out++ = *line++;
  652.         }
  653.         *out = EOS;
  654.         return (++line);
  655.     } else {
  656.         while ( !isspace(*line) && *line != EOS )
  657.             line++;
  658.         if ( *line != EOS )
  659.             *line++ = EOS;
  660.         return line;
  661.     }
  662. }
  663.