[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
reverting `stat --format=FMT'
From: |
Jim Meyering |
Subject: |
reverting `stat --format=FMT' |
Date: |
Thu, 15 Dec 2005 13:40:45 +0100 |
As planned, here's the change to revert stat --format=FMT to
its previous behavior. Note that with this change, backslash
escapes in a --format-specified format string are *not* interpreted.
I'm planning to put the exact same patch on the b5 branch
(i.e., for coreutils-5.94), so if you have any objections,
raise them now.
NEWS:
** Changes in behavior
...
stat's --format=FMT option now works the way it did before 5.3.0:
FMT is automatically newline terminated. The first stable release
containing this change was 5.92.
stat accepts the new option --printf=FMT, where FMT is *not*
automatically newline terminated.
works, backslash escapes in FMT *are* interpreted.
stat: backslash escapes are interpreted in a format string specified
via --printf=FMT, but not one specified via --format=FMT. That includes
octal (\ooo, at most three octal digits), hexadecimal (\xhh, one or
two hex digits), and the standard sequences (\a, \b, \f, \n, \r, \t,
\v, \", \\).
2005-12-15 Jim Meyering <address@hidden>
stat: revert behavior of --format=FMT (-c)
stat: add new option: --printf=FMT
* NEWS: Mention this.
* src/stat.c (isodigit, octtobin, hextobin): Define.
(PRINTF_OPTION): Define.
(usage): Document them. Alphabetize on long option names.
(interpret_backslash_escapes, trailing_delim): New globals.
(print_esc_char): New function.
(print_it): Rewrite, in order to handle backslash escapes.
(main): Handle new option. Set globals for --format, too.
* tests/misc/stat-printf: Test --printf and --format.
* tests/misc/Makefile.am (TESTS): Add stat-printf.
2005-12-15 Jim Meyering <address@hidden>
* coreutils.texi (stat invocation) [--printf]: Describe new option.
[--format]: Add example. Distinguish from --printf.
Sort option descriptions.
Index: src/stat.c
===================================================================
RCS file: /fetish/cu/src/stat.c,v
retrieving revision 1.89
retrieving revision 1.90
diff -u -p -u -r1.89 -r1.90
--- src/stat.c 15 Oct 2005 10:15:48 -0000 1.89
+++ src/stat.c 15 Dec 2005 12:24:30 -0000 1.90
@@ -96,15 +96,27 @@
# endif
#endif
+/* FIXME: these are used by printf.c, too */
+#define isodigit(c) ('0' <= (c) && (c) <= '7')
+#define octtobin(c) ((c) - '0')
+#define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
+ (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
+
#define PROGRAM_NAME "stat"
#define AUTHORS "Michael Meskes"
+enum
+{
+ PRINTF_OPTION = CHAR_MAX + 1,
+};
+
static struct option const long_options[] = {
{"dereference", no_argument, NULL, 'L'},
{"file-system", no_argument, NULL, 'f'},
{"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */
{"format", required_argument, NULL, 'c'},
+ {"printf", required_argument, NULL, PRINTF_OPTION},
{"terse", no_argument, NULL, 't'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
@@ -113,6 +125,14 @@ static struct option const long_options[
char *program_name;
+/* Whether to interpret backslash-escape sequences.
+ True for --printf=FMT, not for --format=FMT (-c). */
+static bool interpret_backslash_escapes;
+
+/* The trailing delimiter string:
+ "" for --printf=FMT, "\n" for --format=FMT (-c). */
+static char const *trailing_delim = "";
+
/* Return the type of the specified file system.
Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
@@ -535,59 +555,130 @@ print_stat (char *pformat, size_t buf_le
}
}
+/* Output a single-character \ escape. */
+
+static void
+print_esc_char (char c)
+{
+ switch (c)
+ {
+ case 'a': /* Alert. */
+ c ='\a';
+ break;
+ case 'b': /* Backspace. */
+ c ='\b';
+ break;
+ case 'f': /* Form feed. */
+ c ='\f';
+ break;
+ case 'n': /* New line. */
+ c ='\n';
+ break;
+ case 'r': /* Carriage return. */
+ c ='\r';
+ break;
+ case 't': /* Horizontal tab. */
+ c ='\t';
+ break;
+ case 'v': /* Vertical tab. */
+ c ='\v';
+ break;
+ case '"':
+ case '\\':
+ break;
+ default:
+ error (0, 0, _("warning: unrecognized escape `\\%c'"), c);
+ break;
+ }
+ putchar (c);
+}
+
static void
-print_it (char const *masterformat, char const *filename,
+print_it (char const *format, char const *filename,
void (*print_func) (char *, size_t, char, char const *, void const *),
void const *data)
{
- char *b;
-
- /* create a working copy of the format string */
- char *format = xstrdup (masterformat);
-
/* Add 2 to accommodate our conversion of the stat `%s' format string
- to the printf `%llu' one. */
+ to the longer printf `%llu' one. */
size_t n_alloc = strlen (format) + 2 + 1;
char *dest = xmalloc (n_alloc);
-
- b = format;
- while (b)
+ char const *b;
+ for (b = format; *b; b++)
{
- char *p = strchr (b, '%');
- if (p != NULL)
+ switch (*b)
{
- size_t len;
- *p++ = '\0';
- fputs (b, stdout);
-
- len = strspn (p, "#-+.I 0123456789");
- dest[0] = '%';
- memcpy (dest + 1, p, len);
- dest[1 + len] = 0;
- p += len;
+ case '%':
+ {
+ size_t len = strspn (b + 1, "#-+.I 0123456789");
+ char const *fmt_char = b + 1 + len;
+ memcpy (dest, b, 1 + len);
+ dest[1 + len] = 0;
+
+ b = fmt_char;
+ switch (*fmt_char)
+ {
+ case '\0':
+ --b;
+ /* fall through */
+ case '%':
+ if (0 < len)
+ error (EXIT_FAILURE, 0, _("%s%s: invalid directive"),
+ quotearg_colon (dest), *fmt_char ? "%" : "");
+ putchar ('%');
+ break;
+ default:
+ print_func (dest, n_alloc, *fmt_char, filename, data);
+ break;
+ }
+ break;
+ }
- b = p + 1;
- switch (*p)
+ case '\\':
+ if ( ! interpret_backslash_escapes)
{
- case '\0':
- b = NULL;
- /* fall through */
- case '%':
- putchar ('%');
- break;
- default:
- print_func (dest, n_alloc, *p, filename, data);
+ putchar ('\\');
break;
}
- }
- else
- {
- fputs (b, stdout);
- b = NULL;
+ ++b;
+ if (isodigit (*b))
+ {
+ int esc_value = octtobin (*b);
+ int esc_length = 1; /* number of octal digits */
+ for (++b; esc_length < 3 && isodigit (*b);
+ ++esc_length, ++b)
+ {
+ esc_value = esc_value * 8 + octtobin (*b);
+ }
+ putchar (esc_value);
+ --b;
+ }
+ else if (*b == 'x' && ISXDIGIT (b[1]))
+ {
+ int esc_value = hextobin (b[1]); /* Value of \xhh escape. */
+ /* A hexadecimal \xhh escape sequence must have
+ 1 or 2 hex. digits. */
+ ++b;
+ if (ISXDIGIT (b[1]))
+ {
+ ++b;
+ esc_value = esc_value * 16 + hextobin (*b);
+ }
+ putchar (esc_value);
+ }
+ else
+ {
+ print_esc_char (*b);
+ }
+ break;
+
+ default:
+ putchar (*b);
+ break;
}
}
- free (format);
free (dest);
+
+ fputs (trailing_delim, stdout);
}
/* Stat the file system and print what we find. */
@@ -678,9 +769,15 @@ usage (int status)
fputs (_("\
Display file or file system status.\n\
\n\
- -f, --file-system display file system status instead of file status\n\
- -c --format=FORMAT use the specified FORMAT instead of the default\n\
-L, --dereference follow links\n\
+ -f, --file-system display file system status instead of file status\n\
+"), stdout);
+ fputs (_("\
+ -c --format=FORMAT use the specified FORMAT instead of the default;\n\
+ output a newline after each use of FORMAT\n\
+ --printf=FORMAT like --format, but interpret backslash escapes,\n\
+ and do not output a mandatory trailing newline.\n\
+ If you want a newline, include \\n in FORMAT.\n\
-t, --terse print the information in terse form\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
@@ -771,8 +868,16 @@ main (int argc, char *argv[])
{
switch (c)
{
+ case PRINTF_OPTION:
+ format = optarg;
+ interpret_backslash_escapes = true;
+ trailing_delim = "";
+ break;
+
case 'c':
format = optarg;
+ interpret_backslash_escapes = false;
+ trailing_delim = "\n";
break;
case 'L':
Index: doc/coreutils.texi
===================================================================
RCS file: /fetish/cu/doc/coreutils.texi,v
retrieving revision 1.300
diff -u -p -r1.300 coreutils.texi
--- doc/coreutils.texi 12 Dec 2005 22:42:16 -0000 1.300
+++ doc/coreutils.texi 15 Dec 2005 08:41:52 -0000
@@ -9277,14 +9277,6 @@ also give information about the files th
@table @samp
address@hidden -f
address@hidden --file-system
address@hidden -f
address@hidden --file-system
address@hidden file systems
-Report information about the file systems where the given files are located
-instead of information about the files themselves.
-
@item -L
@itemx --dereference
@opindex -L
@@ -9295,12 +9287,13 @@ With this option, @command{stat} acts on
by each symbolic link argument.
Without it, @command{stat} acts on any symbolic link argument directly.
address@hidden -t
address@hidden --terse
address@hidden -t
address@hidden --terse
address@hidden terse output
-Print the information in terse form, suitable for parsing by other programs.
address@hidden -f
address@hidden --file-system
address@hidden -f
address@hidden --file-system
address@hidden file systems
+Report information about the file systems where the given files are located
+instead of information about the files themselves.
@item -c
@itemx address@hidden
@@ -9308,6 +9301,36 @@ Print the information in terse form, sui
@opindex address@hidden
@cindex output format
Use @var{format} rather than the default format.
address@hidden is automatically newline-terminated, so
+running a command like the following with two or more @var{file}
+operands produces a line of output for each operand:
address@hidden
+$ stat --format=%d:%i / /usr
+2050:2
+2057:2
address@hidden example
+
address@hidden address@hidden
address@hidden address@hidden
address@hidden output format
+Use @var{format} rather than the default format.
+Like like @option{--format}, but interpret backslash escapes,
+and do not output a mandatory trailing newline.
+If you want a newline, include @samp{\n} in the @var{format}.
+Here's how you would use @option{--printf} to print the device
+and inode numbers of @file{/} and @file{/usr}:
address@hidden
+$ stat --printf='%d:%i\n' / /usr
+2050:2
+2057:2
address@hidden example
+
address@hidden -t
address@hidden --terse
address@hidden -t
address@hidden --terse
address@hidden terse output
+Print the information in terse form, suitable for parsing by other programs.
The valid format sequences for files are:
Index: tests/misc/stat-printf
===================================================================
RCS file: tests/misc/stat-printf
diff -N tests/misc/stat-printf
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/misc/stat-printf 15 Dec 2005 12:23:36 -0000 1.1
@@ -0,0 +1,58 @@
+#!/bin/sh
+
+: ${PERL=perl}
+: ${srcdir=.}
+
+$PERL -e 1 > /dev/null 2>&1 || {
+ echo 1>&2 "$0: configure didn't find a usable version of Perl," \
+ "so can't run this test"
+ exit 77
+}
+
+exec $PERL -w -I$srcdir/.. -MCoreutils -- - <<\EOF
+require 5.003;
+use strict;
+
+(my $ME = $0) =~ s|.*/||;
+my $prog = 'stat';
+
+# Turn off localisation of executable's ouput.
address@hidden(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @Tests =
+ (
+ # test-name, [option, option, ...] {OUT=>"expected-output"}
+ #
+ ['nl', q!--printf='\n' .!, {OUT=>"\n"}],
+ ['no-nl', "--printf=%n .", {OUT=>"."}],
+ ['pct-and-esc', q!--printf='\0%n\0' .!, {OUT=>"\0.\0"}],
+ ['backslash', q!--printf='\\\\' .!, {OUT=>"\\"}],
+ ['nul', q!--printf='\0' .!, {OUT=>"\0"}],
+ # Don't bother testing \v, since Perl doesn't handle it.
+ ['bel-etc', q!--printf='\a\b\f\n\r\t' .!, {OUT=>"\a\b\f\n\r\t"}],
+ ['octal-1', q!--printf='\012\377' .!, {OUT=>"\012\377"}],
+ ['octal-2', q!--printf='.\012a\377b' .!, {OUT=>".\012a\377b"}],
+ ['hex-1', q!--printf='\x34\xf' .!, {OUT=>"\x34\xf"}],
+ ['hex-2', q!--printf='.\x18p\xfq' .!, {OUT=>".\x18p\x0fq"}],
+ ['hex-3', q!--printf='\x' .!, {OUT=>'x'},
+ {ERR=>"$prog: warning: unrecognized escape `\\x'\n"}],
+
+ # With --format, there *is* a trailing newline.
+ ['f-nl', "--format=%n .", {OUT=>".\n"}],
+ ['f-nl2', "--format=%n . .", {OUT=>".\n.\n"}],
+
+ ['end-pct', "--printf=% .", {OUT=>"%"}],
+ ['pct-pct', "--printf=%% .", {OUT=>"%"}],
+
+ ['err-1', "--printf=%9% .", {EXIT => 1},
+ {ERR=>"$prog: %9%: invalid directive\n"}],
+ ['err-2', "--printf=%9 .", {EXIT => 1},
+ {ERR=>"$prog: %9: invalid directive\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($ME, $prog, address@hidden, $save_temps, $verbose);
+exit $fail;
+EOF
Index: tests/misc/Makefile.am
===================================================================
RCS file: /fetish/cu/tests/misc/Makefile.am,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile.am
--- tests/misc/Makefile.am 10 Dec 2005 09:38:07 -0000 1.32
+++ tests/misc/Makefile.am 15 Dec 2005 08:39:32 -0000
@@ -12,6 +12,7 @@ TESTS_ENVIRONMENT = \
PROG=$$tst
TESTS = \
+ stat-printf \
sort-rand \
sha224sum \
sha256sum \
- reverting `stat --format=FMT',
Jim Meyering <=