1 #!/usr/bin/perl
   2 
   3 # Transform K&R C function definitions into ANSI equivalent.
   4 #
   5 # Author: Paul Marquess
   6 # Version: 1.0
   7 # Date: 3 October 2006
   8 
   9 # TODO
  10 #
  11 # Asumes no function pointer parameters. unless they are typedefed.
  12 # Assumes no literal strings that look like function definitions
  13 # Assumes functions start at the beginning of a line
  14 
  15 use strict;
  16 use warnings;
  17 
  18 local $/;
  19 $_ = <>;
  20 
  21 my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments
  22 
  23 my $d1    = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ;
  24 my $decl  = qr{ $sp (?: \w+ $sp )+ $d1 }xo ;
  25 my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ;
  26 
  27 
  28 while (s/^
  29             (                  # Start $1
  30                 (              #   Start $2
  31                     .*?        #     Minimal eat content
  32                     ( ^ \w [\w\s\*]+ )    #     $3 -- function name
  33                     \s*        #     optional whitespace
  34                 )              # $2 - Matched up to before parameter list
  35 
  36                 \( \s*         # Literal "(" + optional whitespace
  37                 ( [^\)]+ )     # $4 - one or more anythings except ")"
  38                 \s* \)         # optional whitespace surrounding a Literal ")"
  39 
  40                 ( (?: $dList )+ ) # $5
  41 
  42                 $sp ^ {        # literal "{" at start of line
  43             )                  # Remember to $1
  44         //xsom
  45       )
  46 {
  47     my $all = $1 ;
  48     my $prefix = $2;
  49     my $param_list = $4 ;
  50     my $params = $5;
  51 
  52     StripComments($params);
  53     StripComments($param_list);
  54     $param_list =~ s/^\s+//;
  55     $param_list =~ s/\s+$//;
  56 
  57     my $i = 0 ;
  58     my %pList = map { $_ => $i++ }
  59                 split /\s*,\s*/, $param_list;
  60     my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ;
  61 
  62     my @params = split /\s*;\s*/, $params;
  63     my @outParams = ();
  64     foreach my $p (@params)
  65     {
  66         if ($p =~ /,/)
  67         {
  68             my @bits = split /\s*,\s*/, $p;
  69             my $first = shift @bits;
  70             $first =~ s/^\s*//;
  71             push @outParams, $first;
  72             $first =~ /^(\w+\s*)/;
  73             my $type = $1 ;
  74             push @outParams, map { $type . $_ } @bits;
  75         }
  76         else
  77         {
  78             $p =~ s/^\s+//;
  79             push @outParams, $p;
  80         }
  81     }
  82 
  83 
  84     my %tmp = map { /$pMatch/;  $_ => $pList{$1}  }
  85               @outParams ;
  86 
  87     @outParams = map  { "    $_" }
  88                  sort { $tmp{$a} <=> $tmp{$b} }
  89                  @outParams ;
  90 
  91     print $prefix ;
  92     print "(\n" . join(",\n", @outParams) . ")\n";
  93     print "{" ;
  94 
  95 }
  96 
  97 # Output any trailing code.
  98 print ;
  99 exit 0;
 100 
 101 
 102 sub StripComments
 103 {
 104 
 105   no warnings;
 106 
 107   # Strip C & C++ coments
 108   # From the perlfaq
 109   $_[0] =~
 110 
 111     s{
 112        /\*         ##  Start of /* ... */ comment
 113        [^*]*\*+    ##  Non-* followed by 1-or-more *'s
 114        (
 115          [^/*][^*]*\*+
 116        )*          ##  0-or-more things which don't start with /
 117                    ##    but do end with '*'
 118        /           ##  End of /* ... */ comment
 119 
 120      |         ##     OR  C++ Comment
 121        //          ## Start of C++ comment //
 122        [^\n]*      ## followed by 0-or-more non end of line characters
 123 
 124      |         ##     OR  various things which aren't comments:
 125 
 126        (
 127          "           ##  Start of " ... " string
 128          (
 129            \\.           ##  Escaped char
 130          |               ##    OR
 131            [^"\\]        ##  Non "\
 132          )*
 133          "           ##  End of " ... " string
 134 
 135        |         ##     OR
 136 
 137          '           ##  Start of ' ... ' string
 138          (
 139            \\.           ##  Escaped char
 140          |               ##    OR
 141            [^'\\]        ##  Non '\
 142          )*
 143          '           ##  End of ' ... ' string
 144 
 145        |         ##     OR
 146 
 147          .           ##  Anything other char
 148          [^/"'\\]*   ##  Chars which doesn't start a comment, string or escape
 149        )
 150      }{$2}gxs;
 151 
 152 }