7 AWK is great. All hail AWK!
9 Now, some utility functions. parsehdr parse extracts the number of
10 lines (old or new) in the following hunk.
12 function parsehdr(s) {
13 s = gensub(".*,", "", 1, s)
14 s = gensub("^-", "", 1, s)
18 Extracts the name of the file from a "+++ path" or "--- path" line.
20 function filename(s) {
21 s = gensub("^... ", "", 1, s)
23 These lines have an optional tab followed by extra informations (the
24 date for example) that needs to be removed too.
26 s = gensub("\t.*", "", 1, s)
30 Switches the current file to the one provided. It's a great place where
31 accumulate part of the summary showed at the end and to reset the
34 function switchfile(newfile) {
36 summary = sprintf("%s+%d -%d\t%s\n",
37 summary, add, rem, file)
45 Now, the real "parser". It start in the "out" state
51 Match the start of a diff on the "+++" line.
53 state == "out" && /^\+\+\+ / {
55 if (nfile == "/dev/null") {
57 When deleting a file, the name will be "/dev/null", but that's not a
58 great name for the stats. Let's use the "old" name instead.
67 Let's save the old name in case it's needed.
69 state == "out" && /^--- / && file == "" {
70 delfile = filename($0)
73 Match the start of a hunk and switch the state to "in"
75 state == "out" && /^@@ / {
77 This part is a bit complicated, but all it does is extracting the number
78 of "new" and "old" lines showed in the hunk. A hunk header looks like this
79 (except for the initial '#' character)
81 # @@ -55,7 +55,19 @@ ...
83 So first extract the text inside the pair of "@@"
85 s = gensub("@@ ", "", 1)
86 s = gensub(" @@.*", "", 1, s)
88 and then parse each number.
90 old = gensub(" .*", "", 1, s)
93 new = gensub(".* ", "", 1, s)
96 Don't forget to switch the state of the parser, now we're reading a
102 Keep count of the added and removed line. Also, decrement the "old" and
103 "new" lines when needed, to know when we're done with the hunk.
105 state == "in" && /^ / {
110 state == "in" && /^-/ {
116 state == "in" && /^\+/ {
122 When there are no more "new" and "old" lines to read, go back to the
123 "out" state, ready to read another hunk or another file.
125 state == "in" && old <= 0 && new <= 0 {
129 Don't be a sink! Continue the pipeline so we can further save or apply
134 At the end, print the stats to standard error to avoid mangling the
135 input. Unfortunately, there doesn't seem to be a "built-in" way of
136 printing to stderr other than using the pseudo-device.
142 printf("%s", summary) > "/dev/stderr"
143 printf("+%d -%d\ttotal\n", totadd, totrem) > "/dev/stderr"
148 * cvs -q di | diffstat | tee /tmp/diff | less
149 * git diff | diffstat > /tmp/diff
150 * got di | diffstat | ssh foo 'cd xyz && got patch'