From 2849f722ef8dd9bf9dcdfb0aa11e08a050cf302e Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 5 Dec 2023 20:10:08 -0500 Subject: [PATCH] help_print_optstring: Better output on some old systems. Some very old printf implementations return 0 on success instead of the number of bytes written. We should never see a return of 0 normally, so we can improve the output to be less of a garbled mess by printing a newline if that happens (same as the error case). This is a simple tweak that should have virtually no impact on modern systems. The tests are adapted to verify the new behaviour, although we'll mark the result as "skipped" (assuming it is correct) instead of "passed" since it's only sortof working. --- Makefile.am | 2 +- src/help.c | 2 +- t/.gitignore | 1 + t/printfchk.c | 16 ++++++++++ tests/functions.at | 76 ++++++++++++++++++++++++++++++++-------------- 5 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 t/printfchk.c diff --git a/Makefile.am b/Makefile.am index f811cde..0e5e20a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,7 +24,7 @@ t_packtests_SOURCES = t/packtests.c src/pack.c src/tap.c t_packtestu64_SOURCES = t/packtestu64.c src/pack.c src/tap.c t_packtests64_SOURCES = t/packtests64.c src/pack.c src/tap.c -check_PROGRAMS += t/helpdesc t/helpopt t/helpopt2 +check_PROGRAMS += t/printfchk t/helpdesc t/helpopt t/helpopt2 if HAVE_WCWIDTH check_PROGRAMS += t/helpopt3 endif diff --git a/src/help.c b/src/help.c index 3886c27..a635a15 100644 --- a/src/help.c +++ b/src/help.c @@ -183,7 +183,7 @@ no_translate: w = printf(fmt, opt->name, argname); } out: - if (w < 0 || w > l) { + if (w <= 0 || w > l) { putchar('\n'); return 0; } diff --git a/t/.gitignore b/t/.gitignore index 8b12d4a..39c659a 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -5,3 +5,4 @@ /helpopt3 /packtest[su] /packtest[su]64 +/printfchk diff --git a/t/printfchk.c b/t/printfchk.c new file mode 100644 index 0000000..8d63f3b --- /dev/null +++ b/t/printfchk.c @@ -0,0 +1,16 @@ +/* + * Copyright © 2023 Nick Bowler + * + * Runtime check of printf behaviour for the test suite. Some very old printf + * implementations return 0 on success instead of the number of bytes written. + * + * License WTFPL2: Do What The Fuck You Want To Public License, version 2. + * This is free software: you are free to do what the fuck you want to. + * There is NO WARRANTY, to the extent permitted by law. + */ +#include + +int main(void) +{ + return printf("hello\n") == 0; +} diff --git a/tests/functions.at b/tests/functions.at index 6b092a0..4a9aeb5 100644 --- a/tests/functions.at +++ b/tests/functions.at @@ -56,20 +56,7 @@ AT_CLEANUP AT_SETUP([help_print_optstring]) AT_KEYWORDS([help]) -AT_SKIP_IF([test ! -x "$builddir/t/helpopt"]) - -AT_CHECK([m4_join([ ], - ["$builddir/t/helpopt"], - [--foo], - [--bar -b], - [--baz ARG], - [--baz -B ARG], - [--quux '@<:@ARG@:>@'], - [--quux -q '@<:@ARG@:>@'], - [--hello-this-is-a-very-long-option 20], - [--hello-this-is-a-very-long-option 50], - [--not-long 12], - [--flagged -f \&])], [0], +AT_DATA([expout], [[ --foo 6 -b, --bar 10 --baz=ARG 10 @@ -83,15 +70,20 @@ AT_CHECK([m4_join([ ], --flagged 10 ]]) -AT_CLEANUP - -AT_SETUP([help_print_optstring (getopt_long_only)]) -AT_KEYWORDS([help]) - -AT_SKIP_IF([test ! -x "$builddir/t/helpopt2"]) +# Some very old printf implementations return 0 on success instead of the +# number of bytes written. The help_print_optstring function is not fully +# functional in this case. It should fallback to printing a newline and +# returning 0 so the overall --help output should be mostly acceptable. +# +# We verify that this indeed works properly by adjusting the expected +# output accordingly, but ... +AS_IF(["$builddir/t/printfchk" >/dev/null], [ancient_printf=false], +[[sed -n -e 's/ [0-9]*$//' -e '/^ *-/p' -e 's/^ *-.*/ 0/p' expout >expout.tmp +mv -f expout.tmp expout +ancient_printf=:]]) AT_CHECK([m4_join([ ], - ["$builddir/t/helpopt2"], + ["$builddir/t/helpopt"], [--foo], [--bar -b], [--baz ARG], @@ -101,7 +93,18 @@ AT_CHECK([m4_join([ ], [--hello-this-is-a-very-long-option 20], [--hello-this-is-a-very-long-option 50], [--not-long 12], - [--flagged -f \&])], [0], + [--flagged -f \&])], [0], [expout]) + +# ... we ultimately skip the test so there's an indication (other than an +# outright failure) that the function is not working completely. +AT_SKIP_IF([$ancient_printf]) + +AT_CLEANUP + +AT_SETUP([help_print_optstring (getopt_long_only)]) +AT_KEYWORDS([help]) + +AT_DATA([expout], [[ -foo 5 -bar 5 -baz ARG 9 @@ -115,6 +118,35 @@ AT_CHECK([m4_join([ ], -flagged 9 ]]) +# Some very old printf implementations return 0 on success instead of the +# number of bytes written. The help_print_optstring function is not fully +# functional in this case. It should fallback to printing a newline and +# returning 0 so the overall --help output should be mostly acceptable. +# +# We verify that this indeed works properly by adjusting the expected +# output accordingly, but ... +AS_IF(["$builddir/t/printfchk" >/dev/null], [ancient_printf=false], +[[sed -n -e 's/ [0-9]*$//' -e '/^ *-/p' -e 's/^ *-.*/ 0/p' expout >expout.tmp +mv -f expout.tmp expout +ancient_printf=:]]) + +AT_CHECK([m4_join([ ], + ["$builddir/t/helpopt2"], + [--foo], + [--bar -b], + [--baz ARG], + [--baz -B ARG], + [--quux '@<:@ARG@:>@'], + [--quux -q '@<:@ARG@:>@'], + [--hello-this-is-a-very-long-option 20], + [--hello-this-is-a-very-long-option 50], + [--not-long 12], + [--flagged -f \&])], [0], [expout]) + +# ... we ultimately skip the test so there's an indication (other than an +# outright failure) that the function is not working completely. +AT_SKIP_IF([$ancient_printf]) + AT_CLEANUP AT_SETUP([help_print_optstring (NLS fullwidth/halfwidth)]) -- 2.43.2