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

Huidae Cho grass4u at gmail.com
Fri Jun 6 06:35:00 PDT 2014


Anna,

I think your code looks like:

opt1->exclusive = "+1,*";
opt2->exclusive = "+1";
opt3->exclusive = "+2,";
opt4->exclusive = "+2";

1. opt1->required has to be YES if you have only one *.
2. the message "or input1" has to be fixed to "input1"
3. but, if you use input1 only, you'll get a message "must be used
together: input1 and input2"
4. if you add * to opt2, the message will say "input1 or input2", not
"input1 and input2"

So even if you get the "or input1" message, you still have to use input1
and input2. It's the message that can be misleading (?). One solution would
be to find all tied options and print them together in the message above in
step 2.

Anyway, you don't have to worry about it anymore because this code has been
reverted by Glynn. Losing hours of work is not fun.

Thanks.
Huidae





On Thu, Jun 5, 2014 at 11:03 PM, Anna Petrášová <kratochanna at gmail.com>
wrote:

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


More information about the grass-dev mailing list