[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