#ifndef sun
main()
{
	printf ("You need a SUN to run this program\n");
}
#else

#include <math.h>
#include <stdio.h>

#define ARGUMENT(s) (!strcmp(argv[0],s))
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#define FABS(f) (((f)<0)?-(f):(f))

extern char *index();

#include <pixrect/pixrect_hs.h>
#undef PIXFONT /* argh!  what is going on here?! */

#define GRIDGRAY 4 /* one pixel in 4 set */

char *malloc();
#define NEW(type) ((type *) malloc(sizeof(type)))

int argcnt;
char **argvec;

typedef struct pixrect PIXRECT;
typedef struct pixfont PIXFONT;

char screendefault[256] = "/dev/fb";
char fontdefault[256] = "/usr/lib/fonts/fixedwidthfonts/screen.r.11";

char *screenpath = &screendefault[0];
char *fontpath = &fontdefault[0];

int blackonwhite = 0;

PIXRECT *screen;
PIXFONT *font;
int winx = 832;
int winy = 0;
int winw = 768;
int winh = 640;
int grid = 0;
PIXRECT *gridcell;
int graphx;
int graphy;
int graphw;
int graphh;
int axisx;
int axisy;
double xmin;
double xmax;
double ymin;
double ymax;
double xaxis_min;
double xaxis_max;
double xdelta;
double yaxis_min;
double yaxis_max;
double ydelta;
double xlim_min;
double xlim_max;
int gavexlim = 0;
double ylim_min;
double ylim_max;
int gaveylim = 0;
double xscale;
double yscale;
typedef struct point_ {
	  struct point_ *link;
	  double x;
	  double y;
	  } POINT;
POINT *points;
int npoints;
POINT **lastpointp;
int aspect_fixed = 0;
double aspect_ratio;
int fieldWidth;
unsigned long int fieldMask;
int xfield = -1;
int yfield = -1;
int startMark = 1;
int stopMark = -1;
int implicitX;

double atof();
int atoi();

FILE *inputf;

int nint(d)
double d;
{
 return((int)((d<0)?(d-.5):(d+.5)));
}

parseIntPair (s, ip1, ip2)
char *s;
int *ip1, *ip2;
{
	char *cp;

	cp = index(s, ':');

	if (cp == NULL || cp != s)
	 { *ip1 = atoi(s);
	 }
	if (cp != NULL && *++cp != '\0')
	 { *ip2 = atoi(cp);
	 }
}

parseDoublePair (s, fp1, fp2)
char *s;
double *fp1, *fp2;
{
	char *cp;

	cp = index(s, ':');

	if (cp == NULL || cp != s)
	 { *fp1 = atof(s);
	 }
	if (cp != NULL && *++cp != '\0')
	 { *fp2 = atof(cp);
	 }
}

#define NUM_DIVISIONS	10

double findScale(min, max)
double min;
double max;
{
	double delta;
	double minScale;
	double scale;
	static int factor[] = { 1, 2, 5 };
	int i;

	delta = FABS(max - min)/NUM_DIVISIONS;

	minScale = FABS(max - min);
	for (i=0; i<ARRAY_SIZE(factor); i++)
	 { double x = delta/factor[i];
	   if ((scale = (pow(10.0, ceil(log10(x)))*factor[i])) < minScale)
	    { minScale = scale;
	    }
	 }
	return (minScale);
}

parseargs()
{
	int argc;
	char **argv;
	int argno;

	inputf = stdin;
	argc = argcnt - 1;
	argv = argvec + 1;
	argno = 0;
	while (argc)
	 { if (ARGUMENT ("-m"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      sscanf (*argv, "%x", &fieldMask);
	    }
	   else if (ARGUMENT ("-f"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      sscanf (*argv, "%d", &fieldWidth);
	    }
	   else if (ARGUMENT ("-a"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      aspect_fixed = 1;
	      aspect_ratio = atof(*argv);
	    }
	   else if (ARGUMENT ("-g"))
	    { grid = 1;
	    }
	   else if (ARGUMENT ("-i"))
	    { implicitX = 1;
	    }
	   else if (ARGUMENT ("-x"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      winx = atoi(*argv);
	    }
	   else if (ARGUMENT ("-y"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      winy = atoi(*argv);
	    }
	   else if (ARGUMENT ("-w"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      winw = atoi(*argv);
	    }
	   else if (ARGUMENT ("-h"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      winh = atoi(*argv);
	    }
	   else if (ARGUMENT ("-r"))
	    { blackonwhite = ! blackonwhite;
	    }
	   else if (ARGUMENT ("-F"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      fontpath = *argv;
	    }
	   else if (ARGUMENT ("-d"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      parseIntPair (*argv, &startMark, &stopMark);
	    }
	   else if (ARGUMENT ("-S"))
	    { argc--; argv++;
	      if (!argc)
	       { argc = -1;
		 break;
	       }
	      screenpath = *argv;
	    }
	   else if (ARGUMENT("-Lx"))
	    { argc --;
	      argv ++;
	      if (! argc)
	       { argc = -1;
		 break;
	       }
	      parseDoublePair(*argv,&xlim_min,&xlim_max);
	      gavexlim = 1;
	    }
	   else if (ARGUMENT("-Ly"))
	    { argc --;
	      argv ++;
	      if (! argc)
	       { argc = -1;
		 break;
	       }
	      parseDoublePair(*argv,&ylim_min,&ylim_max);
	      gaveylim = 1;
	    }
	   else
	    { switch (argno++)
	       { default:
		    fprintf(stderr,"%s: extra argument `%s'\n",argvec[0],*argv);
		    goto usage;
		    break;
		 case 0:
		    inputf = fopen(*argv,"r");
		    if (inputf == 0)
		     { fprintf(stderr,"%s: can't read %s\n",argvec[0],*argv);
		       goto usage;
		     }
		    break;
	       }
	    }
	   argc --;
	   argv ++;
	 }
	if (argc < 0)
	 {
usage:;
	   fprintf (stderr, "\
usage: %s [-f <fieldWidth>] [-m <fieldMask>] [-a <aspectRatio>] [-g] [-i]\n\
	  [-x <xorigin>] [-y <yorigin>] [-w <width>] [-h <height>] \n\
	  [-F <fontPath>] [-S <screenPath>] [-d <start:stop>\n");
	   exit (-1);
	 }
}

openthings()
{
 PIXRECT *frame;

 frame = pr_open(screenpath);
 if (frame == 0)
  { fprintf(stderr,"%s: can't open screen %s\n",argvec[0],screenpath);
    exit(1);
  }
 if (winw == 0) winw = frame->pr_size.x - winx;
 if (winh == 0) winh = frame->pr_size.y - winy;
 screen = pr_region(frame,winx,winy,winw,winh);
 if (screen == 0)
  { fprintf(stderr,"%s: can't create window region\n",argvec[0]);
    exit(1);
  }
 font = pf_open(fontpath);
 if (font == 0)
  { fprintf(stderr,"%s: can't open font %s\n",argvec[0],fontpath);
    exit(1);
  }
 if (blackonwhite)
  { pr_blackonwhite(screen,0,1);
  }
 else
  { pr_whiteonblack(screen,0,1);
  }
}

readinput(xp,yp)
double *xp, *yp;
{
	static int count = 0;
	char bitbucket[256];
	unsigned long inputmask;
	double values[32];
	double x, y;
	int k, ip;

	if ((inputmask = fieldMask) == 0)
	 { return (0);
	 }
	if (stopMark != -1 && count >= stopMark)
	 { return (0);
	 }
	while (count < startMark-1)
	 { for (k=0; k<fieldWidth; k++)
	    { if (fscanf (inputf, "%s", bitbucket) != 1)
	       { return (0);
	       }
	    }
	   count++;
	 }
	ip = 0;
	for (k=0; k<fieldWidth; k++)
	 { if (!(inputmask & 0x1))
	    { if (fscanf (inputf, "%s", bitbucket) != 1)
	       { return (0);
	       }
	    }
	   else
	    { if (fscanf (inputf, "%lf", &values[ip++]) != 1)
	       { return (0);
	       }
	    }
	   inputmask = (inputmask >> 1);
	 }
	count++;
	if (inputmask)
	 { return (0);
	 }
	if (ip == 1)
	 { *xp = count;
	   *yp = values[0];
	 }
	else
	 { *xp = values[0];
	   *yp = values[1];
	 }
	return(1);
}

readpoints()
{
 double ptx;
 double pty;

 lastpointp = &points;
 npoints = 0;
 while (readinput(&ptx,&pty))
  { *lastpointp = NEW(POINT);
    (*lastpointp)->x = ptx;
    (*lastpointp)->y = pty;
    lastpointp = &(*lastpointp)->link;
    npoints ++;
  }
 if (getc(inputf) != EOF)
  { fprintf(stderr,"%s: warning: extra input ignored (after %d pairs)\n",argvec[0],npoints);
  }
 *lastpointp = 0;
 if (points == 0)
  { fprintf(stderr,"%s: no points\n",argvec[0]);
    exit(1);
  }
}

find_limits()
{
 register POINT *p;

 xmin = points->x;
 xmax = xmin;
 ymin = points->y;
 ymax = ymin;
 for (p=points->link;p;p=p->link)
  {      if (p->x < xmin) xmin = p->x;
    else if (p->x > xmax) xmax = p->x;
	 if (p->y < ymin) ymin = p->y;
    else if (p->y > ymax) ymax = p->y;
  }
 if (gavexlim)
  { xmin = xlim_min;
    xmax = xlim_max;
  }
 if (gaveylim)
  { ymin = ylim_min;
    ymax = ylim_max;
  }
}

setup_graph()
{
 int left;
 int right;
 int top;
 int bottom;
 int margin;
 int k;

 margin = 15;
 left = margin + (font->pf_defaultsize.x * 10) + 5 + 5 + margin;
 right = margin + (font->pf_defaultsize.x * 5);
 top = margin;
 bottom = margin + font->pf_defaultsize.y + 5 + 5 + margin;
 graphx = left;
 graphy = top;
 graphw = screen->pr_size.x - left - right;
 graphh = screen->pr_size.y - top - bottom;
 axisx = left - margin;
 axisy = graphy + graphh + margin;
 xscale = (xmax - xmin) / graphw;
 yscale = (ymax - ymin) / graphh;
 if (xscale == 0)
  { fprintf(stderr,"%s: all points have the same X coordinate\n",argvec[0]);
    exit(1);
  }
 if (yscale == 0)
  { fprintf(stderr,"%s: all points have the same Y coordinate\n",argvec[0]);
    exit(1);
  }
 if (aspect_fixed)
  { double m;
    if (xscale < aspect_ratio*yscale)
     { /* grow the X axis */
       xscale = aspect_ratio * yscale;
       m = (xmin + xmax) / 2;
       xmin = m - (xscale * graphw * .5);
       xmax = xmin + (xscale * graphw);
     }
    else
     { /* grow the Y axis */
       yscale = xscale / aspect_ratio;
       m = (ymin + ymax) / 2;
       ymin = m - (yscale * graphh * .5);
       ymax = ymin + (yscale * graphh);
     }
  }
 xdelta = findScale (xmin, xmax);
 ydelta = findScale (ymin, ymax);
 xaxis_min = xmin;
 xaxis_max = xmax;
 yaxis_min = ymin;
 yaxis_max = ymax;
}

foreachtick(min,max,delta,fxn)
double min;
double max;
double delta;
int (*fxn)();
{
	double v;

	for (v=delta*ceil(min/delta);v<=max;v+=delta)
	 { (*fxn)(v);
	 }
}

int xmap(x)
double x;
{
 return(nint((x-xmin)/xscale));
}

int ymap(y)
double y;
{
 return(nint((y-ymin)/yscale));
}

draw_xtick(x)
double x;
{
 int sx;

 sx = xmap(x) + graphx;
 pr_vector(screen,sx,axisy,sx,axisy+4,PIX_SRC,~0);
}

draw_ytick(y)
double y;
{
 int sy;

 sy = ymap(y) + graphy;
 pr_vector(screen,axisx,sy,axisx-4,sy,PIX_SRC,~0);
}

draw_axes()
{
 pr_vector(screen,graphx,axisy,graphx+graphw-1,axisy,PIX_SRC,~0);
 pr_vector(screen,axisx,graphy,axisx,graphy+graphh-1,PIX_SRC,~0);
 foreachtick(xaxis_min,xaxis_max,xdelta,draw_xtick);
 foreachtick(yaxis_min,yaxis_max,ydelta,draw_ytick);
}

draw_xlabel(x)
double x;
{
 char buf[64];
 struct pr_subregion boundbox;
 struct pr_prpos where;

 sprintf(&buf[0],"%g",x);
 pf_textbound(&boundbox,strlen(&buf[0]),font,&buf[0]);
 where.pr = screen;
 where.pos.x = xmap(x) + graphx - (boundbox.size.x / 2) - boundbox.pos.x;
 where.pos.y = axisy + 5 + 5 - boundbox.pos.y;
 pf_text(where,PIX_SRC|PIX_COLOR(~0),font,&buf[0]);
}

draw_ylabel(y)
double y;
{
 char buf[64];
 struct pr_subregion boundbox;
 struct pr_prpos where;

 sprintf(&buf[0],"%g",y);
 pf_textbound(&boundbox,strlen(&buf[0]),font,&buf[0]);
 where.pr = screen;
 where.pos.x = axisx - 5 - 5 - boundbox.size.x - boundbox.pos.x;
 where.pos.y = ymap(y) + graphy - (boundbox.size.y / 2) - boundbox.pos.y;
 pf_text(where,PIX_SRC|PIX_COLOR(~0),font,&buf[0]);
}

label_axes()
{
 foreachtick(xaxis_min,xaxis_max,xdelta,draw_xlabel);
 foreachtick(yaxis_min,yaxis_max,ydelta,draw_ylabel);
}

draw_points()
{
 int lastx;
 int lasty;
 POINT *p;
 int x;
 int y;
 PIXRECT *plotregion;

 x = xmap(xaxis_min);
 y = ymap(yaxis_min);
 plotregion = pr_region(screen,graphx+x,graphy+y,1+xmap(xaxis_max)-x,1+ymap(yaxis_max)-y);
 lastx = xmap(points->x);
 lasty = ymap(points->y);
 for (p=points->link;p;p=p->link)
  { x = xmap(p->x);
    y = ymap(p->y);
    pr_vector(plotregion,lastx,lasty,x,y,PIX_SRC,~0);
    lastx = x;
    lasty = y;
  }
}

draw_xgridline(x)
{
 int sx;

 sx = xmap(x) + graphx;
 pr_replrop(screen,sx,graphy,1,graphh,PIX_SRC|PIX_DST|PIX_COLOR(~0),gridcell,0,0);
}

draw_ygridline(y)
{
 int sy;

 sy = ymap(y) + graphy;
 pr_replrop(screen,graphx,sy,graphw,1,PIX_SRC|PIX_DST|PIX_COLOR(~0),gridcell,0,0);
}

draw_grid()
{
 if (! grid) return;
 gridcell = mem_create(GRIDGRAY,GRIDGRAY,screen->pr_depth);
 pr_rop(gridcell,0,0,4,4,PIX_CLR,(PIXRECT *)0,0,0);
 pr_put(gridcell,0,0,~0);
 foreachtick(xaxis_min,xaxis_max,xdelta,draw_xgridline);
 foreachtick(yaxis_min,yaxis_max,ydelta,draw_ygridline);
}

main(ac,av)
int ac;
char **av;
{
 argcnt = ac;
 argvec = av;
 parseargs();
 openthings();
 pr_rop(screen,0,0,screen->pr_size.x,screen->pr_size.y,PIX_CLR,(PIXRECT *)0,0,0);
 readpoints();
 find_limits();
 setup_graph();
 draw_axes();
 label_axes();
 draw_points();
 draw_grid();
}
#endif

