LCOV - code coverage report
Current view: top level - lib - exclude.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 6 93 6.5 %
Date: 2018-01-30 Functions: 2 7 28.6 %

          Line data    Source code
       1             : /* exclude.c -- exclude file names
       2             : 
       3             :    Copyright (C) 1992, 1993, 1994, 1997, 1999, 2000, 2001, 2002, 2003,
       4             :    2004, 2005, 2006, 2007 Free Software Foundation, Inc.
       5             : 
       6             :    This program is free software: you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
      18             : 
      19             : /* Written by Paul Eggert <eggert@twinsun.com>  */
      20             : 
      21             : #include <config.h>
      22             : 
      23             : #include <stdbool.h>
      24             : 
      25             : #include <ctype.h>
      26             : #include <errno.h>
      27             : #include <stddef.h>
      28             : #include <stdio.h>
      29             : #include <stdlib.h>
      30             : #include <string.h>
      31             : 
      32             : #include "exclude.h"
      33             : #include "fnmatch.h"
      34             : #include "xalloc.h"
      35             : #include "verify.h"
      36             : 
      37             : #if USE_UNLOCKED_IO
      38             : # include "unlocked-io.h"
      39             : #endif
      40             : 
      41             : /* Non-GNU systems lack these options, so we don't need to check them.  */
      42             : #ifndef FNM_CASEFOLD
      43             : # define FNM_CASEFOLD 0
      44             : #endif
      45             : #ifndef FNM_EXTMATCH
      46             : # define FNM_EXTMATCH 0
      47             : #endif
      48             : #ifndef FNM_LEADING_DIR
      49             : # define FNM_LEADING_DIR 0
      50             : #endif
      51             : 
      52             : verify (((EXCLUDE_ANCHORED | EXCLUDE_INCLUDE | EXCLUDE_WILDCARDS)
      53             :          & (FNM_PATHNAME | FNM_NOESCAPE | FNM_PERIOD | FNM_LEADING_DIR
      54             :             | FNM_CASEFOLD | FNM_EXTMATCH))
      55             :         == 0);
      56             : 
      57             : /* An exclude pattern-options pair.  The options are fnmatch options
      58             :    ORed with EXCLUDE_* options.  */
      59             : 
      60             : struct patopts
      61             :   {
      62             :     char const *pattern;
      63             :     int options;
      64             :   };
      65             : 
      66             : /* An exclude list, of pattern-options pairs.  */
      67             : 
      68             : struct exclude
      69             :   {
      70             :     struct patopts *exclude;
      71             :     size_t exclude_alloc;
      72             :     size_t exclude_count;
      73             :   };
      74             : 
      75             : /* Return a newly allocated and empty exclude list.  */
      76             : 
      77             : struct exclude *
      78          68 : new_exclude (void)
      79             : {
      80          68 :   return xzalloc (sizeof *new_exclude ());
      81             : }
      82             : 
      83             : /* Free the storage associated with an exclude list.  */
      84             : 
      85             : void
      86           0 : free_exclude (struct exclude *ex)
      87             : {
      88           0 :   free (ex->exclude);
      89           0 :   free (ex);
      90           0 : }
      91             : 
      92             : /* Return zero if PATTERN matches F, obeying OPTIONS, except that
      93             :    (unlike fnmatch) wildcards are disabled in PATTERN.  */
      94             : 
      95             : static int
      96           0 : fnmatch_no_wildcards (char const *pattern, char const *f, int options)
      97             : {
      98           0 :   if (! (options & FNM_LEADING_DIR))
      99           0 :     return ((options & FNM_CASEFOLD)
     100             :             ? mbscasecmp (pattern, f)
     101           0 :             : strcmp (pattern, f));
     102           0 :   else if (! (options & FNM_CASEFOLD))
     103             :     {
     104           0 :       size_t patlen = strlen (pattern);
     105           0 :       int r = strncmp (pattern, f, patlen);
     106           0 :       if (! r)
     107             :         {
     108           0 :           r = f[patlen];
     109           0 :           if (r == '/')
     110           0 :             r = 0;
     111             :         }
     112           0 :       return r;
     113             :     }
     114             :   else
     115             :     {
     116             :       /* Walk through a copy of F, seeing whether P matches any prefix
     117             :          of F.
     118             : 
     119             :          FIXME: This is an O(N**2) algorithm; it should be O(N).
     120             :          Also, the copy should not be necessary.  However, fixing this
     121             :          will probably involve a change to the mbs* API.  */
     122             : 
     123           0 :       char *fcopy = xstrdup (f);
     124             :       char *p;
     125             :       int r;
     126           0 :       for (p = fcopy; ; *p++ = '/')
     127             :         {
     128           0 :           p = strchr (p, '/');
     129           0 :           if (p)
     130           0 :             *p = '\0';
     131           0 :           r = mbscasecmp (pattern, fcopy);
     132           0 :           if (!p || r <= 0)
     133             :             break;
     134             :         }
     135           0 :       free (fcopy);
     136           0 :       return r;
     137             :     }
     138             : }
     139             : 
     140             : bool
     141           0 : exclude_fnmatch (char const *pattern, char const *f, int options)
     142             : {
     143           0 :   int (*matcher) (char const *, char const *, int) =
     144           0 :     (options & EXCLUDE_WILDCARDS
     145             :      ? fnmatch
     146           0 :      : fnmatch_no_wildcards);
     147           0 :   bool matched = ((*matcher) (pattern, f, options) == 0);
     148             :   char const *p;
     149             : 
     150           0 :   if (! (options & EXCLUDE_ANCHORED))
     151           0 :     for (p = f; *p && ! matched; p++)
     152           0 :       if (*p == '/' && p[1] != '/')
     153           0 :         matched = ((*matcher) (pattern, p + 1, options) == 0);
     154             : 
     155           0 :   return matched;
     156             : }
     157             : 
     158             : /* Return true if EX excludes F.  */
     159             : 
     160             : bool
     161      449528 : excluded_file_name (struct exclude const *ex, char const *f)
     162             : {
     163      449528 :   size_t exclude_count = ex->exclude_count;
     164             : 
     165             :   /* If no options are given, the default is to include.  */
     166      449528 :   if (exclude_count == 0)
     167      449528 :     return false;
     168             :   else
     169             :     {
     170           0 :       struct patopts const *exclude = ex->exclude;
     171             :       size_t i;
     172             : 
     173             :       /* Otherwise, the default is the opposite of the first option.  */
     174           0 :       bool excluded = !! (exclude[0].options & EXCLUDE_INCLUDE);
     175             : 
     176             :       /* Scan through the options, seeing whether they change F from
     177             :          excluded to included or vice versa.  */
     178           0 :       for (i = 0;  i < exclude_count;  i++)
     179             :         {
     180           0 :           char const *pattern = exclude[i].pattern;
     181           0 :           int options = exclude[i].options;
     182           0 :           if (excluded == !! (options & EXCLUDE_INCLUDE))
     183           0 :             excluded ^= exclude_fnmatch (pattern, f, options);
     184             :         }
     185             : 
     186           0 :       return excluded;
     187             :     }
     188             : }
     189             : 
     190             : /* Append to EX the exclusion PATTERN with OPTIONS.  */
     191             : 
     192             : void
     193           0 : add_exclude (struct exclude *ex, char const *pattern, int options)
     194             : {
     195             :   struct patopts *patopts;
     196             : 
     197           0 :   if (ex->exclude_count == ex->exclude_alloc)
     198           0 :     ex->exclude = x2nrealloc (ex->exclude, &ex->exclude_alloc,
     199             :                               sizeof *ex->exclude);
     200             : 
     201           0 :   patopts = &ex->exclude[ex->exclude_count++];
     202           0 :   patopts->pattern = pattern;
     203           0 :   patopts->options = options;
     204           0 : }
     205             : 
     206             : /* Use ADD_FUNC to append to EX the patterns in FILE_NAME, each with
     207             :    OPTIONS.  LINE_END terminates each pattern in the file.  If
     208             :    LINE_END is a space character, ignore trailing spaces and empty
     209             :    lines in FILE.  Return -1 on failure, 0 on success.  */
     210             : 
     211             : int
     212           0 : add_exclude_file (void (*add_func) (struct exclude *, char const *, int),
     213             :                   struct exclude *ex, char const *file_name, int options,
     214             :                   char line_end)
     215             : {
     216           0 :   bool use_stdin = file_name[0] == '-' && !file_name[1];
     217             :   FILE *in;
     218           0 :   char *buf = NULL;
     219             :   char *p;
     220             :   char const *pattern;
     221             :   char const *lim;
     222           0 :   size_t buf_alloc = 0;
     223           0 :   size_t buf_count = 0;
     224             :   int c;
     225           0 :   int e = 0;
     226             : 
     227           0 :   if (use_stdin)
     228           0 :     in = stdin;
     229           0 :   else if (! (in = fopen (file_name, "r")))
     230           0 :     return -1;
     231             : 
     232           0 :   while ((c = getc (in)) != EOF)
     233             :     {
     234           0 :       if (buf_count == buf_alloc)
     235           0 :         buf = x2realloc (buf, &buf_alloc);
     236           0 :       buf[buf_count++] = c;
     237             :     }
     238             : 
     239           0 :   if (ferror (in))
     240           0 :     e = errno;
     241             : 
     242           0 :   if (!use_stdin && fclose (in) != 0)
     243           0 :     e = errno;
     244             : 
     245           0 :   buf = xrealloc (buf, buf_count + 1);
     246           0 :   buf[buf_count] = line_end;
     247           0 :   lim = buf + buf_count + ! (buf_count == 0 || buf[buf_count - 1] == line_end);
     248           0 :   pattern = buf;
     249             : 
     250           0 :   for (p = buf; p < lim; p++)
     251           0 :     if (*p == line_end)
     252             :       {
     253           0 :         char *pattern_end = p;
     254             : 
     255           0 :         if (isspace ((unsigned char) line_end))
     256             :           {
     257           0 :             for (; ; pattern_end--)
     258           0 :               if (pattern_end == pattern)
     259           0 :                 goto next_pattern;
     260           0 :               else if (! isspace ((unsigned char) pattern_end[-1]))
     261           0 :                 break;
     262             :           }
     263             : 
     264           0 :         *pattern_end = '\0';
     265           0 :         (*add_func) (ex, pattern, options);
     266             : 
     267           0 :       next_pattern:
     268           0 :         pattern = p + 1;
     269             :       }
     270             : 
     271           0 :   errno = e;
     272           0 :   return e ? -1 : 0;
     273             : }

Generated by: LCOV version 1.10