X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fexclude.c;h=24146eb93ca0cde34550a53801d1ecca9c12f50f;hb=bcbf6b9fd9098dfb5c37ef710a2db02fa53b7feb;hp=e5cdfc34b9bdcef8d5f0217dcb2db77ad6eddf55;hpb=8a89b026847b0a27d5b9031490f646937eb3da20;p=gnulib.git diff --git a/lib/exclude.c b/lib/exclude.c index e5cdfc34b..24146eb93 100644 --- a/lib/exclude.c +++ b/lib/exclude.c @@ -1,5 +1,7 @@ /* exclude.c -- exclude file names - Copyright 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003, + 2004 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,80 +24,192 @@ # include #endif +#include + +#include #include -#ifndef errno -extern int errno; -#endif -#include -#include +#include #include -#include +#include +#include + +#include "exclude.h" +#include "fnmatch.h" +#include "xalloc.h" + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#if STDC_HEADERS || (! defined isascii && ! HAVE_ISASCII) +# define IN_CTYPE_DOMAIN(c) true +#else +# define IN_CTYPE_DOMAIN(c) isascii (c) +#endif + +static inline bool +is_space (unsigned char c) +{ + return IN_CTYPE_DOMAIN (c) && isspace (c); +} + +/* Verify a requirement at compile-time (unlike assert, which is runtime). */ +#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; } -void *xmalloc __EXCLUDE_P ((size_t)); -void *xrealloc __EXCLUDE_P ((void *, size_t)); +/* Non-GNU systems lack these options, so we don't need to check them. */ +#ifndef FNM_CASEFOLD +# define FNM_CASEFOLD 0 +#endif +#ifndef FNM_LEADING_DIR +# define FNM_LEADING_DIR 0 +#endif + +verify (EXCLUDE_macros_do_not_collide_with_FNM_macros, + (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS) + & (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR + | FNM_CASEFOLD)) + == 0)); + +/* An exclude pattern-options pair. The options are fnmatch options + ORed with EXCLUDE_* options. */ + +struct patopts + { + char const *pattern; + int options; + }; -/* Keep track of excluded file name patterns. */ +/* An exclude list, of pattern-options pairs. */ struct exclude { - char const **exclude; - int exclude_alloc; - int exclude_count; + struct patopts *exclude; + size_t exclude_alloc; + size_t exclude_count; }; -/* FIXME: describe */ +/* Return a newly allocated and empty exclude list. */ struct exclude * new_exclude (void) { - struct exclude *ex = (struct exclude *) xmalloc (sizeof (struct exclude)); - ex->exclude_count = 0; - ex->exclude_alloc = 64; - ex->exclude = (char const **) xmalloc (ex->exclude_alloc * sizeof (char *)); - return ex; + return xzalloc (sizeof *new_exclude ()); } -/* FIXME: describe */ +/* Free the storage associated with an exclude list. */ -int +void +free_exclude (struct exclude *ex) +{ + free (ex->exclude); + free (ex); +} + +/* Return zero if PATTERN matches F, obeying OPTIONS, except that + (unlike fnmatch) wildcards are disabled in PATTERN. */ + +static int +fnmatch_no_wildcards (char const *pattern, char const *f, int options) +{ + if (! (options & FNM_LEADING_DIR)) + return ((options & FNM_CASEFOLD) + ? strcasecmp (pattern, f) + : strcmp (pattern, f)); + else + { + size_t patlen = strlen (pattern); + int r = ((options & FNM_CASEFOLD) + ? strncasecmp (pattern, f, patlen) + : strncmp (pattern, f, patlen)); + if (! r) + { + r = f[patlen]; + if (r == '/') + r = 0; + } + return r; + } +} + +/* Return true if EX excludes F. */ + +bool excluded_filename (struct exclude const *ex, char const *f) { - char const * const *exclude = ex->exclude; - int exclude_count = ex->exclude_count; - int i; + size_t exclude_count = ex->exclude_count; + + /* If no options are given, the default is to include. */ + if (exclude_count == 0) + return false; + else + { + struct patopts const *exclude = ex->exclude; + size_t i; + + /* Otherwise, the default is the opposite of the first option. */ + bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE); + + /* Scan through the options, seeing whether they change F from + excluded to included or vice versa. */ + for (i = 0; i < exclude_count; i++) + { + char const *pattern = exclude[i].pattern; + int options = exclude[i].options; + if (excluded == !! (options & EXCLUDE_INCLUDE)) + { + int (*matcher) (char const *, char const *, int) = + (options & EXCLUDE_WILDCARDS + ? fnmatch + : fnmatch_no_wildcards); + bool matched = ((*matcher) (pattern, f, options) == 0); + char const *p; + + if (! (options & EXCLUDE_ANCHORED)) + for (p = f; *p && ! matched; p++) + if (*p == '/' && p[1] != '/') + matched = ((*matcher) (pattern, p + 1, options) == 0); - for (i = 0; i < exclude_count; i++) - if (fnmatch (exclude[i], f, 0) == 0) - return 1; + excluded ^= matched; + } + } - return 0; + return excluded; + } } -/* FIXME: describe */ +/* Append to EX the exclusion PATTERN with OPTIONS. */ void -add_exclude (struct exclude *ex, char const *pattern) +add_exclude (struct exclude *ex, char const *pattern, int options) { - if (ex->exclude_alloc <= ex->exclude_count) - ex->exclude = (char const **) xrealloc (ex->exclude, - ((ex->exclude_alloc *= 2) - * sizeof (char *))); + struct patopts *patopts; + + if (ex->exclude_count == ex->exclude_alloc) + ex->exclude = x2nrealloc (ex->exclude, &ex->exclude_alloc, + sizeof *ex->exclude); - ex->exclude[ex->exclude_count++] = pattern; + patopts = &ex->exclude[ex->exclude_count++]; + patopts->pattern = pattern; + patopts->options = options; } -/* FIXME: describe */ +/* Use ADD_FUNC to append to EX the patterns in FILENAME, each with + OPTIONS. LINE_END terminates each pattern in the file. If + LINE_END is a space character, ignore trailing spaces and empty + lines in FILE. Return -1 on failure, 0 on success. */ int -add_exclude_file (struct exclude *ex, char const *filename, char line_end) +add_exclude_file (void (*add_func) (struct exclude *, char const *, int), + struct exclude *ex, char const *filename, int options, + char line_end) { - int use_stdin = filename[0] == '-' && !filename[1]; + bool use_stdin = filename[0] == '-' && !filename[1]; FILE *in; - char *buf; + char *buf = NULL; char *p; char const *pattern; char const *lim; - size_t buf_alloc = 1024; + size_t buf_alloc = 0; size_t buf_count = 0; int c; int e = 0; @@ -105,28 +219,42 @@ add_exclude_file (struct exclude *ex, char const *filename, char line_end) else if (! (in = fopen (filename, "r"))) return -1; - buf = xmalloc (buf_alloc); - while ((c = getc (in)) != EOF) { - buf[buf_count++] = c; if (buf_count == buf_alloc) - buf = xrealloc (buf, buf_alloc *= 2); + buf = x2realloc (buf, &buf_alloc); + buf[buf_count++] = c; } - buf = xrealloc (buf, buf_count + 1); - if (ferror (in)) e = errno; if (!use_stdin && fclose (in) != 0) e = errno; - for (pattern = p = buf, lim = buf + buf_count; p <= lim; p++) - if (p < lim ? *p == line_end : buf < p && p[-1]) + buf = xrealloc (buf, buf_count + 1); + buf[buf_count] = line_end; + lim = buf + buf_count + ! (buf_count == 0 || buf[buf_count - 1] == line_end); + pattern = buf; + + for (p = buf; p < lim; p++) + if (*p == line_end) { - *p = '\0'; - add_exclude (ex, pattern); + char *pattern_end = p; + + if (is_space (line_end)) + { + for (; ; pattern_end--) + if (pattern_end == pattern) + goto next_pattern; + else if (! is_space (pattern_end[-1])) + break; + } + + *pattern_end = '\0'; + (*add_func) (ex, pattern, options); + + next_pattern: pattern = p + 1; }