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

Anna Petrášová kratochanna at gmail.com
Thu Jun 5 20:03:52 PDT 2014


Hi,

nice work! I was just trying it and I found a small error, see below

On Thu, Jun 5, 2014 at 1:32 PM, <svn_grass at osgeo.org> wrote:

> 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";
>

It seems that the * is needed for both parameters (opt1 and opt2). When I
have two types of inputs and one of them is required (exactly one) and I
put * only to one of them (and they are in one group), I get this when I
don't specify any of them in the command line:

ERROR: One or more of the following options/flags must be used: or input2=

instead of

ERROR: One or more of the following options/flags must be used: input1= or
input2=


> 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;
>
> _______________________________________________
> grass-commit mailing list
> grass-commit at lists.osgeo.org
> http://lists.osgeo.org/mailman/listinfo/grass-commit
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/grass-dev/attachments/20140605/139bd69a/attachment-0001.html>


More information about the grass-dev mailing list