4
0

exclude.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /* exclude.c -- exclude file names
  2. Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003 Free
  3. Software Foundation, Inc.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; see the file COPYING.
  14. If not, write to the Free Software Foundation,
  15. 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  16. /* Written by Paul Eggert <[email protected]> */
  17. #if HAVE_CONFIG_H
  18. # include <config.h>
  19. #endif
  20. #include <stdbool.h>
  21. #include <errno.h>
  22. #ifndef errno
  23. extern int errno;
  24. #endif
  25. #include <stddef.h>
  26. #include <stdio.h>
  27. #if HAVE_STDLIB_H
  28. # include <stdlib.h>
  29. #endif
  30. #if HAVE_STRING_H
  31. # include <string.h>
  32. #endif
  33. #if HAVE_STRINGS_H
  34. # include <strings.h>
  35. #endif
  36. #if HAVE_INTTYPES_H
  37. # include <inttypes.h>
  38. #else
  39. # if HAVE_STDINT_H
  40. # include <stdint.h>
  41. # endif
  42. #endif
  43. #include "exclude.h"
  44. #include "fnmatch.h"
  45. #include "unlocked-io.h"
  46. #include "xalloc.h"
  47. #ifndef SIZE_MAX
  48. # define SIZE_MAX ((size_t) -1)
  49. #endif
  50. /* Verify a requirement at compile-time (unlike assert, which is runtime). */
  51. #define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; }
  52. /* Non-GNU systems lack these options, so we don't need to check them. */
  53. #ifndef FNM_CASEFOLD
  54. # define FNM_CASEFOLD 0
  55. #endif
  56. #ifndef FNM_LEADING_DIR
  57. # define FNM_LEADING_DIR 0
  58. #endif
  59. verify (EXCLUDE_macros_do_not_collide_with_FNM_macros,
  60. (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
  61. & (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
  62. | FNM_CASEFOLD))
  63. == 0));
  64. /* An exclude pattern-options pair. The options are fnmatch options
  65. ORed with EXCLUDE_* options. */
  66. struct patopts
  67. {
  68. char const *pattern;
  69. int options;
  70. };
  71. /* An exclude list, of pattern-options pairs. */
  72. struct exclude
  73. {
  74. struct patopts *exclude;
  75. size_t exclude_alloc;
  76. size_t exclude_count;
  77. };
  78. /* Return a newly allocated and empty exclude list. */
  79. struct exclude *
  80. new_exclude (void)
  81. {
  82. struct exclude *ex = xmalloc (sizeof *ex);
  83. ex->exclude_count = 0;
  84. ex->exclude_alloc = (1 << 6); /* This must be a power of 2. */
  85. ex->exclude = xmalloc (ex->exclude_alloc * sizeof ex->exclude[0]);
  86. return ex;
  87. }
  88. /* Free the storage associated with an exclude list. */
  89. void
  90. free_exclude (struct exclude *ex)
  91. {
  92. free (ex->exclude);
  93. free (ex);
  94. }
  95. /* Return zero if PATTERN matches F, obeying OPTIONS, except that
  96. (unlike fnmatch) wildcards are disabled in PATTERN. */
  97. static int
  98. fnmatch_no_wildcards (char const *pattern, char const *f, int options)
  99. {
  100. if (! (options & FNM_LEADING_DIR))
  101. return ((options & FNM_CASEFOLD)
  102. ? strcasecmp (pattern, f)
  103. : strcmp (pattern, f));
  104. else
  105. {
  106. size_t patlen = strlen (pattern);
  107. int r = ((options & FNM_CASEFOLD)
  108. ? strncasecmp (pattern, f, patlen)
  109. : strncmp (pattern, f, patlen));
  110. if (! r)
  111. {
  112. r = f[patlen];
  113. if (r == '/')
  114. r = 0;
  115. }
  116. return r;
  117. }
  118. }
  119. /* Return true if EX excludes F. */
  120. bool
  121. excluded_filename (struct exclude const *ex, char const *f)
  122. {
  123. size_t exclude_count = ex->exclude_count;
  124. /* If no options are given, the default is to include. */
  125. if (exclude_count == 0)
  126. return false;
  127. else
  128. {
  129. struct patopts const *exclude = ex->exclude;
  130. size_t i;
  131. /* Otherwise, the default is the opposite of the first option. */
  132. bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
  133. /* Scan through the options, seeing whether they change F from
  134. excluded to included or vice versa. */
  135. for (i = 0; i < exclude_count; i++)
  136. {
  137. char const *pattern = exclude[i].pattern;
  138. int options = exclude[i].options;
  139. if (excluded == !! (options & EXCLUDE_INCLUDE))
  140. {
  141. int (*matcher) (char const *, char const *, int) =
  142. (options & EXCLUDE_WILDCARDS
  143. ? fnmatch
  144. : fnmatch_no_wildcards);
  145. bool matched = ((*matcher) (pattern, f, options) == 0);
  146. char const *p;
  147. if (! (options & EXCLUDE_ANCHORED))
  148. for (p = f; *p && ! matched; p++)
  149. if (*p == '/' && p[1] != '/')
  150. matched = ((*matcher) (pattern, p + 1, options) == 0);
  151. excluded ^= matched;
  152. }
  153. }
  154. return excluded;
  155. }
  156. }
  157. /* Append to EX the exclusion PATTERN with OPTIONS. */
  158. void
  159. add_exclude (struct exclude *ex, char const *pattern, int options)
  160. {
  161. struct patopts *patopts;
  162. if (ex->exclude_alloc <= ex->exclude_count)
  163. {
  164. size_t s = 2 * ex->exclude_alloc;
  165. if (! (0 < s && s <= SIZE_MAX / sizeof ex->exclude[0]))
  166. xalloc_die ();
  167. ex->exclude_alloc = s;
  168. ex->exclude = xrealloc (ex->exclude, s * sizeof ex->exclude[0]);
  169. }
  170. patopts = &ex->exclude[ex->exclude_count++];
  171. patopts->pattern = pattern;
  172. patopts->options = options;
  173. }
  174. /* Use ADD_FUNC to append to EX the patterns in FILENAME, each with
  175. OPTIONS. LINE_END terminates each pattern in the file. Return -1
  176. on failure, 0 on success. */
  177. int
  178. add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
  179. struct exclude *ex, char const *filename, int options,
  180. char line_end)
  181. {
  182. bool use_stdin = filename[0] == '-' && !filename[1];
  183. FILE *in;
  184. char *buf;
  185. char *p;
  186. char const *pattern;
  187. char const *lim;
  188. size_t buf_alloc = (1 << 10); /* This must be a power of two. */
  189. size_t buf_count = 0;
  190. int c;
  191. int e = 0;
  192. if (use_stdin)
  193. in = stdin;
  194. else if (! (in = fopen (filename, "r")))
  195. return -1;
  196. buf = xmalloc (buf_alloc);
  197. while ((c = getc (in)) != EOF)
  198. {
  199. buf[buf_count++] = c;
  200. if (buf_count == buf_alloc)
  201. {
  202. buf_alloc *= 2;
  203. if (! buf_alloc)
  204. xalloc_die ();
  205. buf = xrealloc (buf, buf_alloc);
  206. }
  207. }
  208. if (ferror (in))
  209. e = errno;
  210. if (!use_stdin && fclose (in) != 0)
  211. e = errno;
  212. buf = xrealloc (buf, buf_count + 1);
  213. for (pattern = p = buf, lim = buf + buf_count; p <= lim; p++)
  214. if (p < lim ? *p == line_end : buf < p && p[-1])
  215. {
  216. *p = '\0';
  217. (*add_func) (ex, pattern, options);
  218. pattern = p + 1;
  219. }
  220. errno = e;
  221. return e ? -1 : 0;
  222. }