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

Contents of /trunk/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 125 - (show annotations)
Mon Jun 2 17:52:38 2008 UTC (10 years, 5 months ago) by siliconforks
File MIME type: text/plain
File size: 11535 byte(s)
Fixes for compiling with MinGW.

1 /*
2 util.c - general purpose utility routines
3 Copyright (C) 2007, 2008 siliconforks.com
4
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 #define _GNU_SOURCE
21
22 #include <config.h>
23
24 #include "util.h"
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <limits.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <strings.h>
34
35 #include <dirent.h>
36 #include <libgen.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40
41 const char * program = NULL;
42
43 void fatal(const char * format, ...) {
44 fprintf(stderr, "%s: ", program);
45 va_list ap;
46 va_start(ap, format);
47 vfprintf(stderr, format, ap);
48 va_end(ap);
49 fputc('\n', stderr);
50 fprintf(stderr, "Try `%s --help' for more information.\n", program);
51 exit(EXIT_FAILURE);
52 }
53
54 size_t addst(size_t x, size_t y) {
55 if (SIZE_MAX - x < y) {
56 fatal("integer overflow");
57 }
58 return x + y;
59 }
60
61 size_t mulst(size_t x, size_t y) {
62 if (x == 0 || y == 0) {
63 return 0;
64 }
65 if (SIZE_MAX / x < y) {
66 fatal("integer overflow");
67 }
68 return x * y;
69 }
70
71 void * xmalloc(size_t size) {
72 void * result = malloc(size);
73 if (result == NULL) {
74 fatal("out of memory");
75 }
76 return result;
77 }
78
79 void * xrealloc(void * p, size_t size) {
80 void * result = realloc(p, size);
81 if (result == NULL) {
82 fatal("out of memory");
83 }
84 return result;
85 }
86
87 char * xstrdup(const char * s) {
88 char * result = strdup(s);
89 if (result == NULL) {
90 fatal("out of memory");
91 }
92 return result;
93 }
94
95 char * xstrndup(const char * s, size_t size) {
96 char * result = strndup(s, size);
97 if (result == NULL) {
98 fatal("out of memory");
99 }
100 return result;
101 }
102
103 int xasprintf(char ** s, const char * template, ...) {
104 va_list a;
105 va_start(a, template);
106 int result = vasprintf(s, template, a);
107 va_end(a);
108 if (result < 0) {
109 fatal("out of memory");
110 }
111 return result;
112 }
113
114 char * xgetcwd(void) {
115 char * result = getcwd(NULL, 0);
116 if (result == NULL) {
117 fatal("out of memory");
118 }
119 return result;
120 }
121
122 FILE * xfopen(const char * file, const char * mode) {
123 FILE * result = fopen(file, mode);
124 if (result == NULL) {
125 fatal("cannot open file: %s", file);
126 }
127 return result;
128 }
129
130 DIR * xopendir(const char * directory) {
131 DIR * result = opendir(directory);
132 if (result == NULL) {
133 fatal("cannot open directory: %s", directory);
134 }
135 return result;
136 }
137
138 void xlstat(const char * file, struct stat * buf) {
139 #ifdef _WIN32
140 return xstat(file, buf);
141 #else
142 if (lstat(file, buf) == -1) {
143 fatal("cannot stat file: %s", file);
144 }
145 #endif
146 }
147
148 void xstat(const char * file, struct stat * buf) {
149 if (stat(file, buf) == -1) {
150 fatal("cannot stat file: %s", file);
151 }
152 }
153
154 void xmkdir(const char * directory) {
155 int result;
156 #ifdef _WIN32
157 result = mkdir(directory);
158 #else
159 result = mkdir(directory, 0755);
160 #endif
161 if (result == -1) {
162 fatal("cannot create directory: %s", directory);
163 }
164 }
165
166 void mkdir_if_necessary(const char * directory) {
167 struct stat buf;
168 if (stat(directory, &buf) == 0) {
169 if (! S_ISDIR(buf.st_mode)) {
170 fatal("not a directory: %s", directory);
171 }
172 }
173 else {
174 if (errno == ENOENT) {
175 xmkdir(directory);
176 }
177 else {
178 fatal("cannot stat directory: %s", directory);
179 }
180 }
181 }
182
183 void mkdirs(const char * directory) {
184 char * d = xmalloc(strlen(directory) + 1);
185 for (const char * p = directory; *p != '\0'; p++) {
186 if (*p == '/' && p > directory) {
187 strncpy(d, directory, p - directory);
188 d[p - directory] = '\0';
189 mkdir_if_necessary(d);
190 }
191 }
192 mkdir_if_necessary(directory);
193 free(d);
194 }
195
196 void xchdir(const char * directory) {
197 if (chdir(directory) == -1) {
198 fatal("cannot change directory: %s", directory);
199 }
200 }
201
202 bool str_starts_with(const char * string, const char * prefix) {
203 const char * string_ptr = string;
204 const char * prefix_ptr = prefix;
205 while (*string_ptr != '\0' && *prefix_ptr != '\0') {
206 if (*string_ptr != *prefix_ptr) {
207 return false;
208 }
209 string_ptr++;
210 prefix_ptr++;
211 }
212 if (*string_ptr == '\0' && *prefix_ptr != '\0') {
213 return false;
214 }
215 return true;
216 }
217
218 bool str_ends_with(const char * string, const char * suffix) {
219 size_t string_length = strlen(string);
220 size_t suffix_length = strlen(suffix);
221 if (string_length < suffix_length) {
222 return false;
223 }
224 return strcmp(string + string_length - suffix_length, suffix) == 0;
225 }
226
227 char * make_path(const char * parent, const char * relative_path) {
228 size_t parent_length = strlen(parent);
229 size_t relative_path_length = strlen(relative_path);
230 size_t result_length = addst(parent_length, relative_path_length);
231 result_length = addst(result_length, 2);
232 char * result = xmalloc(result_length);
233 strcpy(result, parent);
234 result[parent_length] = '/';
235 strcpy(result + parent_length + 1, relative_path);
236 return result;
237 }
238
239 char * make_canonical_path(const char * relative_path) {
240 char * original_directory = xgetcwd();
241 char * base = make_basename(relative_path);
242 char * dir = make_dirname(relative_path);
243
244 xchdir(dir);
245 char * canonical_dir = xgetcwd();
246 char * result = make_path(canonical_dir, base);
247
248 free(canonical_dir);
249 free(base);
250 free(dir);
251 xchdir(original_directory);
252 free(original_directory);
253
254 return result;
255 }
256
257 char * make_basename(const char * path) {
258 char * copy = xstrdup(path);
259 char * result = xstrdup(basename(copy));
260 free(copy);
261 return result;
262 }
263
264 char * make_dirname(const char * path) {
265 char * copy = xstrdup(path);
266 char * result = xstrdup(dirname(copy));
267 free(copy);
268 return result;
269 }
270
271 int is_same_file(const char * file1, const char * file2) {
272 #ifdef _WIN32
273 #define FILECMP strcasecmp
274 #else
275 #define FILECMP strcmp
276 #endif
277 if (FILECMP(file1, file2) == 0) {
278 return 1;
279 }
280
281 char * canonical1 = make_canonical_path(file1);
282 char * canonical2 = make_canonical_path(file2);
283 int cmp = FILECMP(canonical1, canonical2);
284 free(canonical1);
285 free(canonical2);
286 if (cmp == 0) {
287 return 1;
288 }
289
290 #ifndef _WIN32
291 struct stat buf1;
292 if (stat(file1, &buf1) == -1) {
293 if (errno == ENOENT) {
294 return 0;
295 }
296 else {
297 fatal("cannot stat file: %s", file1);
298 }
299 }
300 struct stat buf2;
301 if (stat(file2, &buf2) == -1) {
302 if (errno == ENOENT) {
303 return 0;
304 }
305 else {
306 fatal("cannot stat file: %s", file2);
307 }
308 }
309 if (buf1.st_dev == buf2.st_dev &&
310 buf1.st_ino == buf2.st_ino) {
311 return 1;
312 }
313 #endif
314 return 0;
315 #undef FILECMP
316 }
317
318 int contains_file(const char * file1, const char * file2) {
319 int result = 0;
320 char * ancestor = make_canonical_path(file1);
321 char * d = make_canonical_path(file2);
322 char * parent = make_dirname(d);
323 while (strcmp(d, parent) != 0) {
324 if (is_same_file(ancestor, parent)) {
325 result = 1;
326 break;
327 }
328 free(d);
329 d = parent;
330 parent = make_dirname(d);
331 }
332 free(d);
333 free(parent);
334 free(ancestor);
335 return result;
336 }
337
338 void copy_stream(FILE * source, FILE * destination) {
339 unsigned char buffer[8192];
340 for (;;) {
341 int bytes_read = fread(buffer, 1, sizeof(buffer), source);
342 if (bytes_read == 0) {
343 break;
344 }
345 fwrite(buffer, 1, bytes_read, destination);
346 }
347 }
348
349 void copy_file(const char * source_file, const char * destination_file) {
350 FILE * source = xfopen(source_file, "rb");
351 FILE * destination = xfopen(destination_file, "wb");
352
353 copy_stream(source, destination);
354
355 fclose(source);
356 fclose(destination);
357 }
358
359 bool directory_is_empty(const char * directory) {
360 bool result = true;
361 DIR * dir = xopendir(directory);
362 struct dirent * e;
363 while ((e = readdir(dir)) != NULL) {
364 if (strcmp(e->d_name, ".") != 0 &&
365 strcmp(e->d_name, "..") != 0) {
366 result = false;
367 break;
368 }
369 }
370 closedir(dir);
371 return result;
372 }
373
374 static struct DirListEntry * recursive_dir_list(const char * root, const char * directory_wrt_root, struct DirListEntry * head) {
375 char * directory = directory_wrt_root == NULL? xstrdup(root): make_path(root, directory_wrt_root);
376 DIR * dir = xopendir(directory);
377 struct dirent * e;
378 while ((e = readdir(dir)) != NULL) {
379 if (strcmp(e->d_name, ".") == 0 ||
380 strcmp(e->d_name, "..") == 0) {
381 continue;
382 }
383 char * entry = make_path(directory, e->d_name);
384 char * entry_wrt_root = directory_wrt_root == NULL? xstrdup(e->d_name): make_path(directory_wrt_root, e->d_name);
385 struct stat buf;
386 xlstat(entry, &buf);
387 if (S_ISREG(buf.st_mode)) {
388 struct DirListEntry * p = xmalloc(sizeof(struct DirListEntry));
389 p->name = entry_wrt_root;
390 p->next = head;
391 head = p;
392 }
393 else if (S_ISDIR(buf.st_mode)) {
394 head = recursive_dir_list(root, entry_wrt_root, head);
395 free(entry_wrt_root);
396 }
397 else {
398 fatal("unknown file type: %s", entry);
399 }
400 free(entry);
401 }
402 closedir(dir);
403 free(directory);
404 return head;
405 }
406
407 struct DirListEntry * make_recursive_dir_list(const char * directory) {
408 return recursive_dir_list(directory, NULL, NULL);
409 }
410
411 void free_dir_list(struct DirListEntry * list) {
412 while (list != NULL) {
413 struct DirListEntry * next = list->next;
414 free(list->name);
415 free(list);
416 list = next;
417 }
418 }
419
420 #ifndef HAVE_STRNDUP
421 char * strndup(const char * s, size_t size) {
422 size_t length = strlen(s);
423 if (length > size) {
424 char * result = xmalloc(size + 1);
425 strncpy(result, s, size);
426 result[size] = '\0';
427 return result;
428 }
429 else {
430 char * result = xmalloc(length + 1);
431 strcpy(result, s);
432 return result;
433 }
434 }
435 #endif
436
437 #ifndef HAVE_VASPRINTF
438 int vasprintf(char ** s, const char * template, va_list a) {
439 int size = 100;
440 *s = malloc(size);
441 if (*s == NULL) {
442 return -1;
443 }
444
445 va_list copy;
446 va_copy(copy, a);
447 int result = vsnprintf(*s, size, template, copy);
448 if (result >= size) {
449 int new_size = result;
450 if (new_size == INT_MAX) {
451 free(*s);
452 return -1;
453 }
454 new_size++;
455 char * new_s = realloc(*s, new_size);
456 if (new_s == NULL) {
457 free(*s);
458 return -1;
459 }
460 *s = new_s;
461 size = new_size;
462 va_copy(copy, a);
463 result = vsnprintf(*s, size, template, copy);
464 assert(result == size - 1);
465 }
466 else if (result == -1) {
467 while (result == -1) {
468 if (size == INT_MAX) {
469 free(*s);
470 return -1;
471 }
472 int new_size;
473 if (size > INT_MAX / 2) {
474 new_size = INT_MAX;
475 }
476 else {
477 new_size = 2 * size;
478 }
479 char * new_s = realloc(*s, new_size);
480 if (new_s == NULL) {
481 free(*s);
482 return -1;
483 }
484 *s = new_s;
485 size = new_size;
486 va_copy(copy, a);
487 result = vsnprintf(*s, size, template, copy);
488 }
489 assert(result <= size - 1);
490 }
491
492 return result;
493 }
494 #endif
495
496 #ifndef HAVE_ASPRINTF
497 int asprintf(char ** s, const char * template, ...) {
498 va_list a;
499 va_start(a, template);
500 int result = vasprintf(s, template, a);
501 va_end(a);
502 return result;
503 }
504 #endif

  ViewVC Help
Powered by ViewVC 1.1.24