web/drupal/scripts/code-style.pl
branchdrupal
changeset 74 0ff3ba646492
equal deleted inserted replaced
73:fcf75e232c5b 74:0ff3ba646492
       
     1 #!/usr/bin/perl -w
       
     2 # $Id: code-style.pl,v 1.14 2007/02/15 11:40:19 dries Exp $
       
     3 
       
     4 use Pod::Usage;
       
     5 use Getopt::Long qw(GetOptions);
       
     6 Getopt::Long::Configure ("bundling");
       
     7 
       
     8 my %opt = (  "help" => 0,
       
     9     'debug' => 0,
       
    10   );
       
    11 
       
    12 if(!GetOptions(\%opt,
       
    13     'help|?',
       
    14     'debug',
       
    15     )) {
       
    16   pod2usage(-exitval => 1, 'verbose'=>0);
       
    17 }
       
    18 
       
    19 pod2usage(-exitval => 0, -verbose => 2) if($opt{'help'});
       
    20 
       
    21 $debug = $opt{'debug'};
       
    22 
       
    23 $comment = 0; #flag used to signal we're inside /* */
       
    24 $program = 0; #flag used to signal we're inside <?php ?>
       
    25 #read the file
       
    26 while (<>) {
       
    27   $org=$_;
       
    28   s/\\["']//g;
       
    29   # please don't use nested comments for now... thanks!
       
    30   # handles comments // style, but don't mess with http://
       
    31   s/\/\/[^:].*//;
       
    32   # handles comments /**/ on a single line
       
    33   s/\/\*.*\*\///g;
       
    34   # handles comments /**/ over several lines
       
    35   if ($comment == 1) {
       
    36     if (s/.*\*\///) {
       
    37       $comment = 0;
       
    38     }
       
    39     else {
       
    40       next;
       
    41     }
       
    42   }
       
    43   if (s/\/\*.*//) {
       
    44     $comment = 1;
       
    45   }
       
    46   if (/^\s*#/) {
       
    47     next;
       
    48   }
       
    49 
       
    50   if (s/<\?php//) {
       
    51     $program = 1;
       
    52   }
       
    53   if (/\?>/) {
       
    54     $program = 0;
       
    55   }
       
    56 
       
    57   # enforce "bar". foo() ."bar" syntax
       
    58   if (/^("[^"]*"|[^"])*("[^"]*")\.[^ ]/ && $program) {
       
    59     $msg = "'\".' -> '\". '";
       
    60   }
       
    61   elsif (/^("[^"]*"|[^"])*("[^"]*")\s+\./ && $program) {
       
    62     $msg = "'\" .' -> '\".'";
       
    63   }
       
    64   # enforce "bar". foo() ."bar" syntax
       
    65   elsif (/^("[^"]*"|[^"])*[^ "]\.("[^"]*")/ && $program) {
       
    66     $msg = "'.\"' -> '.\"'";
       
    67   }
       
    68   elsif (/^("[^"]*"|[^"])*[^ "]\.\s+("[^"]*")/ && $program) {
       
    69     $msg = "'. \"' -> '.\"'";
       
    70   }
       
    71   # XHTML requires closing tag
       
    72   elsif (/<br>/i) {
       
    73     $msg = "'<br>' -> '<br />'";
       
    74   }
       
    75   elsif (/\$REQUEST_URI/i) {
       
    76     $msg = "the use of REQUEST_URI is prone to XSS exploits and does not work on IIS; use request_uri() instead";
       
    77   }
       
    78   elsif (/\"REQUEST_URI\"/i) {
       
    79     $msg = "the use of REQUEST_URI is prone to XSS exploits and does not work on IIS; use request_uri() instead";
       
    80   }
       
    81 
       
    82   # XHTML compatibility mode suggests a blank before /
       
    83   # i.e. <br />
       
    84   elsif (/<[a-z][^>]*[^ >]\/>/i) {
       
    85     $msg = "'<foo/".">' -> '<foo />'";
       
    86   }
       
    87   # we write '{' on the same line, not on the next
       
    88   elsif (/^\s*{/ && $program) {
       
    89     $msg = "take '{' to previous line";
       
    90   }
       
    91   elsif (/([a-z])([A-Z])/) {
       
    92     $msg = "no mixed case function or variable names, use lower case and _";
       
    93   }
       
    94   elsif (/<[\/]*[A-Z]+[^>]*>/) {
       
    95     $msg = "XHTML demands tags to be lowercase";
       
    96   }
       
    97 
       
    98   # trying to recognize splitted lines
       
    99   # there are only a few valid last characters in programming mode,
       
   100   # only sometimes it is ( if you use if/else with a single statement
       
   101 
       
   102   # from here on we need no more strings
       
   103   while (s/^([^"]*)"[^"]*"/$1#/) {};
       
   104   while (s/^([^']*)'[^']*'/$1#/) {};
       
   105 
       
   106   # it should be 'if (' all the time
       
   107   if (/(^|[^a-zA-Z])(if|else|elseif|while|foreach|switch|return|for)\(/) {
       
   108     $msg = "'(' -> ' ('";
       
   109   }
       
   110   #elsif (/[^;{}:\s\n]\s*\n*$/ && $program && !/^[\s}]*(if|else)/) {
       
   111   #  $msg = "don't split lines";
       
   112   #}
       
   113   elsif (/\}\s*else/) {
       
   114     $msg = "'} else' -> '}\\nelse'";
       
   115   }
       
   116   elsif (/[^{\s\n]\s*\n*$/ && $program && /^\s*(if|else)/) {
       
   117     $msg = "every if/else needs a { at eol";
       
   118   }
       
   119   elsif (/([\(\[]) / && $program) {
       
   120     $msg = "'$1 ' -> '$1'";
       
   121   }
       
   122   elsif (/\S ([\)\]])/ && $program) {
       
   123     $msg = "' $1' -> '$1'";
       
   124   }
       
   125   # but no brackets
       
   126   elsif (/([a-z-A-Z_][a-zA-Z0-9_-]*)\s+\(/ && $program) {
       
   127     if ($1 ne "switch" and $1 ne "if" and $1 ne "while" and $1 ne "foreach" and $1 ne "return" and $1 ne "for" and $1 ne "elseif") {
       
   128       $msg = "'$1 (' -> '$1('";
       
   129     }
       
   130   }
       
   131   # there should be a space before '{'
       
   132   if (/[^ ]{/ && $program) {
       
   133     $msg = "missing space before '{'";
       
   134   }
       
   135   # there should be a space after ','
       
   136   elsif (/[,][^ \n\r]/ && $program) {
       
   137     $msg = "missing space after ','";
       
   138   }
       
   139   # spaces before and after, only foreach may use $foo=>bar
       
   140   elsif (/[^ =|\-|\+](\+|\-)[^ =>|\-|\+]/ && $program && !/foreach/) {
       
   141     $msg = "'$1' -> ' $1 '";
       
   142   }
       
   143   elsif (/[^ =](\*|==|\.=|=>|=|\|\|)[^ =>]/ && $program && !/foreach/) {
       
   144     $msg = "'$1' -> ' $1 '";
       
   145   }
       
   146   # ensure $bar["foo"] and $bar[$foo] and $bar[0]
       
   147   elsif (/\[[^#][^\]]*\]/ && !/\[[0-9\$][^\]]*\]/ && !/\[\]/) {
       
   148     $msg = "only [\"foo\"], [\$foo] or [0] is allowed";
       
   149   }
       
   150   # first try to find missing quotes after = in (X)HTML tags
       
   151   elsif (/<[^>]*=[a-zA-Z0-9][^>]*>/) {
       
   152     $msg = "=... -> =\"...\"";
       
   153   }
       
   154   if (defined $msg) {
       
   155     if ($debug==0) {
       
   156       print $ARGV .":". $. .": $msg : ". $org;
       
   157     }
       
   158     undef $msg;
       
   159   }
       
   160   elsif ($debug==1) {
       
   161     print $org;
       
   162   }
       
   163 } continue {
       
   164   close ARGV if eof;
       
   165 }
       
   166 
       
   167 __END__
       
   168 
       
   169 =head1 NAME
       
   170 
       
   171 code-style.pl - Review drupal code for style
       
   172 
       
   173 =head1 SYNOPSIS
       
   174 
       
   175   code-style.pl [options] <filename>
       
   176 
       
   177   Options:
       
   178 
       
   179   -? --help  detailed help message
       
   180 
       
   181 =head1 DESCRIPTION
       
   182 
       
   183 Originally written for Drupal (http://drupal.org/) to ensure stylish
       
   184 code.  This program reviews PHP code, and tries to show as many code
       
   185 improvements as possible with no false positives.
       
   186 
       
   187 =head1 OPTIONS
       
   188 
       
   189   --comment
       
   190 
       
   191 =head1 EXAMPLES
       
   192 
       
   193  ./code-style.pl ../index.php
       
   194 
       
   195 =cut