diff --git a/Common/Context.cpp b/Common/Context.cpp
index 4b000ca1f61b1957a2e48a063a07b9aa0b58a7dc..3b36d9fc547071784eacded10dc20eb494d1c922 100644
--- a/Common/Context.cpp
+++ b/Common/Context.cpp
@@ -1,4 +1,4 @@
-// $Id: Context.cpp,v 1.62 2008-03-20 11:44:02 geuzaine Exp $
+// $Id: Context.cpp,v 1.63 2008-07-05 23:00:57 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -21,7 +21,6 @@
 
 #include "Numeric.h"
 #include "Context.h"
-#include "DefaultOptions.h"
 #include "Trackball.h"
 
 void Context_T::buildRotationMatrix(void)
diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index e6bdc49c1bc15c3eb5cc57006a8a7cb98f836f4a..3fde28c75abc7eb10e95fb04a735d3a2fda4d2cb 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -1,4 +1,4 @@
-// $Id: Gmsh.cpp,v 1.8 2008-07-04 14:58:30 geuzaine Exp $
+// $Id: Gmsh.cpp,v 1.9 2008-07-05 23:00:57 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -79,6 +79,20 @@ int GmshSetMessageHandler(GmshMessage *callback)
   return 1;
 }
 
+int GmshSetOption(std::string category, std::string name, std::string value, int index)
+{
+  if(StringOption(GMSH_SET, category.c_str(), index, name.c_str(), value.c_str()))
+    return 1;
+  return 0;
+}
+
+int GmshSetOption(std::string category, std::string name, double value, int index)
+{
+  if(NumberOption(GMSH_SET, category.c_str(), index, name.c_str(), value))
+    return 1;
+  return 0;
+}
+
 int GmshFinalize()
 {
   return 1;
diff --git a/Common/Gmsh.h b/Common/Gmsh.h
index fe50f022e43dfa5e552c9581116a9947eb350842..90ac7174cf6a71bc4b477ac111db5444086e33d3 100644
--- a/Common/Gmsh.h
+++ b/Common/Gmsh.h
@@ -30,6 +30,8 @@ class GmshMessage{
 
 int GmshInitialize(int argc=0, char **argv=0);
 int GmshSetMessageHandler(GmshMessage *callback);
+int GmshSetOption(std::string category, std::string name, std::string value, int index=0);
+int GmshSetOption(std::string category, std::string name, double value, int index=0);
 int GmshFinalize();
 int GmshBatch();
 
diff --git a/Common/Makefile b/Common/Makefile
index db1abee2aa2459354e9e549c897c83b680e94a59..ed671f196b7f920b8ae7f8bd116dc45576f2820a 100644
--- a/Common/Makefile
+++ b/Common/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.181 2008-07-04 14:58:30 geuzaine Exp $
+# $Id: Makefile,v 1.182 2008-07-05 23:00:57 geuzaine Exp $
 #
 # Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 #
@@ -76,20 +76,19 @@ depend:
 
 # DO NOT DELETE THIS LINE
 Context.o: Context.cpp ../Numeric/Numeric.h ../Numeric/NumericEmbedded.h \
-  Context.h DefaultOptions.h GmshDefines.h Options.h ../Post/ColorTable.h \
-  Trackball.h
+  Context.h Trackball.h
 Octree.o: Octree.cpp Octree.h OctreeInternals.h
 OctreeInternals.o: OctreeInternals.cpp Message.h OctreeInternals.h
 Options.o: Options.cpp GmshUI.h GmshDefines.h Message.h \
   ../Graphics/Draw.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
   ../Mesh/Generator.h Context.h Options.h ../Post/ColorTable.h \
-  ../Mesh/BackgroundMesh.h ../Post/PView.h ../Post/PViewOptions.h \
-  ../Post/ColorTable.h ../Post/PViewData.h ../Post/adaptiveData.h \
-  ../Common/ListUtils.h ../Common/GmshMatrix.h ../Plugin/PluginManager.h \
-  ../Plugin/Plugin.h ../Common/Options.h ../Common/Message.h \
-  ../Post/PViewDataList.h ../Post/PViewData.h ../Fltk/Solvers.h \
-  ../Fltk/GUI.h ../Fltk/Opengl_Window.h ../Fltk/Colorbar_Window.h \
-  ../Common/GmshUI.h ../Fltk/Popup_Button.h \
+  DefaultOptions.h ../Mesh/BackgroundMesh.h ../Post/PView.h \
+  ../Post/PViewOptions.h ../Post/ColorTable.h ../Post/PViewData.h \
+  ../Post/adaptiveData.h ../Common/ListUtils.h ../Common/GmshMatrix.h \
+  ../Plugin/PluginManager.h ../Plugin/Plugin.h ../Common/Options.h \
+  ../Common/Message.h ../Post/PViewDataList.h ../Post/PViewData.h \
+  ../Fltk/Solvers.h ../Fltk/GUI.h ../Fltk/Opengl_Window.h \
+  ../Fltk/Colorbar_Window.h ../Common/GmshUI.h ../Fltk/Popup_Button.h \
   ../Fltk/SpherePosition_Widget.h ../Mesh/Field.h ../Geo/Geo.h \
   ../Common/GmshDefines.h ../Geo/gmshSurface.h ../Geo/Pair.h \
   ../Geo/Range.h ../Geo/SPoint2.h ../Geo/SPoint3.h ../Geo/SVector3.h \
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 2e5148d8f967783bccd5f453bf3257899a452a3b..daed903e82b8aaeb42f825e0040bb47cc1900700 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.403 2008-07-04 18:32:39 geuzaine Exp $
+// $Id: Options.cpp,v 1.404 2008-07-05 23:00:57 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -28,6 +28,7 @@
 #include "Generator.h"
 #include "Context.h"
 #include "Options.h"
+#include "DefaultOptions.h"
 #include "BackgroundMesh.h"
 
 #if !defined(HAVE_NO_POST)
@@ -47,6 +48,347 @@ extern void activate_cb(Fl_Widget* w, void* data);
 
 extern Context_T CTX;
 
+// General routines for string options
+
+bool StringOption(int action, const char *category, int num, 
+		  const char *name, const char *val)
+{
+  StringXString *s = 0;
+  if(!strcmp(category, "General"))
+    s = GeneralOptions_String;
+  else if(!strcmp(category, "Geometry"))
+    s = GeometryOptions_String;
+  else if(!strcmp(category, "Mesh"))
+    s = MeshOptions_String;
+  else if(!strcmp(category, "Solver"))
+    s = SolverOptions_String;
+  else if(!strcmp(category, "PostProcessing"))
+    s = PostProcessingOptions_String;
+  else if(!strcmp(category, "View"))
+    s = ViewOptions_String;
+  else if(!strcmp(category, "Print"))
+    s = PrintOptions_String;
+  else{
+    Msg::Error("Unknown string option category '%s'", category);
+    return false;
+  }
+
+  int i = 0;
+  while(s[i].str && strcmp(s[i].str, name)) i++;
+  if(!s[i].str){
+    Msg::Error("Unknown string option '%s.%s'", category, name);
+    return false;
+  }
+
+  s[i].function(num, action, val);
+  return true;
+}
+
+static void Set_DefaultStringOptions(int num, StringXString s[])
+{
+  int i = 0;
+  while(s[i].str) {
+    s[i].function(num, GMSH_SET, s[i].def);
+    i++;
+  }
+}
+
+static void Set_StringOptions_GUI(int num, StringXString s[])
+{
+  int i = 0;
+  while(s[i].str) {
+    s[i].function(num, GMSH_GUI, 0);
+    i++;
+  }
+}
+
+static void Print_StringOptions(int num, int level, int diff, int help, 
+				StringXString s[], const char *prefix, FILE *file)
+{
+  int i = 0;
+  char tmp[1024];
+  while(s[i].str) {
+    if(s[i].level & level) {
+      if(!diff || strcmp(s[i].function(num, GMSH_GET, NULL), s[i].def)){
+        sprintf(tmp, "%s%s = \"%s\";%s%s", prefix,
+                s[i].str, s[i].function(num, GMSH_GET, NULL), 
+                help ? " // " : "", help ? s[i].help : "");
+        if(file)
+          fprintf(file, "%s\n", tmp);
+        else
+          Msg::Direct("%s", tmp);
+      }
+    }
+    i++;
+  }
+}
+
+static const char *Get_OptionSaveLevel(int level){
+  if(level & GMSH_SESSIONRC){
+    return "General.SessionFileName";
+  }
+  else if(level & GMSH_OPTIONSRC){
+    return "General.OptionsFileName";
+  }
+  else{
+    return "-";
+  }
+}
+
+static void Print_StringOptionsDoc(StringXString s[], const char *prefix, FILE *file)
+{
+  int i = 0, j;
+  char tmp[1024];
+
+  while(s[i].str) {
+    fprintf(file, "@item %s%s\n", prefix, s[i].str);
+    fprintf(file, "%s@*\n", s[i].help);
+
+    // sanitize the string for texinfo
+    const char *ptr = s[i].function(0, GMSH_GET, NULL);
+    int len = strlen(ptr);
+    j = 0;
+    while(j < len){
+      tmp[j] = *(ptr++);
+      if(j && tmp[j] == '\n' && tmp[j-1] == '\n')
+        tmp[j-1] = '.';
+      j++;
+      if(j == 1023) break;
+    }
+    tmp[j] = '\0';
+
+    fprintf(file, "Default value: @code{\"%s\"}@*\n", tmp);
+    fprintf(file, "Saved in: @code{%s}\n\n", Get_OptionSaveLevel(s[i].level));
+    i++;
+  }
+}
+
+// General routines for numeric options
+
+bool NumberOption(int action, const char *category, int num, 
+		  const char *name, double &val)
+{
+  StringXNumber *s = 0;
+  if(!strcmp(category, "General"))
+    s = GeneralOptions_Number;
+  else if(!strcmp(category, "Geometry"))
+    s = GeometryOptions_Number;
+  else if(!strcmp(category, "Mesh"))
+    s = MeshOptions_Number;
+  else if(!strcmp(category, "Solver"))
+    s = SolverOptions_Number;
+  else if(!strcmp(category, "PostProcessing"))
+    s = PostProcessingOptions_Number;
+  else if(!strcmp(category, "View"))
+    s = ViewOptions_Number;
+  else if(!strcmp(category, "Print"))
+    s = PrintOptions_Number;
+  else{
+    Msg::Error("Unknown number option category '%s'", category);
+    return false;
+  }
+
+  int i = 0;
+  while((s[i].str != NULL) && (strcmp(s[i].str, name))) i++;
+  if(!s[i].str){
+    Msg::Error("Unknown number option '%s.%s'", category, name);
+    return false;
+  }
+  val = s[i].function(num, action, val);
+  return true;
+}
+
+static void Set_DefaultNumberOptions(int num, StringXNumber s[])
+{
+  int i = 0;
+  while(s[i].str) {
+    s[i].function(num, GMSH_SET, s[i].def);
+    i++;
+  }
+}
+
+static void Set_NumberOptions_GUI(int num, StringXNumber s[])
+{
+  int i = 0;
+  while(s[i].str) {
+    s[i].function(num, GMSH_GUI, 0);
+    i++;
+  }
+}
+
+static void Print_NumberOptions(int num, int level, int diff, int help,
+				StringXNumber s[], const char *prefix, FILE * file)
+{
+  int i = 0;
+  char tmp[1024];
+  while(s[i].str) {
+    if(s[i].level & level) {
+      if(!diff || (s[i].function(num, GMSH_GET, 0) != s[i].def)){
+        sprintf(tmp, "%s%s = %.16g;%s%s", prefix,
+                s[i].str, s[i].function(num, GMSH_GET, 0), 
+                help ? " // " : "", help ? s[i].help : "");
+        if(file)
+          fprintf(file, "%s\n", tmp);
+        else
+          Msg::Direct(tmp);
+      }
+    }
+    i++;
+  }
+}
+
+static void Print_NumberOptionsDoc(StringXNumber s[], const char *prefix, FILE * file)
+{
+  int i = 0;
+  while(s[i].str) {
+    fprintf(file, "@item %s%s\n", prefix, s[i].str);
+    fprintf(file, "%s@*\n", s[i].help);
+    fprintf(file, "Default value: @code{%g}@*\n", s[i].function(0, GMSH_GET, 0));
+    fprintf(file, "Saved in: @code{%s}\n\n", Get_OptionSaveLevel(s[i].level));
+    i++;
+  }
+}
+
+// General routines for color options
+
+bool ColorOption(int action, const char *category, int num, 
+		 const char *name, unsigned int &val)
+{
+  StringXColor *s = 0;
+  if(!strcmp(category, "General"))
+    s = GeneralOptions_Color;
+  else if(!strcmp(category, "Geometry"))
+    s = GeometryOptions_Color;
+  else if(!strcmp(category, "Mesh"))
+    s = MeshOptions_Color;
+  else if(!strcmp(category, "Solver"))
+    s = SolverOptions_Color;
+  else if(!strcmp(category, "PostProcessing"))
+    s = PostProcessingOptions_Color;
+  else if(!strcmp(category, "View"))
+    s = ViewOptions_Color;
+  else if(!strcmp(category, "Print"))
+    s = PrintOptions_Color;
+  else{
+    Msg::Error("Unknown color option category '%s'", category);
+    return false;
+  }
+
+  int i = 0;
+  while((s[i].str != NULL) && (strcmp(s[i].str, name))) i++;
+  if(!s[i].str){
+    Msg::Error("Unknown color option '%s.%s'", category, name);
+    return false;
+  }
+  val = s[i].function(num, action, val);
+  return true;
+}
+
+int Get_ColorForString(StringX4Int SX4I[], int alpha,
+                       const char *str, int *FlagError)
+{
+  int i = 0;
+  while((SX4I[i].str != NULL) && (strcmp(SX4I[i].str, str)))
+    i++;
+  *FlagError = (SX4I[i].str == NULL) ? 1 : 0;
+  if(alpha > 0)
+    return CTX.PACK_COLOR(SX4I[i].int1, SX4I[i].int2, SX4I[i].int3, alpha);
+  else
+    return CTX.PACK_COLOR(SX4I[i].int1, SX4I[i].int2, SX4I[i].int3, SX4I[i].int4);
+}
+
+static void Set_DefaultColorOptions(int num, StringXColor s[])
+{
+  int i = 0;
+  // Warning: this assumes that CTX.color_scheme is set...
+  switch (CTX.color_scheme) {
+  case 1:
+    while(s[i].str) {
+      s[i].function(num, GMSH_SET, CTX.PACK_COLOR(s[i].def2[0], s[i].def2[1],
+                                                  s[i].def2[2], s[i].def2[3]));
+      i++;
+    }
+    break;
+  case 2:
+    while(s[i].str) {
+      s[i].function(num, GMSH_SET, CTX.PACK_COLOR(s[i].def3[0], s[i].def3[1],
+                                                  s[i].def3[2], s[i].def3[3]));
+      i++;
+    }
+    break;
+  default:
+    while(s[i].str) {
+      s[i].function(num, GMSH_SET, CTX.PACK_COLOR(s[i].def1[0], s[i].def1[1],
+                                                  s[i].def1[2], s[i].def1[3]));
+      i++;
+    }
+    break;
+  }
+}
+
+static void Set_ColorOptions_GUI(int num, StringXColor s[])
+{
+  int i = 0;
+  while(s[i].str) {
+    s[i].function(num, GMSH_GUI, 0);
+    i++;
+  }
+}
+
+static void Print_ColorOptions(int num, int level, int diff, int help,
+			       StringXColor s[], const char *prefix, FILE * file)
+{
+  int i = 0;
+  char tmp[1024];
+  while(s[i].str) {
+    if(s[i].level & level) {
+      unsigned int def;
+      switch (CTX.color_scheme) {
+      case 1: 
+        def = CTX.PACK_COLOR(s[i].def2[0], s[i].def2[1],
+                             s[i].def2[2], s[i].def2[3]);
+        break;
+      case 2: 
+        def = CTX.PACK_COLOR(s[i].def3[0], s[i].def3[1], 
+                             s[i].def3[2], s[i].def3[3]);
+        break;
+      default: 
+        def = CTX.PACK_COLOR(s[i].def1[0], s[i].def1[1], 
+                             s[i].def1[2], s[i].def1[3]);
+        break;
+      }
+      if(!diff || (s[i].function(num, GMSH_GET, 0) != def)){
+        sprintf(tmp, "%sColor.%s = {%d,%d,%d};%s%s",
+                prefix, s[i].str,
+                CTX.UNPACK_RED(s[i].function(num, GMSH_GET, 0)),
+                CTX.UNPACK_GREEN(s[i].function(num, GMSH_GET, 0)),
+                CTX.UNPACK_BLUE(s[i].function(num, GMSH_GET, 0)), 
+                help ? " // " : "", help ? s[i].help : "");
+        if(file)
+          fprintf(file, "%s\n", tmp);
+        else
+          Msg::Direct(tmp);
+      }
+    }
+    i++;
+  }
+}
+
+static void Print_ColorOptionsDoc(StringXColor s[], const char *prefix, FILE * file)
+{
+  int i = 0;
+  while(s[i].str) {
+    fprintf(file, "@item %sColor.%s\n", prefix, s[i].str);
+    fprintf(file, "%s@*\n", s[i].help);
+    fprintf(file, "Default value: @code{@{%d,%d,%d@}}@*\n",
+            CTX.UNPACK_RED(s[i].function(0, GMSH_GET, 0)),
+            CTX.UNPACK_GREEN(s[i].function(0, GMSH_GET, 0)),
+            CTX.UNPACK_BLUE(s[i].function(0, GMSH_GET, 0)));
+    fprintf(file, "Saved in: @code{%s}\n\n", Get_OptionSaveLevel(s[i].level));
+    i++;
+  }
+}
+
 // General routines
 
 void Init_Options_Safe(int num)
@@ -375,18 +717,6 @@ void Print_Options(int num, int level, int diff, int help, const char *filename)
   if(filename) fclose(file);
 }
 
-static const char *Get_OptionSaveLevel(int level){
-  if(level & GMSH_SESSIONRC){
-    return "General.SessionFileName";
-  }
-  else if(level & GMSH_OPTIONSRC){
-    return "General.OptionsFileName";
-  }
-  else{
-    return "-";
-  }
-}
-
 void Print_OptionsDoc()
 {
   FILE *file;
@@ -532,330 +862,6 @@ void Print_OptionsDoc()
 #endif
 }
 
-// General routines for string options
-
-StringXString *Get_StringOptionCategory(const char *cat)
-{
-  if(!strcmp(cat, "General"))
-    return GeneralOptions_String;
-  else if(!strcmp(cat, "Geometry"))
-    return GeometryOptions_String;
-  else if(!strcmp(cat, "Mesh"))
-    return MeshOptions_String;
-  else if(!strcmp(cat, "Solver"))
-    return SolverOptions_String;
-  else if(!strcmp(cat, "PostProcessing"))
-    return PostProcessingOptions_String;
-  else if(!strcmp(cat, "View"))
-    return ViewOptions_String;
-  else if(!strcmp(cat, "Print"))
-    return PrintOptions_String;
-  else
-    return NULL;
-}
-
-void Set_DefaultStringOptions(int num, StringXString s[])
-{
-  int i = 0;
-  while(s[i].str) {
-    s[i].function(num, GMSH_SET, s[i].def);
-    i++;
-  }
-}
-
-void Set_StringOptions_GUI(int num, StringXString s[])
-{
-  int i = 0;
-  while(s[i].str) {
-    s[i].function(num, GMSH_GUI, 0);
-    i++;
-  }
-}
-
-void *Get_StringOption(const char *str, StringXString s[])
-{
-  int i = 0;
-  while((s[i].str != NULL) && (strcmp(s[i].str, str)))
-    i++;
-  if(!s[i].str)
-    return NULL;
-  else
-    return (void *)s[i].function;
-}
-
-void Print_StringOptions(int num, int level, int diff, int help, 
-                         StringXString s[], const char *prefix, FILE *file)
-{
-  int i = 0;
-  char tmp[1024];
-  while(s[i].str) {
-    if(s[i].level & level) {
-      if(!diff || strcmp(s[i].function(num, GMSH_GET, NULL), s[i].def)){
-        sprintf(tmp, "%s%s = \"%s\";%s%s", prefix,
-                s[i].str, s[i].function(num, GMSH_GET, NULL), 
-                help ? " // " : "", help ? s[i].help : "");
-        if(file)
-          fprintf(file, "%s\n", tmp);
-        else
-          Msg::Direct("%s", tmp);
-      }
-    }
-    i++;
-  }
-}
-
-void Print_StringOptionsDoc(StringXString s[], const char *prefix, FILE *file)
-{
-  int i = 0, j;
-  char tmp[1024];
-
-  while(s[i].str) {
-    fprintf(file, "@item %s%s\n", prefix, s[i].str);
-    fprintf(file, "%s@*\n", s[i].help);
-
-    // sanitize the string for texinfo
-    const char *ptr = s[i].function(0, GMSH_GET, NULL);
-    int len = strlen(ptr);
-    j = 0;
-    while(j < len){
-      tmp[j] = *(ptr++);
-      if(j && tmp[j] == '\n' && tmp[j-1] == '\n')
-        tmp[j-1] = '.';
-      j++;
-      if(j == 1023) break;
-    }
-    tmp[j] = '\0';
-
-    fprintf(file, "Default value: @code{\"%s\"}@*\n", tmp);
-    fprintf(file, "Saved in: @code{%s}\n\n", Get_OptionSaveLevel(s[i].level));
-    i++;
-  }
-}
-
-// General routines for numeric options
-
-StringXNumber *Get_NumberOptionCategory(const char *cat)
-{
-  if(!strcmp(cat, "General"))
-    return GeneralOptions_Number;
-  else if(!strcmp(cat, "Geometry"))
-    return GeometryOptions_Number;
-  else if(!strcmp(cat, "Mesh"))
-    return MeshOptions_Number;
-  else if(!strcmp(cat, "Solver"))
-    return SolverOptions_Number;
-  else if(!strcmp(cat, "PostProcessing"))
-    return PostProcessingOptions_Number;
-  else if(!strcmp(cat, "View"))
-    return ViewOptions_Number;
-  else if(!strcmp(cat, "Print"))
-    return PrintOptions_Number;
-  else
-    return NULL;
-}
-
-void Set_DefaultNumberOptions(int num, StringXNumber s[])
-{
-  int i = 0;
-  while(s[i].str) {
-    s[i].function(num, GMSH_SET, s[i].def);
-    i++;
-  }
-}
-
-void Set_NumberOptions_GUI(int num, StringXNumber s[])
-{
-  int i = 0;
-  while(s[i].str) {
-    s[i].function(num, GMSH_GUI, 0);
-    i++;
-  }
-}
-
-void *Get_NumberOption(const char *str, StringXNumber s[])
-{
-  int i = 0;
-
-  while((s[i].str != NULL) && (strcmp(s[i].str, str)))
-    i++;
-  if(!s[i].str)
-    return NULL;
-  else {
-    return (void *)s[i].function;
-  }
-}
-
-void Print_NumberOptions(int num, int level, int diff, int help,
-                         StringXNumber s[], const char *prefix, FILE * file)
-{
-  int i = 0;
-  char tmp[1024];
-  while(s[i].str) {
-    if(s[i].level & level) {
-      if(!diff || (s[i].function(num, GMSH_GET, 0) != s[i].def)){
-        sprintf(tmp, "%s%s = %.16g;%s%s", prefix,
-                s[i].str, s[i].function(num, GMSH_GET, 0), 
-                help ? " // " : "", help ? s[i].help : "");
-        if(file)
-          fprintf(file, "%s\n", tmp);
-        else
-          Msg::Direct(tmp);
-      }
-    }
-    i++;
-  }
-}
-
-void Print_NumberOptionsDoc(StringXNumber s[], const char *prefix, FILE * file)
-{
-  int i = 0;
-  while(s[i].str) {
-    fprintf(file, "@item %s%s\n", prefix, s[i].str);
-    fprintf(file, "%s@*\n", s[i].help);
-    fprintf(file, "Default value: @code{%g}@*\n", s[i].function(0, GMSH_GET, 0));
-    fprintf(file, "Saved in: @code{%s}\n\n", Get_OptionSaveLevel(s[i].level));
-    i++;
-  }
-}
-
-// General routines for color options
-
-StringXColor *Get_ColorOptionCategory(const char *cat)
-{
-  if(!strcmp(cat, "General"))
-    return GeneralOptions_Color;
-  else if(!strcmp(cat, "Geometry"))
-    return GeometryOptions_Color;
-  else if(!strcmp(cat, "Mesh"))
-    return MeshOptions_Color;
-  else if(!strcmp(cat, "Solver"))
-    return SolverOptions_Color;
-  else if(!strcmp(cat, "PostProcessing"))
-    return PostProcessingOptions_Color;
-  else if(!strcmp(cat, "View"))
-    return ViewOptions_Color;
-  else if(!strcmp(cat, "Print"))
-    return PrintOptions_Color;
-  else
-    return NULL;
-}
-
-void Set_DefaultColorOptions(int num, StringXColor s[])
-{
-  int i = 0;
-  // Warning: this assumes that CTX.color_scheme is set...
-  switch (CTX.color_scheme) {
-  case 1:
-    while(s[i].str) {
-      s[i].function(num, GMSH_SET, CTX.PACK_COLOR(s[i].def2[0], s[i].def2[1],
-                                                  s[i].def2[2], s[i].def2[3]));
-      i++;
-    }
-    break;
-  case 2:
-    while(s[i].str) {
-      s[i].function(num, GMSH_SET, CTX.PACK_COLOR(s[i].def3[0], s[i].def3[1],
-                                                  s[i].def3[2], s[i].def3[3]));
-      i++;
-    }
-    break;
-  default:
-    while(s[i].str) {
-      s[i].function(num, GMSH_SET, CTX.PACK_COLOR(s[i].def1[0], s[i].def1[1],
-                                                  s[i].def1[2], s[i].def1[3]));
-      i++;
-    }
-    break;
-  }
-}
-
-void Set_ColorOptions_GUI(int num, StringXColor s[])
-{
-  int i = 0;
-  while(s[i].str) {
-    s[i].function(num, GMSH_GUI, 0);
-    i++;
-  }
-}
-
-void *Get_ColorOption(const char *str, StringXColor s[])
-{
-  int i = 0;
-  while((s[i].str != NULL) && (strcmp(s[i].str, str)))
-    i++;
-  if(!s[i].str)
-    return NULL;
-  else
-    return (void *)s[i].function;
-}
-
-void Print_ColorOptions(int num, int level, int diff, int help,
-                        StringXColor s[], const char *prefix, FILE * file)
-{
-  int i = 0;
-  char tmp[1024];
-  while(s[i].str) {
-    if(s[i].level & level) {
-      unsigned int def;
-      switch (CTX.color_scheme) {
-      case 1: 
-        def = CTX.PACK_COLOR(s[i].def2[0], s[i].def2[1],
-                             s[i].def2[2], s[i].def2[3]);
-        break;
-      case 2: 
-        def = CTX.PACK_COLOR(s[i].def3[0], s[i].def3[1], 
-                             s[i].def3[2], s[i].def3[3]);
-        break;
-      default: 
-        def = CTX.PACK_COLOR(s[i].def1[0], s[i].def1[1], 
-                             s[i].def1[2], s[i].def1[3]);
-        break;
-      }
-      if(!diff || (s[i].function(num, GMSH_GET, 0) != def)){
-        sprintf(tmp, "%sColor.%s = {%d,%d,%d};%s%s",
-                prefix, s[i].str,
-                CTX.UNPACK_RED(s[i].function(num, GMSH_GET, 0)),
-                CTX.UNPACK_GREEN(s[i].function(num, GMSH_GET, 0)),
-                CTX.UNPACK_BLUE(s[i].function(num, GMSH_GET, 0)), 
-                help ? " // " : "", help ? s[i].help : "");
-        if(file)
-          fprintf(file, "%s\n", tmp);
-        else
-          Msg::Direct(tmp);
-      }
-    }
-    i++;
-  }
-}
-
-void Print_ColorOptionsDoc(StringXColor s[], const char *prefix, FILE * file)
-{
-  int i = 0;
-  while(s[i].str) {
-    fprintf(file, "@item %sColor.%s\n", prefix, s[i].str);
-    fprintf(file, "%s@*\n", s[i].help);
-    fprintf(file, "Default value: @code{@{%d,%d,%d@}}@*\n",
-            CTX.UNPACK_RED(s[i].function(0, GMSH_GET, 0)),
-            CTX.UNPACK_GREEN(s[i].function(0, GMSH_GET, 0)),
-            CTX.UNPACK_BLUE(s[i].function(0, GMSH_GET, 0)));
-    fprintf(file, "Saved in: @code{%s}\n\n", Get_OptionSaveLevel(s[i].level));
-    i++;
-  }
-}
-
-int Get_ColorForString(StringX4Int SX4I[], int alpha,
-                       const char *str, int *FlagError)
-{
-  int i = 0;
-  while((SX4I[i].str != NULL) && (strcmp(SX4I[i].str, str)))
-    i++;
-  *FlagError = (SX4I[i].str == NULL) ? 1 : 0;
-  if(alpha > 0)
-    return CTX.PACK_COLOR(SX4I[i].int1, SX4I[i].int2, SX4I[i].int3, alpha);
-  else
-    return CTX.PACK_COLOR(SX4I[i].int1, SX4I[i].int2, SX4I[i].int3, SX4I[i].int4);
-}
-
 #define GET_VIEW(error_val)                                     \
   PView *view = 0;                                              \
   PViewData *data = 0;                                          \
diff --git a/Common/Options.h b/Common/Options.h
index f427dba05ad51c46ab172da19e8750895874d95b..cf862bfb112a2ea010ec82881446b08116fa7db2 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -749,30 +749,30 @@ typedef struct {
 
 typedef struct {
   int level;
-  const char *str ;
-  const char * (*function)(int num, int action, const char *val) ;
-  const char *def ;
-  const char *help ;
-} StringXString ;
+  const char *str;
+  const char * (*function)(int num, int action, const char *val);
+  const char *def;
+  const char *help;
+} StringXString;
 
 typedef struct {
   int level;
   const char *str;
-  double (*function)(int num, int action, double val) ;
+  double (*function)(int num, int action, double val);
   double def ;
-  const char *help ;
-} StringXNumber ;
+  const char *help;
+} StringXNumber;
 
 typedef struct {
   int level;
-  const char *str ; 
-  unsigned int (*function)(int num, int action, unsigned int val) ;
+  const char *str;
+  unsigned int (*function)(int num, int action, unsigned int val);
   // the defaults are stored in individual bytes so that we can initialize
   // them statically independently of the machine endianness. They will be
   // packed into unsigned ints at runtime
-  unsigned char def1[4], def2[4], def3[4] ;
-  const char *help ;
-} StringXColor ;
+  unsigned char def1[4], def2[4], def3[4];
+  const char *help;
+} StringXColor;
 
 void Init_Options(int num);
 void Init_Options_GUI(int num);
@@ -780,57 +780,13 @@ void ReInit_Options(int num);
 void Print_Options(int num, int level, int diff, int help, const char *filename);
 void Print_OptionsDoc();
 
-StringXString *Get_StringOptionCategory(const char *cat);
-StringXNumber *Get_NumberOptionCategory(const char *cat);
-StringXColor *Get_ColorOptionCategory(const char *cat);
-
-void Set_DefaultStringOptions(int num, StringXString s[]);
-void Set_DefaultNumberOptions(int num, StringXNumber s[]);
-void Set_DefaultColorOptions(int num, StringXColor s[]);
-
-void Set_StringOptions_GUI(int num, StringXString s[]);
-void Set_NumberOptions_GUI(int num, StringXNumber s[]);
-void Set_ColorOptions_GUI(int num, StringXColor s[]);
-
-void * Get_StringOption(const char *str, StringXString s[]);
-void * Get_NumberOption(const char *str, StringXNumber s[]);
-void * Get_ColorOption(const char *str, StringXColor s[]);
-
-void Print_StringOptions(int num, int level, int diff, int help,
-                         StringXString s[], const char *prefix, FILE *file);
-void Print_NumberOptions(int num, int level, int diff, int help,
-                         StringXNumber s[], const char *prefix, FILE *file);
-void Print_ColorOptions(int num, int level, int diff, int help,
-                        StringXColor s[], const char *prefix, FILE *file);
-
-void Print_StringOptionsDoc(StringXString s[], const char *prefix, FILE * file);
-void Print_NumberOptionsDoc(StringXNumber s[], const char *prefix, FILE * file);
-void Print_ColorOptionsDoc(StringXColor s[], const char *prefix, FILE * file);
+bool StringOption(int action, const char *category, int num, 
+		  const char *name, const char *val);
+bool NumberOption(int action, const char *category, int num, 
+		  const char *name, double &val);
+bool ColorOption(int action, const char *category, int num, 
+		 const char *name, unsigned int &val);
 
 GmshColorTable *Get_ColorTable(int num);
 
-extern StringXString GeneralOptions_String[] ;
-extern StringXString GeometryOptions_String[] ;
-extern StringXString MeshOptions_String[] ;
-extern StringXString SolverOptions_String[] ;
-extern StringXString PostProcessingOptions_String[] ;
-extern StringXString ViewOptions_String[] ;
-extern StringXString PrintOptions_String[] ;
-
-extern StringXNumber GeneralOptions_Number[] ;
-extern StringXNumber GeometryOptions_Number[] ;
-extern StringXNumber MeshOptions_Number[] ;
-extern StringXNumber SolverOptions_Number[] ;
-extern StringXNumber PostProcessingOptions_Number[] ;
-extern StringXNumber ViewOptions_Number[] ;
-extern StringXNumber PrintOptions_Number[] ;
-
-extern StringXColor GeneralOptions_Color[] ;
-extern StringXColor GeometryOptions_Color[] ;
-extern StringXColor MeshOptions_Color[] ;
-extern StringXColor SolverOptions_Color[] ;
-extern StringXColor PostProcessingOptions_Color[] ;
-extern StringXColor ViewOptions_Color[] ;
-extern StringXColor PrintOptions_Color[] ;
-
 #endif
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index 58a7e1536addf1f96f060a92af10c39ee51e597b..d737812a9fc6712acb594a1e60ab7f781c20c61f 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.693 2008-07-04 18:32:39 geuzaine Exp $
+// $Id: GUI.cpp,v 1.694 2008-07-05 23:00:57 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -54,6 +54,14 @@
 
 extern Context_T CTX;
 
+extern StringXColor GeneralOptions_Color[] ;
+extern StringXColor GeometryOptions_Color[] ;
+extern StringXColor MeshOptions_Color[] ;
+extern StringXColor SolverOptions_Color[] ;
+extern StringXColor PostProcessingOptions_Color[] ;
+extern StringXColor ViewOptions_Color[] ;
+extern StringXColor PrintOptions_Color[] ;
+
 // Definition of the static menus (we cannot use the 'g', 'm' 's' and
 // 'p' mnemonics since they are already defined as global shortcuts)
 
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index c1e6e3a1f1a44090e113bbd3bdf96108950a7fb9..c83548dcb9ce1b91ac9143986162998b3d4b7d24 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -324,7 +324,7 @@
 /* Copy the first part of user declarations.  */
 #line 1 "Gmsh.y"
 
-// $Id: Gmsh.tab.cpp,v 1.372 2008-07-04 14:58:32 geuzaine Exp $
+// $Id: Gmsh.tab.cpp,v 1.373 2008-07-05 23:00:57 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -991,35 +991,35 @@ static const yytype_uint16 yyrline[] =
      465,   318,   483,   490,   501,   500,   519,   526,   537,   536,
      554,   569,   589,   588,   602,   603,   604,   605,   606,   610,
      611,   618,   649,   688,   742,   759,   777,   788,   805,   812,
-     827,   845,   871,   898,   912,   929,   944,   962,   982,  1005,
-    1014,  1020,  1040,  1061,  1087,  1099,  1116,  1120,  1130,  1133,
-    1151,  1173,  1189,  1211,  1229,  1247,  1265,  1291,  1309,  1335,
-    1355,  1373,  1391,  1417,  1434,  1453,  1471,  1510,  1516,  1522,
-    1529,  1554,  1579,  1595,  1615,  1633,  1650,  1671,  1676,  1681,
-    1686,  1691,  1702,  1708,  1717,  1718,  1723,  1726,  1730,  1753,
-    1776,  1799,  1827,  1836,  1840,  1855,  1869,  1886,  1900,  1906,
-    1912,  1921,  1935,  1983,  2001,  2016,  2038,  2050,  2074,  2078,
-    2083,  2088,  2100,  2117,  2134,  2161,  2188,  2219,  2227,  2233,
-    2240,  2244,  2253,  2261,  2269,  2278,  2277,  2290,  2289,  2302,
-    2301,  2314,  2313,  2325,  2324,  2340,  2347,  2354,  2361,  2368,
-    2375,  2382,  2389,  2396,  2404,  2403,  2415,  2414,  2426,  2425,
-    2437,  2436,  2448,  2447,  2459,  2458,  2470,  2469,  2481,  2480,
-    2492,  2491,  2506,  2509,  2515,  2524,  2544,  2567,  2571,  2595,
-    2613,  2631,  2649,  2678,  2713,  2718,  2745,  2759,  2772,  2789,
-    2795,  2801,  2804,  2813,  2823,  2824,  2825,  2826,  2827,  2828,
-    2829,  2830,  2831,  2838,  2839,  2840,  2841,  2842,  2843,  2844,
-    2845,  2846,  2847,  2848,  2849,  2850,  2851,  2852,  2853,  2854,
-    2855,  2856,  2857,  2858,  2859,  2860,  2861,  2862,  2863,  2864,
-    2865,  2866,  2867,  2868,  2869,  2871,  2872,  2873,  2874,  2875,
-    2876,  2877,  2878,  2879,  2880,  2881,  2882,  2883,  2884,  2885,
-    2886,  2887,  2888,  2889,  2890,  2891,  2900,  2901,  2902,  2903,
-    2904,  2905,  2906,  2910,  2926,  2941,  2961,  2974,  2987,  3010,
-    3028,  3046,  3064,  3082,  3090,  3094,  3098,  3102,  3106,  3113,
-    3117,  3121,  3125,  3132,  3137,  3145,  3150,  3154,  3159,  3163,
-    3171,  3182,  3190,  3198,  3204,  3215,  3235,  3245,  3255,  3272,
-    3299,  3304,  3308,  3312,  3325,  3329,  3341,  3348,  3369,  3373,
-    3388,  3393,  3400,  3404,  3411,  3415,  3423,  3431,  3445,  3459,
-    3463,  3482,  3505
+     817,   825,   843,   861,   870,   882,   887,   895,   915,   938,
+     947,   953,   973,   994,  1020,  1032,  1049,  1053,  1063,  1066,
+    1084,  1106,  1122,  1144,  1162,  1180,  1198,  1224,  1242,  1268,
+    1288,  1306,  1324,  1350,  1367,  1386,  1404,  1443,  1449,  1455,
+    1462,  1487,  1512,  1528,  1548,  1566,  1583,  1604,  1609,  1614,
+    1619,  1624,  1635,  1641,  1650,  1651,  1656,  1659,  1663,  1686,
+    1709,  1732,  1760,  1769,  1773,  1788,  1802,  1819,  1833,  1839,
+    1845,  1854,  1868,  1916,  1934,  1949,  1971,  1983,  2007,  2011,
+    2016,  2021,  2033,  2050,  2067,  2094,  2121,  2152,  2160,  2166,
+    2173,  2177,  2186,  2194,  2202,  2211,  2210,  2223,  2222,  2235,
+    2234,  2247,  2246,  2258,  2257,  2273,  2280,  2287,  2294,  2301,
+    2308,  2315,  2322,  2329,  2337,  2336,  2348,  2347,  2359,  2358,
+    2370,  2369,  2381,  2380,  2392,  2391,  2403,  2402,  2414,  2413,
+    2425,  2424,  2439,  2442,  2448,  2457,  2477,  2500,  2504,  2528,
+    2546,  2564,  2582,  2611,  2646,  2651,  2678,  2692,  2705,  2722,
+    2728,  2734,  2737,  2746,  2756,  2757,  2758,  2759,  2760,  2761,
+    2762,  2763,  2764,  2771,  2772,  2773,  2774,  2775,  2776,  2777,
+    2778,  2779,  2780,  2781,  2782,  2783,  2784,  2785,  2786,  2787,
+    2788,  2789,  2790,  2791,  2792,  2793,  2794,  2795,  2796,  2797,
+    2798,  2799,  2800,  2801,  2802,  2804,  2805,  2806,  2807,  2808,
+    2809,  2810,  2811,  2812,  2813,  2814,  2815,  2816,  2817,  2818,
+    2819,  2820,  2821,  2822,  2823,  2824,  2833,  2834,  2835,  2836,
+    2837,  2838,  2839,  2843,  2859,  2874,  2894,  2907,  2920,  2943,
+    2948,  2953,  2963,  2973,  2981,  2985,  2989,  2993,  2997,  3004,
+    3008,  3012,  3016,  3023,  3028,  3036,  3041,  3045,  3050,  3054,
+    3062,  3073,  3081,  3089,  3095,  3106,  3126,  3136,  3146,  3163,
+    3190,  3195,  3199,  3203,  3216,  3220,  3232,  3239,  3249,  3253,
+    3268,  3273,  3280,  3284,  3291,  3295,  3303,  3311,  3325,  3339,
+    3343,  3362,  3370
 };
 #endif
 
@@ -4445,170 +4445,103 @@ yyreduce:
   case 69:
 #line 813 "Gmsh.y"
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory((yyvsp[(1) - (6)].c))))
-	yymsg(0, "Unknown string option class '%s'", (yyvsp[(1) - (6)].c));
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption((yyvsp[(3) - (6)].c), pStrCat)))
-	  yymsg(0, "Unknown string option '%s.%s'", (yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].c));
-	else
-	  pStrOpt(0, GMSH_SET|GMSH_GUI, (yyvsp[(5) - (6)].c));
-      }
-      Free((yyvsp[(1) - (6)].c)); Free((yyvsp[(3) - (6)].c)); //FIXME: somtimes leak $5
+      StringOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
+      Free((yyvsp[(1) - (6)].c)); Free((yyvsp[(3) - (6)].c));
     ;}
     break;
 
   case 70:
-#line 828 "Gmsh.y"
+#line 818 "Gmsh.y"
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory((yyvsp[(1) - (9)].c))))
-	yymsg(0, "Unknown string option class '%s'", (yyvsp[(1) - (9)].c));
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption((yyvsp[(6) - (9)].c), pStrCat)))
-	  yymsg(0, "Unknown string option '%s[%d].%s'", (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c));
-	else
-	  pStrOpt((int)(yyvsp[(3) - (9)].d), GMSH_SET|GMSH_GUI, (yyvsp[(8) - (9)].c));
-      }
-      Free((yyvsp[(1) - (9)].c)); Free((yyvsp[(6) - (9)].c)); //FIXME: somtimes leak $8
+      StringOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), (yyvsp[(8) - (9)].c));
+      Free((yyvsp[(1) - (9)].c)); Free((yyvsp[(6) - (9)].c));
     ;}
     break;
 
   case 71:
-#line 846 "Gmsh.y"
-    {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (6)].c))))
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (6)].c));
-      else{
-	if(!(pNumOpt = (double (*) (int, int, double))Get_NumberOption((yyvsp[(3) - (6)].c), pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s.%s'", (yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].c));
-	else{
-	  double d = 0;
-	  switch((yyvsp[(4) - (6)].i)){
-	  case 0 : d = (yyvsp[(5) - (6)].d); break;
-	  case 1 : d = pNumOpt(0, GMSH_GET, 0) + (yyvsp[(5) - (6)].d); break;
-	  case 2 : d = pNumOpt(0, GMSH_GET, 0) - (yyvsp[(5) - (6)].d); break;
-	  case 3 : d = pNumOpt(0, GMSH_GET, 0) * (yyvsp[(5) - (6)].d); break;
-	  case 4 : 
-	    if((yyvsp[(5) - (6)].d)) d = pNumOpt(0, GMSH_GET, 0) / (yyvsp[(5) - (6)].d); 
-	    else yymsg(0, "Division by zero in '%s.%s /= %g'", (yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].d));
-	    break;
-	  }
-	  pNumOpt(0, GMSH_SET|GMSH_GUI, d);
+#line 826 "Gmsh.y"
+    {
+      double d = 0.;
+      if(NumberOption(GMSH_GET, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), d)){
+	switch((yyvsp[(4) - (6)].i)){
+	case 0 : d = (yyvsp[(5) - (6)].d); break;
+	case 1 : d += (yyvsp[(5) - (6)].d); break;
+	case 2 : d -= (yyvsp[(5) - (6)].d); break;
+	case 3 : d *= (yyvsp[(5) - (6)].d); break;
+	case 4 : 
+	  if((yyvsp[(5) - (6)].d)) d /= (yyvsp[(5) - (6)].d); 
+	  else yymsg(0, "Division by zero in '%s.%s /= %g'", (yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].d));
+	  break;
 	}
+	NumberOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), d);
       }
       Free((yyvsp[(1) - (6)].c)); Free((yyvsp[(3) - (6)].c));
     ;}
     break;
 
   case 72:
-#line 872 "Gmsh.y"
-    {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (9)].c))))
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (9)].c));
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(6) - (9)].c), pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c));
-	else{
-	  double d = 0;
-	  switch((yyvsp[(7) - (9)].i)){
-	  case 0 : d = (yyvsp[(8) - (9)].d); break;
-	  case 1 : d = pNumOpt((int)(yyvsp[(3) - (9)].d), GMSH_GET, 0) + (yyvsp[(8) - (9)].d); break;
-	  case 2 : d = pNumOpt((int)(yyvsp[(3) - (9)].d), GMSH_GET, 0) - (yyvsp[(8) - (9)].d); break;
-	  case 3 : d = pNumOpt((int)(yyvsp[(3) - (9)].d), GMSH_GET, 0) * (yyvsp[(8) - (9)].d); break;
-	  case 4 : 
-	    if((yyvsp[(8) - (9)].d)) d = pNumOpt((int)(yyvsp[(3) - (9)].d), GMSH_GET, 0) / (yyvsp[(8) - (9)].d);
-	    else yymsg(0, "Division by zero in '%s[%d].%s /= %g'", 
-		       (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), (yyvsp[(8) - (9)].d));
-	    break;
-	  }
-	  pNumOpt((int)(yyvsp[(3) - (9)].d), GMSH_SET|GMSH_GUI, d);
+#line 844 "Gmsh.y"
+    {
+      double d = 0.;
+      if(NumberOption(GMSH_GET, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), d)){
+	switch((yyvsp[(7) - (9)].i)){
+	case 0 : d = (yyvsp[(8) - (9)].d); break;
+	case 1 : d += (yyvsp[(8) - (9)].d); break;
+	case 2 : d -= (yyvsp[(8) - (9)].d); break;
+	case 3 : d *= (yyvsp[(8) - (9)].d); break;
+	case 4 : 
+	  if((yyvsp[(8) - (9)].d)) d /= (yyvsp[(8) - (9)].d); 
+	  else yymsg(0, "Division by zero in '%s[%d].%s /= %g'", (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), (yyvsp[(8) - (9)].d));
+	  break;
 	}
+	NumberOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), d);
       }
       Free((yyvsp[(1) - (9)].c)); Free((yyvsp[(6) - (9)].c));
     ;}
     break;
 
   case 73:
-#line 899 "Gmsh.y"
+#line 862 "Gmsh.y"
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (5)].c))))
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (5)].c));
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(3) - (5)].c), pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s.%s'", (yyvsp[(1) - (5)].c), (yyvsp[(3) - (5)].c));
-	else
-	  pNumOpt(0, GMSH_SET|GMSH_GUI, pNumOpt(0, GMSH_GET, 0)+(yyvsp[(4) - (5)].i));
+      double d = 0.;
+      if(NumberOption(GMSH_GET, (yyvsp[(1) - (5)].c), 0, (yyvsp[(3) - (5)].c), d)){
+	d += (yyvsp[(4) - (5)].i);
+	NumberOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (5)].c), 0, (yyvsp[(3) - (5)].c), d);
       }
       Free((yyvsp[(1) - (5)].c)); Free((yyvsp[(3) - (5)].c));
     ;}
     break;
 
   case 74:
-#line 913 "Gmsh.y"
+#line 871 "Gmsh.y"
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (8)].c))))
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (8)].c));
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(6) - (8)].c), pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", (yyvsp[(1) - (8)].c), (int)(yyvsp[(3) - (8)].d), (yyvsp[(6) - (8)].c));
-	else
-	  pNumOpt((int)(yyvsp[(3) - (8)].d), GMSH_SET|GMSH_GUI, pNumOpt((int)(yyvsp[(3) - (8)].d), GMSH_GET, 0)+(yyvsp[(7) - (8)].i));
+      double d = 0.;
+      if(NumberOption(GMSH_GET, (yyvsp[(1) - (8)].c), (int)(yyvsp[(3) - (8)].d), (yyvsp[(6) - (8)].c), d)){
+	d += (yyvsp[(7) - (8)].i);
+	NumberOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (8)].c), (int)(yyvsp[(3) - (8)].d), (yyvsp[(6) - (8)].c), d);
       }
       Free((yyvsp[(1) - (8)].c)); Free((yyvsp[(6) - (8)].c));
     ;}
     break;
 
   case 75:
-#line 930 "Gmsh.y"
+#line 883 "Gmsh.y"
     {
-      unsigned int (*pColOpt)(int num, int action, unsigned int value);
-      StringXColor *pColCat;
-      if(!(pColCat = Get_ColorOptionCategory((yyvsp[(1) - (8)].c))))
-	yymsg(0, "Unknown color option class '%s'", (yyvsp[(1) - (8)].c));
-      else{
-	if(!(pColOpt = (unsigned int (*) (int, int, unsigned int))
-	     Get_ColorOption((yyvsp[(5) - (8)].c), pColCat)))
-	  yymsg(0, "Unknown color option '%s.Color.%s'", (yyvsp[(1) - (8)].c), (yyvsp[(5) - (8)].c));
-	else
-	  pColOpt(0, GMSH_SET|GMSH_GUI, (yyvsp[(7) - (8)].u));
-      }
+      ColorOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (8)].c), 0, (yyvsp[(5) - (8)].c), (yyvsp[(7) - (8)].u));
       Free((yyvsp[(1) - (8)].c)); Free((yyvsp[(5) - (8)].c));
     ;}
     break;
 
   case 76:
-#line 945 "Gmsh.y"
+#line 888 "Gmsh.y"
     {
-      unsigned int (*pColOpt)(int num, int action, unsigned int value);
-      StringXColor *pColCat;
-      if(!(pColCat = Get_ColorOptionCategory((yyvsp[(1) - (11)].c))))
-	yymsg(0, "Unknown color option class '%s'", (yyvsp[(1) - (11)].c));
-      else{
-	if(!(pColOpt =  (unsigned int (*) (int, int, unsigned int))
-	     Get_ColorOption((yyvsp[(8) - (11)].c), pColCat)))
-	  yymsg(0, "Unknown color option '%s[%d].Color.%s'", (yyvsp[(1) - (11)].c), (int)(yyvsp[(3) - (11)].d), (yyvsp[(8) - (11)].c));
-	else
-	  pColOpt((int)(yyvsp[(3) - (11)].d), GMSH_SET|GMSH_GUI, (yyvsp[(10) - (11)].u));
-      }
+      ColorOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (11)].c), (int)(yyvsp[(3) - (11)].d), (yyvsp[(8) - (11)].c), (yyvsp[(10) - (11)].u));
       Free((yyvsp[(1) - (11)].c)); Free((yyvsp[(8) - (11)].c));
     ;}
     break;
 
   case 77:
-#line 963 "Gmsh.y"
+#line 896 "Gmsh.y"
     {
       GmshColorTable *ct = Get_ColorTable(0);
       if(!ct)
@@ -4631,7 +4564,7 @@ yyreduce:
     break;
 
   case 78:
-#line 983 "Gmsh.y"
+#line 916 "Gmsh.y"
     {
       GmshColorTable *ct = Get_ColorTable((int)(yyvsp[(3) - (9)].d));
       if(!ct)
@@ -4654,7 +4587,7 @@ yyreduce:
     break;
 
   case 79:
-#line 1006 "Gmsh.y"
+#line 939 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (5)].c),"Background")){
 	GModel::current()->getFields()->background_field = (int)(yyvsp[(4) - (5)].d);
@@ -4666,7 +4599,7 @@ yyreduce:
     break;
 
   case 80:
-#line 1015 "Gmsh.y"
+#line 948 "Gmsh.y"
     {
       if(!GModel::current()->getFields()->new_field((int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c)))
 	yymsg(0, "Cannot create field %i of type '%s'", (int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c));
@@ -4675,7 +4608,7 @@ yyreduce:
     break;
 
   case 81:
-#line 1021 "Gmsh.y"
+#line 954 "Gmsh.y"
     {
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (9)].d));
       if(field){
@@ -4698,7 +4631,7 @@ yyreduce:
     break;
 
   case 82:
-#line 1041 "Gmsh.y"
+#line 974 "Gmsh.y"
     {
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (9)].d));
       if(field){
@@ -4722,7 +4655,7 @@ yyreduce:
     break;
 
   case 83:
-#line 1062 "Gmsh.y"
+#line 995 "Gmsh.y"
     {
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (11)].d));
       if(field){
@@ -4748,7 +4681,7 @@ yyreduce:
     break;
 
   case 84:
-#line 1088 "Gmsh.y"
+#line 1021 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       try {
@@ -4763,7 +4696,7 @@ yyreduce:
     break;
 
   case 85:
-#line 1100 "Gmsh.y"
+#line 1033 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       try {
@@ -4778,14 +4711,14 @@ yyreduce:
     break;
 
   case 86:
-#line 1117 "Gmsh.y"
+#line 1050 "Gmsh.y"
     { 
       (yyval.i) = (int)(yyvsp[(1) - (1)].d); 
     ;}
     break;
 
   case 87:
-#line 1121 "Gmsh.y"
+#line 1054 "Gmsh.y"
     { 
       (yyval.i) = GModel::current()->setPhysicalName
 	(std::string((yyvsp[(1) - (1)].c)), ++GModel::current()->getGEOInternals()->MaxPhysicalNum);
@@ -4794,14 +4727,14 @@ yyreduce:
     break;
 
   case 88:
-#line 1130 "Gmsh.y"
+#line 1063 "Gmsh.y"
     {
       (yyval.l) = 0;
     ;}
     break;
 
   case 89:
-#line 1134 "Gmsh.y"
+#line 1067 "Gmsh.y"
     {
       (yyval.l) = List_Create(4, 4, sizeof(double));
       Vertex *v = FindPoint((int)(yyvsp[(4) - (5)].d));
@@ -4816,7 +4749,7 @@ yyreduce:
     break;
 
   case 90:
-#line 1152 "Gmsh.y"
+#line 1085 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindPoint(num)){
@@ -4841,7 +4774,7 @@ yyreduce:
     break;
 
   case 91:
-#line 1174 "Gmsh.y"
+#line 1107 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_POINT)){
@@ -4860,7 +4793,7 @@ yyreduce:
     break;
 
   case 92:
-#line 1190 "Gmsh.y"
+#line 1123 "Gmsh.y"
     {      
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
 	double d;
@@ -4882,7 +4815,7 @@ yyreduce:
     break;
 
   case 93:
-#line 1212 "Gmsh.y"
+#line 1145 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -4903,7 +4836,7 @@ yyreduce:
     break;
 
   case 94:
-#line 1230 "Gmsh.y"
+#line 1163 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -4924,7 +4857,7 @@ yyreduce:
     break;
 
   case 95:
-#line 1248 "Gmsh.y"
+#line 1181 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -4945,7 +4878,7 @@ yyreduce:
     break;
 
   case 96:
-#line 1266 "Gmsh.y"
+#line 1199 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (9)].d);
       if(FindCurve(num)){
@@ -4974,7 +4907,7 @@ yyreduce:
     break;
 
   case 97:
-#line 1292 "Gmsh.y"
+#line 1225 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -4995,7 +4928,7 @@ yyreduce:
     break;
 
   case 98:
-#line 1310 "Gmsh.y"
+#line 1243 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (9)].d);
       if(FindCurve(num)){
@@ -5024,7 +4957,7 @@ yyreduce:
     break;
 
   case 99:
-#line 1337 "Gmsh.y"
+#line 1270 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (17)].d);
       if(FindCurve(num)){
@@ -5046,7 +4979,7 @@ yyreduce:
     break;
 
   case 100:
-#line 1356 "Gmsh.y"
+#line 1289 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -5067,7 +5000,7 @@ yyreduce:
     break;
 
   case 101:
-#line 1374 "Gmsh.y"
+#line 1307 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindCurve(num)){
@@ -5088,7 +5021,7 @@ yyreduce:
     break;
 
   case 102:
-#line 1392 "Gmsh.y"
+#line 1325 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (11)].d);
       if(List_Nbr((yyvsp[(6) - (11)].l)) + (int)(yyvsp[(10) - (11)].d) + 1 != List_Nbr((yyvsp[(8) - (11)].l))){
@@ -5117,7 +5050,7 @@ yyreduce:
     break;
 
   case 103:
-#line 1418 "Gmsh.y"
+#line 1351 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindEdgeLoop(num)){
@@ -5137,7 +5070,7 @@ yyreduce:
     break;
 
   case 104:
-#line 1435 "Gmsh.y"
+#line 1368 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_LINE)){
@@ -5156,7 +5089,7 @@ yyreduce:
     break;
 
   case 105:
-#line 1454 "Gmsh.y"
+#line 1387 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindSurface(num)){
@@ -5177,7 +5110,7 @@ yyreduce:
     break;
 
   case 106:
-#line 1472 "Gmsh.y"
+#line 1405 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (9)].d), type = 0;
       if(FindSurface(num)){
@@ -5219,7 +5152,7 @@ yyreduce:
     break;
 
   case 107:
-#line 1511 "Gmsh.y"
+#line 1444 "Gmsh.y"
     {
       myGmshSurface = 0;
       (yyval.s).Type = 0;
@@ -5228,7 +5161,7 @@ yyreduce:
     break;
 
   case 108:
-#line 1517 "Gmsh.y"
+#line 1450 "Gmsh.y"
     {
       myGmshSurface = gmshSurface::getSurface((int)(yyvsp[(3) - (4)].d));
       (yyval.s).Type = 0;
@@ -5237,7 +5170,7 @@ yyreduce:
     break;
 
   case 109:
-#line 1523 "Gmsh.y"
+#line 1456 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (10)].d);
       myGmshSurface = gmshParametricSurface::NewParametricSurface(num, (yyvsp[(7) - (10)].c), (yyvsp[(8) - (10)].c), (yyvsp[(9) - (10)].c));
@@ -5247,7 +5180,7 @@ yyreduce:
     break;
 
   case 110:
-#line 1530 "Gmsh.y"
+#line 1463 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if (List_Nbr((yyvsp[(6) - (7)].l)) != 2){
@@ -5275,7 +5208,7 @@ yyreduce:
     break;
 
   case 111:
-#line 1555 "Gmsh.y"
+#line 1488 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if (List_Nbr((yyvsp[(6) - (7)].l)) != 2){
@@ -5303,7 +5236,7 @@ yyreduce:
     break;
 
   case 112:
-#line 1580 "Gmsh.y"
+#line 1513 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       if(FindSurfaceLoop(num)){
@@ -5322,7 +5255,7 @@ yyreduce:
     break;
 
   case 113:
-#line 1596 "Gmsh.y"
+#line 1529 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_SURFACE)){
@@ -5341,7 +5274,7 @@ yyreduce:
     break;
 
   case 114:
-#line 1616 "Gmsh.y"
+#line 1549 "Gmsh.y"
     {
       yymsg(0, "'Complex Volume' command is deprecated: use 'Volume' instead");
       int num = (int)(yyvsp[(4) - (8)].d);
@@ -5362,7 +5295,7 @@ yyreduce:
     break;
 
   case 115:
-#line 1634 "Gmsh.y"
+#line 1567 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       if(FindVolume(num)){
@@ -5382,7 +5315,7 @@ yyreduce:
     break;
 
   case 116:
-#line 1651 "Gmsh.y"
+#line 1584 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       if(FindPhysicalGroup(num, MSH_PHYSICAL_VOLUME)){
@@ -5401,7 +5334,7 @@ yyreduce:
     break;
 
   case 117:
-#line 1672 "Gmsh.y"
+#line 1605 "Gmsh.y"
     {
       TranslateShapes((yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], (yyvsp[(4) - (5)].l));
       (yyval.l) = (yyvsp[(4) - (5)].l);
@@ -5409,7 +5342,7 @@ yyreduce:
     break;
 
   case 118:
-#line 1677 "Gmsh.y"
+#line 1610 "Gmsh.y"
     {
       RotateShapes((yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(7) - (11)].d), (yyvsp[(10) - (11)].l));
       (yyval.l) = (yyvsp[(10) - (11)].l);
@@ -5417,7 +5350,7 @@ yyreduce:
     break;
 
   case 119:
-#line 1682 "Gmsh.y"
+#line 1615 "Gmsh.y"
     {
       SymmetryShapes((yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], (yyvsp[(2) - (5)].v)[3], (yyvsp[(4) - (5)].l));
       (yyval.l) = (yyvsp[(4) - (5)].l);
@@ -5425,7 +5358,7 @@ yyreduce:
     break;
 
   case 120:
-#line 1687 "Gmsh.y"
+#line 1620 "Gmsh.y"
     {
       DilatShapes((yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].d), (yyvsp[(8) - (9)].l));
       (yyval.l) = (yyvsp[(8) - (9)].l);
@@ -5433,7 +5366,7 @@ yyreduce:
     break;
 
   case 121:
-#line 1692 "Gmsh.y"
+#line 1625 "Gmsh.y"
     {
       (yyval.l) = List_Create(3, 3, sizeof(Shape));
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
@@ -5447,7 +5380,7 @@ yyreduce:
     break;
 
   case 122:
-#line 1703 "Gmsh.y"
+#line 1636 "Gmsh.y"
     { 
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       IntersectCurvesWithSurface((yyvsp[(4) - (9)].l), (int)(yyvsp[(8) - (9)].d), (yyval.l));
@@ -5456,7 +5389,7 @@ yyreduce:
     break;
 
   case 123:
-#line 1709 "Gmsh.y"
+#line 1642 "Gmsh.y"
     { 
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       BoundaryShapes((yyvsp[(3) - (4)].l), (yyval.l));
@@ -5465,31 +5398,31 @@ yyreduce:
     break;
 
   case 124:
-#line 1717 "Gmsh.y"
+#line 1650 "Gmsh.y"
     { (yyval.l) = (yyvsp[(1) - (1)].l); ;}
     break;
 
   case 125:
-#line 1718 "Gmsh.y"
+#line 1651 "Gmsh.y"
     { (yyval.l) = (yyvsp[(1) - (1)].l); ;}
     break;
 
   case 126:
-#line 1723 "Gmsh.y"
+#line 1656 "Gmsh.y"
     {
       (yyval.l) = List_Create(3, 3, sizeof(Shape));
     ;}
     break;
 
   case 127:
-#line 1727 "Gmsh.y"
+#line 1660 "Gmsh.y"
     {
       List_Add((yyval.l), &(yyvsp[(2) - (2)].s));
     ;}
     break;
 
   case 128:
-#line 1731 "Gmsh.y"
+#line 1664 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -5515,7 +5448,7 @@ yyreduce:
     break;
 
   case 129:
-#line 1754 "Gmsh.y"
+#line 1687 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -5541,7 +5474,7 @@ yyreduce:
     break;
 
   case 130:
-#line 1777 "Gmsh.y"
+#line 1710 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -5567,7 +5500,7 @@ yyreduce:
     break;
 
   case 131:
-#line 1800 "Gmsh.y"
+#line 1733 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -5593,7 +5526,7 @@ yyreduce:
     break;
 
   case 132:
-#line 1828 "Gmsh.y"
+#line 1761 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	Shape TheShape;
@@ -5605,14 +5538,14 @@ yyreduce:
     break;
 
   case 133:
-#line 1837 "Gmsh.y"
+#line 1770 "Gmsh.y"
     {
       GModel::current()->getFields()->delete_field((int)(yyvsp[(4) - (6)].d));
     ;}
     break;
 
   case 134:
-#line 1841 "Gmsh.y"
+#line 1774 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -5630,7 +5563,7 @@ yyreduce:
     break;
 
   case 135:
-#line 1856 "Gmsh.y"
+#line 1789 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Meshes") || !strcmp((yyvsp[(2) - (3)].c), "All")){
 	GModel::current()->destroy();
@@ -5647,7 +5580,7 @@ yyreduce:
     break;
 
   case 136:
-#line 1870 "Gmsh.y"
+#line 1803 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       if(!strcmp((yyvsp[(2) - (4)].c), "Empty") && !strcmp((yyvsp[(3) - (4)].c), "Views")){
@@ -5662,7 +5595,7 @@ yyreduce:
     break;
 
   case 137:
-#line 1887 "Gmsh.y"
+#line 1820 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
 	Shape TheShape;
@@ -5674,7 +5607,7 @@ yyreduce:
     break;
 
   case 138:
-#line 1901 "Gmsh.y"
+#line 1834 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++)
 	VisibilityShape((yyvsp[(2) - (3)].c), i, 1);
@@ -5683,7 +5616,7 @@ yyreduce:
     break;
 
   case 139:
-#line 1907 "Gmsh.y"
+#line 1840 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++)
 	VisibilityShape((yyvsp[(2) - (3)].c), i, 0);
@@ -5692,7 +5625,7 @@ yyreduce:
     break;
 
   case 140:
-#line 1913 "Gmsh.y"
+#line 1846 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	Shape TheShape;
@@ -5704,7 +5637,7 @@ yyreduce:
     break;
 
   case 141:
-#line 1922 "Gmsh.y"
+#line 1855 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	Shape TheShape;
@@ -5716,7 +5649,7 @@ yyreduce:
     break;
 
   case 142:
-#line 1936 "Gmsh.y"
+#line 1869 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (3)].c), "Include")){
 	char tmpstring[1024];
@@ -5767,7 +5700,7 @@ yyreduce:
     break;
 
   case 143:
-#line 1984 "Gmsh.y"
+#line 1917 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       if(!strcmp((yyvsp[(1) - (7)].c), "Save") && !strcmp((yyvsp[(2) - (7)].c), "View")){
@@ -5788,7 +5721,7 @@ yyreduce:
     break;
 
   case 144:
-#line 2002 "Gmsh.y"
+#line 1935 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       if(!strcmp((yyvsp[(1) - (7)].c), "Background") && !strcmp((yyvsp[(2) - (7)].c), "Mesh")  && !strcmp((yyvsp[(3) - (7)].c), "View")){
@@ -5806,7 +5739,7 @@ yyreduce:
     break;
 
   case 145:
-#line 2017 "Gmsh.y"
+#line 1950 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (3)].c), "Sleep")){
 	SleepInSeconds((yyvsp[(2) - (3)].d));
@@ -5831,7 +5764,7 @@ yyreduce:
     break;
 
   case 146:
-#line 2039 "Gmsh.y"
+#line 1972 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
        try {
@@ -5846,7 +5779,7 @@ yyreduce:
     break;
 
   case 147:
-#line 2051 "Gmsh.y"
+#line 1984 "Gmsh.y"
     {
 #if !defined(HAVE_NO_POST)
       if(!strcmp((yyvsp[(2) - (3)].c), "ElementsFromAllViews"))
@@ -5873,14 +5806,14 @@ yyreduce:
     break;
 
   case 148:
-#line 2075 "Gmsh.y"
+#line 2008 "Gmsh.y"
     {
       exit(0);
     ;}
     break;
 
   case 149:
-#line 2079 "Gmsh.y"
+#line 2012 "Gmsh.y"
     {
       CTX.forced_bbox = 0;
       SetBoundingBox();
@@ -5888,7 +5821,7 @@ yyreduce:
     break;
 
   case 150:
-#line 2084 "Gmsh.y"
+#line 2017 "Gmsh.y"
     {
       CTX.forced_bbox = 1;
       SetBoundingBox((yyvsp[(3) - (15)].d), (yyvsp[(5) - (15)].d), (yyvsp[(7) - (15)].d), (yyvsp[(9) - (15)].d), (yyvsp[(11) - (15)].d), (yyvsp[(13) - (15)].d));
@@ -5896,7 +5829,7 @@ yyreduce:
     break;
 
   case 151:
-#line 2089 "Gmsh.y"
+#line 2022 "Gmsh.y"
     {
 #if defined(HAVE_FLTK)
       Draw();
@@ -5905,7 +5838,7 @@ yyreduce:
     break;
 
   case 152:
-#line 2101 "Gmsh.y"
+#line 2034 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(3) - (6)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(5) - (6)].d);
@@ -5925,7 +5858,7 @@ yyreduce:
     break;
 
   case 153:
-#line 2118 "Gmsh.y"
+#line 2051 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(3) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(5) - (8)].d);
@@ -5945,7 +5878,7 @@ yyreduce:
     break;
 
   case 154:
-#line 2135 "Gmsh.y"
+#line 2068 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(5) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(7) - (8)].d);
@@ -5975,7 +5908,7 @@ yyreduce:
     break;
 
   case 155:
-#line 2162 "Gmsh.y"
+#line 2095 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(5) - (10)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(7) - (10)].d);
@@ -6005,7 +5938,7 @@ yyreduce:
     break;
 
   case 156:
-#line 2189 "Gmsh.y"
+#line 2122 "Gmsh.y"
     {
       if(ImbricatedLoop <= 0){
 	yymsg(0, "Invalid For/EndFor loop");
@@ -6039,7 +5972,7 @@ yyreduce:
     break;
 
   case 157:
-#line 2220 "Gmsh.y"
+#line 2153 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->createFunction((yyvsp[(2) - (2)].c), gmsh_yyin, gmsh_yyname,
 						      gmsh_yylineno))
@@ -6050,7 +5983,7 @@ yyreduce:
     break;
 
   case 158:
-#line 2228 "Gmsh.y"
+#line 2161 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->leaveFunction(&gmsh_yyin, gmsh_yyname,
 						     gmsh_yylineno))
@@ -6059,7 +5992,7 @@ yyreduce:
     break;
 
   case 159:
-#line 2234 "Gmsh.y"
+#line 2167 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->enterFunction((yyvsp[(2) - (3)].c), &gmsh_yyin, gmsh_yyname,
 						     gmsh_yylineno))
@@ -6069,20 +6002,20 @@ yyreduce:
     break;
 
   case 160:
-#line 2241 "Gmsh.y"
+#line 2174 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].d)) skip_until("If", "EndIf");
     ;}
     break;
 
   case 161:
-#line 2245 "Gmsh.y"
+#line 2178 "Gmsh.y"
     {
     ;}
     break;
 
   case 162:
-#line 2254 "Gmsh.y"
+#line 2187 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE, (yyvsp[(4) - (5)].l), 
@@ -6093,7 +6026,7 @@ yyreduce:
     break;
 
   case 163:
-#line 2262 "Gmsh.y"
+#line 2195 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(ROTATE, (yyvsp[(10) - (11)].l), 
@@ -6104,7 +6037,7 @@ yyreduce:
     break;
 
   case 164:
-#line 2270 "Gmsh.y"
+#line 2203 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE_ROTATE, (yyvsp[(12) - (13)].l), 
@@ -6115,14 +6048,14 @@ yyreduce:
     break;
 
   case 165:
-#line 2278 "Gmsh.y"
+#line 2211 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 166:
-#line 2282 "Gmsh.y"
+#line 2215 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE, (yyvsp[(4) - (7)].l), 
@@ -6133,14 +6066,14 @@ yyreduce:
     break;
 
   case 167:
-#line 2290 "Gmsh.y"
+#line 2223 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 168:
-#line 2294 "Gmsh.y"
+#line 2227 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(ROTATE, (yyvsp[(10) - (13)].l), 
@@ -6151,14 +6084,14 @@ yyreduce:
     break;
 
   case 169:
-#line 2302 "Gmsh.y"
+#line 2235 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 170:
-#line 2306 "Gmsh.y"
+#line 2239 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(TRANSLATE_ROTATE, (yyvsp[(12) - (15)].l), 
@@ -6169,14 +6102,14 @@ yyreduce:
     break;
 
   case 171:
-#line 2314 "Gmsh.y"
+#line 2247 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 172:
-#line 2318 "Gmsh.y"
+#line 2251 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShapes(BOUNDARY_LAYER, (yyvsp[(3) - (6)].l), 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
@@ -6186,14 +6119,14 @@ yyreduce:
     break;
 
   case 173:
-#line 2325 "Gmsh.y"
+#line 2258 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 174:
-#line 2329 "Gmsh.y"
+#line 2262 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       extr.mesh.ViewIndex = (int)(yyvsp[(4) - (10)].d);
@@ -6206,7 +6139,7 @@ yyreduce:
     break;
 
   case 175:
-#line 2341 "Gmsh.y"
+#line 2274 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_POINT, (int)(yyvsp[(4) - (8)].d), 
@@ -6216,7 +6149,7 @@ yyreduce:
     break;
 
   case 176:
-#line 2348 "Gmsh.y"
+#line 2281 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (8)].d), 
@@ -6226,7 +6159,7 @@ yyreduce:
     break;
 
   case 177:
-#line 2355 "Gmsh.y"
+#line 2288 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (8)].d), 
@@ -6236,7 +6169,7 @@ yyreduce:
     break;
 
   case 178:
-#line 2362 "Gmsh.y"
+#line 2295 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_POINT, (int)(yyvsp[(4) - (12)].d), 
@@ -6246,7 +6179,7 @@ yyreduce:
     break;
 
   case 179:
-#line 2369 "Gmsh.y"
+#line 2302 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (12)].d), 
@@ -6256,7 +6189,7 @@ yyreduce:
     break;
 
   case 180:
-#line 2376 "Gmsh.y"
+#line 2309 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (12)].d), 
@@ -6266,7 +6199,7 @@ yyreduce:
     break;
 
   case 181:
-#line 2383 "Gmsh.y"
+#line 2316 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_POINT, (int)(yyvsp[(4) - (14)].d), 
@@ -6276,7 +6209,7 @@ yyreduce:
     break;
 
   case 182:
-#line 2390 "Gmsh.y"
+#line 2323 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (14)].d), 
@@ -6286,7 +6219,7 @@ yyreduce:
     break;
 
   case 183:
-#line 2397 "Gmsh.y"
+#line 2330 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (14)].d), 
@@ -6296,14 +6229,14 @@ yyreduce:
     break;
 
   case 184:
-#line 2404 "Gmsh.y"
+#line 2337 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 185:
-#line 2408 "Gmsh.y"
+#line 2341 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_POINT, (int)(yyvsp[(4) - (12)].d), 
@@ -6313,14 +6246,14 @@ yyreduce:
     break;
 
   case 186:
-#line 2415 "Gmsh.y"
+#line 2348 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 187:
-#line 2419 "Gmsh.y"
+#line 2352 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (12)].d), 
@@ -6330,14 +6263,14 @@ yyreduce:
     break;
 
   case 188:
-#line 2426 "Gmsh.y"
+#line 2359 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 189:
-#line 2430 "Gmsh.y"
+#line 2363 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (12)].d), 
@@ -6347,14 +6280,14 @@ yyreduce:
     break;
 
   case 190:
-#line 2437 "Gmsh.y"
+#line 2370 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 191:
-#line 2441 "Gmsh.y"
+#line 2374 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_POINT, (int)(yyvsp[(4) - (16)].d), 
@@ -6364,14 +6297,14 @@ yyreduce:
     break;
 
   case 192:
-#line 2448 "Gmsh.y"
+#line 2381 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 193:
-#line 2452 "Gmsh.y"
+#line 2385 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (16)].d), 
@@ -6381,14 +6314,14 @@ yyreduce:
     break;
 
   case 194:
-#line 2459 "Gmsh.y"
+#line 2392 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 195:
-#line 2463 "Gmsh.y"
+#line 2396 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (16)].d), 
@@ -6398,14 +6331,14 @@ yyreduce:
     break;
 
   case 196:
-#line 2470 "Gmsh.y"
+#line 2403 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 197:
-#line 2474 "Gmsh.y"
+#line 2407 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_POINT, (int)(yyvsp[(4) - (18)].d), 
@@ -6415,14 +6348,14 @@ yyreduce:
     break;
 
   case 198:
-#line 2481 "Gmsh.y"
+#line 2414 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 199:
-#line 2485 "Gmsh.y"
+#line 2418 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SEGM_LINE, (int)(yyvsp[(4) - (18)].d), 
@@ -6432,14 +6365,14 @@ yyreduce:
     break;
 
   case 200:
-#line 2492 "Gmsh.y"
+#line 2425 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
     ;}
     break;
 
   case 201:
-#line 2496 "Gmsh.y"
+#line 2429 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       ExtrudeShape(TRANSLATE_ROTATE, MSH_SURF_PLAN, (int)(yyvsp[(4) - (18)].d), 
@@ -6449,19 +6382,19 @@ yyreduce:
     break;
 
   case 202:
-#line 2507 "Gmsh.y"
+#line 2440 "Gmsh.y"
     {
     ;}
     break;
 
   case 203:
-#line 2510 "Gmsh.y"
+#line 2443 "Gmsh.y"
     {
     ;}
     break;
 
   case 204:
-#line 2516 "Gmsh.y"
+#line 2449 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = true;
       extr.mesh.NbLayer = 1;
@@ -6473,7 +6406,7 @@ yyreduce:
     break;
 
   case 205:
-#line 2525 "Gmsh.y"
+#line 2458 "Gmsh.y"
     {
       double d;
       extr.mesh.ExtrudeMesh = true;
@@ -6496,7 +6429,7 @@ yyreduce:
     break;
 
   case 206:
-#line 2545 "Gmsh.y"
+#line 2478 "Gmsh.y"
     {
       yymsg(0, "Explicit region numbers in layers are deprecated");
       double d;
@@ -6522,14 +6455,14 @@ yyreduce:
     break;
 
   case 207:
-#line 2568 "Gmsh.y"
+#line 2501 "Gmsh.y"
     {
       extr.mesh.Recombine = true;
     ;}
     break;
 
   case 208:
-#line 2572 "Gmsh.y"
+#line 2505 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (9)].d);
       if(FindSurface(num)){
@@ -6551,7 +6484,7 @@ yyreduce:
     break;
 
   case 209:
-#line 2596 "Gmsh.y"
+#line 2529 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
 	double d;
@@ -6572,7 +6505,7 @@ yyreduce:
     break;
 
   case 210:
-#line 2614 "Gmsh.y"
+#line 2547 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (9)].l)); i++){
 	double d;
@@ -6593,7 +6526,7 @@ yyreduce:
     break;
 
   case 211:
-#line 2632 "Gmsh.y"
+#line 2565 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (9)].l)); i++){
 	double d;
@@ -6614,7 +6547,7 @@ yyreduce:
     break;
 
   case 212:
-#line 2650 "Gmsh.y"
+#line 2583 "Gmsh.y"
     {
       Surface *s = FindSurface((int)(yyvsp[(4) - (8)].d));
       if(!s)
@@ -6646,7 +6579,7 @@ yyreduce:
     break;
 
   case 213:
-#line 2679 "Gmsh.y"
+#line 2612 "Gmsh.y"
     {
       Surface *s = FindSurface((int)(yyvsp[(4) - (9)].d));
       if(!s)
@@ -6684,7 +6617,7 @@ yyreduce:
     break;
 
   case 214:
-#line 2714 "Gmsh.y"
+#line 2647 "Gmsh.y"
     {
       yymsg(1, "Elliptic Surface is deprecated: use Transfinite instead (with smoothing)");
       List_Delete((yyvsp[(7) - (8)].l));
@@ -6692,7 +6625,7 @@ yyreduce:
     break;
 
   case 215:
-#line 2719 "Gmsh.y"
+#line 2652 "Gmsh.y"
     {
       Volume *v = FindVolume((int)(yyvsp[(4) - (8)].d));
       if(!v)
@@ -6722,7 +6655,7 @@ yyreduce:
     break;
 
   case 216:
-#line 2746 "Gmsh.y"
+#line 2679 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
 	double d;
@@ -6739,7 +6672,7 @@ yyreduce:
     break;
 
   case 217:
-#line 2760 "Gmsh.y"
+#line 2693 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	double d;
@@ -6755,7 +6688,7 @@ yyreduce:
     break;
 
   case 218:
-#line 2773 "Gmsh.y"
+#line 2706 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
 	double d;
@@ -6769,7 +6702,7 @@ yyreduce:
     break;
 
   case 219:
-#line 2790 "Gmsh.y"
+#line 2723 "Gmsh.y"
     { 
       Surface *s = FindSurface((int)(yyvsp[(8) - (10)].d));
       if(s)
@@ -6778,7 +6711,7 @@ yyreduce:
     break;
 
   case 220:
-#line 2796 "Gmsh.y"
+#line 2729 "Gmsh.y"
     {
       Surface *s = FindSurface((int)(yyvsp[(8) - (10)].d));
       if(s)
@@ -6787,66 +6720,66 @@ yyreduce:
     break;
 
   case 221:
-#line 2802 "Gmsh.y"
+#line 2735 "Gmsh.y"
     {
     ;}
     break;
 
   case 222:
-#line 2805 "Gmsh.y"
+#line 2738 "Gmsh.y"
     {
     ;}
     break;
 
   case 223:
-#line 2814 "Gmsh.y"
+#line 2747 "Gmsh.y"
     { 
       ReplaceAllDuplicates();
     ;}
     break;
 
   case 224:
-#line 2823 "Gmsh.y"
+#line 2756 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (1)].d);           ;}
     break;
 
   case 225:
-#line 2824 "Gmsh.y"
+#line 2757 "Gmsh.y"
     { (yyval.d) = (yyvsp[(2) - (3)].d);           ;}
     break;
 
   case 226:
-#line 2825 "Gmsh.y"
+#line 2758 "Gmsh.y"
     { (yyval.d) = -(yyvsp[(2) - (2)].d);          ;}
     break;
 
   case 227:
-#line 2826 "Gmsh.y"
+#line 2759 "Gmsh.y"
     { (yyval.d) = (yyvsp[(2) - (2)].d);           ;}
     break;
 
   case 228:
-#line 2827 "Gmsh.y"
+#line 2760 "Gmsh.y"
     { (yyval.d) = !(yyvsp[(2) - (2)].d);          ;}
     break;
 
   case 229:
-#line 2828 "Gmsh.y"
+#line 2761 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) - (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 230:
-#line 2829 "Gmsh.y"
+#line 2762 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) + (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 231:
-#line 2830 "Gmsh.y"
+#line 2763 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) * (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 232:
-#line 2832 "Gmsh.y"
+#line 2765 "Gmsh.y"
     { 
       if(!(yyvsp[(3) - (3)].d))
 	yymsg(0, "Division by zero in '%g / %g'", (yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));
@@ -6856,307 +6789,307 @@ yyreduce:
     break;
 
   case 233:
-#line 2838 "Gmsh.y"
+#line 2771 "Gmsh.y"
     { (yyval.d) = (int)(yyvsp[(1) - (3)].d) % (int)(yyvsp[(3) - (3)].d);  ;}
     break;
 
   case 234:
-#line 2839 "Gmsh.y"
+#line 2772 "Gmsh.y"
     { (yyval.d) = pow((yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));  ;}
     break;
 
   case 235:
-#line 2840 "Gmsh.y"
+#line 2773 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 236:
-#line 2841 "Gmsh.y"
+#line 2774 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) > (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 237:
-#line 2842 "Gmsh.y"
+#line 2775 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) <= (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 238:
-#line 2843 "Gmsh.y"
+#line 2776 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) >= (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 239:
-#line 2844 "Gmsh.y"
+#line 2777 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) == (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 240:
-#line 2845 "Gmsh.y"
+#line 2778 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) != (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 241:
-#line 2846 "Gmsh.y"
+#line 2779 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) && (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 242:
-#line 2847 "Gmsh.y"
+#line 2780 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) || (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 243:
-#line 2848 "Gmsh.y"
+#line 2781 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (5)].d)? (yyvsp[(3) - (5)].d) : (yyvsp[(5) - (5)].d);  ;}
     break;
 
   case 244:
-#line 2849 "Gmsh.y"
+#line 2782 "Gmsh.y"
     { (yyval.d) = exp((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 245:
-#line 2850 "Gmsh.y"
+#line 2783 "Gmsh.y"
     { (yyval.d) = log((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 246:
-#line 2851 "Gmsh.y"
+#line 2784 "Gmsh.y"
     { (yyval.d) = log10((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 247:
-#line 2852 "Gmsh.y"
+#line 2785 "Gmsh.y"
     { (yyval.d) = sqrt((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 248:
-#line 2853 "Gmsh.y"
+#line 2786 "Gmsh.y"
     { (yyval.d) = sin((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 249:
-#line 2854 "Gmsh.y"
+#line 2787 "Gmsh.y"
     { (yyval.d) = asin((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 250:
-#line 2855 "Gmsh.y"
+#line 2788 "Gmsh.y"
     { (yyval.d) = cos((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 251:
-#line 2856 "Gmsh.y"
+#line 2789 "Gmsh.y"
     { (yyval.d) = acos((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 252:
-#line 2857 "Gmsh.y"
+#line 2790 "Gmsh.y"
     { (yyval.d) = tan((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 253:
-#line 2858 "Gmsh.y"
+#line 2791 "Gmsh.y"
     { (yyval.d) = atan((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 254:
-#line 2859 "Gmsh.y"
+#line 2792 "Gmsh.y"
     { (yyval.d) = atan2((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d));;}
     break;
 
   case 255:
-#line 2860 "Gmsh.y"
+#line 2793 "Gmsh.y"
     { (yyval.d) = sinh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 256:
-#line 2861 "Gmsh.y"
+#line 2794 "Gmsh.y"
     { (yyval.d) = cosh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 257:
-#line 2862 "Gmsh.y"
+#line 2795 "Gmsh.y"
     { (yyval.d) = tanh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 258:
-#line 2863 "Gmsh.y"
+#line 2796 "Gmsh.y"
     { (yyval.d) = fabs((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 259:
-#line 2864 "Gmsh.y"
+#line 2797 "Gmsh.y"
     { (yyval.d) = floor((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 260:
-#line 2865 "Gmsh.y"
+#line 2798 "Gmsh.y"
     { (yyval.d) = ceil((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 261:
-#line 2866 "Gmsh.y"
+#line 2799 "Gmsh.y"
     { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 262:
-#line 2867 "Gmsh.y"
+#line 2800 "Gmsh.y"
     { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 263:
-#line 2868 "Gmsh.y"
+#line 2801 "Gmsh.y"
     { (yyval.d) = sqrt((yyvsp[(3) - (6)].d)*(yyvsp[(3) - (6)].d)+(yyvsp[(5) - (6)].d)*(yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 264:
-#line 2869 "Gmsh.y"
+#line 2802 "Gmsh.y"
     { (yyval.d) = (yyvsp[(3) - (4)].d)*(double)rand()/(double)RAND_MAX; ;}
     break;
 
   case 265:
-#line 2871 "Gmsh.y"
+#line 2804 "Gmsh.y"
     { (yyval.d) = exp((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 266:
-#line 2872 "Gmsh.y"
+#line 2805 "Gmsh.y"
     { (yyval.d) = log((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 267:
-#line 2873 "Gmsh.y"
+#line 2806 "Gmsh.y"
     { (yyval.d) = log10((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 268:
-#line 2874 "Gmsh.y"
+#line 2807 "Gmsh.y"
     { (yyval.d) = sqrt((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 269:
-#line 2875 "Gmsh.y"
+#line 2808 "Gmsh.y"
     { (yyval.d) = sin((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 270:
-#line 2876 "Gmsh.y"
+#line 2809 "Gmsh.y"
     { (yyval.d) = asin((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 271:
-#line 2877 "Gmsh.y"
+#line 2810 "Gmsh.y"
     { (yyval.d) = cos((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 272:
-#line 2878 "Gmsh.y"
+#line 2811 "Gmsh.y"
     { (yyval.d) = acos((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 273:
-#line 2879 "Gmsh.y"
+#line 2812 "Gmsh.y"
     { (yyval.d) = tan((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 274:
-#line 2880 "Gmsh.y"
+#line 2813 "Gmsh.y"
     { (yyval.d) = atan((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 275:
-#line 2881 "Gmsh.y"
+#line 2814 "Gmsh.y"
     { (yyval.d) = atan2((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d));;}
     break;
 
   case 276:
-#line 2882 "Gmsh.y"
+#line 2815 "Gmsh.y"
     { (yyval.d) = sinh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 277:
-#line 2883 "Gmsh.y"
+#line 2816 "Gmsh.y"
     { (yyval.d) = cosh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 278:
-#line 2884 "Gmsh.y"
+#line 2817 "Gmsh.y"
     { (yyval.d) = tanh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 279:
-#line 2885 "Gmsh.y"
+#line 2818 "Gmsh.y"
     { (yyval.d) = fabs((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 280:
-#line 2886 "Gmsh.y"
+#line 2819 "Gmsh.y"
     { (yyval.d) = floor((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 281:
-#line 2887 "Gmsh.y"
+#line 2820 "Gmsh.y"
     { (yyval.d) = ceil((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 282:
-#line 2888 "Gmsh.y"
+#line 2821 "Gmsh.y"
     { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 283:
-#line 2889 "Gmsh.y"
+#line 2822 "Gmsh.y"
     { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 284:
-#line 2890 "Gmsh.y"
+#line 2823 "Gmsh.y"
     { (yyval.d) = sqrt((yyvsp[(3) - (6)].d)*(yyvsp[(3) - (6)].d)+(yyvsp[(5) - (6)].d)*(yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 285:
-#line 2891 "Gmsh.y"
+#line 2824 "Gmsh.y"
     { (yyval.d) = (yyvsp[(3) - (4)].d)*(double)rand()/(double)RAND_MAX; ;}
     break;
 
   case 286:
-#line 2900 "Gmsh.y"
+#line 2833 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (1)].d); ;}
     break;
 
   case 287:
-#line 2901 "Gmsh.y"
+#line 2834 "Gmsh.y"
     { (yyval.d) = 3.141592653589793; ;}
     break;
 
   case 288:
-#line 2902 "Gmsh.y"
+#line 2835 "Gmsh.y"
     { (yyval.d) = Msg::GetCommRank(); ;}
     break;
 
   case 289:
-#line 2903 "Gmsh.y"
+#line 2836 "Gmsh.y"
     { (yyval.d) = Msg::GetCommSize(); ;}
     break;
 
   case 290:
-#line 2904 "Gmsh.y"
+#line 2837 "Gmsh.y"
     { (yyval.d) = Get_GmshMajorVersion(); ;}
     break;
 
   case 291:
-#line 2905 "Gmsh.y"
+#line 2838 "Gmsh.y"
     { (yyval.d) = Get_GmshMinorVersion(); ;}
     break;
 
   case 292:
-#line 2906 "Gmsh.y"
+#line 2839 "Gmsh.y"
     { (yyval.d) = Get_GmshPatchVersion(); ;}
     break;
 
   case 293:
-#line 2911 "Gmsh.y"
+#line 2844 "Gmsh.y"
     {
       Symbol TheSymbol;
       TheSymbol.Name = (yyvsp[(1) - (1)].c);
@@ -7172,7 +7105,7 @@ yyreduce:
     break;
 
   case 294:
-#line 2927 "Gmsh.y"
+#line 2860 "Gmsh.y"
     {
       char tmpstring[1024];
       sprintf(tmpstring, "%s_%d", (yyvsp[(1) - (5)].c), (int)(yyvsp[(4) - (5)].d)) ;
@@ -7190,7 +7123,7 @@ yyreduce:
     break;
 
   case 295:
-#line 2942 "Gmsh.y"
+#line 2875 "Gmsh.y"
     {
       Symbol TheSymbol;
       TheSymbol.Name = (yyvsp[(1) - (4)].c);
@@ -7213,7 +7146,7 @@ yyreduce:
     break;
 
   case 296:
-#line 2962 "Gmsh.y"
+#line 2895 "Gmsh.y"
     {
       Symbol TheSymbol;
       TheSymbol.Name = (yyvsp[(2) - (4)].c);
@@ -7229,7 +7162,7 @@ yyreduce:
     break;
 
   case 297:
-#line 2975 "Gmsh.y"
+#line 2908 "Gmsh.y"
     {
       Symbol TheSymbol;
       TheSymbol.Name = (yyvsp[(1) - (2)].c);
@@ -7245,7 +7178,7 @@ yyreduce:
     break;
 
   case 298:
-#line 2988 "Gmsh.y"
+#line 2921 "Gmsh.y"
     {
       Symbol TheSymbol;
       TheSymbol.Name = (yyvsp[(1) - (5)].c);
@@ -7268,91 +7201,49 @@ yyreduce:
     break;
 
   case 299:
-#line 3011 "Gmsh.y"
+#line 2944 "Gmsh.y"
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (3)].c)))){
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (3)].c));
-	(yyval.d) = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(3) - (3)].c), pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s.%s'", (yyvsp[(1) - (3)].c), (yyvsp[(3) - (3)].c));
-	  (yyval.d) = 0.;
-	}
-	else
-	  (yyval.d) = pNumOpt(0, GMSH_GET, 0);
-      }
+      NumberOption(GMSH_GET, (yyvsp[(1) - (3)].c), 0, (yyvsp[(3) - (3)].c), (yyval.d));
       Free((yyvsp[(1) - (3)].c)); Free((yyvsp[(3) - (3)].c));
     ;}
     break;
 
   case 300:
-#line 3029 "Gmsh.y"
+#line 2949 "Gmsh.y"
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (6)].c)))){
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (6)].c));
-	(yyval.d) = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(6) - (6)].c), pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", (yyvsp[(1) - (6)].c), (int)(yyvsp[(3) - (6)].d), (yyvsp[(6) - (6)].c));
-	  (yyval.d) = 0.;
-	}
-	else
-	  (yyval.d) = pNumOpt((int)(yyvsp[(3) - (6)].d), GMSH_GET, 0);
-      }
+      NumberOption(GMSH_GET, (yyvsp[(1) - (6)].c), (int)(yyvsp[(3) - (6)].d), (yyvsp[(6) - (6)].c), (yyval.d));
       Free((yyvsp[(1) - (6)].c)); Free((yyvsp[(6) - (6)].c));
     ;}
     break;
 
   case 301:
-#line 3047 "Gmsh.y"
+#line 2954 "Gmsh.y"
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (4)].c)))){
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (4)].c));
-	(yyval.d) = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(3) - (4)].c), pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s.%s'", (yyvsp[(1) - (4)].c), (yyvsp[(3) - (4)].c));
-	  (yyval.d) = 0.;
-	}
-	else
-	  (yyval.d) = pNumOpt(0, GMSH_SET|GMSH_GUI, pNumOpt(0, GMSH_GET, 0)+(yyvsp[(4) - (4)].i));
+      double d = 0.;
+      if(NumberOption(GMSH_GET, (yyvsp[(1) - (4)].c), 0, (yyvsp[(3) - (4)].c), d)){
+	d += (yyvsp[(4) - (4)].i);
+	NumberOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (4)].c), 0, (yyvsp[(3) - (4)].c), d);
+	(yyval.d) = d;
       }
       Free((yyvsp[(1) - (4)].c)); Free((yyvsp[(3) - (4)].c));
     ;}
     break;
 
   case 302:
-#line 3065 "Gmsh.y"
+#line 2964 "Gmsh.y"
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory((yyvsp[(1) - (7)].c)))){
-	yymsg(0, "Unknown numeric option class '%s'", (yyvsp[(1) - (7)].c));
-	(yyval.d) = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption((yyvsp[(6) - (7)].c), pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", (yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c));
-	  (yyval.d) = 0.;
-	}
-	else
-	  (yyval.d) = pNumOpt((int)(yyvsp[(3) - (7)].d), GMSH_SET|GMSH_GUI, pNumOpt((int)(yyvsp[(3) - (7)].d), GMSH_GET, 0)+(yyvsp[(7) - (7)].i));
+      double d = 0.;
+      if(NumberOption(GMSH_GET, (yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c), d)){
+	d += (yyvsp[(7) - (7)].i);
+	NumberOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c), d);
+	(yyval.d) = d;
       }
       Free((yyvsp[(1) - (7)].c)); Free((yyvsp[(6) - (7)].c));
     ;}
     break;
 
   case 303:
-#line 3083 "Gmsh.y"
+#line 2974 "Gmsh.y"
     { 
       (yyval.d) = Msg::GetValue((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].d));
       Free((yyvsp[(3) - (6)].c));
@@ -7360,70 +7251,70 @@ yyreduce:
     break;
 
   case 304:
-#line 3091 "Gmsh.y"
+#line 2982 "Gmsh.y"
     {
       memcpy((yyval.v), (yyvsp[(1) - (1)].v), 5*sizeof(double));
     ;}
     break;
 
   case 305:
-#line 3095 "Gmsh.y"
+#line 2986 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = -(yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
   case 306:
-#line 3099 "Gmsh.y"
+#line 2990 "Gmsh.y"
     { 
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
   case 307:
-#line 3103 "Gmsh.y"
+#line 2994 "Gmsh.y"
     { 
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(1) - (3)].v)[i] - (yyvsp[(3) - (3)].v)[i];
     ;}
     break;
 
   case 308:
-#line 3107 "Gmsh.y"
+#line 2998 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(1) - (3)].v)[i] + (yyvsp[(3) - (3)].v)[i];
     ;}
     break;
 
   case 309:
-#line 3114 "Gmsh.y"
+#line 3005 "Gmsh.y"
     { 
       (yyval.v)[0] = (yyvsp[(2) - (11)].d);  (yyval.v)[1] = (yyvsp[(4) - (11)].d);  (yyval.v)[2] = (yyvsp[(6) - (11)].d);  (yyval.v)[3] = (yyvsp[(8) - (11)].d); (yyval.v)[4] = (yyvsp[(10) - (11)].d);
     ;}
     break;
 
   case 310:
-#line 3118 "Gmsh.y"
+#line 3009 "Gmsh.y"
     { 
       (yyval.v)[0] = (yyvsp[(2) - (9)].d);  (yyval.v)[1] = (yyvsp[(4) - (9)].d);  (yyval.v)[2] = (yyvsp[(6) - (9)].d);  (yyval.v)[3] = (yyvsp[(8) - (9)].d); (yyval.v)[4] = 1.0;
     ;}
     break;
 
   case 311:
-#line 3122 "Gmsh.y"
+#line 3013 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (7)].d);  (yyval.v)[1] = (yyvsp[(4) - (7)].d);  (yyval.v)[2] = (yyvsp[(6) - (7)].d);  (yyval.v)[3] = 0.0; (yyval.v)[4] = 1.0;
     ;}
     break;
 
   case 312:
-#line 3126 "Gmsh.y"
+#line 3017 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (7)].d);  (yyval.v)[1] = (yyvsp[(4) - (7)].d);  (yyval.v)[2] = (yyvsp[(6) - (7)].d);  (yyval.v)[3] = 0.0; (yyval.v)[4] = 1.0;
     ;}
     break;
 
   case 313:
-#line 3133 "Gmsh.y"
+#line 3024 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(List_T*));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].l)));
@@ -7431,14 +7322,14 @@ yyreduce:
     break;
 
   case 314:
-#line 3138 "Gmsh.y"
+#line 3029 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].l)));
     ;}
     break;
 
   case 315:
-#line 3146 "Gmsh.y"
+#line 3037 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].d)));
@@ -7446,14 +7337,14 @@ yyreduce:
     break;
 
   case 316:
-#line 3151 "Gmsh.y"
+#line 3042 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
   case 317:
-#line 3155 "Gmsh.y"
+#line 3046 "Gmsh.y"
     {
       // creates an empty list
       (yyval.l) = List_Create(2, 1, sizeof(double));
@@ -7461,14 +7352,14 @@ yyreduce:
     break;
 
   case 318:
-#line 3160 "Gmsh.y"
+#line 3051 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (3)].l);
     ;}
     break;
 
   case 319:
-#line 3164 "Gmsh.y"
+#line 3055 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (4)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -7479,7 +7370,7 @@ yyreduce:
     break;
 
   case 320:
-#line 3172 "Gmsh.y"
+#line 3063 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(4) - (5)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -7490,7 +7381,7 @@ yyreduce:
     break;
 
   case 321:
-#line 3183 "Gmsh.y"
+#line 3074 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (2)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -7501,7 +7392,7 @@ yyreduce:
     break;
 
   case 322:
-#line 3191 "Gmsh.y"
+#line 3082 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (3)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -7512,7 +7403,7 @@ yyreduce:
     break;
 
   case 323:
-#line 3199 "Gmsh.y"
+#line 3090 "Gmsh.y"
     { 
       (yyval.l) = List_Create(2, 1, sizeof(double)); 
       for(double d = (yyvsp[(1) - (3)].d); ((yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d)) ? (d <= (yyvsp[(3) - (3)].d)) : (d >= (yyvsp[(3) - (3)].d)); ((yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d)) ? (d += 1.) : (d -= 1.)) 
@@ -7521,7 +7412,7 @@ yyreduce:
     break;
 
   case 324:
-#line 3205 "Gmsh.y"
+#line 3096 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double)); 
       if(!(yyvsp[(5) - (5)].d) || ((yyvsp[(1) - (5)].d) < (yyvsp[(3) - (5)].d) && (yyvsp[(5) - (5)].d) < 0) || ((yyvsp[(1) - (5)].d) > (yyvsp[(3) - (5)].d) && (yyvsp[(5) - (5)].d) > 0)){
@@ -7535,7 +7426,7 @@ yyreduce:
     break;
 
   case 325:
-#line 3216 "Gmsh.y"
+#line 3107 "Gmsh.y"
     {
       // Returns the coordinates of a point and fills a list with it.
       // This allows to ensure e.g. that relative point positions are
@@ -7558,7 +7449,7 @@ yyreduce:
     break;
 
   case 326:
-#line 3236 "Gmsh.y"
+#line 3127 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -7571,7 +7462,7 @@ yyreduce:
     break;
 
   case 327:
-#line 3246 "Gmsh.y"
+#line 3137 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -7584,7 +7475,7 @@ yyreduce:
     break;
 
   case 328:
-#line 3256 "Gmsh.y"
+#line 3147 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       Symbol TheSymbol;
@@ -7604,7 +7495,7 @@ yyreduce:
     break;
 
   case 329:
-#line 3273 "Gmsh.y"
+#line 3164 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       Symbol TheSymbol;
@@ -7631,7 +7522,7 @@ yyreduce:
     break;
 
   case 330:
-#line 3300 "Gmsh.y"
+#line 3191 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].d)));
@@ -7639,21 +7530,21 @@ yyreduce:
     break;
 
   case 331:
-#line 3305 "Gmsh.y"
+#line 3196 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
   case 332:
-#line 3309 "Gmsh.y"
+#line 3200 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].d)));
     ;}
     break;
 
   case 333:
-#line 3313 "Gmsh.y"
+#line 3204 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (3)].l)); i++){
 	double d;
@@ -7665,21 +7556,21 @@ yyreduce:
     break;
 
   case 334:
-#line 3326 "Gmsh.y"
+#line 3217 "Gmsh.y"
     {
       (yyval.u) = CTX.PACK_COLOR((int)(yyvsp[(2) - (9)].d), (int)(yyvsp[(4) - (9)].d), (int)(yyvsp[(6) - (9)].d), (int)(yyvsp[(8) - (9)].d));
     ;}
     break;
 
   case 335:
-#line 3330 "Gmsh.y"
+#line 3221 "Gmsh.y"
     {
       (yyval.u) = CTX.PACK_COLOR((int)(yyvsp[(2) - (7)].d), (int)(yyvsp[(4) - (7)].d), (int)(yyvsp[(6) - (7)].d), 255);
     ;}
     break;
 
   case 336:
-#line 3342 "Gmsh.y"
+#line 3233 "Gmsh.y"
     {
       int flag;
       (yyval.u) = Get_ColorForString(ColorString, -1, (yyvsp[(1) - (1)].c), &flag);
@@ -7689,35 +7580,24 @@ yyreduce:
     break;
 
   case 337:
-#line 3349 "Gmsh.y"
+#line 3240 "Gmsh.y"
     {
-      unsigned int (*pColOpt)(int num, int action, unsigned int value);
-      StringXColor *pColCat;
-      if(!(pColCat = Get_ColorOptionCategory((yyvsp[(1) - (5)].c)))){
-	yymsg(0, "Unknown color option class '%s'", (yyvsp[(1) - (5)].c));
-	(yyval.u) = 0;
-      }
-      else{
-	if(!(pColOpt =  (unsigned int (*) (int, int, unsigned int))Get_ColorOption((yyvsp[(5) - (5)].c), pColCat))){
-	  yymsg(0, "Unknown color option '%s.Color.%s'", (yyvsp[(1) - (5)].c), (yyvsp[(5) - (5)].c));
-	  (yyval.u) = 0;
-	}
-	else
-	  (yyval.u) = pColOpt(0, GMSH_GET, 0);
-      }
+      unsigned int val = 0;
+      ColorOption(GMSH_GET, (yyvsp[(1) - (5)].c), 0, (yyvsp[(5) - (5)].c), val);
+      (yyval.u) = val;
       Free((yyvsp[(1) - (5)].c)); Free((yyvsp[(5) - (5)].c));
     ;}
     break;
 
   case 338:
-#line 3370 "Gmsh.y"
+#line 3250 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (3)].l);
     ;}
     break;
 
   case 339:
-#line 3374 "Gmsh.y"
+#line 3254 "Gmsh.y"
     {
       (yyval.l) = List_Create(256, 10, sizeof(unsigned int));
       GmshColorTable *ct = Get_ColorTable((int)(yyvsp[(3) - (6)].d));
@@ -7732,7 +7612,7 @@ yyreduce:
     break;
 
   case 340:
-#line 3389 "Gmsh.y"
+#line 3269 "Gmsh.y"
     {
       (yyval.l) = List_Create(256, 10, sizeof(unsigned int));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].u)));
@@ -7740,35 +7620,35 @@ yyreduce:
     break;
 
   case 341:
-#line 3394 "Gmsh.y"
+#line 3274 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].u)));
     ;}
     break;
 
   case 342:
-#line 3401 "Gmsh.y"
+#line 3281 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(1) - (1)].c);
     ;}
     break;
 
   case 343:
-#line 3405 "Gmsh.y"
+#line 3285 "Gmsh.y"
     {
       Msg::Warning("Named string expressions not implemented yet");
     ;}
     break;
 
   case 344:
-#line 3412 "Gmsh.y"
+#line 3292 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(1) - (1)].c);
     ;}
     break;
 
   case 345:
-#line 3416 "Gmsh.y"
+#line 3296 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc(32*sizeof(char));
       time_t now;
@@ -7779,7 +7659,7 @@ yyreduce:
     break;
 
   case 346:
-#line 3424 "Gmsh.y"
+#line 3304 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (6)].c))+strlen((yyvsp[(5) - (6)].c))+1)*sizeof(char));
       strcpy((yyval.c), (yyvsp[(3) - (6)].c));
@@ -7790,7 +7670,7 @@ yyreduce:
     break;
 
   case 347:
-#line 3432 "Gmsh.y"
+#line 3312 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (4)].c))+1)*sizeof(char));
       int i;
@@ -7807,7 +7687,7 @@ yyreduce:
     break;
 
   case 348:
-#line 3446 "Gmsh.y"
+#line 3326 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (4)].c))+1)*sizeof(char));
       int i;
@@ -7824,14 +7704,14 @@ yyreduce:
     break;
 
   case 349:
-#line 3460 "Gmsh.y"
+#line 3340 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(3) - (4)].c);
     ;}
     break;
 
   case 350:
-#line 3464 "Gmsh.y"
+#line 3344 "Gmsh.y"
     {
       char tmpstring[1024];
       int i = PrintListOfDouble((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].l), tmpstring);
@@ -7853,60 +7733,30 @@ yyreduce:
     break;
 
   case 351:
-#line 3483 "Gmsh.y"
+#line 3363 "Gmsh.y"
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory((yyvsp[(3) - (6)].c)))){
-	yymsg(0, "Unknown string option class '%s'", (yyvsp[(3) - (6)].c));
-	(yyval.c) = (char*)Malloc(sizeof(char));
-	(yyval.c)[0] = '\0';
-      }
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption((yyvsp[(5) - (6)].c), pStrCat))){
-	  yymsg(0, "Unknown string option '%s.%s'", (yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
-	  (yyval.c) = (char*)Malloc(sizeof(char));
-	  (yyval.c)[0] = '\0';
-	}
-	else{
-	  const char *str = pStrOpt(0, GMSH_GET, NULL);
-	  (yyval.c) = (char*)Malloc((strlen(str)+1)*sizeof(char));
-	  strcpy((yyval.c), str);
-	}
-      }
+      const char *val = "";
+      StringOption(GMSH_GET, (yyvsp[(3) - (6)].c), 0, (yyvsp[(5) - (6)].c), val);
+      (yyval.c) = (char*)Malloc((strlen(val) + 1) * sizeof(char));
+      strcpy((yyval.c), val);
+      Free((yyvsp[(3) - (6)].c)); Free((yyvsp[(5) - (6)].c));
     ;}
     break;
 
   case 352:
-#line 3506 "Gmsh.y"
+#line 3371 "Gmsh.y"
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory((yyvsp[(3) - (9)].c)))){
-	yymsg(0, "Unknown string option class '%s'", (yyvsp[(3) - (9)].c));
-	(yyval.c) = (char*)Malloc(sizeof(char));
-	(yyval.c)[0] = '\0';
-      }
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption((yyvsp[(8) - (9)].c), pStrCat))){
-	  yymsg(0, "Unknown string option '%s[%d].%s'", (yyvsp[(3) - (9)].c), (int)(yyvsp[(5) - (9)].d), (yyvsp[(8) - (9)].c));
-	  (yyval.c) = (char*)Malloc(sizeof(char));
-	  (yyval.c)[0] = '\0';
-	}
-	else{
-	  const char *str = pStrOpt((int)(yyvsp[(5) - (9)].d), GMSH_GET, NULL);
-	  (yyval.c) = (char*)Malloc((strlen(str)+1)*sizeof(char));
-	  strcpy((yyval.c), str);
-	}
-      }
+      const char *val = "";
+      StringOption(GMSH_GET, (yyvsp[(3) - (9)].c), (int)(yyvsp[(5) - (9)].d), (yyvsp[(8) - (9)].c), val);
+      (yyval.c) = (char*)Malloc((strlen(val) + 1) * sizeof(char));
+      strcpy((yyval.c), val);
+      Free((yyvsp[(3) - (9)].c)); Free((yyvsp[(8) - (9)].c));
     ;}
     break;
 
 
 /* Line 1267 of yacc.c.  */
-#line 7910 "Gmsh.tab.cpp"
+#line 7760 "Gmsh.tab.cpp"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -8120,7 +7970,7 @@ yyreturn:
 }
 
 
-#line 3530 "Gmsh.y"
+#line 3380 "Gmsh.y"
 
 
 void DeleteSymbol(void *a, void *b)
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index 3956d22b7e8eecaec0356a7a9100c16966ace3b8..f399984ad74772b95e2ebe1d883f737940e084a1 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -1,5 +1,5 @@
 %{
-// $Id: Gmsh.y,v 1.321 2008-07-04 14:58:35 geuzaine Exp $
+// $Id: Gmsh.y,v 1.322 2008-07-05 23:01:02 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //
@@ -811,115 +811,68 @@ Affectation :
 
   | tSTRING '.' tSTRING tAFFECT StringExpr tEND 
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory($1)))
-	yymsg(0, "Unknown string option class '%s'", $1);
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption($3, pStrCat)))
-	  yymsg(0, "Unknown string option '%s.%s'", $1, $3);
-	else
-	  pStrOpt(0, GMSH_SET|GMSH_GUI, $5);
-      }
-      Free($1); Free($3); //FIXME: somtimes leak $5
+      StringOption(GMSH_SET|GMSH_GUI, $1, 0, $3, $5);
+      Free($1); Free($3);
     }
   | tSTRING '[' FExpr ']' '.' tSTRING tAFFECT StringExpr tEND 
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory($1)))
-	yymsg(0, "Unknown string option class '%s'", $1);
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption($6, pStrCat)))
-	  yymsg(0, "Unknown string option '%s[%d].%s'", $1, (int)$3, $6);
-	else
-	  pStrOpt((int)$3, GMSH_SET|GMSH_GUI, $8);
-      }
-      Free($1); Free($6); //FIXME: somtimes leak $8
+      StringOption(GMSH_SET|GMSH_GUI, $1, (int)$3, $6, $8);
+      Free($1); Free($6);
     }
 
   // Option Numbers
 
   | tSTRING '.' tSTRING NumericAffectation FExpr tEND 
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1)))
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-      else{
-	if(!(pNumOpt = (double (*) (int, int, double))Get_NumberOption($3, pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s.%s'", $1, $3);
-	else{
-	  double d = 0;
-	  switch($4){
-	  case 0 : d = $5; break;
-	  case 1 : d = pNumOpt(0, GMSH_GET, 0) + $5; break;
-	  case 2 : d = pNumOpt(0, GMSH_GET, 0) - $5; break;
-	  case 3 : d = pNumOpt(0, GMSH_GET, 0) * $5; break;
-	  case 4 : 
-	    if($5) d = pNumOpt(0, GMSH_GET, 0) / $5; 
-	    else yymsg(0, "Division by zero in '%s.%s /= %g'", $1, $3, $5);
-	    break;
-	  }
-	  pNumOpt(0, GMSH_SET|GMSH_GUI, d);
+      double d = 0.;
+      if(NumberOption(GMSH_GET, $1, 0, $3, d)){
+	switch($4){
+	case 0 : d = $5; break;
+	case 1 : d += $5; break;
+	case 2 : d -= $5; break;
+	case 3 : d *= $5; break;
+	case 4 : 
+	  if($5) d /= $5; 
+	  else yymsg(0, "Division by zero in '%s.%s /= %g'", $1, $3, $5);
+	  break;
 	}
+	NumberOption(GMSH_SET|GMSH_GUI, $1, 0, $3, d);
       }
       Free($1); Free($3);
     }
   | tSTRING '[' FExpr ']' '.' tSTRING NumericAffectation FExpr tEND 
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1)))
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($6, pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", $1, (int)$3, $6);
-	else{
-	  double d = 0;
-	  switch($7){
-	  case 0 : d = $8; break;
-	  case 1 : d = pNumOpt((int)$3, GMSH_GET, 0) + $8; break;
-	  case 2 : d = pNumOpt((int)$3, GMSH_GET, 0) - $8; break;
-	  case 3 : d = pNumOpt((int)$3, GMSH_GET, 0) * $8; break;
-	  case 4 : 
-	    if($8) d = pNumOpt((int)$3, GMSH_GET, 0) / $8;
-	    else yymsg(0, "Division by zero in '%s[%d].%s /= %g'", 
-		       $1, (int)$3, $6, $8);
-	    break;
-	  }
-	  pNumOpt((int)$3, GMSH_SET|GMSH_GUI, d);
+      double d = 0.;
+      if(NumberOption(GMSH_GET, $1, (int)$3, $6, d)){
+	switch($7){
+	case 0 : d = $8; break;
+	case 1 : d += $8; break;
+	case 2 : d -= $8; break;
+	case 3 : d *= $8; break;
+	case 4 : 
+	  if($8) d /= $8; 
+	  else yymsg(0, "Division by zero in '%s[%d].%s /= %g'", $1, (int)$3, $6, $8);
+	  break;
 	}
+	NumberOption(GMSH_SET|GMSH_GUI, $1, (int)$3, $6, d);
       }
       Free($1); Free($6);
     }
   | tSTRING '.' tSTRING NumericIncrement tEND 
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1)))
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($3, pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s.%s'", $1, $3);
-	else
-	  pNumOpt(0, GMSH_SET|GMSH_GUI, pNumOpt(0, GMSH_GET, 0)+$4);
+      double d = 0.;
+      if(NumberOption(GMSH_GET, $1, 0, $3, d)){
+	d += $4;
+	NumberOption(GMSH_SET|GMSH_GUI, $1, 0, $3, d);
       }
       Free($1); Free($3);
     }
   | tSTRING '[' FExpr ']' '.' tSTRING NumericIncrement tEND 
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1)))
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($6, pNumCat)))
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", $1, (int)$3, $6);
-	else
-	  pNumOpt((int)$3, GMSH_SET|GMSH_GUI, pNumOpt((int)$3, GMSH_GET, 0)+$7);
+      double d = 0.;
+      if(NumberOption(GMSH_GET, $1, (int)$3, $6, d)){
+	d += $7;
+	NumberOption(GMSH_SET|GMSH_GUI, $1, (int)$3, $6, d);
       }
       Free($1); Free($6);
     }
@@ -928,32 +881,12 @@ Affectation :
 
   | tSTRING '.' tColor '.' tSTRING tAFFECT ColorExpr tEND 
     {
-      unsigned int (*pColOpt)(int num, int action, unsigned int value);
-      StringXColor *pColCat;
-      if(!(pColCat = Get_ColorOptionCategory($1)))
-	yymsg(0, "Unknown color option class '%s'", $1);
-      else{
-	if(!(pColOpt = (unsigned int (*) (int, int, unsigned int))
-	     Get_ColorOption($5, pColCat)))
-	  yymsg(0, "Unknown color option '%s.Color.%s'", $1, $5);
-	else
-	  pColOpt(0, GMSH_SET|GMSH_GUI, $7);
-      }
+      ColorOption(GMSH_SET|GMSH_GUI, $1, 0, $5, $7);
       Free($1); Free($5);
     }
   | tSTRING '[' FExpr ']' '.' tColor '.' tSTRING tAFFECT ColorExpr tEND 
     {
-      unsigned int (*pColOpt)(int num, int action, unsigned int value);
-      StringXColor *pColCat;
-      if(!(pColCat = Get_ColorOptionCategory($1)))
-	yymsg(0, "Unknown color option class '%s'", $1);
-      else{
-	if(!(pColOpt =  (unsigned int (*) (int, int, unsigned int))
-	     Get_ColorOption($8, pColCat)))
-	  yymsg(0, "Unknown color option '%s[%d].Color.%s'", $1, (int)$3, $8);
-	else
-	  pColOpt((int)$3, GMSH_SET|GMSH_GUI, $10);
-      }
+      ColorOption(GMSH_SET|GMSH_GUI, $1, (int)$3, $8, $10);
       Free($1); Free($8);
     }
 
@@ -3009,73 +2942,31 @@ FExpr_Single :
 
   | tSTRING '.' tSTRING 
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1))){
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-	$$ = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($3, pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s.%s'", $1, $3);
-	  $$ = 0.;
-	}
-	else
-	  $$ = pNumOpt(0, GMSH_GET, 0);
-      }
+      NumberOption(GMSH_GET, $1, 0, $3, $$);
       Free($1); Free($3);
     }
   | tSTRING '[' FExpr ']' '.' tSTRING 
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1))){
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-	$$ = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($6, pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", $1, (int)$3, $6);
-	  $$ = 0.;
-	}
-	else
-	  $$ = pNumOpt((int)$3, GMSH_GET, 0);
-      }
+      NumberOption(GMSH_GET, $1, (int)$3, $6, $$);
       Free($1); Free($6);
     }
   | tSTRING '.' tSTRING NumericIncrement
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1))){
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-	$$ = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($3, pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s.%s'", $1, $3);
-	  $$ = 0.;
-	}
-	else
-	  $$ = pNumOpt(0, GMSH_SET|GMSH_GUI, pNumOpt(0, GMSH_GET, 0)+$4);
+      double d = 0.;
+      if(NumberOption(GMSH_GET, $1, 0, $3, d)){
+	d += $4;
+	NumberOption(GMSH_SET|GMSH_GUI, $1, 0, $3, d);
+	$$ = d;
       }
       Free($1); Free($3);
     }
   | tSTRING '[' FExpr ']' '.' tSTRING NumericIncrement
     {
-      double (*pNumOpt)(int num, int action, double value);
-      StringXNumber *pNumCat;
-      if(!(pNumCat = Get_NumberOptionCategory($1))){
-	yymsg(0, "Unknown numeric option class '%s'", $1);
-	$$ = 0.;
-      }
-      else{
-	if(!(pNumOpt =  (double (*) (int, int, double))Get_NumberOption($6, pNumCat))){
-	  yymsg(0, "Unknown numeric option '%s[%d].%s'", $1, (int)$3, $6);
-	  $$ = 0.;
-	}
-	else
-	  $$ = pNumOpt((int)$3, GMSH_SET|GMSH_GUI, pNumOpt((int)$3, GMSH_GET, 0)+$7);
+      double d = 0.;
+      if(NumberOption(GMSH_GET, $1, (int)$3, $6, d)){
+	d += $7;
+	NumberOption(GMSH_SET|GMSH_GUI, $1, (int)$3, $6, d);
+	$$ = d;
       }
       Free($1); Free($6);
     }
@@ -3347,20 +3238,9 @@ ColorExpr :
     }
   | tSTRING '.' tColor '.' tSTRING 
     {
-      unsigned int (*pColOpt)(int num, int action, unsigned int value);
-      StringXColor *pColCat;
-      if(!(pColCat = Get_ColorOptionCategory($1))){
-	yymsg(0, "Unknown color option class '%s'", $1);
-	$$ = 0;
-      }
-      else{
-	if(!(pColOpt =  (unsigned int (*) (int, int, unsigned int))Get_ColorOption($5, pColCat))){
-	  yymsg(0, "Unknown color option '%s.Color.%s'", $1, $5);
-	  $$ = 0;
-	}
-	else
-	  $$ = pColOpt(0, GMSH_GET, 0);
-      }
+      unsigned int val = 0;
+      ColorOption(GMSH_GET, $1, 0, $5, val);
+      $$ = val;
       Free($1); Free($5);
     }
 ;
@@ -3481,49 +3361,19 @@ StringExpr :
     }
   | tSprintf '(' tSTRING '.' tSTRING ')'
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory($3))){
-	yymsg(0, "Unknown string option class '%s'", $3);
-	$$ = (char*)Malloc(sizeof(char));
-	$$[0] = '\0';
-      }
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption($5, pStrCat))){
-	  yymsg(0, "Unknown string option '%s.%s'", $3, $5);
-	  $$ = (char*)Malloc(sizeof(char));
-	  $$[0] = '\0';
-	}
-	else{
-	  const char *str = pStrOpt(0, GMSH_GET, NULL);
-	  $$ = (char*)Malloc((strlen(str)+1)*sizeof(char));
-	  strcpy($$, str);
-	}
-      }
+      const char *val = "";
+      StringOption(GMSH_GET, $3, 0, $5, val);
+      $$ = (char*)Malloc((strlen(val) + 1) * sizeof(char));
+      strcpy($$, val);
+      Free($3); Free($5);
     }
   | tSprintf '(' tSTRING '[' FExpr ']' '.' tSTRING ')'
     { 
-      const char* (*pStrOpt)(int num, int action, const char *value);
-      StringXString *pStrCat;
-      if(!(pStrCat = Get_StringOptionCategory($3))){
-	yymsg(0, "Unknown string option class '%s'", $3);
-	$$ = (char*)Malloc(sizeof(char));
-	$$[0] = '\0';
-      }
-      else{
-	if(!(pStrOpt = (const char *(*) (int, int, const char *))
-	     Get_StringOption($8, pStrCat))){
-	  yymsg(0, "Unknown string option '%s[%d].%s'", $3, (int)$5, $8);
-	  $$ = (char*)Malloc(sizeof(char));
-	  $$[0] = '\0';
-	}
-	else{
-	  const char *str = pStrOpt((int)$5, GMSH_GET, NULL);
-	  $$ = (char*)Malloc((strlen(str)+1)*sizeof(char));
-	  strcpy($$, str);
-	}
-      }
+      const char *val = "";
+      StringOption(GMSH_GET, $3, (int)$5, $8, val);
+      $$ = (char*)Malloc((strlen(val) + 1) * sizeof(char));
+      strcpy($$, val);
+      Free($3); Free($8);
     }
 ;
 
diff --git a/Parser/Gmsh.yy.cpp b/Parser/Gmsh.yy.cpp
index 32779e8e18d336502cf015c56b4e67b6410d6369..9bbd26530b7296e19cad5c5e516812d8b5c22422 100644
--- a/Parser/Gmsh.yy.cpp
+++ b/Parser/Gmsh.yy.cpp
@@ -835,7 +835,7 @@ int gmsh_yy_flex_debug = 0;
 char *gmsh_yytext;
 #line 1 "Gmsh.l"
 #line 2 "Gmsh.l"
-// $Id: Gmsh.yy.cpp,v 1.371 2008-07-04 14:58:36 geuzaine Exp $
+// $Id: Gmsh.yy.cpp,v 1.372 2008-07-05 23:01:02 geuzaine Exp $
 //
 // Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
 //