[GRASS-SVN] r62395 - in grass/branches/releasebranch_7_0: include include/defs lib/gis

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Oct 26 17:17:27 PDT 2014


Author: hcho
Date: 2014-10-26 17:17:27 -0700 (Sun, 26 Oct 2014)
New Revision: 62395

Added:
   grass/branches/releasebranch_7_0/lib/gis/parser_dependencies.c
Modified:
   grass/branches/releasebranch_7_0/include/defs/gis.h
   grass/branches/releasebranch_7_0/include/gis.h
Log:
Backport parser_dependencies.c from trunk

Modified: grass/branches/releasebranch_7_0/include/defs/gis.h
===================================================================
--- grass/branches/releasebranch_7_0/include/defs/gis.h	2014-10-26 23:53:27 UTC (rev 62394)
+++ grass/branches/releasebranch_7_0/include/defs/gis.h	2014-10-27 00:17:27 UTC (rev 62395)
@@ -513,6 +513,15 @@
 FILE *G_open_option_file(const struct Option *);
 void G_close_option_file(FILE *);
 
+/* parser_dependencies.c */
+void G__option_rule(int, int, void **);
+void G_option_exclusive(void *, ...);
+void G_option_required(void *, ...);
+void G_option_requires(void *, ...);
+void G_option_requires_all(void *, ...);
+void G_option_excludes(void *, ...);
+void G_option_collective(void *, ...);
+
 /* paths.c */
 int G_mkdir(const char *);
 int G_is_dirsep(char);

Modified: grass/branches/releasebranch_7_0/include/gis.h
===================================================================
--- grass/branches/releasebranch_7_0/include/gis.h	2014-10-26 23:53:27 UTC (rev 62394)
+++ grass/branches/releasebranch_7_0/include/gis.h	2014-10-27 00:17:27 UTC (rev 62395)
@@ -305,6 +305,16 @@
     G_FLG_V_TOPO,               /*!< do not build topology */
 } STD_FLG;
 
+/* Parser rules for G__option_rule() */
+enum rule_type {
+    RULE_EXCLUSIVE,
+    RULE_REQUIRED,
+    RULE_REQUIRES,
+    RULE_REQUIRES_ALL,
+    RULE_EXCLUDES,
+    RULE_COLLECTIVE
+};
+
 /* Message format */
 #define G_INFO_FORMAT_STANDARD 0	/* GRASS_MESSAGE_FORMAT=standard or not defined */
 #define G_INFO_FORMAT_GUI      1	/* GRASS_MESSAGE_FORMAT=gui */

Added: grass/branches/releasebranch_7_0/lib/gis/parser_dependencies.c
===================================================================
--- grass/branches/releasebranch_7_0/lib/gis/parser_dependencies.c	                        (rev 0)
+++ grass/branches/releasebranch_7_0/lib/gis/parser_dependencies.c	2014-10-27 00:17:27 UTC (rev 62395)
@@ -0,0 +1,410 @@
+/*!
+  \file lib/gis/parser_dependencies.c
+  
+  \brief GIS Library - Argument parsing functions (dependencies between options)
+  
+  (C) 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.
+  
+  \author Glynn Clements Jun. 2014
+*/
+
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <grass/gis.h>
+#include <grass/glocale.h>
+
+#include "parser_local_proto.h"
+
+struct vector {
+    size_t elsize;
+    size_t increment;
+    size_t count;
+    size_t limit;
+    void *data;
+};
+
+static void vector_new(struct vector *v, size_t elsize, size_t increment)
+{
+    v->elsize = elsize;
+    v->increment = increment;
+    v->count = 0;
+    v->limit = 0;
+    v->data = NULL;
+}
+
+static void vector_append(struct vector *v, const void *data)
+{
+    void *p;
+
+    if (v->count >= v->limit) {
+	v->limit += v->increment;
+	v->data = G_realloc(v->data, v->limit * v->elsize);
+    }
+
+    p = G_incr_void_ptr(v->data, v->count * v->elsize);
+    memcpy(p, data, v->elsize);
+    v->count++;
+}
+
+struct rule {
+    int type;
+    int count;
+    void **opts;
+};
+
+static struct vector rules = {sizeof(struct rule), 50};
+
+void G__option_rule(int type, int nopts, void **opts)
+{
+    struct rule rule;
+
+    rule.type = type;
+    rule.count = nopts;
+    rule.opts = opts;
+
+    vector_append(&rules, &rule);
+}
+
+static void make_rule(int type, void *first, va_list ap)
+{
+    struct vector opts;
+    void *opt;
+
+    vector_new(&opts, sizeof(void *), 10);
+
+    opt = first;
+    vector_append(&opts, &opt);
+    for (;;) {
+	opt = va_arg(ap, void*);
+	if (!opt)
+	    break;
+	vector_append(&opts, &opt);
+    }
+
+    G__option_rule(type, opts.count, (void**) opts.data);
+}
+
+static int is_flag(const void *p)
+{
+    if (st->n_flags) {
+	const struct Flag *flag;
+	for (flag = &st->first_flag; flag; flag = flag->next_flag)
+	    if ((const void *) flag == p)
+		return 1;
+    }
+
+    if (st->n_opts) {
+	const struct Option *opt;
+	for (opt = &st->first_option; opt; opt = opt->next_opt)
+	    if ((const void *) opt == p)
+		return 0;
+    }
+
+    G_fatal_error(_("Internal error: option or flag not found"));
+}
+
+static int is_present(const void *p)
+{
+    if (is_flag(p)) {
+	const struct Flag *flag = p;
+	return (int) flag->answer;
+    }
+    else {
+	const struct Option *opt = p;
+	return opt->count > 0;
+    }
+}
+
+static char *get_name(const void *p)
+{
+    if (is_flag(p)) {
+	char *s;
+	G_asprintf(&s, "-%c", ((const struct Flag *) p)->key);
+	return s;
+    }
+    else
+	return G_store(((const struct Option *) p)->key);
+}
+
+static int count_present(const struct rule *rule, int start)
+{
+    int i;
+    int count = 0;
+
+    for (i = start; i < rule->count; i++)
+	if (is_present(rule->opts[i]))
+	    count++;
+
+    return count;
+}
+
+static const char *describe_rule(const struct rule *rule, int start,
+				 int disjunction)
+{
+    char *s = get_name(rule->opts[start]);
+    int i;
+
+    for (i = start + 1; i < rule->count - 1; i++) {
+	char *s0 = s;
+	char *ss = get_name(rule->opts[i]);
+	s = NULL;
+	G_asprintf(&s, "%s, %s", s0, ss);
+	G_free(s0);
+	G_free(ss);
+    }
+
+    if (rule->count - start > 1) {
+	char *s0 = s;
+	char *ss = get_name(rule->opts[i]);
+	s = NULL;
+	G_asprintf(&s, disjunction ? _("%s or %s") : _("%s and %s"), s0, ss);
+	G_free(s0);
+	G_free(ss);
+    }
+
+    return s;
+}
+
+static void append_error(const char *msg)
+{
+    st->error = G_realloc(st->error, sizeof(char *) * (st->n_errors + 1));
+    st->error[st->n_errors++] = G_store(msg);
+}
+
+/*! \brief Sets the options to be mutually exclusive.
+
+    When running the module, at most one option from a set can be
+    provided.
+*/
+void G_option_exclusive(void *first, ...)
+{
+    va_list ap;
+    va_start(ap, first);
+    make_rule(RULE_EXCLUSIVE, first, ap);
+    va_end(ap);
+}
+
+static void check_exclusive(const struct rule *rule)
+{
+    if (count_present(rule, 0) > 1) {
+	char *err;
+	G_asprintf(&err, _("Options %s are mutually exclusive"),
+		   describe_rule(rule, 0, 0));
+	append_error(err);
+    }
+}
+
+/* at least one option from a set */
+void G_option_required(void *first, ...)
+{
+    va_list ap;
+    va_start(ap, first);
+    make_rule(RULE_REQUIRED, first, ap);
+    va_end(ap);
+}
+
+static void check_required(const struct rule *rule)
+{
+    if (count_present(rule, 0) < 1) {
+	char *err;
+	G_asprintf(&err, _("At least one of %s is required"),
+		   describe_rule(rule, 0, 0));
+	append_error(err);
+    }
+}
+
+/*! \brief Define a list of options from which at least one option
+    is required if first option is present.
+
+    If the first option is present, at least one of the other
+    options must also be present.
+
+    If you want all options to be provided use G_option_requires_all()
+    function.
+    If you want more than one option to be present but not all,
+    call this function multiple times.
+*/
+void G_option_requires(void *first, ...)
+{
+    va_list ap;
+    va_start(ap, first);
+    make_rule(RULE_REQUIRES, first, ap);
+    va_end(ap);
+}
+
+static void check_requires(const struct rule *rule)
+{
+    if (!is_present(rule->opts[0]))
+	return;
+    if (count_present(rule, 1) < 1) {
+	char *err;
+	G_asprintf(&err, _("Option %s requires at least one of %s"),
+		   get_name(rule->opts[0]), describe_rule(rule, 1, 1));
+	append_error(err);
+    }
+}
+
+/*! \brief Define additionally required options for an option.
+
+    If the first option is present, all the other options must also
+    be present.
+
+    If it is enough if only one option from a set is present,
+    use G_option_requires() function.
+
+    \see G_option_collective()
+*/
+void G_option_requires_all(void *first, ...)
+{
+    va_list ap;
+    va_start(ap, first);
+    make_rule(RULE_REQUIRES_ALL, first, ap);
+    va_end(ap);
+}
+
+static void check_requires_all(const struct rule *rule)
+{
+    if (!is_present(rule->opts[0]))
+	return;
+    if (count_present(rule, 1) < rule->count - 1) {
+	char *err;
+	G_asprintf(&err, _("Option %s requires all of %s"),
+		   get_name(rule->opts[0]), describe_rule(rule, 1, 0));
+	append_error(err);
+    }
+}
+
+/* if the first option is present, none of the other options may also (should?)
+   be present. */
+void G_option_excludes(void *first, ...)
+{
+    va_list ap;
+    va_start(ap, first);
+    make_rule(RULE_EXCLUDES, first, ap);
+    va_end(ap);
+}
+
+static void check_excludes(const struct rule *rule)
+{
+    if (!is_present(rule->opts[0]))
+	return;
+    if (count_present(rule, 1) > 0) {
+	char *err;
+	G_asprintf(&err, _("Option %s is mutually exclusive with all of %s"),
+		   get_name(rule->opts[0]), describe_rule(rule, 1, 0));
+	append_error(err);
+    }
+}
+
+/* if any option is present, all the other options must also be present
+   all or nothing from a set */
+void G_option_collective(void *first, ...)
+{
+    va_list ap;
+    va_start(ap, first);
+    make_rule(RULE_COLLECTIVE, first, ap);
+    va_end(ap);
+}
+
+static void check_collective(const struct rule *rule)
+{
+    int count = count_present(rule, 0);
+    if (count > 0 && count < rule->count) {
+	char *err;
+	G_asprintf(&err, _("Either all or none of %s must be given"),
+		   describe_rule(rule, 0, 0));
+	append_error(err);
+    }
+}
+
+void G__check_option_rules(void)
+{
+    int i;
+
+    for (i = 0; i < rules.count; i++) {
+	const struct rule *rule = &((const struct rule *) rules.data)[i];
+	switch (rule->type) {
+	case RULE_EXCLUSIVE:
+	    check_exclusive(rule);
+	    break;
+	case RULE_REQUIRED:
+	    check_required(rule);
+	    break;
+	case RULE_REQUIRES:
+	    check_requires(rule);
+	    break;
+	case RULE_REQUIRES_ALL:
+	    check_requires_all(rule);
+	    break;
+	case RULE_EXCLUDES:
+	    check_excludes(rule);
+	    break;
+	case RULE_COLLECTIVE:
+	    check_collective(rule);
+	    break;
+	default:
+	    G_fatal_error(_("Internal error: invalid rule type: %d"),
+			  rule->type);
+	    break;
+	}
+    }
+}
+
+void G__describe_option_rules(void)
+{
+    int i;
+
+    for (i = 0; i < rules.count; i++) {
+	const struct rule *rule = &((const struct rule *) rules.data)[i];
+	switch (rule->type) {
+	case RULE_EXCLUSIVE:
+	    fprintf(stderr, "Exclusive: %s", describe_rule(rule, 0, 0));
+	    break;
+	case RULE_REQUIRED:
+	    fprintf(stderr, "Required: %s", describe_rule(rule, 0, 1));
+	    break;
+	case RULE_REQUIRES:
+	    fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
+		    describe_rule(rule, 1, 1));
+	    break;
+	case RULE_REQUIRES_ALL:
+	    fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
+		    describe_rule(rule, 1, 0));
+	    break;
+	case RULE_EXCLUDES:
+	    fprintf(stderr, "Excludes: %s => %s", get_name(rule->opts[0]),
+		    describe_rule(rule, 1, 0));
+	    break;
+	case RULE_COLLECTIVE:
+	    fprintf(stderr, "Collective: %s", describe_rule(rule, 0, 0));
+	    break;
+	default:
+	    G_fatal_error(_("Internal error: invalid rule type: %d"),
+			  rule->type);
+	    break;
+	}
+    }
+}
+
+/*!
+   \brief Checks if there is any rule RULE_REQUIRED.
+
+   \return 1 if there is such rule
+   \return 0 if not
+ */
+int G__has_required_rule(void)
+{
+    size_t i;
+
+    for (i = 0; i < rules.count; i++) {
+	const struct rule *rule = &((const struct rule *) rules.data)[i];
+	if (rule->type == RULE_REQUIRED)
+	    return TRUE;
+    }
+    return FALSE;
+}



More information about the grass-commit mailing list