GNU file utilities
[gnulib.git] / lib / savedir.c
1 /* savedir.c -- save the list of files in a directory in a string
2    Copyright (C) 1990 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 2, 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
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */
19
20 #ifdef HAVE_CONFIG_H
21 #if defined (CONFIG_BROKETS)
22 /* We use <config.h> instead of "config.h" so that a compilation
23    using -I. -I will use ./config.h rather than /config.h
24    (which it would do because it found this file in ).  */
25 #include <config.h>
26 #else
27 #include "config.h"
28 #endif
29 #endif
30
31 #include <sys/types.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #if defined(DIRENT) || defined(_POSIX_VERSION)
38 #include <dirent.h>
39 #define NLENGTH(direct) (strlen((direct)->d_name))
40 #else /* not (DIRENT or _POSIX_VERSION) */
41 #define dirent direct
42 #define NLENGTH(direct) ((direct)->d_namlen)
43 #ifdef SYSNDIR
44 #include <sys/ndir.h>
45 #endif /* SYSNDIR */
46 #ifdef SYSDIR
47 #include <sys/dir.h>
48 #endif /* SYSDIR */
49 #ifdef NDIR
50 #include <ndir.h>
51 #endif /* NDIR */
52 #endif /* DIRENT or _POSIX_VERSION */
53
54 #ifdef VOID_CLOSEDIR
55 /* Fake a return value. */
56 #define CLOSEDIR(d) (closedir (d), 0)
57 #else
58 #define CLOSEDIR(d) closedir (d)
59 #endif
60
61 #ifdef STDC_HEADERS
62 #include <stdlib.h>
63 #include <string.h>
64 #else
65 char *malloc ();
66 char *realloc ();
67 #ifndef NULL
68 #define NULL 0
69 #endif
70 #endif
71
72 char *stpcpy ();
73
74 /* Return a freshly allocated string containing the filenames
75    in directory DIR, separated by '\0' characters;
76    the end is marked by two '\0' characters in a row.
77    NAME_SIZE is the number of bytes to initially allocate
78    for the string; it will be enlarged as needed.
79    Return NULL if DIR cannot be opened or if out of memory. */
80
81 char *
82 savedir (dir, name_size)
83      char *dir;
84      unsigned name_size;
85 {
86   DIR *dirp;
87   struct dirent *dp;
88   char *name_space;
89   char *namep;
90
91   dirp = opendir (dir);
92   if (dirp == NULL)
93     return NULL;
94
95   name_space = (char *) malloc (name_size);
96   if (name_space == NULL)
97     {
98       closedir (dirp);
99       return NULL;
100     }
101   namep = name_space;
102
103   while ((dp = readdir (dirp)) != NULL)
104     {
105       /* Skip "." and ".." (some NFS filesystems' directories lack them). */
106       if (dp->d_name[0] != '.'
107           || (dp->d_name[1] != '\0'
108               && (dp->d_name[1] != '.' || dp->d_name[2] != '\0')))
109         {
110           unsigned size_needed = (namep - name_space) + NLENGTH (dp) + 2;
111
112           if (size_needed > name_size)
113             {
114               char *new_name_space;
115
116               while (size_needed > name_size)
117                 name_size += 1024;
118
119               new_name_space = realloc (name_space, name_size);
120               if (new_name_space == NULL)
121                 {
122                   closedir (dirp);
123                   return NULL;
124                 }
125               namep += new_name_space - name_space;
126               name_space = new_name_space;
127             }
128           namep = stpcpy (namep, dp->d_name) + 1;
129         }
130     }
131   *namep = '\0';
132   if (CLOSEDIR (dirp))
133     {
134       free (name_space);
135       return NULL;
136     }
137   return name_space;
138 }