[EMAIL PROTECTED] writes:
> Yeah, but WHY? Obviously Greg had too much time on his hands...
Because it was there.
Anyways, here's my contribution to this type of zaniness.
--kevin
PS I wrote this because I *didn't* have enough time on my hands.
#!/usr/bin/perl
# Author: Kevin D. Clark ([EMAIL PROTECTED])
# Description: replaces old C-style sprintf() code with newer C++
# string-stream code (this greatly increases type safety)
# Motivation: A colleague of mine left a body of code for me to maintain.
# This body consisted of tens of thousands of lines of code.
# Unfortunately, she assumed that "all the world's a 32-bit SPARC",
# and when we had to port this code to other architectures all
# of her calls to sprintf() (over 1500 in all) blew up. Faced with
# the tedious task of fixing this code, I wrote this.
# Warning: Caveat Programmer!
# Assumptions and Shortcomings:
# I assume that people are using sprintf() in a legal way.
# Hopefully not too many people do stuff like: foo(a, b, (c, d), e);
# Bug: Hopefully not too many people do stuff like: foo(a, b, ",c", d);
# (I don't think that this is very common in the case of sprintf())
# Design problem: I don't see a great way to get string-streams to
# handle things like "%.5s" and "%g". (sigh)
# (4/10/97) Actually, now I do see how to handle things like %.5s".
# As soon as I get un-busy, I plan on adding support for this.
# I could hack this to handle non-pathological cases in which comments were
# embedded in the actual call to sprintf(), but this would make this much more
# complex and I don't think that there enough cases of this to warrent the
# additional work necessary.
# Bug: If the call to sprintf() is commented out like:
# // sprintf(...) things tend to die quickly.
# Bug: if you do something like this, you're screwed:
#
# sprintf(str, (newVal > 1.0) ? "%.1lf" : "%.4lf", newVal);
#
# I don't plan on fixing this one.... (-:
# Bug: the size of the character array is static.
# TODO: \n -> endl
#
# warn about the bogus %lf conversion
#
# make the trailing semicolon disappear
#
# warn about long doubles -- the HP C++ compiler comes with an
# ostream class that doesn't handle this type (duh!)
#
# make this program handle fprintf() and printf() too.
#
# convert this to use the new C++ Standard Library iostreams
#######################################################################
# Example:
#
# (this example is a wee-bit pathological)
#
# $ cat foo.cc
#
# #include <iostream.h>
# #include <stdio.h>
#
# int main()
# {
# char buf[100];
# double foo=1;
# int bar=2;
#
# sprintf(buf,
#
# "%-2.f\"%%\n%d",
#
# foo,
#
# bar);
#
#
# cout << buf << endl;
# }
# $ replace-sprintf.pl < foo.cc
#
# #include <iostream.h>
# #include <stdio.h>
# #include <iostream.h>
# #include <iomanip.h>
# #include <strstream.h>
# #include <string.h>
#
# int main()
# {
# char buf[100];
# double foo=1;
# int bar=2;
# { // replacement for sprintf() code
# char tempBuf[256];
# ostrstream tempStream(tempBuf, sizeof tempBuf);
# tempStream.setf(ios::left,ios::adjustfield);
# tempStream << setw(2)
# << setprecision(0)
# << (double) foo
# << "\"";
# tempStream.setf(ios::right,ios::adjustfield);
# tempStream << setw(0)
# << "%\n"
# << bar
# << ends;
# strcpy(buf, tempBuf);
# };
#
#
# cout << buf << endl;
# }
# $
#######################################################################
# Last caveat: I wrote this on a bet and I wrote it rather quickly....
require 5;
$tempBufSize=256;
$w = ' ' x length(q(tempStream <<));
$replace=q#
my $whole = $&;
my $cannotDo = 0;
my $space;
($space=$1) =~ y/\012//d;
my $to = $2;
my $rest = $5;
my $format, $result;
my $ignoreFirst = 0;
($format = "$3$4") =~ s/"$//;
$result = "${space}tempStream";
if ( $format =~ /%-?\d+\.?s/
|| $format =~ /%-?\.?\d+s/
|| $format =~ /%-?\d+\.?\d+s/) {
$cannotDo = 1;
warn "$ARGV: warning: unable to handle a complex sprintf() (no change made)\n";
}
if (! $format =~ /%/) {
$result .= $format;
}
else {
$index = 0;
$bare = 1;
$format =~ s/%%/%@/g;
if (! ($format =~ /^%/)) {
$ignoreFirst = 1;
}
@f = split(/%/, $format);
$rest =~ y/\012//d;
@rest = split(/,/, $rest);
foreach $spec (@f) {
if ($ignoreFirst) {
$ignoreFirst = 0;
$result .= " << \"$spec\"\n${space}${w}";
}
elsif ($spec =~ /^@/) {
$spec =~ s/^.//;
$result .= " << \"%$spec\"\n${space}${w}";
$index--;
}
elsif ($spec =~ /^-/) {
$spec =~ s/^.//;
$leftJust = 1;
if (!$bare) {
$result .= ";\n${space}${w}tempStream";
}
$result .= ".setf(ios::left,ios::adjustfield);\n${space} tempStream";
redo;
}
elsif ($spec =~ /^\+/) {
$spec =~ s/^.//;
}
elsif ($spec =~ /^0/) {
$spec =~ s/^.//;
$zeroPad = 1;
$bare = 0;
$result .= " << setfill('0')\n${space}${w}";
redo;
}
elsif ($spec =~ /^\#/) {
$spec =~ s/^.//;
}
elsif ($spec =~ /^\ /) {
$spec =~ s/^.//;
}
elsif ($spec =~ /^([1-9]+)/) {
$width = $1;
$bare = 0;
$result .= " << setw($width)\n${space}${w}";
$spec =~ s/^[1-9]+//;
redo;
}
elsif ($spec =~ /^\.(\d*)/) {
$bare = 0;
if ($1) {
$precisionFlag = 1;
$precision = $1;
}
else {
$precision = 0;
}
$result .= " << setprecision($precision)\n${space}${w}";
$spec =~ s/^\.[1-9]*//;
redo;
}
elsif ($spec =~ /^l/i) {
$sizeSpec = "(long)";
$spec =~ s/^l//i;
redo;
}
elsif ($spec =~ /^h/) {
$sizeSpec = "(short)";
$spec =~ s/^h//;
redo;
}
elsif ($spec =~ /^[di]/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
$result .= " << $sizeSpec$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^u/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec) {
$sizeSpec =~ s/\(/\(unsigned /;
}
else {
$sizeSpec = "(unsigned)";
}
$result .= " << $sizeSpec$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^o/) {
$spec =~ s/^.//;
$bare = 0;
$result .= "<< setfill('0')";
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec) {
$sizeSpec =~ s/\(/\(unsigned /;
}
else {
$sizeSpec = "(unsigned)";
}
$result .= " << oct << $sizeSpec$rest[$index] << dec\n${space}${w}";
$result .= " << setfill(' ') << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^x/) {
$spec =~ s/^.//;
$bare = 0;
$result .= "<< setfill('0')";
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec) {
$sizeSpec =~ s/\(/\(unsigned /;
}
else {
$sizeSpec = "(unsigned)";
}
$result .= " << hex << $sizeSpec$rest[$index] << dec\n${space}${w}";
$result .= "<< setfill(' ') << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^X/) {
print STDERR "Warning: $ARGV: %X not supported correctly!\n";
$spec =~ s/^.//;
$bare = 0;
$result .= "<< setfill('0')";
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec) {
$sizeSpec =~ s/\(/\(unsigned /;
}
else {
$sizeSpec = "(unsigned)";
}
$result .= " << hex << $sizeSpec$rest[$index] << dec\n${space}${w}";
$result .= "<< setfill(' ') << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^c/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
$result .= " << (unsigned char)$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^s/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
$result .= " << (const char *)$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^p/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
$result .= " << (void *)$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^n/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec) {
$sizeSpec =~ s/\)/ *)/;
}
else {
$sizeSpec = "(int *)";
}
$result .= " << $sizeSpec$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^f/) {
$spec =~ s/^.//;
$bare = 0;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec eq "(long)") {
$sizeSpec = "(long double)";
}
elsif ($sizeSpec eq "") {
$sizeSpec = "(double)";
}
else {
print STDERR
"WARNING: $ARGV: there is no such thing as a short double (%hf)!\n";
$result .=
"WARNING: there is no such thing as a short double (%hf)!\n";
}
$result .= " << $sizeSpec$rest[$index]\n${space}${w}";
$result .= " << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^e/) {
$spec =~ s/^.//;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec eq "(long)") {
$sizeSpec = "(long double)";
}
elsif ($sizeSpec eq "") {
$sizeSpec = "(double)";
}
else {
print STDERR
"WARNING: $ARGV: there is no such thing as a short double (%hf)!\n";
$result .=
"WARNING: there is no such thing as a short double (%hf)!\n";
}
if (!$bare) {
$result .= ";\n${space} tempStream";
}
$result .= ".setf(ios::scientific,ios::floatfield);\n${space}";
$result .= " tempStream << $sizeSpec$rest[$index];\n${space}";
$result .= " tempStream.setf(ios::fixed,ios::floatfield);\n${space}";
$result .= " tempStream << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^E/) {
print STDERR "$ARGV: warning: %E conversion not handled correctly!\n";
$spec =~ s/^.//;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec eq "(long)") {
$sizeSpec = "(long double)";
}
elsif ($sizeSpec eq "") {
$sizeSpec = "(double)";
}
else {
print STDERR
"WARNING: $ARGV: there is no such thing as a short double (%hf)!\n";
$result .=
"WARNING: there is no such thing as a short double (%hf)!\n";
}
if (!$bare) {
$result .= ";\n${space} tempStream";
}
$result .= ".setf(ios::scientific,ios::floatfield);\n${space}";
$result .= " tempStream << $sizeSpec$rest[$index];\n${space}";
$result .= " tempStream.setf(ios::fixed,ios::floatfield);\n${space}";
$result .= " tempStream << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
elsif ($spec =~ /^g/i) {
print STDERR "$ARGV: warning: %g conversion not handled correctly!\n";
$spec =~ s/^.//;
if (!($rest[$index] =~ /\"/)) {
$rest[$index] =~ s/\s+/\ /g;
}
if ($sizeSpec eq "(long)") {
$sizeSpec = "(long double)";
}
elsif ($sizeSpec eq "") {
$sizeSpec = "(double)";
}
else {
print STDERR
"WARNING: $ARGV: there is no such thing as a short double (%hf)!\n";
$result .=
"WARNING: there is no such thing as a short double (%hf)!\n";
}
if (!$bare) {
$result .= ";\n${space} tempStream";
}
$result .= ".setf(ios::scientific,ios::floatfield);\n${space}";
$result .= " tempStream << $sizeSpec$rest[$index];\n${space}";
$result .= " tempStream.setf(ios::fixed,ios::floatfield);\n${space}";
$result .= " tempStream << \"$spec\"\n${space}${w}";
$cleanup = 1;
}
else {
$result .= $spec;
}
if ($cleanup == 1) {
$cleanup = 0;
if ($leftJust == 1) {
$leftJust = 0;
$result .= ";\n${space}
tempStream.setf(ios::right,ios::adjustfield);\n${space} tempStream";
}
if ($zeroPad == 1) {
$zeroPad = 0;
$result .= " << setfill(' ')\n${space}${w}";
}
if ($width) {
$width = 0;
$result .= " << setw(0)\n${space}${w}";
}
}
$sizeSpec = "";
$index++;
}
}
$result =~ s/\s*<< ""\n/\n/gs;
$result =~ s/<<\s*""//gs;
if ($cannotDo) {
"$whole;";
}
else {
$result .= " << ends;
${space}strcpy(${to}, tempBuf);";
"
${space}\{ // replacement for sprintf() code
${space} char tempBuf[$tempBufSize];
${space} ostrstream tempStream(tempBuf, sizeof tempBuf);
${space} tempStream.setf(ios::fixed,ios::floatfield); // reasonable default?
$result
${space}\}";
}
#;
$SIG{'INT'}='sigHandler';
$SIG{'QUIT'}='sigHandler';
$/=";";
$^I = ($#ARGV == $[-1) ? "" : ".bak";
while (<>) {
# work on this
# $numQuotes = 0;
# $numQuotes++ while (/"/g);
# while ($numQuotes % 2) { # not perfect
# $_ .= <>;
# $numQuotes++ while (/"/g);
# if (eof) {
# print $_, "\n";
# warn "$0: $ARGV: complex sprintf() case encountered. No changes made\n";
# }
# }
chop;
$addSemiColon = 1;
s{(\s*)\b # for indentation
sprintf\s*
\(([\\[\]\w()*?|~&+\-%.<=>\s]+?), # handle odd but legal cases
\s*"([\000-\377]*?)([^\\\\]\") # be careful
([\[\],\w()*&+\-%.>\s]*)\) # assumed to be legal sprintf() code
}
{
qq($replace)
}eegsx || ($addSemiColon = 1);
s{(.*)\n(\s*);}{$1\;}g;
$_ .= ";" if ($addSemiColon);
$all .= $_;
if (eof) {
push(@lines, split(/\n/, $all));
$line = 0;
$lastInclude = 0;
grep { ++$line; $lastInclude = $line if /^#include/; } @lines;
$lines[$#lines] =~ s/;$//;
foreach $line (@lines) {
if (!$lastInclude--) {
print "#include <iostream.h>\n";
print "#include <iomanip.h>\n";
print "#include <strstream.h>\n";
print "#include <string.h>\n";
}
print "${line}\n";
}
undef @lines;
if ($gotSig) {
close(ARGV);
exit 1;
}
undef $all;
}
}
sub sigHandler {
my($sig) = @_;
exit(1) if !$^I;
print STDERR "Caught signal SIG$sig -- cleaning up gracefully...\n";
$gotSig=1;
}
# Random Zippy quote:
#
# ANN JILLIAN'S HAIR makes LONI ANDERSON'S HAIR look like
# RICARDO MONTALBAN'S HAIR!
__END__
**********************************************************
To unsubscribe from this list, send mail to
[EMAIL PROTECTED] with the following text in the
*body* (*not* the subject line) of the letter:
unsubscribe gnhlug
**********************************************************