#!/usr/bin/perl -w
#
# in sh/bash/zsh:
#    make 2>&1 | .../qt/bin/qt20fix
# in csh/tcsh
#    make |& .../qt/bin/qt20fix
#
# repeat as long as qt20fix says to.  if your make supports the -k
# flag, that speeds up the process a bit.
#
# qt20fix tends to fix a bit over half of the remaining problems in
# each run.
#
# if you don't use gcc, you will need to change parseline.
#


# this function must accept one line, which is presumed to be an error
# message, and return an array of three strings: the file name, the
# line number and the variable that is undefined.
#
# it may also return an empty list, if the line isn't an error message.
#
# the function is called on each line in turn and only once on each
# line, so it's possible to save state.
#

sub parseline{
    my( $line ) = @_;

    chomp $line;

    if ( $line =~ m%^([-a-zA-Z0-9_\./]+\.[a-zA-Z]+):(\d+):\s*\`(.+)\' undeclared% ) {
	@r = ($1,$2,$3);
	$r[0] = $currentdir . $r[0] if ( defined($currentdir) &&
					 $r[0] =~ m%^[^/]% );
	return @r;
    } elsif ( $line =~ m%^([-a-zA-Z0-9_\./]+\.[a-zA-Z]+):(\d+):\s*\`(.+)\' was not declared% ) {
	@r = ($1,$2,$3);
	$r[0] = $currentdir . $r[0] if ( defined($currentdir) &&
					 $r[0] =~ m%^[^/]% );
	return @r;
    } elsif ( $line =~ m%^g?make\[(\d+)\]: Entering directory \`(.*)\'% ) {
	# make[1]: Entering directory `/home/agulbra/2x/src/ui'
	my( $l, $c ) = ( $1, $2 );
	$c =~ s-/?$-/-;
	$dirs[$l] = $c;
	$currentdir = $c;
	print "$line\n";
    } elsif ( $line =~ m%make\[(\d+)\]: Leaving directory \`.*\'$% ) {
	# make[1]: Leaving directory `/home/agulbra/2x/src/ui'
	$currentdir = defined( $dirs[$1 - 1] ) ? $dirs[$1 - 1] : "";
	print "$line\n";
    } elsif ( $line =~ m%^\S+:(?:\d+:)?\s+\S% ) {
	# other compiler message - skip it
    } else {
	print "$line\n";
    }

    return ();
}


#
# this is the big array of globals and their replacements.  add stuff
# at will.
#

%globals =
(
 "Event_None" => "QEvent::None",
 "Event_Timer" => "QEvent::Timer",
 "Event_MouseButtonPress" => "QEvent::MouseButtonPress",
 "Event_MouseButtonRelease" => "QEvent::MouseButtonRelease",
 "Event_MouseButtonDblClick" => "QEvent::MouseButtonDblClick",
 "Event_MouseMove" => "QEvent::MouseMove",
 "Event_KeyPress" => "QEvent::KeyPress",
 "Event_KeyRelease" => "QEvent::KeyRelease",
 "Event_FocusIn" => "QEvent::FocusIn",
 "Event_FocusOut" => "QEvent::FocusOut",
 "Event_Enter" => "QEvent::Enter",
 "Event_Leave" => "QEvent::Leave",
 "Event_Paint" => "QEvent::Paint",
 "Event_Move" => "QEvent::Move",
 "Event_Resize" => "QEvent::Resize",
 "Event_Create" => "QEvent::Create",
 "Event_Destroy" => "QEvent::Destroy",
 "Event_Show" => "QEvent::Show",
 "Event_Hide" => "QEvent::Hide",
 "Event_Close" => "QEvent::Close",
 "Event_Quit" => "QEvent::Quit",
 "Event_Accel" => "QEvent::Accel",
 "Event_Clipboard" => "QEvent::Clipboard",
 "Event_SockAct" => "QEvent::SockAct",
 "Event_DragEnter" => "QEvent::DragEnter",
 "Event_DragMove" => "QEvent::DragMove",
 "Event_DragLeave" => "QEvent::DragLeave",
 "Event_Drop" => "QEvent::Drop",
 "Event_DragResponse" => "QEvent::DragResponse",
 "Event_ChildInserted" => "QEvent::ChildInserted",
 "Event_ChildRemoved" => "QEvent::ChildRemoved",
 "Event_LayoutHint" => "QEvent::LayoutHint",
 "Event_User" => "QEvent::User",

 "color0" => "Qt::color0",
 "color1" => "Qt::color1",
 "black" => "Qt::black",
 "white" => "Qt::white",
 "darkGray" => "Qt::darkGray",
 "gray" => "Qt::gray",
 "lightGray" => "Qt::lightGray",
 "red" => "Qt::red",
 "green" => "Qt::green",
 "blue" => "Qt::blue",
 "cyan" => "Qt::cyan",
 "magenta" => "Qt::magenta",
 "yellow" => "Qt::yellow",
 "darkRed" => "Qt::darkRed",
 "darkGreen" => "Qt::darkGreen",
 "darkBlue" => "Qt::darkBlue",
 "darkCyan" => "Qt::darkCyan",
 "darkMagenta" => "Qt::darkMagenta",
 "darkYellow" => "Qt::darkYellow",

 "AlignLeft" => "Qt::AlignLeft",
 "AlignRight" => "Qt::AlignRight",
 "AlignHCenter" => "Qt::AlignHCenter",
 "AlignTop" => "Qt::AlignTop",
 "AlignBottom" => "Qt::AlignBottom",
 "AlignVCenter" => "Qt::AlignVCenter",
 "AlignCenter" => "Qt::AlignCenter",
 "SingleLine" => "Qt::SingleLine",
 "DontClip" => "Qt::DontClip",
 "ExpandTabs" => "Qt::ExpandTabs",
 "ShowPrefix" => "Qt::ShowPrefix",
 "WordBreak" => "Qt::WordBreak",
 "DontPrint" => "Qt::DontPrint",

 "TransparentMode" => "Qt::TransparentMode",
 "OpaqueMode" => "Qt::OpaqueMode",

 "PixelUnit" => "Qt::PixelUnit",
 "LoMetricUnit" => "Qt::LoMetricUnit",
 "HiMetricUnit" => "Qt::HiMetricUnit",
 "LoEnglishUnit" => "Qt::LoEnglishUnit",
 "HiEnglishUnit" => "Qt::HiEnglishUnit",
 "TwipsUnit" => "Qt::TwipsUnit",

 "WindowsStyle" => "Qt::WindowsStyle",
 "MotifStyle" => "Qt::MotifStyle",

 "Horizontal" => "Qt::Horizontal",
 "Vertical" => "Qt::Vertical",

 "PenStyle" => "Qt::PenStyle",
 "NoPen" => "Qt::NoPen",
 "SolidLine" => "Qt::SolidLine",
 "DashLine" => "Qt::DashLine",
 "DotLine" => "Qt::DotLine",
 "DashDotLine" => "Qt::DashDotLine",
 "DashDotDotLine" => "Qt::DashDotDotLine",

 "BrushStyle" => "Qt::BrushStyle",
 "NoBrush" => "Qt::NoBrush",
 "SolidPattern" => "Qt::SolidPattern",
 "Dense1Pattern" => "Qt::Dense1Pattern",
 "Dense2Pattern" => "Qt::Dense2Pattern",
 "Dense3Pattern" => "Qt::Dense3Pattern",
 "Dense4Pattern" => "Qt::Dense4Pattern",
 "Dense5Pattern" => "Qt::Dense5Pattern",
 "Dense6Pattern" => "Qt::Dense6Pattern",
 "Dense7Pattern" => "Qt::Dense7Pattern",
 "HorPattern" => "Qt::HorPattern",
 "VerPattern" => "Qt::VerPattern",
 "CrossPattern" => "Qt::CrossPattern",
 "BDiagPattern" => "Qt::BDiagPattern",
 "FDiagPattern" => "Qt::FDiagPattern",
 "DiagCrossPattern" => "Qt::DiagCrossPattern",
 "CustomPattern" => "Qt::CustomPattern",

 "arrowCursor" => "Qt::arrowCursor",
 "upArrowCursor" => "Qt::upArrowCursor",
 "crossCursor" => "Qt::crossCursor",
 "waitCursor" => "Qt::waitCursor",
 "ibeamCursor" => "Qt::ibeamCursor",
 "sizeVerCursor" => "Qt::sizeVerCursor",
 "sizeHorCursor" => "Qt::sizeHorCursor",
 "sizeBDiagCursor" => "Qt::sizeBDiagCursor",
 "sizeFDiagCursor" => "Qt::sizeFDiagCursor",
 "sizeAllCursor" => "Qt::sizeAllCursor",
 "blankCursor" => "Qt::blankCursor",
 "splitVCursor" => "Qt::splitVCursor",
 "splitHCursor" => "Qt::splitHCursor",
 "pointingHandCursor" => "Qt::pointingHandCursor"
);

if ( defined( $ENV{"QTDIR"} ) &&
     open( I, "< ". $ENV{"QTDIR"} . "/src/kernel/q1xcompatibility.h" ) ) {
    while( <I> ) {
	if ( /\#define\s+([a-zA-Z0-9_]+)\s+(\S+)/ ) {
	    if ( !defined( $globals{$1} ) ) {
		$globals{$1} = $2;
	    } elsif ( $globals{$1} ne $2 ) {
		#print "conflict: $1 is mapped to $2 and $globals{$1}\n";
	    }
	}
    }
    close I;
}

#
# do the do
#

while( <STDIN> ) {
    @r = parseline($_);
    next unless @r;
    ($file, $line, $variable) = @r;
    if ( defined( $variable ) && defined($globals{$variable}) ) {
	if ( !defined($lastfile) || ($file ne $lastfile) ) {
	    $lastfile = undef if ( !$changes );
	    if ( defined( $lastfile ) ) {
		open( O, "> $lastfile" ) ||
		  die "cannot write to $lastfile, stopped";
		print "qt20fix: writing $lastfile (changes: $changes)\n";
		print O @currentfile;
		close O;
	    }
	    open( I, "< $file" ) || die "cannot read $file, stopped";
	    @currentfile = <I>;
	    close I;
	    $lastfile = $file;
	    $changes = 0;
	}
	next unless ( defined( $currentfile[$line-1] ) );
	next unless ( $currentfile[$line-1] =~ /\b$variable\b/ );
	if ( $currentfile[$line-1] =~ s/([^a-zA-Z0-9])::$variable\b/$1$globals{$variable}/ ||
	     $currentfile[$line-1] =~ s/([^a-zA-Z0-9:])$variable\b/$1$globals{$variable}/ ) {
	    print "$file:$line:replaced \`$variable\' with \`$globals{$variable}\'\n";
	    $changes++;
	    $totalchanges++
	}
    } elsif ( defined( $variable ) ) {
	print "$file:$line: unknown undefined variable $variable\n";
    }
}

if ( defined( $changes) && $changes > 0 && defined( $lastfile ) ) {
    open( O, "> $lastfile" ) ||
      die "cannot write to $lastfile, stopped";
    print "qt20fix: writing $lastfile (changes: $changes)\n";
    print O @currentfile;
    close O;
}


if ( defined( $totalchanges) && $totalchanges > 0 ) {
    print "qt20fix: total changes: $totalchanges\nqt20fix: rerun recommended\n";
}
