#!/usr/bin/perl
#
-# Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+# Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
# Copyright Siemens AG 2019-2020
#
# Licensed under the Apache License 2.0 (the "License").
# [-h|--sloppy-hang] [-1|--1-stmt]
# <files>
#
+# run self-tests:
+# util/check-format.pl util/check-format-test-positives.c
+# util/check-format.pl util/check-format-test-negatives.c
+#
# checks adherence to the formatting rules of the OpenSSL coding guidelines
# assuming that the input files contain syntactically correct C code.
# This pragmatic tool is incomplete and yields some false positives.
# the @ character is used because it cannot occur in normal program code so there is no confusion
# comment text is not blinded to whitespace in order to be able to check double SPC also in comments
my $comment_text = shift;
- $comment_text =~ s/\.\s\s/.. /g; # in double SPC checks allow one extra space after period '.' in comments
+ $comment_text =~ s/([\.\?\!])\s\s/$1. /g; # in double SPC checks allow one extra space after period '.', '?', or '!' in comments
return $comment_text =~ tr/ /@/cr;
}
# treat remaining blinded comments and string literal contents as (single) space during matching below
$intra_line =~ s/@+/ /g; # note that double SPC has already been handled above
$intra_line =~ s/\s+$//; # strip any (resulting) space at EOL
- $intra_line =~ s/(for\s*\();;(\))/"$1$2"/eg; # strip ';;' in for (;;)
+ $intra_line =~ s/(for\s*\([^;]*);;(\))/"$1$2"/eg; # strip trailing ';;' in for (;;)
+ $intra_line =~ s/(for\s*\([^;]+;[^;]+);(\))/"$1$2"/eg; # strip trailing ';' in for (;;)
$intra_line =~ s/(=\s*)\{ /"$1@ "/eg; # do not report {SPC in initializers such as ' = { 0, };'
$intra_line =~ s/, \};/, @;/g; # do not report SPC} in initializers such as ' = { 0, };'
report("SPC before '$1'") if $intra_line =~ m/[\w)\]]\s+(\+\+|--)/; # postfix ++/-- with preceding space
report("no SPC before '=' or '<op>='") if $intra_line =~ m/\S(=)/; # '=' etc. without preceding space
report("no SPC before '$1'") if $intra_line =~ m/\S([|\/%<>^\?])/; # |/%<>^? without preceding space
# TODO ternary ':' without preceding SPC, while allowing no SPC before ':' after 'case'
- report("no SPC before '$1'") if $intra_line =~ m/[^\s{()\[]([+\-])/;# +/- without preceding space or {()[
+ report("no SPC before binary '$1'") if $intra_line =~ m/[^\s{()\[]([+\-])/;# +/- without preceding space or {()[
# or ')' (which is used f type casts)
- report("no SPC before '$1'") if $intra_line =~ m/[^\s{()\[*]([*])/; # '*' without preceding space or {()[*
- report("no SPC before '$1'") if $intra_line =~ m/[^\s{()\[]([&])/; # '&' without preceding space or {()[
+ report("no SPC before binary '$1'") if $intra_line =~ m/[^\s{()\[*]([*])/; # '*' without preceding space or {()[*
+ report("no SPC before binary '$1'") if $intra_line =~ m/[^\s{()\[]([&])/; # '&' without preceding space or {()[
report("no SPC after ternary '$1'") if $intra_line =~ m/(:)[^\s\d]/; # ':' without following space or digit
report("no SPC after '$1'") if $intra_line =~ m/([,;=|\/%<>^\?])\S/; # ,;=|/%<>^? without following space
- report("no SPC after binary '$1'") if $intra_line=~m/([*])[^\sa-zA-Z_(),*]/;# '*' w/o space or \w(),* after
+ report("no SPC after binary '$1'") if $intra_line=~m/[^{(\[]([*])[^\sa-zA-Z_(),*]/;# '*' w/o space or \w(),* after
# TODO unary '*' must not be followed by SPC
report("no SPC after binary '$1'") if $intra_line=~m/([&])[^\sa-zA-Z_(]/; # '&' w/o following space or \w(
# TODO unary '&' must not be followed by SPC
- report("no SPC after binary '$1'") if $intra_line=~m/([+\-])[^\s\d(]/; # +/- w/o following space or \d(
+ report("no SPC after binary '$1'") if $intra_line=~m/[^{(\[]([+\-])[^\s\d(]/; # +/- w/o following space or \d(
# TODO unary '+' and '-' must not be followed by SPC
report("no SPC after '$2'") if $intra_line =~ m/(^|\W)(if|while|for|switch|case)[^\w\s]/; # kw w/o SPC
report("no SPC after '$2'") if $intra_line =~ m/(^|\W)(return)[^\w\s;]/; # return w/o SPC or ';'
$local_offset = -INDENT_LEVEL;
} else {
if (m/^([\s@]*)(\w+):/) { # (leading) label, cannot be "default"
- $local_offset = -INDENT_LEVEL + 1 ;
+ $local_offset = -INDENT_LEVEL;
$has_label = 1;
}
}
$hanging_offset = 0; # compensate for this in case macro ends, e.g., as 'while (0)'
}
- unless (m/^\s*$/) { # essentially empty line: just whitespace (and maybe a '\')
+ if (m/^\s*$/) { # essentially empty line: just whitespace (and maybe a '\')
+ report("empty line at beginnig of file") if $line == 1 && !$sloppy_SPC;
+ } else {
+ if ($line_before > 0) {
+ my $linediff = $line - $line_before - 1;
+ report("$linediff empty lines before") if $linediff > 1 && !$sloppy_SPC;
+ }
$line_before2 = $line_before;
$contents_before2 = $contents_before;
$contents_before_2 = $contents_before_;
if (eof) {
# check for essentially empty line (which may include a '\') just before EOF
report(($1 eq "\n" ? "empty line" : $2 ne "" ? "'\\'" : "whitespace")." at EOF")
- if $contents =~ m/^(\s*(\\?)\s*)$/;
+ if $contents =~ m/^(\s*(\\?)\s*)$/ && !$sloppy_SPC;
# report unclosed expression-level nesting
check_nested_nonblock_indents("expr at EOF"); # also adapts @nested_block_indents