[or-cvs] Re-write configuration option lookup code: use a table, not...

Nick Mathewson nickm at seul.org
Wed Oct 27 02:30:32 UTC 2004


Update of /home/or/cvsroot/src/or
In directory moria.mit.edu:/tmp/cvs-serv21967/src/or

Modified Files:
	config.c 
Log Message:
Re-write configuration option lookup code: use a table, not a big if( || || || ||).  Deprecate unoffical abbrevs and abbrevs not on the command line.

Index: config.c
===================================================================
RCS file: /home/or/cvsroot/src/or/config.c,v
retrieving revision 1.186
retrieving revision 1.187
diff -u -d -r1.186 -r1.187
--- config.c	26 Oct 2004 21:48:41 -0000	1.186
+++ config.c	27 Oct 2004 02:30:28 -0000	1.187
@@ -26,6 +26,93 @@
   CONFIG_TYPE_OBSOLETE,     /**< Obsolete (ignored) option. */
 } config_type_t;
 
+/*DOCDOC*/
+typedef struct config_abbrev_t {
+  char *abbreviated;
+  char *full;
+} config_abbrev_t;
+
+static config_abbrev_t config_abbrevs[] = {
+  { "l", "LogLevel" },
+  { NULL, NULL },
+};
+
+typedef struct config_var_t {
+  char *name;
+  config_type_t type;
+  off_t var_offset;
+} config_var_t;
+
+#define STRUCT_OFFSET(tp, member) ((off_t) &(((tp*)0)->member))
+#define VAR(name,conftype,member) \
+  { name, CONFIG_TYPE_ ## conftype, STRUCT_OFFSET(or_options_t, member) }
+#define OBSOLETE(name) { name, CONFIG_TYPE_OBSOLETE, 0 }
+
+static config_var_t config_vars[] = {
+  VAR("Address",             STRING,   Address),
+  VAR("AllowUnverifiedNodes",CSV,      AllowUnverifiedNodes),
+  VAR("AuthoritativeDirectory",BOOL,   AuthoritativeDir),
+  VAR("BandwidthRate",       UINT,     BandwidthRate),
+  VAR("BandwidthBurst",      UINT,     BandwidthBurst),
+  VAR("ClientOnly",          BOOL,     ClientOnly),
+  VAR("ContactInfo",         STRING,   ContactInfo),
+  VAR("DebugLogFile",        STRING,   DebugLogFile),
+  VAR("DataDirectory",       STRING,   DataDirectory),
+  VAR("DirPort",             UINT,     DirPort),
+  VAR("DirBindAddress",      LINELIST, DirBindAddress),
+  VAR("DirFetchPostPeriod",  UINT,     DirFetchPostPeriod),
+  VAR("DirPolicy",           LINELIST, DirPolicy),
+  VAR("DirServer",           LINELIST, DirServers),
+  VAR("ExitNodes",           STRING,   ExitNodes),
+  VAR("EntryNodes",          STRING,   EntryNodes),
+  VAR("StrictExitNodes",     BOOL,     StrictExitNodes),
+  VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes),
+  VAR("ExitPolicy",          LINELIST, ExitPolicy),
+  VAR("ExcludeNodes",        STRING,   ExcludeNodes),
+  VAR("FascistFirewall",     BOOL,     FascistFirewall),
+  VAR("FirewallPorts",       CSV,      FirewallPorts),
+  VAR("MyFamily",            STRING,   MyFamily),
+  VAR("NodeFamily",          LINELIST, NodeFamilies),
+  VAR("Group",               STRING,   Group),
+  VAR("HttpProxy",           STRING,   HttpProxy),
+  VAR("HiddenServiceDir",    LINELIST, RendConfigLines),
+  VAR("HiddenServicePort",   LINELIST, RendConfigLines),
+  VAR("HiddenServiceNodes",  LINELIST, RendConfigLines),
+  VAR("HiddenServiceExcludeNodes", LINELIST, RendConfigLines),
+  VAR("IgnoreVersion",       BOOL,     IgnoreVersion),
+  VAR("KeepalivePeriod",     UINT,     KeepalivePeriod),
+  VAR("LogLevel",            LINELIST, LogOptions),
+  VAR("LogFile",             LINELIST, LogOptions),
+  OBSOLETE("LinkPadding"),
+  VAR("MaxConn",             UINT,     MaxConn),
+  VAR("MaxOnionsPending",    UINT,     MaxOnionsPending),
+  VAR("Nickname",            STRING,   Nickname),
+  VAR("NewCircuitPeriod",    UINT,     NewCircuitPeriod),
+  VAR("NumCpus",             UINT,     NumCpus),
+  VAR("ORPort",              UINT,     ORPort),
+  VAR("ORBindAddress",       LINELIST, ORBindAddress),
+  VAR("OutboundBindAddress", STRING,   OutboundBindAddress),
+  VAR("PidFile",             STRING,   PidFile),
+  VAR("PathlenCoinWeight",   DOUBLE,   PathlenCoinWeight),
+  VAR("RedirectExit",        LINELIST, RedirectExit),
+  OBSOLETE("RouterFile"),
+  VAR("RunAsDaemon",         BOOL,     RunAsDaemon),
+  VAR("RunTesting",          BOOL,     RunTesting),
+  VAR("RecommendedVersions", LINELIST, RecommendedVersions),
+  VAR("RendNodes",           STRING,   RendNodes),
+  VAR("RendExcludeNodes",    STRING,   RendExcludeNodes),
+  VAR("SocksPort",           UINT,     SocksPort),
+  VAR("SocksBindAddress",    LINELIST, SocksBindAddress),
+  VAR("SocksPolicy",         LINELIST, SocksPolicy),
+  VAR("SysLog",              LINELIST, LogOptions),
+  OBSOLETE("TrafficShaping"),
+  VAR("User",                STRING,   User),
+  { NULL, NULL, NULL }
+};
+#undef VAR
+#undef OBSOLETE
+
+
 /** Largest allowed config line */
 #define CONFIG_LINE_T_MAXLEN 4096
 
@@ -37,7 +124,21 @@
 static int parse_dir_server_line(const char *line);
 static int parse_redirect_line(or_options_t *options,
                                struct config_line_t *line);
+static const char *expand_abbrev(const char *option);
+static config_var_t *config_find_option(const char *key);
 
+/** DOCDOC */
+static const char *
+expand_abbrev(const char *option)
+{
+  int i;
+  for (i=0; config_abbrevs[i].abbreviated; ++i) {
+    /* Abbreviations aren't casei. */
+    if (!strcmp(option,config_abbrevs[i].abbreviated))
+      return config_abbrevs[i].full;
+  }
+  return option;
+}
 
 /** Helper: Read a list of configuration options from the command line. */
 static struct config_line_t *
@@ -61,7 +162,7 @@
     while(*s == '-')
       s++;
 
-    new->key = tor_strdup(s);
+    new->key = tor_strdup(expand_abbrev(s));
     new->value = tor_strdup(argv[i+1]);
 
     log(LOG_DEBUG,"Commandline: parsed keyword '%s', value '%s'",
@@ -132,30 +233,44 @@
   }
 }
 
-/** Search the linked list <b>c</b> for any option whose key is <b>key</b>.
- * If such an option is found, interpret it as of type <b>type</b>, and store
- * the result in <b>arg</b>.  If the option is misformatted, log a warning and
- * skip it.
- */
+static config_var_t *config_find_option(const char *key)
+{
+  int i;
+  for (i=0; config_vars[i].name; ++i) {
+    if (!strcasecmp(key, config_vars[i].name)) {
+      return &config_vars[i];
+    } else if (!strncasecmp(key, config_vars[i].name, strlen(key))) {
+      log_fn(LOG_WARN, "The abbreviation '%s' is deprecated. "
+          "Tell Nick and Roger to make it official, or just use '%s' instead",
+             key, config_vars[i].name);
+      return &config_vars[i];
+    }
+  }
+  return NULL;
+}
+
 static int
-config_compare(struct config_line_t *c, const char *key,
-               config_type_t type, void *arg)
+config_assign_line(or_options_t *options, struct config_line_t *c)
 {
   int i, ok;
+  config_var_t *var;
+  void *lvalue;
 
-  if (strncasecmp(c->key, key, strlen(c->key)))
-    return 0;
+  var = config_find_option(c->key);
+  if (!var) {
+    log_fn(LOG_WARN, "Unknown option '%s'.  Failing.", c->key);
+    return -1;
+  }
 
-  if (strcasecmp(c->key, key)) {
+  /* Put keyword into canonical case. */
+  if (strcmp(var->name, c->key)) {
     tor_free(c->key);
-    c->key = tor_strdup(key);
+    c->key = tor_strdup(var->name);
   }
 
-  /* it's a match. cast and assign. */
-  log_fn(LOG_DEBUG, "Recognized keyword '%s' as %s, using value '%s'.",
-         c->key, key, c->value);
+  lvalue = ((void*)options) + var->var_offset;
+  switch(var->type) {
 
-  switch(type) {
   case CONFIG_TYPE_UINT:
     i = tor_parse_long(c->value, 10, 0, INT_MAX, &ok, NULL);
     if (!ok) {
@@ -163,7 +278,7 @@
           c->key,c->value);
       return 0;
     }
-    *(int *)arg = i;
+    *(int *)lvalue = i;
     break;
 
   case CONFIG_TYPE_BOOL:
@@ -172,23 +287,23 @@
       log(LOG_WARN, "Boolean keyword '%s' expects 0 or 1. Skipping.", c->key);
       return 0;
     }
-    *(int *)arg = i;
+    *(int *)lvalue = i;
     break;
 
   case CONFIG_TYPE_STRING:
-    tor_free(*(char **)arg);
-    *(char **)arg = tor_strdup(c->value);
+    tor_free(*(char **)lvalue);
+    *(char **)lvalue = tor_strdup(c->value);
     break;
 
   case CONFIG_TYPE_DOUBLE:
-    *(double *)arg = atof(c->value);
+    *(double *)lvalue = atof(c->value);
     break;
 
   case CONFIG_TYPE_CSV:
-    if (*(smartlist_t**)arg == NULL)
-      *(smartlist_t**)arg = smartlist_create();
+    if (*(smartlist_t**)lvalue == NULL)
+      *(smartlist_t**)lvalue = smartlist_create();
 
-    smartlist_split_string(*(smartlist_t**)arg, c->value, ",",
+    smartlist_split_string(*(smartlist_t**)lvalue, c->value, ",",
                            SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
     break;
 
@@ -196,8 +311,8 @@
       /* Note: this reverses the order that the lines appear in.  That's
        * just fine, since we build up the list of lines reversed in the
        * first place. */
-      *(struct config_line_t**)arg =
-        config_line_prepend(*(struct config_line_t**)arg, c->key, c->value);
+      *(struct config_line_t**)lvalue =
+        config_line_prepend(*(struct config_line_t**)lvalue, c->key, c->value);
       break;
 
   case CONFIG_TYPE_OBSOLETE:
@@ -205,7 +320,7 @@
     break;
   }
 
-  return 1;
+  return 0;
 }
 
 /** Iterate through the linked list of options <b>list</b>.
@@ -216,94 +331,8 @@
 config_assign(or_options_t *options, struct config_line_t *list)
 {
   while (list) {
-    if (
-
-      /* order matters here! abbreviated arguments use the first match. */
-
-      /* string options */
-      config_compare(list, "Address",        CONFIG_TYPE_STRING, &options->Address) ||
-      config_compare(list, "AllowUnverifiedNodes", CONFIG_TYPE_CSV, &options->AllowUnverifiedNodes) ||
-      config_compare(list, "AuthoritativeDirectory",CONFIG_TYPE_BOOL, &options->AuthoritativeDir) ||
-
-      config_compare(list, "BandwidthRate",  CONFIG_TYPE_UINT, &options->BandwidthRate) ||
-      config_compare(list, "BandwidthBurst", CONFIG_TYPE_UINT, &options->BandwidthBurst) ||
-
-      config_compare(list, "ClientOnly",     CONFIG_TYPE_BOOL, &options->ClientOnly) ||
-      config_compare(list, "ContactInfo",    CONFIG_TYPE_STRING, &options->ContactInfo) ||
-
-      config_compare(list, "DebugLogFile",   CONFIG_TYPE_STRING, &options->DebugLogFile) ||
-      config_compare(list, "DataDirectory",  CONFIG_TYPE_STRING, &options->DataDirectory) ||
-      config_compare(list, "DirPort",        CONFIG_TYPE_UINT, &options->DirPort) ||
-      config_compare(list, "DirBindAddress", CONFIG_TYPE_LINELIST, &options->DirBindAddress) ||
-      config_compare(list, "DirFetchPostPeriod",CONFIG_TYPE_UINT, &options->DirFetchPostPeriod) ||
-      config_compare(list, "DirPolicy",      CONFIG_TYPE_LINELIST, &options->DirPolicy) ||
-      config_compare(list, "DirServer",      CONFIG_TYPE_LINELIST, &options->DirServers) ||
-
-      config_compare(list, "ExitNodes",      CONFIG_TYPE_STRING, &options->ExitNodes) ||
-      config_compare(list, "EntryNodes",     CONFIG_TYPE_STRING, &options->EntryNodes) ||
-      config_compare(list, "StrictExitNodes", CONFIG_TYPE_BOOL, &options->StrictExitNodes) ||
-      config_compare(list, "StrictEntryNodes", CONFIG_TYPE_BOOL, &options->StrictEntryNodes) ||
-      config_compare(list, "ExitPolicy",     CONFIG_TYPE_LINELIST, &options->ExitPolicy) ||
-      config_compare(list, "ExcludeNodes",   CONFIG_TYPE_STRING, &options->ExcludeNodes) ||
-
-      config_compare(list, "FascistFirewall",CONFIG_TYPE_BOOL, &options->FascistFirewall) ||
-      config_compare(list, "FirewallPorts",CONFIG_TYPE_CSV, &options->FirewallPorts) ||
-      config_compare(list, "MyFamily",      CONFIG_TYPE_STRING, &options->MyFamily) ||
-      config_compare(list, "NodeFamily",    CONFIG_TYPE_LINELIST, &options->NodeFamilies) ||
-
-      config_compare(list, "Group",          CONFIG_TYPE_STRING, &options->Group) ||
-
-      config_compare(list, "HttpProxy",      CONFIG_TYPE_STRING, &options->HttpProxy) ||
-      config_compare(list, "HiddenServiceDir", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
-      config_compare(list, "HiddenServicePort", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
-      config_compare(list, "HiddenServiceNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
-      config_compare(list, "HiddenServiceExcludeNodes", CONFIG_TYPE_LINELIST, &options->RendConfigLines)||
-
-      config_compare(list, "IgnoreVersion",  CONFIG_TYPE_BOOL, &options->IgnoreVersion) ||
-
-      config_compare(list, "KeepalivePeriod",CONFIG_TYPE_UINT, &options->KeepalivePeriod) ||
-
-      config_compare(list, "LogLevel",       CONFIG_TYPE_LINELIST, &options->LogOptions) ||
-      config_compare(list, "LogFile",        CONFIG_TYPE_LINELIST, &options->LogOptions) ||
-      config_compare(list, "LinkPadding",    CONFIG_TYPE_OBSOLETE, NULL) ||
-
-      config_compare(list, "MaxConn",        CONFIG_TYPE_UINT, &options->MaxConn) ||
-      config_compare(list, "MaxOnionsPending",CONFIG_TYPE_UINT, &options->MaxOnionsPending) ||
-
-      config_compare(list, "Nickname",       CONFIG_TYPE_STRING, &options->Nickname) ||
-      config_compare(list, "NewCircuitPeriod",CONFIG_TYPE_UINT, &options->NewCircuitPeriod) ||
-      config_compare(list, "NumCpus",        CONFIG_TYPE_UINT, &options->NumCpus) ||
-
-      config_compare(list, "ORPort",         CONFIG_TYPE_UINT, &options->ORPort) ||
-      config_compare(list, "ORBindAddress",  CONFIG_TYPE_LINELIST, &options->ORBindAddress) ||
-      config_compare(list, "OutboundBindAddress",CONFIG_TYPE_STRING, &options->OutboundBindAddress) ||
-
-      config_compare(list, "PidFile",        CONFIG_TYPE_STRING, &options->PidFile) ||
-      config_compare(list, "PathlenCoinWeight",CONFIG_TYPE_DOUBLE, &options->PathlenCoinWeight) ||
-
-      config_compare(list, "RedirectExit",   CONFIG_TYPE_LINELIST, &options->RedirectExit) ||
-      config_compare(list, "RouterFile",     CONFIG_TYPE_OBSOLETE, NULL) ||
-      config_compare(list, "RunAsDaemon",    CONFIG_TYPE_BOOL, &options->RunAsDaemon) ||
-      config_compare(list, "RunTesting",     CONFIG_TYPE_BOOL, &options->RunTesting) ||
-      config_compare(list, "RecommendedVersions",CONFIG_TYPE_LINELIST, &options->RecommendedVersions) ||
-      config_compare(list, "RendNodes",      CONFIG_TYPE_STRING, &options->RendNodes) ||
-      config_compare(list, "RendExcludeNodes",CONFIG_TYPE_STRING, &options->RendExcludeNodes) ||
-
-      config_compare(list, "SocksPort",      CONFIG_TYPE_UINT, &options->SocksPort) ||
-      config_compare(list, "SocksBindAddress",CONFIG_TYPE_LINELIST,&options->SocksBindAddress) ||
-      config_compare(list, "SocksPolicy",     CONFIG_TYPE_LINELIST,&options->SocksPolicy) ||
-      config_compare(list, "SysLog",          CONFIG_TYPE_LINELIST,&options->LogOptions) ||
-      config_compare(list, "TrafficShaping", CONFIG_TYPE_OBSOLETE, NULL) ||
-
-      config_compare(list, "User",           CONFIG_TYPE_STRING, &options->User)
-
-      ) {
-      /* then we're ok. it matched something. */
-    } else {
-      log_fn(LOG_WARN,"Unknown keyword '%s'. Failing.",list->key);
+    if (config_assign_line(options, list))
       return -1;
-    }
-
     list = list->next;
   }
 
@@ -534,7 +563,7 @@
 
   if (is_set)
     return path;
-  
+
   /* Find X:\documents and settings\username\applicatation data\ .
    * We would use SHGetSpecialFolder path, but that wasn't added until IE4.
    */



More information about the tor-commits mailing list