[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Findutils-patches] [PATCH] Fix Savannah bug #22662 (nanoseconds appende
From: |
James Youngman |
Subject: |
[Findutils-patches] [PATCH] Fix Savannah bug #22662 (nanoseconds appended after "PM" for find -printf %AX in locale en_US.UTF-8). |
Date: |
Fri, 16 May 2008 23:36:07 +0100 |
2008-05-16 James Youngman <address@hidden>
Fix Savannah bug #22662 (nanoseconds appended after "PM" for
find -printf %AX in locale en_US.UTF-8).
* find/pred.c (format_date): Use helper function do_time_format
which can insert the nanoseconds field into the appropriate place
within the formatted time. This fixes Savannah bug #22662.
(do_time_format): New function. Formats the date, inserting the
nanoseconds field after the seconds field, if there is a seconds
field.
(scan_for_digit_differences): New function. Locates the seconds
field.
Signed-off-by: James Youngman <address@hidden>
---
NEWS | 7 +++
find/pred.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 152 insertions(+), 13 deletions(-)
diff --git a/NEWS b/NEWS
index b4b8fdc..c0682b7 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,12 @@
GNU findutils NEWS - User visible changes. -*- outline -*- (allout)
+* Major changes in release 4.4.1, YYYY-MM-DD
+
+** Bug Fixes
+
+#22662: nanoseconds wrongly appended after "PM" for find -printf %AX
+in locale en_US.UTF-8.
+
* Major changes in release 4.4.0, 2008-03-15
The 4.4.0 release of findutils is a stable release, succeeding the
diff --git a/find/pred.c b/find/pred.c
index d758276..d5ada2e 100644
--- a/find/pred.c
+++ b/find/pred.c
@@ -32,6 +32,7 @@
#include <fcntl.h>
#include <locale.h>
#include <openat.h>
+#include <ctype.h>
#include "xalloc.h"
#include "dirname.h"
#include "human.h"
@@ -2018,6 +2019,133 @@ launch (const struct buildcmd_control *ctl,
}
+static boolean
+scan_for_digit_differences(const char *p, const char *q,
+ size_t *first, size_t *n)
+{
+ bool ok = true;
+ bool seen = false;
+ size_t i;
+
+ for (i=0; p[i] && q[i]; i++)
+ {
+ if (p[i] != q[i])
+ {
+ if (!isdigit((unsigned char)q[i]) || !isdigit ((unsigned char)q[i]))
+ return false;
+
+ if (!seen)
+ {
+ *first = i;
+ *n = 1;
+ }
+ else
+ {
+ if (*first - i == *n)
+ {
+ /* Still in the first sequence of differing digits. */
+ ++*n;
+ }
+ else
+ {
+ /* More than one differing contiguous character sequence. */
+ return false;
+ }
+ }
+ }
+ }
+ if (p[i] || q[i])
+ {
+ /* strings are different lengths. */
+ return false;
+ }
+ return true;
+}
+
+
+static char*
+do_time_format (const char *fmt, const struct tm *p, const char *ns, size_t
ns_size)
+{
+ static char *buf = NULL;
+ static size_t buf_size = 0u;
+ char *timefmt = NULL;
+ boolean done = false;
+ struct tm altered_time;
+
+
+ /* If the format expands to nothing (%p in some locales, for
+ * example), strftime can return 0. We actually want to distinguish
+ * the error case where the buffer is too short, so we just prepend
+ * an otherwise uninteresting character to prevent the no-output
+ * case.
+ */
+ timefmt = xmalloc (strlen(fmt) + 2u);
+ sprintf (timefmt, "_%s", fmt);
+
+ /* altered_time is a similar time, but in which both
+ * digits of the seconds field are different.
+ */
+ altered_time = *p;
+ if (altered_time.tm_sec >= 11)
+ altered_time.tm_sec -= 11;
+ else
+ altered_time.tm_sec += 11;
+
+ while (!done)
+ {
+ const size_t buf_used = strftime (buf, buf_size, timefmt, p);
+ if (0 != buf_used)
+ {
+ char *altbuf;
+ size_t i, n;
+ size_t final_len = (buf_used
+ + 1u /* for \0 */
+ - 1u /* because we don't need the initial
underscore */
+ + ns_size);
+ buf = xrealloc (buf, final_len);
+ altbuf = xmalloc (final_len);
+ strftime (altbuf, buf_size, timefmt, &altered_time);
+
+ /* Find the seconds digits; they should be the only changed part.
+ * In theory the result of the two formatting operations could differ
in
+ * more than just one sequence of decimal digits (for example %X
might
+ * in theory return a spelled-out time like "thirty seconds past
noon").
+ * When that happens, we just avoid inserting the nanoseconds field.
+ */
+ if (scan_for_digit_differences (buf, altbuf, &i, &n)
+ && (2==n) && buf[i+n] && !isdigit((unsigned char)buf[i+n+1]))
+ {
+ const size_t end_of_seconds = i + n;
+
+ /* Move the tail (including the \0). Note that this
+ * is a move of an overlapping memory block, so we
+ * must use memmove instead of memcpy. Then insert
+ * the nanoseconds (but not its trailing \0).
+ */
+ memmove (buf+end_of_seconds+ns_size,
+ buf+end_of_seconds,
+ buf_used-(end_of_seconds)+1);
+ memcpy (buf+i+n, ns, ns_size);
+ }
+ else
+ {
+ /* No seconds digits. No need to insert anything. */
+ }
+ /* The first character of buf is the underscore, which we actually
+ * don't want.
+ */
+ free (timefmt);
+ return buf+1;
+ }
+ else
+ {
+ buf = x2nrealloc (buf, &buf_size, 2u);
+ }
+ }
+}
+
+
+
/* Return a static string formatting the time WHEN according to the
* strftime format character KIND.
*
@@ -2105,26 +2233,30 @@ format_date (struct timespec ts, int kind)
* The reason for discouraging this is that in the future, the
* granularity may not be nanoseconds.
*/
- ns_buf[0] = 0;
charsprinted = snprintf(ns_buf, NS_BUF_LEN, ".%09ld0", (long
int)ts.tv_nsec);
assert (charsprinted < NS_BUF_LEN);
}
-
- if (kind != '@'
- && (tm = localtime (&ts.tv_sec))
- && strftime (buf, sizeof buf, fmt, tm))
+ else
{
- /* For %AS, %CS, %TS, add the fractional part of the seconds
- * information.
- */
- if (need_ns_suffix)
+ charsprinted = 0;
+ ns_buf[0] = 0;
+ }
+
+ if (kind != '@')
+ {
+ tm = localtime (&ts.tv_sec);
+ if (tm)
{
- assert ((sizeof buf - strlen(buf)) > strlen(ns_buf));
- strcat(buf, ns_buf);
+ char *s = do_time_format (fmt, tm, ns_buf, charsprinted);
+ if (s)
+ return s;
}
- return buf;
}
- else
+
+ /* If we get to here, either the format was %@, or we have fallen back to it
+ * because strftime failed.
+ */
+ if (1)
{
uintmax_t w = ts.tv_sec;
size_t used, len, remaining;
--
1.5.5.1
- [Findutils-patches] [PATCH] Fix Savannah bug #22662 (nanoseconds appended after "PM" for find -printf %AX in locale en_US.UTF-8).,
James Youngman <=