GRASS GIS 7 Programmer's Manual  7.2.2(2017)-exported
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  G_asprintf(&err, _("Option %s requires at least one of %s"),
270  get_name(rule->opts[0]), describe_rule(rule, 1, 1));
271  append_error(err);
272  }
273 }
274 
275 /*! \brief Define additionally required options for an option.
276 
277  If the first option is present, all the other options must also
278  be present.
279 
280  If it is enough if only one option from a set is present,
281  use G_option_requires() function.
282 
283  \see G_option_collective()
284 
285  \param first first given option
286 */
287 void G_option_requires_all(void *first, ...)
288 {
289  va_list ap;
290  va_start(ap, first);
291  make_rule(RULE_REQUIRES_ALL, first, ap);
292  va_end(ap);
293 }
294 
295 static void check_requires_all(const struct rule *rule)
296 {
297  if (!is_present(rule->opts[0]))
298  return;
299  if (count_present(rule, 1) < rule->count - 1) {
300  char *err;
301  G_asprintf(&err, _("Option %s requires all of %s"),
302  get_name(rule->opts[0]), describe_rule(rule, 1, 0));
303  append_error(err);
304  }
305 }
306 
307 /*! \brief Exclude selected options.
308 
309  If the first option is present, none of the other options may also (should?)
310  be present.
311 
312  \param first first given option
313 */
314 void G_option_excludes(void *first, ...)
315 {
316  va_list ap;
317  va_start(ap, first);
318  make_rule(RULE_EXCLUDES, first, ap);
319  va_end(ap);
320 }
321 
322 static void check_excludes(const struct rule *rule)
323 {
324  if (!is_present(rule->opts[0]))
325  return;
326  if (count_present(rule, 1) > 0) {
327  char *err;
328  G_asprintf(&err, _("Option %s is mutually exclusive with all of %s"),
329  get_name(rule->opts[0]), describe_rule(rule, 1, 0));
330  append_error(err);
331  }
332 }
333 
334 /*! \brief Sets the options to be collective.
335 
336  If any option is present, all the other options must also be present
337  all or nothing from a set.
338 
339  \param first first given option
340 */
341 void G_option_collective(void *first, ...)
342 {
343  va_list ap;
344  va_start(ap, first);
345  make_rule(RULE_COLLECTIVE, first, ap);
346  va_end(ap);
347 }
348 
349 static void check_collective(const struct rule *rule)
350 {
351  int count = count_present(rule, 0);
352  if (count > 0 && count < rule->count) {
353  char *err;
354  G_asprintf(&err, _("Either all or none of %s must be given"),
355  describe_rule(rule, 0, 0));
356  append_error(err);
357  }
358 }
359 
360 /*! \brief Check for option rules (internal use only) */
362 {
363  unsigned int i;
364 
365  for (i = 0; i < rules.count; i++) {
366  const struct rule *rule = &((const struct rule *) rules.data)[i];
367  switch (rule->type) {
368  case RULE_EXCLUSIVE:
369  check_exclusive(rule);
370  break;
371  case RULE_REQUIRED:
372  check_required(rule);
373  break;
374  case RULE_REQUIRES:
375  check_requires(rule);
376  break;
377  case RULE_REQUIRES_ALL:
378  check_requires_all(rule);
379  break;
380  case RULE_EXCLUDES:
381  check_excludes(rule);
382  break;
383  case RULE_COLLECTIVE:
384  check_collective(rule);
385  break;
386  default:
387  G_fatal_error(_("Internal error: invalid rule type: %d"),
388  rule->type);
389  break;
390  }
391  }
392 }
393 
394 /*! \brief Describe option rules (stderr) */
396 {
397  unsigned int i;
398 
399  for (i = 0; i < rules.count; i++) {
400  const struct rule *rule = &((const struct rule *) rules.data)[i];
401  switch (rule->type) {
402  case RULE_EXCLUSIVE:
403  fprintf(stderr, "Exclusive: %s", describe_rule(rule, 0, 0));
404  break;
405  case RULE_REQUIRED:
406  fprintf(stderr, "Required: %s", describe_rule(rule, 0, 1));
407  break;
408  case RULE_REQUIRES:
409  fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
410  describe_rule(rule, 1, 1));
411  break;
412  case RULE_REQUIRES_ALL:
413  fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
414  describe_rule(rule, 1, 0));
415  break;
416  case RULE_EXCLUDES:
417  fprintf(stderr, "Excludes: %s => %s", get_name(rule->opts[0]),
418  describe_rule(rule, 1, 0));
419  break;
420  case RULE_COLLECTIVE:
421  fprintf(stderr, "Collective: %s", describe_rule(rule, 0, 0));
422  break;
423  default:
424  G_fatal_error(_("Internal error: invalid rule type: %d"),
425  rule->type);
426  break;
427  }
428  }
429 }
430 
431 /*!
432  \brief Checks if there is any rule RULE_REQUIRED (internal use only).
433 
434  \return 1 if there is such rule
435  \return 0 if not
436  */
438 {
439  size_t i;
440 
441  for (i = 0; i < rules.count; i++) {
442  const struct rule *rule = &((const struct rule *) rules.data)[i];
443  if (rule->type == RULE_REQUIRED)
444  return TRUE;
445  }
446  return FALSE;
447 }
448 
449 static const char * const rule_types[] = {
450  "exclusive",
451  "required",
452  "requires",
453  "requires-all",
454  "excludes",
455  "collective"
456 };
457 
458 /*! \brief Describe option rules in XML format (internal use only)
459 
460  \param fp file where to print XML info
461 */
463 {
464  unsigned int i, j;
465 
466  if (!rules.count)
467  return;
468 
469  fprintf(fp, "\t<rules>\n");
470  for (i = 0; i < rules.count; i++) {
471  const struct rule *rule = &((const struct rule *) rules.data)[i];
472  fprintf(fp, "\t\t<rule type=\"%s\">\n", rule_types[rule->type]);
473  for (j = 0; j < rule->count; j++) {
474  void *p = rule->opts[j];
475  if (is_flag(p)) {
476  const struct Flag *flag = (const struct Flag *) p;
477  fprintf(fp, "\t\t\t<rule-flag key=\"%c\"/>\n", flag->key);
478  }
479  else {
480  const struct Option *opt = (const struct Option *) p;
481  fprintf(fp, "\t\t\t<rule-option key=\"%s\"/>\n", opt->key);
482  }
483  }
484  fprintf(fp, "\t\t</rule>\n");
485  }
486  fprintf(fp, "\t</rules>\n");
487 }
488 
int G__has_required_rule(void)
Checks if there is any rule RULE_REQUIRED (internal use only).
#define FALSE
Definition: dbfopen.c:117
void G_option_required(void *first,...)
Sets the options to be required.
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 TRUE
Definition: dbfopen.c:118
void G_option_requires(void *first,...)
Define a list of options from which at least one option is required if first option is present...
void G_option_exclusive(void *first,...)
Sets the options to be mutually exclusive.
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_option_collective(void *first,...)
Sets the options to be collective.
void * G_incr_void_ptr(const void *ptr, size_t size)
Advance void pointer.
Definition: alloc.c:186
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149