78ebd2ce84da9b1f55ab91b655b55827e2cb897e
[ccan] / tools / ccanlint / idempotent.c
1 #include "ccanlint.h"
2 #include <talloc/talloc.h>
3 #include <str/str.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8 #include <limits.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <err.h>
13 #include <string.h>
14
15 static const char explain[] 
16 = "Headers usually start with the C preprocessor lines to prevent multiple\n"
17   "inclusions.  These look like the following:\n"
18   "#ifndef MY_HEADER_H\n"
19   "#define MY_HEADER_H\n"
20   "...\n"
21   "#endif /* MY_HEADER_H */\n";
22
23 static char *report_idem(struct ccan_file *f, char *sofar)
24 {
25         char **lines;
26         char *secondline;
27
28         lines = get_ccan_file_lines(f);
29         if (f->num_lines < 3)
30                 /* FIXME: We assume small headers probably uninteresting. */
31                 return NULL;
32
33         if (!strstarts(lines[0], "#ifndef "))
34                 return talloc_asprintf_append(sofar,
35                         "%s:1:expect first line to be #ifndef.\n", f->name);
36
37         secondline = talloc_asprintf(f, "#define %s",
38                                      lines[0] + strlen("#ifndef "));
39         if (!streq(lines[1], secondline))
40                 return talloc_asprintf_append(sofar,
41                         "%s:2:expect second line to be '%s'.\n",
42                         f->name, secondline);
43
44         return sofar;
45 }
46
47 static void *check_idempotent(struct manifest *m)
48 {
49         struct ccan_file *f;
50         char *report = NULL;
51
52         list_for_each(&m->h_files, f, list)
53                 report = report_idem(f, report);
54
55         return report;
56 }
57
58 static const char *describe_idempotent(struct manifest *m, void *check_result)
59 {
60         return talloc_asprintf(check_result, 
61                                "Some headers not idempotent:\n"
62                                "%s\n%s", (char *)check_result,
63                                explain);
64 }
65
66 struct ccanlint idempotent = {
67         .name = "Headers are #ifndef/#define idempotent wrapped",
68         .total_score = 1,
69         .check = check_idempotent,
70         .describe = describe_idempotent,
71 };