4 # Copyright (c) 2001-2017 Grant Erickson
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
10 # http://www.apache.org/licenses/LICENSE-2.0
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
19 # This program is used to flexibly and parametrically check for code
20 # formatting style compliance.
22 # Philosophically, this assumes it is working on compilable
23 # code. Consequently, this does not endeavor to be nor is it a
24 # grammatically-correct source code parser.
26 # Where possible, effort is expended to make the syntax, option
27 # invocation, and output familiar to users of compilers and other
28 # linting and formatting tools for ease of use and efficient
36 use Getopt::Long qw(:config gnu_getopt);
43 # Default program options. Eventually, the vision is to allow these to
44 # be overridden by command-line options and via a global
45 # (e.g. /usr/local/etc/style.conf) or local (e.g. ~/.style) or
46 # arbitrary configuration file. However, at present, only command-line
47 # options are supported since loading and parsing configuration files
48 # will, undoubtably, slow the program down considerably.
56 # Mappings of supported languages to style handlers. Supported
57 # languages as translated by file extension or via the '-x' option. In
58 # the absence of any better nomenclature, the language names from GCC
62 "assembler", \&asmstyle,
63 "assembler-with-cpp", \&asmstyle,
67 "c++-header", \&cxxstyle,
68 "objective-c", \&objcstyle,
69 "objective-c-header", \&objcstyle,
70 "objective-c++", \&objcxxstyle,
71 "objective-c++-header", \&objcxxstyle
74 my(@languages) = sort(keys(%handlers));
76 # Mappings of file extensions to source language type. As with the list
77 # of supported languages, language names from GCC are used.
83 "S", "assembler-with-cpp",
94 "mm", "objective-c++",
98 # Some freqeuently-used, precompiled regular expression patterns.
100 my($storage_specifiers_re) = qr/((extern|static)\s+)/;
101 my($type_qualifiers_re) = qr/((const|volatile)\s+)/;
102 my($method_qualifiers_re) = qr/((const|volatile)\s*)/;
103 my($type_declarator_re) = qr/([_[:alpha:]][_[:alnum:]]*\s*)/;
104 my($type_re) = qr/$type_qualifiers_re*$type_declarator_re*\s*($type_qualifiers_re*[*&])*/;
105 my($function_declarator_re) = qr/([_~[:alpha:]][_[:alnum:]]*)/;
106 my($argument_declarator_re) = qr/([_[:alpha:]][_[:alnum:]]*)/;
107 my($array_declarator_re) = qr/(\[\w+\])/;
108 my($argument_re) = qr/$type_re\s*($argument_declarator_re\s*$array_declarator_re*)*/;
109 my($argument_list_re) = qr/(void|($argument_re\s*,*\s*)*)/;
110 my($function_declaration_re) = qr/$storage_specifiers_re*\s*$type_re\s*$function_declarator_re\s*\($argument_list_re\)\s*$method_qualifiers_re*;\s*/;
116 # This routine prints out the proper command line usage for this program
119 # status - Flag determining what usage information will be printed and what
120 # the exit status of the program will be after the information is
127 # This subroutine does not return.
132 print(STDERR "Usage: style [ options... ] [ files... ]\n");
135 print(STDERR "Try `style --help' for more information.\n");
141 -d, --debug Display debug execution information.
142 --help Display this information.
143 -v, --verbose Display verbose execution information.
144 --version Display version information.
145 -W<WARNING> Select a comma-separated WARNING option.
146 -x, --language=<LANGUAGE> Specify LANGUAGE as source language of input
150 Permissible languages include:
153 'none' means revert to the default behavior of guessing the language
154 based on the input file's extension.
157 --copyright=<PATTERN> Copyright pattern to search for.
158 --file-length=<LENGTH> Maximum file length is LENGTH lines.
159 --line-length=<LENGTH> Maximum line length is LENGTH characters.
160 --tab-size=<SIZE> Interpret tab characters as SIZE spaces.
161 --cpp-lines-between-conditionals=<LINES>
162 Initiate preprocessor conditional checks when
163 separation between conditionals is more than
167 -Wall Enable all warning options.
168 -Werror Make all warnings into errors.
169 -Wimplicit-void-declaration Warn about implicit void declarations [EXPERIMENTAL].
170 -Winterpolated-space Warn about interpolated spaces and tabs.
171 -Wfile-length Warn about long files.
172 -Wline-length Warn about long lines.
173 -Wtrailing-line Warn about blank line(s) at the end of a file.
174 -Wblank-trailing-space Warn about white space at the end of a blank line.
175 -Wtrailing-space Warn about white space at the end of a non-blank
177 -Wmissing-cpp-conditional-labels
178 Warn about missing labels on conditionals.
179 -Wcpp-constant-conditionals
180 Warn about constant conditional expressions.
181 -Wcpp-directive-leading-space
182 Warn about leading space before directives.
184 Warn about multiple return statements per function or method.
185 -Wmissing-copyright Warn about a missing copyright declaration.
186 -Wmissing-newline-at-eof Warn about missing new line at the end of a file.
187 -Wmissing-space-after-comma Warn about missing space after a comma.
188 -Wmissing-space-after-else-if Warn about missing space after the 'else if' keyword
189 -Wmissing-space-after-for Warn about missing space after the 'for' keyword
190 -Wmissing-space-after-if Warn about missing space after the 'if' keyword
191 -Wmissing-space-after-operator Warn about missing space after the 'operator' keyword.
192 -Wmissing-space-after-semicolon
193 Warn about missing space after a semicolon.
194 -Wmissing-space-after-switch Warn about missing space after the 'switch' keyword
195 -Wmissing-space-after-while Warn about missing space after the 'while' keyword
196 -Wmissing-space-around-binary-operators
197 Warn about missing space around binary operators [EXPERIMENTAL].
198 -Wmissing-space-around-braces Warn about missing space around braces.
199 -Wspace-around-unary-operators Warn about space around unary operators.
201 # Build up a string of the permissible languages
203 my($languages) = "'" . join("', '", @languages) . "' and 'none'";
205 # Display the usage, substituting in the permissible languages
207 printf(STDERR $usage, $languages);
217 # This routine prints out program version information
226 # This subroutine does not return.
229 print("cstyle Version 1.7.5d\n");
230 print("Copyright (c) 2001-2017 Grant Erickson\n");
239 # This routine handles generating a quick-reference hash to all options
240 # invoked by the '-W' command line option.
243 # option - This is the command option and should always be 'W'.
244 # argument - This is the command argument and may contain one or
245 # more comma-separated arguments.
257 # Options are either going to be singly specified or comma-separated.
258 # In either case, split them up and add them to the warning hash.
260 foreach $warning (split(/,/, $_[1])) {
261 # Warning options may only use alphanumeric characters and the
262 # dash (-) or underscore (_) characters.
264 if ($warning =~ m/[^A-Za-z0-9_\-]/g) {
265 die("Unknown or invalid warning option: `$warning'");
268 # Warnings that are of the form 'no-<warning>' have the effect of
269 # disabling a warning (e.g. overrides -Wall or a previous enabling
272 # Attempt to match and if it matches, delete, the leading 'no-' to
273 # a warning option and then deassert the warning. Otherwise, assert
276 if ($warning =~ s/^no-//g) {
284 # Set the warning hash to true for this warning key.
286 $warnings{$warning} = $flag;
294 # This routine steps through the command-line arguments, parsing out
295 # recognzied options.
310 if (!&GetOptions(\%options,
311 "W=s@" => \&parse_warnings,
316 "cpp-lines-between-conditionals=i",
326 if ($options{"version"}) {
330 if ($options{"help"}) {
334 # If -Wmissing-copyright was set, then so too must be --copyright.
336 @dependencies = ({ OPTION => "copyright",
337 DESCRIPTION => "copyright regular expression pattern" });
339 $errors += check_warning_deps("missing-copyright", \@dependencies);
341 # If -Wfile-length was set, then so too must be --file-length.
343 @dependencies = ({ OPTION => "file-length",
344 DESCRIPTION => "file length" });
346 $errors += check_warning_deps("file-length", \@dependencies);
348 # If -Wline-length was set, then so too must be --line-length and
351 @dependencies = ({ OPTION => "line-length",
352 DESCRIPTION => "line length" },
353 { OPTION => "tab-size",
354 DESCRIPTION => "tab size" });
356 $errors += check_warning_deps("line-length", \@dependencies);
358 # If -Wmissing-cpp-conditional-labels was set, then so too must be
359 # --cpp-lines-between-conditionals.
361 @dependencies = ({ OPTION => "cpp-lines-between-conditionals",
362 DESCRIPTION => "maximum number of lines between " .
363 "preprocessor conditionals" });
365 $errors += check_warning_deps("missing-cpp-conditional-labels", \@dependencies);
367 # At this point, we either have a list of one or more files to process
368 # remaining in the argument list or we will process standard input. If
369 # we are processing standard input, then a language must be specified.
371 if ($#ARGV < 0 && !defined($options{"language"})) {
372 print(STDERR "A language must be specified when using standard input!\n");
376 usage(1) if ($errors);
382 # line_violation_with_column()
385 # This routine is used in response to line style violations and
386 # displays, to standard error, the file path, line number, column
387 # number, and line enforcement violation. If the verbose option flag
388 # is in effect, the actual text of the offending line is also
389 # displayed along with a leader indicating the position of the
390 # error, as specified by the provided column parameter.
393 # file - Path name of the current input file being processed.
394 # message - Violation message to display.
395 # line - The current input line being processed, in its pristine,
397 # column - The column number (0-based) of the violation used to
398 # generate the indicative leader in verbose mode.
406 sub line_violation_with_column {
408 my($message) = $_[1];
412 my($status) = ($warnings{"error"} ? "error" : "warning");
414 if ($options{"verbose"}) {
415 $format = "%s:%d:%d: %s: %s\n%s\n%s%s\n";
417 $format = "%s:%d:%d: %s: %s\n";
420 printf(STDERR $format, $file, $., $column + 1, $status, $message, $line,
428 # This routine is used in response to line style violations and
429 # displays, to standard error, the file path, line number, column
430 # number, and line enforcement violation. If the verbose option flag
431 # is in effect, the actual text of the offending line is also
432 # displayed along with a leader indicating the position of the
433 # error. The column to generate the indicating leader is extraced
437 # file - Path name of the current input file being processed.
438 # message - Violation message to display.
439 # line - The current input line being processed, in its pristine,
450 my($message) = $_[1];
453 line_violation_with_column($file, $message, $line, $-[1]);
460 # This routine is used in response to file style violations and
461 # displays, to standard error, the file path, and file enforcement
465 # file - Path name of the current input file being processed.
466 # message - Violation message to display.
476 my($message) = $_[1];
477 my($format) = "%s: %s: %s\n";
478 my($status) = ($warnings{"error"} ? "error" : "warning");
480 printf(STDERR $format, $file, $status, $message);
487 # This routine checks whether or not the specified warning option has
488 # been set as well as checking the 'all' warning option which implicitly
489 # sets the specified warning.
492 # warning - The name of the warning to be checked.
498 # TRUE (1) if the warning is set; otherwise, FALSE (0).
501 my($warning) = $_[0];
504 # A warning is considered enabled if: 1) The warning was
505 # independently asserted OR 2) The 'all' warning was asserted and
506 # the warning was not independently deasserted.
508 # So, if we are checking warning 'foo', the following truth table
513 # -Wall -Wfoo -> True
514 # -Wall -Wno-foo -> False
518 if (defined($warnings{$warning}) && $warnings{$warning}) {
521 } elsif (defined($warnings{$warning}) && !$warnings{$warnings}) {
525 $flag = $warnings{'all'};
533 # check_warning_deps()
536 # This routine checks for interdependencies between a warning option
537 # and one or more style options settings by ensuring the if the
538 # warning option has been asserted that the style options on which
539 # it depends are defined.
542 # warning - The name of the warning to be checked.
543 # depref - A reference to an array of dependency records, each
544 # record a hash reference containing the style option and
551 # The number of dependency errors encounterd.
553 sub check_warning_deps {
555 my($warning) = $_[0];
558 if (check_warning($warning)) {
559 my($warnings) = "`-Wall' or `-W$warning'";
561 foreach $dependency (@{$depref}) {
563 if (!defined($options{$dependency->{"OPTION"}})) {
564 printf(STDERR "The %s must be specified with " .
565 "`--%s' when used with %s!\n",
566 $dependency->{"DESCRIPTION"},
567 $dependency->{"OPTION"},
581 # This routine performs coding style checking for lines identified
582 # as C preprocessor input.
584 # At minimum, the following preprocessor directives are possible and
588 # assert <predicate> <answer>
589 # define <macro> [<expression>]
597 # ifndef <expression>
600 # line [ (<number> [<string>]) | <expression> ]
602 # unassert <predicate>
607 # file - Path name of the current input file being processed.
608 # line - The current input line being processed, in its pristine,
610 # record - A reference to the record defining the current C preprocessor
611 # directive being checked.
612 # records - A stack of C preprocessor conditional directives
613 # encountered thus far in the input file. This is used as state
614 # for various checks.
617 # records - The C preprocessor conditional directive stack, possibly with
618 # records pushed onto or popped off.
621 # The number of preprocessor violations encountered.
627 my($records) = $_[3];
631 # If enabled, check for leading white space before the
632 # preprocessor directive token ('#').
634 if (check_warning("cpp-directive-leading-space") &&
635 (length($record->{'LEADING'}) > 0)) {
636 line_violation($file, "leading space before preprocessor directive", $line);
640 # Perform directive-specific checking, accumulating state for those
641 # directives which have context-specific checks.
643 DIRECTIVE: for ($record->{'DIRECTIVE'}) {
645 /^(else|endif)$/ && do {
646 # Check to ensure that conditionals, separated by
647 # `cpp-lines-between-conditionals' lines or more have
650 my($top) = pop(@{$records});
651 my($ifline) = $top->{'LINE'};
653 # If the directive is an 'else', put the line the matching
654 # 'if' directive was on back on the stack since we cannot
655 # permanently pop it until we see the matching 'endif'.
657 if ($_ =~ m/^else$/g) {
658 push(@{$records}, $top);
661 # Compute the distance from the last seen if/ifdef/ifndef
664 my($distance) = $record->{'LINE'} - $ifline;
665 my($threshold) = $options{"cpp-lines-between-conditionals"};
667 # If the warning is asserted, the match to anything other than
668 # white space following the directive hits, and the distance
669 # exceeds the threshold, flag a violation.
671 if (check_warning("missing-cpp-conditional-labels") &&
672 ($record->{'REST'} =~ m/^\s*$/g) && ($distance > $threshold)) {
674 # Rematch on the entire original line so that @- is set
675 # correctly and the '-v' leader behavior works to identify
676 # the offending column.
678 $line =~ m/^\s*#\s*(else|endif)\s*$/g;
680 line_violation($file,
681 "Missing preprocessor conditional comment label " .
682 "for '$_' matching '$top->{'DIRECTIVE'}' at line " .
683 "$ifline, which is more than $threshold line(s) away",
691 /^(if|elif)$/ && do {
692 # Push the current line onto the if/ifdef/ifndef
693 # conditional stack so that it can be used for subsequent
696 if ($_ =~ m/^if$/g) {
697 push(@{$records}, $record);
700 # Check for constant numeric conditional expressions which
701 # indicate that the code is being unconditionally compiled
702 # out or in. Any sequence of digits following the directive
705 if (check_warning("cpp-constant-conditionals")) {
706 my($cpp_constant_conditional_re) = qr/[([:space:]]*(\d+)[)[:space:]]*/;
708 if ($record->{'REST'} =~ m/^$cpp_constant_conditional_re$/g) {
710 # Rematch on the entire original line so that @- is set
711 # correctly and the '-v' leader behavior works to identify
712 # the offending column.
714 $line =~ m/$cpp_constant_conditional_re$/g;
716 # Now flag the violation.
718 line_violation($file, "constant numeric preprocessor expression",
727 /^if(n)*def$/ && do {
728 # Push the current line onto the if/ifdef/ifndef
729 # conditional stack so that it can be used for subsequent
732 push(@{$records}, $record);
742 return ($violations);
749 # This routine performs the actual coding style checking for assembler
753 # file - Path name of the current input file being processed.
764 # In the absence of any language-specific checks, just call cstyle...
766 return (cstyle($file));
773 # This routine performs the actual coding style checking for
774 # Objective C source files.
777 # file - Path name of the current input file being processed.
788 # In the absence of any language-specific checks, just call cstyle...
790 return (cstyle($file));
797 # This routine performs the actual coding style checking for
798 # Objective C++ source files.
801 # file - Path name of the current input file being processed.
812 # In the absence of any language-specific checks, just call cstyle...
814 return (cstyle($file));
818 # is_function_or_method_declaration()
821 # This routine attempts to perform a match on the current line ($_)
822 # and determines whether or not it contains a C or C++ function or
823 # method declaration.
832 # True (1) if the current line ($_) is thought to contain a C or C++
833 # function or method declaration; otherwise, false.
835 sub is_function_or_method_declaration {
836 return (/$function_declaration_re/);
840 # is_function_or_method_declaration()
843 # This routine attempts to perform a match on the current line ($_)
844 # and determines whether or not it contains an implicit void (e.g. foo())
845 # C or C++ function or method declaration.
854 # True (1) if the current line ($_) is thought to contain an
855 # implicit void C or C++ function or method declaration; otherwise,
858 sub is_implicit_void_function_or_method_declaration {
859 my($virtual_specifier_re) = qr/((virtual)\s+)/;
860 my($implicit_void_function_declaration_re) = qr/($virtual_specifier_re|$storage_specifiers_re)*\s*$type_re\s*$function_declarator_re\s*\(\s*\)\s*$method_qualifiers_re*(\s*=\s*0)*;\s*/;
863 $retval = m/$implicit_void_function_declaration_re/gp;
867 # - Any member pointer or member reference selection void method
870 # - Any return statements embedding a void function or method
873 # - Any assignments with a void function or method call as an rvalue.
876 if ((${^PREMATCH} =~ m/(\.|->)$/gp) ||
877 (${^PREMATCH} =~ m/\s*return\s/gp) ||
878 (${^PREMATCH} =~ m/\s*=\s*/gp)) {
890 # This routine performs the actual coding style checking for C source
894 # file - Path name of the current input file being processed.
907 my($return_count) = 0;
911 my($in_function_at_depth) = -1;
913 my($saw_copyright) = 0;
915 LINE: while (<STDIN>) {
916 # Attempt to automatically detect end-of-line markers based on what is
917 # encountered on the first line.
920 if (m/(\015?\012?)$/) {
925 # Strip the end-of-line marker. Note that chomp should always be
926 # used rather than chop, since chomp acts intelligently based on
927 # '$/' whereas chop just always consumes that last character on a
928 # line without regard to whether or not its actually a newline
933 # Cache the input line in its pristine, unmodified state.
937 # Clean-up and ignore things we don't want to further check:
939 # 1) Text, including escaped characters, w/i single ('') and double ("") quotes.
941 s/(["'])(?:(?=(\\?))\2.)*?\1/\1\1/g;
943 # 2) Trailing backslashes.
949 if (check_warning("file-length")) {
950 if ($. > $options{"file-length"}) {
951 line_violation($file, "file > " .
952 $options{"file-length"} .
958 # Inline "/* *STYLE-OFF* */" or "// *STYLE-OFF*" directives on a
959 # line by themselves exempt subsequent lines from style checking
960 # until a similar "/* *STYLE-ON* */ or "// *STYLE-ON*" directive
961 # on a line by itself is encountered.
963 if ((/^\s*\/\*\s*\*STYLE-(ON|OFF)\*\s*\*\/$/) || # C-style directive
964 (/^\s*\/\/\s*\*STYLE-(ON|OFF)\*$/)) { # C++-style directive
966 # Set the state based on the positional match argument of "ON" or "OFF"
968 $state{"style-disable"} = ($1 eq "OFF") ? 1 : 0;
971 # If style checking has been disabled by a style directive, skip ahead
974 if (defined($state{"style-disable"}) && $state{"style-disable"} == 1) {
984 if (check_warning("line-length")) {
985 # First, a quick check to see if there is any chance of being too long.
987 if ($line =~ tr/\t/\t/ *
988 ($options{"tab-size"} - 1) +
989 length($line) > $options{"line-length"}) {
991 # Confirmed. Interpolate spaces for tabs and check again.
995 1 while $eline =~ s/\t+/" " x (length($&) *
996 $options{"tab-size"} - length($`) %
997 $options{"tab-size"})/e;
999 if (length($eline) > $options{"line-length"}) {
1000 line_violation($file, "line > " .
1001 $options{"line-length"} .
1002 " characters", $line);
1008 # Check for unnecessary trailing white-space at the end of a
1011 if (check_warning("trailing-space")) {
1012 if (/[^[:space:]]+(\s+)$/) {
1013 line_violation($file, "white space at end of a non-blank line", $line);
1018 # Check for unnecessary trailing white-space at the end of a blank
1021 if (check_warning("blank-trailing-space")) {
1022 if (/^(\s+)$/ && !/^\f$/) {
1023 line_violation($file, "white space at end of a blank line", $line);
1028 # Check for interpolation of tabs with spaces.
1030 if (check_warning("interpolated-space")) {
1032 line_violation($file, "spaces between tabs", $line);
1037 line_violation($file, "tabs between spaces", $line);
1042 # Delete any trailing whitespace; we have already checked for that.
1046 # Check preprocessor directives.
1048 # The following regular expression breaks up the directive as follows
1050 # 1: Optional leading white space, up to the '#'.
1051 # 2: Optional trailing white space, after the '#'.
1052 # 3: The directive itself.
1053 # 4: Optional trailing white space, after the directive.
1054 # 5: Optional directive-specific tokens.
1057 if (/^(\s*)#(\s*)([a-z]+)(\s*)(.*)$/) {
1059 %cpprecord = ( 'LEADING' => $1,
1065 $violations += cppstyle($file, $line, {%cpprecord}, \@cppstack);
1072 # Check for a missing copyright declaration
1074 if (check_warning("missing-copyright") && $saw_copyright != 1) {
1075 if (/$options{"copyright"}/) {
1080 # Search for a start of a multi-line comment
1082 if (/\/\*/ && $in_comment != 1) {
1085 # This might be an one line comment (e.g. "/* ... */")
1096 # Search for the end of a multi-line comment
1098 if (/\*\// && $in_comment != 0) {
1106 # If we are in a multi-line comment, there is no further style
1107 # checking at tis point. Simply iterate to the next line.
1109 if ($in_comment != 0) {
1115 # Swallow, at this point, any inline comments (i.e. "// ...")
1119 # Check for missing white space after commas
1121 if (check_warning("missing-space-after-comma")) {
1123 line_violation($file, "missing space after comma", $line);
1128 # Check for missing white space after semicolons
1130 if (check_warning("missing-space-after-semicolon")) {
1132 line_violation($file, "missing space after semicolon", $line);
1137 # Check for missing space after keywords
1139 if (check_warning("missing-space-after-if")) {
1140 if (/(?<!else)\sif(\()/) {
1141 line_violation($file, "missing space after 'if' keyword", $line);
1146 if (check_warning("missing-space-after-else-if")) {
1147 if (/else if(\()/) {
1148 line_violation($file, "missing space after 'else if' keyword", $line);
1153 if (check_warning("missing-space-after-for")) {
1155 line_violation($file, "missing space after 'for' keyword", $line);
1160 if (check_warning("missing-space-after-operator")) {
1161 if (/[[:space:]&*]operator(new|delete|[.\-+*\/%><=!|^&~\[,(])/) {
1162 line_violation($file, "missing space after 'operator' keyword", $line);
1167 if (check_warning("missing-space-after-switch")) {
1168 if (/\sswitch(\()/) {
1169 line_violation($file, "missing space after 'switch' keyword", $line);
1174 if (check_warning("missing-space-after-while")) {
1175 if (/}*\s*while(\()/) {
1176 line_violation($file, "missing space after 'while' keyword", $line);
1181 if (check_warning("missing-space-around-braces")) {
1182 my($opening_brace_re) = qr/(^\{\S|[^\s@^]\{\s|[^\s@^]\{\S|\s\{\S|[^\s@^]\{$)/;
1183 my($closing_brace_re) = qr/(^}[^\s,;)]|\S}\s|\S}\S|\S}$|\s}[^\s,;)])/;
1185 if ((/${opening_brace_re}/) || (/${closing_brace_re}/)) {
1186 my($column) = $-[1];
1190 $which_brace = "opening";
1192 $which_brace = "closing";
1195 line_violation_with_column($file, "missing space around $which_brace brace", $line, $column);
1200 # Check for missing space around binary operators:
1202 # [space]<binary operator>[space]
1206 # - Comparison operators: ==, !=, <=, >=, <, >
1207 # - Logical operators: &&, ||
1208 # - Bitwise operators: &, |, ^
1209 # - Arithmetic operators: +, *, -, /, %
1210 # - Shift operators: <<, >>
1211 # - Assignment operator: =
1212 # - Compound operators: &=, |=, ^=, +=, *=, -=, /=, %=, <<=, >>=
1214 if (check_warning("missing-space-around-binary-operators")) {
1215 my($eq_operator_re) = qr/==/;
1216 my($ne_operator_re) = qr/!=/;
1217 my($le_operator_re) = qr/<=/;
1218 my($ge_operator_re) = qr/>=/;
1219 my($lt_operator_re) = qr/(?<!([ct]_cast))(?<!<)<(?![=<])/;
1220 my($gt_operator_re) = qr/(?<![>-])>(?![=>])/;
1221 my($logical_and_operator_re) = qr/&&/;
1222 my($logical_or_operator_re) = qr/\|\|/;
1223 my($bitwise_and_operator_re) = qr/(?<![=*&,][[:space:]])(?<![&*(])&(?![&=)])/;
1224 my($bitwise_or_operator_re) = qr/(?<!\|)\|(?![\|=])/;
1225 my($bitwise_xor_operator_re) = qr/\^(?!=)/;
1226 my($addition_operator_re) = qr/(?<!\+)\+(?![\+=])/;
1227 my($multiplication_operator_re) = qr/(?<![=*&,][[:space:]])(?<![(\*])\*(?![=\*&>)])/;
1228 my($subtraction_operator_re) = qr/(?<![=][[:space:](])(?<![-\[\(])-(?![-=>])/;
1229 my($division_operator_re) = qr/\/(?!=)/;
1230 my($modulus_operator_re) = qr/%(?!=)/;
1231 my($left_shift_operator_re) = qr/<</;
1232 my($right_shift_operator_re) = qr/>>/;
1233 my($assignment_operator_re) = qr/(?<![=!<>+*\-\/%&|^])=(?!=)/;
1234 my($bitwise_and_assignment_operator_re) = qr/&=/;
1235 my($bitwise_or_assignment_operator_re) = qr/\|=/;
1236 my($bitwise_xor_assignment_operator_re) = qr/\^=/;
1237 my($addition_assignment_operator_re) = qr/\+=/;
1238 my($multiplication_assignment_operator_re) = qr/\*=/;
1239 my($subtraction_assignment_operator_re) = qr/-=/;
1240 my($division_assignment_operator_re) = qr/\/=/;
1241 my($modulus_assignment_operator_re) = qr/%=/;
1242 my($left_shift_assignment_operator_re) = qr/<<=/;
1243 my($right_shift_assignment_operator_re) = qr/>>=/;
1244 my($binop_core_re) = qr/(?<!operator)
1253 ${logical_and_operator_re}|
1254 ${logical_or_operator_re}|
1255 ${bitwise_and_operator_re}|
1256 ${bitwise_or_operator_re}|
1257 ${bitwise_xor_operator_re}|
1258 ${addition_operator_re}|
1259 ${multiplication_operator_re}|
1260 ${subtraction_operator_re}|
1261 ${division_operator_re}|
1262 ${modulus_operator_re}|
1263 ${left_shift_operator_re}|
1264 ${right_shift_operator_re}|
1265 ${assignment_operator_re}|
1266 ${bitwise_and_assignment_operator_re}|
1267 ${bitwise_or_assignment_operator_re}|
1268 ${bitwise_xor_assignment_operator_re}|
1269 ${addition_assignment_operator_re}|
1270 ${multiplication_assignment_operator_re}|
1271 ${subtraction_assignment_operator_re}|
1272 ${division_assignment_operator_re}|
1273 ${modulus_assignment_operator_re}|
1274 ${left_shift_assignment_operator_re}|
1275 ${right_shift_assignment_operator_re})/x;
1276 if (/\S${binop_core_re}\S/ || /\s${binop_core_re}\S/ || /\S${binop_core_re}\s/) {
1277 line_violation($file, "missing space around binary operator '$1'", $line);
1282 # Check for space around unary operators:
1284 # [space]<unary operator>[space]
1288 # - Logical negation operator: !
1289 # - Bitwise negation operator: ~
1290 # - Post- and prefix increment operator: ++
1291 # - Post- and prefix decrement operator: --
1293 if (check_warning("space-around-unary-operators")) {
1294 my($logical_negation_re) = qr/(!)\s+/;
1295 my($bitwise_negation_re) = qr/(~)\s+/;
1296 my($prefix_increment_re) = qr/(\+\+)\s+[[:alnum:]_(\[]/;
1297 my($postfix_increment_re) = qr/[[:alnum:]_)\]]\s+(\+\+)/;
1298 my($prefix_decrement_re) = qr/(--)\s+[[:alnum:]_(\[]/;
1299 my($postfix_decrement_re) = qr/[[:alnum:]_)\]]\s+(--)/;
1301 if (/${logical_negation_re}/ ||
1302 /${bitwise_negation_re}/ ||
1303 /${prefix_increment_re}/ ||
1304 /${postfix_increment_re}/ ||
1305 /${prefix_decrement_re}/ ||
1306 /${postfix_decrement_re}/) {
1307 line_violation($file, "space around unary operator '$1'", $line);
1312 # Search for implicit void function or method declarations:
1314 # [extern|static ][return type ][name]()[[const ][volatile ]];
1316 if (check_warning("implicit-void-declaration")) {
1317 if (is_implicit_void_function_or_method_declaration()) {
1318 line_violation($file, "implicit void declaration", $line);
1323 # Search for function or method implementations:
1325 # [static ][inline ][return type ][name](argument[, [argument]])[ [const ][volatile]]
1327 if (/((static|inline)\s)*([_A-Za-z]\w+)*(?!if|else|for|while|switch|return|sizeof)([_A-Za-z]\w+)\s*\(\s*.+\)\s*(?!;)(\s(const|volatile)\s)*/) {
1328 print("$file: $.: found a possible function implementation\n") if ($options{"debug"});
1329 $in_function_at_depth = $#bracestack + 1;
1332 # Match and push opening brace lines onto the brace parsing stack.
1335 print("$file: $.: encountered opening brace.\n") if ($options{"debug"});
1336 push(@bracestack, $line);
1339 # Increment the return count (ostensibly within the outermost function or
1340 # method scope) where return statements are encountered.
1342 if (/return\s*\(*.*\)*;/) {
1344 printf("$file: $.: Saw a return statement! Return count %u\n", $return_count) if ($options{"debug"});
1345 if (check_warning("multiple-returns") && ($return_count > 1)) {
1346 line_violation($file, "multiple return statements", $line);
1351 # Match and pop closing brace lines off of the brace parsing
1352 # stack, resetting the return statement count if we have exited
1353 # the current function or method scope.
1356 print("$file: $.: encountered closing brace.\n") if ($options{"debug"});
1358 if ($in_function_at_depth == $#bracestack + 1) {
1359 print("Probably out of function!\n") if ($options{"debug"});
1364 # Cache the last line and move onto the next line.
1369 if (!defined($state{"style-disable"}) || $state{"style-disable"} != 1) {
1370 # Check to make sure that the last line of the file contains a new
1371 # line (depends on the Perl execution environment and is stored in
1374 if (check_warning("missing-newline-at-eof")) {
1375 if ($neolchars == 0) {
1376 line_violation($file, "missing new line at the end of file", $line);
1381 # Check to make sure that the last line in the file is not blank
1383 if (check_warning("trailing-line")) {
1385 line_violation($file, "last line in file is blank", $line);
1390 # Check to make sure we saw a matching copyright declaration if
1393 if (check_warning("missing-copyright") && $saw_copyright != 1) {
1394 file_violation($file, "missing copyright declaration");
1399 return ($violations);
1406 # This routine performs the actual coding style checking for C source
1410 # file - Path name of the current input file being processed.
1421 # In the absence of any language-specific checks, just call cstyle...
1423 return (cstyle($file));
1430 # This routine performs the actual coding style checking for all language
1431 # independent checks and calls a handler for the specified language to
1432 # perform language-specific checks.
1435 # file - Path name of the current input file being processed.
1436 # language - Language-specific handler reference.
1446 my($language) = $_[1];
1447 my($eol, $handler, $status);
1449 # Identify whether or not a valid handler is registered for
1452 $handler = $handlers{$language};
1454 if (!defined($handler)) {
1455 printf(STDERR "%s: Unknown or unsupported language!\n", $language);
1459 # The EOL variable may get set (differently) from file to file when
1460 # the program is operating on multiple files. Save the initial EOL
1461 # marker and reset it on entry and exit, respectively. Failure to do
1462 # so, leads to interesting and incorrect program behavior when one
1463 # file has one line ending type (e.g DS) and the subsequent one
1464 # another (e.g. UNIX).
1468 $status = &{$handler}($file);
1482 my($useextensions) = 0;
1484 # Set the program name
1486 $program = basename($0);
1488 # Parse non-file program options from the command line
1492 # Determine whether or not a default language has been specified.
1493 # This is required when working from standard input; otherwise, the
1494 # language is determined file-by-file based on the extension.
1496 # If the language option is explicitly "none", then it is the same
1497 # as if it had not been defined at all.
1499 $language = $options{"language"};
1501 if (!defined($language) || ($language eq "none")) {
1505 # Work on each file specified on the command line. Otherwise, just
1506 # process standard input.
1509 SOURCEFILE: foreach $file (@ARGV) {
1511 if ($useextensions) {
1512 # Determine which parser/handler to use by mapping the
1513 # file extension. Extensions are split at the last dot (.)
1514 # in the extension, so "foo.c.N" yields ".N" and
1515 # "bar.tar.gz" yields ".gz" for extensions, respectively.
1517 my($extension) = (fileparse($file, qr(\.[^.]+)))[2];
1519 # Strip the dot off the beginning of the extension.
1521 $extension =~ s/^\.//;
1523 # Attempt to map the extension to a language through the
1526 $language = $extensions{$extension};
1528 if (!defined($language)) {
1529 printf(STDERR "%s: Unknown or unsupported file type!\n", $file);
1535 # Attempt to open the file
1537 if (!open(STDIN, $file)) {
1538 printf(STDERR "%s: Cannot open!\n", $file);
1543 # Style check the file, note the status and close the stream
1545 $status += style($file, $language);
1550 $status += style("<standard input>", $language);
1553 # If the caller invoked with '-Werror', return the accumulated
1554 # status; otherwise, return zero (0).
1556 exit($warnings{"error"} ? $status : 0);