GRASS GIS 7 Programmer's Manual  7.5.svn(2018)-r72090
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parser_dependencies.c
Go to the documentation of this file.
1 /*!
2  \file lib/gis/parser_dependencies.c
3 
4  \brief GIS Library - Argument parsing functions (dependencies between options)
5 
6  (C) 2014-2015 by the GRASS Development Team
7 
8  This program is free software under the GNU General Public License
9  (>=v2). Read the file COPYING that comes with GRASS for details.
10 
11  \author Glynn Clements Jun. 2014
12 */
13 
14 #include <stdarg.h>
15 #include <string.h>
16 #include <stdio.h>
17 
18 #include <grass/gis.h>
19 #include <grass/glocale.h>
20 
21 #include "parser_local_proto.h"
22 
23 struct vector {
24  size_t elsize;
25  size_t increment;
26  size_t count;
27  size_t limit;
28  void *data;
29 };
30 
31 static void vector_new(struct vector *v, size_t elsize, size_t increment)
32 {
33  v->elsize = elsize;
34  v->increment = increment;
35  v->count = 0;
36  v->limit = 0;
37  v->data = NULL;
38 }
39 
40 static void vector_append(struct vector *v, const void *data)
41 {
42  void *p;
43 
44  if (v->count >= v->limit) {
45  v->limit += v->increment;
46  v->data = G_realloc(v->data, v->limit * v->elsize);
47  }
48 
49  p = G_incr_void_ptr(v->data, v->count * v->elsize);
50  memcpy(p, data, v->elsize);
51  v->count++;
52 }
53 
54 struct rule {
55  int type;
56  int count;
57  void **opts;
58 };
59 
60 static struct vector rules = {sizeof(struct rule), 50};
61 
62 /*! \brief Set generic option rule
63 
64  Supported rule types:
65  - RULE_EXCLUSIVE
66  - RULE_REQUIRED
67  - RULE_REQUIRES
68  - RULE_REQUIRES_ALL
69  - RULE_EXCLUDES
70  - RULE_COLLECTIVE
71 
72  \param type rule type
73  \param nopts number of options in the array
74  \param opts array of options
75 */
76 void G_option_rule(int type, int nopts, void **opts)
77 {
78  struct rule rule;
79 
80  rule.type = type;
81  rule.count = nopts;
82  rule.opts = opts;
83 
84  vector_append(&rules, &rule);
85 }
86 
87 static void make_rule(int type, void *first, va_list ap)
88 {
89  struct vector opts;
90  void *opt;
91 
92  vector_new(&opts, sizeof(void *), 10);
93 
94  opt = first;
95  vector_append(&opts, &opt);
96  for (;;) {
97  opt = va_arg(ap, void*);
98  if (!opt)
99  break;
100  vector_append(&opts, &opt);
101  }
102 
103  G_option_rule(type, opts.count, (void**) opts.data);
104 }
105 
106 static int is_flag(const void *p)
107 {
108  if (st->n_flags) {
109  const struct Flag *flag;
110  for (flag = &st->first_flag; flag; flag = flag->next_flag)
111  if ((const void *) flag == p)
112  return 1;
113  }
114 
115  if (st->n_opts) {
116  const struct Option *opt;
117  for (opt = &st->first_option; opt; opt = opt->next_opt)
118  if ((const void *) opt == p)
119  return 0;
120  }
121 
122  G_fatal_error(_("Internal error: option or flag not found"));
123 }
124 
125 static int is_present(const void *p)
126 {
127  if (is_flag(p)) {
128  const struct Flag *flag = p;
129  return (int) flag->answer;
130  }
131  else {
132  const struct Option *opt = p;
133  return opt->count > 0;
134  }
135 }
136 
137 static char *get_name(const void *p)
138 {
139  if (is_flag(p)) {
140  char *s;
141  G_asprintf(&s, "-%c", ((const struct Flag *) p)->key);
142  return s;
143  }
144  else
145  return G_store(((const struct Option *) p)->key);
146 }
147 
148 static int count_present(const struct rule *rule, int start)
149 {
150  int i;
151  int count = 0;
152 
153  for (i = start; i < rule->count; i++)
154  if (is_present(rule->opts[i]))
155  count++;
156 
157  return count;
158 }
159 
160 static const char *describe_rule(const struct rule *rule, int start,
161  int disjunction)
162 {
163  char *s = get_name(rule->opts[start]);
164  int i;
165 
166  for (i = start + 1; i < rule->count - 1; i++) {
167  char *s0 = s;
168  char *ss = get_name(rule->opts[i]);
169  s = NULL;
170  G_asprintf(&s, "%s>, <%s", s0, ss);
171  G_free(s0);
172  G_free(ss);
173  }
174 
175  if (rule->count - start > 1) {
176  char *s0 = s;
177  char *ss = get_name(rule->opts[i]);
178  s = NULL;
179  G_asprintf(&s, disjunction ? _("<%s> or <%s>") : _("<%s> and <%s>"), s0, ss);
180  G_free(s0);
181  G_free(ss);
182  }
183 
184  return s;
185 }
186 
187 static void append_error(const char *msg)
188 {
189  st->error = G_realloc(st->error, sizeof(char *) * (st->n_errors + 1));
190  st->error[st->n_errors++] = G_store(msg);
191 }
192 
193 /*! \brief Sets the options to be mutually exclusive.
194 
195  When running the module, at most one option from a set can be
196  provided.
197 
198  \param first first given option
199 */
200 void G_option_exclusive(void *first, ...)
201 {
202  va_list ap;
203  va_start(ap, first);
204  make_rule(RULE_EXCLUSIVE, first, ap);
205  va_end(ap);
206 }
207 
208 static void check_exclusive(const struct rule *rule)
209 {
210  if (count_present(rule, 0) > 1) {
211  char *err;
212  G_asprintf(&err, _("Options %s are mutually exclusive"),
213  describe_rule(rule, 0, 0));
214  append_error(err);
215  }
216 }
217 
218 /*! \brief Sets the options to be required.
219 
220  At least one option from a set must be given.
221 
222  \param first first given option
223 */
224 void G_option_required(void *first, ...)
225 {
226  va_list ap;
227  va_start(ap, first);
228  make_rule(RULE_REQUIRED, first, ap);
229  va_end(ap);
230 }
231 
232 static void check_required(const struct rule *rule)
233 {
234  if (count_present(rule, 0) < 1) {
235  char *err;
236  G_asprintf(&err, _("At least one of the following options is required: %s"),
237  describe_rule(rule, 0, 0));
238  append_error(err);
239  }
240 }
241 
242 /*! \brief Define a list of options from which at least one option
243  is required if first option is present.
244 
245  If the first option is present, at least one of the other
246  options must also be present.
247 
248  If you want all options to be provided use G_option_requires_all()
249  function.
250  If you want more than one option to be present but not all,
251  call this function multiple times.
252 
253  \param first first given option
254 */
255 void G_option_requires(void *first, ...)
256 {
257  va_list ap;
258  va_start(ap, first);
259  make_rule(RULE_REQUIRES, first, ap);
260  va_end(ap);
261 }
262 
263 static void check_requires(const struct rule *rule)
264 {
265  if (!is_present(rule->opts[0]))
266  return;
267  if (count_present(rule, 1) < 1) {
268  char *err;
269  if (rule->count > 2)
270  G_asprintf(&err, _("Option <%s> requires at least one of %s"),
271  get_name(rule->opts[0]), describe_rule(rule, 1, 1));
272  else
273  G_asprintf(&err, _("Option <%s> requires <%s>"),
274  get_name(rule->opts[0]), describe_rule(rule, 1, 1));
275  append_error(err);
276  }
277 }
278 
279 /*! \brief Define additionally required options for an option.
280 
281  If the first option is present, all the other options must also
282  be present.
283 
284  If it is enough if only one option from a set is present,
285  use G_option_requires() function.
286 
287  \see G_option_collective()
288 
289  \param first first given option
290 */
291 void G_option_requires_all(void *first, ...)
292 {
293  va_list ap;
294  va_start(ap, first);
295  make_rule(RULE_REQUIRES_ALL, first, ap);
296  va_end(ap);
297 }
298 
299 static void check_requires_all(const struct rule *rule)
300 {
301  if (!is_present(rule->opts[0]))
302  return;
303  if (count_present(rule, 1) < rule->count - 1) {
304  char *err;
305  G_asprintf(&err, _("Option %s requires all of %s"),
306  get_name(rule->opts[0]), describe_rule(rule, 1, 0));
307  append_error(err);
308  }
309 }
310 
311 /*! \brief Exclude selected options.
312 
313  If the first option is present, none of the other options may also (should?)
314  be present.
315 
316  \param first first given option
317 */
318 void G_option_excludes(void *first, ...)
319 {
320  va_list ap;
321  va_start(ap, first);
322  make_rule(RULE_EXCLUDES, first, ap);
323  va_end(ap);
324 }
325 
326 static void check_excludes(const struct rule *rule)
327 {
328  if (!is_present(rule->opts[0]))
329  return;
330  if (count_present(rule, 1) > 0) {
331  char *err;
332  G_asprintf(&err, _("Option %s is mutually exclusive with all of %s"),
333  get_name(rule->opts[0]), describe_rule(rule, 1, 0));
334  append_error(err);
335  }
336 }
337 
338 /*! \brief Sets the options to be collective.
339 
340  If any option is present, all the other options must also be present
341  all or nothing from a set.
342 
343  \param first first given option
344 */
345 void G_option_collective(void *first, ...)
346 {
347  va_list ap;
348  va_start(ap, first);
349  make_rule(RULE_COLLECTIVE, first, ap);
350  va_end(ap);
351 }
352 
353 static void check_collective(const struct rule *rule)
354 {
355  int count = count_present(rule, 0);
356  if (count > 0 && count < rule->count) {
357  char *err;
358  G_asprintf(&err, _("Either all or none of %s must be given"),
359  describe_rule(rule, 0, 0));
360  append_error(err);
361  }
362 }
363 
364 /*! \brief Check for option rules (internal use only) */
366 {
367  unsigned int i;
368 
369  for (i = 0; i < rules.count; i++) {
370  const struct rule *rule = &((const struct rule *) rules.data)[i];
371  switch (rule->type) {
372  case RULE_EXCLUSIVE:
373  check_exclusive(rule);
374  break;
375  case RULE_REQUIRED:
376  check_required(rule);
377  break;
378  case RULE_REQUIRES:
379  check_requires(rule);
380  break;
381  case RULE_REQUIRES_ALL:
382  check_requires_all(rule);
383  break;
384  case RULE_EXCLUDES:
385  check_excludes(rule);
386  break;
387  case RULE_COLLECTIVE:
388  check_collective(rule);
389  break;
390  default:
391  G_fatal_error(_("Internal error: invalid rule type: %d"),
392  rule->type);
393  break;
394  }
395  }
396 }
397 
398 /*! \brief Describe option rules (stderr) */
400 {
401  unsigned int i;
402 
403  for (i = 0; i < rules.count; i++) {
404  const struct rule *rule = &((const struct rule *) rules.data)[i];
405  switch (rule->type) {
406  case RULE_EXCLUSIVE:
407  fprintf(stderr, "Exclusive: %s", describe_rule(rule, 0, 0));
408  break;
409  case RULE_REQUIRED:
410  fprintf(stderr, "Required: %s", describe_rule(rule, 0, 1));
411  break;
412  case RULE_REQUIRES:
413  fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
414  describe_rule(rule, 1, 1));
415  break;
416  case RULE_REQUIRES_ALL:
417  fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
418  describe_rule(rule, 1, 0));
419  break;
420  case RULE_EXCLUDES:
421  fprintf(stderr, "Excludes: %s => %s", get_name(rule->opts[0]),
422  describe_rule(rule, 1, 0));
423  break;
424  case RULE_COLLECTIVE:
425  fprintf(stderr, "Collective: %s", describe_rule(rule, 0, 0));
426  break;
427  default:
428  G_fatal_error(_("Internal error: invalid rule type: %d"),
429  rule->type);
430  break;
431  }
432  }
433 }
434 
435 /*!
436  \brief Checks if there is any rule RULE_REQUIRED (internal use only).
437 
438  \return 1 if there is such rule
439  \return 0 if not
440  */
442 {
443  size_t i;
444 
445  for (i = 0; i < rules.count; i++) {
446  const struct rule *rule = &((const struct rule *) rules.data)[i];
447  if (rule->type == RULE_REQUIRED)
448  return TRUE;
449  }
450  return FALSE;
451 }
452 
453 static const char * const rule_types[] = {
454  "exclusive",
455  "required",
456  "requires",
457  "requires-all",
458  "excludes",
459  "collective"
460 };
461 
462 /*! \brief Describe option rules in XML format (internal use only)
463 
464  \param fp file where to print XML info
465 */
467 {
468  unsigned int i, j;
469 
470  if (!rules.count)
471  return;
472 
473  fprintf(fp, "\t<rules>\n");
474  for (i = 0; i < rules.count; i++) {
475  const struct rule *rule = &((const struct rule *) rules.data)[i];
476  fprintf(fp, "\t\t<rule type=\"%s\">\n", rule_types[rule->type]);
477  for (j = 0; j < rule->count; j++) {
478  void *p = rule->opts[j];
479  if (is_flag(p)) {
480  const struct Flag *flag = (const struct Flag *) p;
481  fprintf(fp, "\t\t\t<rule-flag key=\"%c\"/>\n", flag->key);
482  }
483  else {
484  const struct Option *opt = (const struct Option *) p;
485  fprintf(fp, "\t\t\t<rule-option key=\"%s\"/>\n", opt->key);
486  }
487  }
488  fprintf(fp, "\t\t</rule>\n");
489  }
490  fprintf(fp, "\t</rules>\n");
491 }
492 
#define TRUE
Definition: gis.h:49
int G__has_required_rule(void)
Checks if there is any rule RULE_REQUIRED (internal use only).
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:149
int count
Definition: gis.h:530
void G_option_required(void *first,...)
Sets the options to be required.
char answer
Definition: gis.h:541
int count
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:86
void G__check_option_rules(void)
Check for option rules (internal use only)
int G_asprintf(char **out, const char *fmt,...)
Definition: asprintf.c:70
#define NULL
Definition: ccmath.h:32
void G_option_excludes(void *first,...)
Exclude selected options.
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:159
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
struct state * st
Definition: parser.c:103
void G_option_rule(int type, int nopts, void **opts)
Set generic option rule.
#define FALSE
Definition: gis.h:53
Structure that stores flag info.
Definition: gis.h:538
void G_option_requires(void *first,...)
Define a list of options from which at least one option is required if first option is present...
char key
Definition: gis.h:540
void G_option_exclusive(void *first,...)
Sets the options to be mutually exclusive.
struct Flag * next_flag
Definition: gis.h:547
void G__describe_option_rules(void)
Describe option rules (stderr)
void G__describe_option_rules_xml(FILE *fp)
Describe option rules in XML format (internal use only)
void G_option_requires_all(void *first,...)
Define additionally required options for an option.
void * G_incr_void_ptr(const void *ptr, size_t size)
Advance void pointer.
Definition: gis/alloc.c:186
Structure that stores option information.
Definition: gis.h:509
#define _(str)
Definition: glocale.h:13
const char * key
Definition: gis.h:511
void G_option_collective(void *first,...)
Sets the options to be collective.
struct Option * next_opt
Definition: gis.h:525