aboutsummaryrefslogtreecommitdiff
path: root/stdio-common/tst-printf-format.awk
diff options
context:
space:
mode:
Diffstat (limited to 'stdio-common/tst-printf-format.awk')
-rw-r--r--stdio-common/tst-printf-format.awk127
1 files changed, 127 insertions, 0 deletions
diff --git a/stdio-common/tst-printf-format.awk b/stdio-common/tst-printf-format.awk
new file mode 100644
index 0000000000..8b4bc7b1e4
--- /dev/null
+++ b/stdio-common/tst-printf-format.awk
@@ -0,0 +1,127 @@
+# Testing of printf conversions.
+# Copyright (C) 2024 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+BEGIN {
+ FS = ":"
+}
+
+/^prec:/ {
+ PREC = $2
+ next
+}
+
+/^val:/ {
+ val = $2
+ # Prepend "+" for +Inf or +NaN value lacking a sign, because gawk
+ # interpretes them as strings rather than numeric values in the
+ # non-bignum mode unless a sign has been explicitly given. Keep
+ # original 'val' for reporting.
+ value = gensub(/^(INF|NAN|inf|nan)/, "+\\1", 1, val)
+ next
+}
+
+/^%/ {
+ # Discard the trailing empty field, used to improve legibility of data.
+ input = $--NF
+ format = $1
+ width = $2
+ precision = "." $(NF - 1)
+ # Discard any negative precision, which is to be taken as if omitted.
+ sub(/\.-.*/, "", precision)
+ # Simplify handling and paste the precision and width specified as
+ # arguments to '*' directly into the format.
+ sub(/\.\*/, precision, format)
+ sub(/\*/, width, format)
+ # Discard length modifiers. They are only relevant to C data types.
+ sub(/([DHLjhltz]|wf?[1-9][0-9]*)/, "", format)
+ # Discard the '#' flag with the octal conversion if output starts with
+ # 0 in the absence of this flag. In that case no extra 0 is supposed
+ # to be produced, but gawk prepends it anyway.
+ if (format ~ /#.*o/)
+ {
+ tmpfmt = gensub(/#/, "", "g", format)
+ tmpout = sprintf(tmpfmt, value)
+ if (tmpout ~ /^ *0/)
+ format = tmpfmt
+ }
+ # Likewise with the hexadecimal conversion where zero value with the
+ # precision of zero is supposed to produce no characters, but gawk
+ # outputs 0 instead.
+ else if (format ~ /#.*[Xx]/)
+ {
+ tmpfmt = gensub(/#/, "", "g", format)
+ tmpout = sprintf(tmpfmt, value)
+ if (tmpout ~ /^ *$/)
+ format = tmpfmt
+ }
+ # AWK interpretes input opportunistically as a number, which interferes
+ # with how the 'c' conversion works: "a" input will result in "a" output
+ # however "0" input will result in "^@" output rather than "0". Force
+ # the value to be interpreted as a string then, by appending "".
+ output = sprintf(format, value "")
+ # Make up for various anomalies with the handling of +/-Inf and +/-NaN
+ # values and reprint the output produced using the string conversion,
+ # with the field width carried over and the relevant flags handled by
+ # hand.
+ if (format ~ /[EFGefg]/ && value ~ /(INF|NAN|inf|nan)/)
+ {
+ minus = format ~ /-/ ? "-" : ""
+ sign = value ~ /-/ ? "-" : format ~ /\+/ ? "+" : format ~ / / ? " " : ""
+ if (format ~ /^%[^\.1-9]*[1-9][0-9]*/)
+ width = gensub(/^%[^\.1-9]*([1-9][0-9]*).*$/, "\\1", 1, format)
+ else
+ width = ""
+ output = gensub(/[-+ ]/, "", "g", output)
+ output = sprintf("%" minus width "s", sign output)
+ }
+ # Produce "+" where the '+' flag has been used with a signed integer
+ # conversion for zero value, observing any field width in effect.
+ # In that case "+" is always supposed to be produced, but with the
+ # precision of zero gawk in the non-bignum mode produces any padding
+ # requested only.
+ else if (format ~ /\+.*[di]/ && value == 0)
+ {
+ output = gensub(/^( *) $/, format ~ /-/ ? "+\\1" : "\\1+", 1, output)
+ output = gensub(/^$/, "+", 1, output)
+ }
+ # Produce " " where the space flag has been used with a signed integer
+ # conversion for zero value. In that case at least one " " is
+ # supposed to be produced, but with the precision of zero gawk in the
+ # non-bignum mode produces nothing.
+ else if (format ~ / .*[di]/ && value == 0)
+ {
+ output = gensub(/^$/, " ", 1, output)
+ }
+ if (output != input)
+ {
+ printf "(\"%s\"%s%s, %s) => \"%s\", expected \"%s\"\n", \
+ $1, (NF > 2 ? ", " $2 : ""), (NF > 3 ? ", " $3 : ""), val, \
+ input, output > "/dev/stderr"
+ status = 1
+ }
+ next
+}
+
+{
+ printf "unrecognized input: \"%s\"\n", $0 > "/dev/stderr"
+ status = 1
+}
+
+END {
+ exit status
+}