date: optional support for %N. Closes bug 1861.
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Jun 2010 16:19:15 +0000 (18:19 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Jun 2010 16:19:15 +0000 (18:19 +0200)
function                                             old     new   delta
date_main                                            862    1090    +228
clock_gettime                                          -      41     +41
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/0 up/down: 269/0)             Total: 269 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/Config.in
coreutils/date.c

index ead632a312c14f69739ef671409a4a9a421ce3ff..37e885c1c5a201c6e13c037e5a927044ce527916 100644 (file)
@@ -115,6 +115,13 @@ config FEATURE_DATE_ISOFMT
          Enable option (-I) to output an ISO-8601 compliant
          date/time string.
 
+config FEATURE_DATE_NANO
+       bool "Support %[num]N nanosecond format specifier"
+       default y
+       depends on DATE
+       help
+         Support %[num]N format specifier. Adds ~250 bytes of code.
+
 config FEATURE_DATE_COMPAT
        bool "Support weird 'date MMDDhhmm[[YY]YY][.ss]' format"
        default y
index 4e5b3b0b8591c620840060ca6c6f50c6b25bf349..c1390be76c9322eda108a1e1a2ccd311b298d5d1 100644 (file)
@@ -84,9 +84,9 @@ static const char date_longopts[] ALIGN1 =
 int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int date_main(int argc UNUSED_PARAM, char **argv)
 {
+       struct timespec ts;
        struct tm tm_time;
        char buf_fmt_dt2str[64];
-       time_t tm;
        unsigned opt;
        int ifmt = -1;
        char *date_str;
@@ -161,11 +161,18 @@ int date_main(int argc UNUSED_PARAM, char **argv)
        if (opt & OPT_REFERENCE) {
                struct stat statbuf;
                xstat(filename, &statbuf);
-               tm = statbuf.st_mtime;
+               ts.tv_sec = statbuf.st_mtime;
+#if ENABLE_FEATURE_DATE_NANO
+               ts.tv_nsec = statbuf.st_mtimensec; //or st_atim.tv_nsec?
+#endif
        } else {
-               time(&tm);
+#if ENABLE_FEATURE_DATE_NANO
+               clock_gettime(CLOCK_REALTIME, &ts);
+#else
+               time(&ts.tv_nsec);
+#endif
        }
-       localtime_r(&tm, &tm_time);
+       localtime_r(&ts.tv_sec, &tm_time);
 
        /* If date string is given, update tm_time, and maybe set date */
        if (date_str != NULL) {
@@ -184,12 +191,12 @@ int date_main(int argc UNUSED_PARAM, char **argv)
 
                /* Correct any day of week and day of year etc. fields */
                tm_time.tm_isdst = -1;  /* Be sure to recheck dst */
-               tm = validate_tm_time(date_str, &tm_time);
+               ts.tv_sec = validate_tm_time(date_str, &tm_time);
 
                maybe_set_utc(opt);
 
                /* if setting time, set it */
-               if ((opt & OPT_SET) && stime(&tm) < 0) {
+               if ((opt & OPT_SET) && stime(&ts.tv_sec) < 0) {
                        bb_perror_msg("can't set date");
                }
        }
@@ -222,6 +229,46 @@ int date_main(int argc UNUSED_PARAM, char **argv)
                        fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y";
                }
        }
+#if ENABLE_FEATURE_DATE_NANO
+       else {
+               /* User-specified fmt_dt2str */
+               /* Search for and process "%N" */
+               char *p = fmt_dt2str;
+               while ((p = strchr(p, '%')) != NULL) {
+                       int n, m;
+                       unsigned pres, scale;
+
+                       p++;
+                       if (*p == '%') {
+                               p++;
+                               continue;
+                       }
+                       n = strspn(p, "0123456789");
+                       if (p[n] != 'N') {
+                               p += n;
+                               continue;
+                       }
+                       /* We have "%[nnn]N" */
+                       p[-1] = '\0';
+                       p[n] = '\0';
+                       scale = 1;
+                       pres = 9;
+                       if (n) {
+                               pres = xatoi_u(p);
+                               if (pres == 0)
+                                       pres = 9;
+                               m = 9 - pres;
+                               while (--m >= 0)
+                                       scale *= 10;
+                       }
+
+                       m = p - fmt_dt2str;
+                       p += n + 1;
+                       fmt_dt2str = xasprintf("%s%0*u%s", fmt_dt2str, pres, (unsigned)ts.tv_nsec / scale, p);
+                       p = fmt_dt2str + m;
+               }
+       }
+#endif
 
 #define date_buf bb_common_bufsiz1
        if (*fmt_dt2str == '\0') {