grab_fd and grab_file: add a size arg, use everywhere.
[ccan] / tools / depends.c
1 #include "talloc/talloc.h"
2 #include "string/string.h"
3 #include "tools.h"
4 #include <err.h>
5 #include <stdbool.h>
6 #include <unistd.h>
7
8 static char ** __attribute__((format(printf, 3, 4)))
9 lines_from_cmd(const void *ctx, unsigned int *num, char *format, ...)
10 {
11         va_list ap;
12         char *cmd, *buffer;
13         FILE *p;
14
15         va_start(ap, format);
16         cmd = talloc_vasprintf(ctx, format, ap);
17         va_end(ap);
18
19         p = popen(cmd, "r");
20         if (!p)
21                 err(1, "Executing '%s'", cmd);
22
23         buffer = grab_fd(ctx, fileno(p), NULL);
24         if (!buffer)
25                 err(1, "Reading from '%s'", cmd);
26         pclose(p);
27
28         return strsplit(ctx, buffer, "\n", num);
29 }
30
31 static int unlink_info(char *infofile)
32 {
33         unlink(infofile);
34         return 0;
35 }
36
37 /* Be careful about trying to compile over running programs (parallel make) */
38 static char *compile_info(const void *ctx, const char *dir)
39 {
40         char *infofile = talloc_asprintf(ctx, "%s/_info.%u", dir, getpid());
41         char *cmd = talloc_asprintf(ctx, "cc " CFLAGS " -o %s %s/_info.c",
42                                     infofile, dir);
43         talloc_set_destructor(infofile, unlink_info);
44         if (system(cmd) != 0)
45                 return NULL;
46
47         return infofile;
48 }
49
50 static char **get_one_deps(const void *ctx, const char *dir, unsigned int *num)
51 {
52         char **deps, *cmd, *infofile;
53
54         infofile = compile_info(ctx, dir);
55         if (!infofile)
56                 errx(1, "Could not compile _info for '%s'", dir);
57
58         cmd = talloc_asprintf(ctx, "%s depends", infofile);
59         deps = lines_from_cmd(cmd, num, "%s", cmd);
60         if (!deps)
61                 err(1, "Could not run '%s'", cmd);
62         return deps;
63 }
64
65 static bool have_dep(char **deps, unsigned int num, const char *dep)
66 {
67         unsigned int i;
68
69         for (i = 0; i < num; i++)
70                 if (streq(deps[i], dep))
71                         return true;
72         return false;
73 }
74
75 /* Gets all the dependencies, recursively. */
76 char **get_deps(const void *ctx, const char *dir)
77 {
78         char **deps;
79         unsigned int i, num;
80
81         deps = get_one_deps(ctx, dir, &num);
82         for (i = 0; i < num; i++) {
83                 char **newdeps;
84                 unsigned int j, newnum;
85
86                 if (!strstarts(deps[i], "ccan/"))
87                         continue;
88
89                 newdeps = get_one_deps(ctx, deps[i], &newnum);
90
91                 /* Should be short, so brute-force out dups. */
92                 for (j = 0; j < newnum; j++) {
93                         if (have_dep(deps, num, newdeps[j]))
94                                 continue;
95
96                         deps = talloc_realloc(NULL, deps, char *, num + 2);
97                         deps[num++] = newdeps[j];
98                         deps[num] = NULL;
99                 }
100         }
101         return deps;
102 }