parser_dependencies.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*!
  2. \file lib/gis/parser_dependencies.c
  3. \brief GIS Library - Argument parsing functions (dependencies between options)
  4. (C) 2014 by the GRASS Development Team
  5. This program is free software under the GNU General Public License
  6. (>=v2). Read the file COPYING that comes with GRASS for details.
  7. \author Glynn Clements Jun. 2014
  8. */
  9. #include <stdarg.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <grass/gis.h>
  13. #include <grass/glocale.h>
  14. #include "parser_local_proto.h"
  15. enum rule_type {
  16. RULE_EXCLUSIVE,
  17. RULE_REQUIRED,
  18. RULE_REQUIRES,
  19. RULE_REQUIRES_ALL,
  20. RULE_EXCLUDES,
  21. RULE_COLLECTIVE
  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. static void vector_new(struct vector *v, size_t elsize, size_t increment)
  31. {
  32. v->elsize = elsize;
  33. v->increment = increment;
  34. v->count = 0;
  35. v->limit = 0;
  36. v->data = NULL;
  37. }
  38. static void vector_append(struct vector *v, const void *data)
  39. {
  40. void *p;
  41. if (v->count >= v->limit) {
  42. v->limit += v->increment;
  43. v->data = G_realloc(v->data, v->limit * v->elsize);
  44. }
  45. p = G_incr_void_ptr(v->data, v->count * v->elsize);
  46. memcpy(p, data, v->elsize);
  47. v->count++;
  48. }
  49. struct rule {
  50. int type;
  51. int count;
  52. void **opts;
  53. };
  54. static struct vector rules = {sizeof(struct rule), 50};
  55. static void make_rule(int type, void *first, va_list ap)
  56. {
  57. struct vector opts;
  58. void *opt;
  59. struct rule rule;
  60. vector_new(&opts, sizeof(void *), 10);
  61. opt = first;
  62. vector_append(&opts, &opt);
  63. for (;;) {
  64. opt = va_arg(ap, void*);
  65. if (!opt)
  66. break;
  67. vector_append(&opts, &opt);
  68. }
  69. rule.type = type;
  70. rule.count = opts.count;
  71. rule.opts = (void**) opts.data;
  72. vector_append(&rules, &rule);
  73. }
  74. static int is_flag(const void *p)
  75. {
  76. if (st->n_flags) {
  77. const struct Flag *flag;
  78. for (flag = &st->first_flag; flag; flag = flag->next_flag)
  79. if ((const void *) flag == p)
  80. return 1;
  81. }
  82. if (st->n_opts) {
  83. const struct Option *opt;
  84. for (opt = &st->first_option; opt; opt = opt->next_opt)
  85. if ((const void *) opt == p)
  86. return 0;
  87. }
  88. G_fatal_error(_("Internal error: option or flag not found"));
  89. }
  90. static int is_present(const void *p)
  91. {
  92. if (is_flag(p)) {
  93. const struct Flag *flag = p;
  94. return (int) flag->answer;
  95. }
  96. else {
  97. const struct Option *opt = p;
  98. return opt->count > 0;
  99. }
  100. }
  101. static char *get_name(const void *p)
  102. {
  103. if (is_flag(p)) {
  104. char *s;
  105. G_asprintf(&s, "-%c", ((const struct Flag *) p)->key);
  106. return s;
  107. }
  108. else
  109. return G_store(((const struct Option *) p)->key);
  110. }
  111. static int count_present(const struct rule *rule, int start)
  112. {
  113. int i;
  114. int count = 0;
  115. for (i = start; i < rule->count; i++)
  116. if (is_present(rule->opts[i]))
  117. count++;
  118. return count;
  119. }
  120. static const char *describe_rule(const struct rule *rule, int start,
  121. int disjunction)
  122. {
  123. char *s = get_name(rule->opts[start]);
  124. int i;
  125. for (i = start + 1; i < rule->count - 1; i++) {
  126. char *s0 = s;
  127. char *ss = get_name(rule->opts[i]);
  128. s = NULL;
  129. G_asprintf(&s, "%s, %s", s0, ss);
  130. G_free(s0);
  131. G_free(ss);
  132. }
  133. if (rule->count - start > 1) {
  134. char *s0 = s;
  135. char *ss = get_name(rule->opts[i]);
  136. s = NULL;
  137. G_asprintf(&s, disjunction ? _("%s or %s") : _("%s and %s"), s0, ss);
  138. G_free(s0);
  139. G_free(ss);
  140. }
  141. return s;
  142. }
  143. static void append_error(const char *msg)
  144. {
  145. st->error = G_realloc(st->error, sizeof(char *) * (st->n_errors + 1));
  146. st->error[st->n_errors++] = G_store(msg);
  147. }
  148. /* at most one option from a set */
  149. void G_option_exclusive(void *first, ...)
  150. {
  151. va_list ap;
  152. va_start(ap, first);
  153. make_rule(RULE_EXCLUSIVE, first, ap);
  154. va_end(ap);
  155. }
  156. static void check_exclusive(const struct rule *rule)
  157. {
  158. if (count_present(rule, 0) > 1) {
  159. char *err;
  160. G_asprintf(&err, _("Options %s are mutually exclusive"),
  161. describe_rule(rule, 0, 0));
  162. append_error(err);
  163. }
  164. }
  165. /* at least one option from a set */
  166. void G_option_required(void *first, ...)
  167. {
  168. va_list ap;
  169. va_start(ap, first);
  170. make_rule(RULE_REQUIRED, first, ap);
  171. va_end(ap);
  172. }
  173. static void check_required(const struct rule *rule)
  174. {
  175. if (count_present(rule, 0) < 1) {
  176. char *err;
  177. G_asprintf(&err, _("At least one of %s is required"),
  178. describe_rule(rule, 0, 0));
  179. append_error(err);
  180. }
  181. }
  182. /* if the first option is present, at least one of the other
  183. options must also be present */
  184. void G_option_requires(void *first, ...)
  185. {
  186. va_list ap;
  187. va_start(ap, first);
  188. make_rule(RULE_REQUIRES, first, ap);
  189. va_end(ap);
  190. }
  191. static void check_requires(const struct rule *rule)
  192. {
  193. if (!is_present(rule->opts[0]))
  194. return;
  195. if (count_present(rule, 1) < 1) {
  196. char *err;
  197. G_asprintf(&err, _("Option %s requires at least one of %s"),
  198. get_name(rule->opts[0]), describe_rule(rule, 1, 1));
  199. append_error(err);
  200. }
  201. }
  202. /* if the first option is present, all the other options must also
  203. be present. */
  204. void G_option_requires_all(void *first, ...)
  205. {
  206. va_list ap;
  207. va_start(ap, first);
  208. make_rule(RULE_REQUIRES_ALL, first, ap);
  209. va_end(ap);
  210. }
  211. static void check_requires_all(const struct rule *rule)
  212. {
  213. if (!is_present(rule->opts[0]))
  214. return;
  215. if (count_present(rule, 1) < rule->count - 1) {
  216. char *err;
  217. G_asprintf(&err, _("Option %s requires all of %s"),
  218. get_name(rule->opts[0]), describe_rule(rule, 1, 0));
  219. append_error(err);
  220. }
  221. }
  222. /* if the first option is present, none of the other options may also
  223. be present. */
  224. void G_option_excludes(void *first, ...)
  225. {
  226. va_list ap;
  227. va_start(ap, first);
  228. make_rule(RULE_EXCLUDES, first, ap);
  229. va_end(ap);
  230. }
  231. static void check_excludes(const struct rule *rule)
  232. {
  233. if (!is_present(rule->opts[0]))
  234. return;
  235. if (count_present(rule, 1) > 0) {
  236. char *err;
  237. G_asprintf(&err, _("Option %s is mutually exclusive with all of %s"),
  238. get_name(rule->opts[0]), describe_rule(rule, 1, 0));
  239. append_error(err);
  240. }
  241. }
  242. /* if any option is present, all the other options must also be present
  243. all or nothing from a set */
  244. void G_option_collective(void *first, ...)
  245. {
  246. va_list ap;
  247. va_start(ap, first);
  248. make_rule(RULE_COLLECTIVE, first, ap);
  249. va_end(ap);
  250. }
  251. static void check_collective(const struct rule *rule)
  252. {
  253. int count = count_present(rule, 0);
  254. if (count > 0 && count < rule->count) {
  255. char *err;
  256. G_asprintf(&err, _("Either all or none of %s must be given"),
  257. describe_rule(rule, 0, 0));
  258. append_error(err);
  259. }
  260. }
  261. void G__check_option_rules(void)
  262. {
  263. int i;
  264. for (i = 0; i < rules.count; i++) {
  265. const struct rule *rule = &((const struct rule *) rules.data)[i];
  266. switch (rule->type) {
  267. case RULE_EXCLUSIVE:
  268. check_exclusive(rule);
  269. break;
  270. case RULE_REQUIRED:
  271. check_required(rule);
  272. break;
  273. case RULE_REQUIRES:
  274. check_requires(rule);
  275. break;
  276. case RULE_REQUIRES_ALL:
  277. check_requires_all(rule);
  278. break;
  279. case RULE_EXCLUDES:
  280. check_excludes(rule);
  281. break;
  282. case RULE_COLLECTIVE:
  283. check_collective(rule);
  284. break;
  285. default:
  286. G_fatal_error(_("Internal error: invalid rule type: %d"),
  287. rule->type);
  288. break;
  289. }
  290. }
  291. }
  292. void G__describe_option_rules(void)
  293. {
  294. int i;
  295. for (i = 0; i < rules.count; i++) {
  296. const struct rule *rule = &((const struct rule *) rules.data)[i];
  297. switch (rule->type) {
  298. case RULE_EXCLUSIVE:
  299. fprintf(stderr, "Exclusive: %s", describe_rule(rule, 0, 0));
  300. break;
  301. case RULE_REQUIRED:
  302. fprintf(stderr, "Required: %s", describe_rule(rule, 0, 1));
  303. break;
  304. case RULE_REQUIRES:
  305. fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
  306. describe_rule(rule, 1, 1));
  307. break;
  308. case RULE_REQUIRES_ALL:
  309. fprintf(stderr, "Requires: %s => %s", get_name(rule->opts[0]),
  310. describe_rule(rule, 1, 0));
  311. break;
  312. case RULE_EXCLUDES:
  313. fprintf(stderr, "Excludes: %s => %s", get_name(rule->opts[0]),
  314. describe_rule(rule, 1, 0));
  315. break;
  316. case RULE_COLLECTIVE:
  317. fprintf(stderr, "Collective: %s", describe_rule(rule, 0, 0));
  318. break;
  319. default:
  320. G_fatal_error(_("Internal error: invalid rule type: %d"),
  321. rule->type);
  322. break;
  323. }
  324. }
  325. }