2 #include <ccan/talloc/talloc.h>
3 #include <ccan/str/str.h>
17 static const char explain[]
18 = "Headers usually start with the C preprocessor lines to prevent multiple\n"
19 "inclusions. These look like the following:\n"
20 "#ifndef MY_HEADER_H\n"
21 "#define MY_HEADER_H\n"
23 "#endif /* MY_HEADER_H */\n";
25 static char *get_ifndef_sym(char *line)
27 line += strspn(line, SPACE_CHARS);
31 line += strspn(line, SPACE_CHARS);
32 if (strstarts(line, "ifndef") && isspace(line[6]))
33 return line+6+strspn(line+6, SPACE_CHARS);
34 else if (strstarts(line, "if"))
37 line += strspn(line, SPACE_CHARS);
41 line += strspn(line, SPACE_CHARS);
42 if (strstarts(line, "defined"))
45 line += strspn(line, SPACE_CHARS);
60 static int is_define(char *line, char *id, size_t id_len)
62 line += strspn(line, SPACE_CHARS);
66 line += strspn(line, SPACE_CHARS);
67 if (strstarts(line, "define") && isspace(line[6]))
70 line += strspn(line, SPACE_CHARS);
71 if (strspn(line, IDENT_CHARS) == id_len &&
72 memcmp(id, line, id_len) == 0)
79 static char *report_idem(struct ccan_file *f, char *sofar)
85 lines = get_ccan_file_lines(f);
87 /* FIXME: We assume small headers probably uninteresting. */
90 id = get_ifndef_sym(lines[0]);
92 return talloc_asprintf_append(sofar,
93 "%s:1:expect first line to be #ifndef.\n", f->name);
94 id_len = strspn(id, IDENT_CHARS);
96 if (!is_define(lines[1], id, id_len))
97 return talloc_asprintf_append(sofar,
98 "%s:2:expect second line to be '#define %.*s'.\n",
99 f->name, (int)id_len, id);
104 static void *check_idempotent(struct manifest *m)
109 list_for_each(&m->h_files, f, list)
110 report = report_idem(f, report);
115 static const char *describe_idempotent(struct manifest *m, void *check_result)
117 return talloc_asprintf(check_result,
118 "Some headers not idempotent:\n"
119 "%s\n%s", (char *)check_result,
123 struct ccanlint idempotent = {
124 .name = "Headers are #ifndef/#define idempotent wrapped",
126 .check = check_idempotent,
127 .describe = describe_idempotent,