3 # ref_match - TopGit awk utility script used by tg--awksome
4 # Copyright (C) 2017 Kyle J. McKay <mackyle@gmail.com>
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 # dupesok keep dupes in output (only works if patterns is empty or "refs")
15 # maxout stop after no more matches than this
17 # NOTE: fnmatch (FNM_PATHNAME) style matches are not currently supported.
18 # All "patterns" must match exactly as a prefix at a "/" boundary
19 # (a "prefix" that is actually the entire ref matches too).
21 # input is a list of "<ref> <hash>" per line (or packed-refs style if
22 # pckdrefs is true) if there are multiple entries for the same ref name
23 # only one wins (which exactly is indeterminate since the sort is unstable).
24 # However, if dupesok is true and there are no patterns (or the only pattern
25 # is "refs" or "refs/") then refname duplicates will be kept in the output.
27 # hash values are always converted to lowercase
29 # output is each matching ref shown using the output matchfmt format whcih
30 # is a limited form of the for-each-ref format in that the default is similar
31 # to for-each-ref and only fields "%(refname)" and "%(objectname)" are
32 # supported along with "%%" and "%xx" EXCEPT "%00" (it will try don't expect
33 # it to work though) any other % sequence will pass through unchanged
35 # here is the actual format string (as a --format argument) used by default:
37 # --format="%(objectname) object%09%(refname)"
39 # while this is similar the for-each-ref default it uses "object" for the object
40 # type since one is not available and, in fact, %(objecttype) will indeed also
41 # be replaced with "object"
43 # output will be sorted by "refname" by default (it's always sorted somehow)
44 # and for the two-key form, the LAST key is the primary key; if the leading
45 # "-" is present it's a descending sort instead of ascending; only "objectname"
46 # and "refname" keys are supported (obviously)
48 # This one was supposed to be just a simple quick little thing *sigh*
51 function arrayswp
(anarray
, i1
, i2
, _swapper
) {
52 _swapper = anarray
[i1
]
53 anarray
[i1
] = anarray
[i2
]
54 anarray
[i2
] = _swapper
55 if (!multisort
) return # ** cough **
57 hashes
[i1
] = hashes
[i2
]
61 function kasort_order3
(anarray
, i1
, i2
, i3
, _c12
, _c13
, _c23
) {
62 _c12 = cmpkeys
(anarray
, i1
, i2
)
63 _c23 = cmpkeys
(anarray
, i2
, i3
)
65 if (_c23
<=
0) return ((!_c12
&& _c23
) || (!_c23
&& _c12
)) ?
-1 : 0
67 arrayswp
(anarray
, i1
, i3
)
70 } else if (_c23
>=
0) {
71 arrayswp
(anarray
, i1
, i3
)
74 _c13 = cmpkeys
(anarray
, i1
, i3
)
75 if (_c13
> 0) arrayswp
(anarray
, i1
, i3
)
76 if (_c12
<=
0) arrayswp
(anarray
, i2
, i3
)
77 else arrayswp
(anarray
, i1
, i2
)
81 # Could "ka" mean, oh I don't know, perhaps one of these? ;)
82 # Kyle's Awesome alternative to the low iQ sort
86 function kasort_partition
(anarray
, si
, ei
, _mi
, _le
, _ge
, _o3
, _n
) {
89 if (cmpkeys
(anarray
, si
, ei
) > 0)
90 arrayswp
(anarray
, si
, ei
)
93 _mi = int
((si
+ ei
) / 2)
97 kasort_order3
(anarray
, si
+ _n
, _mi
, ei
- _n
)
99 _o3 = kasort_order3
(anarray
, si
, _mi
, ei
)
105 while (++_le
< _ge
&& _le
!= _mi
&& cmpkeys
(anarray
, _le
, _mi
) <= _o3
) ;
107 while (_mi
< _ge
&& _le
< --_ge
&& cmpkeys
(anarray
, _mi
, _ge
) <= _o3
) ;
108 if (_le
< _ge
&& _ge
<= _mi
)
109 while (_le
< --_ge
&& cmpkeys
(anarray
, _mi
, _ge
) < 0) ;
110 if (_mi
<= _le
&& _le
< _ge
)
111 while (++_le
< _ge
&& cmpkeys
(anarray
, _le
, _mi
) < 0) ;
113 arrayswp
(anarray
, _le
, _ge
)
117 arrayswp
(anarray
, _le
, _mi
)
119 } else if (_mi
< _ge
) {
120 arrayswp
(anarray
, _mi
, _ge
)
123 kasort_partition
(anarray
, si
, _mi
- 1)
124 kasort_partition
(anarray
, _mi
+ 1, ei
)
129 function getpatarr
(patstr
,
130 _p
, _pi
, _pc
, _sa1
, _c2
, _sa2
, _lpat
, _llen
, _i
) {
132 split(patstr
, _sa1
, " ")
136 if (_p !~
/^refs\
/[^\
/]/) continue
142 kasort_partition
(_sa2
, 1, _c2
)
144 _llen =
length(_lpat
)
145 patarr
[++_pc
] = _lpat
146 for (_i =
2; _i
<= _c2
; ++_i
) {
148 if (length(_p
) >= _llen
&& _lpat ==
substr(_p
, 1, _llen
))
152 _llen =
length(_lpat
)
155 patarr
[++_pc
] =
"refs/"
157 patarr
[++_pc
] = _sa2
[1] "/"
159 patarr
[_pc
+ 1] =
"zend"
169 patcnt = getpatarr
(patterns
)
170 for (i =
split(tolower(sortkey
), keys
, /[, \t\r\n]+/); i
>=
1; --i
) {
171 if (keys
[i
] ==
"refname") {
174 } else if (keys
[i
] ==
"-refname") {
178 if (sortobj ==
0 && keys
[i
] ==
"objectname") sortobj =
1
179 if (sortobj ==
0 && keys
[i
] ==
"-objectname") sortobj =
-1
181 if (!sortref
) sortref =
1
182 if (matchfmt ==
"") matchfmt =
"%(objectname) %(objecttype)%09%(refname)"
183 fc =
split(matchfmt
, fmts
, /%
(%
|[0-9a
-fA
-F
][0-9a
-fA
-F
])/)
186 fpos =
length(theformat
) + 1
187 while (fpos
<=
length(matchfmt
)) {
188 pct =
tolower(substr(matchfmt
, fpos
, 3))
189 if (substr(pct
, 1, 2) ==
"%%") {
190 theformat = theformat
"%"
193 hexval = (index("0123456789abcdef
", substr(pct, 2, 1)) - 1) * 16
194 hexval += index("0123456789abcdef
", substr(pct, 3, 1)) - 1
195 theformat = theformat sprintf("%c
", hexval)
199 theformat = theformat fmts[++fi]
200 fpos += length(fmts[fi])
205 pckdrefs && $2 ~ /^refs\/./ &&
206 $1 ~ /^[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]+$/ {
210 hashes[cnt] = tolower($1)
213 !pckdrefs && $1 ~ /^refs\/./ &&
214 $2 ~ /^[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]+$/ {
218 hashes[cnt] = tolower($2)
221 function cmpkeys(anarray, i1, i2, _k1, _k2, _ans) {
223 if (dosortobj) { # ** cough **
226 if (_k1 < _k2) _ans = -1
227 else if (_k1 > _k2) _ans = 1
228 if (sortobj < 0) _ans = 0 - _ans
233 if (_k1 < _k2) _ans = -1
234 else if (_k1 > _k2) _ans = 1
235 if (sortref < 0) _ans = 0 - _ans
240 function formatline(rname, oname, _out) {
242 gsub(/%\(objectname\)/, oname, _out)
243 gsub(/%\(objecttype\)/, "object
", _out)
244 gsub(/[&]/, "\\\\&", rname)
245 gsub(/%\(refname\)/, rname, _out)
251 presortedbyrefonly = 0
252 if (!dupesok || patcnt > 1 || patarr[1] != "refs
/") {
253 savesortref = sortref
255 if (cnt > 1) kasort_partition(refs, 1, cnt)
256 presortedbyrefonly = 1
260 for (i = 1; i <= cnt; ++i) {
261 refs_i = (refs[i] != "") ? refs[i] "/" : ""
271 if (substr(ref, 1, length(curpat)) == curpat) continue
274 while (patarr[ji] < substr(ref, 1, length(patarr[ji])))
279 sortref = savesortref
282 if (cnt > 1 && (!presortedbyrefonly || sortobj || sortref < 0))
283 kasort_partition(refs, 1, cnt)
285 for (i = 1; i <= cnt; ++i) {
287 if (refname == "") continue
288 if (maxout > 0 && ++outcnt > maxout) exit 0
290 print formatline(refname, objname)