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.c1157
1 files changed, 549 insertions, 608 deletions
diff --git a/converter/other/fiasco/params.c b/converter/other/fiasco/params.c
index 29f52afc..042a14e2 100644
--- a/converter/other/fiasco/params.c
+++ b/converter/other/fiasco/params.c
@@ -1,8 +1,8 @@
 /*
- *  params.c:		Parameter file and command line parsing
+ *  params.c:           Parameter file and command line parsing
  *
- *  Written by:		Stefan Frank
- *			Ullrich Hafner
+ *  Written by:         Stefan Frank
+ *                      Ullrich Hafner
  *
  *  This file is part of FIASCO (Fractal Image And Sequence COdec)
  *  Copyright (C) 1994-2000 Ullrich Hafner
@@ -22,16 +22,18 @@
 
 #include "config.h"
 
+#include <assert.h>
 #include <stdio.h>
 #include <ctype.h>
-#include <math.h>			/* strtod() on SUN sparc */
+#include <math.h>                       /* strtod() on SUN sparc */
 
 #include <stdlib.h>
 #include <string.h>
 
-#include <getopt.h>			/* system or ../lib */
+#include <getopt.h>                     /* system or ../lib */
 
 #include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
 
 #include "types.h"
@@ -40,627 +42,182 @@
 #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);
+setParameter(param_t *    const parameter,
+             const char * const 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)
+                    pm_message("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)
+           pm_message("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)
+           pm_message("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:
+         pm_error("Invalid parameter type for %s", parameter->name);
+    }
+}
 
-/*****************************************************************************
 
-				public code
 
-*****************************************************************************/
+static int
+getParameterIndex(const param_t * const params,
+                  const char *    const 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;
+        }
+    }
 
-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 command 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]);
-           {
-              /* Kludge for standard Netpbm version announcement */
-              char * modified_argv[2];
-              int argc;
-              modified_argv[0] = argv[0];
-              modified_argv[1] = (char *) "--version";
-              argc = 2;
-              pm_proginit(&argc, (const char **) modified_argv);
-           }
-           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;
+    return index;
 }
 
-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;
+static void
+readParameterFile(param_t * const params,
+                  FILE *    const file) {
+/*----------------------------------------------------------------------------
 
-   return (void *) &(params [pind].value);
-}
+  Read parameter settings from 'file'.
 
-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);
-   }
-}
+  No return value.
 
-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);
-}
+  Side effects:
+      'params [].value' are changed if specified in 'file'
+-----------------------------------------------------------------------------*/
+    char buffer [MAXSTRLEN];
+    int  n = 0;
 
-/*****************************************************************************
+    assert (params && file);
 
-				private code
+    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';
 
-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);
-   }
-}
+        b = strchr (buffer, '=');
+        if (b == NULL)                    /* Strip lines that contain no '=' */
+            continue;
+        *b = '\0';                       /* Replace '=' by string terminator */
 
-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;
+        /* Extract value of parameter */
+        for (value = b + 1; ISSPACE (*value); value++)
+            ;                              /* Delete leading spaces */
 
-   assert (params && search_string);
+        for (b = value + strlen (value) - 1; b >= value && ISSPACE (*b); b--)
+            *b = '\0';                     /* Delete trailing spaces. */
 
-   for (n = 0; params [n].name != NULL; n++)
-      if (strcaseeq (params [n].name, search_string))
-      {
-	 index = n;
-	 break;
-      }
+        /* Extract parameter name */
+        for (name = buffer; ISSPACE (*name); name++)
+            ;                              /* Delete leading spaces */
 
-   return index;
-}
+        for (b = name + strlen (name) - 1; b >= name && ISSPACE (*b); b--)
+            *b = '\0';                     /* Delete trailing spaces. */
 
-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++;
-   }
+        pind = getParameterIndex(params, name);
+        if (pind >= 0)
+            setParameter(&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 executable, '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;
+usage(const param_t *  const params,
+      const char *     const progname,
+      const char *     const synopsis,
+      const char *     const comment,
+      const char *     const non_opt_string,
+      bool_t           const show_all_options,
+      const char *     const sys_file_name,
+      const char *     const usr_file_name) {
+/*----------------------------------------------------------------------------
+
+  Generates and prints command line description from param_t struct 'params'.
+  'progname' is the name of the executable, '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,
@@ -671,9 +228,8 @@ usage (const param_t *params, const char *progname, const char *synopsis,
     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)
-        {
+    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));
@@ -683,10 +239,9 @@ usage (const param_t *params, const char *progname, const char *synopsis,
             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)
-        {
+    }
+    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
@@ -708,8 +263,7 @@ usage (const param_t *params, const char *progname, const char *synopsis,
 
             fprintf (stderr, params [i].use, params [i].argument_name);
 
-            switch (params [i].type)
-            {
+            switch (params [i].type) {
             case PFLAG:
                 break;
             case PINT:
@@ -724,20 +278,407 @@ usage (const param_t *params, const char *progname, const char *synopsis,
                     fprintf (stderr, "{%s}", params [i].value.s);
                 break;
             default:
-                error ("type %d for %s invalid",
-                       params [i].type, params [i].name);
+               pm_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);
 }
 
+
+
+const void *
+parameter_value(const param_t * const params,
+                const char *    const name) {
+/*----------------------------------------------------------------------------
+  Extract value of parameter 'name.' of the given parameters 'params'.
+
+  Return value: value of given parameter
+
+-----------------------------------------------------------------------------*/
+    int pind = getParameterIndex(params, name);
+
+    if (pind < 0)
+        pm_error("Invalid parameter '%s'.", name);
+
+    if (params[pind].type == PSTR || params[pind].type == POSTR)
+        return params[pind].value.s;
+
+    return &(params[pind].value);
+}
+
+
+
+int
+parseargs(param_t *     const usr_params,
+          int argc,
+          const char ** const argv,
+          const char *  const synopsis,
+          const char *  const comment,
+          const char *  const non_opt_string,
+          const char *  const path,
+          const char *  const sys_file_name,
+          const char *  const 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 }
+        };
+    const char * sys_path;                     /* path to system config file */
+
+    pm_asprintf(&sys_path, "%s/%s", path, sys_file_name);
+
+    /* Set parameters defaults */
+    {
+        param_t *p;
+
+        for (p = usr_params; p->name != NULL; p++)
+        {
+            setParameter(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++)
+            setParameter(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++)
+        ;
+    MALLOCARRAY_NOFAIL(params, n1 + n2 + 1);
+
+    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) {
+            readParameterFile(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) {
+            readParameterFile(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;
+
+            MALLOCARRAY_NOFAIL(long_options, n1 + n2 + 1);
+
+            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 command line */
+
+        while ((optchar = getopt_long(argc, (char **)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) {
+                setParameter(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]);
+                    {
+                        /* Kludge for standard Netpbm version announcement */
+                        const char * modifiedArgv[2];
+                        int argc;
+                        modifiedArgv[0] = argv[0];
+                        modifiedArgv[1] = (char *) "--version";
+                        argc = 2;
+                        pm_proginit(&argc, modifiedArgv);
+                    }
+                    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 */
+
+            pm_message("Options set in file `%s' will override"
+                       " command line options.", filename);
+            parameter_file = open_file(filename, NULL, READ_ACCESS);
+            if (parameter_file != NULL) {
+                readParameterFile(params, parameter_file);
+                fclose(parameter_file);
+            } else
+                pm_error("Failed to open config file '%s'", filename);
+        } else
+            pm_error("Invalid config filename.");
+    }
+
+    memcpy(usr_params, params, n1 * sizeof (param_t)); /* fill user struct */
+    pm_strfree(sys_path);
+
+    return optind;
+}
+
+
+
+void
+ask_and_set(param_t *    const params,
+            const char * const name,
+            const char * const 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 = getParameterIndex(params, name);
+
+    if (index < 0)
+        pm_error("Invalid parameter '%s'.", name);
+
+    if (msg)
+        pm_message("%s", msg);
+
+    switch (params[index].type) {
+    case PFLAG:                       /* Unusual, at least. */
+        pm_message("Flags should be initialized and set on demand, "
+                   "not request");
+    case PINT:
+    case PSTR:
+    case POSTR:
+    case PFLOAT:
+        scanf(MAXSTRLEN_SCANF, answer);
+        setParameter(&params [index], answer);
+        break;
+    default:
+        pm_error("Invalid parameter type for %s", name);
+    }
+}
+
+
+
+void
+write_parameters(const param_t * const params,
+                 FILE *          const output) {
+/*----------------------------------------------------------------------------
+  Write all parameter settings to 'output'.
+
+  No return value.
+-----------------------------------------------------------------------------*/
+    unsigned int pind;
+
+    if (!params || !output)
+        pm_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:
+            pm_error("Invalid type %d for parameter %s",
+                     params[pind].type, params[pind].name);
+        }
+    }
+    fputc ('\n', output);
+}
+
+
+