Upgrade grep version 2.7 to 2.9 on the vendor branch
[dragonfly.git] / contrib / grep / lib / savedir.c
1 /* savedir.c -- save the list of files in a directory in a string
2    Copyright (C) 1990, 1997-2001, 2009-2011 Free Software Foundation, Inc.
3
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 3, or (at your option)
7    any later version.
8
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
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
19
20 #include <config.h>
21
22 #include <sys/types.h>
23 #include <unistd.h>
24 #include <dirent.h>
25
26 #ifdef CLOSEDIR_VOID
27 /* Fake a return value. */
28 # define CLOSEDIR(d) (closedir (d), 0)
29 #else
30 # define CLOSEDIR(d) closedir (d)
31 #endif
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fnmatch.h>
36 #include "savedir.h"
37 #include "xalloc.h"
38
39 static char *path;
40 static size_t pathlen;
41
42 extern int isdir (const char *name);
43
44 static int
45 isdir1 (const char *dir, const char *file)
46 {
47   size_t dirlen = strlen (dir);
48   size_t filelen = strlen (file);
49
50   while (dirlen && dir[dirlen - 1] == '/')
51     dirlen--;
52
53   if ((dirlen + filelen + 2) > pathlen)
54     {
55       pathlen *= 2;
56       if ((dirlen + filelen + 2) > pathlen)
57         pathlen = dirlen + filelen + 2;
58
59       path = xrealloc (path, pathlen);
60     }
61
62   memcpy (path, dir, dirlen);
63   path[dirlen] = '/';
64   strcpy (path + dirlen + 1, file);
65   return isdir (path);
66 }
67
68 /* Return a freshly allocated string containing the filenames
69    in directory DIR, separated by '\0' characters;
70    the end is marked by two '\0' characters in a row.
71    NAME_SIZE is the number of bytes to initially allocate
72    for the string; it will be enlarged as needed.
73    Return NULL if DIR cannot be opened or if out of memory. */
74 char *
75 savedir (const char *dir, off_t name_size, struct exclude *included_patterns,
76          struct exclude *excluded_patterns, struct exclude *excluded_directory_patterns )
77 {
78   DIR *dirp;
79   struct dirent *dp;
80   char *name_space;
81   char *namep;
82
83   dirp = opendir (dir);
84   if (dirp == NULL)
85     return NULL;
86
87   /* Be sure name_size is at least `1' so there's room for
88      the final NUL byte.  */
89   if (name_size <= 0)
90     name_size = 1;
91
92   name_space = (char *) malloc (name_size);
93   if (name_space == NULL)
94     {
95       closedir (dirp);
96       return NULL;
97     }
98   namep = name_space;
99
100   while ((dp = readdir (dirp)) != NULL)
101     {
102       /* Skip "." and ".." (some NFS file systems' directories lack them). */
103       if (dp->d_name[0] != '.'
104           || (dp->d_name[1] != '\0'
105               && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
106         {
107           size_t namlen = strlen (dp->d_name);
108           size_t size_needed = (namep - name_space) + namlen + 2;
109
110           if ((included_patterns || excluded_patterns)
111               && !isdir1 (dir, dp->d_name))
112             {
113               if (included_patterns
114                   && excluded_file_name (included_patterns, dp->d_name))
115                 continue;
116               if (excluded_patterns
117                   && excluded_file_name (excluded_patterns, dp->d_name))
118                 continue;
119             }
120
121           if ( excluded_directory_patterns
122               && isdir1 (dir, dp->d_name) )
123             {
124               if (excluded_directory_patterns
125                   && excluded_file_name (excluded_directory_patterns, dp->d_name))
126                 continue;
127             }
128
129           if (size_needed > name_size)
130             {
131               char *new_name_space;
132
133               while (size_needed > name_size)
134                 name_size += 1024;
135
136               new_name_space = realloc (name_space, name_size);
137               if (new_name_space == NULL)
138                 {
139                   closedir (dirp);
140                   goto fail;
141                 }
142               namep = new_name_space + (namep - name_space);
143               name_space = new_name_space;
144             }
145           strcpy (namep, dp->d_name);
146           namep += namlen + 1;
147         }
148     }
149   *namep = '\0';
150   if (CLOSEDIR (dirp))
151     {
152      fail:
153       free (name_space);
154       name_space = NULL;
155     }
156   if (path)
157     {
158       free (path);
159       path = NULL;
160       pathlen = 0;
161     }
162   return name_space;
163 }