4
0

argmatch.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /* argmatch.c -- find a match for a string in an array
  2. Copyright (C) 1990, 1998, 1999 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software Foundation,
  13. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  14. /* Written by David MacKenzie <[email protected]>
  15. Modified by Akim Demaille <[email protected]> */
  16. #include "argmatch.h"
  17. #include <stdio.h>
  18. #ifdef STDC_HEADERS
  19. # include <string.h>
  20. #endif
  21. #if HAVE_LOCALE_H
  22. # include <locale.h>
  23. #endif
  24. #if ENABLE_NLS
  25. # include <libintl.h>
  26. # define _(Text) gettext (Text)
  27. #else
  28. # define _(Text) Text
  29. #endif
  30. #include "error.h"
  31. #include "quotearg.h"
  32. /* When reporting an invalid argument, show nonprinting characters
  33. by using the quoting style ARGMATCH_QUOTING_STYLE. Do not use
  34. literal_quoting_style. */
  35. #ifndef ARGMATCH_QUOTING_STYLE
  36. # define ARGMATCH_QUOTING_STYLE escape_quoting_style
  37. #endif
  38. /* The following test is to work around the gross typo in
  39. systems like Sony NEWS-OS Release 4.0C, whereby EXIT_FAILURE
  40. is defined to 0, not 1. */
  41. #if !EXIT_FAILURE
  42. # undef EXIT_FAILURE
  43. # define EXIT_FAILURE 1
  44. #endif
  45. /* Non failing version of argmatch call this function after failing. */
  46. #ifndef ARGMATCH_DIE
  47. # define ARGMATCH_DIE exit (EXIT_FAILURE)
  48. #endif
  49. #ifdef ARGMATCH_DIE_DECL
  50. ARGMATCH_DIE_DECL;
  51. #endif
  52. static void
  53. __argmatch_die (void)
  54. {
  55. ARGMATCH_DIE;
  56. }
  57. /* Used by XARGMATCH and XARGCASEMATCH. See description in argmatch.h.
  58. Default to __argmatch_die, but allow caller to change this at run-time. */
  59. argmatch_exit_fn argmatch_die = __argmatch_die;
  60. /* If ARG is an unambiguous match for an element of the
  61. null-terminated array ARGLIST, return the index in ARGLIST
  62. of the matched element, else -1 if it does not match any element
  63. or -2 if it is ambiguous (is a prefix of more than one element).
  64. If SENSITIVE, comparison is case sensitive.
  65. If VALLIST is none null, use it to resolve ambiguities limited to
  66. synonyms, i.e., for
  67. "yes", "yop" -> 0
  68. "no", "nope" -> 1
  69. "y" is a valid argument, for `0', and "n" for `1'. */
  70. static int
  71. __argmatch_internal (const char *arg, const char *const *arglist,
  72. const char *vallist, size_t valsize,
  73. int case_sensitive)
  74. {
  75. int i; /* Temporary index in ARGLIST. */
  76. size_t arglen; /* Length of ARG. */
  77. int matchind = -1; /* Index of first nonexact match. */
  78. int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
  79. arglen = strlen (arg);
  80. /* Test all elements for either exact match or abbreviated matches. */
  81. for (i = 0; arglist[i]; i++)
  82. {
  83. if (case_sensitive
  84. ? !strncmp (arglist[i], arg, arglen)
  85. : !strncasecmp (arglist[i], arg, arglen))
  86. {
  87. if (strlen (arglist[i]) == arglen)
  88. /* Exact match found. */
  89. return i;
  90. else if (matchind == -1)
  91. /* First nonexact match found. */
  92. matchind = i;
  93. else
  94. {
  95. /* Second nonexact match found. */
  96. if (vallist == NULL
  97. || memcmp (vallist + valsize * matchind,
  98. vallist + valsize * i, valsize))
  99. {
  100. /* There is a real ambiguity, or we could not
  101. disambiguate. */
  102. ambiguous = 1;
  103. }
  104. }
  105. }
  106. }
  107. if (ambiguous)
  108. return -2;
  109. else
  110. return matchind;
  111. }
  112. /* argmatch - case sensitive version */
  113. int
  114. argmatch (const char *arg, const char *const *arglist,
  115. const char *vallist, size_t valsize)
  116. {
  117. return __argmatch_internal (arg, arglist, vallist, valsize, 1);
  118. }
  119. /* argcasematch - case insensitive version */
  120. int
  121. argcasematch (const char *arg, const char *const *arglist,
  122. const char *vallist, size_t valsize)
  123. {
  124. return __argmatch_internal (arg, arglist, vallist, valsize, 0);
  125. }
  126. /* Error reporting for argmatch.
  127. CONTEXT is a description of the type of entity that was being matched.
  128. VALUE is the invalid value that was given.
  129. PROBLEM is the return value from argmatch. */
  130. void
  131. argmatch_invalid (const char *context, const char *value, int problem)
  132. {
  133. enum quoting_style saved_quoting_style;
  134. char const *format;
  135. /* Make sure to have a good quoting style to report errors.
  136. literal is insane here. */
  137. saved_quoting_style = get_quoting_style (NULL);
  138. set_quoting_style (NULL, ARGMATCH_QUOTING_STYLE);
  139. format = (problem == -1
  140. ? _("invalid argument `%s' for `%s'")
  141. : _("ambiguous argument `%s' for `%s'"));
  142. error (0, 0, format, quotearg (value), context);
  143. set_quoting_style (NULL, saved_quoting_style);
  144. }
  145. /* List the valid arguments for argmatch.
  146. ARGLIST is the same as in argmatch.
  147. VALLIST is a pointer to an array of values.
  148. VALSIZE is the size of the elements of VALLIST */
  149. void
  150. argmatch_valid (const char *const *arglist,
  151. const char *vallist, size_t valsize)
  152. {
  153. int i;
  154. const char *last_val = NULL;
  155. /* We try to put synonyms on the same line. The assumption is that
  156. synonyms follow each other */
  157. fprintf (stderr, _("Valid arguments are:"));
  158. for (i = 0; arglist[i]; i++)
  159. if ((i == 0)
  160. || memcmp (last_val, vallist + valsize * i, valsize))
  161. {
  162. fprintf (stderr, "\n - `%s'", arglist[i]);
  163. last_val = vallist + valsize * i;
  164. }
  165. else
  166. {
  167. fprintf (stderr, ", `%s'", arglist[i]);
  168. }
  169. putc ('\n', stderr);
  170. }
  171. /* Never failing versions of the previous functions.
  172. CONTEXT is the context for which argmatch is called (e.g.,
  173. "--version-control", or "$VERSION_CONTROL" etc.). Upon failure,
  174. calls the (supposed never to return) function EXIT_FN. */
  175. int
  176. __xargmatch_internal (const char *context,
  177. const char *arg, const char *const *arglist,
  178. const char *vallist, size_t valsize,
  179. int case_sensitive,
  180. argmatch_exit_fn exit_fn)
  181. {
  182. int res = __argmatch_internal (arg, arglist,
  183. vallist, valsize,
  184. case_sensitive);
  185. if (res >= 0)
  186. /* Success. */
  187. return res;
  188. /* We failed. Explain why. */
  189. argmatch_invalid (context, arg, res);
  190. argmatch_valid (arglist, vallist, valsize);
  191. (*exit_fn) ();
  192. return -1; /* To please the compilers. */
  193. }
  194. /* Look for VALUE in VALLIST, an array of objects of size VALSIZE and
  195. return the first corresponding argument in ARGLIST */
  196. const char *
  197. argmatch_to_argument (const char *value,
  198. const char *const *arglist,
  199. const char *vallist, size_t valsize)
  200. {
  201. int i;
  202. for (i = 0; arglist[i]; i++)
  203. if (!memcmp (value, vallist + valsize * i, valsize))
  204. return arglist[i];
  205. return NULL;
  206. }
  207. #ifdef TEST
  208. /*
  209. * Based on "getversion.c" by David MacKenzie <[email protected]>
  210. */
  211. char *program_name;
  212. extern const char *getenv ();
  213. /* When to make backup files. */
  214. enum backup_type
  215. {
  216. /* Never make backups. */
  217. none,
  218. /* Make simple backups of every file. */
  219. simple,
  220. /* Make numbered backups of files that already have numbered backups,
  221. and simple backups of the others. */
  222. numbered_existing,
  223. /* Make numbered backups of every file. */
  224. numbered
  225. };
  226. /* Two tables describing arguments (keys) and their corresponding
  227. values */
  228. static const char *const backup_args[] =
  229. {
  230. "no", "none", "off",
  231. "simple", "never",
  232. "existing", "nil",
  233. "numbered", "t",
  234. 0
  235. };
  236. static const enum backup_type backup_vals[] =
  237. {
  238. none, none, none,
  239. simple, simple,
  240. numbered_existing, numbered_existing,
  241. numbered, numbered
  242. };
  243. int
  244. main (int argc, const char *const *argv)
  245. {
  246. const char *cp;
  247. enum backup_type backup_type = none;
  248. program_name = (char *) argv[0];
  249. if (argc > 2)
  250. {
  251. fprintf (stderr, "Usage: %s [VERSION_CONTROL]\n", program_name);
  252. exit (1);
  253. }
  254. if ((cp = getenv ("VERSION_CONTROL")))
  255. backup_type = XARGCASEMATCH ("$VERSION_CONTROL", cp,
  256. backup_args, backup_vals);
  257. if (argc == 2)
  258. backup_type = XARGCASEMATCH (program_name, argv[1],
  259. backup_args, backup_vals);
  260. printf ("The version control is `%s'\n",
  261. ARGMATCH_TO_ARGUMENT (backup_type, backup_args, backup_vals));
  262. return 0;
  263. }
  264. #endif