1#!/usr/bin/perl 2 3# mksigs.pl - extract signatures from C headers 4# 5# Copyright (C) Michael Adam 2009 6# 7# This program is free software; you can redistribute it and/or modify it 8# under the terms of the GNU General Public License as published by the Free 9# Software Foundation; either version 3 of the License, or (at your option) 10# any later version. 11# 12# This program is distributed in the hope that it will be useful, but WITHOUT 13# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15# more details. 16# 17# You should have received a copy of the GNU General Public License along with 18# this program; if not, see <http://www.gnu.org/licenses/>. 19 20# USAGE: cat $header_files | mksigs.pl > $signature_file 21# 22# The header files to parse are read from stdin. 23# The output is in a form as produced by gcc with the -aux-info switch 24# and printed to stdout. 25 26use strict; 27use warnings; 28 29my $in_comment = 0; 30my $extern_C_block = 0; 31 32while (my $LINE = <>) { 33 # find end of started multi-line-comment 34 if ($in_comment) { 35 if ($LINE =~ /^.*?\*\/(.*)$/) { 36 $LINE = $1; 37 $in_comment = 0; 38 } else { 39 # whole line within comment 40 next; 41 } 42 } 43 44 # strip C++-style comments 45 $LINE =~ s/^(.*?)\/\/.*$/$1/; 46 47 # strip in-line-comments: 48 while ($LINE =~ /\/\*.*?\*\//) { 49 $LINE =~ s/\/\*.*?\*\///; 50 } 51 52 # find starts of multi-line-comments 53 if ($LINE =~ /^(.*)\/\*/) { 54 $in_comment = 1; 55 $LINE = $1; 56 } 57 58 # skip empty lines 59 next if $LINE =~ /^\s*$/; 60 61 # remove leading spaces 62 $LINE =~ s/^\s*(.*)$/$1/; 63 64 # concatenate lines split with "\" (usually macro defines) 65 while ($LINE =~ /^(.*?)\s+\\$/) { 66 my $LINE2 = <>; 67 $LINE = $1; 68 $LINE2 =~ s/^\s*(.*)$/$1/; 69 $LINE .= " " . $LINE2; 70 } 71 72 # remove all preprocessor directives 73 next if ($LINE =~ /^#/); 74 75 if ($LINE =~ /^extern\s+"C"\s+\{/) { 76 $extern_C_block = 1; 77 next; 78 } 79 80 if (($LINE =~ /^[^\{]*\}/) and $extern_C_block) { 81 $extern_C_block = 0; 82 next; 83 } 84 85 $LINE =~ s/^extern\s//; 86 87 # concatenate braces stretched over multiple lines 88 # (from structs or enums) 89 my $REST = $LINE; 90 my $braces = 0; 91 while (($REST =~ /[\{\}]/) or ($braces)) { 92 while ($REST =~ /[\{\}]/) { 93 # collect opening 94 while ($REST =~ /^[^\{\}]*\{(.*)$/) { 95 $braces++; 96 $REST = $1; 97 } 98 99 # collect closing 100 while ($REST =~ /^[^\{\}]*\}(.*)$/) { 101 $braces--; 102 $REST = $1; 103 } 104 } 105 106 # concatenate if not balanced 107 if ($braces) { 108 if (my $LINE2 = <>) { 109 $LINE2 =~ s/^\s*(.*)$/$1/; 110 chomp($LINE); 111 $LINE .= " " . $LINE2; 112 chomp $REST; 113 $REST .= " " . $LINE2; 114 } else { 115 print "ERROR: unbalanced braces ($braces)\n"; 116 last; 117 } 118 } 119 } 120 121 # concetenate function prototypes that stretch over multiple lines 122 $REST = $LINE; 123 my $parenthesis = 0; 124 while (($REST =~ /[\(\)]/) or ($parenthesis)) { 125 while ($REST =~ /[\(\)]/) { 126 # collect opening 127 while ($REST =~ /^[^\(\)]*\((.*)$/) { 128 $parenthesis++; 129 $REST = $1; 130 } 131 132 # collect closing 133 while ($REST =~ /^[^\(\)]*\)(.*)$/) { 134 $parenthesis--; 135 $REST = $1; 136 } 137 } 138 139 # concatenate if not balanced 140 if ($parenthesis) { 141 if (my $LINE2 = <>) { 142 $LINE2 =~ s/^\s*(.*)$/$1/; 143 chomp($LINE); 144 $LINE .= " " . $LINE2; 145 chomp($REST); 146 $REST .= " " . $LINE2; 147 } else { 148 print "ERROR: unbalanced parantheses ($parenthesis)\n"; 149 last; 150 } 151 } 152 } 153 154 next if ($LINE =~ /^typedef\s/); 155 next if ($LINE =~ /^enum\s+[^\{\(]+\s+\{/); 156 next if ($LINE =~ /^struct\s+[^\{\(]+\s+\{.*\}\s*;/); 157 next if ($LINE =~ /^struct\s+[a-zA-Z0-9_]+\s*;/); 158 159 # remove trailing spaces 160 $LINE =~ s/(.*?)\s*$/$1/; 161 162 $LINE =~ s/^(.*\))\s+PRINTF_ATTRIBUTE\([^\)]*\)(\s*[;,])/$1$2/; 163 $LINE =~ s/^(.*\))\s*[a-zA-Z0-9_]+\s*;$/$1;/; 164 165 # remove parameter names - slightly too coarse probably 166 $LINE =~ s/([\s\(]\*?)[_0-9a-zA-Z]+\s*([,\)])/$1$2/g; 167 168 # remedy (void) from last line 169 $LINE =~ s/\(\)/(void)/g; 170 171 # normalize spaces 172 $LINE =~ s/\s*\)\s*/)/g; 173 $LINE =~ s/\s*\(\s*/ (/g; 174 $LINE =~ s/\s*,\s*/, /g; 175 176 # normalize unsigned 177 $LINE =~ s/([\s,\(])unsigned([,\)])/$1unsigned int$2/g; 178 179 # normalize bool 180 $LINE =~ s/(\b)bool(\b)/_Bool/g; 181 182 print $LINE . "\n"; 183} 184