GRASS GIS 7 Programmer's Manual  7.0.3(2016)-r00000
parser_dependencies.c
Go to the documentation of this file.
1 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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:101
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