Jim Meyering <[EMAIL PROTECTED]> writes: > Thank you for the patch. > I've applied it
Yes, it's a nice thing to add. Thanks too. I reviewed the patch and have some more ideas, which I installed as follows. One more thing (which I didn't do yet) is that there's a reasonable amount of code duplication between ls, du, and date, and it should be refactored at some point. I see you've got a FIXME about that already.... 2005-06-23 Paul Eggert <[EMAIL PROTECTED]> Address the following "du" issues: - The option name "--last-time=TYPE" is different from the ls's option "--time=TYPE" with a similar meaning. I assume this wasn't intended. - --time-style implies --time, but this is not true for "ls". It's better to be consistent. - Since we don't have POSIX compatibility concerns, there's no need for the "posix-" styles, or for support of styles with newlines, or for the "locale" style, except for parsing the TIME_STYLE environment variable. - It's cleaner (and these days, no less efficient) to use functions rather than macros when possible. - struct duinfo doesn't need a 'valid' flag; you can simply use a time stamp that is less than all valid time stamps. - The code needs a bit of reformatting to fit the usual GNU style. * NEWS: du's --last-time option is now --time. * doc/coreutils.texi (ls invocation): Fix typo: --time=use is equivalent to --time=atime, not --time=ctime. (ls invocation, du invocation): Fix typo: --time-style=long-iso is equivalent to a time style with a leading "+". (du invocation): --last-time is now --time. --time-style no longer implies --time. The locale and posix- stuff now works only for TIME_STYLE, not for --time-style. Give equivalent format for --time-style=iso. * src/du.c: Do not include hard-locale.h. (struct duinfo): Remove 'valid' member. All uses changed to use negative nsec instead. (DUIINFO_INI, DUINFO_SET, DUINFO_ADD): Remove. (duinfo_init, duinfo_set, duinfo_add): New functions, taking the role of the removed macros. (opt_time): Renamed from opt_last_time. All uses changed. (TIME_OPTION): Renamed from LAST_TIME_OPTION. All uses changed. (long_options, usage): Rename --last-time to --time. (locale_time_style): Remove. (time_style_args, time_style_types, usage): Remove support for --time-style=locale. (show_date): Now returns void, since nobody looked at the result. Assume FORMAT is not null. An empty FORMAT now outputs an empty time. Simplify nstrftime invocation. (main): Put in ls compatibility workarounds only for TIME_STYLE, not for --time-style. Omit unnecessary space in iso time style. Index: NEWS =================================================================== RCS file: /fetish/cu/NEWS,v retrieving revision 1.298 diff -p -u -r1.298 NEWS --- NEWS 23 Jun 2005 14:47:27 -0000 1.298 +++ NEWS 23 Jun 2005 22:24:38 -0000 @@ -151,7 +151,7 @@ GNU coreutils NEWS dd has new iflag= and oflag= flags "binary" and "text", which have an effect only on nonstandard platforms that distinguish text from binary I/O. - du accepts new options: --last-time[=TYPE] and --time-style=STYLE + du accepts new options: --time[=TYPE] and --time-style=STYLE join now supports a NUL field separator, e.g., "join -t '\0'". join now detects and reports incompatible options, e.g., "join -t x -t y", Index: doc/coreutils.texi =================================================================== RCS file: /fetish/cu/doc/coreutils.texi,v retrieving revision 1.267 diff -p -u -r1.267 coreutils.texi --- doc/coreutils.texi 23 Jun 2005 15:00:29 -0000 1.267 +++ doc/coreutils.texi 23 Jun 2005 22:24:40 -0000 @@ -5677,7 +5677,6 @@ it outputs. By default, sorting is done @item -c @itemx --time=ctime @itemx --time=status [EMAIL PROTECTED] --time=use @opindex -c @opindex --time @opindex [EMAIL PROTECTED], printing or sorting by} @@ -5724,6 +5723,7 @@ Sort by modification time (the @samp{mti @item -u @itemx --time=atime @itemx --time=access [EMAIL PROTECTED] --time=use @opindex -u @opindex --time @opindex use [EMAIL PROTECTED], printing or sorting files by} @@ -6009,7 +6009,7 @@ uses the full timestamp to determine whe List @acronym{ISO} 8601 date and time in minutes, e.g., @samp{2002-03-30 23:45}. These timestamps are shorter than @samp{full-iso} timestamps, and are usually good enough for everyday -work. This style is equivalent to @samp{%Y-%m-%d %H:%M}. +work. This style is equivalent to @samp{+%Y-%m-%d %H:%M}. @item iso List @acronym{ISO} 8601 dates for non-recent timestamps (e.g., @@ -9004,30 +9004,6 @@ Dereference symbolic links (show the dis or directory that the link points to instead of the space used by the link). [EMAIL PROTECTED] --last-time [EMAIL PROTECTED] --last-time [EMAIL PROTECTED] last modified dates, displaying in @command{du} -Show time of the most recent modification of any file in the directory, -or any of its subdirectories. - [EMAIL PROTECTED] --last-time=ctime [EMAIL PROTECTED] --last-time=status [EMAIL PROTECTED] --last-time=use [EMAIL PROTECTED] --last-time [EMAIL PROTECTED] [EMAIL PROTECTED], show the most recent} [EMAIL PROTECTED] status [EMAIL PROTECTED], show the most recent} [EMAIL PROTECTED] use [EMAIL PROTECTED], show the most recent} -Show the most recent status change time (the @samp{ctime} in the inode) of -any file in the directory, instead of the modification time. - [EMAIL PROTECTED] --last-time=atime [EMAIL PROTECTED] --last-time=access [EMAIL PROTECTED] --last-time [EMAIL PROTECTED] [EMAIL PROTECTED], show the most recent} [EMAIL PROTECTED] access [EMAIL PROTECTED], show the most recent} -Show the most recent access time (the @samp{atime} in the inode) of -any file in the directory, instead of the modification time. - @item -P @itemx --no-dereference @opindex -P @@ -9073,12 +9049,35 @@ Display only a total for each argument. Report the size of each directory separately, not including the sizes of subdirectories. [EMAIL PROTECTED] --time [EMAIL PROTECTED] --time [EMAIL PROTECTED] last modified dates, displaying in @command{du} +Show time of the most recent modification of any file in the directory, +or any of its subdirectories. + [EMAIL PROTECTED] --time=ctime [EMAIL PROTECTED] --time=status [EMAIL PROTECTED] --time=use [EMAIL PROTECTED] --time [EMAIL PROTECTED] [EMAIL PROTECTED], show the most recent} [EMAIL PROTECTED] status [EMAIL PROTECTED], show the most recent} [EMAIL PROTECTED] use [EMAIL PROTECTED], show the most recent} +Show the most recent status change time (the @samp{ctime} in the inode) of +any file in the directory, instead of the modification time. + [EMAIL PROTECTED] --time=atime [EMAIL PROTECTED] --time=access [EMAIL PROTECTED] --time [EMAIL PROTECTED] [EMAIL PROTECTED], show the most recent} [EMAIL PROTECTED] access [EMAIL PROTECTED], show the most recent} +Show the most recent access time (the @samp{atime} in the inode) of +any file in the directory, instead of the modification time. + @item [EMAIL PROTECTED] @opindex --time-style @cindex time style -Implicity selects the option @option{--last-time} to show last modified -date if an explicit @option{--last-time} option has not been selected. -List timestamps in style @var{style}. The @var{style} should +List timestamps in style @var{style}. This option has an effect only if +the @option{--time} option is also specified. The @var{style} should be one of the following: @table @samp @@ -9101,49 +9100,21 @@ format with nanosecond precision, e.g., List @acronym{ISO} 8601 date and time in minutes, e.g., @samp{2002-03-30 23:45}. These timestamps are shorter than @samp{full-iso} timestamps, and are usually good enough for everyday -work. This style is equivalent to @samp{%Y-%m-%d %H:%M}. +work. This style is equivalent to @samp{+%Y-%m-%d %H:%M}. @item iso -List @acronym{ISO} 8601 dates for timestamps - [EMAIL PROTECTED] locale [EMAIL PROTECTED] LC_TIME -List timestamps in a locale-dependent form. For example, a Finnish -locale might list timestamps like @samp{maalis 30@ @ 2002}. -Locale-dependent timestamps typically consume more space than @samp{iso} -timestamps and are harder for programs to parse because locale -conventions vary so widely, but they are easier for many people to read. - -The @env{LC_TIME} locale category specifies the timestamp format. The -default @acronym{POSIX} locale uses timestamps like @samp{Mar 30@ -@ 2002}; in this locale, the following two @command{du} invocations are -equivalent: - [EMAIL PROTECTED] -du --last-time --time-style="+%b %e %Y" -du --last-time --time-style="locale" [EMAIL PROTECTED] example - -Other locales behave differently. For example, in a German locale, [EMAIL PROTECTED]"locale"} might be equivalent to [EMAIL PROTECTED]"+%e. %b %Y"} -and might generate timestamps like @samp{30. M@"ar 2002@ }. - [EMAIL PROTECTED] [EMAIL PROTECTED] [EMAIL PROTECTED] LC_TIME -List @acronym{POSIX}-locale timestamps if the @env{LC_TIME} locale -category is @acronym{POSIX}, @var{style} timestamps otherwise. For -example, the default style, which is @samp{posix-long-iso}, lists -timestamps like @samp{Mar 30@ @ 2002} when in -the @acronym{POSIX} locale, and like @samp{2002-03-30 23:45} otherwise. +List @acronym{ISO} 8601 dates for timestamps, e.g., @samp{2002-03-30}. +This style is equivalent to @samp{+%Y-%m-%d}. @end table @vindex TIME_STYLE You can specify the default value of the @option{--time-style} option with the environment variable @env{TIME_STYLE}; if @env{TIME_STYLE} is not set -the default style is @samp{posix-long-iso}. If @env{TIME_STYLE} contains two -styles, separated by a newline (for @command{ls}), the @command{du} uses only -the first of the two styles. +the default style is @samp{long-iso}. For compatibility with @command{ls}, +if @env{TIME_STYLE} begins with @samp{+} and contains a newline, +the newline and any later characters are ignored; if @env{TIME_STYLE} +begins with @samp{posix-} the @samp{posix-} is ignored; and if [EMAIL PROTECTED] is @samp{locale} it is ignored. @item -x @itemx --one-file-system Index: src/du.c =================================================================== RCS file: /fetish/cu/src/du.c,v retrieving revision 1.209 diff -p -u -r1.209 du.c --- src/du.c 23 Jun 2005 15:27:55 -0000 1.209 +++ src/du.c 23 Jun 2005 22:24:40 -0000 @@ -34,7 +34,6 @@ #include "dirname.h" /* for strip_trailing_slashes */ #include "error.h" #include "exclude.h" -#include "hard-locale.h" #include "hash.h" #include "human.h" #include "inttostr.h" @@ -81,43 +80,54 @@ static Hash_table *htab; struct duinfo { - uintmax_t size; /* Size of files in directory */ - time_t dmax; /* Last modified date */ - int nsec; /* Nanoseconds part of date */ - int valid; /* Indicates that date is valid */ + /* Size of files in directory. */ + uintmax_t size; + + /* Latest time stamp found. If dmax == TYPE_MINIMUM (time_t) && nsec < 0, + no time stamp has been found. */ + time_t dmax; + int nsec; }; -/* DUINFO_INI (struct duinfo a); - Initialise duinfo structure. */ -#define DUINFO_INI(a) \ - do { (a).size = 0; (a).dmax = 0; (a).nsec = 0; (a).valid = 0; } while (0) - -/* DUINFO_SET (struct duinfo a, uintmax_t size, time_t date, int nsec) - Set structure data. */ -#define DUINFO_SET(a, fsize, fdmax, fnsec) \ - do { (a).size = (fsize); (a).dmax = (fdmax); (a).nsec = fnsec; (a).valid = 1; } while (0) - -/* DUINFO_ADD (struct duinfo a, const struct duinfo b) - Accumulate directory data. */ -#define DUINFO_ADD(a, b) \ - do { if ( (b).valid ) \ - { \ - (a).size += (b).size; \ - if ( ( ! (a).valid ) || ( (b).dmax > (a).dmax ) ) \ - { \ - (a).dmax = (b).dmax; \ - (a).nsec = (b).nsec; \ - (a).valid = 1; \ - } \ - else if ( ( (b).dmax == (a).dmax ) && ( (b).nsec > (a).nsec ) ) \ - { \ - (a).nsec = (b).nsec; \ - } \ - } \ - } while (0) +/* Initialize directory data. */ +static inline void +duinfo_init (struct duinfo *a) +{ + a->size = 0; + a->dmax = TYPE_MINIMUM (time_t); + a->nsec = -1; +} + +/* Set directory data. */ +static inline void +duinfo_set (struct duinfo *a, uintmax_t size, time_t dmax, int nsec) +{ + a->size = size; + a->dmax = dmax; + a->nsec = nsec; +} + +/* Accumulate directory data. */ +static inline void +duinfo_add (struct duinfo *a, struct duinfo const *b) +{ + a->size += b->size; + if (a->dmax < b->dmax + || (a->dmax == b->dmax && a->nsec < b->nsec)) + { + a->dmax = b->dmax; + a->nsec = b->nsec; + } +} -/* A structure for per-directory level information */ +/* A structure for per-directory level information. */ struct dulevel { - struct duinfo ent; /* Entries in this directory */ - struct duinfo subdir; /* Total for subdirectories */ + /* Entries in this directory. */ + struct duinfo ent; + + /* Total for subdirectories. */ + struct duinfo subdir; }; /* Name under which this program was invoked. */ @@ -150,14 +160,14 @@ static size_t max_depth = SIZE_MAX; /* Human-readable options for output. */ static int human_output_opts; -/* If option non-zero, print most recently modified date, using the specified format */ -static int opt_last_time = 0; +/* If true, print most recently modified date, using the specified format. */ +static bool opt_time = false; -/* Type of time to display. controlled by --last-time */ +/* Type of time to display. controlled by --time. */ enum time_type { - time_mtime, /* default */ + time_mtime, /* default */ time_ctime, time_atime }; @@ -177,7 +187,7 @@ static uintmax_t output_block_size; static struct exclude *exclude; /* Grand total size of all args, in bytes. Also latest modified date. */ -static struct duinfo tot_dui = { 0, 0, 0, 0 }; +static struct duinfo tot_dui = { 0, 0 }; #define IS_DIR_TYPE(Type) \ ((Type) == FTS_DP \ @@ -192,7 +202,7 @@ enum FILES0_FROM_OPTION, HUMAN_SI_OPTION, MAX_DEPTH_OPTION, - LAST_TIME_OPTION, + TIME_OPTION, TIME_STYLE_OPTION }; @@ -219,7 +229,7 @@ static struct option const long_options[ {"separate-dirs", no_argument, NULL, 'S'}, {"summarize", no_argument, NULL, 's'}, {"total", no_argument, NULL, 'c'}, - {"last-time", optional_argument, NULL, LAST_TIME_OPTION}, + {"time", optional_argument, NULL, TIME_OPTION}, {"time-style", required_argument, NULL, TIME_STYLE_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, @@ -238,28 +248,24 @@ static enum time_type const time_types[] /* `full-iso' uses full ISO-style dates and times. `long-iso' uses longer ISO-style time stamps, though shorter than `full-iso'. `iso' uses shorter - ISO-style time stamps. `locale' uses locale-dependent time stamps. */ + ISO-style time stamps. */ enum time_style { full_iso_time_style, /* --time-style=full-iso */ long_iso_time_style, /* --time-style=long-iso */ - iso_time_style, /* --time-style=iso */ - locale_time_style /* --time-style=locale */ + iso_time_style /* --time-style=iso */ }; static char const *const time_style_args[] = { - "full-iso", "long-iso", "iso", "locale", 0 + "full-iso", "long-iso", "iso", NULL }; static enum time_style const time_style_types[] = { - full_iso_time_style, long_iso_time_style, iso_time_style, - locale_time_style, 0 + full_iso_time_style, long_iso_time_style, iso_time_style, 0 }; -static char const posix_prefix[] = "posix-"; - void usage (int status) { @@ -317,14 +323,13 @@ Mandatory arguments to long options are --summarize\n\ "), stdout); fputs (_("\ - --last-time show time of the most recent modification of any\n\ - file in the directory, or any of its subdirectories\n\ - --last-time=WORD show time as WORD instead of modification time:\n\ - atime, access, use, ctime or status; use\n\ + --time show time of the last modification of any file in the\n\ + directory, or any of its subdirectories\n\ + --time=WORD show time as WORD instead of modification time:\n\ + atime, access, use, ctime or status\n\ --time-style=STYLE show times using style STYLE:\n\ - full-iso, long-iso, iso, locale, +FORMAT\n\ - FORMAT is interpreted like `date';\n\ - implies --last-time\n\ + full-iso, long-iso, iso, +FORMAT\n\ + FORMAT is interpreted like `date'\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -404,18 +409,13 @@ hash_init (void) in TIME_FORMAT. If TIME_FORMAT is NULL, use the standard output format. Return zero if successful. */ -static int +static void show_date (const char *format, time_t when, int nsec) { struct tm *tm; char *out = NULL; size_t out_length = 0; - if (format == NULL || *format == '\0') - { - format = "%Y-%m-%d %H:%M"; - } - tm = localtime (&when); if (! tm) { @@ -425,12 +425,11 @@ show_date (const char *format, time_t wh ? imaxtostr (when, buf) : umaxtostr (when, buf))); fputs (buf, stdout); - return 1; + return; } - while (1) + do { - bool done; out = x2nrealloc (out, &out_length, sizeof *out); /* Mark the first byte of the buffer so we can detect the case @@ -438,17 +437,11 @@ show_date (const char *format, time_t wh would not terminate when date was invoked like this `LANG=de date +%p' on a system with good language support. */ out[0] = '\1'; - - done = (nstrftime (out, out_length, format, tm, 0, nsec) - || out[0] == '\0'); - - if (done) - break; } + while (nstrftime (out, out_length, format, tm, 0, nsec) == 0 && out[0]); fputs (out, stdout); free (out); - return 0; } /* Print N_BYTES. Convert it to a readable value before printing. */ @@ -461,15 +454,13 @@ print_only_size (uintmax_t n_bytes) 1, output_block_size), stdout); } -/* Print N_BYTES followed by STRING on a line. - Optionally include last modified date. - Convert N_BYTES to a readable value before printing. */ +/* Print size (and optionally time) indicated by *PDUI, followed by STRING. */ static void print_size (const struct duinfo *pdui, const char *string) { print_only_size (pdui->size); - if (opt_last_time) + if (opt_time) { putchar ('\t'); show_date (time_format, pdui->dmax, pdui->nsec); @@ -552,21 +543,21 @@ process_file (FTS *fts, FTSENT *ent) /* Note that we must not simply return here. We still have to update prev_level and maybe propagate some sums up the hierarchy. */ - DUINFO_INI (dui); + duinfo_init (&dui); print = false; } else { - DUINFO_SET (dui, + duinfo_set (&dui, (apparent_size ? sb->st_size : ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), - ( time_type == time_ctime ) ? sb->st_ctime : - ( time_type == time_atime ) ? sb->st_atime : - sb->st_mtime, - ( time_type == time_ctime ) ? TIMESPEC_NS (sb->st_ctim) : - ( time_type == time_atime ) ? TIMESPEC_NS (sb->st_atim) : - TIMESPEC_NS (sb->st_mtim)); + (time_type == time_ctime ? sb->st_ctime + : time_type == time_atime ? sb->st_atime + : sb->st_mtime), + (time_type == time_ctime ? TIMESPEC_NS (sb->st_ctim) + : time_type == time_atime ? TIMESPEC_NS (sb->st_atim) + : TIMESPEC_NS (sb->st_mtim))); } level = ent->fts_level; @@ -599,8 +590,8 @@ process_file (FTS *fts, FTSENT *ent) for (i = prev_level + 1; i <= level; i++) { - DUINFO_INI (dulvl[i].ent); - DUINFO_INI (dulvl[i].subdir); + duinfo_init (&dulvl[i].ent); + duinfo_init (&dulvl[i].subdir); } } else /* level < prev_level */ @@ -612,11 +603,11 @@ process_file (FTS *fts, FTSENT *ent) Here, the current level is always one smaller than the previous one. */ assert (level == prev_level - 1); - DUINFO_ADD (dui_to_print, dulvl[prev_level].ent); + duinfo_add (&dui_to_print, &dulvl[prev_level].ent); if (!opt_separate_dirs) - DUINFO_ADD (dui_to_print, dulvl[prev_level].subdir); - DUINFO_ADD (dulvl[level].subdir, dulvl[prev_level].ent); - DUINFO_ADD (dulvl[level].subdir, dulvl[prev_level].subdir); + duinfo_add (&dui_to_print, &dulvl[prev_level].subdir); + duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].ent); + duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].subdir); } } @@ -625,11 +616,11 @@ process_file (FTS *fts, FTSENT *ent) /* Let the size of a directory entry contribute to the total for the containing directory, unless --separate-dirs (-S) is specified. */ if ( ! (opt_separate_dirs && IS_DIR_TYPE (ent->fts_info))) - DUINFO_ADD (dulvl[level].ent, dui); + duinfo_add (&dulvl[level].ent, &dui); /* Even if this directory is unreadable or we can't chdir into it, do let its size contribute to the total, ... */ - DUINFO_ADD (tot_dui, dui); + duinfo_add (&tot_dui, &dui); /* ... but don't print out a total for it, since without the size(s) of any potential entries, it could be very misleading. */ @@ -644,9 +635,7 @@ process_file (FTS *fts, FTSENT *ent) if ((IS_DIR_TYPE (ent->fts_info) && level <= max_depth) || ((opt_all && level <= max_depth) || level == 0)) - { - print_size (&dui_to_print, file); - } + print_size (&dui_to_print, file); return ok; } @@ -854,14 +843,15 @@ main (int argc, char **argv) add_exclude (exclude, optarg, EXCLUDE_WILDCARDS); break; - case LAST_TIME_OPTION: - opt_last_time = 1; - if ( optarg ) - time_type = XARGMATCH ("--last-time", optarg, time_args, time_types); + case TIME_OPTION: + opt_time = true; + time_type = + (optarg + ? XARGMATCH ("--time", optarg, time_args, time_types) + : time_mtime); break; case TIME_STYLE_OPTION: - opt_last_time = 1; time_style = optarg; break; @@ -899,22 +889,36 @@ main (int argc, char **argv) if (opt_summarize_only) max_depth = 0; - /* Process time style if printing last times */ - if ( opt_last_time ) + /* Process time style if printing last times. */ + if (opt_time) { - if (! time_style ) - if (! (time_style = getenv ("TIME_STYLE"))) - time_style = "posix-long-iso"; + if (! time_style) + { + time_style = getenv ("TIME_STYLE"); - while (strncmp (time_style, posix_prefix, sizeof posix_prefix - 1) == 0) - { - time_style += sizeof posix_prefix - 1; - } + /* Ignore TIMESTYLE="locale", for compatibility with ls. */ + if (! time_style || STREQ (time_style, "locale")) + time_style = "long-iso"; + else if (*time_style == '+') + { + /* Ignore anything after a newline, for compatibility + with ls. */ + char *p = strchr (time_style, '\n'); + if (p) + *p = '\0'; + } + else + { + /* Ignore "posix-" prefix, for compatibility with ls. */ + static char const posix_prefix[] = "posix-"; + while (strncmp (time_style, posix_prefix, sizeof posix_prefix - 1) + == 0) + time_style += sizeof posix_prefix - 1; + } + } if (*time_style == '+') - { - time_format = time_style + 1; - } + time_format = time_style + 1; else { switch (XARGMATCH ("time style", time_style, @@ -929,12 +933,8 @@ main (int argc, char **argv) break; case iso_time_style: - time_format = "%Y-%m-%d "; + time_format = "%Y-%m-%d"; break; - - case locale_time_style: - if (hard_locale (LC_TIME)) - time_format = dcgettext (NULL, time_format, LC_TIME); } } } _______________________________________________ Bug-coreutils mailing list Bug-coreutils@gnu.org http://lists.gnu.org/mailman/listinfo/bug-coreutils