]> git.ozlabs.org Git - ccan/blob - tools/ccanlint/tests/objects_build_with_stringchecks.c
tools: more intelligent caching for compile _info.
[ccan] / tools / ccanlint / tests / objects_build_with_stringchecks.c
1 #include <tools/ccanlint/ccanlint.h>
2 #include <tools/tools.h>
3 #include <ccan/talloc/talloc.h>
4 #include <ccan/str/str.h>
5 #include <ccan/str_talloc/str_talloc.h>
6 #include <ccan/foreach/foreach.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <limits.h>
12 #include <errno.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <err.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include "reduce_features.h"
19
20 static const char *uses_stringfuncs(struct manifest *m)
21 {
22         struct list_head *list;
23
24         foreach_ptr(list, &m->c_files, &m->h_files) {
25                 struct ccan_file *i;
26                 char *match;
27
28                 list_for_each(list, i, list) {
29                         if (strreg(m, get_ccan_file_contents(i),
30                                    "(isalnum|isalpha|isascii|isblank|iscntrl"
31                                    "|isdigit|isgraph|islower|isprint|ispunct"
32                                    "|isspace|isupper|isxdigit"
33                                    "|strstr|strchr|strrchr)", &match)) {
34                                 if (verbose > 2)
35                                         printf("Matched '%s' in %s\n",
36                                                match, i->fullname);
37                                 return NULL;
38                         }
39                 }
40         }
41         return "No ctype.h or string functions found";
42 }
43
44 static void write_str(int fd, const char *str)
45 {
46         if (write(fd, str, strlen(str)) != strlen(str))
47                 err(1, "Writing to temporary file");
48 }
49
50 static int start_file(const char *filename)
51 {
52         int fd;
53         fd = open(filename, O_WRONLY|O_CREAT, 0600);
54         write_str(fd, "#define CCAN_STR_DEBUG 1\n#include <ccan/str/str.h>\n");
55         return fd;
56 }
57
58 static void test_compile(struct score *score,
59                          struct ccan_file *file,
60                          const char *filename,
61                          const char *flags,
62                          bool *errors,
63                          bool *warnings)
64 {
65         char *output, *compiled;
66
67         compiled = temp_file(score, "", filename);
68         if (!compile_object(score, filename, ccan_dir, compiler, flags,
69                             compiled, &output)) {
70                 score_file_error(score, file, 0,
71                                  "Compiling object files:\n%s",
72                                  output);
73                 *errors = true;
74         } else if (!streq(output, "")) {
75                 score_file_error(score, file, 0,
76                                  "Compiling object files gave warnings:\n%s",
77                                  output);
78                 *warnings = true;
79         }
80 }
81
82 static struct ccan_file *get_main_header(struct manifest *m)
83 {
84         struct ccan_file *f;
85
86         list_for_each(&m->h_files, f, list) {
87                 if (strstarts(f->name, m->basename)
88                     && strlen(f->name) == strlen(m->basename) + 2) {
89                         return f;
90                 }
91         }
92         /* Should not happen, since we passed main_header_exists! */
93         errx(1, "No main header?");
94 }
95
96 static void build_objects_with_stringchecks(struct manifest *m,
97                                             unsigned int *timeleft,
98                                             struct score *score)
99 {
100         struct ccan_file *i;
101         bool errors = false, warnings = false;
102         char *tmp, *flags;
103         int tmpfd;
104
105         /* FIXME:: We need -I so local #includes work outside normal dir. */
106         flags = talloc_asprintf(score, "-I%s %s", m->dir, cflags);
107
108         /* Won't work into macros, but will get inline functions. */
109         if (list_empty(&m->c_files)) {
110                 char *line;
111                 i = get_main_header(m);
112                 tmp = temp_file(score, ".c", i->fullname);
113                 tmpfd = start_file(tmp);
114                 line = talloc_asprintf(score, "#include <ccan/%s/%s.h>\n",
115                                        m->basename, m->basename);
116                 write_str(tmpfd, line);
117                 close(tmpfd);
118                 test_compile(score, i, tmp, flags, &errors, &warnings);
119         } else {
120                 list_for_each(&m->c_files, i, list) {
121                         tmp = temp_file(score, ".c", i->fullname);
122                         tmpfd = start_file(tmp);
123                         write_str(tmpfd, get_ccan_file_contents(i));
124                         close(tmpfd);
125                         test_compile(score, i, tmp, flags, &errors, &warnings);
126                 }
127         }
128
129         /* We don't fail ccanlint for this. */
130         score->pass = true;
131
132         score->total = 1;
133         if (!errors) {
134                 score->score = !warnings;
135         }
136 }
137
138 struct ccanlint objects_build_with_stringchecks = {
139         .key = "objects_build_with_stringchecks",
140         .name = "Module compiles with extra ctype.h and str function checks",
141         .check = build_objects_with_stringchecks,
142         .can_run = uses_stringfuncs,
143         .needs = "objects_build main_header_exists"
144 };
145 REGISTER_TEST(objects_build_with_stringchecks);