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
vector_new(struct vector * v,size_t elsize,size_t increment)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
vector_append(struct vector * v,const void * data)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 */
G_option_rule(int type,int nopts,void ** opts)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
make_rule(int type,void * first,va_list ap)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
is_flag(const void * p)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
is_present(const void * p)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
get_name(const void * p)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
count_present(const struct rule * rule,int start)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
describe_rule(const struct rule * rule,int start,int disjunction)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
append_error(const char * msg)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 */
G_option_exclusive(void * first,...)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
check_exclusive(const struct rule * rule)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 */
G_option_required(void * first,...)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
check_required(const struct rule * rule)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 */
G_option_requires(void * first,...)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
check_requires(const struct rule * rule)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 */
G_option_requires_all(void * first,...)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
check_requires_all(const struct rule * rule)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 */
G_option_excludes(void * first,...)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
check_excludes(const struct rule * rule)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 */
G_option_collective(void * first,...)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
check_collective(const struct rule * rule)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) */
G__check_option_rules(void)365 void G__check_option_rules(void)
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) */
G__describe_option_rules(void)399 void G__describe_option_rules(void)
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 */
G__has_required_rule(void)441 int G__has_required_rule(void)
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 */
G__describe_option_rules_xml(FILE * fp)466 void G__describe_option_rules_xml(FILE *fp)
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
493