summaryrefslogtreecommitdiff
path: root/lib/strftime.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2005-09-13 22:08:18 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2005-09-13 22:08:18 +0000
commit7846768c6c727afaee4ed22d4ab4fb43d3030cae (patch)
treeb4555483a22b775c424130aa5202f9098c112598 /lib/strftime.c
parent602043e0b8b54c31cb5bd52749a26de442e2b6c9 (diff)
downloadcoreutils-7846768c6c727afaee4ed22d4ab4fb43d3030cae.tar.xz
(my_strftime): Add support for %:z, %::z, %:::z.
Fix bug in formats like %2N.
Diffstat (limited to 'lib/strftime.c')
-rw-r--r--lib/strftime.c83
1 files changed, 67 insertions, 16 deletions
diff --git a/lib/strftime.c b/lib/strftime.c
index b68b4cf5a..e884ea8b8 100644
--- a/lib/strftime.c
+++ b/lib/strftime.c
@@ -480,8 +480,11 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
int digits; /* Max digits for numeric format. */
int number_value; /* Numeric value to be printed. */
unsigned int u_number_value; /* (unsigned int) number_value. */
- bool negative_number; /* 1 if the number is negative. */
+ bool negative_number; /* The number is negative. */
+ bool always_output_a_sign; /* +/- should always be output. */
+ int tz_colon_mask; /* Bitmask of where ':' should appear. */
const CHAR_T *subfmt;
+ CHAR_T sign_char;
CHAR_T *bufp;
CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
? INT_STRLEN_BOUND (time_t)
@@ -489,6 +492,7 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
int width = -1;
bool to_lowcase = false;
bool to_uppcase = false;
+ size_t colons = 0;
bool change_case = false;
int format_char;
@@ -592,6 +596,11 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
pad = *f;
continue;
+ /* This influences the %z format. */
+ case L_(':'):
+ colons++;
+ continue;
+
/* This changes textual output. */
case L_('^'):
to_uppcase = true;
@@ -650,6 +659,11 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
digits = d; \
negative_number = negative; \
u_number_value = v; goto do_signed_number
+#define DO_TZ_OFFSET(d, negative, mask, v) \
+ digits = d; \
+ negative_number = negative; \
+ tz_colon_mask = mask; \
+ u_number_value = v; goto do_tz_offset
#define DO_NUMBER_SPACEPAD(d, v) \
digits = d; \
number_value = v; goto do_number_spacepad
@@ -857,6 +871,10 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
/* All numeric formats set DIGITS and NUMBER_VALUE (or U_NUMBER_VALUE)
and then jump to one of these three labels. */
+ do_tz_offset:
+ always_output_a_sign = true;
+ goto do_number_body;
+
do_number_spacepad:
/* Force `_' flag unless overridden by `0' or `-' flag. */
if (pad != L_('0') && pad != L_('-'))
@@ -868,6 +886,10 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
u_number_value = number_value;
do_signed_number:
+ always_output_a_sign = false;
+ tz_colon_mask = 0;
+
+ do_number_body:
/* Format U_NUMBER_VALUE according to the MODIFIER flag.
NEGATIVE_NUMBER is nonzero if the original number was
negative; in this case it was converted directly to
@@ -904,17 +926,24 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
do
{
+ if (tz_colon_mask & 1)
+ *--bufp = ':';
+ tz_colon_mask >>= 1;
*--bufp = u_number_value % 10 + L_('0');
u_number_value /= 10;
}
- while (u_number_value != 0);
+ while (u_number_value != 0 || tz_colon_mask != 0);
do_number_sign_and_padding:
if (digits < width)
digits = width;
- if (negative_number)
- *--bufp = L_('-');
+ sign_char = (negative_number ? L_('-')
+ : always_output_a_sign ? L_('+')
+ : 0);
+
+ if (sign_char)
+ *--bufp = sign_char;
if (pad != L_('-'))
{
@@ -938,12 +967,12 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
if ((size_t) digits >= maxsize - i)
return 0;
- if (negative_number)
+ if (sign_char)
{
++bufp;
if (p)
- *p++ = L_('-');
+ *p++ = sign_char;
++i;
}
@@ -1012,7 +1041,9 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
goto bad_format;
number_value = ns;
- if (width != -1)
+ if (width == -1)
+ width = 9;
+ else
{
/* Take an explicit width less than 9 as a precision. */
int j;
@@ -1020,7 +1051,7 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
number_value /= 10;
}
- DO_NUMBER (9, number_value);
+ DO_NUMBER (width, number_value);
#endif
case L_('n'):
@@ -1093,6 +1124,7 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
while (t != 0);
digits = 1;
+ always_output_a_sign = false;
goto do_number_sign_and_padding;
}
@@ -1286,6 +1318,9 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
{
int diff;
+ int hour_diff;
+ int min_diff;
+ int sec_diff;
#if HAVE_TM_GMTOFF
diff = tp->tm_gmtoff;
#else
@@ -1324,16 +1359,32 @@ my_strftime (CHAR_T *s, size_t maxsize, const CHAR_T *format,
}
#endif
- if (diff < 0)
+ hour_diff = diff / 60 / 60;
+ min_diff = diff / 60 % 60;
+ sec_diff = diff % 60;
+
+ switch (colons)
{
- add (1, *p = L_('-'));
- diff = -diff;
- }
- else
- add (1, *p = L_('+'));
+ case 0: /* +hhmm */
+ DO_TZ_OFFSET (5, diff < 0, 0, hour_diff * 100 + min_diff);
+
+ case 1: tz_hh_mm: /* +hh:mm */
+ DO_TZ_OFFSET (6, diff < 0, 04, hour_diff * 100 + min_diff);
- diff /= 60;
- DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
+ case 2: tz_hh_mm_ss: /* +hh:mm:ss */
+ DO_TZ_OFFSET (9, diff < 0, 044,
+ hour_diff * 10000 + min_diff * 100 + sec_diff);
+
+ case 3: /* +hh if possible, else +hh:mm, else +hh:mm:ss */
+ if (sec_diff != 0)
+ goto tz_hh_mm_ss;
+ if (min_diff != 0)
+ goto tz_hh_mm;
+ DO_TZ_OFFSET (3, diff < 0, 0, hour_diff);
+
+ default:
+ goto bad_format;
+ }
}
case L_('\0'): /* GNU extension: % at end of format. */