Selectively changing case using sed

I was faced today with a situation where I had to convert Qt4 style (???) includes:
#include <QMap>
with Qt3 style includes:
#include <qmap.h>
while trying to see if I could port some of my changes to the GSoC branch of KStars to the KDE 3.5.9 version. Of course, I may be overlooking at a lot of impossibilities in making the shift, but there’s not much harm in trying – only new learning :D.

So how would one do that? I searched around a bit here and there and got the solution, in bits and pieces, so I thought I should blog about it. The flow should go like this: First match include <Q\([^>]*\)> and substitute it with include <q\1.h>. That will replace #include <QMap> with #include <qMap.h>. But that’s not enough. We need to get qmap.h instead.

A first (dumb) attempt would be to pipe the output of sed through tr and tell it to translate [:upper:] to [:lower:], but that would translate everything. But “translate” is the key word. Search around a bit and you’ll find that sed has a translate command. To translate [:upper:] to [:lower:], you will need to do:
sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'
Because sed doesn’t support regular expressions or POSIX groups for translation. (Referred here)

But that will give me the same output as tr would. I want something more sophisticated – I want to convert only those lines which matched my initial substitution. Some more searching around (“conditional sed” were the keywords) and man sed told me that I could do “if( not substituted ) goto end;” by using the ‘T‘ command. So the whole things boils down to this:

sed 's/include <Q\([^>]*\)>/include <q\1.h>/;T;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'

Here’s a test run:

cat skycomponents/skymesh.h | sed 's/include <Q\([^>]*\)>/include <q\1.h>/;T;y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' | diff - skycomponents/skymesh.h
< #include <qhash.h>
< #include <qlist.h>
< #include <qobject.h>
> #include <QHash>
> #include <QList>
> #include <QObject>
< #include <qpainter.h>
> #include <QPainter>