When 'stat' is given a format string using the --printf option, it
checks the QUOTING_STYLE environment variable if there is a %N
substring in the format string. This leads to the following behavior:
$ QUOTING_STYLE='invalid' ./src/stat-prev --printf='%N\n' HACKING
stat-prev: ignoring invalid value of environment variable QUOTING_STYLE:
‘invalid’
'HACKING'
$ QUOTING_STYLE='invalid' ./src/stat-prev --printf='%%N\n' HACKING
stat-prev: ignoring invalid value of environment variable QUOTING_STYLE:
‘invalid’
%N
I don't think we should warn in the second case, because QUOTING_STYLE
has no effect on the output. Here is the behavior after this patch:
$ QUOTING_STYLE='invalid' ./src/stat --printf='%N\n' HACKING
stat: ignoring invalid value of environment variable QUOTING_STYLE:
‘invalid’
'HACKING'
$ QUOTING_STYLE='invalid' ./src/stat --printf='%%N\n' HACKING
%N
-- 8< --
* NEWS: Mention the fix.
* src/stat.c (main): Only check QUOTING_STYLE if there is a %N that is
not preceded by a percentage sign.
* tests/stat/stat-fmt.sh: Add some test cases.
---
NEWS | 4 ++++
src/stat.c | 11 ++++++++++-
tests/stat/stat-fmt.sh | 30 ++++++++++++++++++++++++++++++
3 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/NEWS b/NEWS
index a01a13acc..473b7c21d 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,10 @@ GNU coreutils NEWS -*-
outline -*-
when operating in deep paths longer than twice the system PATH_MAX.
[bug introduced in coreutils-9.6]
+ 'stat --printf=%%N' no longer performs unnecessary checks of the
QUOTING_STYLE
+ environment variable.
+ [bug introduced in coreutils-8.26]
+
** New Features
'date --date' now parses dot delimited dd.mm.yy format common in Europe.
diff --git a/src/stat.c b/src/stat.c
index 128fafd31..1e3501525 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -1970,7 +1970,16 @@ main (int argc, char *argv[])
if (format)
{
- if (strstr (format, "%N"))
+ bool need_quoting_style = false;
+ for (char const *p = format; (p = strchr (p, '%')); ++p)
+ {
+ if (p[1] == 'N' && (p == format || p[-1] != '%'))
+ {
+ need_quoting_style = true;
+ break;
+ }
+ }
+ if (need_quoting_style)
getenv_quoting_style ();
format2 = format;
}
diff --git a/tests/stat/stat-fmt.sh b/tests/stat/stat-fmt.sh
index 1c208e378..066c48133 100755
--- a/tests/stat/stat-fmt.sh
+++ b/tests/stat/stat-fmt.sh
@@ -40,6 +40,36 @@ cat <<\EOF >exp
EOF
compare exp out || fail=1
+# Check the behavior with invalid values of QUOTING_STYLE.
+for style in '' 'abcdef'; do
+ QUOTING_STYLE="$style" stat -c%N \' > out 2> err || fail=1
+ cat <<\EOF > exp-out || framework_failure_
+"'"
+EOF
+ cat <<EOF > exp-err || framework_failure_
+stat: ignoring invalid value of environment variable QUOTING_STYLE: '$style'
+EOF
+ compare exp-out out || fail=1
+ compare exp-err err || fail=1
+ # coreutils-9.10 and earlier would unnecessarily check QUOTING_STYLE in
+ # these cases.
+ for format in '%%N' 'abc%%Ndef' 'abc%%Ndef%%N'; do
+ QUOTING_STYLE="$style" stat -c"$format" \' > out 2> err || fail=1
+ printf "$format\n" > exp-out || framework_failure_
+ compare exp-out out || fail=1
+ compare /dev/null err || fail=1
+ done
+done
+
+# Check the behavior with %N following %%N.
+stat -cabc%%Ndef%N \' > out || fail=1
+QUOTING_STYLE=locale stat -cabc%%Ndef%N \' >> out || fail=1
+cat <<\EOF >exp
+abc%Ndef"'"
+abc%Ndef'\''
+EOF
+compare exp out || fail=1
+
# ensure %H and %L modifiers are handled
stat -c '%r %R %Hd,%Ld %Hr,%Lr' . > out || fail=1
grep -F '?' out && fail=1
--
2.53.0