#!/usr/bin/perl # Program to automatically update .h files from .cc file # For more info, see headergen.txt use strict; my $QTDIR=$ENV{'QTDIR'}; my $cppflags="-I$QTDIR/include -D__GNUC__"; #preprocessor flags my $file_count=0; # refresh one header sub refresh { my ($name)=@_; # Base name without extension my $wmessage="Parsing $name"; my @fn=(); my $f_c=$name.".cc"; # Name of .cc file my $f_h=$name.".h"; # Name of .h file my $realname=''; # Name of class with proper capitalization my $mark="__".uc($f_h)."__"; $mark=~s/\./_/g; # Open C++ file # open FC, "cpp $f_c $cppflags|"; #use preprocessor to strip comments etc ... open FC, "cat $f_c|"; #do not use preprocessor while (my $line=) { next if ($line=~/^\s*$/); # Empty line next if ($line=~/^#/); # Line with preprocessor directive if ($line=~/\/\*\*/) { # Line contain /** style doxygen comment while (!($line=~/\*\//)) { # Read until first "*/" comment end my $lw=; $line.=$lw; last if ($lw eq ''); # End of file } $line=~s/\/\*\*[\x00-\xff]*?\*\///mg; # Weed the comment out } $line=~s/^\s+//g; if ($line=~/(^|\s)${name}::/i) { # Line contain class name (assuming filename=classname, except for case) while (!($line=~/\{/)) { # Read until first "{" bracket my $lw=; $line.=$lw; last if ($lw eq ''); # End of file } $line=~s/\n/ /mg; # Newlines to space $line=~s/\s*\{.*\s*//g; # strip bracket { $line.=';'; # Append semicolon ; $line=~/::(~?\w+)/; # get name of method my $func=$1; # Name of method if ($line=~s/(${name}):://i) { $realname=$1; # Set correct name of class when we found it } # Convert commented initializers ( "/*=something*/" --> "=something" ) $line=~s|\s*/\*=\s*(.*?)\*/\s*|=\1|g; # Strip out calling of superclass constructor(s) "X() : Y();" -> "X();" # up to one extra level of brackets can occur in calling of constructor, like "X(x):Y(f(x))" $line=~s/([^:])\s*:\s*[a-zA-Z_][a-zA-Z_0-9]*\s*\(([^()]*|\([^()]*\))*\)(\s*,\s*[a-zA-Z_][a-zA-Z_0-9]*\s*\(([^()]*|\([^()]*\))*\))*\s*;$/\1;/; # Remove "unused" attribute $line=~s/__attribute__\(\(unused\)\)\s*//g; # Add to line with functions found push @fn,$line; # print $func." -> ".$line."\n"; } } close FC; $file_count++; if (!@fn) { #nothing that can be added to headers in this file -> return print "$wmessage .. no headers\n"; return; } $wmessage.="\n"; # Open header file open FH, "<$f_h"; my $head=''; my $head_h=''; while (my $line=) { $head.=$line; # Look for class definition if ($line=~/class\s+$name(\s+|:|$)/i) { #split the content into two pieces ("before class definition" and "inside class definition and further") $head_h=$head;$head=''; } } if ($head_h=~/^$/) { # No class defined in header -> create one $head_h="$head\n\nclass $realname {\n"; $head="};\n"; } close FH; my $added=0; my $addedh=0; # Look for include guards if (!($head_h=~/$mark/)) { $head_h="#ifndef $mark\n#define $mark\n".$head_h; $head.="#endif\n"; $addedh=1; } my $out=''; $out.=$head_h; # For each function found in .cc file foreach my $i (@fn) { # Is present in header? my $idx=0; my $c=''; for(;;) { $idx=index($head,$i,$idx); last if ($idx<=0); #check for character before definition -> must be whitespace $c=substr($head,$idx-1,1); if ($c=~/\S/) { #non-whitespace -> Invalid match my $idxo=$idx; $idx=index($head,$i,$idx+1); last if ($idx<=0); next; } last; } if ($idx==-1) { if (!$added) {$out.="//ADDED functions begin\n";} $out.=" $i\n";$added++; } } if ($added) {$out.="//ADDED functions end\n";} $out.=$head; # Write modifications, if any ... if ($added || $addedh) { if ($added) { print "$wmessage (added $added function(s) to $f_h)\n"; $wmessage='';} if ($addedh) { print "$wmessage (added include guards to $f_h)\n"; $wmessage='';} # Backup the original file rename($f_h,$f_h.".old"); # Write modified header file open FH, ">$f_h"; binmode FH; print FH $out; close FH; } } my @ignore=(); open IGN, "<.headergen.ignore"; while (my $l=){ $l=~s/^\s+//mg; $l=~s/\s+$//mg; push @ignore,$l; } my $ign=join('|',@ignore); #print "Ignoring: $ign\n"; close IGN; opendir (DH,".") || die "Cannot open current directory"; while (my $s=readdir(DH)) { if ($ign=~/./ && $s=~/$ign/) { # print "Ignoring $s\n"; next; } next if (!($s=~/(.*)\.cc$/i)); refresh($1); } print "Parsed $file_count file(s)\n"; closedir DH;