1 /* febootstrap-supermin-helper reimplementation in C.
2 * Copyright (C) 2009-2010 Red Hat Inc.
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 of the License, or
7 * (at your option) any later version.
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.
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.
34 #include "filevercmp.h"
41 /* Compute Y - X and return the result in milliseconds.
42 * Approximately the same as this code:
43 * http://www.mpp.mpg.de/~huber/util/timevaldiff.c
46 timeval_diff (const struct timeval *x, const struct timeval *y)
50 msec = (y->tv_sec - x->tv_sec) * 1000;
51 msec += (y->tv_usec - x->tv_usec) / 1000;
56 print_timestamped_message (const char *fs, ...)
59 gettimeofday (&tv, NULL);
66 err = vasprintf (&msg, fs, args);
71 fprintf (stderr, "supermin helper [%05" PRIi64 "ms] %s\n",
72 timeval_diff (&start_t, &tv), msg);
78 reverse_filevercmp (const void *p1, const void *p2)
80 const char *s1 = * (char * const *) p1;
81 const char *s2 = * (char * const *) p2;
83 /* Note, arguments are reversed to achieve a reverse sort. */
84 return filevercmp (s2, s1);
88 add_string (char ***argv, size_t *n_used, size_t *n_alloc, const char *str)
92 if (*n_used >= *n_alloc)
93 *argv = x2nrealloc (*argv, n_alloc, sizeof (char *));
96 new_str = xstrdup (str);
100 (*argv)[*n_used] = new_str;
106 count_strings (char *const *argv)
110 for (argc = 0; argv[argc] != NULL; ++argc)
121 dir_cache_hash (void const *x, size_t table_size)
123 struct dir_cache const *p = x;
124 return hash_pjw (p->path, table_size);
128 dir_cache_compare (void const *x, void const *y)
130 struct dir_cache const *p = x;
131 struct dir_cache const *q = y;
132 return strcmp (p->path, q->path) == 0;
135 /* Read a directory into a list of strings.
137 * Previously looked up directories are cached and returned quickly,
138 * saving some considerable amount of time compared to reading the
139 * directory over again. However this means you really must not
140 * alter the array of strings that are returned.
142 * Returns an empty list if the directory cannot be opened.
145 read_dir (const char *name)
147 static Hash_table *ht = NULL;
150 ht = hash_initialize (1024, NULL, dir_cache_hash, dir_cache_compare, NULL);
152 struct dir_cache key = { .path = (char *) name };
153 struct dir_cache *p = hash_lookup (ht, &key);
158 size_t n_used = 0, n_alloc = 0;
160 DIR *dir = opendir (name);
162 /* If it fails to open, that's OK, skip to the end. */
169 struct dirent *d = readdir (dir);
172 /* But if it fails here, after opening and potentially reading
173 * part of the directory, that's a proper failure - inform the
176 error (EXIT_FAILURE, errno, "%s", name);
180 add_string (&files, &n_used, &n_alloc, d->d_name);
183 if (closedir (dir) == -1)
184 error (EXIT_FAILURE, errno, "closedir: %s", name);
187 /* NULL-terminate the array. */
188 add_string (&files, &n_used, &n_alloc, NULL);
190 /* Add it to the hash for next time. */
191 p = xmalloc (sizeof *p);
192 p->path = (char *) name;
194 p = hash_insert (ht, p);
200 /* Filter a list of strings, returning only those where f(s) != 0. */
202 filter (char **strings, int (*f) (const char *))
205 size_t n_used = 0, n_alloc = 0;
208 for (i = 0; strings[i] != NULL; ++i) {
209 if (f (strings[i]) != 0)
210 add_string (&out, &n_used, &n_alloc, strings[i]);
213 add_string (&out, &n_used, &n_alloc, NULL);
217 /* Filter a list of strings and return only those matching the wildcard. */
219 filter_fnmatch (char **strings, const char *patt, int flags)
222 size_t n_used = 0, n_alloc = 0;
225 for (i = 0; strings[i] != NULL; ++i) {
226 r = fnmatch (patt, strings[i], flags);
228 add_string (&out, &n_used, &n_alloc, strings[i]);
229 else if (r != FNM_NOMATCH)
230 error (EXIT_FAILURE, 0, "internal error: fnmatch ('%s', '%s', %d) returned unexpected non-zero value %d\n",
231 patt, strings[i], flags, r);
234 add_string (&out, &n_used, &n_alloc, NULL);
238 /* Filter a list of strings and return only those which DON'T contain sub. */
240 filter_notmatching_substring (char **strings, const char *sub)
243 size_t n_used = 0, n_alloc = 0;
246 for (i = 0; strings[i] != NULL; ++i) {
247 if (strstr (strings[i], sub) == NULL)
248 add_string (&out, &n_used, &n_alloc, strings[i]);
251 add_string (&out, &n_used, &n_alloc, NULL);
255 /* Sort a list of strings, in place, with the comparison function supplied. */
257 sort (char **strings, int (*compare) (const void *, const void *))
259 qsort (strings, count_strings (strings), sizeof (char *), compare);
262 /* Return true iff path exists and is a directory. This version
266 isdir (const char *path)
270 if (stat (path, &statbuf) == -1)
273 return S_ISDIR (statbuf.st_mode);
276 /* Load in a file, returning a list of lines. */
278 load_file (const char *filename)
281 size_t n_used = 0, n_alloc = 0;
284 fp = fopen (filename, "r");
286 error (EXIT_FAILURE, errno, "fopen: %s", filename);
289 while (fgets (line, sizeof line, fp)) {
290 size_t len = strlen (line);
291 if (len > 0 && line[len-1] == '\n')
293 add_string (&lines, &n_used, &n_alloc, line);
296 add_string (&lines, &n_used, &n_alloc, NULL);