about summary refs log tree commit diff
path: root/converter/other/fiasco/params.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/fiasco/params.c')
-rw-r--r--converter/other/fiasco/params.c727
1 files changed, 727 insertions, 0 deletions
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
new file mode 100644
index 00000000..3d0a0252
--- /dev/null
+++ b/converter/other/fiasco/params.c
@@ -0,0 +1,727 @@
+/*
+ *  params.c:		Parameter file and command line parsing
+ *
+ *  Written by:		Stefan Frank
+ *			Ullrich Hafner
+ *		
+ *  This file is part of FIASCO («F»ractal «I»mage «A»nd «S»equence «CO»dec)
+ *  Copyright (C) 1994-2000 Ullrich Hafner <hafner@bigfoot.de>
+ */
+
+/*
+ *  $Date: 2000/07/15 17:24:21 $
+ *  $Author: hafner $
+ *  $Revision: 5.2 $
+ *  $State: Exp $
+ */
+
+#define _BSD_SOURCE 1   /* Make sure strdup() is in string.h */
+#define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>			/* strtod() on SUN sparc */
+
+#include <stdlib.h>
+#include <string.h>
+ 
+#include <getopt.h>			/* system or ../lib */
+
+#include "nstring.h"
+
+#include "types.h"
+#include "macros.h"
+#include "bit-io.h"
+#include "misc.h"
+#include "fiasco.h"
+
+#include "binerror.h"
+
+#include "params.h"
+
+/*****************************************************************************
+
+				prototypes
+  
+*****************************************************************************/
+
+static void
+read_parameter_file (param_t *params, FILE *file);
+static int
+get_parameter_index (const param_t *params, const char *search_string);
+static void
+set_parameter (param_t *parameter, const char *value);
+static void 
+usage (const param_t *params, const char *progname, const char *synopsis,
+       const char *comment, const char *non_opt_string,
+       bool_t show_all_options, const char *sys_file_name,
+       const char *usr_file_name);
+
+/*****************************************************************************
+
+				public code
+  
+*****************************************************************************/
+
+int
+parseargs (param_t *usr_params, 
+           int argc, char **argv, 
+           const char *synopsis,
+           const char *comment, 
+           const char *non_opt_string, 
+           const char *path,
+           const char *sys_file_name, 
+           const char *usr_file_name)
+/*
+ *  Perform the command line parsing.
+ *  List of allowed parameters is given by 'usr_params'.
+ *  Command line and number of parameters are given by 'argv' and 'argc'.
+ *  'synopsis' contains a brief description of the program and
+ *  'comment' may contain some additional advice.
+ *  Initialization order of parameters:
+ *	1.) Default values given by the param_t struct
+ *	2.) System parameter-file ('path'/'sys_file_name')
+ *	3.) User parameter-file ($HOME/'usr_file_name')
+ *	4.) Command line parameters
+ *	5.) Parameter-file forced by option -f (--config-file)
+ *
+ *  Return value:
+ *	index in ARGV of the first ARGV-element that is not an option.
+ *
+ *  Side effects:
+ *	the elements of ARGV are permuted
+ *      usr_params [].value is modified 
+ */
+{
+   extern int optind;			/* index in ARGV of the 1st element
+					   that is not an option */
+   bool_t     detailed_help = NO;	/* NO if all parameters can be modified
+					   with short options too */
+   unsigned   n1;			/* number of user parameters */
+   unsigned   n2;			/* number of system parameters */
+   bool_t     read_config_file = NO;	/* will override command line */
+   param_t    *params;			/* array of user and system params */
+   param_t    *sys_params;		/* array of system parameters */
+   param_t    detailed_sys_params [] =  /* detailed system parameters */
+   {
+      {"version", NULL, 'v', PFLAG, {0}, NULL,
+       "Print program version number, then exit."},
+      {"verbose", "NUM", 'V', PINT, {0}, "1",
+       "Set level of verbosity to `%s'."},
+      {"config", "FILE", 'f', PSTR, {0}, NULL,
+       "Load `%s' to initialize parameters."},
+      {"info", NULL, 'h', PFLAG, {0}, NULL,
+       "Print brief help, then exit."},
+      {"help", NULL, 'H', PFLAG, {0}, NULL,
+       "Print detailed help, then exit."},
+      {NULL, NULL, 0, PSTR, {0}, NULL, NULL }
+   };
+   param_t    short_sys_params [] =	/* short system parameters */
+   {
+      {"version", NULL, 'v', PFLAG, {0}, NULL,
+       "Print program version number, then exit."},
+      {"verbose", "NUM", 'V', PINT, {0}, "1",
+       "Set level of verbosity to `%s'."},
+      {"config", "FILE", 'f', PSTR, {0}, NULL,
+       "Load `%s' to initialize parameters."},
+      {"help", NULL, 'h', PFLAG, {0}, NULL,
+       "Print this help, then exit."},
+      {NULL, NULL, 0, PSTR, {0}, NULL, NULL }
+   };
+   char *sys_path;			/* path to system config file */
+
+   sys_path = calloc (strlen (path) + strlen (sys_file_name) + 2,
+		      sizeof (char));
+   if (!sys_path)
+      error ("Out of memory.");
+   sprintf (sys_path, "%s/%s", path, sys_file_name);
+
+   /*
+    *  Set parameters defaults
+    */
+   {
+       param_t *p;
+      
+       for (p = usr_params; p->name != NULL; p++)
+       {
+           set_parameter (p, p->default_value);
+           if (p->optchar == '\0')
+               detailed_help = YES;
+       }
+
+      sys_params = detailed_help ? detailed_sys_params : short_sys_params;
+      
+      for (p = sys_params; p->name != NULL; p++)
+          set_parameter (p, p->default_value);
+   }
+   /*
+    *  Append system command line option to user parameters
+    */
+   for (n1 = 0; usr_params [n1].name != NULL; n1++)
+      ;
+   for (n2 = 0; sys_params [n2].name != NULL; n2++)
+      ;
+   params = calloc (n1 + n2 + 1, sizeof (param_t));
+   if (!params)
+      error ("Out of memory.");
+
+   memcpy (params, usr_params, n1 * sizeof (param_t));
+   memcpy (params + n1, sys_params, (n2 + 1) * sizeof (param_t));
+   /*
+    *  Try to open the system resource file 'path'/'sys_file_name'
+    */
+   {
+      FILE *parameter_file = open_file (sys_path, NULL, READ_ACCESS);
+      if (parameter_file == NULL)
+/*
+	 warning ("No system resource file found.");
+*/ {}
+      else
+      {
+	 read_parameter_file (params, parameter_file);
+	 fclose (parameter_file);
+      }
+   }
+   /*
+    *  Try to read user resource file $HOME/'usr_file_name'
+    */
+   {
+      FILE *parameter_file = open_file (usr_file_name, "HOME", READ_ACCESS);
+      if (parameter_file != NULL)
+      {
+	 read_parameter_file (params, parameter_file);
+	 fclose (parameter_file);
+      }
+   }
+   /*
+    *  Parse command line options
+    */
+   {
+      extern char   *optarg;		/* argument of current option */
+      struct option *long_options;	/* array of long options */
+      int	     option_index = 0;
+      char	     optstr [MAXSTRLEN]; /* string containing the legitimate
+					    option characters */
+      int	     optchar;		/* found option character */
+
+      /*
+       *  Build short option string for getopt_long (). 
+       */
+      {
+	 param_t *p;			/* counter */
+	 char	 *ptr_optstr;		/* pointer to position in string */
+	 
+	 ptr_optstr = optstr;
+	 for (p = params; p->name != NULL; p++)
+	    if (p->optchar != '\0')
+	    {
+	       *ptr_optstr++ = p->optchar;
+	       if (p->type == POSTR)
+	       {
+		  *ptr_optstr++ = ':';
+		  *ptr_optstr++ = ':';
+	       }
+	       else if (p->type != PFLAG)
+		  *ptr_optstr++ = ':';
+	    }
+	 *ptr_optstr = '\0';
+      }
+      
+      /*
+       *  Build long option string for getopt_long (). 
+       */
+      {
+	 int i;
+	 
+	 long_options = calloc (n1 + n2 + 1, sizeof (struct option));
+	 if (!long_options)
+	    error ("Out of memory.");
+	 for (i = 0; params [i].name != NULL; i++)
+	 {
+	    long_options [i].name    = params [i].name;
+	    switch (params [i].type)
+	    {
+	       case PFLAG:
+		  long_options [i].has_arg = 0;
+		  break;
+	       case POSTR:
+		  long_options [i].has_arg = 2;
+		  break;
+	       case PINT:
+	       case PSTR:
+	       case PFLOAT:
+	       default:
+		  long_options [i].has_arg = 1;
+		  break;
+	    }
+	    long_options [i].has_arg = params [i].type != PFLAG;
+	    long_options [i].flag    = NULL;
+	    long_options [i].val     = 0;
+	 }
+      }
+      
+      /*
+       *  Parse comand line
+       */
+      while ((optchar = getopt_long (argc, argv, optstr, long_options,
+				     &option_index)) != EOF)
+      {
+	 int param_index = -1;
+	 
+	 switch (optchar)
+	 {
+	    case 0:
+	       param_index = option_index;
+	       break;
+	    case ':':
+	       if (detailed_help)
+		  fprintf (stderr,
+			   "Try `%s -h' or `%s --help' for "
+			   "more information.\n",
+			   argv [0], argv [0]);
+	       else
+		  fprintf (stderr, "Try `%s --help' for more information.\n",
+			   argv [0]);
+	       exit (2);
+	       break;
+	    case '?':
+	       if (detailed_help)
+		  fprintf (stderr,
+			   "Try `%s -h' or `%s --help' "
+			   "for more information.\n",
+			   argv [0], argv [0]);
+	       else
+		  fprintf (stderr, "Try `%s --help' for more information.\n",
+			   argv [0]);
+	       exit (2);
+	       break;
+	    default:
+	       {
+		  int i;
+		  
+		  for (i = 0; params [i].name != NULL; i++)
+		     if (params [i].optchar == optchar)
+		     {
+			param_index = i;
+			break;
+		     }
+	       }
+	 }
+	 /*
+	  *  Check for system options
+	  */
+	 if (param_index >= 0)
+	 {
+	    set_parameter (params + param_index, optarg ? optarg : "");
+	    if (streq (params [param_index].name, "help"))
+	       usage (params, argv [0], synopsis, comment, non_opt_string,
+		      YES, sys_path, usr_file_name);
+	    else if (streq (params [param_index].name, "info"))
+	       usage (params, argv [0], synopsis, comment, non_opt_string,
+		      NO, sys_path, usr_file_name);
+	    else if (streq (params [param_index].name, "version"))
+	    {
+	       fprintf (stderr, "%s " VERSION "\n", argv [0]);
+	       exit (2);
+	    }
+	    else if (streq (params [param_index].name, "verbose"))
+	       fiasco_set_verbosity (
+               * (fiasco_verbosity_e *) parameter_value (params,
+                                                         "verbose"));
+	    else if (streq (params [param_index].name, "config"))
+	       read_config_file = YES;
+	    param_index = -1;		/* clear index flag */
+	 }
+      }
+
+      free (long_options);
+   }
+   
+   /*
+    *  Read config-file if specified by option -f
+    */
+   if (read_config_file)
+   {
+      char *filename;
+
+      if ((filename = (char *) parameter_value (params, "config")) != NULL)
+      {
+	 FILE *parameter_file;		/* input file */
+	 
+	 warning ("Options set in file `%s' will override"
+		  " command line options.", filename);
+	 parameter_file = open_file (filename, NULL, READ_ACCESS);
+	 if (parameter_file != NULL)
+	 {
+	    read_parameter_file (params, parameter_file);
+	    fclose (parameter_file);
+	 }
+	 else
+	    file_error (filename);
+      }
+      else
+	 error ("Invalid config filename.");
+   }
+
+   memcpy (usr_params, params, n1 * sizeof (param_t)); /* fill user struct */
+   free (sys_path);
+   
+   return optind;
+}
+ 
+void *
+parameter_value (const param_t *params, const char *name)
+/*
+ *  Extract value of parameter 'name.' of the given parameters 'params'.
+ *
+ *  Return value:
+ *	value of given parameter
+ */
+{
+   int pind = get_parameter_index (params, name);
+
+   if (pind < 0)
+      error ("Invalid parameter `%s'.", name);
+
+   if (params [pind].type == PSTR || params [pind].type == POSTR)
+      return (void *) params [pind].value.s;
+      
+   return (void *) &(params [pind].value);
+}
+
+void
+ask_and_set (param_t *params, const char *name, const char *msg)
+/*
+ *  Ask user (print given message 'msg') for missing mandatory
+ *  parameter 'name' of the given parameters 'params'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'params ['name'].value' is changed
+ */
+{ 
+   char answer [MAXSTRLEN];
+   int  index = get_parameter_index (params, name);
+
+   if (index < 0)
+      error ("Invalid parameter %s.", name);
+
+   if (msg)
+      fprintf (stderr, "%s\n", msg);
+  
+   switch (params [index].type)
+   {
+      case PFLAG:			/* Unusual, at least. */
+	 warning ("Flags should be initialized and set on demand, "
+		  "not request");
+      case PINT:
+      case PSTR:
+      case POSTR:
+      case PFLOAT:
+	 scanf (MAXSTRLEN_SCANF, answer);
+	 set_parameter (&params [index], answer);
+	 break;
+      default:
+	 error ("Invalid parameter type for %s", name);
+   }
+} 
+
+void
+write_parameters (const param_t *params, FILE *output)
+/*
+ *  Write all parameter settings to 'output'.
+ *
+ *  No return value.
+ */
+{
+   int pind;
+
+   if (!params || !output)
+      error ("Parameters must be not NULL.");
+
+   for (pind = 0; params [pind].name != NULL; pind++)
+   {
+      fprintf (output, "# %s = ", params [pind].name);
+      switch (params [pind].type)
+      {
+	 case PFLAG:
+	    fprintf (output, "%s\n", params [pind].value.b ? "TRUE" : "FALSE");
+	    break;
+	 case PINT:
+	    fprintf (output, "%d\n", params [pind].value.i);
+	    break;
+	 case PFLOAT:
+	    fprintf (output, "%.4f\n", (double) params [pind].value.f);
+	    break;
+	 case PSTR:
+	 case POSTR:
+	    fprintf (output, "%s\n", params [pind].value.s);
+	    break;
+	 default:
+	    error ("Invalid type %d for parameter %s",
+		   params [pind].type, params [pind].name);
+      }
+   }
+   fputc ('\n', output);
+}
+
+/*****************************************************************************
+
+				private code
+  
+*****************************************************************************/
+
+static void
+set_parameter (param_t *parameter, const char *value)
+/*
+ *  Set value of 'parameter' to 'value'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'parameter.value' is changed accordingly
+ */
+{
+   assert (parameter);
+   
+   switch (parameter->type)
+   {
+      case PFLAG:
+	 if (value != NULL && *value != '\0')
+	 {
+	    if (strcaseeq (value, "TRUE"))
+	       parameter->value.b = YES;
+	    else if (strcaseeq (value, "FALSE"))
+	       parameter->value.b = NO;
+	    else if (strcaseeq (value, "YES"))
+	       parameter->value.b = YES;
+	    else if (strcaseeq (value, "NO"))
+	       parameter->value.b = NO;
+	    else
+	    {
+	       long int	data;
+	       char	*endptr;
+	    
+	       data = strtol (value, &endptr, 0);
+	       if (*endptr != '\0' || endptr == value)
+		  warning ("Invalid value `%s' converted to %d",
+			   value, (int) data);
+	       parameter->value.b = data ? YES : NO;
+	    }
+	 }
+	 else
+	    parameter->value.b = !parameter->value.b;
+	 break;
+      case PINT:
+	 {
+	    long int  data;
+	    char     *endptr;
+	    
+	    data = strtol (value, &endptr, 0);
+	    if (*endptr != '\0' || endptr == value)
+	       warning ("Invalid value `%s' converted to %d",
+			value, (int) data);
+	    parameter->value.i = data;
+	 }
+	 break;
+      case PFLOAT:
+	 {
+	    double	data;
+	    char	*endptr;
+	    
+	    data = strtod (value, &endptr);
+	    if (*endptr != '\0' || endptr == value)
+	       warning ("Invalid value `%s' converted to %f",
+			value, (double) data);
+	    parameter->value.f = data;
+	 }
+	 break;
+      case PSTR:
+      case POSTR:
+	 parameter->value.s = value ? strdup (value) : NULL;
+	 break;
+      default:				
+	 error ("Invalid parameter type for %s", parameter->name);
+   }
+}
+
+static int
+get_parameter_index (const param_t *params, const char *search_string)
+/*
+ *  Search for parameter with name 'search_string' in parameter struct.
+ *
+ *  Return value:
+ *	index of parameter or -1 if no matching parameter has been found
+ */
+{
+   int n;
+   int index = -1;
+
+   assert (params && search_string);
+
+   for (n = 0; params [n].name != NULL; n++)
+      if (strcaseeq (params [n].name, search_string))
+      {
+	 index = n;
+	 break;
+      }
+
+   return index;
+}
+
+static void
+read_parameter_file (param_t *params, FILE *file)
+/*
+ *  Read parameter settings from 'file'.
+ *
+ *  No return value.
+ *
+ *  Side effects:
+ *	'params [].value' are changed if specified in 'file'
+ */
+{
+   char buffer [MAXSTRLEN];
+   int  n = 0;
+
+   assert (params && file);
+
+   while (fgets (buffer, MAXSTRLEN, file) != NULL)
+   {
+      char *b;				/* temporary variable */
+      char *name;			/* parameter name */
+      char *value;			/* parameter value */
+      int   pind;			/* current argument number */
+      
+      b = strchr (buffer, '#');
+      if (b != NULL)			/* Strip comments. */
+	 *b = '\0';
+
+      b = strchr (buffer, '=');
+      if (b == NULL)			/* Strip lines that contain no '=' */
+	 continue;
+      *b = '\0';			/* Replace '=' by string terminator */
+
+      /*
+       *  Extract value of parameter
+       */
+      for (value = b + 1; ISSPACE (*value); value++) 
+	 ;				/* Delete leading spaces */
+
+      for (b = value + strlen (value) - 1; b >= value && ISSPACE (*b); b--)
+	 *b = '\0';			/* Delete trailing spaces. */
+
+      /*
+       *  Extract parameter name
+       */
+      for (name = buffer; ISSPACE (*name); name++) 
+	 ;				/* Delete leading spaces */
+
+      for (b = name + strlen (name) - 1; b >= name && ISSPACE (*b); b--)
+	 *b = '\0';			/* Delete trailing spaces. */
+
+      pind = get_parameter_index (params, name);
+      if (pind >= 0)
+	 set_parameter (&params [pind], value);
+      
+      n++;
+   }
+}   
+
+static void 
+usage (const param_t *params, const char *progname, const char *synopsis,
+       const char *comment, const char *non_opt_string,
+       bool_t show_all_options, const char *sys_file_name,
+       const char *usr_file_name)
+/*
+ *  Generates and prints command line description from param_t struct 'params'.
+ *  'progname' is the name of the excecutable, 'synopsis' a short program
+ *  description, and 'comment' some more advice.
+ *  If flag 'show_all_options' is set then print also options that are not
+ *  associated with a short option character.
+ *  'sys_file_name' and 'usr_file_name' are filenames to parameter files.
+ *
+ *  No return value.
+ */
+{
+   int	  i;
+   size_t width = 0;
+   
+   fprintf (stderr, "Usage: %s [OPTION]...%s\n", progname,
+	    non_opt_string ? non_opt_string : " ");
+   if (synopsis != NULL)
+      fprintf (stderr, synopsis);
+   fprintf (stderr, "\n\n");
+   fprintf (stderr, "Mandatory or optional arguments to long options "
+	    "are mandatory or optional\nfor short options too. "
+	    "Default values are surrounded by {}.\n");
+   for (i = 0; params [i].name != NULL; i++)
+      if (params [i].optchar != '\0' || show_all_options)
+      {
+	 if (params [i].type == POSTR)
+	    width = max (width, (strlen (params [i].name)
+				 + strlen (params [i].argument_name) + 2));
+	 else if (params [i].type != PFLAG)
+	    width = max (width, (strlen (params [i].name)
+				 + strlen (params [i].argument_name)));
+	 else
+	    width = max (width, (strlen (params [i].name)) - 1);
+      }
+   
+   for (i = 0; params [i].name != NULL; i++)
+      if (params [i].optchar != '\0' || show_all_options)
+      {
+	 if (params [i].optchar != '\0')
+	    fprintf (stderr, "  -%c, --", params [i].optchar);
+	 else
+	    fprintf (stderr, "      --");
+	 
+	 if (params [i].type == POSTR)
+	    fprintf (stderr, "%s=[%s]%-*s  ", params [i].name,
+		     params [i].argument_name,
+		     max (0, (width - 2 - strlen (params [i].name)
+			   - strlen (params [i].argument_name))), "");
+	 else if (params [i].type != PFLAG)
+	    fprintf (stderr, "%s=%-*s  ", params [i].name,
+		  width - strlen (params [i].name),
+		  params [i].argument_name);
+	 else
+	    fprintf (stderr, "%-*s  ", width + 1, params [i].name);
+
+	 fprintf (stderr, params [i].use, params [i].argument_name);
+	 
+	 switch (params [i].type)
+	 {
+	    case PFLAG:
+	       break;
+	    case PINT:
+	       fprintf (stderr, "{%d}", params [i].value.i);
+	       break;
+	    case PFLOAT:
+	       fprintf (stderr, "{%.2f}", (double) params [i].value.f);
+	       break;
+	    case PSTR:
+	    case POSTR:
+	       if (params [i].value.s)
+		  fprintf (stderr, "{%s}", params [i].value.s);
+	       break;
+	    default:
+	       error ("type %d for %s invalid",
+		      params [i].type, params [i].name);
+	 }
+	 fprintf (stderr, "\n");
+      }
+   fprintf (stderr, "\n");
+   fprintf (stderr, "Parameter initialization order:\n");
+   fprintf (stderr,
+	    "1.) %s\n2.) $HOME/%s\t 3.) command line\t 4.) --config=file",
+	    sys_file_name, usr_file_name);
+   fprintf (stderr, "\n\n");
+   if (comment != NULL)
+      fprintf (stderr, "%s\n", comment);
+
+   exit (1);
+}
+