/* "UNTIL", a graphics editor,
   Copyright (C) 1985, 1990 California Institute of Technology.
   Original authors: Glenn Gribble, port by Steve DeWeerth
   Unix Port Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425 CU Boulder/Boulder CO 91125. 

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (Version 1, 1989).

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
USA. */


/*******************************************************************************/
/*                                                                             */ 
/*  file contains stuff used to read in until.cnf file                         */
/*  cleaned up by steve - 8 May 1990                                           */
/*                                                                             */ 
/*******************************************************************************/

#include <p2c/p2c.h>

#include "cnf_stuff.h"

#include "sys_stuff.h"

extern char *GetChipmunkPath();

typedef struct cnfBuf {
  boolean interactive;
  FILE *cnfFile;
  long cnfLine;   /* line number in file */
  long cnfPos;   /* current character position on line */
  Char buffer[256];   /* current line */
} cnfBuf;


Char announce[81];


Static boolean error;   /* Error on this command? */




Static void show_help(void)
{
  printf("\f");
  printf("\215addfont        \200 -   add a new font to definitions\n");
  printf("\215announce       \200 -   set startup announce string\n");
  printf("\215bezcontrol     \200 -   turn on/off bezier control points\n");
  printf("\215boopfreq       \200 -   input request beep frequency\n");
  printf("\215booptime       \200 -   input request beep time\n");
  printf("\215color          \200 -   current color\n");
  printf("\215cursor         \200 -   cursor type\n");
  printf("\215defzoom        \200 -   set default zoom for empty figures\n");
  printf("\215displaygrid    \200 -   show/don't show grid\n");
  printf("\215grid           \200 -   grid size, offset x, offset y\n");
  printf("\215grids          \200 -   set loop of grid sizes\n");
  printf("\215help           \200 -   duh\n");
  printf("\215initfonts      \200 -   erase all fonts, start again\n");
  printf("\215maxzoom        \200 -   max zoom for \"5\" command\n");
  printf("\215minzoom        \200 -   min zoom for \"5\" command\n");
  printf("\215pensps         \200 -   set pensps.map search list\n");
  printf("\215ps-bounding-box\200 -   set ps page bounding box\n");
  printf("\215read           \200 -   read another file\n");
  printf("\215rot            \200 -   set current allowed rotations\n");
  printf("\215rots           \200 -   set loop of rotations\n");
  printf("\215showinstbb     \200 -   display instance bounding boxes\n");

  if (hasAlpha) {
    printf("press [enter] for more:");
    scanf("%*[^\n]");
    getchar();
  }

  printf("\215draftmode      \200 -   show filename/figure on LaserWriter\n");
  printf("\215textfont       \200 -   set current font\n");
  printf("\215textorig       \200 -   set text origin\n");
  printf("\215textrot        \200 -   set text rotation\n");
  printf("\215textscale      \200 -   set text size in points\n");
  printf("\215textslant      \200 -   set text slant (which is not used)\n");
  printf("\215widelinewidth  \200 -   set line width of wide arrows\n");
  printf("\215widewinglength \200 -   set wing length of wide arrows\n");
  printf("\215widewingwidth  \200 -   set wing width of wide arrows\n");
  printf("\215width          \200 -   set current line width\n");
  printf("\215widths         \200 -   set loop of line widths\n");
  printf("\215winglength     \200 -   set wing length of normal arrows\n");
  printf("\215wingwidth      \200 -   set wing width of normal arrows\n");
  printf("\215zoom           \200 -   set current zoom numerically\n");
  printf("DONE: press [enter]:");
  scanf("%*[^\n]");
  getchar();
}


Static void read_error(cnfBuf *cb, Char *s)
{
  error = true;
  if (XPOS > 0)
    putchar('\n');
  puts(cb->buffer);
  printf("%*s^\n", (int)cb->cnfPos, "");

  printf("Line: %ld Error: %s\n", cb->cnfLine, s);
  printf("Press RETURN to continue:");
  scanf("%*[^\n]");
  getchar();
  printf("\015\t");
}


Static void skip_blanks(cnfBuf *cb)
{
  boolean done = false;

  while (!done) {
    while (cb->cnfPos <= strlen(cb->buffer) &&
	  (cb->buffer[cb->cnfPos - 1] == '\t' ||
	   cb->buffer[cb->cnfPos - 1] == '\n' ||
	   cb->buffer[cb->cnfPos - 1] == '\015' ||
	   cb->buffer[cb->cnfPos - 1] == ' '))
      cb->cnfPos++;

    if (cb->cnfPos <= strlen(cb->buffer) && cb->buffer[cb->cnfPos - 1] == '{') {
      while (cb->cnfPos <= strlen(cb->buffer) && cb->buffer[cb->cnfPos - 1] != '}')
	cb->cnfPos++;

      cb->cnfPos++;
    }
    else
      done = true;
  }
}


Local char *getPlainWord(cnfBuf *cb)
{
  /* return the next word */
  char s[256];
  long p;

  skip_blanks(cb);

  if (cb->cnfPos > strlen(cb->buffer))
    *s = '\0';
  else {
    p = cb->cnfPos;
    while (cb->cnfPos <= strlen(cb->buffer) &&
	   cb->buffer[cb->cnfPos - 1] != '\t' &&
	   cb->buffer[cb->cnfPos - 1] != '\n' &&
	   cb->buffer[cb->cnfPos - 1] != '\015' &&
	   cb->buffer[cb->cnfPos - 1] != ' ')
      cb->cnfPos++;

    sprintf(s, "%.*s", (int)(cb->cnfPos - p), cb->buffer + p - 1);
  }

  return (char *) strdup(s);
}


Local char *getWord(cnfBuf *cb)  /* return an upper-case word */
{
  char *temp;

  temp = getPlainWord(cb);

  return strupper(temp, temp);
}


Local char *expectWord(cnfBuf *cb, Char *wordkind)
{
  Char temp[256]; 
  char *param;

  param = getWord(cb);

  if (*param == '\0') {
    sprintf(temp, "%s expected.", wordkind);
    read_error(cb, temp);
  }

  return param;
}


Local char *expectPlainWord(cnfBuf *cb, Char *wordkind)
{
  char temp[256];
  char *param;

  param = getPlainWord(cb);

  if (*param == '\0') {
    sprintf(temp, "%s expected.", wordkind);
    read_error(cb, temp);
  }

  return param;
}

Local boolean expectBool(cnfBuf *cb)
{
  char *param;

  param = getWord(cb);

  if (!strcmp(param, "ON"))
    return true;
  else if (!strcmp(param, "OFF"))
    return false;
  else
    read_error(cb, "Boolean value expected.");
}

Local short expectShort(cnfBuf *cb)
{
  char *param,t[100];
  short temp;

  param = strcpy(t,getWord(cb));

  if (sscanf(param, "%hd", &temp) == 1)
    return temp;
  else {
    read_error(cb, "Integer value expected.");
    return 1;
  }
}

Local long expectInt(cnfBuf *cb)
{
  char *param,t[100];
  long temp;

  param = strcpy(t,getWord(cb));

  if (sscanf(param, "%ld", &temp) == 1)
    return temp;
  else {
    read_error(cb, "Integer value expected.");
    return 1;
  }
}

Local double expectReal(cnfBuf *cb)
{
  char *param;
  long i;
  float a, b;
  Char *temp;
  char ch, dummy,t[100];
  int count;

  param = getWord(cb);
  
  strcpy(t,param);
  param = t;
  count = sscanf(param, "%f%c%f", &a, &ch, &b);


  /* count = sscanf(param, "%e%c%e%c", &a, &ch, &b, &dummy); */ 

  if (count == 1)  /* real value */
    return a;
  else if ((count == 3) && (ch == '/'))  {  /* fractional value */
    if (b != 0)
      return a/b;
    else {
      read_error(cb, "Bad fraction: denominator = 0.");	  
      return a;
    }
  }
  else {
    read_error(cb, "Real or fractional value expected (2).");
    return 1;
  }
}

Local vRec expectLots(cnfBuf *cb)
{
  char *param;
  vRec v;
  short s;
  Char *temp,t[100];

  v.num = 0;
  do {
    param = strcpy(t,getWord(cb));

    if (*param != '\0') {
      if (sscanf(param, "%hd", &s)) {
	v.arr[v.num] = s;
	v.num++;
      }
      else
	read_error(cb, "Shortint value expected.");
    }
  } while (v.num <= vRecMax && *param != '\0');

  return v;
}


Static void do_read(cnfBuf *ocb, Char *newFile);


Static void parseline(cnfBuf *cb)
{
  Char *param;

  Char *cmd;
  short ignoreShort, newColor;
  long p;
  short defaultCursor;
  bbrec tempBB;
  double newZoom;
  Char STR1[96];
  Char STR2[256];
  Char STR3[104];

  error = false;
  cmd = getWord(cb);
  if (!strcmp(cmd, "DEFZOOM"))
    default_zoom = expectReal(cb);
  else if (!strcmp(cmd, "ZOOM")) {
    newZoom = expectReal(cb);
    if (cb->interactive)
      set_zoom(newZoom);
  } 
  else if (!strcmp(cmd, "MAXZOOM"))
    max_zoom = expectReal(cb);
  else if (!strcmp(cmd, "MINZOOM"))
    min_zoom = expectReal(cb);
  else if (!strcmp(cmd, "DISPLAYGRID"))
    showGrid = expectBool(cb);
  else if (!strcmp(cmd, "FORCETOGRID"))
    forceToGrid = expectBool(cb);
  else if (!strcmp(cmd, "GRID")) {
    grid_mul = expectShort(cb);
    ignoreShort = expectShort(cb);
    ignoreShort = expectShort(cb);
  } 
  else if (!strcmp(cmd, "COLOR")) {
    param = expectWord(cb, "color name");
    newColor = nameToColor(param);
    if (newColor < 0)
      read_error(cb, "Illegal color name");
    else
      curColor = newColor;
  } 
  else if (!strcmp(cmd, "?") || !strcmp(cmd, "HELP"))
    show_help();
  else if (!strcmp(cmd, "BOOPFREQ"))
    boopFreq = expectShort(cb);
  else if (!strcmp(cmd, "BOOPTIME"))
    boopTime = expectShort(cb);
  else if (!strcmp(cmd, "BEZCONTROL"))
    gr_show_control = expectBool(cb);
  else if (!strcmp(cmd, "SHOWINSTBB"))
    showInstBB = expectBool(cb);
  else if (!strcmp(cmd, "DRAFTMODE"))
    draftMode = expectBool(cb);
  else if (!strcmp(cmd, "ROT"))
    curRots = expectShort(cb);
  else if (!strcmp(cmd, "ROTS"))
    rotRec = expectLots(cb);
  else if (!strcmp(cmd, "GRIDS"))
    gridRec = expectLots(cb);
  else if (!strcmp(cmd, "WIDTH"))
    curLWid = expectShort(cb);
  else if (!strcmp(cmd, "WIDTHS"))
    widthRec = expectLots(cb);
  else if (!strcmp(cmd, "CURSOR")) {
    defaultCursor = expectShort(cb);
    m_choosecursor(defaultCursor);
  } else if (!strcmp(cmd, "WINGWIDTH"))
    curWWidN = expectShort(cb);
  else if (!strcmp(cmd, "WINGLENGTH"))
    curWLenN = expectShort(cb);
  else if (!strcmp(cmd, "WIDELINEWIDTH"))
    curLWidW = expectShort(cb);
  else if (!strcmp(cmd, "WIDEWINGWIDTH"))
    curWWidW = expectShort(cb);
  else if (!strcmp(cmd, "WIDEWINGLENGTH"))
    curWLenW = expectShort(cb);
  else if (!strcmp(cmd, "TEXTSCALE"))
    curTextScale = expectShort(cb);
  else if (!strcmp(cmd, "TEXTROT"))
    curTextRot = expectShort(cb);
  else if (!strcmp(cmd, "TEXTSLANT"))
    curTextSlant = expectShort(cb);
  else if (!strcmp(cmd, "TEXTORIG")) {
    param = expectWord(cb, "Text-Origin");
    if (*param != '\0') {   /* already gave an error */
      if (!strcmp(param, "UL") || !strcmp(param, "UPLEFT"))
	curTextOrig = TUL;
      else if (!strcmp(param, "UC") || !strcmp(param, "UPCENT"))
	curTextOrig = TUC;
      else if (!strcmp(param, "UR") || !strcmp(param, "UPRIGHT"))
	curTextOrig = TUR;
      else if (!strcmp(param, "CL") || !strcmp(param, "CENTLEFT"))
	curTextOrig = TCL;
      else if (!strcmp(param, "CC") || !strcmp(param, "CENTCENT"))
	curTextOrig = TCC;
      else if (!strcmp(param, "CR") || !strcmp(param, "CENTRIGHT"))
	curTextOrig = TCR;
      else if (!strcmp(param, "LL") || !strcmp(param, "LOWLEFT"))
	curTextOrig = TLL;
      else if (!strcmp(param, "LC") || !strcmp(param, "LOWCENT"))
	curTextOrig = TLC;
      else if (!strcmp(param, "LR") || !strcmp(param, "LOWRIGHT"))
	curTextOrig = TLR;
      else
	read_error(cb, "Bad Text-Origin");
    }
  } else if (!strcmp(cmd, "TEXTFONT")) {
    param = expectPlainWord(cb, "font name");
    curTextFont = -1;
    for (p = 1 ; p <= numFonts ; p++) {
      if (!strcmp(param, fonts[p - 1].dispName) || !strcmp(param, fonts[p - 1].psName))
	curTextFont = p;
    }
    if (curTextFont == -1) {
      sprintf(STR1, "Unknown font: %s", param);
      read_error(cb, STR1);
      curTextFont = 1;
    }
  } else if (!strcmp(cmd, "INITFONTS"))
    numFonts = 0;
  else if (!strcmp(cmd, "ADDFONT")) {
    if (numFonts < maxFonts) {
      numFonts++;
      param = expectPlainWord(cb, "Displayed font name");
      strcpy(fonts[numFonts - 1].dispName, param);
      param = expectPlainWord(cb, "Postscript font name");
      strcpy(fonts[numFonts - 1].psName, param);
      if (!strcmp(param, "Symbol"))
	symbolFontNum = numFonts;
      if (!strcmp(param, "Music-Notation"))
	musicFontNum = numFonts;
    } else {
      sprintf(STR2, "Too many fonts, only %ld allowed.", (long)maxFonts);
      read_error(cb, STR2);
    }
  } else if (!strcmp(cmd, "READ")) {
    param = expectWord(cb, "Configuration file name");
    if (*param != '\0')
      do_read(cb, param);
  } else if (!strcmp(cmd, "ANNOUNCE")) {
    skip_blanks(cb);
    strsub(announce, cb->buffer, cb->cnfPos, 80);
    cb->cnfPos = 256;
  } else if (!strcmp(cmd, "PENSPS")) {
    for (p = 0; p <= 4; p++)
     *pensPsSearch[p] = '\0';
    p = 1;
    do {
      param = getPlainWord(cb);
      if (*param != '\0') {
      strcpy(pensPsSearch[p - 1], param);}
      else {
       strcpy(pensPsSearch[p - 1], GetChipmunkPath("UNTILPSMAP",UNTILPSMAP));}
      p++;
    } while (p <= 5 && *param != '\0');
  } else if (!strcmp(cmd, "PS-BOUNDING-BOX")) {
    tempBB.xl = expectInt(cb);
    tempBB.yl = expectInt(cb);
    tempBB.xh = expectInt(cb);
    tempBB.yh = expectInt(cb);
    if (!error)
      psBoundingBox = tempBB;
  } else {
    sprintf(STR3, "Unrecognized command: %s", cmd);
    read_error(cb, STR3);
    cb->cnfPos = 256;   /* Do not do parameter check */
  }
  p = cb->cnfPos;
  param = getPlainWord(cb);
  if (*param != '\0') {
    cb->cnfPos = p;
    read_error(cb, "Extra parameters ignored.");
  }
}


Static boolean getInterestingLine(cnfBuf *cb)
{
  Char *TEMP;

  cb->cnfPos = 256;   /* Force read of new line */
  while (cb->cnfPos > strlen(cb->buffer) && !P_eof(cb->cnfFile)) {
    fgets(cb->buffer, 256, cb->cnfFile);
    TEMP = (char *) strchr(cb->buffer, '\n');
    if (TEMP != NULL)
      *TEMP = 0;

    cb->cnfLine++;
    cb->cnfPos = 1;
    skip_blanks(cb);
  }
  return (cb->cnfPos < strlen(cb->buffer));
}


Static void do_read(cnfBuf *ocb, Char *newFile)
{
  cnfBuf newCb;
  Char STR1[138];

  if (newCb.cnfFile = fopen(newFile, "r")) {
    newCb.cnfPos = 255;
    *newCb.buffer = '\0';
    newCb.cnfLine = 0;
    newCb.interactive = false;
    while (getInterestingLine(&newCb))
      parseline(&newCb);
    fclose(newCb.cnfFile);
  }
  else {
    printf(STR1, "Can't read file %s", newFile);
    read_error(ocb, STR1);
  }
}


void readCnf(Char *theFile)
{
  cnfBuf cb;

  cb.cnfFile = NULL;
  cb.cnfPos = 6;
  sprintf(cb.buffer, "read %s { System-Initialization }", theFile);
  cb.cnfLine = 1;
  cb.interactive = false;
  printf("Configuration: %s\n", theFile);
  do_read(&cb, theFile);

}


void readCnfLine(Char *theLine)
{
  cnfBuf cb;
  cb.cnfFile = NULL;
  cb.cnfPos = 1;
  strcpy(cb.buffer, theLine);
  cb.cnfLine = 0;
  cb.interactive = true;
  parseline(&cb);
}

