The next two questions are: Does anyone know a good method to untabify the entire codebase in one shot?
I don't know of any automation that does this well, assuming you want to change to 4-space indentation quantum at the same time as untabifying.
One tricky thing is continuation lines, making sure that the continuation line matches up with the right thing:
void long_function_name(int foo, int this_needs_to_line_up_with_the_paren)
Emacs C-M-\ (indent-region) works for the above case, but only because the indentation settings say that the args should line up with the open paren. If somewhere else in that file has a function call where the open paren is far to the right, so the programmer wanted just one indentation quantum for the arguments rather than lining up with the open paren, then emacs will get it wrong: it mechanically applies the same formatting policy across the file rather than trying to guess what the programmer wanted. E.g.
call_of_a_function_with_a_very_very_long_name( foo, bar);
will be transformed to the ugly-looking
call_of_a_function_with_a_very_very_long_name( foo, bar);
Also, emacs often does the wrong thing to block comments: it tries to re-indent individual lines in the comment rather than treating the comment block as a unit. E.g.
/* This can be called as foo(bar) to get something or other. */
will wrongly force all lines to line up:
/* This can be called as foo(bar) to get something or other. */
(Incidentally, the right thing happens if the block comment were written with leading `*':
/* This can be called as * foo(bar) * to get something or other. */
would leave the "foo(bar)" lined up with "s can be".)
Emacs/xemacs is the best tool I know of to do this untabification, but the above caveats should be kept in mind. It may be worthwhile doing smaller chunks and checking for cases that emacs gets wrong.
Another issue is tabs other than at the beginning of the line, e.g.
#define foo 1 #define bar 2 #define fittle 4
Keeping these tabs has the advantage of making it easier to keep things lined up (especially when using search & replace, where one can't use overwrite mode (vi "R", emacsen "Ins")).
Converting these tabs to spaces (i.e. no tabs left in file) has the advantage of making searches a little easier when matching whitespace. Another advantage is that this automatic conversion is easier to do in a way that keeps things lined up: do untabify-region (or equivalently the shell program `expand') before re-indenting the file.
Does anyone know how best to put modelines in the codebase to get vi and emacs to behave correctly?
Appending the following to all files (e.g. for i in `find ...`; do cat modeline
"$i"; done) should do the trick. (Probably should only be appended to files
that have already been converted, though.) The emacs indentation settings probably still want tweaking, though I haven't so far found a case where they do the wrong thing (in all of 2 minutes).
"(substatement-open . 0)" is actually default for stroustrup mode, I included it just to make it obvious how to add things to the list.
/* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(substatement-open . 0)) indent-tabs-mode:nil c-brace-offset:0 fill-column:99 End: vim: filetype=c++:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : */
pjrm.