]> git.saurik.com Git - apple/libc.git/blobdiff - stdtime/FreeBSD/strptime.c.patch
Libc-498.tar.gz
[apple/libc.git] / stdtime / FreeBSD / strptime.c.patch
index 498fcd5b460ad9e9d343c211fd9e85a903a5e510..2c6acc50f67fa95856009d54e133e4d929e9a197 100644 (file)
@@ -1,6 +1,6 @@
---- strptime.c.orig    2004-11-25 11:38:45.000000000 -0800
-+++ strptime.c 2005-02-24 01:09:32.000000000 -0800
-@@ -61,6 +61,8 @@
+--- strptime.c.orig    2007-04-03 12:19:24.000000000 -0700
++++ strptime.c 2007-04-03 12:39:20.000000000 -0700
+@@ -61,10 +61,13 @@
  #endif /* not lint */
  __FBSDID("$FreeBSD: src/lib/libc/stdtime/strptime.c,v 1.35 2003/11/17 04:19:15 nectar Exp $");
  
@@ -9,22 +9,33 @@
  #include "namespace.h"
  #include <time.h>
  #include <ctype.h>
-@@ -72,19 +74,19 @@
+ #include <errno.h>
++#include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <pthread.h>
+@@ -72,30 +75,41 @@
  #include "libc_private.h"
  #include "timelocal.h"
  
 -static char * _strptime(const char *, const char *, struct tm *, int *);
-+static char * _strptime(const char *, const char *, struct tm *, int *, locale_t);
++static char * _strptime(const char *, const char *, struct tm *, int *, locale_t) __DARWIN_ALIAS(_strptime);
++time_t _mktime(struct tm *, const char *);
  
  #define asizeof(a)    (sizeof (a) / sizeof ((a)[0]))
  
++enum {CONVERT_NONE, CONVERT_GMT, CONVERT_ZONE};
++
  static char *
 -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
-+_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, locale_t loc)
++_strptime(const char *buf, const char *fmt, struct tm *tm, int *convp, locale_t loc)
  {
        char    c;
        const char *ptr;
        int     i,
++              year = -1,
++              yday = 0,
++              wday = -1,
                len;
        int Ealternative, Oalternative;
 -      struct lc_time_T *tptr = __get_current_time_locale();
  
        ptr = fmt;
        while (*ptr != 0) {
-@@ -94,8 +96,8 @@
+-              if (*buf == 0)
+-                      break;
++              if (*buf == 0) {
++                      fmt = ptr;
++                      while (isspace_l((unsigned char)*ptr, loc)) {
++                              ptr++;
++                      }
++                      return ((*ptr)==0) ? fmt : 0; /* trailing whitespace is ok */
++              }
                c = *ptr++;
  
                if (c != '%') {
                                        buf++;
                        else if (c != *buf++)
                                return 0;
-@@ -114,18 +116,18 @@
+@@ -114,18 +128,18 @@
                        break;
  
                case '+':
 -                      buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
-+                      buf = _strptime(buf, tptr->date_fmt, tm, GMTp, loc);
++                      buf = _strptime(buf, tptr->date_fmt, tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -137,13 +139,13 @@
+@@ -133,17 +147,21 @@
+                       if (i < 19)
+                               return 0;
++                      if (year != -1)
++                              tm->tm_year = (year % 100) + i * 100 - 1900;
++                      else
+                       tm->tm_year = i * 100 - 1900;
++                      year = tm->tm_year;
                        break;
  
                case 'c':
 -                      buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
-+                      buf = _strptime(buf, tptr->c_fmt, tm, GMTp, loc);
++                      buf = _strptime(buf, tptr->c_fmt, tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
  
                case 'D':
 -                      buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
-+                      buf = _strptime(buf, "%m/%d/%y", tm, GMTp, loc);
++                      buf = _strptime(buf, "%m/%d/%y", tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
-@@ -161,47 +163,47 @@
+@@ -161,47 +179,55 @@
                        goto label;
  
                case 'F':
 -                      buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
-+                      buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, loc);
++                      buf = _strptime(buf, "%Y-%m-%d", tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
  
                case 'R':
 -                      buf = _strptime(buf, "%H:%M", tm, GMTp);
-+                      buf = _strptime(buf, "%H:%M", tm, GMTp, loc);
++                      buf = _strptime(buf, "%H:%M", tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
  
                case 'r':
 -                      buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
-+                      buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, loc);
++                      buf = _strptime(buf, tptr->ampm_fmt, tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
  
++              case 'n':
++              case 't':
++                      if (!isspace((unsigned char)*buf))
++                              return 0;
++                      while (isspace((unsigned char)*buf))
++                              buf++;
++                      break;
++
                case 'T':
 -                      buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
-+                      buf = _strptime(buf, "%H:%M:%S", tm, GMTp, loc);
++                      buf = _strptime(buf, "%H:%M:%S", tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
  
                case 'X':
 -                      buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
-+                      buf = _strptime(buf, tptr->X_fmt, tm, GMTp, loc);
++                      buf = _strptime(buf, tptr->X_fmt, tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
  
                case 'x':
 -                      buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
-+                      buf = _strptime(buf, tptr->x_fmt, tm, GMTp, loc);
++                      buf = _strptime(buf, tptr->x_fmt, tm, convp, loc);
                        if (buf == 0)
                                return 0;
                        break;
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -214,14 +216,14 @@
+@@ -209,19 +235,19 @@
+                       if (i < 1 || i > 366)
+                               return 0;
+-                      tm->tm_yday = i - 1;
++                      tm->tm_yday = yday = i - 1;
+                       break;
  
                case 'M':
                case 'S':
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -237,8 +239,8 @@
+@@ -237,8 +263,8 @@
                                tm->tm_sec = i;
                        }
  
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-@@ -254,11 +256,11 @@
+@@ -254,11 +280,11 @@
                         * XXX The %l specifier may gobble one too many
                         * digits if used incorrectly.
                         */
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -271,8 +273,8 @@
+@@ -271,8 +297,8 @@
  
                        tm->tm_hour = i;
  
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-@@ -282,7 +284,7 @@
+@@ -282,7 +308,7 @@
                         * specifiers.
                         */
                        len = strlen(tptr->am);
                                if (tm->tm_hour > 12)
                                        return 0;
                                if (tm->tm_hour == 12)
-@@ -292,7 +294,7 @@
+@@ -292,7 +318,7 @@
                        }
  
                        len = strlen(tptr->pm);
                                if (tm->tm_hour > 12)
                                        return 0;
                                if (tm->tm_hour != 12)
-@@ -307,12 +309,12 @@
+@@ -307,34 +333,28 @@
                case 'a':
                        for (i = 0; i < asizeof(tptr->weekday); i++) {
                                len = strlen(tptr->weekday[i]);
                                        break;
                        }
                        if (i == asizeof(tptr->weekday))
-@@ -330,11 +332,11 @@
-                        * point to calculate a real value, so just check the
-                        * range for now.
-                        */
+                               return 0;
+-                      tm->tm_wday = i;
++                      tm->tm_wday = wday = i;
+                       buf += len;
+                       break;
+-              case 'U':
+-              case 'W':
+-                      /*
+-                       * XXX This is bogus, as we can not assume any valid
+-                       * information present in the tm structure at this
+-                       * point to calculate a real value, so just check the
+-                       * range for now.
+-                       */
 -                      if (!isdigit((unsigned char)*buf))
++              case 'U':       /* Sunday week */
++              case 'W':       /* Monday week */
 +                      if (!isdigit_l((unsigned char)*buf, loc))
                                return 0;
  
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -342,13 +344,13 @@
+@@ -342,23 +362,46 @@
                        if (i > 53)
                                return 0;
  
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
++                      /* Calculate yday if we have enough data */
++                      if ((year != -1) && (wday != -1)) {
++                              struct tm mktm;
++                              mktm.tm_year = year;
++                              mktm.tm_mon = 0;
++                              mktm.tm_mday = 1;
++                              mktm.tm_sec = 1;
++                              mktm.tm_min = mktm.tm_hour = 0;
++                              mktm.tm_isdst = 0;
++                              mktm.tm_gmtoff = 0;
++                              if (mktime(&mktm) != -1) {
++                                      /* yday0 == Jan 1 == mktm.tm_wday */
++                                      int delta = wday - mktm.tm_wday;
++                                      if (!wday && c =='W')
++                                              i++; /* Sunday is part of the following week */
++                                      yday = 7 * i + delta;
++                                      if (yday < 0)
++                                              yday += 7;
++                                      tm->tm_yday = yday;
++                              }
++                      }
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-               case 'w':
+-              case 'w':
 -                      if (!isdigit((unsigned char)*buf))
++              case 'u':       /* [1,7] */
++              case 'w':       /* [0,6] */
 +                      if (!isdigit_l((unsigned char)*buf, loc))
                                return 0;
  
                        i = *buf - '0';
-@@ -357,8 +359,8 @@
-                       tm->tm_wday = i;
+-                      if (i > 6)
++                      if (i > 6 + (c == 'u'))
+                               return 0;
+-
+-                      tm->tm_wday = i;
+-
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
++                      if (i == 7)
++                              i = 0;
++                      tm->tm_wday = wday = i;
++                      buf++;
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-@@ -372,11 +374,11 @@
+@@ -372,11 +415,18 @@
                         * XXX The %e specifier may gobble one too many
                         * digits if used incorrectly.
                         */
 -                      if (!isdigit((unsigned char)*buf))
++                      /* Leading space is ok if date is single digit */
++                      len = 2;
++                      if (isspace_l((unsigned char)buf[0], loc) &&
++                          isdigit_l((unsigned char)buf[1], loc) &&
++                          !isdigit_l((unsigned char)buf[2], loc)) {
++                              len = 1;
++                              buf++;
++                      }
 +                      if (!isdigit_l((unsigned char)*buf, loc))
                                return 0;
  
-                       len = 2;
+-                      len = 2;
 -                      for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
 +                      for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -386,8 +388,8 @@
+@@ -386,8 +436,8 @@
  
                        tm->tm_mday = i;
  
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-@@ -398,19 +400,19 @@
+@@ -398,19 +448,19 @@
                                if (Oalternative) {
                                        if (c == 'B') {
                                                len = strlen(tptr->alt_month[i]);
                                                break;
                                }
                        }
-@@ -422,11 +424,11 @@
+@@ -422,11 +472,11 @@
                        break;
  
                case 'm':
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -436,8 +438,8 @@
+@@ -436,8 +486,8 @@
  
                        tm->tm_mon = i - 1;
  
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-@@ -450,7 +452,7 @@
+@@ -450,7 +500,7 @@
  
                        sverrno = errno;
                        errno = 0;
                        if (errno == ERANGE || (long)(t = n) != n) {
                                errno = sverrno;
                                return 0;
-@@ -464,14 +466,14 @@
+@@ -458,24 +508,37 @@
+                       errno = sverrno;
+                       buf = cp;
+                       gmtime_r(&t, tm);
+-                      *GMTp = 1;
++                      *convp = CONVERT_GMT;
+                       }
+                       break;
  
                case 'Y':
                case 'y':
 +                      if (!isdigit_l((unsigned char)*buf, loc))
                                return 0;
  
++#if __DARWIN_UNIX03
++                      if (c == 'Y') {
++                              for (i = 0; *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
++                                      i *= 10;
++                                      i += *buf - '0';
++                              }
++                      } else {
++                              len = 2;
++#else /* !__DARWIN_UNIX03 */
                        len = (c == 'Y') ? 4 : 2;
 -                      for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
++#endif /* __DARWIN_UNIX03 */
 +                      for (i = 0; len && *buf != 0 && isdigit_l((unsigned char)*buf, loc); buf++) {
                                i *= 10;
                                i += *buf - '0';
                                len--;
-@@ -485,8 +487,8 @@
+                       }
++#if __DARWIN_UNIX03
++                      }
++#endif /* __DARWIN_UNIX03 */
+                       if (c == 'Y')
+                               i -= 1900;
+                       if (c == 'y' && i < 69)
+@@ -483,10 +546,10 @@
+                       if (i < 0)
+                               return 0;
  
-                       tm->tm_year = i;
+-                      tm->tm_year = i;
++                      tm->tm_year = year = i;
  
 -                      if (*buf != 0 && isspace((unsigned char)*buf))
 -                              while (*ptr != 0 && !isspace((unsigned char)*ptr))
 +                      if (*buf != 0 && isspace_l((unsigned char)*buf, loc))
-+                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc))
++                              while (*ptr != 0 && !isspace_l((unsigned char)*ptr, loc) && *ptr != '%')
                                        ptr++;
                        break;
  
-@@ -495,7 +497,7 @@
-                       const char *cp;
-                       char *zonestr;
--                      for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
-+                      for (cp = buf; *cp && isupper_l((unsigned char)*cp, loc); ++cp) {/*empty*/}
-                       if (cp - buf) {
-                               zonestr = alloca(cp - buf + 1);
-                               strncpy(zonestr, buf, cp - buf);
-@@ -528,7 +530,25 @@
-       int gmt;
-       gmt = 0;
--      ret = _strptime(buf, fmt, tm, &gmt);
-+      ret = _strptime(buf, fmt, tm, &gmt, __current_locale());
-+      if (ret && gmt) {
-+              time_t t = timegm(tm);
-+              localtime_r(&t, tm);
-+      }
+@@ -502,7 +565,7 @@
+                               zonestr[cp - buf] = '\0';
+                               tzset();
+                               if (0 == strcmp(zonestr, "GMT")) {
+-                                  *GMTp = 1;
++                                  *convp = CONVERT_GMT;
+                               } else if (0 == strcmp(zonestr, tzname[0])) {
+                                   tm->tm_isdst = 0;
+                               } else if (0 == strcmp(zonestr, tzname[1])) {
+@@ -514,6 +577,26 @@
+                       }
+                       }
+                       break;
++
++              case 'z':
++                      {
++                      char sign;
++                      int hr, min;
 +
-+      return (ret);
++                      if ((buf[0] != '+' && buf[0] != '-')
++                       || !isdigit_l((unsigned char)buf[1], loc)
++                       || !isdigit_l((unsigned char)buf[2], loc)
++                       || !isdigit_l((unsigned char)buf[3], loc)
++                       || !isdigit_l((unsigned char)buf[4], loc))
++                              return 0;
++                      sscanf(buf, "%c%2d%2d", &sign, &hr, &min);
++                      *convp = CONVERT_ZONE;
++                      tm->tm_gmtoff = 60 * (60 * hr + min);
++                      if (sign == '-')
++                          tm->tm_gmtoff = -tm->tm_gmtoff;
++                      buf += 5;
++                      }
++                      break;
+               }
+       }
+       return (char *)buf;
+@@ -524,14 +607,39 @@
+ strptime(const char * __restrict buf, const char * __restrict fmt,
+     struct tm * __restrict tm)
+ {
++      return strptime_l(buf, fmt, tm, __current_locale());
 +}
 +
++extern time_t timeoff(struct tm *, long);
++
 +char *
 +strptime_l(const char * __restrict buf, const char * __restrict fmt,
 +    struct tm * __restrict tm, locale_t loc)
 +{
-+      char *ret;
-+      int gmt;
-+
+       char *ret;
+-      int gmt;
++      int conv;
+-      gmt = 0;
+-      ret = _strptime(buf, fmt, tm, &gmt);
+-      if (ret && gmt) {
+-              time_t t = timegm(tm);
+-              localtime_r(&t, tm);
 +      NORMALIZE_LOCALE(loc);
-+      gmt = 0;
-+      ret = _strptime(buf, fmt, tm, &gmt, loc);
-       if (ret && gmt) {
-               time_t t = timegm(tm);
-               localtime_r(&t, tm);
++      conv = CONVERT_NONE;
++      tm->tm_zone = NULL;
++      ret = _strptime(buf, fmt, tm, &conv, loc);
++      if (ret) {
++              time_t t;
++
++              switch(conv) {
++              case CONVERT_GMT:
++                      t = timegm(tm);
++                      localtime_r(&t, tm);
++                      break;
++              case CONVERT_ZONE:
++                  {
++                      long offset = tm->tm_gmtoff;
++                      tm->tm_gmtoff = 0;
++                      t = timeoff(tm, offset);
++                      localtime_r(&t, tm);
++                      break;
++                  }
++              }
+       }
+       return (ret);