| # awk script to merge a config-specific .symlist file with others. |
| # The input files should be existing .abilist files, and a .symlist |
| # file. This must be run with awk -v config=REGEXP to specify a |
| # regexp matching configuration tuples for which the .symlist input |
| # defines an ABI. The result merges all duplicate occurrences of any |
| # symbol into a stanza listing the regexps matching configurations |
| # that contain it and giving associated versions. |
| # The merged file contains stanzas in the form: |
| # GLIBC_x.y regexp... |
| # | GLIBC_x.y.z regexp... |
| # | GLIBC_m.n regexp... |
| # function F |
| # variable D 0x4 |
| |
| BEGIN { current = "UNSET" } |
| |
| /^[^| ]/ { |
| if (NF < 2 && config == "") { |
| print FILENAME ":" FNR ": BAD SET LINE:", $0 > "/dev/stderr"; |
| exit 2; |
| } |
| |
| if (NF < 2) { |
| current = $1 ":" config; |
| } |
| else { |
| # Filter out the old stanzas from the config we are merging in. |
| # That way, if a set disappears from the .symlist file for this |
| # config, the old stanza doesn't stay in the merged output tagged |
| # for this config. (Disappearing sets might happen during development, |
| # and between releases could happen on a soname change). |
| nc = 0; |
| for (i = 2; i <= NF; ++i) |
| if ($i != config) |
| c[nc++] = $i; |
| if (nc == 0) |
| current = ""; |
| else { |
| current = $1 ":" c[0]; |
| for (i = 1; i < nc; ++i) |
| current = current "," $1 ":" c[i]; |
| } |
| } |
| |
| next; |
| } |
| |
| /^\| / { |
| if (NF < 3 || current == "UNSET") { |
| print FILENAME ":" FNR ": BAD | LINE:", $0 > "/dev/stderr"; |
| exit 2; |
| } |
| |
| nc = 0; |
| for (i = 3; i <= NF; ++i) |
| if ($i != config) |
| c[nc++] = $i; |
| for (i = 0; i < nc; ++i) |
| current = current "," $2 ":" c[i]; |
| |
| next; |
| } |
| |
| { |
| if (current == "") next; |
| if (current == "UNSET") { |
| print FILENAME ":" FNR ": IGNORED LINE:", $0 > "/dev/stderr"; |
| next; |
| } |
| |
| ns = split(seen[$0], s, ","); |
| nc = split(current, c, ","); |
| for (i = 1; i <= nc; ++i) { |
| if (c[i] == "") |
| continue; |
| # Sorted insert. |
| for (j = 1; j <= ns; ++j) { |
| if (c[i] == s[j]) |
| break; |
| if (c[i] < s[j]) { |
| for (k = ns; k >= j; --k) |
| s[k + 1] = s[k]; |
| s[j] = c[i]; |
| ++ns; |
| break; |
| } |
| } |
| if (j > ns) |
| s[++ns] = c[i]; |
| } |
| |
| seen[$0] = s[1]; |
| for (i = 2; i <= ns; ++i) |
| seen[$0] = seen[$0] "," s[i]; |
| |
| next; |
| } |
| |
| END { |
| for (line in seen) { |
| if (seen[line] in stanzas) |
| stanzas[seen[line]] = stanzas[seen[line]] "\n" line; |
| else |
| stanzas[seen[line]] = line; |
| } |
| |
| ns = split("", s); |
| for (configs in stanzas) { |
| # Sorted insert. |
| for (j = 1; j <= ns; ++j) { |
| if (configs == s[j]) |
| break; |
| if (configs < s[j]) { |
| for (k = ns; k >= j; --k) |
| s[k + 1] = s[k]; |
| s[j] = configs; |
| ++ns; |
| break; |
| } |
| } |
| if (j > ns) |
| s[++ns] = configs; |
| } |
| |
| # S[1..NS] is now a sorted list of stanza identifiers. |
| # STANZAS[ID] contains the lines for that stanza. |
| # All we have to do is pretty-print the stanza ID, |
| # and then print the sorted list. |
| |
| for (i = 1; i <= ns; ++i) { |
| # S[I] is a sorted, comma-separated list of SET:CONFIG pairs. |
| # All we have to do is pretty-print them. |
| nc = split(s[i], c, ","); |
| lastvers = lastconf = ""; |
| for (j = 1; j <= nc; ++j) { |
| split(c[j], temp, ":"); |
| version = temp[1]; |
| conf = temp[2]; |
| if (version != lastvers) |
| printf "%s%s", (lastvers != "" ? "\n| " : ""), version; |
| # Hack: if CONF is foo.*/bar and LASTCONF was foo.*, |
| # then we can omit the foo.*/bar since foo.* matches already. |
| # Note we don't update LASTCONF, so foo.*/baz next time will match too. |
| else if ((slash = index(conf, ".*/")) > 0 && \ |
| substr(conf, 1, slash + 2 - 1) == lastconf) |
| continue; |
| printf " %s", conf; |
| lastvers = version; |
| lastconf = conf; |
| } |
| print ""; |
| outpipe = "sort"; |
| print stanzas[s[i]] | outpipe; |
| close(outpipe); |
| } |
| } |