2d17f3f2c234f599d9d249ba48c0f58366908c95
[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-2010 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 #include <stddef.h>
26
27 #ifdef CLOSEDIR_VOID
28 /* Fake a return value. */
29 # define CLOSEDIR(d) (closedir (d), 0)
30 #else
31 # define CLOSEDIR(d) closedir (d)
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <fnmatch.h>
37 #include "savedir.h"
38 #include "xalloc.h"
39
40 static char *path;
41 static size_t pathlen;
42
43 extern int isdir (const char *name);
44
45 static int
46 isdir1 (const char *dir, const char *file)
47 {
48   size_t dirlen = strlen (dir);
49   size_t filelen = strlen (file);
50
51   while (dirlen && dir[dirlen - 1] == '/')
52     dirlen--;
53
54   if ((dirlen + filelen + 2) > pathlen)
55     {
56       pathlen *= 2;
57       if ((dirlen + filelen + 2) > pathlen)
58         pathlen = dirlen + filelen + 2;
59
60       path = xrealloc (path, pathlen);
61     }
62
63   memcpy (path, dir, dirlen);
64   path[dirlen] = '/';
65   strcpy (path + dirlen + 1, file);
66   return isdir (path);
67 }
68
69 /* Return a freshly allocated string containing the filenames
70    in directory DIR, separated by '\0' characters;
71    the end is marked by two '\0' characters in a row.
72    NAME_SIZE is the number of bytes to initially allocate
73    for the string; it will be enlarged as needed.
74    Return NULL if DIR cannot be opened or if out of memory. */
75 char *
76 savedir (const char *dir, off_t name_size, struct exclude *included_patterns,
77          struct exclude *excluded_patterns, struct exclude *excluded_directory_patterns )
78 {
79   DIR *dirp;
80   struct dirent *dp;
81   char *name_space;
82   char *namep;
83
84   dirp = opendir (dir);
85   if (dirp == NULL)
86     return NULL;
87
88   /* Be sure name_size is at least `1' so there's room for
89      the final NUL byte.  */
90   if (name_size <= 0)
91     name_size = 1;
92
93   name_space = (char *) malloc (name_size);
94   if (name_space == NULL)
95     {
96       closedir (dirp);
97       return NULL;
98     }
99   namep = name_space;
100
101   while ((dp = readdir (dirp)) != NULL)
102     {
103       /* Skip "." and ".." (some NFS file systems' directories lack them). */
104       if (dp->d_name[0] != '.'
105           || (dp->d_name[1] != '\0'
106               && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
107         {
108           size_t namlen = strlen (dp->d_name);
109           size_t size_needed = (namep - name_space) + namlen + 2;
110
111           if ((included_patterns || excluded_patterns)
112               && !isdir1 (dir, dp->d_name))
113             {
114               if (included_patterns
115                   && excluded_file_name (included_patterns, dp->d_name))
116                 continue;
117               if (excluded_patterns
118                   && excluded_file_name (excluded_patterns, dp->d_name))
119                 continue;
120             }
121
122           if ( excluded_directory_patterns
123               && isdir1 (dir, dp->d_name) )
124             {
125               if (excluded_directory_patterns
126                   && excluded_file_name (excluded_directory_patterns, dp->d_name))
127                 continue;
128             }
129
130           if (size_needed > name_size)
131             {
132               char *new_name_space;
133
134               while (size_needed > name_size)
135                 name_size += 1024;
136
137               new_name_space = realloc (name_space, name_size);
138               if (new_name_space == NULL)
139                 {
140                   closedir (dirp);
141                   goto fail;
142                 }
143               namep = new_name_space + (namep - name_space);
144               name_space = new_name_space;
145             }
146           strcpy (namep, dp->d_name);
147           namep += namlen + 1;
148         }
149     }
150   *namep = '\0';
151   if (CLOSEDIR (dirp))
152     {
153      fail:
154       free (name_space);
155       name_space = NULL;
156     }
157   if (path)
158     {
159       free (path);
160       path = NULL;
161       pathlen = 0;
162     }
163   return name_space;
164 }