Stub. Just #define STRTOUXMAX_SIGNED, then
[gnulib.git] / lib / strftime.c
index 95e55cb..dea5509 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1999, 2000, 2001 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.
@@ -98,8 +98,8 @@ extern char *tzname[];
 # define L_(Str) L##Str
 # define NLW(Sym) _NL_W##Sym
 
-# define MEMCPY(d, s, n) wmemcpy (d, s, n)
-# define STRLEN(s) wcslen (s)
+# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
+# define STRLEN(s) __wcslen (s)
 
 #else
 # define CHAR_T char
@@ -289,7 +289,7 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */
         else if (to_uppcase)                                                 \
           memcpy_uppcase (p, (s), _n);                                       \
         else                                                                 \
-          MEMCPY ((PTR) p, (PTR) (s), _n))
+          MEMCPY ((PTR) p, (const PTR) (s), _n))
 
 #ifdef COMPILE_WIDE
 # define widen(os, ws, l) \
@@ -421,44 +421,52 @@ static CHAR_T const month_name[][10] =
 #endif
 
 
-#ifdef emacs
-# define my_strftime emacs_strftimeu
-# define ut_argument , ut
-# define ut_argument_spec int ut;
-# define ut_argument_spec_iso , int ut
+/* 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
+   this Emacs-specific code can be removed once Emacs's config.h
+   defines my_strftime.  */
+#if defined emacs && !defined my_strftime
+# define my_strftime nstrftime
+#endif
+
+#ifdef my_strftime
+# define extra_args , ut, ns
+# define extra_args_spec int ut; int ns;
+# define extra_args_spec_iso , int ut, int ns
 #else
 # ifdef COMPILE_WIDE
 #  define my_strftime wcsftime
 # else
 #  define my_strftime strftime
 # endif
-# define ut_argument
-# define ut_argument_spec
-# define ut_argument_spec_iso
+# define extra_args
+# define extra_args_spec
+# define extra_args_spec_iso
 /* We don't have this information in general.  */
 # define ut 0
+# define ns 0
 #endif
 
 #if !defined _LIBC && HAVE_TZNAME && HAVE_TZSET
   /* Solaris 2.5 tzset sometimes modifies the storage returned by localtime.
      Work around this bug by copying *tp before it might be munged.  */
   size_t _strftime_copytm __P ((char *, size_t, const char *,
-                               const struct tm * ut_argument_spec_iso));
+                               const struct tm * extra_args_spec_iso));
   size_t
-  my_strftime (s, maxsize, format, tp ut_argument)
+  my_strftime (s, maxsize, format, tp extra_args)
       CHAR_T *s;
       size_t maxsize;
       const CHAR_T *format;
       const struct tm *tp;
-      ut_argument_spec
+      extra_args_spec
   {
     struct tm tmcopy;
     tmcopy = *tp;
-    return _strftime_copytm (s, maxsize, format, &tmcopy ut_argument);
+    return _strftime_copytm (s, maxsize, format, &tmcopy extra_args);
   }
 # undef my_strftime
-# define my_strftime(S, Maxsize, Format, Tp) \
-  _strftime_copytm (S, Maxsize, Format, Tp)
+# define my_strftime _strftime_copytm
 #endif
 
 
@@ -469,12 +477,12 @@ static CHAR_T const month_name[][10] =
    anywhere, so to determine how many characters would be
    written, use NULL for S and (size_t) UINT_MAX for MAXSIZE.  */
 size_t
-my_strftime (s, maxsize, format, tp ut_argument)
+my_strftime (s, maxsize, format, tp extra_args)
       CHAR_T *s;
       size_t maxsize;
       const CHAR_T *format;
       const struct tm *tp;
-      ut_argument_spec
+      extra_args_spec
 {
   int hour12 = tp->tm_hour;
 #ifdef _NL_CURRENT
@@ -516,6 +524,9 @@ my_strftime (s, maxsize, format, tp ut_argument)
   size_t i = 0;
   CHAR_T *p = s;
   const CHAR_T *f;
+#if DO_MULTIBYTE && !defined COMPILE_WIDE
+  const char *format_end = NULL;
+#endif
 
   zone = NULL;
 #if HAVE_TM_ZONE
@@ -608,10 +619,15 @@ my_strftime (s, maxsize, format, tp ut_argument)
          {
            mbstate_t mbstate = mbstate_zero;
            size_t len = 0;
+           size_t fsize;
+
+           if (! format_end)
+             format_end = f + strlen (f) + 1;
+           fsize = format_end - f;
 
            do
              {
-               size_t bytes = mbrlen (f + len, (size_t) -1, &mbstate);
+               size_t bytes = mbrlen (f + len, fsize - len, &mbstate);
 
                if (bytes == 0)
                  break;
@@ -752,6 +768,11 @@ my_strftime (s, maxsize, format, tp ut_argument)
 
        case L_('b'):
        case L_('h'):           /* POSIX.2 extension.  */
+         if (change_case)
+           {
+             to_uppcase = 1;
+             to_lowcase = 0;
+           }
          if (modifier != 0)
            goto bad_format;
 #if defined _NL_CURRENT || !HAVE_STRFTIME
@@ -781,10 +802,11 @@ my_strftime (s, maxsize, format, tp ut_argument)
            goto bad_format;
 #ifdef _NL_CURRENT
          if (! (modifier == 'E'
-                && (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,
-                                                       NLW(ERA_D_T_FMT)))
+                && (*(subfmt =
+                      (const CHAR_T *) _NL_CURRENT (LC_TIME,
+                                                    NLW(ERA_D_T_FMT)))
                     != '\0')))
-           subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
+           subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_T_FMT));
 #else
 # if HAVE_STRFTIME
          goto underlying_strftime;
@@ -796,8 +818,10 @@ my_strftime (s, maxsize, format, tp ut_argument)
        subformat:
          {
            CHAR_T *old_start = p;
-           size_t len = my_strftime (NULL, (size_t) -1, subfmt, tp);
-           add (len, my_strftime (p, maxsize - i, subfmt, tp));
+           size_t len = my_strftime (NULL, (size_t) -1, subfmt,
+                                     tp extra_args);
+           add (len, my_strftime (p, maxsize - i, subfmt,
+                                  tp extra_args));
 
            if (to_uppcase)
              while (old_start < p)
@@ -817,6 +841,14 @@ my_strftime (s, maxsize, format, tp ut_argument)
            char *u = ufmt;
            char ubuf[1024]; /* enough for any single format in practice */
            size_t len;
+           /* Make sure we're calling the actual underlying strftime.
+              In some cases, config.h contains something like
+              "#define strftime rpl_strftime".  */
+# ifdef strftime
+#  undef strftime
+           size_t strftime ();
+# endif
+
            *u++ = '%';
            if (modifier != 0)
              *u++ = modifier;
@@ -840,7 +872,7 @@ my_strftime (s, maxsize, format, tp ut_argument)
              if (era)
                {
 # ifdef COMPILE_WIDE
-                 size_t len = wcslen (era->era_wname);
+                 size_t len = __wcslen (era->era_wname);
                  cpy (len, era->era_wname);
 # else
                  size_t len = strlen (era->era_name);
@@ -865,10 +897,10 @@ my_strftime (s, maxsize, format, tp ut_argument)
            goto bad_format;
 #ifdef _NL_CURRENT
          if (! (modifier == L_('E')
-                && (*(subfmt = (CHAR_T *)_NL_CURRENT (LC_TIME,
-                                                      NLW(ERA_D_FMT)))
+                && (*(subfmt =
+                      (const CHAR_T *)_NL_CURRENT (LC_TIME, NLW(ERA_D_FMT)))
                     != L_('\0'))))
-           subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
+           subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(D_FMT));
          goto subformat;
 #else
 # if HAVE_STRFTIME
@@ -1021,6 +1053,21 @@ my_strftime (s, maxsize, format, tp ut_argument)
 
          DO_NUMBER (2, tp->tm_mon + 1);
 
+       case L_('N'):           /* GNU extension.  */
+         if (modifier == L_('E'))
+           goto bad_format;
+
+         number_value = ns;
+         if (width != -1)
+           {
+             /* Take an explicit width less than 9 as a precision.  */
+             int j;
+             for (j = width; j < 9; j++)
+               number_value /= 10;
+           }
+
+         DO_NUMBER (9, number_value);
+
        case L_('n'):           /* POSIX.2 extension.  */
          add (1, *p = L_('\n'));
          break;
@@ -1045,14 +1092,15 @@ my_strftime (s, maxsize, format, tp ut_argument)
          goto underlying_strftime;
 #endif
 
-       case L_('R'):           /* GNU extension.  */
+       case L_('R'):           /* ISO C99 extension.  */
          subfmt = L_("%H:%M");
          goto subformat;
 
        case L_('r'):           /* POSIX.2 extension.  */
 #ifdef _NL_CURRENT
-         if (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,
-                                                NLW(T_FMT_AMPM))) == L_('\0'))
+         if (*(subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME,
+                                                      NLW(T_FMT_AMPM)))
+             == L_('\0'))
 #endif
            subfmt = L_("%I:%M:%S %p");
          goto subformat;
@@ -1107,10 +1155,10 @@ my_strftime (s, maxsize, format, tp ut_argument)
            goto bad_format;
 #ifdef _NL_CURRENT
          if (! (modifier == L_('E')
-                && (*(subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME,
-                                                       NLW(ERA_T_FMT)))
+                && (*(subfmt =
+                      (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ERA_T_FMT)))
                     != L_('\0'))))
-           subfmt = (CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
+           subfmt = (const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(T_FMT));
          goto subformat;
 #else
 # if HAVE_STRFTIME
@@ -1137,8 +1185,8 @@ my_strftime (s, maxsize, format, tp ut_argument)
          DO_NUMBER (2, (tp->tm_yday - tp->tm_wday + 7) / 7);
 
        case L_('V'):
-       case L_('g'):           /* GNU extension.  */
-       case L_('G'):           /* GNU extension.  */
+       case L_('g'):           /* ISO C99 extension.  */
+       case L_('G'):           /* ISO C99 extension.  */
          if (modifier == L_('E'))
            goto bad_format;
          {
@@ -1262,7 +1310,7 @@ my_strftime (s, maxsize, format, tp ut_argument)
 #endif
          break;
 
-       case L_('z'):           /* GNU extension.  */
+       case L_('z'):           /* ISO C99 extension.  */
          if (tp->tm_isdst < 0)
            break;
 
@@ -1344,15 +1392,15 @@ my_strftime (s, maxsize, format, tp ut_argument)
 
 #ifdef emacs
 /* For Emacs we have a separate interface which corresponds to the normal
-   strftime function and does not have the extra information whether the
-   TP arguments comes from a `gmtime' call or not.  */
+   strftime function plus the ut argument, but without the ns argument.  */
 size_t
-emacs_strftime (s, maxsize, format, tp)
+emacs_strftimeu (s, maxsize, format, tp, ut)
       char *s;
       size_t maxsize;
       const char *format;
       const struct tm *tp;
+      int ut;
 {
-  return my_strftime (s, maxsize, format, tp, 0);
+  return my_strftime (s, maxsize, format, tp, ut, 0);
 }
 #endif