-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 According to Jim Meyering on 10/27/2009 1:39 AM: >>>>> env -0/--null >>>>> printenv -0/--null >>>>> >>>>> as a means of unambiguously representing the current contents of the >>>>> environment with NUL terminators instead of newlines? > Yes, now I'm in favor of this, too.
This patch implements the option; I'm still working on developing a test (comparing binary output takes a bit more effort) before I will commit anything, but thought I'd at least get the review started. - -- Don't work too hard, make some time for fun as well! Eric Blake e...@byu.net -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkrm6hIACgkQ84KuGfSFAYCtXACgw4el/QauE6MpIR3tqmExTxLX NfQAoNbWY57yRVCSmnMSWCDMm8tMitSl =dSbs -----END PGP SIGNATURE-----
From 128acc9e68bb1ac44efdb559f7751079f8d76ab8 Mon Sep 17 00:00:00 2001 From: Eric Blake <e...@byu.net> Date: Mon, 26 Oct 2009 22:21:22 -0600 Subject: [PATCH 1/2] tests: add printenv coverage * tests/misc/printenv: New test. * tests/Makefile.am (TESTS): Run it. * .gitignore: Ignore more cruft. --- .gitignore | 1 + tests/Makefile.am | 1 + tests/misc/printenv | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 0 deletions(-) create mode 100755 tests/misc/printenv diff --git a/.gitignore b/.gitignore index 3ae9bf0..a284154 100644 --- a/.gitignore +++ b/.gitignore @@ -74,4 +74,5 @@ src/version.c src/version.h stamp-h1 tests/*/*.log +tests/t? tests/test-suite.log diff --git a/tests/Makefile.am b/tests/Makefile.am index 03fe6f1..731f657 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -192,6 +192,7 @@ TESTS = \ misc/od-x8 \ misc/paste \ misc/pathchk1 \ + misc/printenv \ misc/printf \ misc/printf-cov \ misc/printf-hex \ diff --git a/tests/misc/printenv b/tests/misc/printenv new file mode 100755 index 0000000..0edb39e --- /dev/null +++ b/tests/misc/printenv @@ -0,0 +1,74 @@ +#!/bin/sh +# Verify behavior of printenv. + +# Copyright (C) 2009 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program 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 General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +prog="$abs_top_builddir/src/printenv" + +if test "$VERBOSE" = yes; then + set -x + "$prog" --version +fi + +. $srcdir/test-lib.sh + +fail=0 + +# Without arguments, printenv behaves like env. Some shells provide +# printenv as a builtin, so we must test via absolute name. +# But beware of $_, set by many shells to the last command run. +env | grep -v '^_' > exp || framework_failure +"$prog" | grep -v '^_' > out || fail=1 +compare exp out || fail=1 + +# POSIX is clear that environ may, but need not be, sorted. +# Environment variable values may contain newlines, which cannot be +# observed by merely inspecting output from printenv. +if "$prog" | grep '^ENV_TEST' >/dev/null ; then + skip_test_ "environment has potential interference from ENV_TEST*" +fi + +# Printing a single variable's value. +"$prog" ENV_TEST > out +test $? = 1 || fail=1 +test -s out && fail=1 +echo a > exp || framework_failure +ENV_TEST=a "$prog" ENV_TEST > out || fail=1 +compare exp out || fail=1 + +# Printing multiple variables. Order follows command line. +ENV_TEST1=a ENV_TEST2=b "$prog" ENV_TEST2 ENV_TEST1 > out || fail=1 +ENV_TEST1=a ENV_TEST2=b "$prog" ENV_TEST1 ENV_TEST2 >> out || fail=1 +cat <<EOF > exp || framework_failure +b +a +a +b +EOF +compare exp out || fail=1 + +# Exit status reflects missing variable, but remaining arguments processed. +ENV_TEST1=a "$prog" ENV_TEST2 ENV_TEST1 > out +test $? = 1 || fail=1 +ENV_TEST1=a "$prog" ENV_TEST1 ENV_TEST2 >> out +test $? = 1 || fail=1 +cat <<EOF > exp || framework_failure +a +a +EOF +compare exp out || fail=1 + +Exit $fail -- 1.6.5.rc1 From ad7db2a0877eac5bc4195bb4add9145746c87d37 Mon Sep 17 00:00:00 2001 From: Eric Blake <e...@byu.net> Date: Tue, 27 Oct 2009 06:36:40 -0600 Subject: [PATCH 2/2] env, printenv: add -0/--null option * src/env.c (longopts): Add new option. (usage): Document it. (main): Implement it. * src/printenv.c (longopts): New variable. (usage): Document new option. (main): Implement it. * doc/coreutils.texi (Common options): New macro optNull. (du invocation, env invocation, printenv invocation): Use it. * NEWS: Mention this. --- NEWS | 3 +++ doc/coreutils.texi | 33 ++++++++++++++++++++++----------- src/env.c | 27 ++++++++++++++++++++++----- src/printenv.c | 38 ++++++++++++++++++++++++++++++-------- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/NEWS b/NEWS index abbeb27..442ce13 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,9 @@ GNU coreutils NEWS -*- outline -*- ** New features + env and printenv now accept the option --null (-0), as a means to + avoid ambiguity with newlines embedded in the environment. + md5sum --check now also accepts openssl-style checksums. So do sha1sum, sha224sum, sha384sum and sha512sum. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 138cf01..e5d0120 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -574,6 +574,18 @@ Common options symbolic link to a directory. @xref{Target directory}. @end macro +...@macro optNull{cmd} +...@item -0 +...@opindex -0 +...@itemx --null +...@opindex --null +...@cindex output null-byte-terminated lines +Output a zero byte (@acronym{ASCII} @sc{nul}) at the end of each line, +rather than a newline. This option enables other programs to parse the +output of @command{\cmd\} even when that output would contain data +with embedded newlines. +...@end macro + @macro optSi @itemx --si @opindex --si @@ -10376,15 +10388,7 @@ du invocation most MAX_DEPTH levels down from the root of the hierarchy. The root is at level 0, so @code{du --max-depth=0} is equivalent to @code{du -s}. -...@item -0 -...@opindex -0 -...@itemx --null -...@opindex --null -...@cindex output null-byte-terminated lines -Output a zero byte (@acronym{ASCII} @sc{nul}) at the end of each line, -rather than a newline. This option enables other programs to parse the -output of @command{du} even when that output would contain file names -with embedded newlines. +...@optnull{du} @optSi @@ -12806,8 +12810,13 @@ printenv invocation every environment variable. Otherwise, it prints the value of each @var{variable} that is set, and nothing for those that are not set. -The only options are a lone @option{--help} or @option{--version}. -...@xref{common options}. +The program accepts the following option. Also see @ref{Common options}. + +...@table @samp + +...@optnull{printenv} + +...@end table @cindex exit status of @command{printenv} Exit status: @@ -14438,6 +14447,8 @@ env invocation @table @samp +...@optnull{env} + @item -u @var{name} @itemx --uns...@var{name} @opindex -u diff --git a/src/env.c b/src/env.c index 8d7d55e..778129b 100644 --- a/src/env.c +++ b/src/env.c @@ -29,6 +29,11 @@ Unset variable VARIABLE (remove it from the environment). If VARIABLE was not set, does nothing. + -0 + --null + When no program is specified, output environment information + separated by nul bytes rather than newlines. + variable=value (an arg containing a "=" character) Set the environment variable VARIABLE to value VALUE. VALUE may be of zero length ("variable="). Setting a variable to a @@ -96,6 +101,7 @@ static struct option const longopts[] = { {"ignore-environment", no_argument, NULL, 'i'}, + {"null", no_argument, NULL, '0'}, {"unset", required_argument, NULL, 'u'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, @@ -116,8 +122,9 @@ Usage: %s [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]\n"), fputs (_("\ Set each NAME to VALUE in the environment and run COMMAND.\n\ \n\ - -i, --ignore-environment start with an empty environment\n\ - -u, --unset=NAME remove variable from the environment\n\ + -i, --ignore-environment start with an empty environment\n\ + -0, --null end each output line with 0 byte rather than newline\n\ + -u, --unset=NAME remove variable from the environment\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -135,6 +142,7 @@ main (int argc, char **argv) { int optc; bool ignore_environment = false; + bool opt_nul_terminate_output = false; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -145,7 +153,7 @@ main (int argc, char **argv) initialize_exit_failure (EXIT_CANCELED); atexit (close_stdout); - while ((optc = getopt_long (argc, argv, "+iu:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "+iu:0", longopts, NULL)) != -1) { switch (optc) { @@ -154,6 +162,9 @@ main (int argc, char **argv) break; case 'u': break; + case '0': + opt_nul_terminate_output = true; + break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); default: @@ -171,7 +182,7 @@ main (int argc, char **argv) } optind = 0; /* Force GNU getopt to re-initialize. */ - while ((optc = getopt_long (argc, argv, "+iu:", longopts, NULL)) != -1) + while ((optc = getopt_long (argc, argv, "+iu:0", longopts, NULL)) != -1) if (optc == 'u' && unsetenv (optarg)) error (EXIT_CANCELED, errno, _("cannot unset %s"), quote (optarg)); @@ -191,10 +202,16 @@ main (int argc, char **argv) { char *const *e = environ; while (*e) - puts (*e++); + printf ("%s%c", *e++, opt_nul_terminate_output ? '\0' : '\n'); exit (EXIT_SUCCESS); } + if (opt_nul_terminate_output) + { + error (0, errno, _("cannot specify --null (-0) with command")); + usage (EXIT_CANCELED); + } + execvp (argv[optind], &argv[optind]); { diff --git a/src/printenv.c b/src/printenv.c index dcdcb83..516b646 100644 --- a/src/printenv.c +++ b/src/printenv.c @@ -45,6 +45,14 @@ enum { PRINTENV_FAILURE = 2 }; proper_name ("David MacKenzie"), \ proper_name ("Richard Mlynarik") +static struct option const longopts[] = +{ + {"null", no_argument, NULL, '0'}, + {GETOPT_HELP_OPTION_DECL}, + {GETOPT_VERSION_OPTION_DECL}, + {NULL, 0, NULL, 0} +}; + void usage (int status) { @@ -54,13 +62,15 @@ usage (int status) else { printf (_("\ -Usage: %s [VARIABLE]...\n\ - or: %s OPTION\n\ +Usage: %s [OPTION]... [VARIABLE]...\n\ Print the values of the specified environment VARIABLE(s).\n\ If no VARIABLE is specified, print name and value pairs for them all.\n\ \n\ "), program_name, program_name); + fputs (_("\ + -0, --null end each output line with 0 byte rather than newline\n\ +"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME); @@ -76,6 +86,8 @@ main (int argc, char **argv) char *ep, *ap; int i; bool ok; + int optc; + bool opt_nul_terminate_output = false; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -86,15 +98,24 @@ main (int argc, char **argv) initialize_exit_failure (PRINTENV_FAILURE); atexit (close_stdout); - parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version, - usage, AUTHORS, (char const *) NULL); - if (getopt_long (argc, argv, "+", NULL, NULL) != -1) - usage (PRINTENV_FAILURE); + while ((optc = getopt_long (argc, argv, "+iu:0", longopts, NULL)) != -1) + { + switch (optc) + { + case '0': + opt_nul_terminate_output = true; + break; + case_GETOPT_HELP_CHAR; + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + default: + usage (PRINTENV_FAILURE); + } + } if (optind >= argc) { for (env = environ; *env != NULL; ++env) - puts (*env); + printf ("%s%c", *env, opt_nul_terminate_output ? '\0' : '\n'); ok = true; } else @@ -113,7 +134,8 @@ main (int argc, char **argv) { if (*ep == '=' && *ap == '\0') { - puts (ep + 1); + printf ("%s%c", ep + 1, + opt_nul_terminate_output ? '\0' : '\n'); matched = true; break; } -- 1.6.5.rc1