You have to source [wiki:roelkluin/cvars cvars] to use these tools and run these commands in your git Linux kernel directory.
gg
gg does something like
git grep -n -E [other_options] "$(bli2 "$1")"
bli2
bli2() parses a string and transforms it into a more complex extended regexp, which it simply echoes.
To understand how it parses things try these:
bli2 "@V" bli2 "@d" bli2 " " bli2 " "
Note that @V will catch the identifier of a simple local variable, @d will catch a number (even if it's a hex or 1ull), spaces are squeezed and parsed to match optional spaces.
bli2 pattern |
echoed (description) |
echoed literal |
number of backrefs |
any space |
optional space |
no backref |
|
\! |
exclamation mark (because bash otherwise bangs) |
! |
no backref |
@S |
obligatory space |
no backref |
|
@V |
identifier |
[[:alpha:]_]+[[:alnum:]_]* |
no backref |
@K |
identifier in only uppercases |
[[:upper:]_]+[[:upper:][:digit:]_]* |
no backref |
@Q |
a non-alnumeric |
[^[:alnum:]_] |
no backref |
@Q2 |
a non-alnumeric or extension to the left of a variable |
[^[:alnum:]_>.] |
no backref |
@w |
(pointer) member, array |
see `bli2 "@w"' |
one backref |
@d |
any number |
see `bli2 "@d"' |
one backref |
\(...\) |
up to 2 nested parentheses |
see `bli2 "\(...\)"' |
two backrefs |
\{...\} |
up to 2 nested curly brackets |
see `bli2 "\{...\}"' |
two backrefs |
\[...\] |
up to 2 nested square brackets |
see `bli2 "\[...\]"' |
two backrefs |
\(-..\) |
characters optionally followed by up to 2 nested parentheses |
see `bli2 "\(...\)"' |
three backrefs |
\{-..\} |
characters optionally followed by up to 2 curly brackets |
see `bli2 "\{...\}"' |
three backrefs |
\{.8.\} |
up to 8 curly brackets |
see `bli2 "\(...\)"' |
eight backrefs |
gres
I wrote this to do a multiline (git-)grep
lets say we want to search for an erroneous pattern like this:
for (i = 0; i < n; i++) {} ... if (i > n) ...
We can match this with:
gres -B1 -A40 "@V < @d ;" "for \( (@V) = @d ; \1 < (@d) ; \1 \+\+ \) \{.8.\}@n if \( \1 > \3 \)"
For me - I currently have kernel version 2.6.33-rc2 - this results after a few seconds in:
-- ---[ vi drivers/mmc/host/s3cmci.c +1209 ]--- /* Set clock */ for (mci_psc = 0; mci_psc < 255; mci_psc++) { host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); if (host->real_rate <= ios->clock) break; } if (mci_psc > 255) mci_psc = 255; host->prescaler = mci_psc; writel(host->prescaler, host->base + S3C2410_SDIPRE); /* If requested clock is 0, real_rate will be 0, too */ if (ios->clock == 0) host->real_rate = 0;
So how does it work? gres does something in the order of:
git grep -E -n -other_opts "$(bli2 "$1")" -- '*.c' '*.h' | sed -n -r "$(ecsed2 "${@:2})"
The -B1' and -A40' are passed to git-grep, bli2() parses the first pattern and subsequent patterns are passed to ecsed2().
ecsed2
ecsed2() parses the `git grep' output and prints only the ones of which the last passed pattern matches, prior patterns (if any) are excluded.
More in detail:
gg -B1 -A40 "@V < @d ;"
The first of the `path/to/filename.c-301-' is transformed into a vi command, the remainder are removed. Also any comments are removed before pattern matching. newlines are extended. For each match that git grep piped to sed (parsed) matches are displayed if:
- The last pattern matched and
- no exclusion pattern matched
- no end-of-function occurred, i.e. "\^}"
- no end-of-match-pattern occurred, i.e. "\^--"