tg-info.sh: support --deps and --dependents options
[topgit/pro.git] / awk / ref_match.awk
blobecab587874f5486744c545715095eae84a70584d
1 #!/usr/bin/awk -f
3 # ref_match - TopGit awk utility script used by tg--awksome
4 # Copyright (C) 2017 Kyle J. McKay <mackyle@gmail.com>
5 # All rights reserved.
6 # License GPLv2
8 # ref_match
10 # pckdrefs input refs are in packed-refs format
11 # patterns whitespace-separated for-each-ref style patterns to match
12 # matchfmt a for-each-ref format string (limited, see below)
13 # sortkey optional "[-]<key>" or "[-]<key>,[-]<key>" (see below)
14 # maxout stop after no more matches than this
16 # input is a list of "<ref> <hash>" per line (or packed-refs style if
17 # pckdrefs is true) if there are multiple entries for the same ref name
18 # only one wins (which exactly is indeterminate since the sort is unstable)
20 # hash values are always converted to lowercase
22 # output is each matching ref shown using the output matchfmt format whcih
23 # is a limited form of the for-each-ref format in that the default is similar
24 # to for-each-ref and only fields "%(refname)" and "%(objectname)" are
25 # supported along with "%%" and "%xx" EXCEPT "%00" (it will try don't expect
26 # it to work though) any other % sequence will pass through unchanged
28 # here is the actual format string (as a --format argument) used by default:
30 # --format="%(objectname) object%09%(refname)"
32 # while this is similar the for-each-ref default it uses "object" for the object
33 # type since one is not available and, in fact, %(objecttype) will indeed also
34 # be replaced with "object"
36 # output will be sorted by "refname" by default (it's always sorted somehow)
37 # and for the two-key form, the LAST key is the primary key; if the leading
38 # "-" is present it's a descending sort instead of ascending; only "objectname"
39 # and "refname" keys are supported (obviously)
41 # This one was supposed to be jast a simple quick little thing *sigh*
44 function arrayswp(anarray, i1, i2, _swapper) {
45 _swapper = anarray[i1]
46 anarray[i1] = anarray[i2]
47 anarray[i2] = _swapper
48 if (!multisort) return # ** cough **
49 _swapper = hashes[i1]
50 hashes[i1] = hashes[i2]
51 hashes[i2] = _swapper
54 function kasort_order3(anarray, i1, i2, i3, _c12, _c13, _c23) {
55 _c12 = cmpkeys(anarray, i1, i2)
56 _c23 = cmpkeys(anarray, i2, i3)
57 if (_c12 <= 0) {
58 if (_c23 <= 0) return
59 if (_c12 == 0) {
60 arrayswp(anarray, i1, i3)
61 return
63 } else if (_c23 >= 0) {
64 arrayswp(anarray, i1, i3)
65 return
67 _c13 = cmpkeys(anarray, i1, i3)
68 if (_c13 > 0) arrayswp(anarray, i1, i3)
69 if (_c12 <= 0) arrayswp(anarray, i2, i3)
70 else arrayswp(anarray, i1, i2)
73 # Could "ka" mean, oh I don't know, perhaps one of these? ;)
74 # Kyle's Awesome alternativve to the low iQ sort
75 # Kick Ass sort
76 # Kyle's Array sort
78 function kasort_partition(anarray, si, ei, _mi, _le, _ge) {
79 if (ei <= si) return
80 if (si + 1 == ei) {
81 if (cmpkeys(anarray, si, ei) > 0)
82 arrayswp(anarray, si, ei)
83 return
85 _mi = int((si + ei) / 2)
86 kasort_order3(anarray, si, _mi, ei)
87 if (si + 2 == ei) return
88 _le = si
89 _ge = ei
90 for (;;) {
91 if (_le < _mi)
92 while (++_le < _ge && _le != _mi && cmpkeys(anarray, _le, _mi) <= 0) ;
93 if (_le < _ge)
94 while (_le < --_ge && cmpkeys(anarray, _mi, _ge) <= 0) ;
95 if (_mi <= _le && _le < _ge)
96 while (++_le < _ge && cmpkeys(anarray, _le, _mi) <= 0) ;
97 if (_le < _ge) {
98 arrayswp(anarray, _le, _ge)
99 continue
101 if (_le < mi) {
102 arrayswp(anarray, _le, _mi)
103 _mi = _le
104 } else {
105 arrayswp(anarray, _mi, _ge)
106 _mi = _ge
108 kasort_partition(anarray, si, _mi - 1)
109 kasort_partition(anarray, _mi + 1, ei)
110 return
114 function getpatarr(patstr,
115 _p, _pi, _pc, _sa1, _c2, _sa2, _lpat, _llen, _i) {
117 split(patstr, _sa1, " ")
118 _c2 = 0
119 for (_pi in _sa1) {
120 _p = _sa1[_pi]
121 if (_p !~ /^refs\/./) continue
122 if (_p !~ /\/$/) _p = _p "/"
123 _sa2[++_c2] = _p
125 _pc = 0
126 if (_c2 > 1) {
127 kasort_partition(_sa2, 1, _c2)
128 _lpat = _sa2[1]
129 _llen = length(_lpat)
130 patarr[++_pc] = _lpat
131 for (_i = 2; _i <= _c2; ++_i) {
132 _p = _sa2[_i]
133 if (length(_p) >= _llen && _lpat == substr(_p, 1, _llen))
134 continue
135 patarr[++_pc] = _p
136 _lpat = _p
137 _llen = length(_lpat)
139 } else if (!_c2) {
140 patarr[++_pc] = "refs/"
141 } else {
142 patarr[++_pc] = _sa2[1]
144 patarr[_pc + 1] = "zend"
145 return _pc
148 BEGIN {
149 multisort = 0
150 dosortobj = 0
151 cnt = 0
152 sortobj = 0
153 sortref = 0
154 patcnt = getpatarr(patterns)
155 for (i = split(tolower(sortkey), keys, /[, \t\r\n]+/); i >= 1; --i) {
156 if (keys[i] == "refname") {
157 sortref = 1
158 break
159 } else if (keys[i] == "-refname") {
160 sortref = -1
161 break
163 if (sortobj == 0 && keys[i] == "objectname") sortobj = 1
164 if (sortobj == 0 && keys[i] == "-objectname") sortobj = -1
166 if (!sortref) sortref = 1
167 if (matchfmt == "") matchfmt = "%(objectname) %(objecttype)%09%(refname)"
168 fc = split(matchfmt, fmts, /%(%|[0-9a-fA-F]{2})/)
169 fi = 1
170 theformat = fmts[fi]
171 fpos = length(theformat) + 1
172 while (fpos <= length(matchfmt)) {
173 pct = tolower(substr(matchfmt, fpos, 3))
174 if (substr(pct, 1, 2) == "%%") {
175 theformat = theformat "%"
176 fpos += 2
177 } else {
178 hexval = (index("0123456789abcdef", substr(pct, 2, 1)) - 1) * 16
179 hexval += index("0123456789abcdef", substr(pct, 3, 1)) - 1
180 theformat = theformat sprintf("%c", hexval)
181 fpos += 3
183 if (fi <= fc) {
184 theformat = theformat fmts[++fi]
185 fpos += length(fmts[fi])
190 pckdrefs && $2 ~ /^refs\/./ && $1 ~ /^[0-9A-Fa-f]{4,}$/ {
191 r = $2
192 sub(/\/+$/, "", r)
193 refs[++cnt] = r "/"
194 hashes[cnt] = tolower($1)
197 !pckdrefs && $1 ~ /^refs\/./ && $2 ~ /^[0-9A-Fa-f]{4,}$/ {
198 r = $1
199 sub(/\/+$/, "", r)
200 refs[++cnt] = r "/"
201 hashes[cnt] = tolower($2)
204 function cmpkeys(anarray, i1, i2, _k1, _k2, _ans) {
205 _ans = 0
206 if (dosortobj) { # ** cough **
207 _k1 = hashes[i1]
208 _k2 = hashes[i2]
209 if (_k1 < _k2) _ans = -1
210 else if (_k1 > _k2) _ans = 1
211 if (sortobj < 0) _ans = 0 - _ans
213 if (!_ans) {
214 _k1 = anarray[i1]
215 _k2 = anarray[i2]
216 if (_k1 < _k2) _ans = -1
217 else if (_k1 > _k2) _ans = 1
218 if (sortref < 0) _ans = 0 - _ans
220 return _ans
223 function formatline(rname, oname, _out) {
224 _out = theformat
225 gsub(/%\(objectname\)/, oname, _out)
226 gsub(/%\(objecttype\)/, "object", _out)
227 gsub(/%\(refname\)/, rname, _out)
228 return _out
231 END {
232 multisort = 1
233 presortedbyrefonly = 0
234 if (patcnt > 1 || patarr[1] != "refs/") {
235 savesortref = sortref
236 sortref = 1
237 if (cnt > 1) kasort_partition(refs, 1, cnt)
238 presortedbyrefonly = 1
239 ji = 1
240 ref = ""
241 curpat = patarr[ji]
242 for (i = 1; i <= cnt; ++i) {
243 if (refs[i] == ref) {
244 refs[i] = ""
245 continue
247 ref = refs[i]
248 if (ref < curpat) {
249 refs[i] = ""
250 continue
252 if (substr(ref, 1, length(curpat)) == curpat) continue
253 while (patarr[++ji] < ref) ;
254 curpat = patarr[ji]
255 ref = ""
258 sortref = savesortref
260 dosortobj = sortobj
261 if (cnt > 1 && (!presortedbyrefonly || sortobj || sortref < 0))
262 kasort_partition(refs, 1, cnt)
263 outcnt = 0
264 for (i = 1; i <= cnt; ++i) {
265 refname = refs[i]
266 sub(/\/+$/, "", refname)
267 if (refname == "") continue
268 if (maxout > 0 && ++outcnt > maxout) exit 0
269 objname = hashes[i]
270 print formatline(refname, objname)