/[jscoverage]/trunk/util.c
ViewVC logotype

Annotation of /trunk/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 99 - (hide annotations)
Wed May 14 00:01:21 2008 UTC (11 years, 4 months ago) by siliconforks
File MIME type: text/plain
File size: 9657 byte(s)
Add replacement `asprintf' for Windows.

1 siliconforks 2 /*
2     util.c - general purpose utility routines
3 siliconforks 87 Copyright (C) 2007, 2008 siliconforks.com
4 siliconforks 2
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18     */
19    
20     #include "util.h"
21    
22     #include <assert.h>
23     #include <errno.h>
24 siliconforks 99 #include <limits.h>
25 siliconforks 2 #include <stdarg.h>
26     #include <stdio.h>
27     #include <string.h>
28     #include <strings.h>
29    
30     #include <dirent.h>
31     #include <libgen.h>
32     #include <sys/stat.h>
33     #include <sys/types.h>
34     #include <unistd.h>
35    
36     const char * program = NULL;
37    
38     void fatal(const char * format, ...) {
39     fprintf(stderr, "%s: ", program);
40     va_list ap;
41     va_start(ap, format);
42     vfprintf(stderr, format, ap);
43     va_end(ap);
44     fputc('\n', stderr);
45     fprintf(stderr, "Try `%s --help' for more information.\n", program);
46     exit(EXIT_FAILURE);
47     }
48    
49     void * xmalloc(size_t size) {
50     void * result = malloc(size);
51     if (result == NULL) {
52     fatal("out of memory");
53     }
54     return result;
55     }
56    
57 siliconforks 91 void * xrealloc(void * p, size_t size) {
58     void * result = realloc(p, size);
59     if (result == NULL) {
60     fatal("out of memory");
61     }
62     return result;
63     }
64    
65 siliconforks 2 char * xstrdup(const char * s) {
66     char * result = strdup(s);
67     if (result == NULL) {
68     fatal("out of memory");
69     }
70     return result;
71     }
72    
73     char * xgetcwd(void) {
74     char * result = getcwd(NULL, 0);
75     if (result == NULL) {
76     fatal("out of memory");
77     }
78     return result;
79     }
80    
81     FILE * xfopen(const char * file, const char * mode) {
82     FILE * result = fopen(file, mode);
83     if (result == NULL) {
84     fatal("cannot open file: %s", file);
85     }
86     return result;
87     }
88    
89     DIR * xopendir(const char * directory) {
90     DIR * result = opendir(directory);
91     if (result == NULL) {
92     fatal("cannot open directory: %s", directory);
93     }
94     return result;
95     }
96    
97     void xlstat(const char * file, struct stat * buf) {
98     #ifdef _WIN32
99     return xstat(file, buf);
100     #else
101     if (lstat(file, buf) == -1) {
102     fatal("cannot stat file: %s", file);
103     }
104     #endif
105     }
106    
107     void xstat(const char * file, struct stat * buf) {
108     if (stat(file, buf) == -1) {
109     fatal("cannot stat file: %s", file);
110     }
111     }
112    
113     void xmkdir(const char * directory) {
114     int result;
115     #ifdef _WIN32
116     result = mkdir(directory);
117     #else
118     result = mkdir(directory, 0755);
119     #endif
120     if (result == -1) {
121     fatal("cannot create directory: %s", directory);
122     }
123     }
124    
125     void mkdir_if_necessary(const char * directory) {
126     struct stat buf;
127     if (stat(directory, &buf) == 0) {
128     if (! S_ISDIR(buf.st_mode)) {
129     fatal("not a directory: %s", directory);
130     }
131     }
132     else {
133     if (errno == ENOENT) {
134     xmkdir(directory);
135     }
136     else {
137     fatal("cannot stat directory: %s", directory);
138     }
139     }
140     }
141    
142     void mkdirs(const char * directory) {
143     char * d = xmalloc(strlen(directory) + 1);
144     for (const char * p = directory; *p != '\0'; p++) {
145     if (*p == '/' && p > directory) {
146     strncpy(d, directory, p - directory);
147     d[p - directory] = '\0';
148     mkdir_if_necessary(d);
149     }
150     }
151     mkdir_if_necessary(directory);
152     free(d);
153     }
154    
155     void xchdir(const char * directory) {
156     if (chdir(directory) == -1) {
157     fatal("cannot change directory: %s", directory);
158     }
159     }
160    
161     char * make_path(const char * parent, const char * relative_path) {
162     size_t parent_length = strlen(parent);
163     size_t relative_path_length = strlen(relative_path);
164     char * result = xmalloc(parent_length + relative_path_length + 2);
165     strcpy(result, parent);
166     result[parent_length] = '/';
167     strcpy(result + parent_length + 1, relative_path);
168     return result;
169     }
170    
171     char * make_canonical_path(const char * relative_path) {
172     char * original_directory = xgetcwd();
173     char * base = make_basename(relative_path);
174     char * dir = make_dirname(relative_path);
175    
176     xchdir(dir);
177     char * canonical_dir = xgetcwd();
178     char * result = make_path(canonical_dir, base);
179    
180     free(canonical_dir);
181     free(base);
182     free(dir);
183     xchdir(original_directory);
184     free(original_directory);
185    
186     return result;
187     }
188    
189     char * make_basename(const char * path) {
190     char * copy = xstrdup(path);
191     char * result = xstrdup(basename(copy));
192     free(copy);
193     return result;
194     }
195    
196     char * make_dirname(const char * path) {
197     char * copy = xstrdup(path);
198     char * result = xstrdup(dirname(copy));
199     free(copy);
200     return result;
201     }
202    
203     int is_same_file(const char * file1, const char * file2) {
204     #ifdef _WIN32
205     #define FILECMP strcasecmp
206     #else
207     #define FILECMP strcmp
208     #endif
209     if (FILECMP(file1, file2) == 0) {
210     return 1;
211     }
212    
213     char * canonical1 = make_canonical_path(file1);
214     char * canonical2 = make_canonical_path(file2);
215     int cmp = FILECMP(canonical1, canonical2);
216     free(canonical1);
217     free(canonical2);
218     if (cmp == 0) {
219     return 1;
220     }
221    
222     #ifndef _WIN32
223     struct stat buf1;
224     if (stat(file1, &buf1) == -1) {
225     if (errno == ENOENT) {
226     return 0;
227     }
228     else {
229     fatal("cannot stat file: %s", file1);
230     }
231     }
232     struct stat buf2;
233     if (stat(file2, &buf2) == -1) {
234     if (errno == ENOENT) {
235     return 0;
236     }
237     else {
238     fatal("cannot stat file: %s", file2);
239     }
240     }
241     if (buf1.st_dev == buf2.st_dev &&
242     buf1.st_ino == buf2.st_ino) {
243     return 1;
244     }
245     #endif
246     return 0;
247     #undef FILECMP
248     }
249    
250     int contains_file(const char * file1, const char * file2) {
251     int result = 0;
252     char * ancestor = make_canonical_path(file1);
253     char * d = make_canonical_path(file2);
254     char * parent = make_dirname(d);
255     while (strcmp(d, parent) != 0) {
256     if (is_same_file(ancestor, parent)) {
257     result = 1;
258     break;
259     }
260     free(d);
261     d = parent;
262     parent = make_dirname(d);
263     }
264     free(d);
265     free(parent);
266     free(ancestor);
267     return result;
268     }
269    
270     void copy_stream(FILE * source, FILE * destination) {
271     unsigned char buffer[8192];
272     for (;;) {
273     int bytes_read = fread(buffer, 1, sizeof(buffer), source);
274     if (bytes_read == 0) {
275     break;
276     }
277     fwrite(buffer, 1, bytes_read, destination);
278     }
279     }
280    
281     void copy_file(const char * source_file, const char * destination_file) {
282     FILE * source = xfopen(source_file, "rb");
283     FILE * destination = xfopen(destination_file, "wb");
284    
285     copy_stream(source, destination);
286    
287     fclose(source);
288     fclose(destination);
289     }
290    
291     int directory_is_empty(const char * directory) {
292     DIR * dir = xopendir(directory);
293     int num_entries = 0;
294     struct dirent * e;
295     while ((e = readdir(dir)) != NULL) {
296     if (strcmp(e->d_name, ".") != 0 &&
297     strcmp(e->d_name, "..") != 0) {
298     num_entries++;
299     }
300     }
301     closedir(dir);
302     return num_entries == 0;
303     }
304    
305     static struct DirListEntry * recursive_dir_list(const char * root, const char * directory_wrt_root, struct DirListEntry * head) {
306     char * directory = directory_wrt_root == NULL? xstrdup(root): make_path(root, directory_wrt_root);
307     DIR * dir = xopendir(directory);
308     struct dirent * e;
309     while ((e = readdir(dir)) != NULL) {
310     if (strcmp(e->d_name, ".") == 0 ||
311     strcmp(e->d_name, "..") == 0) {
312     continue;
313     }
314     char * entry = make_path(directory, e->d_name);
315     char * entry_wrt_root = directory_wrt_root == NULL? xstrdup(e->d_name): make_path(directory_wrt_root, e->d_name);
316     struct stat buf;
317     xlstat(entry, &buf);
318     if (S_ISREG(buf.st_mode)) {
319     struct DirListEntry * p = xmalloc(sizeof(struct DirListEntry));
320     p->name = entry_wrt_root;
321     p->next = head;
322     head = p;
323     }
324     else if (S_ISDIR(buf.st_mode)) {
325     head = recursive_dir_list(root, entry_wrt_root, head);
326     free(entry_wrt_root);
327     }
328     else {
329     fatal("unknown file type: %s", entry);
330     }
331     free(entry);
332     }
333     closedir(dir);
334     free(directory);
335     return head;
336     }
337    
338     struct DirListEntry * make_recursive_dir_list(const char * directory) {
339     return recursive_dir_list(directory, NULL, NULL);
340     }
341    
342     void free_dir_list(struct DirListEntry * list) {
343     while (list != NULL) {
344     struct DirListEntry * next = list->next;
345     free(list->name);
346     free(list);
347     list = next;
348     }
349     }
350 siliconforks 99
351     #ifndef HAVE_VASPRINTF
352     int vasprintf(char ** s, const char * template, va_list a) {
353     int size = 100;
354     *s = malloc(size);
355     if (*s == NULL) {
356     return -1;
357     }
358    
359     va_list copy;
360     va_copy(copy, a);
361     int result = vsnprintf(*s, size, template, copy);
362     if (result >= size) {
363     /* TODO: check for overflow? */
364     int new_size = result;
365     if (new_size == INT_MAX) {
366     free(*s);
367     return - 1;
368     }
369     new_size++;
370     char * new_s = realloc(*s, new_size);
371     if (new_s == NULL) {
372     free(*s);
373     return -1;
374     }
375     *s = new_s;
376     size = new_size;
377     va_copy(copy, a);
378     result = vsnprintf(*s, size, template, copy);
379     assert(result == size - 1);
380     }
381     else if (result == -1) {
382     while (result == -1) {
383     if (size > INT_MAX / 2) {
384     free(*s);
385     return - 1;
386     }
387     int new_size = 2 * size;
388     char * new_s = realloc(*s, new_size);
389     if (new_s == NULL) {
390     free(*s);
391     return -1;
392     }
393     *s = new_s;
394     size = new_size;
395     va_copy(copy, a);
396     result = vsnprintf(*s, size, template, copy);
397     }
398     assert(result <= size - 1);
399     }
400    
401     return result;
402     }
403     #endif
404    
405     #ifndef HAVE_ASPRINTF
406     int asprintf(char ** s, const char * template, ...) {
407     va_list a;
408     va_start(a, template);
409     int result = vasprintf(s, template, a);
410     va_end(a);
411     return result;
412     }
413     #endif
414    

  ViewVC Help
Powered by ViewVC 1.1.24