[GRASS-SVN] r60707 - in grass/trunk: general/g.mlist general/g.mremove general/g.parser include lib/gis

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Jun 4 15:58:35 PDT 2014


Author: hcho
Date: 2014-06-04 15:58:35 -0700 (Wed, 04 Jun 2014)
New Revision: 60707

Modified:
   grass/trunk/general/g.mlist/main.c
   grass/trunk/general/g.mremove/main.c
   grass/trunk/general/g.parser/main.c
   grass/trunk/general/g.parser/parse.c
   grass/trunk/include/gis.h
   grass/trunk/lib/gis/parser.c
   grass/trunk/lib/gis/parser_local_proto.h
Log:
1. Added Option.exclusive and Flag.exclusive for supporting mutually exclusive groups.
2. G_parser() checks for mutually exclusive options/flags based on the exclusive string and stops if any found.
3. g.mlist and g.mremove for examples.
4. Doesn't support option values (e.g., g.mlist -p/-f and mapset=..)
5. Existing modules are not affected, but make distclean is required.
6. If exclusive is NULL (default) or "", no grouping is done and the exclusive check has to be done manually as before.

USAGE

C modules:

opt1 = G_define_option();
opt1->exclusive = "group1,group2";

opt2 = G_define_option();
opt2->exclusive = "group1";

flag1 = G_define_flag();
flag1->exclusive = "group2";

opt1 & opt2 are mutually exclusive because they are in group1.
opt1 & flag1 are mutually exclusive because they are in group2.

Python scripts:

#%option
#% key: opt1
#% exclusive: group1,group2
#%end
#%option
#% key: opt2
#% exclusive: group1
#%end
#%flag
#% key: f
#% exclusive: group2
#%end



Modified: grass/trunk/general/g.mlist/main.c
===================================================================
--- grass/trunk/general/g.mlist/main.c	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/general/g.mlist/main.c	2014-06-04 22:58:35 UTC (rev 60707)
@@ -101,23 +101,27 @@
     opt.output->required = NO;
     opt.output->label = _("Name for output file");
     opt.output->description = _("If not given or '-' then standard output");
+    opt.output->exclusive = "format";
 
     flag.regex = G_define_flag();
     flag.regex->key = 'r';
     flag.regex->description =
 	_("Use basic regular expressions instead of wildcards");
     flag.regex->guisection = _("Pattern");
+    flag.regex->exclusive = "regex";
 
     flag.extended = G_define_flag();
     flag.extended->key = 'e';
     flag.extended->description =
 	_("Use extended regular expressions instead of wildcards");
     flag.extended->guisection = _("Pattern");
+    flag.extended->exclusive = "regex";
 
     flag.type = G_define_flag();
     flag.type->key = 't';
     flag.type->description = _("Print data types");
     flag.type->guisection = _("Print");
+    flag.type->exclusive = "type";
     
     flag.mapset = G_define_flag();
     flag.mapset->key = 'm';
@@ -128,31 +132,17 @@
     flag.pretty->key = 'p';
     flag.pretty->description = _("Pretty printing in human readable format");
     flag.pretty->guisection = _("Print");
+    flag.pretty->exclusive = "format,type";
 
     flag.full = G_define_flag();
     flag.full->key = 'f';
     flag.full->description = _("Verbose listing (also list map titles)");
     flag.full->guisection = _("Print");
+    flag.full->exclusive = "format,type";
 
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
 
-    if ((flag.pretty->answer || flag.full->answer) && opt.output->answer)
-        G_fatal_error(_("-%c/-%c and %s= are mutually exclusive"),
-		      flag.pretty->key, flag.full->key, opt.output->key);
-
-    if ((flag.pretty->answer || flag.full->answer) && flag.type->answer)
-	G_fatal_error(_("-%c/-%c and -%c are mutually exclusive"),
-		      flag.pretty->key, flag.full->key, flag.type->key);
-
-    if (flag.pretty->answer && flag.full->answer)
-	G_fatal_error(_("-%c and -%c are mutually exclusive"),
-		      flag.pretty->key, flag.full->key);
-
-    if (flag.regex->answer && flag.extended->answer)
-	G_fatal_error(_("-%c and -%c are mutually exclusive"),
-		      flag.regex->key, flag.extended->key);
-
     if (opt.pattern->answer) {
 	if (flag.regex->answer || flag.extended->answer)
 	    filter = G_ls_regex_filter(opt.pattern->answer, 0,

Modified: grass/trunk/general/g.mremove/main.c
===================================================================
--- grass/trunk/general/g.mremove/main.c	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/general/g.mremove/main.c	2014-06-04 22:58:35 UTC (rev 60707)
@@ -68,11 +68,13 @@
     flag.regex->key = 'r';
     flag.regex->description =
 	_("Use basic regular expressions instead of wildcards");
+    flag.regex->exclusive = "regex";
 
     flag.extended = G_define_flag();
     flag.extended->key = 'e';
     flag.extended->description =
 	_("Use extended regular expressions instead of wildcards");
+    flag.extended->exclusive = "regex";
 
     flag.force = G_define_flag();
     flag.force->key = 'f';
@@ -95,10 +97,6 @@
     if (G_parser(argc, argv))
 	exit(EXIT_FAILURE);
 
-    if (flag.regex->answer && flag.extended->answer)
-	G_fatal_error(_("-%c and -%c are mutually exclusive"),
-		      flag.regex->key, flag.extended->key);
-
     if (!flag.force->answer)
 	G_message(_("The following data base element files would be deleted:"));
 

Modified: grass/trunk/general/g.parser/main.c
===================================================================
--- grass/trunk/general/g.parser/main.c	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/general/g.parser/main.c	2014-06-04 22:58:35 UTC (rev 60707)
@@ -7,9 +7,10 @@
  *               Cedric Shock <cedricgrass shockfamily.net>, 
  *               Hamish Bowman <hamish_b yahoo.com>, 
  *               Paul Kelly <paul-grass stjohnspoint.co.uk>, 
- *               Radim Blazek <radim.blazek gmail.com>
+ *               Radim Blazek <radim.blazek gmail.com>,
+ *               Huidae Cho <grass4u gmail.com>
  * PURPOSE:      
- * COPYRIGHT:    (C) 2001-2007, 2010-2011 by the GRASS Development Team
+ * COPYRIGHT:    (C) 2001-2007, 2010-2014 by the GRASS Development Team
  *
  *               This program is free software under the GNU General Public
  *               License (>=v2). Read the file COPYING that comes with GRASS

Modified: grass/trunk/general/g.parser/parse.c
===================================================================
--- grass/trunk/general/g.parser/parse.c	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/general/g.parser/parse.c	2014-06-04 22:58:35 UTC (rev 60707)
@@ -126,6 +126,11 @@
 	return;
     }
 
+    if (G_strcasecmp(cmd, "exclusive") == 0) {
+	ctx->flag->exclusive = xstrdup(arg);
+	return;
+    }
+
     if (G_strcasecmp(cmd, "end") == 0) {
 	ctx->state = S_TOPLEVEL;
 	return;
@@ -219,6 +224,11 @@
 	return;
     }
 
+    if (G_strcasecmp(cmd, "exclusive") == 0) {
+	ctx->option->exclusive = xstrdup(arg);
+	return;
+    }
+
     if (G_strcasecmp(cmd, "end") == 0) {
 	ctx->state = S_TOPLEVEL;
 	return;

Modified: grass/trunk/include/gis.h
===================================================================
--- grass/trunk/include/gis.h	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/include/gis.h	2014-06-04 22:58:35 UTC (rev 60707)
@@ -480,6 +480,7 @@
     int type;			/*!< Option type */
     int required;		/*!< REQUIRED or OPTIONAL */
     int multiple;		/*!< Multiple entries OK */
+    const char *exclusive;	/*!< Exclusive option/flag groups */
     const char *options;	/*!< Approved values or range or NULL */
     const char **opts;		/*!< NULL or NULL terminated array of parsed options */
     const char *key_desc;	/*!< one word describing the key */
@@ -508,6 +509,7 @@
     char key;			/*!< Key char used on command line */
     char answer;		/*!< Stores flag state: 0/1 */
     char suppress_required;	/*!< Suppresses checking of required options */
+    const char *exclusive;	/*!< Exclusive option/flag groups */
     const char *label;		/*!< Optional short label, used in GUI as item label */
     const char *description;	/*!< String describing flag meaning   */
     const char *guisection;	/*!< GUI Layout guidance: ';' delimited hierarchical tree position */

Modified: grass/trunk/lib/gis/parser.c
===================================================================
--- grass/trunk/lib/gis/parser.c	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/lib/gis/parser.c	2014-06-04 22:58:35 UTC (rev 60707)
@@ -64,7 +64,7 @@
  *    that the "map" option is required and also that the number 12 is
  *    out of range.  The acceptable range (or list) will be printed.
  *
- * (C) 2001-2009, 2011 by the GRASS Development Team
+ * (C) 2001-2009, 2011-2014 by the GRASS Development Team
  *
  * This program is free software under the GNU General Public License
  * (>=v2). Read the file COPYING that comes with GRASS for details.
@@ -113,8 +113,12 @@
 static void check_multiple_opts(void);
 static int check_overwrite(void);
 static void define_keywords(void);
-static void split_gisprompt(const char *gisprompt, char *age, char *element, char *desc);
+static void split_gisprompt(const char *, char *, char *, char *);
 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_key(struct Exclusive *, char *);
+static void check_exclusive(int);
 static void append_error(const char *);
 
 /*!
@@ -319,6 +323,11 @@
     G_basename(tmp_name, "exe");
     st->pgm_name = tmp_name;
 
+    st->allocated_exclusive = 10;
+    st->n_exclusive = 0;
+    st->exclusive = G_malloc(st->allocated_exclusive *
+		    	     sizeof(struct Exclusive));
+
     /* Stash default answers */
 
     opt = &st->first_option;
@@ -516,7 +525,6 @@
 	    else if (*ptr == '-') {
 		while (*(++ptr))
 		    set_flag(*ptr);
-
 	    }
 	    /* If we see standard option format (option=val) */
 	    else if (is_option(ptr)) {
@@ -529,6 +537,8 @@
 		st->first_option.answer = G_store(ptr);
 		st->first_option.count++;
 		need_first_opt = 0;
+		add_exclusive(st->first_option.key, 0,
+			      st->first_option.exclusive);
 	    }
 
 	    /* If we see the non valid argument (no "=", just argument) */
@@ -538,6 +548,8 @@
 	    }
 
 	}
+
+	check_exclusive(0);
     }
     
     /* Split options where multiple answers are OK */
@@ -810,6 +822,144 @@
     G_spawn(getenv("GRASS_PYTHON"), getenv("GRASS_PYTHON"), script, G_recreate_command(), NULL);
 }
 
+static void add_exclusive(const char *option_key, int flag_key,
+			  const char *names)
+{
+    char *keyname, *ptr1;
+
+    if (!names || !*names)
+	return;
+
+    if (option_key)
+	G_asprintf(&keyname, "%s=", option_key);
+    else
+	G_asprintf(&keyname, "-%c", flag_key);
+
+    for (ptr1 = (char *)names;;) {
+	int len;
+	char *ptr2;
+
+	for (len = 0, ptr2 = ptr1; *ptr2 != '\0' && *ptr2 != ',';
+	     ptr2++, len++) ;
+
+	if (len > 0) {	/* skip ,, */
+	    char *name;
+	    struct Exclusive *exclusive;
+
+	    name = G_malloc(len + 1);
+	    memcpy(name, ptr1, len);
+	    name[len] = 0;
+
+	    if (!(exclusive = find_exclusive(name))) {
+		exclusive = &st->exclusive[st->n_exclusive++];
+		exclusive->name = name;
+		exclusive->allocated_keys = 10;
+		exclusive->n_keys = 0;
+		exclusive->keys = G_malloc(exclusive->allocated_keys *
+					   sizeof(char *));
+
+		if (st->n_exclusive >= st->allocated_exclusive) {
+		    st->allocated_exclusive += 10;
+		    st->exclusive = G_realloc(st->exclusive,
+				    	      st->allocated_exclusive *
+					      sizeof(struct Exclusive));
+		    exclusive = find_exclusive(name);
+		}
+	    }
+
+	    if (!has_exclusive_key(exclusive, keyname)) {
+		exclusive->keys[exclusive->n_keys++] = keyname;
+
+		if (exclusive->n_keys >= exclusive->allocated_keys) {
+		    exclusive->allocated_keys += 10;
+		    exclusive->keys = G_realloc(exclusive->keys,
+				    		exclusive->allocated_keys *
+						sizeof(char *));
+		}
+	    }
+	}
+
+	if (*ptr2 == '\0')
+	    break;
+
+	ptr1 = ptr2 + 1;
+
+	if (*ptr1 == '\0')
+	    break;
+    }
+}
+
+static struct Exclusive *find_exclusive(char *name)
+{
+    int i;
+
+    for (i = 0; i < st->n_exclusive; i++) {
+	if (strcmp(st->exclusive[i].name, name) == 0)
+	    return &st->exclusive[i];
+    }
+
+    return NULL;
+}
+
+static int has_exclusive_key(struct Exclusive *exclusive, char *key)
+{
+    int i;
+
+    for (i = 0; i < exclusive->n_keys; i++) {
+	if (strcmp(exclusive->keys[i], key) == 0)
+	    return 1;
+    }
+
+    return 0;
+}
+
+static void check_exclusive(int print_group)
+{
+    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->n_keys >= 1)
+	    G_debug(1, "check_exclusive():\t%s", exclusive->keys[0]);
+
+	if (exclusive->n_keys > 1) {
+	    int len, j;
+	    char *err;
+
+	    len = strlen(exclusive->name);
+	    for (j = 0; j < exclusive->n_keys; j++) {
+		len += strlen(exclusive->keys[j]) + 2; /* 2 for comma space */
+		if (j > 0)
+		    G_debug(1, "check_exclusive():\t%s", exclusive->keys[j]);
+	    }
+
+	    err = G_malloc(len + 100);
+	    if (print_group)
+		sprintf(err, _("Options/flags in group '%s' are "
+			       "mutually exclusive: "), exclusive->name);
+	    else
+		sprintf(err, _("The following options/flags are "
+			       "mutually exclusive: "));
+
+	    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);
+	}
+    }
+}
+
 static void set_flag(int f)
 {
     struct Flag *flag;
@@ -831,6 +981,7 @@
 	    flag->answer = 1;
 	    if (flag->suppress_required)
 		st->suppress_required = 1;
+	    add_exclusive(NULL, f, flag->exclusive);
 	    return;
 	}
 	flag = flag->next_flag;
@@ -961,6 +1112,8 @@
     }
     else
 	opt->answer = G_store(string);
+
+    add_exclusive(opt->key, 0, opt->exclusive);
 }
 
 static void check_opts(void)

Modified: grass/trunk/lib/gis/parser_local_proto.h
===================================================================
--- grass/trunk/lib/gis/parser_local_proto.h	2014-06-04 19:08:34 UTC (rev 60706)
+++ grass/trunk/lib/gis/parser_local_proto.h	2014-06-04 22:58:35 UTC (rev 60707)
@@ -11,6 +11,13 @@
     struct Item *next_item;
 };
 
+struct Exclusive {
+    int allocated_keys;
+    int n_keys;
+    char *name;
+    char **keys;
+};
+
 struct state {
     int no_interactive;
     int n_opts;
@@ -33,6 +40,10 @@
     struct Option first_option;
     struct Option *current_option;
 
+    int allocated_exclusive;
+    int n_exclusive;
+    struct Exclusive *exclusive;
+
     struct Item first_item;
     struct Item *current_item;
     int n_items;



More information about the grass-commit mailing list