From: "Timothy B. Terriberry" <tterribe@xiph.org>
[ccan] / tools / ccanlint / idempotent.c
index 81984ec713198abed4f94baa88a421d7f9efa042..38d48d8319676e9044ca631a423559d7657e3d11 100644 (file)
@@ -11,6 +11,8 @@
 #include <stdio.h>
 #include <err.h>
 #include <string.h>
+#include <ctype.h>
+#include "../tools.h"
 
 static const char explain[] 
 = "Headers usually start with the C preprocessor lines to prevent multiple\n"
@@ -20,26 +22,81 @@ static const char explain[]
   "...\n"
   "#endif /* MY_HEADER_H */\n";
 
+static char *get_ifndef_sym(char *line)
+{
+       line += strspn(line, SPACE_CHARS);
+       if (line[0] == '#')
+       {
+               line++;
+               line += strspn(line, SPACE_CHARS);
+               if (strstarts(line, "ifndef") && isspace(line[6]))
+                       return line+6+strspn(line+6, SPACE_CHARS);
+               else if (strstarts(line, "if"))
+               {
+                       line += 2;
+                       line += strspn(line, SPACE_CHARS);
+                       if (line[0] == '!')
+                       {
+                               line++;
+                               line += strspn(line, SPACE_CHARS);
+                               if (strstarts(line, "defined"))
+                               {
+                                       line += 7;
+                                       line += strspn(line, SPACE_CHARS);
+                                       if (line[0] == '(')
+                                       {
+                                               line++;
+                                               line += strspn(line,
+                                                       SPACE_CHARS);
+                                       }
+                                       return line;
+                               }
+                       }
+               }
+       }
+       return NULL;
+}
+
+static int is_define(char *line, char *id, size_t id_len)
+{
+       line += strspn(line, SPACE_CHARS);
+       if (line[0] == '#')
+       {
+               line++;
+               line += strspn(line, SPACE_CHARS);
+               if (strstarts(line, "define") && isspace(line[6]))
+               {
+                       line += 6;
+                       line += strspn(line, SPACE_CHARS);
+                       if (strspn(line, IDENT_CHARS) == id_len &&
+                           memcmp(id, line, id_len) == 0)
+                               return 1;
+               }
+       }
+       return 0;
+}
+
 static char *report_idem(struct ccan_file *f, char *sofar)
 {
        char **lines;
-       char *secondline;
+       char *id;
+       size_t id_len;
 
        lines = get_ccan_file_lines(f);
        if (f->num_lines < 3)
                /* FIXME: We assume small headers probably uninteresting. */
                return NULL;
 
-       if (!strstarts(lines[0], "#ifndef "))
+       id = get_ifndef_sym(lines[0]);
+       if (!id)
                return talloc_asprintf_append(sofar,
                        "%s:1:expect first line to be #ifndef.\n", f->name);
+       id_len = strspn(id, IDENT_CHARS);
 
-       secondline = talloc_asprintf(f, "#define %s",
-                                    lines[0] + strlen("#ifndef "));
-       if (!streq(lines[1], secondline))
+       if (!is_define(lines[1], id, id_len))
                return talloc_asprintf_append(sofar,
-                       "%s:2:expect second line to be '%s'.\n",
-                       f->name, secondline);
+                       "%s:2:expect second line to be '#define %.*s'.\n",
+                       f->name, (int)id_len, id);
 
        return sofar;
 }