X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fexclude.c;h=f38abf2ba657a2beca56fd924b222faa859217f0;hb=2b7b09fce6b4dfcce32dfd6fe4642957e4bc3eee;hp=7df879dd17dfaa3f605a0b2249b09ce8dc0ab520;hpb=02e3bf2a532498c860f248a9bd81869dbf514404;p=gnulib.git diff --git a/lib/exclude.c b/lib/exclude.c index 7df879dd1..f38abf2ba 100644 --- a/lib/exclude.c +++ b/lib/exclude.c @@ -1,12 +1,12 @@ /* exclude.c -- exclude file names - Copyright 1992, 1993, 1994, 1997, 1999, 2000, 2001 Free Software - Foundation, Inc. + Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003, + 2004, 2005, 2006, 2007 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + 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 - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -14,63 +14,45 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. - If not, write to the Free Software Foundation, - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ /* Written by Paul Eggert */ -#if HAVE_CONFIG_H -# include -#endif +#include -#if HAVE_STDBOOL_H -# include -#else -typedef enum {false = 0, true = 1} bool; -#endif +#include +#include #include -#ifndef errno -extern int errno; -#endif +#include #include -#if HAVE_SYS_TYPES_H -# include -#endif -#if HAVE_STDLIB_H -# include -#endif -#if HAVE_STRING_H -# include -#endif -#if HAVE_STRINGS_H -# include -#endif -#if HAVE_INTTYPES_H -# include -#else -# if HAVE_STDINT_H -# include -# endif -#endif +#include +#include #include "exclude.h" #include "fnmatch.h" #include "xalloc.h" +#include "verify.h" -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) +#if USE_UNLOCKED_IO +# include "unlocked-io.h" #endif -/* Verify a requirement at compile-time (unlike assert, which is runtime). */ -#define verify(name, assertion) struct name { char a[(assertion) ? 1 : -1]; } +/* Non-GNU systems lack these options, so we don't need to check them. */ +#ifndef FNM_CASEFOLD +# define FNM_CASEFOLD 0 +#endif +#ifndef FNM_EXTMATCH +# define FNM_EXTMATCH 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_FILE_NAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR - | FNM_CASEFOLD)) - == 0)); +verify (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS) + & (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR + | FNM_CASEFOLD | FNM_EXTMATCH)) + == 0); /* An exclude pattern-options pair. The options are fnmatch options ORed with EXCLUDE_* options. */ @@ -95,12 +77,7 @@ struct exclude struct exclude * new_exclude (void) { - struct exclude *ex = (struct exclude *) xmalloc (sizeof *ex); - ex->exclude_count = 0; - ex->exclude_alloc = (1 << 6); /* This must be a power of 2. */ - ex->exclude = (struct patopts *) xmalloc (ex->exclude_alloc - * sizeof ex->exclude[0]); - return ex; + return xzalloc (sizeof *new_exclude ()); } /* Free the storage associated with an exclude list. */ @@ -118,36 +95,76 @@ free_exclude (struct exclude *ex) static int fnmatch_no_wildcards (char const *pattern, char const *f, int options) { - if (! (options & FNM_CASEFOLD)) - return ((options & FNM_LEADING_DIR) - ? strcasecmp (pattern, f) + if (! (options & FNM_LEADING_DIR)) + return ((options & FNM_CASEFOLD) + ? mbscasecmp (pattern, f) : strcmp (pattern, f)); - else + else if (! (options & FNM_CASEFOLD)) { size_t patlen = strlen (pattern); - int r = ((options & FNM_LEADING_DIR) - ? strncasecmp (pattern, f, patlen) - : strncmp (pattern, f, patlen)); + int r = strncmp (pattern, f, patlen); if (! r) { r = f[patlen]; - if (r == '/' && (options & FNM_LEADING_DIR)) + if (r == '/') r = 0; } return r; } + else + { + /* Walk through a copy of F, seeing whether P matches any prefix + of F. + + FIXME: This is an O(N**2) algorithm; it should be O(N). + Also, the copy should not be necessary. However, fixing this + will probably involve a change to the mbs* API. */ + + char *fcopy = xstrdup (f); + char *p; + int r; + for (p = fcopy; ; *p++ = '/') + { + p = strchr (p, '/'); + if (p) + *p = '\0'; + r = mbscasecmp (pattern, fcopy); + if (!p || r <= 0) + break; + } + free (fcopy); + return r; + } +} + +bool +exclude_fnmatch (char const *pattern, char const *f, int options) +{ + 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); + + return matched; } /* Return true if EX excludes F. */ bool -excluded_filename (struct exclude const *ex, char const *f) +excluded_file_name (struct exclude const *ex, char const *f) { size_t exclude_count = ex->exclude_count; /* If no options are given, the default is to include. */ if (exclude_count == 0) - return 0; + return false; else { struct patopts const *exclude = ex->exclude; @@ -163,21 +180,7 @@ excluded_filename (struct exclude const *ex, char const *f) char const *pattern = exclude[i].pattern; int options = exclude[i].options; if (excluded == !! (options & EXCLUDE_INCLUDE)) - { - int (*matcher) PARAMS ((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); - - excluded ^= matched; - } + excluded ^= exclude_fnmatch (pattern, f, options); } return excluded; @@ -191,59 +194,46 @@ add_exclude (struct exclude *ex, char const *pattern, int options) { struct patopts *patopts; - if (ex->exclude_alloc <= ex->exclude_count) - { - size_t s = 2 * ex->exclude_alloc; - if (! (0 < s && s <= SIZE_MAX / sizeof ex->exclude[0])) - xalloc_die (); - ex->exclude_alloc = s; - ex->exclude = (struct patopts *) xrealloc (ex->exclude, - s * sizeof ex->exclude[0]); - } + if (ex->exclude_count == ex->exclude_alloc) + ex->exclude = x2nrealloc (ex->exclude, &ex->exclude_alloc, + sizeof *ex->exclude); patopts = &ex->exclude[ex->exclude_count++]; patopts->pattern = pattern; patopts->options = options; } -/* Use ADD_FUNC to append to EX the patterns in FILENAME, each with - OPTIONS. LINE_END terminates each pattern in the file. Return -1 - on failure, 0 on success. */ +/* Use ADD_FUNC to append to EX the patterns in FILE_NAME, 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 (void (*add_func) PARAMS ((struct exclude *, - char const *, int)), - struct exclude *ex, char const *filename, int options, +add_exclude_file (void (*add_func) (struct exclude *, char const *, int), + struct exclude *ex, char const *file_name, int options, char line_end) { - bool use_stdin = filename[0] == '-' && !filename[1]; + bool use_stdin = file_name[0] == '-' && !file_name[1]; FILE *in; - char *buf; + char *buf = NULL; char *p; char const *pattern; char const *lim; - size_t buf_alloc = (1 << 10); /* This must be a power of two. */ + size_t buf_alloc = 0; size_t buf_count = 0; int c; int e = 0; if (use_stdin) in = stdin; - else if (! (in = fopen (filename, "r"))) + else if (! (in = fopen (file_name, "r"))) return -1; - buf = xmalloc (buf_alloc); - while ((c = getc (in)) != EOF) { - buf[buf_count++] = c; if (buf_count == buf_alloc) - { - buf_alloc *= 2; - if (! buf_alloc) - xalloc_die (); - buf = xrealloc (buf, buf_alloc); - } + buf = x2realloc (buf, &buf_alloc); + buf[buf_count++] = c; } if (ferror (in)) @@ -253,12 +243,28 @@ add_exclude_file (void (*add_func) PARAMS ((struct exclude *, e = errno; 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 (pattern = p = buf, lim = buf + buf_count; p <= lim; p++) - if (p < lim ? *p == line_end : buf < p && p[-1]) + for (p = buf; p < lim; p++) + if (*p == line_end) { - *p = '\0'; + char *pattern_end = p; + + if (isspace ((unsigned char) line_end)) + { + for (; ; pattern_end--) + if (pattern_end == pattern) + goto next_pattern; + else if (! isspace ((unsigned char) pattern_end[-1])) + break; + } + + *pattern_end = '\0'; (*add_func) (ex, pattern, options); + + next_pattern: pattern = p + 1; }