Index: owl.h
===================================================================
--- owl.h	(revision b9517cf7ce2959a6e86a52d25a98b1d03df56d58)
+++ owl.h	(revision c0e728aa9740f95d79437aec2697748bcfa6b226)
@@ -237,5 +237,5 @@
   void *pval_default;  /* for types other and string */
   int   ival_default;  /* for types int and bool     */
-  const char *validsettings;	/* documentation of valid settings */
+  char *validsettings;          /* documentation of valid settings */
   char *summary;		/* summary of usage */
   char *description;		/* detailed description */
Index: perl/lib/BarnOwl.pm
===================================================================
--- perl/lib/BarnOwl.pm	(revision 78033261fc599d8d986e1c32b68523132b853d40)
+++ perl/lib/BarnOwl.pm	(revision cce93697ded79353e09913214d2d8fbf8423dc88)
@@ -17,5 +17,5 @@
                     add_io_dispatch remove_io_dispatch
                     new_command
-                    new_variable_int new_variable_bool new_variable_string
+                    new_variable_int new_variable_bool new_variable_string new_variable_enum
                     quote redisplay);
 our %EXPORT_TAGS = (all => \@EXPORT_OK);
@@ -389,6 +389,8 @@
 =head2 new_variable_string NAME [{ARGS}]
 
-Add a new owl variable, either an int, a bool, or a string, with the
-specified name.
+=head2 new_variable_enum NAME [{ARGS}]
+
+Add a new owl variable, either an int, a bool, a string, or an enum,
+with the specified name.
 
 ARGS can optionally contain the following keys:
@@ -398,5 +400,6 @@
 =item default
 
-The default and initial value for the variable
+The default and initial value for the variable.
+Note that this should be a string value for an enum.
 
 =item summary
@@ -408,4 +411,11 @@
 A longer description of the function of the variable
 
+=item valid_settings
+
+A listref of valid setttings for the enum variable, or a string describing
+the valid settings for any other type of variable.  The settings for an enum
+variable may not contain any commas.  You should not specify valid settings
+for boolean variables.
+
 =back
 
@@ -413,21 +423,16 @@
 
 sub new_variable_int {
-    unshift @_, \&BarnOwl::Internal::new_variable_int, 0;
-    goto \&_new_variable;
+    _new_variable(\&BarnOwl::Internal::new_variable_int, 0, "<int>", @_);
 }
 
 sub new_variable_bool {
-    unshift @_, \&BarnOwl::Internal::new_variable_bool, 0;
-    goto \&_new_variable;
+    _new_variable(\&BarnOwl::Internal::new_variable_bool, 0, "on,off", @_);
 }
 
 sub new_variable_string {
-    unshift @_, \&BarnOwl::Internal::new_variable_string, "";
-    goto \&_new_variable;
-}
-
-sub _new_variable {
-    my $func = shift;
-    my $default_default = shift;
+    _new_variable(\&BarnOwl::Internal::new_variable_string, "", "<string>", @_);
+}
+
+sub new_variable_enum {
     my $name = shift;
     my $args = shift || {};
@@ -435,7 +440,30 @@
         summary     => "",
         description => "",
-        default     => $default_default,
         %{$args});
-    $func->($name, $args{default}, $args{summary}, $args{description});
+
+    my @valid_settings =  @{$args{valid_settings}};
+    if (defined $args{default}) {
+        ($args{default}) = grep { $args{default} eq $valid_settings[$_] } 0..$#valid_settings; # turn the string default into a numerical default
+    } else {
+        $args{default} = 0;
+    }
+    $args{valid_settings} = join ",", @valid_settings;
+
+    BarnOwl::Internal::new_variable_enum($name, $args{default}, $args{summary}, $args{description}, $args{valid_settings});
+}
+
+sub _new_variable {
+    my $func = shift;
+    my $default_default = shift;
+    my $default_valid_settings = shift;
+    my $name = shift;
+    my $args = shift || {};
+    my %args = (
+        summary        => "",
+        description    => "",
+        default        => $default_default,
+        valid_settings => $default_valid_settings,
+        %{$args});
+    $func->($name, $args{default}, $args{summary}, $args{description}, $args{valid_settings});
 }
 
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision e89ec4812c55797bc9528067c03b42edc49e6386)
+++ perlglue.xs	(revision cce93697ded79353e09913214d2d8fbf8423dc88)
@@ -405,9 +405,10 @@
 
 void
-new_variable_string(name, ival, summ, desc)
+new_variable_string(name, ival, summ, desc, validset)
 	const char * name
 	const char * ival
 	const char * summ
 	const char * desc
+	const char * validset
 	CODE:
 	owl_variable_dict_newvar_string(owl_global_get_vardict(&g),
@@ -415,12 +416,14 @@
 					summ,
 					desc,
-					ival);
-
-void
-new_variable_int(name, ival, summ, desc)
+					ival,
+					validset);
+
+void
+new_variable_int(name, ival, summ, desc, validset)
 	const char * name
 	int ival
 	const char * summ
 	const char * desc
+	const char * validset
 	CODE:
 	owl_variable_dict_newvar_int(owl_global_get_vardict(&g),
@@ -428,13 +431,17 @@
 				     summ,
 				     desc,
-				     ival);
-
-void
-new_variable_bool(name, ival, summ, desc)
+				     ival,
+				     validset);
+
+void
+new_variable_bool(name, ival, summ, desc, validset)
 	const char * name
 	int ival
 	const char * summ
 	const char * desc
-	CODE:
+	const char * validset
+	CODE:
+	if (strcmp(validset, "on,off")) /* gcc complains if we don't do anything with it, but the perl code isn't nice enough to let us get rid of it */
+		croak("Invalid bool variable valid settings: %s", validset);
 	owl_variable_dict_newvar_bool(owl_global_get_vardict(&g),
 				      name,
@@ -442,4 +449,19 @@
 				      desc,
 				      ival);
+
+void
+new_variable_enum(name, ival, summ, desc, validset)
+	const char * name
+	int ival
+	const char * summ
+	const char * desc
+	const char * validset
+	CODE:
+	owl_variable_dict_newvar_enum(owl_global_get_vardict(&g),
+				      name,
+				      summ,
+				      desc,
+				      ival,
+				      validset);
 
 void
Index: tester.c
===================================================================
--- tester.c	(revision a74a04441b9bb3d375840a9198cd9c529be66f9f)
+++ tester.c	(revision e21b9212952a5f6ff9f30193013153a0470944bb)
@@ -390,5 +390,5 @@
   FAIL_UNLESS("get int 7", 9 == owl_variable_get_int(var));
 
-  owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval");
+  owl_variable_dict_newvar_string(&vd, "stringvar", "", "", "testval", "<string>");
   FAIL_UNLESS("get new string var", NULL != (var = owl_variable_get_var(&vd, "stringvar")));
   FAIL_UNLESS("get new string var", NULL != (v = owl_variable_get(var)));
@@ -397,5 +397,21 @@
   FAIL_UNLESS("update string val", !strcmp("new val", owl_variable_get_string(var)));
 
-  owl_variable_dict_newvar_int(&vd, "intvar", "", "", 47);
+  owl_variable_dict_newvar_enum(&vd, "enumvar", "", "", 0, "foo,bar,baz");
+  FAIL_UNLESS("get new enum var", NULL != (var = owl_variable_get_var(&vd, "enumvar")));
+  FAIL_UNLESS("get new enum var", NULL != (v = owl_variable_get(var)));
+  FAIL_UNLESS("get new enum val tostring", !strcmp("foo", value = owl_variable_get_tostring(var)));
+  g_free(value);
+  FAIL_UNLESS("valid update enum var", 0 == owl_variable_set_int(var, 1));
+  FAIL_UNLESS("update int enum val tostring", !strcmp("bar", value = owl_variable_get_tostring(var)));
+  g_free(value);
+  FAIL_UNLESS("update int enum val", 1 == owl_variable_get_int(var));
+  FAIL_UNLESS("invalid update enum var", -1 == owl_variable_set_int(var, 5));
+  FAIL_UNLESS("no update int enum val", 1 == owl_variable_get_int(var));
+  FAIL_UNLESS("valid update enum var fromstring", 0 == owl_variable_set_fromstring(var, "baz", 0));
+  FAIL_UNLESS("update int enum val fromstring", 2 == owl_variable_get_int(var));
+  FAIL_UNLESS("invalid update enum var fromstring", -1 == owl_variable_set_fromstring(var, "xxx", 0));
+  FAIL_UNLESS("no update int enum val fromstring", 2 == owl_variable_get_int(var));
+
+  owl_variable_dict_newvar_int(&vd, "intvar", "", "", 47, 0);
   FAIL_UNLESS("get new int var", NULL != (var = owl_variable_get_var(&vd, "intvar")));
   FAIL_UNLESS("get new int var", NULL != (v = owl_variable_get(var)));
@@ -411,5 +427,5 @@
   FAIL_UNLESS("update bool val", !owl_variable_get_bool(var));
 
-  owl_variable_dict_newvar_string(&vd, "nullstringvar", "", "", NULL);
+  owl_variable_dict_newvar_string(&vd, "nullstringvar", "", "", NULL, "<string>");
   FAIL_UNLESS("get new string (NULL) var", NULL != (var = owl_variable_get_var(&vd, "nullstringvar")));
   FAIL_UNLESS("get string (NULL)", NULL == (value = owl_variable_get_tostring(var)));
Index: variable.c
===================================================================
--- variable.c	(revision f271129fbb186598811b923e406d65f9d2b3031a)
+++ variable.c	(revision cce93697ded79353e09913214d2d8fbf8423dc88)
@@ -3,29 +3,29 @@
 
 #define OWLVAR_BOOL(name,default,summary,description) \
-        { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, "on,off", g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, g_strdup("on,off"), g_strdup(summary), g_strdup(description), NULL, \
         NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_BOOL_FULL(name,default,summary,description,validate,set,get) \
-        { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, "on,off", g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_BOOL, NULL, default, g_strdup("on,off"), g_strdup(summary), g_strdup(description), NULL, \
         validate, set, NULL, get, NULL, NULL }
 
 #define OWLVAR_INT(name,default,summary,description) \
-        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, "<int>", g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, g_strdup("<int>"), g_strdup(summary), g_strdup(description), NULL, \
         NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_INT_FULL(name,default,summary,description,validset,validate,set,get) \
-        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, g_strdup(validset), g_strdup(summary), g_strdup(description), NULL, \
         validate, set, NULL, get, NULL, NULL }
 
 #define OWLVAR_PATH(name,default,summary,description) \
-        { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, "<path>", g_strdup(summary), g_strdup(description),  NULL, \
+        { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, g_strdup("<path>"), g_strdup(summary), g_strdup(description),  NULL, \
         NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_STRING(name,default,summary,description) \
-        { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, "<string>", g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, g_strdup("<string>"), g_strdup(summary), g_strdup(description), NULL, \
         NULL, NULL, NULL, NULL, NULL, NULL }
 
 #define OWLVAR_STRING_FULL(name,default,validset,summary,description,validate,set,get) \
-        { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, validset, g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_STRING, g_strdup(default), 0, g_strdup(validset), g_strdup(summary), g_strdup(description), NULL, \
         validate, set, NULL, get, NULL, NULL }
 
@@ -34,5 +34,5 @@
  * correspond to the values that may be specified. */
 #define OWLVAR_ENUM(name,default,summary,description,validset) \
-        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, g_strdup(validset), g_strdup(summary), g_strdup(description), NULL, \
         owl_variable_enum_validate, \
         NULL, owl_variable_enum_set_fromstring, \
@@ -41,5 +41,5 @@
 
 #define OWLVAR_ENUM_FULL(name,default,summary,description,validset,validate, set, get) \
-        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, validset, g_strdup(summary), g_strdup(description), NULL, \
+        { g_strdup(name), OWL_VARIABLE_INT, NULL, default, g_strdup(validset), g_strdup(summary), g_strdup(description), NULL, \
         validate, \
         set, owl_variable_enum_set_fromstring, \
@@ -568,4 +568,5 @@
 int owl_variable_dict_add_from_list(owl_vardict *vd, owl_variable *variables_to_init)
 {
+  int ret;
   owl_variable *var, *cur;
   for (var = variables_to_init; var->name != NULL; var++) {
@@ -576,5 +577,20 @@
     cur->summary = g_strdup(var->summary);
     cur->description = g_strdup(var->description);
-    switch (cur->type) {
+    cur->validsettings = g_strdup(var->validsettings);
+    if (cur->type == OWL_VARIABLE_STRING)
+      cur->pval_default = g_strdup(var->pval_default);
+    ret = owl_variable_init_defaults(cur);
+    if (ret != 0) {
+      fprintf(stderr, "owl_variable_setup: invalid variable type\n");
+      return ret;
+    }
+    owl_dict_insert_element(vd, cur->name, cur, NULL);
+  }
+  return 0;
+}
+
+int owl_variable_init_defaults(owl_variable *cur)
+{
+  switch (cur->type) {
     case OWL_VARIABLE_OTHER:
       cur->set_fn(cur, cur->pval_default);
@@ -593,5 +609,4 @@
       if (!cur->delete_fn)
 	cur->delete_fn = owl_variable_delete_default;
-      cur->pval_default = g_strdup(var->pval_default);
       cur->set_fn(cur, cur->pval_default);
       break;
@@ -629,8 +644,5 @@
       break;
     default:
-      fprintf(stderr, "owl_variable_setup: invalid variable type\n");
-      return(-2);
-    }
-    owl_dict_insert_element(vd, cur->name, cur, NULL);
+      return -2;
   }
   return 0;
@@ -642,5 +654,5 @@
 }
 
-CALLER_OWN owl_variable *owl_variable_newvar(const char *name, const char *summary, const char *description)
+CALLER_OWN owl_variable *owl_variable_newvar(const char *name, const char *summary, const char *description, const char *validsettings, int type)
 {
   owl_variable * var = g_new0(owl_variable, 1);
@@ -648,57 +660,36 @@
   var->summary = g_strdup(summary);
   var->description = g_strdup(description);
+  var->validsettings = g_strdup(validsettings);
+  var->type = type;
   return var;
 }
 
-void owl_variable_update(owl_variable *var, const char *summary, const char *desc) {
-  g_free(var->summary);
-  var->summary = g_strdup(summary);
-  g_free(var->description);
-  var->description = g_strdup(desc);
-}
-
-void owl_variable_dict_newvar_string(owl_vardict *vd, const char *name, const char *summ, const char *desc, const char *initval)
+void owl_variable_dict_newvar_string(owl_vardict *vd, const char *name, const char *summ, const char *desc, const char *initval, const char *validsettings)
 {
   owl_variable *old = owl_variable_get_var(vd, name);
-  if (old && owl_variable_get_type(old) == OWL_VARIABLE_STRING) {
-    owl_variable_update(old, summ, desc);
-    g_free(old->pval_default);
-    old->pval_default = g_strdup(initval);
-  } else {
-    owl_variable * var = owl_variable_newvar(name, summ, desc);
-    var->type = OWL_VARIABLE_STRING;
-    var->validsettings = "<string>";
-    var->pval_default = g_strdup(initval);
-    var->set_fn = owl_variable_string_set_default;
-    var->set_fromstring_fn = owl_variable_string_set_fromstring_default;
-    var->get_fn = owl_variable_get_default;
-    var->get_tostring_fn = owl_variable_string_get_tostring_default;
-    var->delete_fn = owl_variable_delete_default;
-    var->set_fn(var, initval);
-    owl_variable_dict_add_variable(vd, var);
-  }
-}
-
-void owl_variable_dict_newvar_int(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval)
+  char *oldval = NULL;
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_STRING)
+    oldval = owl_variable_get_tostring(old);
+  owl_variable *var = owl_variable_newvar(name, summ, desc, validsettings, OWL_VARIABLE_STRING);
+  var->pval_default = g_strdup(initval);
+  owl_variable_init_defaults(var);
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_STRING)
+    var->set_fn(var, oldval);
+  g_free(oldval);
+  owl_variable_dict_add_variable(vd, var);
+}
+
+void owl_variable_dict_newvar_int(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval, const char *validsettings)
 {
   owl_variable *old = owl_variable_get_var(vd, name);
-  if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT) {
-    owl_variable_update(old, summ, desc);
-    old->ival_default = initval;
-  } else {
-    owl_variable * var = owl_variable_newvar(name, summ, desc);
-    var->type = OWL_VARIABLE_INT;
-    var->validsettings = "<int>";
-    var->ival_default = initval;
-    var->validate_fn = owl_variable_int_validate_default;
-    var->set_fn = owl_variable_int_set_default;
-    var->set_fromstring_fn = owl_variable_int_set_fromstring_default;
-    var->get_fn = owl_variable_get_default;
-    var->get_tostring_fn = owl_variable_int_get_tostring_default;
-    var->delete_fn = owl_variable_delete_default;
-    var->val = g_new(int, 1);
-    var->set_fn(var, &initval);
-    owl_variable_dict_add_variable(vd, var);
-  }
+  int oldval;
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT)
+    oldval = owl_variable_get_int(old);
+  owl_variable *var = owl_variable_newvar(name, summ, desc, validsettings, OWL_VARIABLE_INT);
+  var->ival_default = initval;
+  owl_variable_init_defaults(var);
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT)
+    var->set_fn(var, &oldval);
+  owl_variable_dict_add_variable(vd, var);
 }
 
@@ -706,22 +697,30 @@
 {
   owl_variable *old = owl_variable_get_var(vd, name);
-  if (old && owl_variable_get_type(old) == OWL_VARIABLE_BOOL) {
-    owl_variable_update(old, summ, desc);
-    old->ival_default = initval;
-  } else {
-    owl_variable * var = owl_variable_newvar(name, summ, desc);
-    var->type = OWL_VARIABLE_BOOL;
-    var->validsettings = "on,off";
-    var->ival_default = initval;
-    var->validate_fn = owl_variable_bool_validate_default;
-    var->set_fn = owl_variable_bool_set_default;
-    var->set_fromstring_fn = owl_variable_bool_set_fromstring_default;
-    var->get_fn = owl_variable_get_default;
-    var->get_tostring_fn = owl_variable_bool_get_tostring_default;
-    var->delete_fn = owl_variable_delete_default;
-    var->val = g_new(int, 1);
-    var->set_fn(var, &initval);
-    owl_variable_dict_add_variable(vd, var);
-  }
+  int oldval;
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_BOOL)
+    oldval = owl_variable_get_bool(old);
+  owl_variable *var = owl_variable_newvar(name, summ, desc, "on,off", OWL_VARIABLE_BOOL);
+  var->ival_default = initval;
+  owl_variable_init_defaults(var);
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_BOOL)
+    var->set_fn(var, &oldval);
+  owl_variable_dict_add_variable(vd, var);
+}
+
+void owl_variable_dict_newvar_enum(owl_vardict *vd, const char *name, const char *summ, const char *desc, int initval, const char *validsettings)
+{
+  owl_variable *old = owl_variable_get_var(vd, name);
+  int oldval;
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT)
+    oldval = owl_variable_get_int(old);
+  owl_variable *var = owl_variable_newvar(name, summ, desc, validsettings, OWL_VARIABLE_INT);
+  var->ival_default = initval;
+  var->validate_fn = owl_variable_enum_validate;
+  var->set_fromstring_fn = owl_variable_enum_set_fromstring;
+  var->get_tostring_fn = owl_variable_enum_get_tostring;
+  owl_variable_init_defaults(var);
+  if (old && owl_variable_get_type(old) == OWL_VARIABLE_INT)
+    var->set_fn(var, &oldval);
+  owl_variable_dict_add_variable(vd, var);
 }
 
@@ -741,4 +740,5 @@
   g_free(v->summary);
   g_free(v->description);
+  g_free(v->validsettings);
   if (v->type == OWL_VARIABLE_STRING)
     g_free(v->pval_default);
