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