浏览代码

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



git-svn-id: https://svn.osgeo.org/grass/grass/trunk@60707 15284696-431f-4ddb-bdfa-cd5b030d7da7

Huidae Cho 11 年之前
父节点
当前提交
01ec3512d2
共有 7 个文件被更改,包括 190 次插入25 次删除
  1. 6 16
      general/g.mlist/main.c
  2. 2 4
      general/g.mremove/main.c
  3. 3 2
      general/g.parser/main.c
  4. 10 0
      general/g.parser/parse.c
  5. 2 0
      include/gis.h
  6. 156 3
      lib/gis/parser.c
  7. 11 0
      lib/gis/parser_local_proto.h

+ 6 - 16
general/g.mlist/main.c

@@ -101,23 +101,27 @@ int main(int argc, char *argv[])
     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 @@ int main(int argc, char *argv[])
     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,

+ 2 - 4
general/g.mremove/main.c

@@ -68,11 +68,13 @@ int main(int argc, char *argv[])
     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 @@ int main(int argc, char *argv[])
     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:"));
 

+ 3 - 2
general/g.parser/main.c

@@ -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

+ 10 - 0
general/g.parser/parse.c

@@ -126,6 +126,11 @@ void parse_flag(struct context *ctx, const char *cmd, const char *arg)
 	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 @@ void parse_option(struct context *ctx, const char *cmd, const char *arg)
 	return;
     }
 
+    if (G_strcasecmp(cmd, "exclusive") == 0) {
+	ctx->option->exclusive = xstrdup(arg);
+	return;
+    }
+
     if (G_strcasecmp(cmd, "end") == 0) {
 	ctx->state = S_TOPLEVEL;
 	return;

+ 2 - 0
include/gis.h

@@ -480,6 +480,7 @@ struct Option
     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 @@ struct Flag
     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 */

+ 156 - 3
lib/gis/parser.c

@@ -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 split_opts(void);
 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 @@ int G_parser(int argc, char **argv)
     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 @@ int G_parser(int argc, char **argv)
 	    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 @@ int G_parser(int argc, char **argv)
 		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 @@ int G_parser(int argc, char **argv)
 	    }
 
 	}
+
+	check_exclusive(0);
     }
     
     /* Split options where multiple answers are OK */
@@ -810,6 +822,144 @@ static void module_gui_wx(void)
     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 @@ static void set_flag(int f)
 	    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 @@ static void set_option(const char *string)
     }
     else
 	opt->answer = G_store(string);
+
+    add_exclusive(opt->key, 0, opt->exclusive);
 }
 
 static void check_opts(void)

+ 11 - 0
lib/gis/parser_local_proto.h

@@ -11,6 +11,13 @@ struct Item
     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 state {
     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;