diff --git a/betty-style.pl b/betty-style.pl index 428c788..01eec8f 100755 --- a/betty-style.pl +++ b/betty-style.pl @@ -1092,12 +1092,6 @@ sub line_stats { return (length($line), length($white)); } -sub real_length { - my ($line) = @_; - - return (length($line)); -} - my $sanitise_quote = ''; sub sanitise_line_reset { @@ -2094,6 +2088,13 @@ sub pos_last_openparen { return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; } +sub count { + my ($s, $r) = @_; + + my $count = () = "$s" =~ /$r/g; + return $count; +} + sub process { my $filename = shift; @@ -2104,7 +2105,6 @@ sub process { my $stashrawline=""; my $length; - my $real_length; my $indent; my $previndent=0; my $stashindent=0; @@ -2250,14 +2250,22 @@ sub process { my $infunc = 0; my $infuncproto = 0; my $funcprotovalid = 0; # Prevline ended a valid function prototype (no trailing ';') + my $realscope = 0; my $inscope = 0; my $funclines = 0; + my $incond = 0; + my $condparentheses_depth = 0; + my $inparams = 0; + my $paramsparentheses_depth = 0; foreach my $line (@lines) { $linenr++; $fixlinenr++; my $sline = $line; #copy of $line $sline =~ s/$;/ /g; #with comments as spaces + my $previnscope = $realscope; + $realscope = $inscope; + my $onelinescope = 0; my $rawline = $rawlines[$linenr - 1]; @@ -2290,7 +2298,6 @@ sub process { # Measure the line length and indent. ($length, $indent) = line_stats($rawline); - $real_length = real_length($rawline); # Track the previous line. ($prevline, $stashline) = ($stashline, $line); @@ -2362,6 +2369,120 @@ sub process { $cnt_lines++ if ($realcnt != 0); +# Check for global variables (not allowed). + if ($allow_global_variables == 0 && + $inscope == 0 && + $infuncproto == 0) { + if ($line =~ /^\+\s*$Type\s*$Ident(?:\s+$Modifier)*(?:\s*=\s*.*)?;/ || + $line =~ /^\+\s*$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(].*;/ || + $line =~ /^\+\s*$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || + $line =~ /^\+\s*$declaration_macros/) { + ERROR("GLOBAL_DECLARATION", + "global variables are not allowed\n" . $herecurr); + } + } + +# Detect possible multiline function definition + if (!$infuncproto && $line =~ /^.((?:typedef\s*)?(?:(?:$Storage|$Inline)\s*(?:$Attribute\s*)?)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { + $funcprotovalid = 0; + $infuncproto = 0; + + if ($line =~ /\)\s*$/ && ($line =~ tr/(// == $line =~ tr/)//)) { + # Line ends with closing parenthesis -> End of function prototype + $funcprotovalid = 1; + } + else { + $infuncproto = 1; + } + } + elsif ($infuncproto && $line =~ /\)\s*$/ && ($line =~ tr/(// == ($line =~ tr/)// - 1))) { + # Line ends with closing parenthesis -> End of function prototype + $funcprotovalid = 1; + $infuncproto = 0; + } + +# Check whether current line is part of +# a multi line condition + if ($incond == 1 && $prevline =~ /\)/g) { + $condparentheses_depth -= count($prevline, qr/\)/); + $incond = 0 if ($condparentheses_depth == 0); + # print "[$incond] <$prevline>\n"; + } + + if ($incond == 0 && + $prevline =~ /(?:if|else|while|for)\s*\(/ && + $prevline =~ /\(/g) { + $condparentheses_depth += count($prevline, qr/\(/); + if ($prevline =~ /\)/g) { + $condparentheses_depth -= count($prevline, qr/\)/); + } + if ($condparentheses_depth > 0 && + $line =~ /\(/g) { + $condparentheses_depth += count($line, qr/\(/); + } + $incond = 1 if ($condparentheses_depth > 0); + } + +# Check whether current line is part of +# a multi line parameters list + if ($inparams == 1 && $prevline =~ /\)/g) { + $paramsparentheses_depth -= count($prevline, qr/\)/); + $inparams = 0 if ($paramsparentheses_depth == 0); + } + + if ($inparams == 0 && + $prevline =~ /$Ident\(/ && + $prevline !~ /;\s*$/ && + $prevline =~ /\(/g) { + $paramsparentheses_depth += count($prevline, qr/\(/); + if ($prevline =~ /\)/g) { + $paramsparentheses_depth -= count($prevline, qr/\)/); + } + if ($paramsparentheses_depth > 0 && + $line =~ /\(/g) { + $paramsparentheses_depth += count($line, qr/\(/); + } + $inparams = 1 if ($paramsparentheses_depth > 0); + } + +# check number of functions +# and number of lines per function + if ($line =~ /(\{)/g) { + $inscope += $#-; # TODO: Change to count() + if ($funcprotovalid && $inscope == 1) { + $infunc = 1; + $nbfunc++; + $funclines = -1; + if ($max_funcs > 0 && $nbfunc > $max_funcs) { + my $tmpline = $realline - 1; + $prefix = "$realfile:$tmpline: "; + ERROR("FUNCTIONS", + "More than $max_funcs functions in the file\n"); + } + } + } + elsif ($previnscope == $realscope && + $incond == 0 && + $prevline !~ /^.\s*\#/ && + $prevline =~ /\+\s*(if|else|while|for|do)/) { + $onelinescope = 1; + } + + if ($line =~ /(})/g) { + $inscope -= $#-; + $infunc = 0 if ($inscope == 0); + $funclines = 0 if ($infunc == 0); + $realscope = $inscope; + } + + if ($inscope >= 1 && $infunc == 1) { + $funclines++; + if ($funclines > $max_func_length) { + WARN("FUNCTIONS", + "More than $max_func_length lines in a function\n"); + } + } + # Check if the commit log has what seems like a diff which can confuse patch if ($in_commit_log && !$commit_log_has_diff && (($line =~ m@^\s+diff\b.*a/[\w/]+@ && @@ -2810,7 +2931,7 @@ sub process { # if LONG_LINE is ignored, the other 2 types are also ignored # - if ($line =~ /^\+/ && $real_length > $max_line_length) { + if ($line =~ /^\+/ && $length > $max_line_length) { my $msg_type = "LONG_LINE"; # Check the allowed long line types first @@ -2843,7 +2964,7 @@ sub process { if ($msg_type ne "" && (show_type("LONG_LINE") || show_type($msg_type))) { WARN($msg_type, - "line over $max_line_length characters ($real_length)\n" . $herecurr); + "line over $max_line_length characters ($length)\n" . $herecurr); } } @@ -3117,6 +3238,7 @@ sub process { } # check for multiple instructions on a single line +# TODO if ($rawline =~ /;/) { my $pure = $rawline; $pure =~ s/\/\*+.*//; @@ -3466,7 +3588,7 @@ sub process { $stat_real = "[...]\n$stat_real"; } - #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; + # print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; if ($check && $s ne '' && (($sindent % 8) != 0 || @@ -3477,6 +3599,29 @@ sub process { } } +# Check for correct indentation + if ($line !~ /^\+\s*#/ && + $line !~ /^\+\s*$/ && + $line !~ /^\+ +/) { + my $expected_indent = $realscope + $incond + $inparams; + $expected_indent-- if ($line =~ /^\+\s*(case\s+\S+|default)\s*:/); + # print "[$expected_indent] <$line>\n\t$realscope | $incond | $inparams\n"; + + if ($onelinescope != 0) { + $expected_indent = ($previndent / 8) + 1; + } + + my $line_indent = $indent; + if ($rawline =~ /^\+\s*( +)\*/) { + $line_indent -= $#-; + } + + if ($line_indent != (8 * $expected_indent)) { + WARN("LINE_INDENT", + "Expected $expected_indent leading tabs\n"); + } + } + # Track the 'values' across context and added lines. my $opline = $line; $opline =~ s/^./ /; my ($curr_values, $curr_vars) = @@ -3636,19 +3781,6 @@ sub process { "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); } -# Check for global variables (not allowed). - if ($allow_global_variables == 0 && - $inscope == 0 && - $infuncproto == 0) { - if ($line =~ /^\+\s*$Type\s*$Ident(?:\s+$Modifier)*(?:\s*=\s*.*)?;/ || - $line =~ /^\+\s*$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(].*;/ || - $line =~ /^\+\s*$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || - $line =~ /^\+\s*$declaration_macros/) { - ERROR("GLOBAL_DECLARATION", - "global variables are not allowed\n" . $herecurr); - } - } - # check for global initialisers. # if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*($zero_initializer)\s*;/) { # if (ERROR("GLOBAL_INITIALISERS", @@ -3892,56 +4024,6 @@ sub process { } } -# Detect possible multiline function definition - if (!$infuncproto && $line =~ /^.((?:typedef\s*)?(?:(?:$Storage|$Inline)\s*(?:$Attribute\s*)?)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { - $funcprotovalid = 0; - $infuncproto = 0; - - if ($line =~ /\)\s*$/ && ($line =~ tr/(// == $line =~ tr/)//)) { - # Line ends with closing parenthesis -> End of function prototype - $funcprotovalid = 1; - } - else { - $infuncproto = 1; - } - } - elsif ($infuncproto && $line =~ /\)\s*$/ && ($line =~ tr/(// == ($line =~ tr/)// - 1))) { - # Line ends with closing parenthesis -> End of function prototype - $funcprotovalid = 1; - $infuncproto = 0; - } - -# check number of functions -# and number of lines per function - if ($line =~ /(\{)/g) { - $inscope += $#-; - if ($funcprotovalid && $inscope == 1) { - $infunc = 1; - $nbfunc++; - $funclines = -1; - if ($max_funcs > 0 && $nbfunc > $max_funcs) { - my $tmpline = $realline - 1; - $prefix = "$realfile:$tmpline: "; - ERROR("FUNCTIONS", - "More than $max_funcs functions in the file\n"); - } - } - } - if ($line =~ /(})/g) { - $inscope -= $#-; - $infunc = 0 if ($inscope == 0); - $funclines = 0 if ($infunc == 0); - } - - if ($inscope >= 1 && $infunc == 1) { - $funclines++; - if ($funclines > $max_func_length) { - WARN("FUNCTIONS", - "More than $max_func_length lines in a function\n"); - } - } - # printf "[${infunc}][${inscope}|${infuncproto}][${funclines}]${line}\n"; - # open braces for enum, union and struct go on the same line. # if ($line =~ /^.\s*{/ && # $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { diff --git a/tests/style/functions/functions6.expected b/tests/style/functions/functions6.expected index 71f682f..b0f8849 100644 --- a/tests/style/functions/functions6.expected +++ b/tests/style/functions/functions6.expected @@ -1,3 +1,4 @@ +tests/style/functions/functions6.c:33: WARNING: line over 80 characters (101) tests/style/functions/functions6.c:43: WARNING: More than 40 lines in a function tests/style/functions/functions6.c:44: WARNING: More than 40 lines in a function tests/style/functions/functions6.c:45: WARNING: More than 40 lines in a function @@ -6,4 +7,4 @@ tests/style/functions/functions6.c:47: WARNING: More than 40 lines in a function tests/style/functions/functions6.c:48: WARNING: More than 40 lines in a function tests/style/functions/functions6.c:49: WARNING: More than 40 lines in a function tests/style/functions/functions6.c:50: WARNING: More than 40 lines in a function -total: 0 errors, 8 warnings, 51 lines checked +total: 0 errors, 9 warnings, 51 lines checked diff --git a/tests/style/headers/headers2.expected b/tests/style/headers/headers2.expected index 6dcbfcd..686da20 100644 --- a/tests/style/headers/headers2.expected +++ b/tests/style/headers/headers2.expected @@ -2,4 +2,5 @@ tests/style/headers/headers2.c:1: WARNING: typedefs should be avoided in .c file tests/style/headers/headers2.c:3: WARNING: struct definition should be avoided in .c files tests/style/headers/headers2.c:8: WARNING: enum definition should be avoided in .c files tests/style/headers/headers2.c:14: WARNING: union definition should be avoided in .c files -total: 0 errors, 4 warnings, 29 lines checked +tests/style/headers/headers2.c:27: WARNING: line over 80 characters (85) +total: 0 errors, 5 warnings, 29 lines checked diff --git a/tests/style/indentation/indentation1.c b/tests/style/indentation/indentation1.c new file mode 100644 index 0000000..efe5df4 --- /dev/null +++ b/tests/style/indentation/indentation1.c @@ -0,0 +1,42 @@ +#include +#include + +/** + * main - pmultiplies two numbers. + * @argc: argument counter + * @argv: argument vector + * Return: 0 + */ + +int main(int argc, char *argv[]) +{ + int num1, num2, r; + int arr[] = { + 0, 1, 2, + 3, 4 + }; + + if (argc != 3 && + argc != 1 && + argc != 2 && + argc != 3 && + argc != 4) + { +#define TEST 12 + puts("Error"); + return (1); + } + + if (1 < 1 + 1) + if (!func(1, 2)) + if (!func(1, 2)) + if (!func(1, 2)) + return (0); + + if (1 <= 2) + num1 = atoi(argv[1]); + num2 = atoi(argv[2]); + r = num1 * num2; + printf("%d\n", r); + return (0); +} diff --git a/tests/style/indentation/indentation1.expected b/tests/style/indentation/indentation1.expected new file mode 100644 index 0000000..e69de29 diff --git a/tests/style/indentation/indentation2.c b/tests/style/indentation/indentation2.c new file mode 100644 index 0000000..830ec3f --- /dev/null +++ b/tests/style/indentation/indentation2.c @@ -0,0 +1,39 @@ +#include +#include + + /** + * main - pmultiplies two numbers. + * @argc: argument counter + * @argv: argument vector + * Return: 0 + */ + + int main(int argc, char *argv[]) +{ +int num1, num2, r; + int arr[] = { + 0, 1, 2, + 3, 4 +}; + +if (argc != 3 && + argc != 1 && + argc != 2 && + argc != 3 && + argc != 4) +{ + #define TEST 12 + puts("Error"); + return (1); + } + +/** + * Multi-line comment in scope + */ + if (1 <= 2) + num1 = atoi(argv[1]); + num2 = atoi(argv[2]); + r = num1 * num2; + printf("%d\n", r); + return (0); +} diff --git a/tests/style/indentation/indentation2.expected b/tests/style/indentation/indentation2.expected new file mode 100644 index 0000000..3b09dcb --- /dev/null +++ b/tests/style/indentation/indentation2.expected @@ -0,0 +1,16 @@ +tests/style/indentation/indentation2.c:4: WARNING: Expected 0 leading tabs +tests/style/indentation/indentation2.c:5: WARNING: Expected 0 leading tabs +tests/style/indentation/indentation2.c:11: WARNING: Expected 0 leading tabs +tests/style/indentation/indentation2.c:13: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:15: WARNING: Expected 2 leading tabs +tests/style/indentation/indentation2.c:16: WARNING: Expected 2 leading tabs +tests/style/indentation/indentation2.c:17: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:19: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:20: WARNING: Expected 2 leading tabs +tests/style/indentation/indentation2.c:24: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:26: WARNING: Expected 2 leading tabs +tests/style/indentation/indentation2.c:30: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:31: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:32: WARNING: Expected 1 leading tabs +tests/style/indentation/indentation2.c:34: WARNING: Expected 2 leading tabs +total: 0 errors, 15 warnings, 39 lines checked diff --git a/tests/style/indentation/indentation3.c b/tests/style/indentation/indentation3.c new file mode 100644 index 0000000..a11d884 --- /dev/null +++ b/tests/style/indentation/indentation3.c @@ -0,0 +1,34 @@ +/** + * is_perfect - check if the subtrees has the same height + * and check for each subtree be perfect + * @root: Tree or subtree to check + * Return: 1 if subtree or tree is perfect or not + */ +int is_perfect(const binary_tree_t *root) +{ + if (root && _height(root->left) == _height(root->right)) + { + if (_height(root->left) == -1) + return (1); + if ((root->left && !((root->left)->left) + && !((root->left)->right)) + && (root->right && !((root->right)->left) + && !((root->right)->right))) + return (1); + if (root && root->left && root->right) + return (is_perfect(root->left) + && is_perfect(root->right)); + } + return (0); +} + +/** + * heap_insert - function that inserts a value in Max Binary Heap + * @root: double pointer to the root f of the Heap to insert the value + * @value: is the value to store in the f to be inserted + * Return: NULL on failure + */ +heap_t *heap_insert(heap_t **root, int value) +{ + return (NULL); +} diff --git a/tests/style/indentation/indentation3.expected b/tests/style/indentation/indentation3.expected new file mode 100644 index 0000000..e69de29 diff --git a/tests/style/line_break/line_break0.expected b/tests/style/line_break/line_break0.expected index bf2ebdd..1925f63 100644 --- a/tests/style/line_break/line_break0.expected +++ b/tests/style/line_break/line_break0.expected @@ -1,2 +1,3 @@ -tests/style/line_break/line_break0.c:3: WARNING: line over 80 characters (81) -total: 0 errors, 1 warnings, 4 lines checked +tests/style/line_break/line_break0.c:3: WARNING: line over 80 characters (563) +tests/style/line_break/line_break0.c:3: WARNING: Expected 1 leading tabs +total: 0 errors, 2 warnings, 4 lines checked diff --git a/tests/style/variables/variables0.expected b/tests/style/variables/variables0.expected index 4485480..40f0ac0 100644 --- a/tests/style/variables/variables0.expected +++ b/tests/style/variables/variables0.expected @@ -1,6 +1,7 @@ tests/style/variables/variables0.c:1: ERROR: global variables are not allowed tests/style/variables/variables0.c:2: ERROR: global variables are not allowed tests/style/variables/variables0.c:3: ERROR: global variables are not allowed +tests/style/variables/variables0.c:3: WARNING: Expected 0 leading tabs tests/style/variables/variables0.c:4: ERROR: global variables are not allowed tests/style/variables/variables0.c:5: ERROR: global variables are not allowed -total: 5 errors, 0 warnings, 12 lines checked +total: 5 errors, 1 warnings, 12 lines checked diff --git a/tests/style/variables/variables1.expected b/tests/style/variables/variables1.expected index 7320c59..a774602 100644 --- a/tests/style/variables/variables1.expected +++ b/tests/style/variables/variables1.expected @@ -1,2 +1,3 @@ tests/style/variables/variables1.c:3: ERROR: global variables are not allowed -total: 1 errors, 0 warnings, 19 lines checked +tests/style/variables/variables1.c:12: WARNING: Expected 1 leading tabs +total: 1 errors, 1 warnings, 19 lines checked diff --git a/tests/style/variables/variables3.expected b/tests/style/variables/variables3.expected index bb15c1d..bc9ad24 100644 --- a/tests/style/variables/variables3.expected +++ b/tests/style/variables/variables3.expected @@ -2,4 +2,5 @@ tests/style/variables/variables3.c:8: WARNING: typedefs should be avoided in .c tests/style/variables/variables3.c:10: WARNING: struct definition should be avoided in .c files tests/style/variables/variables3.c:15: WARNING: enum definition should be avoided in .c files tests/style/variables/variables3.c:21: WARNING: union definition should be avoided in .c files -total: 0 errors, 4 warnings, 36 lines checked +tests/style/variables/variables3.c:34: WARNING: line over 80 characters (85) +total: 0 errors, 5 warnings, 36 lines checked