Vim Header Guard Trick
Thu 2008-01-24 17:35
Quite some time ago a friend of mine at work supplied us with a magical vim
binding that generated safe header guards. (And copyright/licence/doxygen
preamble too!) The idea is that it automatically inserts the matching
(#ifndef, #define, #endif) triplet and uses a guard that incorporates
the file name and a suitably long random number. (The random number is what
makes it "safe", for example what if you have a "UTIL_H" but another library
you're using also has a "UTIL_H"?)
Today I went to use the trusty old insert-guard key-binding and I see: "shell
returned 127". The problem was a simple one, the vim binding called on a
script written by yet another colleague. I had copied my usual .vimrc over
but not the required script so the guard failed. Since I'm easily distracted I
decided to work out a way to generate the guards that wouldn't do this to me
again, rather than just scp the script onto the system! I ended up with
this:
" function to insert a C/C++ header file guard
function! s:InsertGuard()
let randlen = 7
let randnum = system("xxd -c " . randlen * 2 . " -l " . randlen . " -p /dev/urandom")
let randnum = strpart(randnum, 0, randlen * 2)
let fname = expand("%")
let lastslash = strridx(fname, "/")
if lastslash >= 0
let fname = strpart(fname, lastslash+1)
endif
let fname = substitute(fname, "[^a-zA-Z0-9]", "_", "g")
let randid = toupper(fname . "_" . randnum)
exec 'norm O#ifndef ' . randid
exec 'norm o#define ' . randid
let origin = getpos('.')
exec '$norm o#endif /* ' . randid . ' */'
norm o
-norm O
call setpos('.', origin)
norm w
endfunction
" keymap Ctrl-g to the InsertGuard function
map <silent> <C-g> :call <SID>InsertGuard()<CR>
It is still dependent on an external command, but if vim is installed then
xxd is pretty likely to be around! (Since xxd is part of the vim
toolset.) I wonder if it could be shorter? I didn't find an obvious
equivalent to "basename" in vim, I suspect there might be an alternative
variable to '%' that gives what I want.
An example of what it generates when you're editing "src/util.h" and hit
Ctrl-h:
#ifndef UTIL_H_668A545328A5CC #define UTIL_H_668A545328A5CC <existing file content> #endif /* UTIL_H_668A545328A5CC */
Recent Entries
Categories
- Entries - 260
- Beer - 1
- Cycling - 2
- Food - 53
- Cooking - 26
- Hare - 5
- Soup - 1
- Eating - 5
- England - 5
- London - 4
- Rickmansworth - 1
- Produce - 14
- Ristretto - 8
- Health - 3
- Money - 2
- Random - 74
- Technology - 93
- Code - 22
- General - 46
- Security - 23
- Work - 2
- Wanderings - 32
- Australia - 2
- Barcelona - 2
- Belgium - 2
- England - 15
- Cambridge_Easter - 3
- Lakes - 9
- Finland - 4
- France - 1
- Germany - 1
- Ramble - 3
- Wales - 1




5 Responses
That said, if working on an library interface I aim to follow that rule 100%, so that victims of the API don't suffer the very problem I worry about. The lack of discipline only applies to the internal code.
It doesn't solve the problem of your own .cc file including your own "util.h" and then including <monkey/blah.h> from some third party library that its self includes its own "util.h". You just have to hope that everyone else reasonably "warts" their #ifndef guards as well.
You know, now I've bothered to add comments I should add an opt-in "email me comments on this story" too. Anyway...
Requiring code that uses x.h to do:
#include "a.h"
#include "b.h"
#include "c.h"
#include "x.h"
was OK, when it was only ever 2 or 3 extra includes, but now that it tends to be dozens, it doesn't work...
Of course you still have the problem of two third party libs you are using both using the same include guard name. But so does your technique - unless everyone uses it...
why there isn't a "include this file if it hasn't already been included" preprocessor command (in addition to #include obviously, sometimes you want to include something multiple times - poor man's templates for example) in the standard I'll never understand - it would be trivial to implement (a lookup table of files already included), faster (no need to parse the entire file everytime it is included to find the #endif), and the whole problem goes away. PHP has one for fuck sake...
By the way a preview comment would be nicer than a "email the address I signed up with and never check since it'd a spam magnet" feature.
As for the last note. Better than an email "push" would be comment feed RSS "pull"... but email is easier to implement! Yes, comment preview would be good, I'll bump it up to somewhere above "eat hippo" on my TODO list.