ccanlint: only compile _info once; speeds tdb test from 18 to 16 seconds.
[ccan] / tools / tools.c
1 #include <ccan/talloc/talloc.h>
2 #include <ccan/grab_file/grab_file.h>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <stdarg.h>
8 #include <errno.h>
9 #include <err.h>
10 #include "tools.h"
11
12 static char *tmpdir = NULL;
13 static unsigned int count;
14
15 char *talloc_basename(const void *ctx, const char *dir)
16 {
17         char *p = strrchr(dir, '/');
18
19         if (!p)
20                 return (char *)dir;
21         return talloc_strdup(ctx, p+1);
22 }
23
24 char *talloc_dirname(const void *ctx, const char *dir)
25 {
26         char *p = strrchr(dir, '/');
27
28         if (!p)
29                 return talloc_strdup(ctx, ".");
30         return talloc_strndup(ctx, dir, p - dir);
31 }
32
33 char *talloc_getcwd(const void *ctx)
34 {
35         unsigned int len;
36         char *cwd;
37
38         /* *This* is why people hate C. */
39         len = 32;
40         cwd = talloc_array(ctx, char, len);
41         while (!getcwd(cwd, len)) {
42                 if (errno != ERANGE) {
43                         talloc_free(cwd);
44                         return NULL;
45                 }
46                 cwd = talloc_realloc(ctx, cwd, char, len *= 2);
47         }
48         return cwd;
49 }
50
51 /* Returns output if command fails. */
52 char *run_command(const void *ctx, const char *fmt, ...)
53 {
54         va_list ap;
55         char *cmd, *contents;
56         FILE *pipe;
57
58         va_start(ap, fmt);
59         cmd = talloc_vasprintf(ctx, fmt, ap);
60         va_end(ap);
61
62         /* Ensure stderr gets to us too. */
63         cmd = talloc_asprintf_append(cmd, " 2>&1");
64         
65         pipe = popen(cmd, "r");
66         if (!pipe)
67                 return talloc_asprintf(ctx, "Failed to run '%s'", cmd);
68
69         contents = grab_fd(cmd, fileno(pipe), NULL);
70         if (pclose(pipe) != 0)
71                 return talloc_asprintf(ctx, "Running '%s':\n%s",
72                                        cmd, contents);
73
74         talloc_free(cmd);
75         return NULL;
76 }
77
78 static int unlink_all(char *dir)
79 {
80         char cmd[strlen(dir) + sizeof("rm -rf ")];
81         sprintf(cmd, "rm -rf %s", dir);
82 //      system(cmd);
83         return 0;
84 }
85
86 char *temp_file(const void *ctx, const char *extension)
87 {
88         /* For first call, create dir. */
89         while (!tmpdir) {
90                 tmpdir = getenv("TMPDIR");
91                 if (!tmpdir)
92                         tmpdir = "/tmp";
93                 tmpdir = talloc_asprintf(talloc_autofree_context(),
94                                          "%s/ccanlint-%u.%lu",
95                                          tmpdir, getpid(), random());
96                 if (mkdir(tmpdir, 0700) != 0) {
97                         if (errno == EEXIST) {
98                                 talloc_free(tmpdir);
99                                 tmpdir = NULL;
100                                 continue;
101                         }
102                         err(1, "mkdir %s failed", tmpdir);
103                 }
104                 talloc_set_destructor(tmpdir, unlink_all);
105         }
106
107         return talloc_asprintf(ctx, "%s/%u%s", tmpdir, count++, extension);
108 }