I have a C file in which we are moving the logging infrastructure. So
if ( logging_level >= LEVEL_FINE )
printf("Value at %p is %d\n", p, i);
becomes
do_log2(LEVEL_FINE, "Value at %p is %d\n", _ptr(p), _num(i));
do_log2 means log with 2 arguments.
So I need a C parsing and modification infrastructure to do this.
Which tool can I use to accomplish this most easily ?
Note: the printf can also appear in the file as :
if ( logging_level >= LEVEL_FINE )
{
printf("Value at %p is %d\n",
p,
i);
}
(indented and in a block). So this will be hard to do from simple text parsing in perl.
EDIT: This is my final perl code that does what I want
#!/usr/bin/perl -W
$source=<<'END';
include etc
if ( logging_level >= LEVEL_DEBUG )
{
printf("1:Value at %p is %d\n",
p(1),
i(2));
}
hello();
if ( logging_level >= LEVEL_FINE )
{
printf("2:Value is %d\n", i);
printf("3:Value is %d\n", i);
}
if ( logging_level >= LEVEL_FINE )
{
printf("2:Value is %d\n"
"and other info", i);
}
other();
if(logging_level>=LEVEL_INFO){printf("4:Value at %p is %d %d\n",p(x),i,j);}
if(logging_level>=LEVEL_FINE) printf("5:Just sayin\"\n");
printf("not logging statement\n").
END
while( $source =~ m/\G(.*?\n)\s* if \s* \( \s* logging_level \s* >= \s* ([A-Z_0-9]+) \s* \) \s*(\{?)/sgxc )
{
my $othercode = $1;
my $loglevel=$2;
my $inblock = $3;
print("$othercode");
while($source =~ m/\G\s*printf \( ([^;]*) \) \;/sgxc )
{
my $insideprint = $1;
unless ($insideprint =~ /((\"([^\"\\]|\\.)*\")(\s*(\"([^\"\\]|\\.)*\"))*)/g) #fixing stackoverflow quote problem "
{
die "First arg not string literal";
}
my $formatstr = $1;
my $remain = substr($insideprint, pos($insideprint));
$remain =~ tr/\n \t//d;
my @args = split(",", $remain);
shift @args;
my $numargs = @args;
print "do_log${numargs}($loglevel, $formatstr";
for (my $i=0; $i < $numargs; $i++)
{
unless ($formatstr =~ /%([a-z]+)/g)
{
die "Not enough format for args : $formatstr, args = ", join(",", @args), "\n";
}
my $lastchar = substr($1, length($1) -1);
my $wrapper = "";
if ($lastchar eq "u" || $lastchar eq "d")
{ $wrapper = "_numeric";}
elsif($lastchar eq "p"){ $wrapper = "_ptr";}
elsif($lastchar eq "s"){ $wrapper = "_str";}
else { die "Unknown format char %$lastchar in $formatstr"; }
print ", ${wrapper}($args[$i])";
}
print ");";
last unless ($inblock);
}
# eat trailing }
if ($inblock)
{
if ($source =~ m/\G \s* \} /sgxc)
{
}
else
{
}
}
}
#whatever is left
print substr($source, pos($source));
output:
include etc
do_log2(LEVEL_DEBUG, "1:Value at %p is %d\n", _ptr(p(1)), _numeric(i(2)));
hello();
do_log1(LEVEL_FINE, "2:Value is %d\n", _numeric(i));
do_log1(LEVEL_FINE, "3:Value is %d\n", _numeric(i));
do_log1(LEVEL_FINE, "2:Value is %d\n"
"and other info", _numeric(i));
other();
do_log3(LEVEL_INFO, "4:Value at %p is %d %d\n", _ptr(p(x)), _numeric(i), _numeric(j));
do_log0(LEVEL_FINE, "5:Just sayin\"\n");
printf("not logging statement\n").
Woohoo! Now to apply to actual source code.