20#include <grass/glocale.h>
22#include "parser_local_proto.h"
32static void vector_new(
struct vector *v,
size_t elsize,
size_t increment)
35 v->increment = increment;
41static void vector_append(
struct vector *v,
const void *data)
45 if (v->count >= v->limit) {
46 v->limit += v->increment;
47 v->data = G_realloc(v->data, v->limit * v->elsize);
51 memcpy(p, data, v->elsize);
61static struct vector rules = {.elsize =
sizeof(
struct rule), .increment = 50};
85 vector_append(&rules, &rule);
88static void make_rule(
int type,
void *first, va_list ap)
93 vector_new(&opts,
sizeof(
void *), 10);
96 vector_append(&opts, &opt);
98 opt = va_arg(ap,
void *);
102 vector_append(&opts, &opt);
108static int is_flag(
const void *p)
111 const struct Flag *flag;
113 for (flag = &st->first_flag; flag; flag = flag->next_flag)
114 if ((
const void *)flag == p)
119 const struct Option *opt;
121 for (opt = &st->first_option; opt; opt = opt->next_opt)
122 if ((
const void *)opt == p)
126 G_fatal_error(_(
"Internal error: option or flag not found"));
129static int is_present(
const void *p)
132 const struct Flag *flag = p;
134 return (
int)flag->answer;
137 const struct Option *opt = p;
139 return opt->count > 0;
143static char *get_name(
const void *p)
148 G_asprintf(&s,
"-%c", ((
const struct Flag *)p)->key);
152 return G_store(((
const struct Option *)p)->key);
155static int count_present(
const struct rule *rule,
int start)
160 for (i = start; i < rule->count; i++)
161 if (is_present(rule->opts[i]))
167static const char *describe_rule(
const struct rule *rule,
int start,
173 G_asprintf(&s,
"<%s>", get_name(rule->opts[start]));
175 for (i = start + 1; i < rule->count - 1; i++) {
177 char *ss = get_name(rule->opts[i]);
185 if (rule->count - start > 1) {
187 char *ss = get_name(rule->opts[i]);
190 G_asprintf(&s, disjunction ? _(
"%s or <%s>") : _(
"%s and <%s>"), s0,
199static void append_error(
const char *msg)
201 st->error = G_realloc(st->error,
sizeof(
char *) * (st->n_errors + 1));
202 st->error[st->n_errors++] =
G_store(msg);
219 make_rule(RULE_EXCLUSIVE, first, ap);
223static void check_exclusive(
const struct rule *rule)
225 if (count_present(rule, 0) > 1) {
229 describe_rule(rule, 0, 0));
247 make_rule(RULE_REQUIRED, first, ap);
251static void check_required(
const struct rule *rule)
253 if (count_present(rule, 0) < 1) {
257 _(
"At least one of the following options is required: %s"),
258 describe_rule(rule, 0, 0));
283 make_rule(RULE_REQUIRES, first, ap);
287static void check_requires(
const struct rule *rule)
289 if (!is_present(rule->opts[0]))
291 if (count_present(rule, 1) < 1) {
295 G_asprintf(&
err, _(
"Option <%s> requires at least one of %s"),
296 get_name(rule->opts[0]), describe_rule(rule, 1, 1));
299 get_name(rule->opts[0]), describe_rule(rule, 1, 1));
323 make_rule(RULE_REQUIRES_ALL, first, ap);
327static void check_requires_all(
const struct rule *rule)
329 if (!is_present(rule->opts[0]))
331 if (count_present(rule, 1) < rule->count - 1) {
335 get_name(rule->opts[0]), describe_rule(rule, 1, 0));
354 make_rule(RULE_EXCLUDES, first, ap);
358static void check_excludes(
const struct rule *rule)
360 if (!is_present(rule->opts[0]))
362 if (count_present(rule, 1) > 0) {
365 G_asprintf(&
err, _(
"Option <%s> is mutually exclusive with all of %s"),
366 get_name(rule->opts[0]), describe_rule(rule, 1, 0));
385 make_rule(RULE_COLLECTIVE, first, ap);
389static void check_collective(
const struct rule *rule)
391 int count = count_present(rule, 0);
396 G_asprintf(&
err, _(
"Either all or none of %s must be given"),
397 describe_rule(rule, 0, 0));
407 for (i = 0; i < rules.count; i++) {
408 const struct rule *rule = &((
const struct rule *)rules.data)[i];
410 switch (rule->type) {
412 check_exclusive(rule);
415 check_required(rule);
418 check_requires(rule);
420 case RULE_REQUIRES_ALL:
421 check_requires_all(rule);
424 check_excludes(rule);
426 case RULE_COLLECTIVE:
427 check_collective(rule);
442 for (i = 0; i < rules.count; i++) {
443 const struct rule *rule = &((
const struct rule *)rules.data)[i];
445 switch (rule->type) {
447 fprintf(stderr,
"Exclusive: %s", describe_rule(rule, 0, 0));
450 fprintf(stderr,
"Required: %s", describe_rule(rule, 0, 1));
453 fprintf(stderr,
"Requires: %s => %s", get_name(rule->opts[0]),
454 describe_rule(rule, 1, 1));
456 case RULE_REQUIRES_ALL:
457 fprintf(stderr,
"Requires: %s => %s", get_name(rule->opts[0]),
458 describe_rule(rule, 1, 0));
461 fprintf(stderr,
"Excludes: %s => %s", get_name(rule->opts[0]),
462 describe_rule(rule, 1, 0));
464 case RULE_COLLECTIVE:
465 fprintf(stderr,
"Collective: %s", describe_rule(rule, 0, 0));
485 for (i = 0; i < rules.count; i++) {
486 const struct rule *rule = &((
const struct rule *)rules.data)[i];
488 if (rule->type == RULE_REQUIRED)
494static const char *
const rule_types[] = {
"exclusive",
"required",
495 "requires",
"requires-all",
496 "excludes",
"collective"};
509 fprintf(fp,
"\t<rules>\n");
510 for (i = 0; i < rules.count; i++) {
511 const struct rule *rule = &((
const struct rule *)rules.data)[i];
514 G_fatal_error(_(
"Internal error: the number of options is < 0"));
516 fprintf(fp,
"\t\t<rule type=\"%s\">\n", rule_types[rule->type]);
517 for (j = 0; j < (
unsigned int)rule->count; j++) {
518 void *p = rule->opts[j];
521 const struct Flag *flag = (
const struct Flag *)p;
523 fprintf(fp,
"\t\t\t<rule-flag key=\"%c\"/>\n", flag->key);
526 const struct Option *opt = (
const struct Option *)p;
528 fprintf(fp,
"\t\t\t<rule-option key=\"%s\"/>\n", opt->key);
531 fprintf(fp,
"\t\t</rule>\n");
533 fprintf(fp,
"\t</rules>\n");
void * G_incr_void_ptr(const void *ptr, size_t size)
Advance void pointer.
void G_free(void *buf)
Free allocated memory.
int G_asprintf(char **out, const char *fmt,...)
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
void G__check_option_rules(void)
Check for option rules (internal use only)
void G_option_rule(int type, int nopts, void **opts)
Set generic option rule.
void G_option_collective(void *first,...)
Sets the options to be collective.
int G__has_required_rule(void)
Checks if there is any rule RULE_REQUIRED (internal use only).
void G__describe_option_rules(void)
Describe option rules (stderr)
void G_option_requires_all(void *first,...)
Define additionally required options for an option.
void G_option_excludes(void *first,...)
Exclude selected options.
void G_option_exclusive(void *first,...)
Sets the options to be mutually exclusive.
void G__describe_option_rules_xml(FILE *fp)
Describe option rules in XML format (internal use only)
void G_option_required(void *first,...)
Sets the options to be required.
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 * G_store(const char *s)
Copy string to allocated memory.
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)