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>
18 #include "reduce_features.h"
20 static const char *uses_stringfuncs(struct manifest *m)
22 struct list_head *list;
24 foreach_ptr(list, &m->c_files, &m->h_files) {
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)) {
35 printf("Matched '%s' in %s\n",
41 return "No ctype.h or string functions found";
44 static void write_str(int fd, const char *str)
46 if (write(fd, str, strlen(str)) != strlen(str))
47 err(1, "Writing to temporary file");
50 static int start_file(const char *filename)
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");
58 static void test_compile(struct score *score,
59 struct ccan_file *file,
66 char *output, *compiled;
68 compiled = maybe_temp_file(score, "", keep, filename);
69 if (!compile_object(score, filename, ccan_dir, compiler, flags,
71 score_file_error(score, file, 0,
72 "Compiling object files:\n%s",
75 } else if (!streq(output, "")) {
76 score_file_error(score, file, 0,
77 "Compiling object files gave warnings:\n%s",
83 static struct ccan_file *get_main_header(struct manifest *m)
87 list_for_each(&m->h_files, f, list) {
88 if (strstarts(f->name, m->basename)
89 && strlen(f->name) == strlen(m->basename) + 2) {
93 /* Should not happen, since we passed main_header_exists! */
94 errx(1, "No main header?");
97 static void build_objects_with_stringchecks(struct manifest *m,
98 bool keep, unsigned int *timeleft,
102 bool errors = false, warnings = false;
106 /* FIXME:: We need -I so local #includes work outside normal dir. */
107 flags = talloc_asprintf(score, "-I%s %s", m->dir, cflags);
109 /* Won't work into macros, but will get inline functions. */
110 if (list_empty(&m->c_files)) {
112 i = get_main_header(m);
113 tmp = maybe_temp_file(score, ".c", keep, i->fullname);
114 tmpfd = start_file(tmp);
115 line = talloc_asprintf(score, "#include <ccan/%s/%s.h>\n",
116 m->basename, m->basename);
117 write_str(tmpfd, line);
119 test_compile(score, i, tmp, keep, flags, &errors, &warnings);
121 list_for_each(&m->c_files, i, list) {
122 tmp = maybe_temp_file(score, ".c", keep, i->fullname);
123 tmpfd = start_file(tmp);
124 write_str(tmpfd, get_ccan_file_contents(i));
126 test_compile(score, i, tmp, keep, flags,
131 /* We don't fail ccanlint for this. */
136 score->score = !warnings;
140 struct ccanlint objects_build_with_stringchecks = {
141 .key = "objects_build_with_stringchecks",
142 .name = "Module compiles with extra ctype.h and str function checks",
143 .check = build_objects_with_stringchecks,
144 .can_run = uses_stringfuncs,
145 .needs = "objects_build main_header_exists"
147 REGISTER_TEST(objects_build_with_stringchecks);