1#!/usr/local/bin/perl 2 3my $ignore_re = '^(' . join("|", 4 qw( 5 _ 6 [a-z] 7 DBM 8 DBC 9 DB_AM_ 10 DB_BT_ 11 DB_RE_ 12 DB_HS_ 13 DB_FUNC_ 14 DB_DBT_ 15 DB_DBM 16 DB_TSL 17 MP 18 TXN 19 DB_TXN_GETPGNOS 20 )) . ')' ; 21 22my %ignore_def = map {$_, 1} qw() ; 23 24%ignore_enums = map {$_, 1} qw( ACTION db_status_t db_notices db_lockmode_t ) ; 25 26my %ignore_exact_enum = map { $_ => 1} 27 qw( 28 DB_TXN_GETPGNOS 29 ); 30 31my $filler = ' ' x 26 ; 32 33chdir "libraries" || die "Cannot chdir into './libraries': $!\n"; 34 35foreach my $name (sort tuple glob "[2-9]*") 36{ 37 next if $name =~ /(NC|private)$/; 38 39 my $inc = "$name/include/db.h" ; 40 next unless -f $inc ; 41 42 my $file = readFile($inc) ; 43 StripCommentsAndStrings($file) ; 44 my $result = scan($name, $file) ; 45 print "\n\t#########\n\t# $name\n\t#########\n\n$result" 46 if $result; 47} 48exit ; 49 50 51sub scan 52{ 53 my $version = shift ; 54 my $file = shift ; 55 56 my %seen_define = () ; 57 my $result = "" ; 58 59 if (1) { 60 # Preprocess all tri-graphs 61 # including things stuck in quoted string constants. 62 $file =~ s/\?\?=/#/g; # | ??=| #| 63 $file =~ s/\?\?\!/|/g; # | ??!| || 64 $file =~ s/\?\?'/^/g; # | ??'| ^| 65 $file =~ s/\?\?\(/[/g; # | ??(| [| 66 $file =~ s/\?\?\)/]/g; # | ??)| ]| 67 $file =~ s/\?\?\-/~/g; # | ??-| ~| 68 $file =~ s/\?\?\//\\/g; # | ??/| \| 69 $file =~ s/\?\?</{/g; # | ??<| {| 70 $file =~ s/\?\?>/}/g; # | ??>| }| 71 } 72 73 while ( $file =~ /^\s*#\s*define\s+([\$\w]+)\b(?!\()\s*(.*)/gm ) 74 { 75 my $def = $1; 76 my $rest = $2; 77 my $ignore = 0 ; 78 79 $ignore = 1 if $ignore_def{$def} || $def =~ /$ignore_re/o ; 80 81 # Cannot do: (-1) and ((LHANDLE)3) are OK: 82 #print("Skip non-wordy $def => $rest\n"), 83 84 $rest =~ s/\s*$//; 85 #next if $rest =~ /[^\w\$]/; 86 87 #print "Matched $_ ($def)\n" ; 88 89 next if $before{$def} ++ ; 90 91 if ($ignore) 92 { $seen_define{$def} = 'IGNORE' } 93 elsif ($rest =~ /"/) 94 { $seen_define{$def} = 'STRING' } 95 else 96 { $seen_define{$def} = 'DEFINE' } 97 } 98 99 foreach $define (sort keys %seen_define) 100 { 101 my $out = $filler ; 102 substr($out,0, length $define) = $define; 103 $result .= "\t$out => $seen_define{$define},\n" ; 104 } 105 106 while ($file =~ /\btypedef\s+enum\s*{(.*?)}\s*(\w+)/gs ) 107 { 108 my $enum = $1 ; 109 my $name = $2 ; 110 my $ignore = 0 ; 111 112 $ignore = 1 if $ignore_enums{$name} ; 113 114 #$enum =~ s/\s*=\s*\S+\s*(,?)\s*\n/$1/g; 115 $enum =~ s/^\s*//; 116 $enum =~ s/\s*$//; 117 118 my @tokens = map { s/\s*=.*// ; $_} split /\s*,\s*/, $enum ; 119 my @new = grep { ! $Enums{$_}++ } @tokens ; 120 if (@new) 121 { 122 my $value ; 123 if ($ignore) 124 { $value = "IGNORE, # $version" } 125 else 126 { $value = "'$version'," } 127 128 $result .= "\n\t# enum $name\n"; 129 my $out = $filler ; 130 foreach $name (@new) 131 { 132 next if $ignore_exact_enum{$name} ; 133 $out = $filler ; 134 substr($out,0, length $name) = $name; 135 $result .= "\t$out => $value\n" ; 136 } 137 } 138 } 139 140 return $result ; 141} 142 143 144sub StripCommentsAndStrings 145{ 146 147 # Strip C & C++ coments 148 # From the perlfaq 149 $_[0] =~ 150 151 s{ 152 /\* ## Start of /* ... */ comment 153 [^*]*\*+ ## Non-* followed by 1-or-more *'s 154 ( 155 [^/*][^*]*\*+ 156 )* ## 0-or-more things which don't start with / 157 ## but do end with '*' 158 / ## End of /* ... */ comment 159 160 | ## OR C++ Comment 161 // ## Start of C++ comment // 162 [^\n]* ## followed by 0-or-more non end of line characters 163 164 | ## OR various things which aren't comments: 165 166 ( 167 " ## Start of " ... " string 168 ( 169 \\. ## Escaped char 170 | ## OR 171 [^"\\] ## Non "\ 172 )* 173 " ## End of " ... " string 174 175 | ## OR 176 177 ' ## Start of ' ... ' string 178 ( 179 \\. ## Escaped char 180 | ## OR 181 [^'\\] ## Non '\ 182 )* 183 ' ## End of ' ... ' string 184 185 | ## OR 186 187 . ## Anything other char 188 [^/"'\\]* ## Chars which doesn't start a comment, string or escape 189 ) 190 }{$2}gxs; 191 192 193 194 # Remove double-quoted strings. 195 #$_[0] =~ s#"(\\.|[^"\\])*"##g; 196 197 # Remove single-quoted strings. 198 #$_[0] =~ s#'(\\.|[^'\\])*'##g; 199 200 # Remove leading whitespace. 201 $_[0] =~ s/\A\s+//m ; 202 203 # Remove trailing whitespace. 204 $_[0] =~ s/\s+\Z//m ; 205 206 # Replace all multiple whitespace by a single space. 207 #$_[0] =~ s/\s+/ /g ; 208} 209 210 211sub readFile 212{ 213 my $filename = shift ; 214 open F, "<$filename" || die "Cannot open $filename: $!\n" ; 215 local $/ ; 216 my $x = <F> ; 217 close F ; 218 return $x ; 219} 220 221sub tuple 222{ 223 my (@a) = split(/\./, $a) ; 224 my (@b) = split(/\./, $b) ; 225 if (@a != @b) { 226 my $diff = @a - @b ; 227 push @b, (0 x $diff) if $diff > 0 ; 228 push @a, (0 x -$diff) if $diff < 0 ; 229 } 230 foreach $A (@a) { 231 $B = shift @b ; 232 $A == $B or return $A <=> $B ; 233 } 234 return 0; 235} 236 237__END__ 238 239