/* plot, unix plot file to graphics device translators.
   Copyright (C) 1989 Free Software Foundation, Inc.

   plot is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY.  No author or distributor accepts responsibility to
   anyone for the consequences of using it or for whether it serves any
   particular purpose or works at all, unless he says so in writing.
   Refer to the GNU General Public License for full details.
   
   Everyone is granted permission to copy, modify and redistribute plot,
   but only under the conditions described in the GNU General Public
   License.  A copy of this license is supposed to have been given to you
   along with plot so you can know your rights and responsibilities.  It
   should be in a file named COPYING.  Among other things, the copyright
   notice and this notice must be preserved on all copies.  */


/* This file is the main routine for plot.

   It includes code to read the plot file and call plot functions
   to draw the graphics. */

#include <stdio.h>
#include <ctype.h>
#ifdef sequent
#include <strings.h>
#else
#include <string.h>
#endif
#include <math.h>
#include "libplot.h"


extern int perror();
extern int exit();
extern int printf();
extern int fprintf();
extern int fclose();
#ifndef mips
extern char *sprintf();
#endif
#ifndef hpux
extern void *malloc();
extern void *realloc();
#endif
extern int fputs();

#include "../COPYING"

enum plot_instruction
{
  ALABEL =	'T',
  ARC =		'a',
  CIRCLE =	'c',
  COLOR =	'C',
  CONT =	'n',
  ERASE =	'e',
  FILL =	'L',
  FONT =	'F',
  FONTSIZE =	'S',
  LABEL =	't',
  LINE =	'l',
  LINEMOD =	'f',
  MOVE =	'm',
  POINT =	'p',
  ROTATE =	'r',
  SPACE =	's',
};

/* This flag specifies that the input contains unsigned (if zero) or
   signed (if nonzero) two byte intgers. The default is signed. */
int signed_input = 1;

/* read in two byte intgers with high_byte_first. The default is to read the low
   byte first. */
int high_byte_first = 0;

/* guess_byte_order is a flag which, if non-zero, indicated that the function
   find_byte_order should be used to guess the byte order for the input file. */
int guess_byte_order = 1;

/* swap_bytes returns the bottom two bytes of its integer argument with
   their bytes reversed. */

int
swap_bytes (x)
     int x;
{
  unsigned char a, b;
  a = x & 0xff;
  b = (x >> 8) & 0xff;
  return ((a << 8)|b);
}

/* This is a set of known values for the maximum x (abscissa) values
   specified in the plot size command for known devices.  Using this
   set we can construct a heuristic proceedure for recognizing plot
   files in which the bytes of two byte integers are reversed.  We can
   recognize these files by looking for size commands containing these
   known sizes in byte reversed form. The last entry should be 0. */
   
int known_size[32] = {
  504,				/* plot3d output 504x504 */
  2048,				/* versatek plotter 2048x2048 */
  2100,				/* plot3d output */
  3120,				/* Tektronix 4010 terminal 3120x3120 */
  4096,				/* GSI 300 terminal 4096x4096 */
  0				/* the last entry should be 0 */
  };

/* find_byte_order takes four integer arguments and matches third one
   against a set of known values (sizes, see above). If there is a match
   it merely returns.  If there is no match, it check each of the values
   again with the bottom two bytes reversed. If such a match is found, the
   bottom two bytes of each argument is reversed, the high_byte_first flag
   is inverted to indicated how two byte integers should be read and the
   runction returns. */
   
void
find_byte_order (x0, y0, x1, y1)
     int *x0, *y0, *x1, *y1;
{
  int i;
  for (i=0; known_size[i]!=0; i++)
    {
      if (*x1 == known_size[i])
	return;
    }
  /* now check to see if reversing the bytes allows a match... */
  for (i=0; known_size[i]!=0; i++)
    {
      if (*x1 == swap_bytes (known_size[i]))
	{
	  *x0 = swap_bytes( *x0);
	  *y0 = swap_bytes( *y0);
	  *x1 = swap_bytes( *x1);
	  *y1 = swap_bytes( *y1);
	  high_byte_first = ! high_byte_first;
	  return;
	}
    }
}

/* Read a byte */

#define read_byte(stream) (getc (stream))

/* Read a coordinate - a two byte integer. */
  
int coord (input)
     FILE *input;
{
  int x;
  if ( high_byte_first )
    {
      x = ((char) read_byte (input)) << 8; /* get sign from high byte */
      x |= read_byte (input) & 0xFF; /* not from low byte */
    }
  else
    {
      x = read_byte (input) & 0xFF; /* ingnore sign in low byte */
      x |= ((char) read_byte (input)) << 8; /* get sign from high byte */
    }
  if ( ! signed_input )
    {
      x &= 0xFFFF;
    }

  return x;
}
  
/*  Read a string, change termination to null.
    note: string (buffer) reads a newline terminated string. */
  
void
read_string (input, buffer, buffer_length)
     FILE *input;
     char *buffer;
     int buffer_length;
{
  int length=0;
  char termination = '\n';
  char c = '\0';

  while (!feof (input))
    {
      if (length > buffer_length)
	{
	  buffer_length *= 2;
	  buffer = (char *) realloc (buffer, buffer_length);
	  if (buffer <= (char *) 0)
	    {
	      perror ("realloc failed:");
	      exit (-1);
	    }
	}
      c = read_byte (input);
      if (c == termination)
	break;
      buffer [length++] = c;
    }

  buffer [length] = '\0';	/*  null terminate label */
}


/* read_plot reads a plot file from the standard input and calls
   a plot function according to each plot instruction found in the
   file. */

void
read_plot (in_stream, buffer, buffer_length)
     FILE *in_stream;
     char *buffer;
     int  buffer_length;
{
  char x_adjust, y_adjust;
  int x0, y0, x1, y1, x2, y2;
  int instruction;

  instruction = read_byte (in_stream);
  while (!feof (in_stream))
    {
      switch (instruction)
	{
	  /*  Note: we must get all but the last argument before calling to
	      ensure reading them in the proper order. */
	  
	case ALABEL:
	  x_adjust = read_byte (in_stream);
	  y_adjust = read_byte (in_stream); 
	  read_string (in_stream, buffer, buffer_length);
	  alabel (x_adjust, y_adjust, buffer);
	  break;
	case ARC:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  x1 = coord (in_stream);
	  y1 = coord (in_stream); 
	  x2 = coord (in_stream);
	  y2 = coord (in_stream); 
	  arc (x0, y0, x1, y1, x2, y2);
	  break;
	case CIRCLE:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  x1 = coord (in_stream);
	  circle (x0, y0, x1);
	  break;
	case COLOR:
	  x0 = coord (in_stream)&0xFFFF;
	  y0 = coord (in_stream)&0xFFFF;
	  x1 = coord (in_stream)&0xFFFF;
	  color (x0, y0, x1);
	  break;
	case CONT:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  cont (x0, y0);
	  break;
	case ERASE:
	  erase (in_stream);
	  break;
	case FILL:
	  fill (coord (in_stream)&0xFFFF); break;
	case FONT:
	  read_string (in_stream, buffer, buffer_length);
	  fontname (buffer);
	  break;
	case FONTSIZE:
	  fontsize (coord (in_stream));
	  break;
	case LABEL:
	  read_string (in_stream, buffer, buffer_length);
	  label (buffer);
	  break;
	case LINE:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  x1 = coord (in_stream);
	  y1 = coord (in_stream); 
	  line (x0, y0, x1, y1);
	  break;
	case LINEMOD:
	  read_string (in_stream, buffer, buffer_length);
	  linemod (buffer);
	  break;
	case MOVE:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  move (x0, y0);
	  break;
	case POINT:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  point (x0, y0);
	  break;
	case ROTATE:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  x1 = coord (in_stream);
	  rotate (x0, y0, x1);
	  break;
	case SPACE:
	  x0 = coord (in_stream);
	  y0 = coord (in_stream);
	  x1 = coord (in_stream);
	  y1 = coord (in_stream); 
	  if (guess_byte_order)
	    find_byte_order(&x0, &y0, &x1, &y1);
	  space (x0, y0, x1, y1);
	  break;
	default:
	  fprintf (stderr, "Unrecognized plot command `%c' ignored.\n", instruction);
	}
      instruction = read_byte (in_stream);
    }
  return;
}


int
main (argc, argv)
     int argc;
     char *argv[];
{
  int i;
  char *buffer;
  int  buffer_length;
  int  named_plot=0;		/* count named plot files on command line. */
  int  show_usage=0;		/* remember whether to output usage message. */
  int  opened=0;		/* remember whether we have opened output. */

  buffer_length = 1024;
  buffer = (char *) malloc (buffer_length);
  if (buffer <= (char *) 0)
    {
      perror ("malloc failed:");
      exit (-1);
    }

  for (i = 1; i < argc; i++)
    {
      if ((strcmp (argv [i], "-fontsize") == 0)
	  || (strcmp (argv [i], "-fs") == 0))
	{
	  /* Sizes supported by X: 8, 10, 12, 14, 18, and 24. */
	  fontsize (atoi (argv[i+1]));
	  i += 1;
	}
      else if ((strcmp (argv [i], "-fontname") == 0)
	       || (strcmp (argv [i], "-fn") == 0))
	{
	  fontname (argv [i+1]);
	  i += 1;
	}
      else if ((strcmp (argv [i], "-high-byte-first") == 0)
	       || (strcmp (argv [i], "-h") == 0))
	{
	  guess_byte_order = 0;
	  high_byte_first = 1;
	}
      else if ((strcmp (argv [i], "-low-byte-first") == 0)
	       || (strcmp (argv [i], "-l") == 0))
	{
	  guess_byte_order = 0;
	  high_byte_first = 0;
	}
      else if ((strcmp (argv [i], "-warranty") == 0)
	       || (strcmp (argv [i], "-copying") == 0))
	{
	  for (i=0; copy_notice[i][0]>0; i++)
	    fputs (copy_notice[i], stdout);
	  named_plot++;
	}
      else if ((strcmp (argv [i], "-help") == 0)
	       || (strcmp (argv [i], "-V") == 0))
	{
	  printf ("%s version %s\n", argv[0], VERS);
	  show_usage++;
	  named_plot++;
	}
      else if ((strcmp (argv [i], "-signed") == 0))
	{
	  signed_input=1;
	}
      else if ((strcmp (argv [i], "-unsigned") == 0))
	{
	  signed_input=0;
	}
      else if ((strcmp (argv [i], "-") == 0))
	{
	  read_plot (stdin, buffer, buffer_length);
	  named_plot++;
	}
      else
	{
	  FILE *filep;
	  filep = fopen ( argv [i], "r");
	  if (filep == NULL)
	    {
	      fprintf (stderr, "Unrecognized option or file `%s' ignored.\n",
		       argv [i]);
	      show_usage++;
	    }
	  else
	    {
	      named_plot++;
	      if (!opened)
		{
		  openpl ();
		  opened ++;
		}
	      read_plot (filep, buffer, buffer_length);
	      fclose (filep);
	    }
	}
    }



  /* if there were no named plot files on the command line, then read
     the standard input. */
  if (named_plot == 0)
    {
      if (!opened)
	{
	  openpl ();
	  opened ++;
	}
      read_plot (stdin, buffer, buffer_length);
    }
  if (opened)
    closepl();

  if ( show_usage || !opened)
    {
      fprintf (stderr, "\n\
usage: %s [-fontsize|-fs SIZE] [-high-byte-first|-h]\n\
       [-low-byte-first|-l] [-fontname|-fn FONTNAME]\n\
       [-help|-V] [-copying|-warranty] [PLOT_FILE_NAMES ...]\n",
	       *argv);
      fprintf (stderr, "\n\
    %s version 0.9, Copyright (C) 1989 Free Software Foundation, Inc.\n\
    %s comes with ABSOLUTELY NO WARRANTY.  This is free software, and\n\
    you are welcome to redistribute it. Type `%s -warranty' for warranty\n\
    details and copying conditions.\n\n",
	       *argv, *argv, *argv, *argv);
    }
  return 0;
}
