/* Original Author:         Andrew Trevorrow
   Implementation: Modula-2 under VAX/UNIX 4.2 BSD
   Date Started:   June, 1986

   Description:
   SYSDEP: Implements InitSysInterface() the routine that gets the
   DVItoVDU command line and extracts the DVI file name and option values.

   This version converted to C and ported to BSD and System V UNIX by
   some chaps at Kernel Technology up to September 1989.  Contact
   mjh@uk.co.kernel (Mark J. Hewitt) with bug fixes etc.

   Involved were:	Mark J. Hewitt
   			Dave Dixon
			Marc Hadley
*/

#include "def.h"
#ifdef USG
#include <string.h>
#else
#include <strings.h>
#endif /* USG */
#include "systemif.h"

static char *sccsid[] = "@(#)systemif.c	1.1";

/* TYPE UNITS = (IC,CM,MM,PC,PT,PX);*/
 /* SYSDEP: changed in to IC; compiler confused with IN, even with -sk!!! */
#define IC 1
#define CM 2
#define MM 3
#define PC 4
#define PT 5
#define PX 6
#define UNITS short

#ifndef PKFONTDIR
#define PKFONTDIR "/usr/local/lib/tex/fonts/pk"
#endif

#ifndef HELPFILELOC
#define HELPFILELOC "/usr/local/lib/tex/dvitovdu.hlp" 
#endif

extern int NumParameters;

char  option;			/* current command option */
stringvalue value;		/* current option's value */
int   length;			/* current value's length */

/**********************************************************************/

short   ExplicitExt (fname, len)
char *fname;
int   len;

{

/* SYSDEP: Check for an extension of the form ".*" where * is any string.
   len is length of fname.
   If "." found then TRUE is returned, otherwise FALSE.
*/

  while (len > 0)		/* search backwards looking for . */
  {
    len--;
    if (fname[len] == '.')
    {
      return TRUE;
    }
  }
  return FALSE;
}

/**********************************************************************/

void GetCardinal (n)
unsigned int *n;
{

/* If current value represents a positive integer then return via n. */

  if ((sscanf (value, "%d", n) != 1) || ((long)n <= 0L))
  {
    WriteString ("Bad -");
    Write (option);
    WriteString (" value: ");
    WriteString (value);
    WriteLn ();
    WriteString ("Specify a positive integer.");
    WriteLn ();
    RestoreTerminal ();
    exitprog (1);
  }
}

/**********************************************************************/

void Get2Dimension (r, un)
float  *r;
UNITS * un;
/* A valid dimension consists of a positive integer or real number followed
   by a two-letter unit: IN, CM, MM, PC, PT or PX (or in lowercase).
   If current value represents a valid dimension, we return number part in r
   and units part in un.
*/
{
  int   i;
  char  ch1, ch2;

/* extract un */
  if (length > 1)
    i = length - 1;
  else
    i = 1;
  if (((value[i - 1] == 'I') || (value[i - 1] == 'i')) &&
      ((value[i] == 'N')     || (value[i] == 'n')))
  {
    *un = IC;
  }
  else
    if (((value[i - 1] == 'C') || (value[i - 1] == 'c')) &&
	((value[i] == 'M')     || (value[i] == 'm')))
    {
      *un = CM;
    }
    else
      if (((value[i - 1] == 'M') || (value[i - 1] == 'm')) &&
	  ((value[i] == 'M')     || (value[i] == 'm')))
      {
	*un = MM;
      }
      else
	if (((value[i - 1] == 'P') || (value[i - 1] == 'p')) &&
	    ((value[i] == 'C')     || (value[i] == 'c')))
	{
	  *un = PC;
	}
	else
	  if (((value[i - 1] == 'P') || (value[i - 1] == 'p')) &&
	      ((value[i] == 'T')     || (value[i] == 't')))
	  {
	    *un = PT;
	  }
	  else
	    if (((value[i - 1] == 'P') || (value[i - 1] == 'p')) &&
		((value[i] == 'X')     || (value[i] == 'x')))
	    {
	      *un = PX;
	    }
	    else
	    {
	      WriteString ("Bad units in -");
	      Write (option);
	      WriteString (" value: ");
	      WriteString (value);
	      WriteLn ();
	      WriteString ("Last two letters should be IN, CM, MM, PC, PT or PX.");
	      WriteLn ();
	      RestoreTerminal ();
	      exitprog (1);
	    }
  ch1 = value[i - 1];		/* remember letters in units */
  ch2 = value[i];
  value[i] = '\0';		/* remove units */
  value[i - 1] = '\0';
  if ((sscanf (value, "%f", r) != 1) || (*r <= 0.0))
  {
    value[i - 1] = ch1;		/* restore units */
    value[i] = ch2;
    WriteString ("Bad -");
    Write (option);
    WriteString (" value: ");
    WriteString (value);
    WriteLn ();
    WriteString ("Specify a positive dimension.");
    WriteLn ();
    RestoreTerminal ();
    exitprog (1);
  }
}

/**********************************************************************/

void InitSysInterface ()
{

/* If an option appears more than once then we return the last value. */

  unsigned int  i;
  int num;
  UNITS unitwd, unitht;
  float   realwd, realht;
  extern char *getenv();

/* SYSDEP: initialize option values with defaults */
  resolution = 300;		/* LaserWriter resolution */
  unitwd = IC;			/* paper dimensions in inches */
  unitht = IC;
  realwd = 8.3;			/* A4 paper is 8.3" wide */
  realht = 11.7;		/* A4 paper is 11.7" high */
  mag = 0;			/* use DVI mag */
  (void) strcpy (vdu, getenv ("TERM"));/* set vdu to value of TERM */
  if (vdu[0] == '\0')
  {
    (void) strcpy (vdu, "unknown");
  }
  (void) strcpy (dummyfont, "cmr10.1500pxl");
  (void) strcpy (fontdir, PKFONTDIR);
  (void) strcpy (helpname, HELPFILELOC);
  DVIname[0] = '\0';		/* SYSDEP: empty string */
  num = 1;
  while (num < NumParameters)
  {
    length = GetParameter (num, value);
    num++;
    if (value[0] == '-')
    {
      if (length > 1)
      {
	option = value[1];
      }
      else
      {
	option = ' ';
      }
      if ((option != 'r') && (option != 'm') && (option != 'x') &&
	  (option != 'y') && (option != 'v') && (option != 'd') &&
	  (option != 'h') && (option != 'f'))
      {
	WriteString ("Unknown option: -");
	Write (option);
	WriteLn ();
	RestoreTerminal ();
	exitprog (1);
      }
    /* allow things like -vvis500 */
      if (length > 2)
      {				/* shift value left 2 places */
	for (i = 0; i <= length - 1; i++)
	{
	  value[i] = value[i + 2];
	}
	length = length - 2;
	value[length] = '\0';	/* SYSDEP: terminate with NULL */
      }
      else			/* value is next parameter */
      {
	length = GetParameter (num, value);
	num++;
	if (length <= 0)
	{
	  WriteString ("Missing value after -");
	  Write (option);
	  WriteLn ();
	  RestoreTerminal ();
	  exitprog (1);
	}
      }
      switch (option)
      {
	case 'r': 
	  GetCardinal (&resolution);
	  break;
	case 'm': 
	  GetCardinal (&mag);
	  break;
	case 'x':
	  Get2Dimension (&realwd, &unitwd);
	  break;
	case 'y':
	  Get2Dimension (&realht, &unitht);
	  break;
	case 'v': 
	  (void) strcpy (vdu, value);
	  break;
	case 'd': 
	  (void) strcpy (dummyfont, value);
	  break;
	case 'h':
	  (void) strcpy (helpname, value);
	  break;
	case 'f':
	  (void) strcpy (fontdir, value);
	  break;
	/* bad string values will be detected in other modules */
      }
    }
    else
    {
      (void) strcpy (DVIname, value);
      if (!ExplicitExt (DVIname, length))/* append .dvi */
      {
	if ((length + 3) <= MAXSTRLEN - 1)
	{
	  DVIname[length] = '.';
	  DVIname[length + 1] = 'd';
	  DVIname[length + 2] = 'v';
	  DVIname[length + 3] = 'i';
	  if (length + 4 <= MAXSTRLEN - 1)
	  /* SYSDEP: append NULL */
	  {
	    DVIname[length + 4] = '\0';
	  }
	}
	else			/* user has given a mighty long file name! */
	{
	  WriteString ("DVI file name too long: ");
	  WriteString (DVIname);
	  WriteLn ();
	  RestoreTerminal ();
	  exitprog (1);
	}
      }
    /* bad DVIname will be detected upon open in main module */
    }
  }
  if (DVIname[0] == '\0')
  {
  /* no file name on command line */
    WriteString ("Missing DVI file name!");
    WriteLn ();
    RestoreTerminal ();
    exitprog (1);
  }
/* set paperwd and paperht only after resolution has been decided */
  switch (unitwd)
  {
    case IC: 
      paperwd = (unsigned) (realwd * ((float) resolution) + 0.5);
      break;
    case CM: 
      paperwd = (unsigned) ((realwd / 2.54) * ((float) resolution) + 0.5);
      break;
    case MM: 
      paperwd = (unsigned) ((realwd / 25.4) * ((float) resolution) + 0.5);
      break;
    case PT: 
      paperwd = (unsigned) ((realwd / 72.27) * ((float) resolution) + 0.5);
      break;
    case PC: 
      paperwd = (unsigned) ((realwd / 72.27) * 12.0 * ((float) resolution) + 0.5);
      break;
    case PX: 
      paperwd = (unsigned) (realwd + 0.5);
      break;
  }
  switch (unitht)
  {
    case IC: 
      paperht = (unsigned) (realht * ((float) resolution) + 0.5);
      break;
    case CM: 
      paperht = (unsigned) ((realht / 2.54) * ((float) resolution) + 0.5);
      break;
    case MM: 
      paperht = (unsigned) ((realht / 25.4) * ((float) resolution) + 0.5);
      break;
    case PT: 
      paperht = (unsigned) ((realht / 72.27) * ((float) resolution) + 0.5);
      break;
    case PC: 
      paperht = (unsigned) ((realht / 72.27) * 12.0 * ((float) resolution) + 0.5);
      break;
    case PX: 
      paperht = (unsigned) (realht + 0.5);
      break;
  }
}




