Back to index

glibc  2.9
strftime_l.c
Go to the documentation of this file.
00001 /* Copyright (C) 2002, 2004, 2007, 2008 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 # include <config.h>
00021 #endif
00022 
00023 #ifdef _LIBC
00024 # define USE_IN_EXTENDED_LOCALE_MODEL 1
00025 # define HAVE_LIMITS_H 1
00026 # define HAVE_MBLEN 1
00027 # define HAVE_MBRLEN 1
00028 # define HAVE_STRUCT_ERA_ENTRY 1
00029 # define HAVE_TM_GMTOFF 1
00030 # define HAVE_TM_ZONE 1
00031 # define HAVE_TZNAME 1
00032 # define HAVE_TZSET 1
00033 # define MULTIBYTE_IS_FORMAT_SAFE 1
00034 # define STDC_HEADERS 1
00035 # include "../locale/localeinfo.h"
00036 #endif
00037 
00038 #if defined emacs && !defined HAVE_BCOPY
00039 # define HAVE_MEMCPY 1
00040 #endif
00041 
00042 #include <ctype.h>
00043 #include <sys/types.h>             /* Some systems define `time_t' here.  */
00044 
00045 #ifdef TIME_WITH_SYS_TIME
00046 # include <sys/time.h>
00047 # include <time.h>
00048 #else
00049 # ifdef HAVE_SYS_TIME_H
00050 #  include <sys/time.h>
00051 # else
00052 #  include <time.h>
00053 # endif
00054 #endif
00055 #if HAVE_TZNAME
00056 extern char *tzname[];
00057 #endif
00058 
00059 /* Do multibyte processing if multibytes are supported, unless
00060    multibyte sequences are safe in formats.  Multibyte sequences are
00061    safe if they cannot contain byte sequences that look like format
00062    conversion specifications.  The GNU C Library uses UTF8 multibyte
00063    encoding, which is safe for formats, but strftime.c can be used
00064    with other C libraries that use unsafe encodings.  */
00065 #define DO_MULTIBYTE (HAVE_MBLEN && ! MULTIBYTE_IS_FORMAT_SAFE)
00066 
00067 #if DO_MULTIBYTE
00068 # if HAVE_MBRLEN
00069 #  include <wchar.h>
00070 # else
00071    /* Simulate mbrlen with mblen as best we can.  */
00072 #  define mbstate_t int
00073 #  define mbrlen(s, n, ps) mblen (s, n)
00074 #  define mbsinit(ps) (*(ps) == 0)
00075 # endif
00076   static const mbstate_t mbstate_zero;
00077 #endif
00078 
00079 #if HAVE_LIMITS_H
00080 # include <limits.h>
00081 #endif
00082 
00083 #if STDC_HEADERS
00084 # include <stddef.h>
00085 # include <stdlib.h>
00086 # include <string.h>
00087 # include <stdbool.h>
00088 #else
00089 # ifndef HAVE_MEMCPY
00090 #  define memcpy(d, s, n) bcopy ((s), (d), (n))
00091 # endif
00092 #endif
00093 
00094 #ifdef COMPILE_WIDE
00095 # include <endian.h>
00096 # define CHAR_T wchar_t
00097 # define UCHAR_T unsigned int
00098 # define L_(Str) L##Str
00099 # define NLW(Sym) _NL_W##Sym
00100 
00101 # define MEMCPY(d, s, n) __wmemcpy (d, s, n)
00102 # define STRLEN(s) __wcslen (s)
00103 
00104 #else
00105 # define CHAR_T char
00106 # define UCHAR_T unsigned char
00107 # define L_(Str) Str
00108 # define NLW(Sym) Sym
00109 
00110 # if !defined STDC_HEADERS && !defined HAVE_MEMCPY
00111 #  define MEMCPY(d, s, n) bcopy ((s), (d), (n))
00112 # else
00113 #  define MEMCPY(d, s, n) memcpy ((d), (s), (n))
00114 # endif
00115 # define STRLEN(s) strlen (s)
00116 
00117 # ifdef _LIBC
00118 #  define MEMPCPY(d, s, n) __mempcpy (d, s, n)
00119 # else
00120 #  ifndef HAVE_MEMPCPY
00121 #   define MEMPCPY(d, s, n) ((void *) ((char *) memcpy (d, s, n) + (n)))
00122 #  endif
00123 # endif
00124 #endif
00125 
00126 #ifndef PTR
00127 # ifdef __STDC__
00128 #  define PTR void *
00129 # else
00130 #  define PTR char *
00131 # endif
00132 #endif
00133 
00134 #ifndef CHAR_BIT
00135 # define CHAR_BIT 8
00136 #endif
00137 
00138 #ifndef NULL
00139 # define NULL 0
00140 #endif
00141 
00142 #define TYPE_SIGNED(t) ((t) -1 < 0)
00143 
00144 /* Bound on length of the string representing an integer value of type t.
00145    Subtract one for the sign bit if t is signed;
00146    302 / 1000 is log10 (2) rounded up;
00147    add one for integer division truncation;
00148    add one more for a minus sign if t is signed.  */
00149 #define INT_STRLEN_BOUND(t) \
00150  ((sizeof (t) * CHAR_BIT - TYPE_SIGNED (t)) * 302 / 1000 + 1 + TYPE_SIGNED (t))
00151 
00152 #define TM_YEAR_BASE 1900
00153 
00154 #ifndef __isleap
00155 /* Nonzero if YEAR is a leap year (every 4 years,
00156    except every 100th isn't, and every 400th is).  */
00157 # define __isleap(year)     \
00158   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
00159 #endif
00160 
00161 
00162 #ifdef _LIBC
00163 # define tzname __tzname
00164 # define tzset __tzset
00165 #endif
00166 
00167 #if !HAVE_TM_GMTOFF
00168 /* Portable standalone applications should supply a "time_r.h" that
00169    declares a POSIX-compliant localtime_r, for the benefit of older
00170    implementations that lack localtime_r or have a nonstandard one.
00171    Similarly for gmtime_r.  See the gnulib time_r module for one way
00172    to implement this.  */
00173 # include "time_r.h"
00174 # undef __gmtime_r
00175 # undef __localtime_r
00176 # define __gmtime_r gmtime_r
00177 # define __localtime_r localtime_r
00178 #endif
00179 
00180 
00181 #if !defined memset && !defined HAVE_MEMSET && !defined _LIBC
00182 /* Some systems lack the `memset' function and we don't want to
00183    introduce additional dependencies.  */
00184 /* The SGI compiler reportedly barfs on the trailing null
00185    if we use a string constant as the initializer.  28 June 1997, rms.  */
00186 static const CHAR_T spaces[16] = /* "                " */
00187 {
00188   L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),
00189   L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' '),L_(' ')
00190 };
00191 static const CHAR_T zeroes[16] = /* "0000000000000000" */
00192 {
00193   L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),
00194   L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0'),L_('0')
00195 };
00196 
00197 # define memset_space(P, Len) \
00198   do {                                                               \
00199     int _len = (Len);                                                       \
00200                                                                      \
00201     do                                                               \
00202       {                                                                     \
00203        int _this = _len > 16 ? 16 : _len;                            \
00204        (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T));                \
00205        _len -= _this;                                                       \
00206       }                                                                     \
00207     while (_len > 0);                                                       \
00208   } while (0)
00209 
00210 # define memset_zero(P, Len) \
00211   do {                                                               \
00212     int _len = (Len);                                                       \
00213                                                                      \
00214     do                                                               \
00215       {                                                                     \
00216        int _this = _len > 16 ? 16 : _len;                            \
00217        (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T));                \
00218        _len -= _this;                                                       \
00219       }                                                                     \
00220     while (_len > 0);                                                       \
00221   } while (0)
00222 #else
00223 # ifdef COMPILE_WIDE
00224 #  define memset_space(P, Len) (wmemset ((P), L' ', (Len)), (P) += (Len))
00225 #  define memset_zero(P, Len) (wmemset ((P), L'0', (Len)), (P) += (Len))
00226 # else
00227 #  define memset_space(P, Len) (memset ((P), ' ', (Len)), (P) += (Len))
00228 #  define memset_zero(P, Len) (memset ((P), '0', (Len)), (P) += (Len))
00229 # endif
00230 #endif
00231 
00232 #define add(n, f)                                                    \
00233   do                                                                 \
00234     {                                                                \
00235       int _n = (n);                                                  \
00236       int _delta = width - _n;                                              \
00237       int _incr = _n + (_delta > 0 ? _delta : 0);                           \
00238       if ((size_t) _incr >= maxsize - i)                             \
00239        return 0;                                                     \
00240       if (p)                                                         \
00241        {                                                             \
00242          if (_delta > 0)                                             \
00243            {                                                         \
00244              if (pad == L_('0'))                                     \
00245               memset_zero (p, _delta);                               \
00246              else                                                    \
00247               memset_space (p, _delta);                              \
00248            }                                                         \
00249          f;                                                          \
00250          p += _n;                                                    \
00251        }                                                             \
00252       i += _incr;                                                    \
00253     } while (0)
00254 
00255 #define cpy(n, s) \
00256     add ((n),                                                        \
00257         if (to_lowcase)                                              \
00258           memcpy_lowcase (p, (s), _n LOCALE_ARG);                           \
00259         else if (to_uppcase)                                                \
00260           memcpy_uppcase (p, (s), _n LOCALE_ARG);                           \
00261         else                                                         \
00262           MEMCPY ((PTR) p, (const PTR) (s), _n))
00263 
00264 #ifdef COMPILE_WIDE
00265 # ifndef USE_IN_EXTENDED_LOCALE_MODEL
00266 #  undef __mbsrtowcs_l
00267 #  define __mbsrtowcs_l(d, s, l, st, loc) __mbsrtowcs (d, s, l, st)
00268 # endif
00269 # define widen(os, ws, l) \
00270   {                                                                  \
00271     mbstate_t __st;                                                  \
00272     const char *__s = os;                                            \
00273     memset (&__st, '\0', sizeof (__st));                             \
00274     l = __mbsrtowcs_l (NULL, &__s, 0, &__st, loc);                          \
00275     ws = alloca ((l + 1) * sizeof (wchar_t));                               \
00276     (void) __mbsrtowcs_l (ws, &__s, l, &__st, loc);                         \
00277   }
00278 #endif
00279 
00280 
00281 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
00282 /* We use this code also for the extended locale handling where the
00283    function gets as an additional argument the locale which has to be
00284    used.  To access the values we have to redefine the _NL_CURRENT
00285    macro.  */
00286 # define strftime           __strftime_l
00287 # define wcsftime           __wcsftime_l
00288 # undef _NL_CURRENT
00289 # define _NL_CURRENT(category, item) \
00290   (current->values[_NL_ITEM_INDEX (item)].string)
00291 # define LOCALE_PARAM , loc
00292 # define LOCALE_ARG , loc
00293 # define LOCALE_PARAM_DECL  __locale_t loc;
00294 # define LOCALE_PARAM_PROTO , __locale_t loc
00295 # define HELPER_LOCALE_ARG  , current
00296 #else
00297 # define LOCALE_PARAM
00298 # define LOCALE_PARAM_PROTO
00299 # define LOCALE_ARG
00300 # define LOCALE_PARAM_DECL
00301 # ifdef _LIBC
00302 #  define HELPER_LOCALE_ARG , _NL_CURRENT_DATA (LC_TIME)
00303 # else
00304 #  define HELPER_LOCALE_ARG
00305 # endif
00306 #endif
00307 
00308 #ifdef COMPILE_WIDE
00309 # ifdef USE_IN_EXTENDED_LOCALE_MODEL
00310 #  define TOUPPER(Ch, L) __towupper_l (Ch, L)
00311 #  define TOLOWER(Ch, L) __towlower_l (Ch, L)
00312 # else
00313 #  define TOUPPER(Ch, L) towupper (Ch)
00314 #  define TOLOWER(Ch, L) towlower (Ch)
00315 # endif
00316 #else
00317 # ifdef _LIBC
00318 #  ifdef USE_IN_EXTENDED_LOCALE_MODEL
00319 #   define TOUPPER(Ch, L) __toupper_l (Ch, L)
00320 #   define TOLOWER(Ch, L) __tolower_l (Ch, L)
00321 #  else
00322 #   define TOUPPER(Ch, L) toupper (Ch)
00323 #   define TOLOWER(Ch, L) tolower (Ch)
00324 #  endif
00325 # else
00326 #  define TOUPPER(Ch, L) (islower (Ch) ? toupper (Ch) : (Ch))
00327 #  define TOLOWER(Ch, L) (isupper (Ch) ? tolower (Ch) : (Ch))
00328 # endif
00329 #endif
00330 /* We don't use `isdigit' here since the locale dependent
00331    interpretation is not what we want here.  We only need to accept
00332    the arabic digits in the ASCII range.  One day there is perhaps a
00333    more reliable way to accept other sets of digits.  */
00334 #define ISDIGIT(Ch) ((unsigned int) (Ch) - L_('0') <= 9)
00335 
00336 static CHAR_T *memcpy_lowcase (CHAR_T *dest, const CHAR_T *src,
00337                             size_t len LOCALE_PARAM_PROTO) __THROW;
00338 
00339 static CHAR_T *
00340 memcpy_lowcase (dest, src, len LOCALE_PARAM)
00341      CHAR_T *dest;
00342      const CHAR_T *src;
00343      size_t len;
00344      LOCALE_PARAM_DECL
00345 {
00346   while (len-- > 0)
00347     dest[len] = TOLOWER ((UCHAR_T) src[len], loc);
00348   return dest;
00349 }
00350 
00351 static CHAR_T *memcpy_uppcase (CHAR_T *dest, const CHAR_T *src,
00352                             size_t len LOCALE_PARAM_PROTO) __THROW;
00353 
00354 static CHAR_T *
00355 memcpy_uppcase (dest, src, len LOCALE_PARAM)
00356      CHAR_T *dest;
00357      const CHAR_T *src;
00358      size_t len;
00359      LOCALE_PARAM_DECL
00360 {
00361   while (len-- > 0)
00362     dest[len] = TOUPPER ((UCHAR_T) src[len], loc);
00363   return dest;
00364 }
00365 
00366 
00367 #if ! HAVE_TM_GMTOFF
00368 /* Yield the difference between *A and *B,
00369    measured in seconds, ignoring leap seconds.  */
00370 # define tm_diff ftime_tm_diff
00371 static int tm_diff (const struct tm *, const struct tm *) __THROW;
00372 static int
00373 tm_diff (a, b)
00374      const struct tm *a;
00375      const struct tm *b;
00376 {
00377   /* Compute intervening leap days correctly even if year is negative.
00378      Take care to avoid int overflow in leap day calculations,
00379      but it's OK to assume that A and B are close to each other.  */
00380   int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3);
00381   int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3);
00382   int a100 = a4 / 25 - (a4 % 25 < 0);
00383   int b100 = b4 / 25 - (b4 % 25 < 0);
00384   int a400 = a100 >> 2;
00385   int b400 = b100 >> 2;
00386   int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
00387   int years = a->tm_year - b->tm_year;
00388   int days = (365 * years + intervening_leap_days
00389              + (a->tm_yday - b->tm_yday));
00390   return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
00391               + (a->tm_min - b->tm_min))
00392          + (a->tm_sec - b->tm_sec));
00393 }
00394 #endif /* ! HAVE_TM_GMTOFF */
00395 
00396 
00397 
00398 /* The number of days from the first day of the first ISO week of this
00399    year to the year day YDAY with week day WDAY.  ISO weeks start on
00400    Monday; the first ISO week has the year's first Thursday.  YDAY may
00401    be as small as YDAY_MINIMUM.  */
00402 #define ISO_WEEK_START_WDAY 1 /* Monday */
00403 #define ISO_WEEK1_WDAY 4 /* Thursday */
00404 #define YDAY_MINIMUM (-366)
00405 static int iso_week_days (int, int) __THROW;
00406 #ifdef __GNUC__
00407 __inline__
00408 #endif
00409 static int
00410 iso_week_days (yday, wday)
00411      int yday;
00412      int wday;
00413 {
00414   /* Add enough to the first operand of % to make it nonnegative.  */
00415   int big_enough_multiple_of_7 = (-YDAY_MINIMUM / 7 + 2) * 7;
00416   return (yday
00417          - (yday - wday + ISO_WEEK1_WDAY + big_enough_multiple_of_7) % 7
00418          + ISO_WEEK1_WDAY - ISO_WEEK_START_WDAY);
00419 }
00420 
00421 
00422 #if !(defined _NL_CURRENT || HAVE_STRFTIME)
00423 static CHAR_T const weekday_name[][10] =
00424   {
00425     L_("Sunday"), L_("Monday"), L_("Tuesday"), L_("Wednesday"),
00426     L_("Thursday"), L_("Friday"), L_("Saturday")
00427   };
00428 static CHAR_T const month_name[][10] =
00429   {
00430     L_("January"), L_("February"), L_("March"), L_("April"), L_("May"),
00431     L_("June"), L_("July"), L_("August"), L_("September"), L_("October"),
00432     L_("November"), L_("December")
00433   };
00434 #endif
00435 
00436 
00437 #ifdef emacs
00438 # define my_strftime emacs_strftimeu
00439 # define ut_argument , ut
00440 # define ut_argument_spec int ut;
00441 # define ut_argument_spec_iso , int ut
00442 #else
00443 # ifdef COMPILE_WIDE
00444 #  define my_strftime wcsftime
00445 #  define nl_get_alt_digit _nl_get_walt_digit
00446 # else
00447 #  define my_strftime strftime
00448 #  define nl_get_alt_digit _nl_get_alt_digit
00449 # endif
00450 # define ut_argument
00451 # define ut_argument_spec
00452 # define ut_argument_spec_iso
00453 /* We don't have this information in general.  */
00454 # define ut 0
00455 #endif
00456 
00457 static size_t __strftime_internal (CHAR_T *, size_t, const CHAR_T *,
00458                                const struct tm *, bool *
00459                                ut_argument_spec_iso
00460                                LOCALE_PARAM_PROTO) __THROW;
00461 
00462 /* Write information from TP into S according to the format
00463    string FORMAT, writing no more that MAXSIZE characters
00464    (including the terminating '\0') and returning number of
00465    characters written.  If S is NULL, nothing will be written
00466    anywhere, so to determine how many characters would be
00467    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
00468 
00469 size_t
00470 my_strftime (s, maxsize, format, tp ut_argument LOCALE_PARAM)
00471      CHAR_T *s;
00472      size_t maxsize;
00473      const CHAR_T *format;
00474      const struct tm *tp;
00475      ut_argument_spec
00476      LOCALE_PARAM_DECL
00477 {
00478 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
00479   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
00480      Work around this bug by copying *tp before it might be munged.  */
00481   struct tm tmcopy;
00482   tmcopy = *tp;
00483   tp = &tmcopy;
00484 #endif
00485   bool tzset_called = false;
00486   return __strftime_internal (s, maxsize, format, tp, &tzset_called
00487                            ut_argument LOCALE_ARG);
00488 }
00489 #ifdef _LIBC
00490 libc_hidden_def (my_strftime)
00491 #endif
00492 
00493 static size_t
00494 __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
00495                    LOCALE_PARAM)
00496       CHAR_T *s;
00497       size_t maxsize;
00498       const CHAR_T *format;
00499       const struct tm *tp;
00500       bool *tzset_called;
00501       ut_argument_spec
00502       LOCALE_PARAM_DECL
00503 {
00504 #if defined _LIBC && defined USE_IN_EXTENDED_LOCALE_MODEL
00505   struct locale_data *const current = loc->__locales[LC_TIME];
00506 #endif
00507 
00508   int hour12 = tp->tm_hour;
00509 #ifdef _NL_CURRENT
00510   /* We cannot make the following values variables since we must delay
00511      the evaluation of these values until really needed since some
00512      expressions might not be valid in every situation.  The `struct tm'
00513      might be generated by a strptime() call that initialized
00514      only a few elements.  Dereference the pointers only if the format
00515      requires this.  Then it is ok to fail if the pointers are invalid.  */
00516 # define a_wkday \
00517   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
00518 # define f_wkday \
00519   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
00520 # define a_month \
00521   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
00522 # define f_month \
00523   ((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
00524 # define ampm \
00525   ((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11                  \
00526                              ? NLW(PM_STR) : NLW(AM_STR)))
00527 
00528 # define aw_len STRLEN (a_wkday)
00529 # define am_len STRLEN (a_month)
00530 # define ap_len STRLEN (ampm)
00531 #else
00532 # if !HAVE_STRFTIME
00533 #  define f_wkday (weekday_name[tp->tm_wday])
00534 #  define f_month (month_name[tp->tm_mon])
00535 #  define a_wkday f_wkday
00536 #  define a_month f_month
00537 #  define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
00538 
00539   size_t aw_len = 3;
00540   size_t am_len = 3;
00541   size_t ap_len = 2;
00542 # endif
00543 #endif
00544   const char *zone;
00545   size_t i = 0;
00546   CHAR_T *p = s;
00547   const CHAR_T *f;
00548 #if DO_MULTIBYTE && !defined COMPILE_WIDE
00549   const char *format_end = NULL;
00550 #endif
00551 
00552   zone = NULL;
00553 #if HAVE_TM_ZONE
00554   /* The POSIX test suite assumes that setting
00555      the environment variable TZ to a new value before calling strftime()
00556      will influence the result (the %Z format) even if the information in
00557      TP is computed with a totally different time zone.
00558      This is bogus: though POSIX allows bad behavior like this,
00559      POSIX does not require it.  Do the right thing instead.  */
00560   zone = (const char *) tp->tm_zone;
00561 #endif
00562 #if HAVE_TZNAME
00563   if (ut)
00564     {
00565       if (! (zone && *zone))
00566        zone = "GMT";
00567     }
00568 #endif
00569 
00570   if (hour12 > 12)
00571     hour12 -= 12;
00572   else
00573     if (hour12 == 0)
00574       hour12 = 12;
00575 
00576   for (f = format; *f != '\0'; ++f)
00577     {
00578       int pad = 0;          /* Padding for number ('-', '_', or 0).  */
00579       int modifier;         /* Field modifier ('E', 'O', or 0).  */
00580       int digits;           /* Max digits for numeric format.  */
00581       int number_value;     /* Numeric value to be printed.  */
00582       int negative_number;  /* 1 if the number is negative.  */
00583       const CHAR_T *subfmt;
00584       CHAR_T *bufp;
00585       CHAR_T buf[1 + (sizeof (int) < sizeof (time_t)
00586                     ? INT_STRLEN_BOUND (time_t)
00587                     : INT_STRLEN_BOUND (int))];
00588       int width = -1;
00589       int to_lowcase = 0;
00590       int to_uppcase = 0;
00591       int change_case = 0;
00592       int format_char;
00593 
00594 #if DO_MULTIBYTE && !defined COMPILE_WIDE
00595       switch (*f)
00596        {
00597        case L_('%'):
00598          break;
00599 
00600        case L_('\b'): case L_('\t'): case L_('\n'):
00601        case L_('\v'): case L_('\f'): case L_('\r'):
00602        case L_(' '): case L_('!'): case L_('"'): case L_('#'): case L_('&'):
00603        case L_('\''): case L_('('): case L_(')'): case L_('*'): case L_('+'):
00604        case L_(','): case L_('-'): case L_('.'): case L_('/'): case L_('0'):
00605        case L_('1'): case L_('2'): case L_('3'): case L_('4'): case L_('5'):
00606        case L_('6'): case L_('7'): case L_('8'): case L_('9'): case L_(':'):
00607        case L_(';'): case L_('<'): case L_('='): case L_('>'): case L_('?'):
00608        case L_('A'): case L_('B'): case L_('C'): case L_('D'): case L_('E'):
00609        case L_('F'): case L_('G'): case L_('H'): case L_('I'): case L_('J'):
00610        case L_('K'): case L_('L'): case L_('M'): case L_('N'): case L_('O'):
00611        case L_('P'): case L_('Q'): case L_('R'): case L_('S'): case L_('T'):
00612        case L_('U'): case L_('V'): case L_('W'): case L_('X'): case L_('Y'):
00613        case L_('Z'): case L_('['): case L_('\\'): case L_(']'): case L_('^'):
00614        case L_('_'): case L_('a'): case L_('b'): case L_('c'): case L_('d'):
00615        case L_('e'): case L_('f'): case L_('g'): case L_('h'): case L_('i'):
00616        case L_('j'): case L_('k'): case L_('l'): case L_('m'): case L_('n'):
00617        case L_('o'): case L_('p'): case L_('q'): case L_('r'): case L_('s'):
00618        case L_('t'): case L_('u'): case L_('v'): case L_('w'): case L_('x'):
00619        case L_('y'): case L_('z'): case L_('{'): case L_('|'): case L_('}'):
00620        case L_('~'):
00621          /* The C Standard requires these 98 characters (plus '%') to
00622             be in the basic execution character set.  None of these
00623             characters can start a multibyte sequence, so they need
00624             not be analyzed further.  */
00625          add (1, *p = *f);
00626          continue;
00627 
00628        default:
00629          /* Copy this multibyte sequence until we reach its end, find
00630             an error, or come back to the initial shift state.  */
00631          {
00632            mbstate_t mbstate = mbstate_zero;
00633            size_t len = 0;
00634            size_t fsize;
00635 
00636            if (! format_end)
00637              format_end = f + strlen (f) + 1;
00638            fsize = format_end - f;
00639 
00640            do
00641              {
00642               size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
00643 
00644               if (bytes == 0)
00645                 break;
00646 
00647               if (bytes == (size_t) -2)
00648                 {
00649                   len += strlen (f + len);
00650                   break;
00651                 }
00652 
00653               if (bytes == (size_t) -1)
00654                 {
00655                   len++;
00656                   break;
00657                 }
00658 
00659               len += bytes;
00660              }
00661            while (! mbsinit (&mbstate));
00662 
00663            cpy (len, f);
00664            f += len - 1;
00665            continue;
00666          }
00667        }
00668 
00669 #else /* ! DO_MULTIBYTE */
00670 
00671       /* Either multibyte encodings are not supported, they are
00672         safe for formats, so any non-'%' byte can be copied through,
00673         or this is the wide character version.  */
00674       if (*f != L_('%'))
00675        {
00676          add (1, *p = *f);
00677          continue;
00678        }
00679 
00680 #endif /* ! DO_MULTIBYTE */
00681 
00682       /* Check for flags that can modify a format.  */
00683       while (1)
00684        {
00685          switch (*++f)
00686            {
00687              /* This influences the number formats.  */
00688            case L_('_'):
00689            case L_('-'):
00690            case L_('0'):
00691              pad = *f;
00692              continue;
00693 
00694              /* This changes textual output.  */
00695            case L_('^'):
00696              to_uppcase = 1;
00697              continue;
00698            case L_('#'):
00699              change_case = 1;
00700              continue;
00701 
00702            default:
00703              break;
00704            }
00705          break;
00706        }
00707 
00708       /* As a GNU extension we allow to specify the field width.  */
00709       if (ISDIGIT (*f))
00710        {
00711          width = 0;
00712          do
00713            {
00714              if (width > INT_MAX / 10
00715                 || (width == INT_MAX / 10 && *f - L_('0') > INT_MAX % 10))
00716               /* Avoid overflow.  */
00717               width = INT_MAX;
00718              else
00719               {
00720                 width *= 10;
00721                 width += *f - L_('0');
00722               }
00723              ++f;
00724            }
00725          while (ISDIGIT (*f));
00726        }
00727 
00728       /* Check for modifiers.  */
00729       switch (*f)
00730        {
00731        case L_('E'):
00732        case L_('O'):
00733          modifier = *f++;
00734          break;
00735 
00736        default:
00737          modifier = 0;
00738          break;
00739        }
00740 
00741       /* Now do the specified format.  */
00742       format_char = *f;
00743       switch (format_char)
00744        {
00745 #define DO_NUMBER(d, v) \
00746          digits = d > width ? d : width;                             \
00747          number_value = v; goto do_number
00748 #define DO_NUMBER_SPACEPAD(d, v) \
00749          digits = d > width ? d : width;                             \
00750          number_value = v; goto do_number_spacepad
00751 
00752        case L_('%'):
00753          if (modifier != 0)
00754            goto bad_format;
00755          add (1, *p = *f);
00756          break;
00757 
00758        case L_('a'):
00759          if (modifier != 0)
00760            goto bad_format;
00761          if (change_case)
00762            {
00763              to_uppcase = 1;
00764              to_lowcase = 0;
00765            }
00766 #if defined _NL_CURRENT || !HAVE_STRFTIME
00767          cpy (aw_len, a_wkday);
00768          break;
00769 #else
00770          goto underlying_strftime;
00771 #endif
00772 
00773        case 'A':
00774          if (modifier != 0)
00775            goto bad_format;
00776          if (change_case)
00777            {
00778              to_uppcase = 1;
00779              to_lowcase = 0;
00780            }
00781 #if defined _NL_CURRENT || !HAVE_STRFTIME
00782          cpy (STRLEN (f_wkday), f_wkday);
00783          break;
00784 #else
00785          goto underlying_strftime;
00786 #endif
00787 
00788        case L_('b'):
00789        case L_('h'):
00790          if (change_case)
00791            {
00792              to_uppcase = 1;
00793              to_lowcase = 0;
00794            }
00795          if (modifier != 0)
00796            goto bad_format;
00797 #if defined _NL_CURRENT || !HAVE_STRFTIME
00798          cpy (am_len, a_month);
00799          break;
00800 #else
00801          goto underlying_strftime;
00802 #endif
00803 
00804        case L_('B'):
00805          if (modifier != 0)
00806            goto bad_format;
00807          if (change_case)
00808            {
00809              to_uppcase = 1;
00810              to_lowcase = 0;
00811            }
00812 #if defined _NL_CURRENT || !HAVE_STRFTIME
00813          cpy (STRLEN (f_month), f_month);
00814          break;
00815 #else
00816          goto underlying_strftime;
00817 #endif
00818 
00819        case L_('c'):
00820          if (modifier == L_('O'))
00821            goto bad_format;
00822 #ifdef _NL_CURRENT
00823          if (! (modifier == 'E'
00824                && (*(subfmt =
00825                      (const CHAR_T *) _NL_CURRENT (LC_TIME,
00826                                                NLW(ERA_D_T_FMT)))
00827                    != '\0')))
00828            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
00829 #else
00830 # if HAVE_STRFTIME
00831          goto underlying_strftime;
00832 # else
00833          subfmt = L_("%a %b %e %H:%M:%S %Y");
00834 # endif
00835 #endif
00836 
00837        subformat:
00838          {
00839            CHAR_T *old_start = p;
00840            size_t len = __strftime_internal (NULL, (size_t) -1, subfmt,
00841                                          tp, tzset_called ut_argument
00842                                          LOCALE_ARG);
00843            add (len, __strftime_internal (p, maxsize - i, subfmt,
00844                                       tp, tzset_called ut_argument
00845                                       LOCALE_ARG));
00846 
00847            if (to_uppcase)
00848              while (old_start < p)
00849               {
00850                 *old_start = TOUPPER ((UCHAR_T) *old_start, loc);
00851                 ++old_start;
00852               }
00853          }
00854          break;
00855 
00856 #if HAVE_STRFTIME && ! (defined _NL_CURRENT && HAVE_STRUCT_ERA_ENTRY)
00857        underlying_strftime:
00858          {
00859            /* The relevant information is available only via the
00860               underlying strftime implementation, so use that.  */
00861            char ufmt[4];
00862            char *u = ufmt;
00863            char ubuf[1024]; /* enough for any single format in practice */
00864            size_t len;
00865            /* Make sure we're calling the actual underlying strftime.
00866               In some cases, config.h contains something like
00867               "#define strftime rpl_strftime".  */
00868 # ifdef strftime
00869 #  undef strftime
00870            size_t strftime ();
00871 # endif
00872 
00873            *u++ = '%';
00874            if (modifier != 0)
00875              *u++ = modifier;
00876            *u++ = format_char;
00877            *u = '\0';
00878            len = strftime (ubuf, sizeof ubuf, ufmt, tp);
00879            if (len == 0 && ubuf[0] != '\0')
00880              return 0;
00881            cpy (len, ubuf);
00882          }
00883          break;
00884 #endif
00885 
00886        case L_('C'):
00887          if (modifier == L_('O'))
00888            goto bad_format;
00889          if (modifier == L_('E'))
00890            {
00891 #if HAVE_STRUCT_ERA_ENTRY
00892              struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
00893              if (era)
00894               {
00895 # ifdef COMPILE_WIDE
00896                 size_t len = __wcslen (era->era_wname);
00897                 cpy (len, era->era_wname);
00898 # else
00899                 size_t len = strlen (era->era_name);
00900                 cpy (len, era->era_name);
00901 # endif
00902                 break;
00903               }
00904 #else
00905 # if HAVE_STRFTIME
00906              goto underlying_strftime;
00907 # endif
00908 #endif
00909            }
00910 
00911          {
00912            int year = tp->tm_year + TM_YEAR_BASE;
00913            DO_NUMBER (1, year / 100 - (year % 100 < 0));
00914          }
00915 
00916        case L_('x'):
00917          if (modifier == L_('O'))
00918            goto bad_format;
00919 #ifdef _NL_CURRENT
00920          if (! (modifier == L_('E')
00921                && (*(subfmt =
00922                      (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
00923                    != L_('\0'))))
00924            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
00925          goto subformat;
00926 #else
00927 # if HAVE_STRFTIME
00928          goto underlying_strftime;
00929 # else
00930          /* Fall through.  */
00931 # endif
00932 #endif
00933        case L_('D'):
00934          if (modifier != 0)
00935            goto bad_format;
00936          subfmt = L_("%m/%d/%y");
00937          goto subformat;
00938 
00939        case L_('d'):
00940          if (modifier == L_('E'))
00941            goto bad_format;
00942 
00943          DO_NUMBER (2, tp->tm_mday);
00944 
00945        case L_('e'):
00946          if (modifier == L_('E'))
00947            goto bad_format;
00948 
00949          DO_NUMBER_SPACEPAD (2, tp->tm_mday);
00950 
00951          /* All numeric formats set DIGITS and NUMBER_VALUE and then
00952             jump to one of these two labels.  */
00953 
00954        do_number_spacepad:
00955          /* Force `_' flag unless overwritten by `0' or '-' flag.  */
00956          if (pad != L_('0') && pad != L_('-'))
00957            pad = L_('_');
00958 
00959        do_number:
00960          /* Format the number according to the MODIFIER flag.  */
00961 
00962          if (modifier == L_('O') && 0 <= number_value)
00963            {
00964 #ifdef _NL_CURRENT
00965              /* Get the locale specific alternate representation of
00966                the number NUMBER_VALUE.  If none exist NULL is returned.  */
00967              const CHAR_T *cp = nl_get_alt_digit (number_value
00968                                              HELPER_LOCALE_ARG);
00969 
00970              if (cp != NULL)
00971               {
00972                 size_t digitlen = STRLEN (cp);
00973                 if (digitlen != 0)
00974                   {
00975                     cpy (digitlen, cp);
00976                     break;
00977                   }
00978               }
00979 #else
00980 # if HAVE_STRFTIME
00981              goto underlying_strftime;
00982 # endif
00983 #endif
00984            }
00985          {
00986            unsigned int u = number_value;
00987 
00988            bufp = buf + sizeof (buf) / sizeof (buf[0]);
00989            negative_number = number_value < 0;
00990 
00991            if (negative_number)
00992              u = -u;
00993 
00994            do
00995              *--bufp = u % 10 + L_('0');
00996            while ((u /= 10) != 0);
00997          }
00998 
00999        do_number_sign_and_padding:
01000          if (negative_number)
01001            *--bufp = L_('-');
01002 
01003          if (pad != L_('-'))
01004            {
01005              int padding = digits - (buf + (sizeof (buf) / sizeof (buf[0]))
01006                                   - bufp);
01007 
01008              if (padding > 0)
01009               {
01010                 if (pad == L_('_'))
01011                   {
01012                     if ((size_t) padding >= maxsize - i)
01013                      return 0;
01014 
01015                     if (p)
01016                      memset_space (p, padding);
01017                     i += padding;
01018                     width = width > padding ? width - padding : 0;
01019                   }
01020                 else
01021                   {
01022                     if ((size_t) digits >= maxsize - i)
01023                      return 0;
01024 
01025                     if (negative_number)
01026                      {
01027                        ++bufp;
01028 
01029                        if (p)
01030                          *p++ = L_('-');
01031                        ++i;
01032                      }
01033 
01034                     if (p)
01035                      memset_zero (p, padding);
01036                     i += padding;
01037                     width = 0;
01038                   }
01039               }
01040            }
01041 
01042          cpy (buf + sizeof (buf) / sizeof (buf[0]) - bufp, bufp);
01043          break;
01044 
01045        case L_('F'):
01046          if (modifier != 0)
01047            goto bad_format;
01048          subfmt = L_("%Y-%m-%d");
01049          goto subformat;
01050 
01051        case L_('H'):
01052          if (modifier == L_('E'))
01053            goto bad_format;
01054 
01055          DO_NUMBER (2, tp->tm_hour);
01056 
01057        case L_('I'):
01058          if (modifier == L_('E'))
01059            goto bad_format;
01060 
01061          DO_NUMBER (2, hour12);
01062 
01063        case L_('k'):        /* GNU extension.  */
01064          if (modifier == L_('E'))
01065            goto bad_format;
01066 
01067          DO_NUMBER_SPACEPAD (2, tp->tm_hour);
01068 
01069        case L_('l'):        /* GNU extension.  */
01070          if (modifier == L_('E'))
01071            goto bad_format;
01072 
01073          DO_NUMBER_SPACEPAD (2, hour12);
01074 
01075        case L_('j'):
01076          if (modifier == L_('E'))
01077            goto bad_format;
01078 
01079          DO_NUMBER (3, 1 + tp->tm_yday);
01080 
01081        case L_('M'):
01082          if (modifier == L_('E'))
01083            goto bad_format;
01084 
01085          DO_NUMBER (2, tp->tm_min);
01086 
01087        case L_('m'):
01088          if (modifier == L_('E'))
01089            goto bad_format;
01090 
01091          DO_NUMBER (2, tp->tm_mon + 1);
01092 
01093        case L_('n'):
01094          add (1, *p = L_('\n'));
01095          break;
01096 
01097        case L_('P'):
01098          to_lowcase = 1;
01099 #if !defined _NL_CURRENT && HAVE_STRFTIME
01100          format_char = L_('p');
01101 #endif
01102          /* FALLTHROUGH */
01103 
01104        case L_('p'):
01105          if (change_case)
01106            {
01107              to_uppcase = 0;
01108              to_lowcase = 1;
01109            }
01110 #if defined _NL_CURRENT || !HAVE_STRFTIME
01111          cpy (ap_len, ampm);
01112          break;
01113 #else
01114          goto underlying_strftime;
01115 #endif
01116 
01117        case L_('R'):
01118          subfmt = L_("%H:%M");
01119          goto subformat;
01120 
01121        case L_('r'):
01122 #if !defined _NL_CURRENT && HAVE_STRFTIME
01123          goto underlying_strftime;
01124 #else
01125 # ifdef _NL_CURRENT
01126          if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
01127                                                  NLW(T_FMT_AMPM)))
01128              == L_('\0'))
01129 # endif
01130            subfmt = L_("%I:%M:%S %p");
01131          goto subformat;
01132 #endif
01133 
01134        case L_('S'):
01135          if (modifier == L_('E'))
01136            goto bad_format;
01137 
01138          DO_NUMBER (2, tp->tm_sec);
01139 
01140        case L_('s'):        /* GNU extension.  */
01141          {
01142            struct tm ltm;
01143            time_t t;
01144 
01145            ltm = *tp;
01146            t = mktime (&ltm);
01147 
01148            /* Generate string value for T using time_t arithmetic;
01149               this works even if sizeof (long) < sizeof (time_t).  */
01150 
01151            bufp = buf + sizeof (buf) / sizeof (buf[0]);
01152            negative_number = t < 0;
01153 
01154            do
01155              {
01156               int d = t % 10;
01157               t /= 10;
01158 
01159               if (negative_number)
01160                 {
01161                   d = -d;
01162 
01163                   /* Adjust if division truncates to minus infinity.  */
01164                   if (0 < -1 % 10 && d < 0)
01165                     {
01166                      t++;
01167                      d += 10;
01168                     }
01169                 }
01170 
01171               *--bufp = d + L_('0');
01172              }
01173            while (t != 0);
01174 
01175            digits = 1;
01176            goto do_number_sign_and_padding;
01177          }
01178 
01179        case L_('X'):
01180          if (modifier == L_('O'))
01181            goto bad_format;
01182 #ifdef _NL_CURRENT
01183          if (! (modifier == L_('E')
01184                && (*(subfmt =
01185                      (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
01186                    != L_('\0'))))
01187            subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
01188          goto subformat;
01189 #else
01190 # if HAVE_STRFTIME
01191          goto underlying_strftime;
01192 # else
01193          /* Fall through.  */
01194 # endif
01195 #endif
01196        case L_('T'):
01197          subfmt = L_("%H:%M:%S");
01198          goto subformat;
01199 
01200        case L_('t'):
01201          add (1, *p = L_('\t'));
01202          break;
01203 
01204        case L_('u'):
01205          DO_NUMBER (1, (tp->tm_wday - 1 + 7) % 7 + 1);
01206 
01207        case L_('U'):
01208          if (modifier == L_('E'))
01209            goto bad_format;
01210 
01211          DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
01212 
01213        case L_('V'):
01214        case L_('g'):
01215        case L_('G'):
01216          if (modifier == L_('E'))
01217            goto bad_format;
01218          {
01219            int year = tp->tm_year + TM_YEAR_BASE;
01220            int days = iso_week_days (tp->tm_yday, tp->tm_wday);
01221 
01222            if (days < 0)
01223              {
01224               /* This ISO week belongs to the previous year.  */
01225               year--;
01226               days = iso_week_days (tp->tm_yday + (365 + __isleap (year)),
01227                                   tp->tm_wday);
01228              }
01229            else
01230              {
01231               int d = iso_week_days (tp->tm_yday - (365 + __isleap (year)),
01232                                    tp->tm_wday);
01233               if (0 <= d)
01234                 {
01235                   /* This ISO week belongs to the next year.  */
01236                   year++;
01237                   days = d;
01238                 }
01239              }
01240 
01241            switch (*f)
01242              {
01243              case L_('g'):
01244               DO_NUMBER (2, (year % 100 + 100) % 100);
01245 
01246              case L_('G'):
01247               DO_NUMBER (1, year);
01248 
01249              default:
01250               DO_NUMBER (2, days / 7 + 1);
01251              }
01252          }
01253 
01254        case L_('W'):
01255          if (modifier == L_('E'))
01256            goto bad_format;
01257 
01258          DO_NUMBER (2, (tp->tm_yday - (tp->tm_wday - 1 + 7) % 7 + 7) / 7);
01259 
01260        case L_('w'):
01261          if (modifier == L_('E'))
01262            goto bad_format;
01263 
01264          DO_NUMBER (1, tp->tm_wday);
01265 
01266        case L_('Y'):
01267          if (modifier == 'E')
01268            {
01269 #if HAVE_STRUCT_ERA_ENTRY
01270              struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
01271              if (era)
01272               {
01273 # ifdef COMPILE_WIDE
01274                 subfmt = era->era_wformat;
01275 # else
01276                 subfmt = era->era_format;
01277 # endif
01278                 goto subformat;
01279               }
01280 #else
01281 # if HAVE_STRFTIME
01282              goto underlying_strftime;
01283 # endif
01284 #endif
01285            }
01286          if (modifier == L_('O'))
01287            goto bad_format;
01288          else
01289            DO_NUMBER (1, tp->tm_year + TM_YEAR_BASE);
01290 
01291        case L_('y'):
01292          if (modifier == L_('E'))
01293            {
01294 #if HAVE_STRUCT_ERA_ENTRY
01295              struct era_entry *era = _nl_get_era_entry (tp HELPER_LOCALE_ARG);
01296              if (era)
01297               {
01298                 int delta = tp->tm_year - era->start_date[0];
01299                 DO_NUMBER (1, (era->offset
01300                              + delta * era->absolute_direction));
01301               }
01302 #else
01303 # if HAVE_STRFTIME
01304              goto underlying_strftime;
01305 # endif
01306 #endif
01307            }
01308          DO_NUMBER (2, (tp->tm_year % 100 + 100) % 100);
01309 
01310        case L_('Z'):
01311          if (change_case)
01312            {
01313              to_uppcase = 0;
01314              to_lowcase = 1;
01315            }
01316 
01317 #if HAVE_TZNAME
01318          /* The tzset() call might have changed the value.  */
01319          if (!(zone && *zone) && tp->tm_isdst >= 0)
01320            {
01321              /* POSIX.1 requires that local time zone information is used as
01322                though strftime called tzset.  */
01323 # if HAVE_TZSET
01324              if (!*tzset_called)
01325               {
01326                 tzset ();
01327                 *tzset_called = true;
01328               }
01329 # endif
01330              zone = tzname[tp->tm_isdst];
01331            }
01332 #endif
01333          if (! zone)
01334            zone = "";
01335 
01336 #ifdef COMPILE_WIDE
01337          {
01338            /* The zone string is always given in multibyte form.  We have
01339               to transform it first.  */
01340            wchar_t *wczone;
01341            size_t len;
01342            widen (zone, wczone, len);
01343            cpy (len, wczone);
01344          }
01345 #else
01346          cpy (strlen (zone), zone);
01347 #endif
01348          break;
01349 
01350        case L_('z'):
01351          if (tp->tm_isdst < 0)
01352            break;
01353 
01354          {
01355            int diff;
01356 #if HAVE_TM_GMTOFF
01357            diff = tp->tm_gmtoff;
01358 #else
01359            if (ut)
01360              diff = 0;
01361            else
01362              {
01363               struct tm gtm;
01364               struct tm ltm;
01365               time_t lt;
01366 
01367               /* POSIX.1 requires that local time zone information is used as
01368                  though strftime called tzset.  */
01369 # if HAVE_TZSET
01370               if (!*tzset_called)
01371                 {
01372                   tzset ();
01373                   *tzset_called = true;
01374                 }
01375 # endif
01376 
01377               ltm = *tp;
01378               lt = mktime (&ltm);
01379 
01380               if (lt == (time_t) -1)
01381                 {
01382                   /* mktime returns -1 for errors, but -1 is also a
01383                      valid time_t value.  Check whether an error really
01384                      occurred.  */
01385                   struct tm tm;
01386 
01387                   if (! __localtime_r (&lt, &tm)
01388                      || ((ltm.tm_sec ^ tm.tm_sec)
01389                          | (ltm.tm_min ^ tm.tm_min)
01390                          | (ltm.tm_hour ^ tm.tm_hour)
01391                          | (ltm.tm_mday ^ tm.tm_mday)
01392                          | (ltm.tm_mon ^ tm.tm_mon)
01393                          | (ltm.tm_year ^ tm.tm_year)))
01394                     break;
01395                 }
01396 
01397               if (! __gmtime_r (&lt, &gtm))
01398                 break;
01399 
01400               diff = tm_diff (&ltm, &gtm);
01401              }
01402 #endif
01403 
01404            if (diff < 0)
01405              {
01406               add (1, *p = L_('-'));
01407               diff = -diff;
01408              }
01409            else
01410              add (1, *p = L_('+'));
01411 
01412            diff /= 60;
01413            DO_NUMBER (4, (diff / 60) * 100 + diff % 60);
01414          }
01415 
01416        case L_('\0'):              /* GNU extension: % at end of format.  */
01417            --f;
01418            /* Fall through.  */
01419        default:
01420          /* Unknown format; output the format, including the '%',
01421             since this is most likely the right thing to do if a
01422             multibyte string has been misparsed.  */
01423        bad_format:
01424          {
01425            int flen;
01426            for (flen = 1; f[1 - flen] != L_('%'); flen++)
01427              continue;
01428            cpy (flen, &f[1 - flen]);
01429          }
01430          break;
01431        }
01432     }
01433 
01434   if (p && maxsize != 0)
01435     *p = L_('\0');
01436   return i;
01437 }
01438 
01439 
01440 #ifdef emacs
01441 /* For Emacs we have a separate interface which corresponds to the normal
01442    strftime function and does not have the extra information whether the
01443    TP arguments comes from a `gmtime' call or not.  */
01444 size_t
01445 emacs_strftime (s, maxsize, format, tp)
01446       char *s;
01447       size_t maxsize;
01448       const char *format;
01449       const struct tm *tp;
01450 {
01451   return my_strftime (s, maxsize, format, tp, 0);
01452 }
01453 #endif
01454 
01455 #if defined _LIBC && !defined COMPILE_WIDE
01456 weak_alias (__strftime_l, strftime_l)
01457 #endif