PageRenderTime 34ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/rpmatch.c

https://github.com/rofl0r/gnulib
C | 173 lines | 92 code | 19 blank | 62 comment | 36 complexity | 36d2fe633ce854b14f03fd23ff9cd9f4 MD5 | raw file
  1. /* Determine whether string value is affirmation or negative response
  2. according to current locale's data.
  3. Copyright (C) 1996, 1998, 2000, 2002-2003, 2006-2011 Free Software
  4. Foundation, Inc.
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. #include <config.h>
  16. /* Specification. */
  17. #include <stdlib.h>
  18. #include <stdbool.h>
  19. #include <stddef.h>
  20. #if ENABLE_NLS
  21. # include <sys/types.h>
  22. # include <limits.h>
  23. # include <string.h>
  24. # if HAVE_LANGINFO_YESEXPR
  25. # include <langinfo.h>
  26. # endif
  27. # include <regex.h>
  28. # include "gettext.h"
  29. # define _(msgid) gettext (msgid)
  30. # define N_(msgid) gettext_noop (msgid)
  31. # if HAVE_LANGINFO_YESEXPR
  32. /* Return the localized regular expression pattern corresponding to
  33. ENGLISH_PATTERN. NL_INDEX can be used with nl_langinfo.
  34. The resulting string may only be used until the next nl_langinfo call. */
  35. static const char *
  36. localized_pattern (const char *english_pattern, nl_item nl_index,
  37. bool posixly_correct)
  38. {
  39. const char *translated_pattern;
  40. /* We prefer to get the patterns from a PO file. It would be possible to
  41. always use nl_langinfo (YESEXPR) instead of _("^[yY]"), and
  42. nl_langinfo (NOEXPR) instead of _("^[nN]"), if we could assume that the
  43. system's locale support is good. But this is not the case e.g. on Cygwin.
  44. The localizations of gnulib.pot are of better quality in general.
  45. Also, if we use locale info from non-free systems that don't have a
  46. 'localedef' command, we deprive the users of the freedom to localize
  47. this pattern for their preferred language.
  48. But some programs, such as 'cp', 'mv', 'rm', 'find', 'xargs', are
  49. specified by POSIX to use nl_langinfo (YESEXPR). We implement this
  50. behaviour if POSIXLY_CORRECT is set, for the sake of these programs. */
  51. /* If the user wants strict POSIX compliance, use nl_langinfo. */
  52. if (posixly_correct)
  53. {
  54. translated_pattern = nl_langinfo (nl_index);
  55. /* Check against a broken system return value. */
  56. if (translated_pattern != NULL && translated_pattern[0] != '\0')
  57. return translated_pattern;
  58. }
  59. /* Look in the gnulib message catalog. */
  60. translated_pattern = _(english_pattern);
  61. if (translated_pattern == english_pattern)
  62. {
  63. /* The gnulib message catalog provides no translation.
  64. Try the system's message catalog. */
  65. translated_pattern = nl_langinfo (nl_index);
  66. /* Check against a broken system return value. */
  67. if (translated_pattern != NULL && translated_pattern[0] != '\0')
  68. return translated_pattern;
  69. /* Fall back to English. */
  70. translated_pattern = english_pattern;
  71. }
  72. return translated_pattern;
  73. }
  74. # else
  75. # define localized_pattern(english_pattern,nl_index,posixly_correct) \
  76. _(english_pattern)
  77. # endif
  78. static int
  79. try (const char *response, const char *pattern, char **lastp, regex_t *re)
  80. {
  81. if (*lastp == NULL || strcmp (pattern, *lastp) != 0)
  82. {
  83. char *safe_pattern;
  84. /* The pattern has changed. */
  85. if (*lastp != NULL)
  86. {
  87. /* Free the old compiled pattern. */
  88. regfree (re);
  89. free (*lastp);
  90. *lastp = NULL;
  91. }
  92. /* Put the PATTERN into safe memory before calling regcomp.
  93. (regcomp may call nl_langinfo, overwriting PATTERN's storage. */
  94. safe_pattern = strdup (pattern);
  95. if (safe_pattern == NULL)
  96. return -1;
  97. /* Compile the pattern and cache it for future runs. */
  98. if (regcomp (re, safe_pattern, REG_EXTENDED) != 0)
  99. return -1;
  100. *lastp = safe_pattern;
  101. }
  102. /* See if the regular expression matches RESPONSE. */
  103. return regexec (re, response, 0, NULL, 0) == 0;
  104. }
  105. #endif
  106. int
  107. rpmatch (const char *response)
  108. {
  109. #if ENABLE_NLS
  110. /* Match against one of the response patterns, compiling the pattern
  111. first if necessary. */
  112. /* We cache the response patterns and compiled regexps here. */
  113. static char *last_yesexpr, *last_noexpr;
  114. static regex_t cached_yesre, cached_nore;
  115. # if HAVE_LANGINFO_YESEXPR
  116. bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
  117. # endif
  118. const char *yesexpr, *noexpr;
  119. int result;
  120. /* TRANSLATORS: A regular expression testing for an affirmative answer
  121. (english: "yes"). Testing the first character may be sufficient.
  122. Take care to consider upper and lower case.
  123. To enquire the regular expression that your system uses for this
  124. purpose, you can use the command
  125. locale -k LC_MESSAGES | grep '^yesexpr=' */
  126. yesexpr = localized_pattern (N_("^[yY]"), YESEXPR, posixly_correct);
  127. result = try (response, yesexpr, &last_yesexpr, &cached_yesre);
  128. if (result < 0)
  129. return -1;
  130. if (result)
  131. return 1;
  132. /* TRANSLATORS: A regular expression testing for a negative answer
  133. (english: "no"). Testing the first character may be sufficient.
  134. Take care to consider upper and lower case.
  135. To enquire the regular expression that your system uses for this
  136. purpose, you can use the command
  137. locale -k LC_MESSAGES | grep '^noexpr=' */
  138. noexpr = localized_pattern (N_("^[nN]"), NOEXPR, posixly_correct);
  139. result = try (response, noexpr, &last_noexpr, &cached_nore);
  140. if (result < 0)
  141. return -1;
  142. if (result)
  143. return 0;
  144. return -1;
  145. #else
  146. /* Test against "^[yY]" and "^[nN]", hardcoded to avoid requiring regex */
  147. return (*response == 'y' || *response == 'Y' ? 1
  148. : *response == 'n' || *response == 'N' ? 0 : -1);
  149. #endif
  150. }