bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] nstrftime: support the ‘+’ flag


From: Paul Eggert
Subject: [PATCH] nstrftime: support the ‘+’ flag
Date: Sun, 24 Feb 2019 23:33:10 -0800

* lib/nstrftime.c (add, __strftime_internal):
Add support for the ‘+’ flag introduced in POSIX.1-2017.
(__strftime_internal): New arg ‘width’.  All uses changed.
(DO_YEARISH, DO_MAYBE_SIGNED_NUMBER): New macros.
---
 ChangeLog       |  8 +++++
 lib/nstrftime.c | 84 ++++++++++++++++++++++++++++++++-----------------
 2 files changed, 64 insertions(+), 28 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 1f4205582..4fe487749 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2019-02-24  Paul Eggert  <address@hidden>
+
+       nstrftime: support the ‘+’ flag
+       * lib/nstrftime.c (add, __strftime_internal):
+       Add support for the ‘+’ flag introduced in POSIX.1-2017.
+       (__strftime_internal): New arg ‘width’.  All uses changed.
+       (DO_YEARISH, DO_MAYBE_SIGNED_NUMBER): New macros.
+
 2019-02-24  Bruno Haible  <address@hidden>
 
        relocatable-prog: Improve verbose output.
diff --git a/lib/nstrftime.c b/lib/nstrftime.c
index 424fb6069..01db02bfe 100644
--- a/lib/nstrftime.c
+++ b/lib/nstrftime.c
@@ -180,7 +180,7 @@ extern char *tzname[];
           if (digits == 0 && _n < _w)                                         \
             {                                                                 \
               size_t _delta = width - _n;                                     \
-              if (pad == L_('0'))                                             \
+              if (pad == L_('0') || pad == L_('+'))                           \
                 memset_zero (p, _delta);                                      \
               else                                                            \
                 memset_space (p, _delta);                                     \
@@ -418,7 +418,7 @@ iso_week_days (int yday, int wday)
 
 static size_t __strftime_internal (STREAM_OR_CHAR_T *, STRFTIME_ARG (size_t)
                                    const CHAR_T *, const struct tm *,
-                                   bool, int, bool *
+                                   bool, int, int, bool *
                                    extra_args_spec LOCALE_PARAM);
 
 /* Write information from TP into S according to the format
@@ -434,7 +434,7 @@ my_strftime (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t 
maxsize)
 {
   bool tzset_called = false;
   return __strftime_internal (s, STRFTIME_ARG (maxsize) format, tp, false,
-                              0, &tzset_called extra_args LOCALE_ARG);
+                              0, -1, &tzset_called extra_args LOCALE_ARG);
 }
 #if defined _LIBC && ! FPRINTFTIME
 libc_hidden_def (my_strftime)
@@ -447,7 +447,7 @@ static size_t
 __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG (size_t maxsize)
                      const CHAR_T *format,
                      const struct tm *tp, bool upcase,
-                     int yr_spec, bool *tzset_called
+                     int yr_spec, int width, bool *tzset_called
                      extra_args_spec LOCALE_PARAM)
 {
 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
@@ -559,7 +559,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
     if (hour12 == 0)
       hour12 = 12;
 
-  for (f = format; *f != '\0'; ++f)
+  for (f = format; *f != '\0'; width = -1, f++)
     {
       int pad = 0;              /* Padding for number ('-', '_', or 0).  */
       int modifier;             /* Field modifier ('E', 'O', or 0).  */
@@ -577,12 +577,12 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
                  + (sizeof (int) < sizeof (time_t)
                     ? INT_STRLEN_BOUND (time_t)
                     : INT_STRLEN_BOUND (int))];
-      int width = -1;
       bool to_lowcase = false;
       bool to_uppcase = upcase;
       size_t colons;
       bool change_case = false;
       int format_char;
+      int subwidth;
 
 #if DO_MULTIBYTE && !defined COMPILE_WIDE
       switch (*f)
@@ -680,6 +680,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
               /* This influences the number formats.  */
             case L_('_'):
             case L_('-'):
+            case L_('+'):
             case L_('0'):
               pad = *f;
               continue;
@@ -698,7 +699,6 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
           break;
         }
 
-      /* As a GNU extension we allow the field width to be specified.  */
       if (ISDIGIT (*f))
         {
           width = 0;
@@ -744,12 +744,16 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
             }                                                                 \
           while (0)
 #define DO_SIGNED_NUMBER(d, negative, v) \
+          DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_signed_number)
+#define DO_YEARISH(d, negative, v) \
+          DO_MAYBE_SIGNED_NUMBER (d, negative, v, do_yearish)
+#define DO_MAYBE_SIGNED_NUMBER(d, negative, v, label) \
           do                                                                  \
             {                                                                 \
               digits = d;                                                     \
               negative_number = negative;                                     \
               u_number_value = v;                                             \
-              goto do_signed_number;                                          \
+              goto label;                                                     \
             }                                                                 \
           while (0)
 
@@ -862,15 +866,17 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
 #endif
 
         subformat:
+          subwidth = -1;
+        subformat_width:
           {
             size_t len = __strftime_internal (NULL, STRFTIME_ARG ((size_t) -1)
                                               subfmt, tp, to_uppcase,
-                                              yr_spec, tzset_called
+                                              pad, subwidth, tzset_called
                                               extra_args LOCALE_ARG);
             add (len, __strftime_internal (p,
                                            STRFTIME_ARG (maxsize - i)
                                            subfmt, tp, to_uppcase,
-                                           yr_spec, tzset_called
+                                           pad, subwidth, tzset_called
                                            extra_args LOCALE_ARG));
           }
           break;
@@ -931,7 +937,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
           {
             int century = tp->tm_year / 100 + TM_YEAR_BASE / 100;
             century -= tp->tm_year % 100 < 0 && 0 < century;
-            DO_SIGNED_NUMBER (2, tp->tm_year < - TM_YEAR_BASE, century);
+            DO_YEARISH (2, tp->tm_year < - TM_YEAR_BASE, century);
           }
 
         case L_('x'):
@@ -972,9 +978,17 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
           always_output_a_sign = true;
           goto do_number_body;
 
+        do_yearish:
+          if (pad == 0)
+            pad = yr_spec;
+          always_output_a_sign
+            = (pad == L_('+')
+               && ((digits == 2 ? 99 : 9999) < u_number_value
+                   || digits < width));
+          goto do_maybe_signed_number;
+
         do_number_spacepad:
-          /* Force '_' flag unless overridden by '0' or '-' flag.  */
-          if (pad != L_('0') && pad != L_('-'))
+          if (pad == 0)
             pad = L_('_');
 
         do_number:
@@ -984,6 +998,8 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
 
         do_signed_number:
           always_output_a_sign = false;
+
+        do_maybe_signed_number:
           tz_colon_mask = 0;
 
         do_number_body:
@@ -1088,8 +1104,19 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
         case L_('F'):
           if (modifier != 0)
             goto bad_format;
+          if (pad == 0 && width < 0)
+            {
+              pad = L_('+');
+              subwidth = 4;
+            }
+          else
+            {
+              subwidth = width - 6;
+              if (subwidth < 0)
+                subwidth = 0;
+            }
           subfmt = L_("%Y-%m-%d");
-          goto subformat;
+          goto subformat_width;
 
         case L_('H'):
           if (modifier == L_('E'))
@@ -1298,17 +1325,18 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
               case L_('g'):
                 {
                   int yy = (tp->tm_year % 100 + year_adjust) % 100;
-                  DO_NUMBER (2, (0 <= yy
-                                 ? yy
-                                 : tp->tm_year < -TM_YEAR_BASE - year_adjust
-                                 ? -yy
-                                 : yy + 100));
+                  DO_YEARISH (2, false,
+                              (0 <= yy
+                               ? yy
+                               : tp->tm_year < -TM_YEAR_BASE - year_adjust
+                               ? -yy
+                               : yy + 100));
                 }
 
               case L_('G'):
-                DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
-                                  (tp->tm_year + (unsigned int) TM_YEAR_BASE
-                                   + year_adjust));
+                DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE - year_adjust,
+                            (tp->tm_year + (unsigned int) TM_YEAR_BASE
+                             + year_adjust));
 
               default:
                 DO_NUMBER (2, days / 7 + 1);
@@ -1339,8 +1367,8 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
 # else
                   subfmt = era->era_format;
 # endif
-                  if (pad != 0)
-                    yr_spec = pad;
+                  if (pad == 0)
+                    pad = yr_spec;
                   goto subformat;
                 }
 #else
@@ -1350,8 +1378,8 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
           if (modifier == L_('O'))
             goto bad_format;
 
-          DO_SIGNED_NUMBER (4, tp->tm_year < -TM_YEAR_BASE,
-                            tp->tm_year + (unsigned int) TM_YEAR_BASE);
+          DO_YEARISH (4, tp->tm_year < -TM_YEAR_BASE,
+                      tp->tm_year + (unsigned int) TM_YEAR_BASE);
 
         case L_('y'):
           if (modifier == L_('E'))
@@ -1361,7 +1389,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
               if (era)
                 {
                   int delta = tp->tm_year - era->start_date[0];
-                  if (yr_spec != 0)
+                  if (pad == 0)
                     pad = yr_spec;
                   DO_NUMBER (2, (era->offset
                                  + delta * era->absolute_direction));
@@ -1375,7 +1403,7 @@ __strftime_internal (STREAM_OR_CHAR_T *s, STRFTIME_ARG 
(size_t maxsize)
             int yy = tp->tm_year % 100;
             if (yy < 0)
               yy = tp->tm_year < - TM_YEAR_BASE ? -yy : yy + 100;
-            DO_NUMBER (2, yy);
+            DO_YEARISH (2, false, yy);
           }
 
         case L_('Z'):
-- 
2.20.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]