diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2011-05-12 13:41:22 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2011-05-12 13:41:22 +0000 |
commit | 4d1bf2fbb8af2538f5a204a746341408819fd6ca (patch) | |
tree | 821c8c46e4d57429506dfff4b6d632853f2f8ed4 /newlib/libc/time | |
parent | 7bb76e751b1df7b8d0a7527197540a0a26071758 (diff) | |
download | cygnal-4d1bf2fbb8af2538f5a204a746341408819fd6ca.tar.gz cygnal-4d1bf2fbb8af2538f5a204a746341408819fd6ca.tar.bz2 cygnal-4d1bf2fbb8af2538f5a204a746341408819fd6ca.zip |
* libc/time/strptime.c (strptime): Fill in tm_yday when all of tm_year,
tm_mon and tm_mday are updated. Fill in tm_mon, tm_mday and tm_wday
when both of tm_year and tm_yday are updated.
Diffstat (limited to 'newlib/libc/time')
-rw-r--r-- | newlib/libc/time/strptime.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/newlib/libc/time/strptime.c b/newlib/libc/time/strptime.c index bc16fa5eb..359fe5e9d 100644 --- a/newlib/libc/time/strptime.c +++ b/newlib/libc/time/strptime.c @@ -40,6 +40,16 @@ #define _ctloc(x) (_CurrentTimeLocale->x) +static _CONST int _DAYS_BEFORE_MONTH[12] = +{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + +#define SET_MDAY 1 +#define SET_MON 2 +#define SET_YEAR 4 +#define SET_WDAY 8 +#define SET_YDAY 16 +#define SET_YMD (SET_YEAR | SET_MON | SET_MDAY) + /* * tm_year is relative this year */ @@ -147,6 +157,7 @@ _DEFUN (strptime, (buf, format, timeptr), struct tm *timeptr) { char c; + int ymd = 0; struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale (); for (; (c = *format) != '\0'; ++format) { @@ -166,18 +177,21 @@ _DEFUN (strptime, (buf, format, timeptr), if (ret < 0) return NULL; timeptr->tm_wday = ret; + ymd |= SET_WDAY; break; case 'a' : ret = match_string (&buf, _ctloc (wday)); if (ret < 0) return NULL; timeptr->tm_wday = ret; + ymd |= SET_WDAY; break; case 'B' : ret = match_string (&buf, _ctloc (month)); if (ret < 0) return NULL; timeptr->tm_mon = ret; + ymd |= SET_MON; break; case 'b' : case 'h' : @@ -185,6 +199,7 @@ _DEFUN (strptime, (buf, format, timeptr), if (ret < 0) return NULL; timeptr->tm_mon = ret; + ymd |= SET_MON; break; case 'C' : ret = strtol (buf, &s, 10); @@ -192,18 +207,21 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_year = (ret * 100) - tm_year_base; buf = s; + ymd |= SET_YEAR; break; case 'c' : /* %a %b %e %H:%M:%S %Y */ s = strptime (buf, _ctloc (c_fmt), timeptr); if (s == NULL) return NULL; buf = s; + ymd |= SET_WDAY | SET_YMD; break; case 'D' : /* %m/%d/%y */ s = strptime (buf, "%m/%d/%y", timeptr); if (s == NULL) return NULL; buf = s; + ymd |= SET_YMD; break; case 'd' : case 'e' : @@ -212,6 +230,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_mday = ret; buf = s; + ymd |= SET_MDAY; break; case 'H' : case 'k' : @@ -238,6 +257,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_yday = ret - 1; buf = s; + ymd |= SET_YDAY; break; case 'm' : ret = strtol (buf, &s, 10); @@ -245,6 +265,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_mon = ret - 1; buf = s; + ymd |= SET_MON; break; case 'M' : ret = strtol (buf, &s, 10); @@ -306,6 +327,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_wday = ret - 1; buf = s; + ymd |= SET_WDAY; break; case 'w' : ret = strtol (buf, &s, 10); @@ -313,6 +335,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_wday = ret; buf = s; + ymd |= SET_WDAY; break; case 'U' : ret = strtol (buf, &s, 10); @@ -320,6 +343,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; set_week_number_sun (timeptr, ret); buf = s; + ymd |= SET_YDAY; break; case 'V' : ret = strtol (buf, &s, 10); @@ -327,6 +351,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; set_week_number_mon4 (timeptr, ret); buf = s; + ymd |= SET_YDAY; break; case 'W' : ret = strtol (buf, &s, 10); @@ -334,12 +359,14 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; set_week_number_mon (timeptr, ret); buf = s; + ymd |= SET_YDAY; break; case 'x' : s = strptime (buf, _ctloc (x_fmt), timeptr); if (s == NULL) return NULL; buf = s; + ymd |= SET_YMD; break; case 'X' : s = strptime (buf, _ctloc (X_fmt), timeptr); @@ -356,6 +383,7 @@ _DEFUN (strptime, (buf, format, timeptr), else timeptr->tm_year = ret; buf = s; + ymd |= SET_YEAR; break; case 'Y' : ret = strtol (buf, &s, 10); @@ -363,6 +391,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; timeptr->tm_year = ret - tm_year_base; buf = s; + ymd |= SET_YEAR; break; case 'Z' : /* Unsupported. Just ignore. */ @@ -390,6 +419,58 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; } } + + if ((ymd & SET_YMD) == SET_YMD) { + /* all of tm_year, tm_mon and tm_mday, but... */ + + if (!(ymd & SET_YDAY)) { + /* ...not tm_yday, so fill it in */ + timeptr->tm_yday = _DAYS_BEFORE_MONTH[timeptr->tm_mon] + + timeptr->tm_mday; + if (!is_leap_year (timeptr->tm_year + tm_year_base) + || timeptr->tm_mon < 2) + { + timeptr->tm_yday--; + } + ymd |= SET_YDAY; + } + } + else if ((ymd & (SET_YEAR | SET_YDAY)) == (SET_YEAR | SET_YDAY)) { + /* both of tm_year and tm_yday, but... */ + + if (!(ymd & SET_MON)) { + /* ...not tm_mon, so fill it in, and/or... */ + if (timeptr->tm_yday < _DAYS_BEFORE_MONTH[1]) + timeptr->tm_mon = 0; + else { + int leap = is_leap_year (timeptr->tm_year + tm_year_base); + int i; + for (i = 2; i < 12; ++i) { + if (timeptr->tm_yday < _DAYS_BEFORE_MONTH[i] + leap) + break; + } + timeptr->tm_mon = i - 1; + } + } + + if (!(ymd & SET_MDAY)) { + /* ...not tm_mday, so fill it in */ + timeptr->tm_mday = timeptr->tm_yday + - _DAYS_BEFORE_MONTH[timeptr->tm_mon]; + if (!is_leap_year (timeptr->tm_year + tm_year_base) + || timeptr->tm_mon < 2) + { + timeptr->tm_mday++; + } + } + } + + if ((ymd & (SET_YEAR | SET_YDAY | SET_WDAY)) == (SET_YEAR | SET_YDAY)) { + /* fill in tm_wday */ + int fday = first_day (timeptr->tm_year + tm_year_base); + timeptr->tm_wday = (fday + timeptr->tm_yday) % 7; + } + return (char *)buf; } |