test-xvasprintf: silence compiler warnings
[gnulib.git] / lib / strftime.c
index 13c8acc..4ca2ffa 100644 (file)
@@ -1,73 +1,62 @@
-/* Copyright (C) 1991-1999, 2000, 2001, 2003, 2004, 2005, 2006 Free Software
+/* Copyright (C) 1991-1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2009 Free Software
    Foundation, Inc.
 
    NOTE: The canonical source of this file is maintained with the GNU C Library.
    Bugs can be reported to bug-glibc@prep.ai.mit.edu.
 
-   This program is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
-   You should have received a copy of the GNU General Public License along
-   with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #ifdef _LIBC
-# define HAVE_MBLEN 1
-# define HAVE_MBRLEN 1
 # define HAVE_STRUCT_ERA_ENTRY 1
 # define HAVE_TM_GMTOFF 1
 # define HAVE_TM_ZONE 1
 # define HAVE_TZNAME 1
 # define HAVE_TZSET 1
-# define MULTIBYTE_IS_FORMAT_SAFE 1
 # include "../locale/localeinfo.h"
-#endif
-
-#include <ctype.h>
-#include <sys/types.h>         /* Some systems define `time_t' here.  */
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
 #else
-# ifdef HAVE_SYS_TIME_H
-#  include <sys/time.h>
+# include <config.h>
+# if FPRINTFTIME
+#  include "ignore-value.h"
+#  include "fprintftime.h"
 # else
-#  include <time.h>
+#  include "strftime.h"
 # endif
 #endif
-#if HAVE_TZNAME && ! defined tzname
+
+#include <ctype.h>
+#include <time.h>
+
+#if HAVE_TZNAME && !HAVE_DECL_TZNAME
 extern char *tzname[];
 #endif
 
 /* Do multibyte processing if multibytes are supported, unless
    multibyte sequences are safe in formats.  Multibyte sequences are
    safe if they cannot contain byte sequences that look like format
-   conversion specifications.  The GNU C Library uses UTF8 multibyte
-   encoding, which is safe for formats, but strftime.c can be used
-   with other C libraries that use unsafe encodings.  */
-#define DO_MULTIBYTE (HAVE_MBLEN && HAVE_WCHAR_H && ! MULTIBYTE_IS_FORMAT_SAFE)
+   conversion specifications.  The multibyte encodings used by the
+   C library on the various platforms (UTF-8, GB2312, GBK, CP936,
+   GB18030, EUC-TW, BIG5, BIG5-HKSCS, CP950, EUC-JP, EUC-KR, CP949,
+   SHIFT_JIS, CP932, JOHAB) are safe for formats, because the byte '%'
+   cannot occur in a multibyte character except in the first byte.
+   But this does not hold for the DEC-HANYU encoding used on OSF/1.  */
+#if !defined __osf__
+# define MULTIBYTE_IS_FORMAT_SAFE 1
+#endif
+#define DO_MULTIBYTE (! MULTIBYTE_IS_FORMAT_SAFE)
 
 #if DO_MULTIBYTE
-# if HAVE_MBRLEN
-#  include <wchar.h>
-# else
-   /* Simulate mbrlen with mblen as best we can.  */
-#  define mbstate_t int
-#  define mbrlen(s, n, ps) mblen (s, n)
-#  define mbsinit(ps) (*(ps) == 0)
-# endif
+# include <wchar.h>
   static const mbstate_t mbstate_zero;
 #endif
 
@@ -96,13 +85,6 @@ extern char *tzname[];
 # define MEMCPY(d, s, n) memcpy (d, s, n)
 # define STRLEN(s) strlen (s)
 
-# ifdef _LIBC
-#  define MEMPCPY(d, s, n) __mempcpy (d, s, n)
-# else
-#  ifndef HAVE_MEMPCPY
-#   define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
-#  endif
-# endif
 #endif
 
 /* Shift A right by B bits portably, by dividing A by 2**B and
@@ -143,11 +125,10 @@ extern char *tzname[];
 #endif
 
 #if !HAVE_TM_GMTOFF
-/* Portable standalone applications should supply a "time_r.h" that
+/* Portable standalone applications should supply a "time.h" that
    declares a POSIX-compliant localtime_r, for the benefit of older
    implementations that lack localtime_r or have a nonstandard one.
    See the gnulib time_r module for one way to implement this.  */
-# include "time_r.h"
 # undef __gmtime_r
 # undef __localtime_r
 # define __gmtime_r gmtime_r
@@ -180,6 +161,12 @@ extern char *tzname[];
 # define memset_zero(P, Len) (memset (P, '0', Len), (P) += (Len))
 #endif
 
+#if FPRINTFTIME
+# define advance(P, N)
+#else
+# define advance(P, N) ((P) += (N))
+#endif
+
 #define add(n, f)                                                            \
   do                                                                         \
     {                                                                        \
@@ -198,7 +185,7 @@ extern char *tzname[];
                memset_space (p, _delta);                                     \
            }                                                                 \
          f;                                                                  \
-         p += FPRINTFTIME ? 0 : _n;                                          \
+         advance (p, _n);                                                    \
        }                                                                     \
       i += _incr;                                                            \
     } while (0)
@@ -212,12 +199,25 @@ extern char *tzname[];
 #if FPRINTFTIME
 # define cpy(n, s) \
     add ((n),                                                                \
+     do                                                                              \
+       {                                                                     \
         if (to_lowcase)                                                      \
           fwrite_lowcase (p, (s), _n);                                       \
         else if (to_uppcase)                                                 \
           fwrite_uppcase (p, (s), _n);                                       \
         else                                                                 \
-          fwrite ((s), _n, 1, p))
+          {                                                                  \
+            /* We are ignoring the value of fwrite here, in spite of the     \
+               fact that technically, that may not be valid: the fwrite      \
+               specification in POSIX 2008 defers to that of fputc, which    \
+               is intended to be consistent with the one from ISO C,         \
+               which permits failure due to ENOMEM *without* setting the     \
+               stream's error indicator.  */                                 \
+            ignore_value (fwrite ((s), _n, 1, p));                           \
+          }                                                                  \
+       }                                                                     \
+     while (0)                                                               \
+    )
 #else
 # define cpy(n, s)                                                           \
     add ((n),                                                                \
@@ -278,17 +278,12 @@ extern char *tzname[];
 #  define TOLOWER(Ch, L) towlower (Ch)
 # endif
 #else
-# ifdef _LIBC
-#  ifdef USE_IN_EXTENDED_LOCALE_MODEL
-#   define TOUPPER(Ch, L) __toupper_l (Ch, L)
-#   define TOLOWER(Ch, L) __tolower_l (Ch, L)
-#  else
-#   define TOUPPER(Ch, L) toupper (Ch)
-#   define TOLOWER(Ch, L) tolower (Ch)
-#  endif
+# ifdef USE_IN_EXTENDED_LOCALE_MODEL
+#  define TOUPPER(Ch, L) __toupper_l (Ch, L)
+#  define TOLOWER(Ch, L) __tolower_l (Ch, L)
 # else
-#  define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
-#  define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
+#  define TOUPPER(Ch, L) toupper (Ch)
+#  define TOLOWER(Ch, L) tolower (Ch)
 # endif
 #endif
 /* We don't use `isdigit' here since the locale dependent
@@ -387,21 +382,6 @@ iso_week_days (int yday, int wday)
 }
 
 
-#if !(defined _NL_CURRENT || HAVE_STRFTIME)
-static CHAR_T const weekday_name[][10] =
-  {
-    L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
-    L_("Thursday"), L_("Friday"), L_("Saturday")
-  };
-static CHAR_T const month_name[][10] =
-  {
-    L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
-    L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
-    L_("November"), L_("December")
-  };
-#endif
-
-
 /* When compiling this file, GNU applications can #define my_strftime
    to a symbol (typically nstrftime) to get an extended strftime with
    extra arguments UT and NS.  Emacs is a special case for now, but
@@ -473,18 +453,6 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
 # define aw_len STRLEN (a_wkday)
 # define am_len STRLEN (a_month)
 # define ap_len STRLEN (ampm)
-#else
-# if !HAVE_STRFTIME
-#  define f_wkday (weekday_name[tp->tm_wday])
-#  define f_month (month_name[tp->tm_mon])
-#  define a_wkday f_wkday
-#  define a_month f_month
-#  define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
-
-  size_t aw_len = 3;
-  size_t am_len = 3;
-  size_t ap_len = 2;
-# endif
 #endif
   const char *zone;
   size_t i = 0;
@@ -745,7 +713,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
              to_uppcase = true;
              to_lowcase = false;
            }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
+#ifdef _NL_CURRENT
          cpy (aw_len, a_wkday);
          break;
 #else
@@ -760,7 +728,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
              to_uppcase = true;
              to_lowcase = false;
            }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
+#ifdef _NL_CURRENT
          cpy (STRLEN (f_wkday), f_wkday);
          break;
 #else
@@ -776,7 +744,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
            }
          if (modifier != 0)
            goto bad_format;
-#if defined _NL_CURRENT || !HAVE_STRFTIME
+#ifdef _NL_CURRENT
          cpy (am_len, a_month);
          break;
 #else
@@ -791,7 +759,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
              to_uppcase = true;
              to_lowcase = false;
            }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
+#ifdef _NL_CURRENT
          cpy (STRLEN (f_month), f_month);
          break;
 #else
@@ -809,11 +777,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
                     != '\0')))
            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
 #else
-# if HAVE_STRFTIME
          goto underlying_strftime;
-# else
-         subfmt = L_("%a %b %e %H:%M:%S %Y");
-# endif
 #endif
 
        subformat:
@@ -829,7 +793,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
          }
          break;
 
-#if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
+#if !(defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
        underlying_strftime:
          {
            /* The relevant information is available only via the
@@ -880,9 +844,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
                  break;
                }
 #else
-# if HAVE_STRFTIME
              goto underlying_strftime;
-# endif
 #endif
            }
 
@@ -903,11 +865,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
          goto subformat;
 #else
-# if HAVE_STRFTIME
          goto underlying_strftime;
-# else
-         /* Fall through.  */
-# endif
 #endif
        case L_('D'):
          if (modifier != 0)
@@ -972,9 +930,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
                    }
                }
 #else
-# if HAVE_STRFTIME
              goto underlying_strftime;
-# endif
 #endif
            }
 
@@ -1122,7 +1078,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
 
        case L_('P'):
          to_lowcase = true;
-#if !defined _NL_CURRENT && HAVE_STRFTIME
+#ifndef _NL_CURRENT
          format_char = L_('p');
 #endif
          /* FALLTHROUGH */
@@ -1133,7 +1089,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
              to_uppcase = false;
              to_lowcase = true;
            }
-#if defined _NL_CURRENT || !HAVE_STRFTIME
+#ifdef _NL_CURRENT
          cpy (ap_len, ampm);
          break;
 #else
@@ -1145,16 +1101,14 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
          goto subformat;
 
        case L_('r'):
-#if !defined _NL_CURRENT && HAVE_STRFTIME
-         goto underlying_strftime;
-#else
-# ifdef _NL_CURRENT
+#ifdef _NL_CURRENT
          if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
                                                       NLW(T_FMT_AMPM)))
              == L_('\0'))
-# endif
            subfmt = L_("%I:%M:%S %p");
          goto subformat;
+#else
+         goto underlying_strftime;
 #endif
 
        case L_('S'):
@@ -1201,11 +1155,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
          goto subformat;
 #else
-# if HAVE_STRFTIME
          goto underlying_strftime;
-# else
-         /* Fall through.  */
-# endif
 #endif
        case L_('T'):
          subfmt = L_("%H:%M:%S");
@@ -1309,9 +1259,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
                  goto subformat;
                }
 #else
-# if HAVE_STRFTIME
              goto underlying_strftime;
-# endif
 #endif
            }
          if (modifier == L_('O'))
@@ -1332,9 +1280,7 @@ strftime_case_ (bool upcase, STREAM_OR_CHAR_T *s,
                                 + delta * era->absolute_direction));
                }
 #else
-# if HAVE_STRFTIME
              goto underlying_strftime;
-# endif
 #endif
            }