[GRASS-SVN] r60713 - in grass/trunk: include lib/gis

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Jun 5 10:32:48 PDT 2014


Author: hcho
Date: 2014-06-05 10:32:48 -0700 (Thu, 05 Jun 2014)
New Revision: 60713

Modified:
   grass/trunk/include/gis.h
   grass/trunk/lib/gis/parser.c
Log:
The "exclusive" member of the Option and Flag structures is a comma-separated
string. Whitespaces are not ignored. Each name separated by comma can be used
to group options/flags together, make them mutually exclusive, or make one of
them conditionally required.

Names starting with "+" tie together options/flags and names starting with "*"
(name ignored) make them conditionally required (not always required, but if
some other options/flags are not used, they become required). Other names make
options/flags mutually exclusive in the same group. These three different types
of grouping can be mixed.

EXAMPLES

1. opt1 & opt2 are mutually exclusive.
   opt2 & opt3 are mutually exclusive.

   opt1->exclusive = "1";
   opt2->exclusive = "1,2";
   opt3->exclusive = "2";

2. opt1 & opt2 must be used together.

   opt1->exclusive = "+1";
   opt2->exclusive = "+1";
   opt3->exclusive = "";

3. opt1 or opt2 must be used. Both can be used together. Naming ignored.

   opt1->exclusive = "*ignored";
   opt2->exclusive = "*";
   opt3->exclusive = "";

4. (opt1 & opt2 together) or (opt3 & opt4 together) must be used. All four can
   be used together.

   opt1->exclusive = "+1,*";
   opt2->exclusive = "+1";   /* * is optional because opt2 is tied with opt1 */
   opt3->exclusive = "+2,*";
   opt4->exclusive = "+2";

5. Only one of (opt1 & opt2 together) or (opt3 & opt4 together) must be used.
   All four cannot be used together.

   opt1->exclusive = "+1,*,1";
   opt2->exclusive = "+1";   /* * is optional because opt2 is tied with opt1 */
   opt3->exclusive = "+2,*,1";
   opt4->exclusive = "+2";   /* 1 is optional because opt4 is tied with opt3 */


Modified: grass/trunk/include/gis.h
===================================================================
--- grass/trunk/include/gis.h	2014-06-05 04:48:03 UTC (rev 60712)
+++ grass/trunk/include/gis.h	2014-06-05 17:32:48 UTC (rev 60713)
@@ -75,12 +75,12 @@
 #define U_RADIANS	7
 #define U_DEGREES	8
 /* Temporal units from the datetime library */
-#define U_YEARS         DATETIME_YEAR   
-#define U_MONTHS        DATETIME_MONTH  
-#define U_DAYS          DATETIME_DAY    
-#define U_HOURS         DATETIME_HOUR   
-#define U_MINUTES       DATETIME_MINUTE 
-#define U_SECONDS       DATETIME_SECOND 
+#define U_YEARS         DATETIME_YEAR
+#define U_MONTHS        DATETIME_MONTH
+#define U_DAYS          DATETIME_DAY
+#define U_HOURS         DATETIME_HOUR
+#define U_MINUTES       DATETIME_MINUTE
+#define U_SECONDS       DATETIME_SECOND
 
 /*! \brief Projection code - XY coordinate system (unreferenced data) */
 #define PROJECTION_XY     0
@@ -256,7 +256,7 @@
     G_OPT_M_MAPSET,             /*!< mapset */
     G_OPT_M_COORDS,             /*!< coordinates */
     G_OPT_M_COLR,               /*!< color rules */
-    G_OPT_M_DIR,                /*!< directory input */    
+    G_OPT_M_DIR,                /*!< directory input */
     G_OPT_M_REGION,             /*!< saved region */
 
     G_OPT_STDS_INPUT,           /*!< old input space time dataset of type strds, str3ds or stvds */
@@ -273,7 +273,7 @@
     G_OPT_STVDS_OUTPUT,         /*!< new output space time vector dataset */
     G_OPT_MAP_INPUT,            /*!< old input map of type raster, vector or raster3d  */
     G_OPT_MAP_INPUTS,           /*!< old input maps of type raster, vector or raster3d  */
-    G_OPT_STDS_TYPE,            /*!< the type of a space time dataset: strds, str3ds, stvds */ 
+    G_OPT_STDS_TYPE,            /*!< the type of a space time dataset: strds, str3ds, stvds */
     G_OPT_MAP_TYPE,             /*!< The type of an input map: raster, vect, rast3d */
     G_OPT_T_TYPE,               /*!< The temporal type of a space time dataset */
     G_OPT_T_WHERE,              /*!< A temporal GIS framework SQL WHERE statement */
@@ -393,15 +393,15 @@
     /*! \brief Resolution - east to west cell size for 2D data */
     double ew_res;
     /*! \brief Resolution - east to west cell size for 3D data */
-    double ew_res3;   
+    double ew_res3;
     /*! \brief Resolution - north to south cell size for 2D data */
-    double ns_res;     
+    double ns_res;
     /*! \brief Resolution - north to south cell size for 3D data */
-    double ns_res3;   
+    double ns_res3;
     /*! \brief Resolution - top to bottom cell size for 3D data */
-    double tb_res;    
+    double tb_res;
     /*! \brief Extent coordinates (north) */
-    double north;     
+    double north;
     /*! \brief Extent coordinates (south) */
     double south;
     /*! \brief Extent coordinates (east) */
@@ -455,6 +455,8 @@
 /*!
   \brief Structure that stores option information
 
+  Used by the G_parser() system.
+
   The descriptions member contains pairs of option and option
   descriptions separated by semicolon ';'.
   For example, when options member is set using:
@@ -472,7 +474,61 @@
   GUI dependency is a list of options (separated by commas) to be updated
   if the value is changed.
 
-  Used by the G_parser() system.
+  The exclusive member of the Option and Flag structures is a comma-separated
+  string. Whitespaces are not ignored. Each name separated by comma can be used
+  to group options/flags together, make them mutually exclusive, or make one of
+  them conditionally required. Names starting with "+" tie together
+  options/flags and names starting with "*" (name ignored) make them
+  conditionally required (not always required, but if some other options/flags
+  are not used, they become required). Other names make options/flags mutually
+  exclusive in the same group. These three different types of grouping can be
+  mixed. G_parser() raises a fatal error if any violations are found.
+
+  Examples
+
+  1. opt1 & opt2 are mutually exclusive and opt2 & opt3 are mutually exclusive.
+
+     \code
+     opt1->exclusive = "1";
+     opt2->exclusive = "1,2";
+     opt3->exclusive = "2";
+     \endcode
+
+  2. opt1 & opt2 must be used together.
+
+     \code
+     opt1->exclusive = "+1";
+     opt2->exclusive = "+1";
+     opt3->exclusive = "";
+     \endcode
+
+  3. opt1 or opt2 must be used. Both can be used together. Naming ignored.
+
+     \code
+     opt1->exclusive = "*ignored";
+     opt2->exclusive = "*";
+     opt3->exclusive = "";
+     \endcode
+
+  4. (opt1 & opt2 together) or (opt3 & opt4 together) must be used. All four
+     can be used together.
+
+     \code
+     opt1->exclusive = "+1,*";
+     opt2->exclusive = "+1";   // * is optional because opt2 is tied with opt1
+     opt3->exclusive = "+2,*";
+     opt4->exclusive = "+2";
+     \endcode
+
+  5. Only one of (opt1 & opt2 together) or (opt3 & opt4 together) must be used.
+     All four cannot be used together.
+
+     \code
+     opt1->exclusive = "+1,*,1";
+     opt2->exclusive = "+1";   // * is optional because opt2 is tied with opt1
+     opt3->exclusive = "+2,*,1";
+     opt4->exclusive = "+2";   // 1 is optional because opt4 is tied with opt3
+     \endcode
 */
 struct Option
 {

Modified: grass/trunk/lib/gis/parser.c
===================================================================
--- grass/trunk/lib/gis/parser.c	2014-06-05 04:48:03 UTC (rev 60712)
+++ grass/trunk/lib/gis/parser.c	2014-06-05 17:32:48 UTC (rev 60713)
@@ -117,8 +117,13 @@
 static void module_gui_wx(void);
 static void add_exclusive(const char *, int, const char *);
 static struct Exclusive *find_exclusive(char *);
+static int has_exclusive_name(const char *, char *);
 static int has_exclusive_key(int, char **, char *);
-static void check_exclusive(int);
+static int has_either_or(const char *);
+static void check_exclusive();
+static void check_mutually_exclusive_inputs();
+static void check_tied_together_inputs();
+static void check_either_or_inputs();
 static void append_error(const char *);
 
 /*!
@@ -550,7 +555,7 @@
 
 	}
 
-	check_exclusive(0);
+	check_exclusive();
     }
     
     /* Split options where multiple answers are OK */
@@ -902,6 +907,44 @@
     return NULL;
 }
 
+static int has_exclusive_name(const char *names, char *name)
+{
+    char *ptr1;
+
+    for (ptr1 = (char *)names;;) {
+	int len;
+	char *ptr2;
+
+	for (len = 0, ptr2 = ptr1; *ptr2 != '\0' && *ptr2 != ',';
+	     ptr2++, len++) ;
+
+	if (len > 0) {	/* skip ,, */
+	    char *aname;
+
+	    aname = G_malloc(len + 1);
+	    memcpy(aname, ptr1, len);
+	    aname[len] = 0;
+
+	    if (strcmp(name, aname) == 0) {
+		G_free(aname);
+		return 1;
+	    }
+
+	    G_free(aname);
+	}
+
+	if (*ptr2 == '\0')
+	    break;
+
+	ptr1 = ptr2 + 1;
+
+	if (*ptr1 == '\0')
+	    break;
+    }
+
+    return 0;
+}
+
 static int has_exclusive_key(int n_keys, char **keys, char *key)
 {
     int i;
@@ -914,87 +957,234 @@
     return 0;
 }
 
-static void check_exclusive(int print_group)
+static int has_either_or(const char *names)
 {
-    int i, n, allocated, len;
-    char **keys, *err;
+    return names && (names[0] == '*' || strstr(names, ",*"));
+}
 
-    n = 0;
-    allocated = 0;
-    len = 0;
-    keys = NULL;
+static void check_exclusive()
+{
+    check_mutually_exclusive_inputs();
+    check_tied_together_inputs();
+    check_either_or_inputs();
+}
 
+static void check_mutually_exclusive_inputs()
+{
+    int i;
+
     for (i = 0; i < st->n_exclusive; i++) {
 	struct Exclusive *exclusive;
 
 	exclusive = &st->exclusive[i];
 
-	G_debug(1, "check_exclusive(): Exclusive option/flag group: %s",
-			exclusive->name);
+	if (exclusive->name[0] == '+' || exclusive->name[0] == '*')
+	    continue;
 
-	if (exclusive->n_keys >= 1)
-	    G_debug(1, "check_exclusive():\t%s", exclusive->keys[0]);
+	G_debug(1, "check_exclusive(): Mutually exclusive option/flag group: "
+		   "%s", exclusive->name);
+	G_debug(1, "check_exclusive():\t%s", exclusive->keys[0]);
 
 	if (exclusive->n_keys > 1) {
-	    int j;
+	    int len, j;
+	    char *err;
+	    
+	    len = 0;
+	    for (j = 0; j < exclusive->n_keys; j++) {
+		len += strlen(exclusive->keys[j]) + 2; /* 2 for comma adn space
+							*/
+		if (j > 0)
+		    G_debug(1, "check_exclusive():\t%s", exclusive->keys[j]);
+	    }
+	    
+	    err = G_malloc(len + 100);
+	    sprintf(err, _("The following options/flags cannot be used "
+			   "together: "));
+	    
+	    len = strlen(err);
+	    for (j = 0; j < exclusive->n_keys - 2; j++) {
+		sprintf(err + len, "%s, ", exclusive->keys[j]);
+		len = strlen(err);
+	    }
+	    
+	    sprintf(err + len, _("%s and %s"), exclusive->keys[j],
+		    exclusive->keys[j + 1]);
+	    
+	    append_error(err);
+	    G_free(err);
+	}
+    }
+}
 
-	    if (print_group) {
-		len = strlen(exclusive->name);
-		for (j = 0; j < exclusive->n_keys; j++) {
-		    len += strlen(exclusive->keys[j]) + 2; /* 2 for comma adn
-							      space */
-		    if (j > 0)
-			G_debug(1, "check_exclusive():\t%s",
-				exclusive->keys[j]);
-		}
+static void check_tied_together_inputs()
+{
+    int i;
 
-		err = G_malloc(len + 100);
-		sprintf(err, _("Mutually exclusive options/flags "
-			       "in group '%s': "), exclusive->name);
-		
-		len = strlen(err);
-		for (j = 0; j < exclusive->n_keys - 2; j++) {
-		    sprintf(err + len, "%s, ", exclusive->keys[j]);
-		    len = strlen(err);
-		}
-		
-		sprintf(err + len, _("%s and %s"), exclusive->keys[j],
-			exclusive->keys[j + 1]);
+    for (i = 0; i < st->n_exclusive; i++) {
+	struct Exclusive *exclusive;
+	struct Option *opt;
+	struct Flag *flag;
+	int n, n_keys, len;
+	char *err;
 
-		append_error(err);
+	exclusive = &st->exclusive[i];
+
+	if (exclusive->name[0] != '+')
+	    continue;
+
+	G_debug(1, "check_exclusive(): Tied-together option/flag group: %s",
+		exclusive->name);
+	
+	n_keys = 0;
+	len = 0;
+	opt = &st->first_option;
+	while (opt) {
+	    if (has_exclusive_name(opt->exclusive, exclusive->name)) {
+		n_keys++;
+		len += strlen(opt->key) + 3; /* 3 for =, comma and space */
+		G_debug(1, "check_exclusive():\t%s=", opt->key);
 	    }
-	    else {
-		for (j = 0; j < exclusive->n_keys; j++) {
-		    if (!has_exclusive_key(n, keys, exclusive->keys[j])) {
-			if (n >= allocated) {
-			    allocated += 10;
-			    keys = G_realloc(keys, allocated * sizeof(char *));
-			}
-			keys[n] = exclusive->keys[j];
-			len += strlen(keys[n++]) + 2; /* 2 for comma and space
-						       */
-		    }
-		}
+	    opt = opt->next_opt;
+	}
+	
+	flag = &st->first_flag;
+	while (flag) {
+	    if (has_exclusive_name(flag->exclusive, exclusive->name)) {
+		n_keys++;
+		len += 4; /* 4 for -, flag, comma and space */
+		G_debug(1, "check_exclusive():\t-%c", flag->key);
 	    }
+	    flag = flag->next_flag;
 	}
-    }
 
-    if (!print_group && n) {
+	if (n_keys == 1 || exclusive->n_keys == n_keys)
+	    continue;
+	
 	err = G_malloc(len + 100);
-	sprintf(err, _("Mutually exclusive options/flags: "));
+	sprintf(err, _("The following options/flags must be used together: "));
 
+	n = 0;
 	len = strlen(err);
-	for (i = 0; i < n - 2; i++) {
-	    sprintf(err + len, "%s, ", keys[i]);
-	    len = strlen(err);
+	opt = &st->first_option;
+	while (opt) {
+	    if (has_exclusive_name(opt->exclusive, exclusive->name)) {
+		n++;
+		if (n <= n_keys - 2)
+		    sprintf(err + len, "%s=, ", opt->key);
+		else if (n == n_keys - 1)
+		    sprintf(err + len, "%s= ", opt->key);
+		else
+		    sprintf(err + len, "and %s=", opt->key);
+		len = strlen(err);
+	    }
+	    opt = opt->next_opt;
 	}
 	
-	sprintf(err + len, _("%s and %s"), keys[i], keys[i + 1]);
-
+	flag = &st->first_flag;
+	while (flag) {
+	    if (has_exclusive_name(flag->exclusive, exclusive->name)) {
+		n++;
+		if (n <= n_keys - 2)
+		    sprintf(err + len, "-%c, ", flag->key);
+		else if (n == n_keys - 1)
+		    sprintf(err + len, "-%c ", flag->key);
+		else
+		    sprintf(err + len, "and -%c", flag->key);
+		len = strlen(err);
+	    }
+	    flag = flag->next_flag;
+	}
+	
 	append_error(err);
+	G_free(err);
     }
 }
 
+static void check_either_or_inputs()
+{
+    int n_keys, len;
+    struct Option *opt;
+    struct Flag *flag;
+
+    G_debug(1, "check_exclusive(): Either-or options/flags "
+	       "(group names ignored)");
+
+    n_keys = 0;
+    len = 0;
+    opt = &st->first_option;
+    while (opt) {
+	if (has_either_or(opt->exclusive)) {
+	    n_keys++;
+	    len += strlen(opt->key) + 3; /* 3 for =, comma and space */
+	    G_debug(1, "check_exclusive():\t%s=", opt->key);
+	}
+	opt = opt->next_opt;
+    }
+
+    flag = &st->first_flag;
+    while (flag) {
+	if (has_either_or(flag->exclusive)) {
+	    n_keys++;
+	    len += 4; /* 4 for -, flag, comma and space */
+	    G_debug(1, "check_exclusive():\t-%c", flag->key);
+	}
+	flag = flag->next_flag;
+    }
+
+    if (n_keys > 0) {
+	int i;
+
+	for (i = 0; i < st->n_exclusive; i++) {
+	    if (st->exclusive[i].name[0] == '*')
+		break;
+	}
+
+	if (i == st->n_exclusive) {
+	    int n;
+	    char *err;
+
+	    err = G_malloc(len + 100);
+	    sprintf(err, _("One or more of the following options/flags "
+			   "must be used: "));
+	    
+	    n = 0;
+	    len = strlen(err);
+	    opt = &st->first_option;
+	    while (opt) {
+		if (has_either_or(opt->exclusive)) {
+		    n++;
+		    if (n <= n_keys - 2)
+			sprintf(err + len, "%s=, ", opt->key);
+		    else if (n == n_keys - 1)
+			sprintf(err + len, "%s= ", opt->key);
+		    else
+			sprintf(err + len, "or %s=", opt->key);
+		    len = strlen(err);
+		}
+		opt = opt->next_opt;
+	    }
+
+	    flag = &st->first_flag;
+	    while (flag) {
+		if (has_either_or(flag->exclusive)) {
+		    n++;
+		    if (n <= n_keys - 2)
+			sprintf(err + len, "-%c, ", flag->key);
+		    else if (n == n_keys - 1)
+			sprintf(err + len, "-%c ", flag->key);
+		    else
+			sprintf(err + len, "or -%c", flag->key);
+		    len = strlen(err);
+		}
+		flag = flag->next_flag;
+	    }
+	    
+	    append_error(err);
+	    G_free(err);
+	}
+    }
+}
+
 static void set_flag(int f)
 {
     struct Flag *flag;



More information about the grass-commit mailing list