| summaryrefslogtreecommitdiff | 
diff options
Diffstat (limited to 'src/config')
| -rw-r--r-- | src/config/config_file.c | 821 | ||||
| -rw-r--r-- | src/config/parameters.c | 287 | 
2 files changed, 1108 insertions, 0 deletions
| diff --git a/src/config/config_file.c b/src/config/config_file.c new file mode 100644 index 0000000..ad060a5 --- /dev/null +++ b/src/config/config_file.c @@ -0,0 +1,821 @@ +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> + +#include <sys/time.h> + +#include "error.h" +#include "pervasive.h" +#include "axis.h" +#include "config.h" + +#ifndef RELABSD_OPTION_MAX_SIZE +   #define RELABSD_OPTION_MAX_SIZE 64 +#endif +/* + * "errno is never set to zero by any system call or library function." + * This file makes use of this, by setting it to zero and checking if + * it was modified after calling an function (I'm guessing this is common + * practice, but I think it's worth explaining). + * Following the principle of least astonishment, if a function sets errno to + * zero, it will not return before setting it back either to its previous + * value or to a arbitrary nonzero value. + */ + +/* + * Returns -1 on (fatal) error, + *          0 on EOF, + *          1 on newline. + */ +static int reach_next_line_or_eof (FILE * const f) +{ +   int prev_errno; +   char c; + +   prev_errno = errno; + +   errno = 0; + +   c = (char) getc(f); + +   while ((c != '\n') && c != EOF) +   { +      c = (char) getc(f); +   } + +   if (errno != 0) +   { +      RELABSD_FATAL +      ( +         "[CONFIG] Error while attempting to reach EOF or next line: %s.", +         strerror(errno) +      ); + +      errno = prev_errno; + +      return -1; +   } + +   errno = prev_errno; + +   if (c == EOF) +   { +      return 0; +   } + +   return 1; +} + +/* + * Returns -1 if the option was discarded (an error has been reported), + *         0 if the option was successfully parsed. + * + * ('length' - 1) is the number of relevant characters in 'name'. + * 'name' must support 'length' characters. + * name[length] will be set to \0, so it does not need to be when calling + * this function. + */ +static int parse_option +( +   struct relabsd_config * const conf, +   enum relabsd_axis const axis, +   char * const name, +   int const length +) +{ +   name[length] = '\0'; + +   if (strcmp(name, "direct") == 0) +   { +      conf->axis[axis].option[RELABSD_DIRECT_OPTION] = 1; + +      RELABSD_DEBUG +      ( +         RELABSD_DEBUG_CONFIG, +         "Axis '%s' enabled option 'direct'.", +         relabsd_axis_to_name(axis) +      ); + +      if (conf->axis[axis].option[RELABSD_FRAMED_OPTION]) +      { +         RELABSD_WARNING +         ( +            "[CONFIG] Axis '%s': using option 'direct' discards option" +            "'framed'.", +            relabsd_axis_to_name(axis) +         ); +      } +   } +   else if (strcmp(name, "real_fuzz") == 0) +   { +      conf->axis[axis].option[RELABSD_REAL_FUZZ_OPTION] = 1; + +      RELABSD_DEBUG +      ( +         RELABSD_DEBUG_CONFIG, +         "Axis '%s' enabled option 'real_fuzz'.", +         relabsd_axis_to_name(axis) +      ); +   } +   else if (strcmp(name, "framed") == 0) +   { +      conf->axis[axis].option[RELABSD_FRAMED_OPTION] = 1; + +      RELABSD_DEBUG +      ( +         RELABSD_DEBUG_CONFIG, +         "Axis '%s' enabled option 'framed'.", +         relabsd_axis_to_name(axis) +      ); + +      if (conf->axis[axis].option[RELABSD_DIRECT_OPTION]) +      { +         RELABSD_WARNING +         ( +            "[CONFIG] Axis '%s': using option 'direct' discards option" +            "'framed'.", +            relabsd_axis_to_name(axis) +         ); +      } +   } +   else +   { +      RELABSD_ERROR +      ( +         "[CONFIG] Unknown option '%s' for axis '%s'.", +         name, +         relabsd_axis_to_name(axis) +      ); + +      return -1; +   } + +   return 0; +} + +/* + * Returns -1 on error, + *          0 on EOF, + *          1 on newline. + */ +static int read_axis_options +( +   struct relabsd_config * const conf, +   FILE * const f, +   enum relabsd_axis const axis +) +{ +   char option[(RELABSD_OPTION_MAX_SIZE + 1)]; +   int i, prev_errno; +   char c; + +   option[RELABSD_OPTION_MAX_SIZE] = '\0'; + +   prev_errno = errno; + +   errno = 0; + +   memset(conf->axis[axis].option, 0, RELABSD_OPTIONS_COUNT * sizeof(int)); + +   i = 0; + +   while (i <= RELABSD_OPTION_MAX_SIZE) +   { +      c = (char) getc(f); + +      if ((errno != 0) && (c == EOF)) +      { +         RELABSD_FATAL +         ( +            "[CONFIG] Reading error while parsing option name (axis '%s'): %s.", +            relabsd_axis_to_name(axis), +            strerror(errno) +         ); + +         errno = prev_errno; + +         return -1; +      } + +      switch (c) +      { +         case ' ': +         case '\t': +            break; + +         case ',': +            /* We parsed a new option and there is a least another. */ +            parse_option(conf, axis, option, i); + +            i = 0; + +            break; + +         case '\n': +            parse_option(conf, axis, option, i); +            errno = prev_errno; + +            return 1; + +         case EOF: +            parse_option(conf, axis, option, i); +            errno = prev_errno; + +            return 0; + +         default: +            option[i] = c; +            i++; + +            break; +      } +   } + +   RELABSD_FATAL +   ( +      "[CONFIG] Option name '%s[...]' (axis '%s') is too long (%d chars max).", +      option, +      relabsd_axis_to_name(axis), +      RELABSD_OPTION_MAX_SIZE +   ); + +   return -1; +} + +static int parse_timeout_option +( +   struct relabsd_config * const conf, +   const char * const param +) +{ +   int timeout_msec; +   const int prev_errno = errno; + +   conf->enable_timeout = 1; + +   errno = 0; + +   timeout_msec = atoi(param); + +   if (timeout_msec <= 0) +   { +      RELABSD_FATAL +      ( +         "Illegal value for timeout \"%d\": accepted range is [1, %d].", +         timeout_msec, +         INT_MAX +      ); + +      return -1; +   } + +   memset((void *) &(conf->timeout), 0, sizeof(struct timeval)); + +   conf->timeout.tv_sec = (time_t) (timeout_msec / 1000); + +   conf->timeout.tv_usec = +      ( +         ((suseconds_t) timeout_msec) +         * ((suseconds_t) 1000) +      ); + +   return 0; +} + +/* + * Returns -1 on (fatal) error, + *          0 on succes. + */ +static int parse_axis_configuration_line +( +   struct relabsd_config * const conf, +   FILE * const f, +   const char * const buffer +) +{ +   int valc, prev_errno; +   enum relabsd_axis axis; + +   axis = relabsd_axis_from_name(buffer); + +   if (axis == RELABSD_UNKNOWN) +   { +      RELABSD_FATAL +      ( +         "[CONFIG] Unknown axis '%s'.", +         buffer +      ); + +      return -1; +   } + +   prev_errno = errno; +   errno = 0; + +   valc = +   fscanf +   ( +      f, +      "%d %d %d %d %d", +      &(conf->axis[axis].min), +      &(conf->axis[axis].max), +      &(conf->axis[axis].fuzz), +      &(conf->axis[axis].flat), +      &(conf->axis[axis].resolution) +   ); + +   if (valc == EOF) +   { +      if (errno == 0) +      { +         RELABSD_FATAL +         ( +            "[CONFIG] Unexpected end of file while reading axis '%s'.", +            buffer +         ); +      } +      else +      { +         RELABSD_FATAL +         ( +            "[CONFIG] An error occured while reading axis '%s': %s.", +            buffer, +            strerror(errno) +         ); +      } + +      errno = prev_errno; + +      return -1; +   } +   else if (valc < 5) +   { +      RELABSD_FATAL +      ( +         "[CONFIG] Invalid parameter count for axis '%s'.", +         buffer +      ); + +      errno = prev_errno; + +      return -1; +   } + +   RELABSD_DEBUG +   ( +      RELABSD_DEBUG_CONFIG, +      "Axis '%s': {min = %d; max = %d; fuzz = %d; flat = %d; resolution = %d}", +      buffer, +      conf->axis[axis].min, +      conf->axis[axis].max, +      conf->axis[axis].fuzz, +      conf->axis[axis].flat, +      conf->axis[axis].resolution +   ); + +   errno = prev_errno; + +   conf->axis[axis].enabled = 1; +   conf->axis[axis].previous_value = 0; + +   return read_axis_options(conf, f, axis); +} + +/* + * Returns -1 on (fatal) error, + *          0 on EOF, + *          1 on newline. + */ +static int read_config_line +( +   struct relabsd_config * const conf, +   FILE * const f, +   const char * const prefix +) +{ +   if (!RELABSD_IS_PREFIX("#", prefix)) +   { +      return parse_axis_configuration_line(conf, f, prefix); +   } + +   return reach_next_line_or_eof(f); +} + +/* + * Returns -1 on (fatal) error, + *         0 on success. + */ +static int read_config_file +( +   struct relabsd_config * const conf, +   char * const filename +) +{ +   FILE * f; +   char buffer[(RELABSD_CONF_AXIS_CODE_SIZE + 1)]; +   int continue_reading, prev_errno; + +   buffer[RELABSD_CONF_AXIS_CODE_SIZE] = '\0'; + +   f = fopen(filename, "r"); + +   if (f == (FILE *) NULL) +   { +      RELABSD_FATAL +      ( +         "[CONFIG] Could not open file: %s.", +         strerror(errno) +      ); + +      return -1; +   } + + +   prev_errno = errno; +   errno = 0; + +   continue_reading = 1; + +   while +   ( +      (continue_reading == 1) +      && +      ( +         fscanf +         ( +            f, +            "%" RELABSD_TO_STRING(RELABSD_CONF_AXIS_CODE_SIZE) "s", +            buffer +         ) +         != EOF +      ) +   ) +   { +      switch (read_config_line(conf, f, buffer)) +      { +         case 1: +            /* Everything is going well. */ +            break; + +         case 0: +            /* EOF reached. */ +            continue_reading = 0; +            break; + +         case -1: +            /* A fatal error occured. */ +            errno = prev_errno; + +            fclose(f); +            return -1; +      } +   } + +   if (errno != 0) +   { +      /* An error happened in the while loop condition. */ +      RELABSD_FATAL +      ( +         "[CONFIG] Error while reading file: %s, last read '%s'.", +         strerror(errno), +         buffer +      ); + +      errno = prev_errno; + +      fclose(f); + +      return -1; +   } + +   errno = prev_errno; + +   fclose(f); + +   return 0; +} + +static void print_usage +( +   const char * const exec +) +{ +   RELABSD_FATAL +   ( +      "USAGE: %s input_device config_file [<OPTION>+]\n" +      "<OPTION>:\n" +      "\t [-n | --name] <relabsd_device_name>: Names the virtual device.\n" +      "\t [-t | --timeout] <timeout_in_ms>: Resets all enabled axes to zero" +      " <timeout_in_ms> milliseconds after the last event. Range for" +      " <timeout_in_ms>: [1, %d].\n" +      "Alternatively, the previous usage is still supported:\n" +      "\t%s input_device config_file [<relabsd_device_name>]\n" +      "However, with that usage, <relabsd_device_name> cannot start with '-'.", +      exec, +      INT_MAX, +      exec +   ); +} +/* + * Returns -1 on (fatal) error, + *          0 on valid usage. + */ +static int check_usage +( +   int const argc, +   char * const * const argv +) +{ +   if (argc < 3) +   { +      print_usage(argv[0]); + +      return -1; +   } + +   return 0; +} + +static void init_axes_config (struct relabsd_config * const conf) +{ +   int i; + +   for (i = RELABSD_VALID_AXES_COUNT; i --> 0;) +   { +      conf->axis[i].enabled = 0; +   } +} + +static int parse_options +( +   struct relabsd_config * const conf, +   int const argc, +   char * const * const argv +) +{ +   int i; + +   if ((argc == 4) && !RELABSD_IS_PREFIX("-", argv[3])) +   { +      /* Old usage */ + +      RELABSD_S_DEBUG(RELABSD_DEBUG_CONFIG, "Old usage detected."); + +      conf->device_name = argv[3]; + +      RELABSD_DEBUG +      ( +         RELABSD_DEBUG_CONFIG, +         "Virtual device name param set to '%s'.", +         conf->device_name +      ); + +      return 0; +   } + +   conf->device_name = NULL; +   conf->enable_timeout = 0; + +   for (i = 3; i < argc; ++i) +   { +      if +      ( +         RELABSD_STRING_EQUALS("-n", argv[i]) +         || RELABSD_STRING_EQUALS("--name", argv[i]) +      ) +      { +         i += 1; + +         if (i >= argc) +         { +            RELABSD_S_FATAL +            ( +               "Missing value for parameter \"--name\"." +            ); + +            print_usage(argv[0]); + +            return -1; +         } + +         conf->device_name = argv[i]; +      } +      else if +      ( +         RELABSD_STRING_EQUALS("-t", argv[i]) +         || RELABSD_STRING_EQUALS("--timeout", argv[i]) +      ) +      { +         i += 1; + +         if (i >= argc) +         { +            RELABSD_S_FATAL +            ( +               "Missing value for parameter \"--timeout\"." +            ); + +            print_usage(argv[0]); + +            return -1; +         } + +         if (parse_timeout_option(conf, argv[i]) < 0) +         { +            return -1; +         } +      } +      else +      { +         RELABSD_FATAL +         ( +            "Unknown parameter \"%s\".", +            argv[i] +         ); + +         print_usage(argv[0]); + +         return -1; +      } +   } + +   return 0; +} +int relabsd_config_parse +( +   struct relabsd_config * const conf, +   int const argc, +   char * const * const argv +) +{ +   RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Parsing config & params..."); + +   if (check_usage(argc, argv) < 0) +   { +      return -1; +   } + +   if (parse_options(conf, argc, argv) < 0) +   { +      return -1; +   } + +   conf->input_file = argv[1]; + +   RELABSD_DEBUG +   ( +      RELABSD_DEBUG_CONFIG, +      "Using configuration file '%s'.", +      conf->input_file +   ); + +   init_axes_config(conf); + +   if (read_config_file(conf, argv[2]) < 0) +   { +      return -1; +   } + +   return 0; +} + +static int direct_filter +( +   struct relabsd_config_axis * const axis, +   int * const value +) +{ +   if (abs(*value - axis->previous_value) <= axis->fuzz) +   { +      if (axis->option[RELABSD_REAL_FUZZ_OPTION]) +      { +         axis->previous_value = *value; +      } + +      return -1; +   } + +   if (*value < axis->min) +   { +      *value = axis->min; +   } +   else if (*value > axis->max) +   { +      *value = axis->max; +   } +   else if (abs(*value) <= axis->flat) +   { +      *value = 0; +   } + +   if (*value == axis->previous_value) +   { +      return -1; +   } + +   axis->previous_value = *value; + +   return 1; +} + +static int rel_to_abs_filter +( +   struct relabsd_config_axis * const axis, +   int * const value +) +{ +   long int guard; + +   guard = (((long int) axis->previous_value) + ((long int) *value)); + +   if (guard < ((long int) INT_MIN)) +   { +      guard = ((long int) INT_MIN); +   } +   else if (guard > ((long int) INT_MAX)) +   { +      guard = ((long int) INT_MAX); +   } + +   *value = (int) guard; + +   if (axis->option[RELABSD_FRAMED_OPTION]) +   { +      if (*value < axis->min) +      { +         *value = axis->min; +      } +      else if (*value > axis->max) +      { +         *value = axis->max; +      } + +      if (*value == axis->previous_value) +      { +         return 0; +      } + +      axis->previous_value = *value; + +      return 1; +   } +   else +   { +      if (*value == axis->previous_value) +      { +         return 0; +      } + +      axis->previous_value = *value; + +      if ((*value < axis->min) || (*value > axis->max)) +      { +         return 0; +      } +      else +      { +         return 1; +      } +   } +} + +int relabsd_config_filter +( +   struct relabsd_config * const conf, +   enum relabsd_axis const axis, +   int * const value +) +{ +   if ((axis == RELABSD_UNKNOWN) || !conf->axis[axis].enabled) +   { +      return 0; +   } + +   /* TODO: handle conf->axis[axis].resolution */ + +   if (conf->axis[axis].option[RELABSD_DIRECT_OPTION]) +   { +      return direct_filter((conf->axis + axis), value); +   } +   else +   { +      return rel_to_abs_filter((conf->axis + axis), value); +   } +} + +void relabsd_config_get_absinfo +( +   const struct relabsd_config * const conf, +   enum relabsd_axis const axis, +   struct input_absinfo * const absinfo +) +{ +   absinfo->value = (__s32) 0; +   absinfo->minimum = (__s32) conf->axis[axis].min; +   absinfo->maximum = (__s32) conf->axis[axis].max; +   absinfo->fuzz = (__s32) conf->axis[axis].fuzz; +   absinfo->flat = (__s32) conf->axis[axis].flat; +   absinfo->resolution = (__s32) conf->axis[axis].resolution; +} diff --git a/src/config/parameters.c b/src/config/parameters.c new file mode 100644 index 0000000..308e5db --- /dev/null +++ b/src/config/parameters.c @@ -0,0 +1,287 @@ +/**** POSIX *******************************************************************/ +#include <limits.h> + +/**** RELABSD *****************************************************************/ +#include <relabsd/config.h> +#include <relabsd/debug.h> + +#include <relabsd/device/axis.h> + +#include <relabsd/util/string.h> + +#include <relabsd/config/parameters.h> + +/******************************************************************************/ +/**** LOCAL FUNCTIONS *********************************************************/ +/******************************************************************************/ +static void print_usage (const char exec [const restrict static 1]) +{ +   printf +   ( +      "USAGE: %s [<MODE>] [<OPTION>+]\n\n" + +      "<MODE>:\n" +      "\t[-c | --client] <server_file>:\n" +         "\t\tSends the commands to a given server instance.\n\n" + +      "\t[-s | --server] <server_file>:\n" +         "\t\tCreates a named server instance.\n\n" + +      "\t[-1 | --self]:\n" +         "\t\tCreates a unnamed server instance.\n\n" + +      "<OPTION>:\n" +      "\t[-d | --daemon]:\n" +         "\t\tRuns server instance in the background.\n\n" + +      "\t[-n | --name] <relabsd_device_name>:\n" +         "\t\tNames the virtual device.\n\n" + +      "\t[-t | --timeout] <timeout_in_ms>:\n" +         "\t\tSets a zeroing timeout (0 to disable).\n\n" + +      "\t[-a | --axis] <name> <min> <max> <fuzz> <flat> <resolution> " +         "<options>:\n" +         "\t\t(Re)defines an axis.\n\n" + +      "\t[-f | --config] <config_file>" +         "<options>:\n" +         "\t\t(Re)defines an axis.\n", +      exec +   ); +} + +static int parse_axis +( +   const int argc, +   const char * argv [const restrict static argc], +   struct relabsd_axis axes [const restrict static RELABSD_AXIS_AXES_COUNT] +) +{ +   enum relabsd_axis_name axis_name; +   struct relabsd_axis *axis; + +   if (argc < 7) +   { +      RELABSD_S_FATAL("7 parameters must be provided for axis definition."); + +      return -1; +   } + +   axis_index = relabsd_axis_from_name(argv[0]); + +   if (axis_index == RELABSD_UNKNOWN) +   { +      RELABSD_FATAL("Unknown axis \"%s\".", argv[0]); + +      return -1; +   } + +   axis = (axes + axis_index); + +   axis->min = atoi(argv[1]); +   axis->max = atoi(argv[2]); +   axis->fuzz = atoi(argv[3]); +   axis->flat = atoi(argv[4]); +   axis->resolution = atoi(argv[5]); + + +   return 0; +} + +/******************************************************************************/ +/**** EXPORTED FUNCTIONS ******************************************************/ +/******************************************************************************/ +int relabsd_parameters_parse_execution_mode +( +   const int argc, +   const char * argv [const restrict static argc], +   struct relabsd_parameters params [const restrict static 1] +) +{ +   RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Parsing exec mode..."); + +   if (argc < 3) +   { +      print_usage(argv[0]); + +      return -1; +   } + +   if +   ( +      RELABSD_STRING_EQUALS("-c", argv[1]) +      || RELABSD_STRING_EQUALS("--client", argv[1]) +   ) +   { +      params->mode = RELABSD_PARAMETERS_CLIENT_MODE; +      params->node = argv[2]; +      params->read_argc = 2; +   } +   else if +   ( +      RELABSD_STRING_EQUALS("-s", argv[1]) +      || RELABSD_STRING_EQUALS("--server", argv[1]) +   ) +   { +      params->mode = RELABSD_PARAMETERS_CLIENT_MODE; +      params->node = argv[2]; +      params->read_argc = 2; +   } +   else if +   ( +      RELABSD_STRING_EQUALS("-1", argv[1]) +      || RELABSD_STRING_EQUALS("--self", argv[1]) +   ) +   { +      params->mode = RELABSD_PARAMETERS_SERVER_MODE; +      params->node = (char *) NULL; +      params->read_argc = 1; +   } +   else +   { +      print_usage(argv[0]); + +      return -1; +   } + +   RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Parsed exec mode."); + +   return 0; +} + +int relabsd_parameters_parse_options +( +   const int argc, +   const char * argv [const restrict static argc], +   struct relabsd_parameters params [const restrict static 1] +) +{ +   int i; + +   RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Parsing options..."); + +   set_default_options(params); + +   for (i = params->read_argc; i < argc; ++i) +   { +      if +      ( +         RELABSD_STRING_EQUALS("-d", argv[i]) +         || RELABSD_STRING_EQUALS("--daemon", argv[i]) +      ) +      { +         params->run_as_daemon = 1; + +         if (params->node == ((char *) NULL)) +         { +            RELABSD_S_WARNING +            ( +               "Running as a daemon without any communication file." +            ); +         } +      } +      else if +      ( +         RELABSD_STRING_EQUALS("-n", argv[i]) +         || RELABSD_STRING_EQUALS("--name", argv[i]) +      ) +      { +         if (argc == i) +         { +            RELABSD_FATAL("Missing value for \"%s\" <OPTION>.", argv[i]); + +            return -1; +         } + +         ++i; +         params->name = argv[i]; +      } +      else if +      ( +         RELABSD_STRING_EQUALS("-t", argv[i]) +         || RELABSD_STRING_EQUALS("--timeout", argv[i]) +      ) +      { +         if (argc == i) +         { +            RELABSD_FATAL("Missing value for \"%s\" <OPTION>.", argv[i]); +            print_usage(argv[0]); + +            return -1; +         } + +         ++i; + +         if +         ( +            relabsd_util_parse_int(argv[i], 0, INT_MAX, &(params->timeout)) +            < 0 +         ) +         { +            RELABSD_FATAL +            ( +               "Invalid value for \"%s\" <OPTION> (valid range is [%d, %d]).", +               argv[i - 1], +               0, +               INT_MAX +            ); + +            print_usage(argv[0]); + +            return -1; +         } +      } +      else if +      ( +         RELABSD_STRING_EQUALS("-a", argv[i]) +         || RELABSD_STRING_EQUALS("--axis", argv[i]) +      ) +      { +         if (argc == i) +         { +            RELABSD_FATAL("Missing values for \"%s\" <OPTION>.", argv[i]); +            print_usage(argv[0]); + +            return -1; +         } + +         ++i; + +         if (parse_axis((argc - i), (argv + i), params->axes) < 0) +         { +            print_usage(argv[0]); + +            return -1; +         } +      } +      else if +      ( +         RELABSD_STRING_EQUALS("-f", argv[i]) +         || RELABSD_STRING_EQUALS("--config", argv[i]) +      ) +      { +         if (argc == i) +         { +            RELABSD_FATAL("Missing value for \"%s\" <OPTION>.", argv[i]); +            print_usage(argv[0]); + +            return -1; +         } + +         ++i; +         params->config_file = argv[i]; +      } +      else +      { +         RELABSD_FATAL("Unknown <OPTION> \"%s\".", argv[i]); +         print_usage(argv[0]); + +         return -1; +      } +   } + +   RELABSD_S_DEBUG(RELABSD_DEBUG_PROGRAM_FLOW, "Parsed options."); + +   return 0; +} | 


