1 /** @file
2     Source code style checks.
3 
4     Copyright (C) 2019 by Christian Zuckschwerdt <zany@triq.net>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 */
11 
12 // Run with: make CTEST_OUTPUT_ON_FAILURE=1 test
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <assert.h>
18 
19 #define MAX_LEN 1024
20 
21 /// Source code file style checks.
22 /// Check that there are no long lines.
23 /// Check that there are no CRLF endings.
24 /// Check that there are no mixed tabs/spaces.
style_check(char * path)25 static int style_check(char *path)
26 {
27     char *strict = strstr(path, "/devices/");
28 
29     FILE *fp = fopen(path, "r");
30     assert(fp);
31     if (!fp)
32         exit(EXIT_FAILURE);
33 
34     int read_errors = 0;
35     int long_errors = 0;
36     int crlf_errors = 0;
37     int tabs_errors = 0;
38     int trailing_errors = 0;
39     int memc_errors = 0;
40     int funbrace_errors = 0;
41 
42     int leading_tabs = 0;
43     int leading_spcs = 0;
44 
45     int use_stdout = 0;
46     int use_printf = 0;
47 
48     int need_cond = 0;
49 
50     char str[MAX_LEN];
51     while (fgets(str, MAX_LEN, fp)) {
52         int len = strlen(str);
53         if (len <= 0) {
54             read_errors++;
55             continue;
56         }
57         if (len >= MAX_LEN - 1) {
58             long_errors++;
59         }
60         if (str[len - 1] == '\r' || (len > 1 && str[len - 2] == '\r')) {
61             crlf_errors++;
62         }
63 
64         if (str[0] == '\t') {
65             leading_tabs++;
66         }
67         if (len >= 4 && str[0] == ' ' && str[1] == ' ' && str[2] == ' ' && str[3] == ' ') {
68             leading_spcs++;
69         }
70         if (len > 1 && (str[len - 2] == ' ' || str[len - 2] == '\t')) {
71             trailing_errors++;
72         }
73         if (strstr(str, "(r_device *decoder") && str[len - 2] == '{') {
74             funbrace_errors++;
75         }
76 
77         if (strstr(str, "stdout")) {
78             use_stdout++;
79         }
80         char *p;
81         if ((p = strstr(str, "printf"))) {
82             if (p == str || p[-1] < '_'|| p[-1] > 'z') {
83                 use_printf++;
84             }
85         }
86         if (need_cond && !strstr(str, "if (!")) {
87             // we had an alloc but no check on the following line
88             memc_errors++;
89         }
90         need_cond = 0;
91         if (strstr(str, "alloc(") && !strstr(str, "alloc()")) {
92             need_cond++;
93         }
94         if (strstr(str, "strdup(") && !strstr(str, "strdup()")) {
95             need_cond++;
96         }
97     }
98     fclose(fp);
99     if (leading_tabs && leading_spcs) {
100         tabs_errors = leading_tabs > leading_spcs ? leading_spcs : leading_tabs;
101     }
102 
103     if (read_errors)
104         printf("File \"%s\" has %d READ errors.\n", path, read_errors);
105     if (long_errors)
106         printf("File \"%s\" has %d LONG line errors.\n", path, long_errors);
107     if (crlf_errors)
108         printf("File \"%s\" has %d CRLF errors.\n", path, crlf_errors);
109     if (tabs_errors)
110         printf("File \"%s\" has %d MIXED tab/spaces errors.\n", path, tabs_errors);
111     if (trailing_errors)
112         printf("File \"%s\" has %d TRAILING whitespace errors.\n", path, trailing_errors);
113     if (memc_errors)
114         printf("File \"%s\" has %d ALLOC check errors.\n", path, memc_errors);
115     if (funbrace_errors)
116         printf("File \"%s\" has %d BRACE function on newline error.\n", path, funbrace_errors);
117     if (leading_tabs)
118         printf("File \"%s\" has %d TAB indented lines.\n", path, leading_tabs);
119     if (strict && use_stdout)
120         printf("File \"%s\" has %d STDOUT lines.\n", path, use_stdout);
121     if (strict && use_printf)
122         printf("File \"%s\" has %d PRINTF lines.\n", path, use_printf);
123 
124     return read_errors + long_errors + crlf_errors + tabs_errors + leading_tabs + trailing_errors
125             + funbrace_errors + (strict ? use_stdout + use_printf : 0) + memc_errors;
126 }
127 
main(int argc,char * argv[])128 int main(int argc, char *argv[])
129 {
130     int failed = 0;
131     for (int i = 1; i < argc; ++i) {
132         failed += style_check(argv[i]);
133     }
134     exit(!!failed);
135 }
136