Blob


1 # diffstat
3 Show diff statistics.
5 #!/usr/bin/awk -f
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)
15 return s + 0
16 }
18 Switches the current file to the one provided. It's a great place where
19 accumulate part of the summary showed at the end and to reset the
20 per-file counters.
22 function switchfile(newfile) {
23 if (file != "") {
24 summary = sprintf("%s+%d -%d\t%s\n",
25 summary, add, rem, file)
26 }
28 add = 0
29 rem = 0
30 file = newfile
31 }
33 Now, the real "parser". It start in the "out" state
35 BEGIN {
36 state = "out"
37 }
39 Match the start of a diff on the "+++" line.
41 state == "out" && /^\+\+\+ / {
42 nfile = gensub("\\\+\\\+\\\+ ", "", 1)
43 if (nfile == "/dev/null") {
45 When deleting a file, the name will be "/dev/null", but that's not a
46 great name for the stats. Let's use the "old" name instead.
48 nfile = delfile
49 }
51 switchfile(nfile)
52 delfile = ""
53 }
55 Let's save the old name in case it's needed.
57 state == "out" && /^--- / && file == "" {
58 delfile = gensub("--- ", "", 1)
59 }
61 Match the start of a hunk and switch the state to "in"
63 state == "out" && /^@@ / {
65 This part is a bit complicated, but all it does is extracting the number
66 of "new" and "old" lines showed in the hunk. A hunk header looks like this
67 (except for the initial '#' character)
69 # @@ -55,7 +55,19 @@ ...
71 So first extract the text inside the pair of "@@"
73 s = gensub("@@ ", "", 1)
74 s = gensub(" @@.*", "", 1, s)
76 and then parse each number.
78 old = gensub(" .*", "", 1, s)
79 old = parsehdr(old)
81 new = gensub(".* ", "", 1, s)
82 new = parsehdr(new)
84 Don't forget to switch the state of the parser, now we're reading a
85 hunk.
87 state = "in"
88 }
90 Keep count of the added and removed line. Also, decrement the "old" and
91 "new" lines when needed, to know when we're done with the hunk.
93 state == "in" && /^ / {
94 old--
95 new--
96 }
98 state == "in" && /^-/ {
99 old--
100 rem++
101 totrem++
104 state == "in" && /^\+/ {
105 new--
106 add++
107 totadd++
110 When there are no more "new" and "old" lines to read, go back to the
111 "out" state, ready to read another hunk or another file.
113 state == "in" && old <= 0 && new <= 0 {
114 state = "out"
117 Don't be a sink! Continue the pipeline so we can further save or apply
118 the diff.
120 // { print $0 }
122 At the end, print the stats to standard error to avoid mangling the
123 input. Unfortunately, there doesn't seem to be a "built-in" way of
124 printing to stderr other than using the pseudo-device.
126 END {
127 fflush()
128 switchfile("")
130 printf("%s", summary) > "/dev/stderr"
131 printf("+%d -%d\ttotal\n", totadd, totrem) > "/dev/stderr"
134 some example usages:
136 * cvs -q di | diffstat | tee /tmp/diff | less
137 * git diff | diffstat > /tmp/diff
138 * got di | diffstat | ssh foo 'cd xyz && got patch'