/*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
 *
 *  Copyright (C) 1995  Koen Gadeyne
 *
 *  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; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */


/***
 *** configfile.c: funtions to process config file, and some more general parsing functions
 *** (c) 1995 Koen Gadeyne (kmg@barco.be)
 ***
 ***/
 
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include "misc.h"
#include "configfile.h"
#include "messages.h"


void cleanupstring(char *tstring)
{
     char *p=tstring;
     while (*p) 
     {
        switch (*p)
          {
             case '#':              /* discard remarks */
             case '\n': *p = '\0';  /* convert \n terminated strings to \0 terminated ones */
                        break;
             case '\t':             /* TABS to spaces */
             case '"': *p = ' ';    /* convert " (quotes) to spaces */
                       break;
          }
          if (*p == '\0') break;    /* stop processing */
          p++;
     }
}

char* findlabel(FILE* inputfile, char* reqlabel, int options)
 /* look for 'reqlabel' in config file, exit if not found */
{
   static char video_param_str[1024];
   char temp_param_str[1024];
   char inlabel[256];
   int nfound=1;
   int foundone=0;
   int required=(options&LABEL_REQUIRED);
   int fromstart=(options&LABEL_FROMSTART);
   int findlast=(options&LABEL_LAST);
   
   PDEBUG(("findlabel: Looking for %s %s label '%s' from %s Configfile",
            (findlast) ? "last" : "first",
            (required) ? "required" : "optional",
            reqlabel,
            (fromstart) ? "start of" : "curr. pos. in"));
   if (fromstart) rewind(inputfile);
   do
   {
     nfound = 1;
     while ( (fgets(temp_param_str,1024,inputfile) != NULL) && (!feof(inputfile)) )   /* look for requested line */
     {
        strcpy(inlabel,""); /* avoid empty lines from leaving previous result in inlabel */
        cleanupstring(temp_param_str);
        sscanf(temp_param_str, "%s",inlabel);
        nfound = strcasecmp(inlabel,reqlabel);
        if (!nfound) break;
     }
     if (!nfound)
     {
       PDEBUG(("findlabel: found the following '%s' line:\n --> %s", reqlabel, temp_param_str));
       foundone=1;  /* remember if we already found a line (for "LAST" function) */
       strcpy(video_param_str, temp_param_str);
     }
   } while (findlast && !nfound);
   
   if (nfound && !foundone)
   {
     if (required) PERROR(("Could not find required '%s' line in config file. Aborting...",reqlabel));
     PDEBUG(("findlabel: no (more) optional '%s' line found", reqlabel));
     return(NULL);
   }
   else return(video_param_str);
}


FILE* open_param_file(char* conf_file)
{
  FILE* param_file;
  PDEBUG(("Opening config file '%s'",conf_file));
  if ((param_file = fopen(conf_file,"r")) == NULL)
  {
      perror("fopen");
      PERROR(("Could not open Text mode config file '%s'",conf_file));
  }
  return(param_file);
}


char* showopts(const char* optstrings[], int num_optstrings)
{
  int i;
  static char optionstring[256];
  for (i=0; i<num_optstrings; i++)
  {
     strcat(optionstring, optstrings[i]);
     strcat(optionstring, (i==num_optstrings-1) ? "." : ", ");
  }
  return optionstring;
}


int findoption(char* inputstr, const char* optstrings[], int num_optstrings, char* optiontype)
{
  /* look which option string from given list matches input string, return option number, or exit when not found */
  int i, foundindex=-1;
  PDEBUG(("findoption: Looking for one out of %d %s string(s) in '%s'",num_optstrings, optiontype, inputstr));
  for (i=0; i<num_optstrings; i++) { if (!strcasecmp(inputstr,optstrings[i])) foundindex=i; };
  if ((foundindex < 0) || (foundindex > num_optstrings))
    PERROR(("Unknown %s definition '%s'.
     Valid %s definitions are: %s ",optiontype, inputstr, optiontype, showopts(optstrings, num_optstrings)));
  PDEBUG(("findoption: Selecting %s #%d = %s", optiontype, foundindex, optstrings[foundindex]));
  return(foundindex);
}


void check_int_range(int cvalue, int lmin, int lmax, char* descstr)
{
  if (cvalue<lmin || cvalue>lmax)
    PERROR(("%s = %d (0x%x) out of range [%d..%d]!", descstr, cvalue, cvalue, lmin, lmax));
}

int getbyte(char* instring, char* descrstring, int lmin, int lmax)
  /* convert the byte in 'instring' into an integer. Must be within specified limits 'lmin' and 'lmax' */
  /* 'descrstring' contains a description of the number to be parsed, used in error message */
{
  char** errstr=NULL;
  int readbyte;
  readbyte = strtol(instring,errstr,0);
  if (errstr != NULL) PERROR(("Illegal character '%c' in %s: '%s'", *errstr, descrstring, instring));
  check_int_range(readbyte, lmin, lmax, descrstring);
  return(readbyte);
}

float getfloat(char* instring, char* descrstring, int lmin, int lmax)
  /* convert the float in 'instring' into a float. Must be within specified INTEGER limits 'lmin' and 'lmax' */
  /* 'descrstring' contains a description of the number to be parsed, used in error message */
{
  char** errstr=NULL;
  double readfloat;
  readfloat = strtod(instring,errstr);
  if (errstr != NULL) PERROR(("Illegal character '%c' in %s: '%s'", *errstr, descrstring, instring));
  check_int_range(readfloat, lmin, lmax, descrstring);
  return((float)readfloat);
}


int GetPathOption(FILE *param_file, char *optionstring, int label_config, char *path)
/* look for certain path-related options in config file */
{ 
  char *arg_str;

  arg_str = findlabel(param_file, optionstring, label_config);
  if (arg_str)
  {
    strtok(arg_str," ");
    if ((arg_str=strtok(NULL," ")) == NULL) PERROR(("%s: pathname not defined", optionstring));
    strcpy(path, arg_str);
    PDEBUG(("Using %s '%s'",optionstring , path));
    return(TRUE);
  } 
  return(FALSE);   /* no path option found */
}

void ParseFontXY(char *inputstr, int *x, int*y)
{
  if (sscanf(inputstr, "%dx%d", x, y) < 2)
    PERROR(("Illegal font size specification '%s'", inputstr));
  check_int_range(*x, 8, 9, "font width");
  check_int_range(*y, 1, 32, "font height");
}


void get_range(FILE *param_file, char* descrline, float range[MAX_RANGE_SPECS][2], char* textdescr, int dfltmin, int dfltmax)
  /* will parse the sync range lines from Config File and create a {0,0} terminated sequence of 
     allowable ranges in the range[][] array */
{
  float start, end;
  int num;
  char *arg_str;
  int rangepos=0;

  if (strtok(findlabel(param_file, descrline, LABEL_OPTIONAL+LABEL_FROMSTART)," ") != NULL)
  {
    if ((arg_str=strtok(NULL,",")) == NULL)
      PERROR(("'%s' line in config file: empty line.", descrline));
      
    /* find boundaries, separated by commas, allowing spaces in between the range specifications. */
    do
    {
      if ((num = sscanf(arg_str, "%f%*[ -]%f", &start, &end)) < 1) 
        PERROR(("%s: Must define <start>-<end> pairs or single values separated by comma's", descrline));
      check_int_range(start, 5.0, 200.0, descrline);
      if (num==1)
      {
        end = start+FRMARGIN;
        start -= FRMARGIN;
      }
      else check_int_range(end, 5.0, 200.0, descrline);
    range[rangepos][0] = start;
    range[rangepos][1] = end;
    rangepos++;
    }
    while (((arg_str=strtok(NULL,",")) != NULL) && (rangepos<MAX_RANGE_SPECS));
  }
  else
  {
    range[rangepos][0] = dfltmin;
    range[rangepos][1] = dfltmax;
    rangepos++;
  }
  range[rangepos][0] = 0;
  range[rangepos][1] = 0;
}

