strptime.c revision 267677
1267677Spfg/*- 228019Sjoerg * Copyright (c) 1994 Powerdog Industries. All rights reserved. 328019Sjoerg * 4227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation 5227753Stheraven * All rights reserved. 6227753Stheraven * Portions of this software were developed by David Chisnall 7227753Stheraven * under sponsorship from the FreeBSD Foundation. 8227753Stheraven * 928021Sjoerg * Redistribution and use in source and binary forms, with or without 1028019Sjoerg * modification, are permitted provided that the following conditions 1128019Sjoerg * are met: 1228019Sjoerg * 1. Redistributions of source code must retain the above copyright 1328019Sjoerg * notice, this list of conditions and the following disclaimer. 1428019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1528019Sjoerg * notice, this list of conditions and the following disclaimer 1628019Sjoerg * in the documentation and/or other materials provided with the 1728019Sjoerg * distribution. 1828019Sjoerg * 1928019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 2028019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2128019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2228019Sjoerg * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 2328019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2428019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2528019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 2628019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2728019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 2828019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 2928019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30267677Spfg * 31267677Spfg * The views and conclusions contained in the software and documentation 32267677Spfg * are those of the authors and should not be interpreted as representing 33267677Spfg * official policies, either expressed or implied, of Powerdog Industries. 3428019Sjoerg */ 3528019Sjoerg 36111010Snectar#include <sys/cdefs.h> 3728019Sjoerg#ifndef lint 3828021Sjoerg#ifndef NOID 39111010Snectarstatic char copyright[] __unused = 4028019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 41111010Snectarstatic char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 4228021Sjoerg#endif /* !defined NOID */ 4328019Sjoerg#endif /* not lint */ 4492986Sobrien__FBSDID("$FreeBSD: stable/10/lib/libc/stdtime/strptime.c 267677 2014-06-20 15:43:58Z pfg $"); 4528019Sjoerg 4671579Sdeischen#include "namespace.h" 4728019Sjoerg#include <time.h> 4828019Sjoerg#include <ctype.h> 49122830Snectar#include <errno.h> 5079664Sdd#include <stdlib.h> 5128019Sjoerg#include <string.h> 5248614Sobrien#include <pthread.h> 5371579Sdeischen#include "un-namespace.h" 5471579Sdeischen#include "libc_private.h" 5528021Sjoerg#include "timelocal.h" 5628019Sjoerg 57227753Stheravenstatic char * _strptime(const char *, const char *, struct tm *, int *, locale_t); 5848614Sobrien 5928021Sjoerg#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 6028019Sjoerg 6148614Sobrienstatic char * 62227753Stheraven_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, 63227753Stheraven locale_t locale) 6428019Sjoerg{ 6528021Sjoerg char c; 6628021Sjoerg const char *ptr; 6728021Sjoerg int i, 6828021Sjoerg len; 6953941Sache int Ealternative, Oalternative; 70227753Stheraven struct lc_time_T *tptr = __get_current_time_locale(locale); 7128019Sjoerg 7228021Sjoerg ptr = fmt; 7328021Sjoerg while (*ptr != 0) { 7428021Sjoerg if (*buf == 0) 7528021Sjoerg break; 7628019Sjoerg 7728021Sjoerg c = *ptr++; 7828019Sjoerg 7928021Sjoerg if (c != '%') { 80227753Stheraven if (isspace_l((unsigned char)c, locale)) 81227753Stheraven while (*buf != 0 && 82227753Stheraven isspace_l((unsigned char)*buf, locale)) 8328021Sjoerg buf++; 8428021Sjoerg else if (c != *buf++) 8528021Sjoerg return 0; 8628021Sjoerg continue; 8728021Sjoerg } 8828019Sjoerg 8953941Sache Ealternative = 0; 9053941Sache Oalternative = 0; 9153941Sachelabel: 9228021Sjoerg c = *ptr++; 9328021Sjoerg switch (c) { 9428021Sjoerg case 0: 9528021Sjoerg case '%': 9628021Sjoerg if (*buf++ != '%') 9728021Sjoerg return 0; 9828021Sjoerg break; 9928019Sjoerg 10053941Sache case '+': 101227753Stheraven buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale); 10228021Sjoerg if (buf == 0) 10328021Sjoerg return 0; 10428021Sjoerg break; 10528019Sjoerg 10653941Sache case 'C': 107227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 10853941Sache return 0; 10953941Sache 11054316Ssheldonh /* XXX This will break for 3-digit centuries. */ 11154316Ssheldonh len = 2; 112227753Stheraven for (i = 0; len && *buf != 0 && 113227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 11453941Sache i *= 10; 11553941Sache i += *buf - '0'; 11654316Ssheldonh len--; 11753941Sache } 11853941Sache if (i < 19) 11953941Sache return 0; 12053941Sache 12153941Sache tm->tm_year = i * 100 - 1900; 12253941Sache break; 12353941Sache 12428021Sjoerg case 'c': 125227753Stheraven buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale); 12628021Sjoerg if (buf == 0) 12728021Sjoerg return 0; 12828021Sjoerg break; 12928019Sjoerg 13028021Sjoerg case 'D': 131227753Stheraven buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale); 13228021Sjoerg if (buf == 0) 13328021Sjoerg return 0; 13428021Sjoerg break; 13528019Sjoerg 13653941Sache case 'E': 13753960Sache if (Ealternative || Oalternative) 13853960Sache break; 13953941Sache Ealternative++; 14053941Sache goto label; 14153941Sache 14253941Sache case 'O': 14353960Sache if (Ealternative || Oalternative) 14453960Sache break; 14553941Sache Oalternative++; 14653941Sache goto label; 14753941Sache 14853960Sache case 'F': 149227753Stheraven buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale); 15074412Sache if (buf == 0) 15174412Sache return 0; 15274412Sache break; 15374412Sache 15428021Sjoerg case 'R': 155227753Stheraven buf = _strptime(buf, "%H:%M", tm, GMTp, locale); 15628021Sjoerg if (buf == 0) 15728021Sjoerg return 0; 15828021Sjoerg break; 15928019Sjoerg 16028021Sjoerg case 'r': 161227753Stheraven buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale); 16228021Sjoerg if (buf == 0) 16328021Sjoerg return 0; 16428021Sjoerg break; 16528019Sjoerg 16628021Sjoerg case 'T': 167227753Stheraven buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale); 16828021Sjoerg if (buf == 0) 16928021Sjoerg return 0; 17028021Sjoerg break; 17128019Sjoerg 17228021Sjoerg case 'X': 173227753Stheraven buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale); 17428021Sjoerg if (buf == 0) 17528021Sjoerg return 0; 17628021Sjoerg break; 17728019Sjoerg 17828021Sjoerg case 'x': 179227753Stheraven buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale); 18028021Sjoerg if (buf == 0) 18128021Sjoerg return 0; 18228021Sjoerg break; 18328019Sjoerg 18428021Sjoerg case 'j': 185227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 18628021Sjoerg return 0; 18728019Sjoerg 18854316Ssheldonh len = 3; 189227753Stheraven for (i = 0; len && *buf != 0 && 190227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++){ 19128021Sjoerg i *= 10; 19228021Sjoerg i += *buf - '0'; 19354316Ssheldonh len--; 19428021Sjoerg } 19553083Ssheldonh if (i < 1 || i > 366) 19628021Sjoerg return 0; 19728019Sjoerg 19853083Ssheldonh tm->tm_yday = i - 1; 19928021Sjoerg break; 20028019Sjoerg 20128021Sjoerg case 'M': 20228021Sjoerg case 'S': 203227753Stheraven if (*buf == 0 || 204227753Stheraven isspace_l((unsigned char)*buf, locale)) 20528021Sjoerg break; 20628019Sjoerg 207227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 20828021Sjoerg return 0; 20928019Sjoerg 21054316Ssheldonh len = 2; 211227753Stheraven for (i = 0; len && *buf != 0 && 212227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++){ 21328021Sjoerg i *= 10; 21428021Sjoerg i += *buf - '0'; 21554316Ssheldonh len--; 21628021Sjoerg } 21728019Sjoerg 21853083Ssheldonh if (c == 'M') { 21953083Ssheldonh if (i > 59) 22053083Ssheldonh return 0; 22128021Sjoerg tm->tm_min = i; 22253083Ssheldonh } else { 22353083Ssheldonh if (i > 60) 22453083Ssheldonh return 0; 22528021Sjoerg tm->tm_sec = i; 22653083Ssheldonh } 22728019Sjoerg 228227753Stheraven if (*buf != 0 && 229227753Stheraven isspace_l((unsigned char)*buf, locale)) 230227753Stheraven while (*ptr != 0 && 231227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 23228021Sjoerg ptr++; 23328021Sjoerg break; 23428019Sjoerg 23528021Sjoerg case 'H': 23628021Sjoerg case 'I': 23728021Sjoerg case 'k': 23828021Sjoerg case 'l': 23954316Ssheldonh /* 24054316Ssheldonh * Of these, %l is the only specifier explicitly 24154316Ssheldonh * documented as not being zero-padded. However, 24254316Ssheldonh * there is no harm in allowing zero-padding. 24354316Ssheldonh * 24454316Ssheldonh * XXX The %l specifier may gobble one too many 24554316Ssheldonh * digits if used incorrectly. 24654316Ssheldonh */ 247227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 24828021Sjoerg return 0; 24928019Sjoerg 25054316Ssheldonh len = 2; 251227753Stheraven for (i = 0; len && *buf != 0 && 252227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 25328021Sjoerg i *= 10; 25428021Sjoerg i += *buf - '0'; 25554316Ssheldonh len--; 25628021Sjoerg } 25728021Sjoerg if (c == 'H' || c == 'k') { 25828021Sjoerg if (i > 23) 25928021Sjoerg return 0; 26054301Ssheldonh } else if (i > 12) 26128021Sjoerg return 0; 26228019Sjoerg 26328021Sjoerg tm->tm_hour = i; 26428019Sjoerg 265227753Stheraven if (*buf != 0 && 266227753Stheraven isspace_l((unsigned char)*buf, locale)) 267227753Stheraven while (*ptr != 0 && 268227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 26928021Sjoerg ptr++; 27028021Sjoerg break; 27128019Sjoerg 27228021Sjoerg case 'p': 27354316Ssheldonh /* 27454316Ssheldonh * XXX This is bogus if parsed before hour-related 27554316Ssheldonh * specifiers. 27654316Ssheldonh */ 27772168Sphantom len = strlen(tptr->am); 278227753Stheraven if (strncasecmp_l(buf, tptr->am, len, locale) == 0) { 27928021Sjoerg if (tm->tm_hour > 12) 28028021Sjoerg return 0; 28128021Sjoerg if (tm->tm_hour == 12) 28228021Sjoerg tm->tm_hour = 0; 28328021Sjoerg buf += len; 28428021Sjoerg break; 28528021Sjoerg } 28628019Sjoerg 28772168Sphantom len = strlen(tptr->pm); 288227753Stheraven if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) { 28928021Sjoerg if (tm->tm_hour > 12) 29028021Sjoerg return 0; 29128021Sjoerg if (tm->tm_hour != 12) 29228021Sjoerg tm->tm_hour += 12; 29328021Sjoerg buf += len; 29428021Sjoerg break; 29528021Sjoerg } 29628019Sjoerg 29728021Sjoerg return 0; 29828019Sjoerg 29928021Sjoerg case 'A': 30028021Sjoerg case 'a': 30172168Sphantom for (i = 0; i < asizeof(tptr->weekday); i++) { 30274409Sache len = strlen(tptr->weekday[i]); 303227753Stheraven if (strncasecmp_l(buf, tptr->weekday[i], 304227753Stheraven len, locale) == 0) 30574409Sache break; 30674409Sache len = strlen(tptr->wday[i]); 307227753Stheraven if (strncasecmp_l(buf, tptr->wday[i], 308227753Stheraven len, locale) == 0) 30974409Sache break; 31028021Sjoerg } 31172168Sphantom if (i == asizeof(tptr->weekday)) 31228021Sjoerg return 0; 31328019Sjoerg 31428021Sjoerg tm->tm_wday = i; 31528021Sjoerg buf += len; 31628021Sjoerg break; 31728019Sjoerg 31853083Ssheldonh case 'U': 31953083Ssheldonh case 'W': 32053083Ssheldonh /* 32153083Ssheldonh * XXX This is bogus, as we can not assume any valid 32253083Ssheldonh * information present in the tm structure at this 32353083Ssheldonh * point to calculate a real value, so just check the 32453083Ssheldonh * range for now. 32553083Ssheldonh */ 326227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 32753083Ssheldonh return 0; 32853083Ssheldonh 32954316Ssheldonh len = 2; 330227753Stheraven for (i = 0; len && *buf != 0 && 331227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 33253083Ssheldonh i *= 10; 33353083Ssheldonh i += *buf - '0'; 33454316Ssheldonh len--; 33553083Ssheldonh } 33653083Ssheldonh if (i > 53) 33753083Ssheldonh return 0; 33853083Ssheldonh 339227753Stheraven if (*buf != 0 && 340227753Stheraven isspace_l((unsigned char)*buf, locale)) 341227753Stheraven while (*ptr != 0 && 342227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 34353083Ssheldonh ptr++; 34453083Ssheldonh break; 34553083Ssheldonh 34653083Ssheldonh case 'w': 347227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 34853083Ssheldonh return 0; 34953083Ssheldonh 35054316Ssheldonh i = *buf - '0'; 35153083Ssheldonh if (i > 6) 35253083Ssheldonh return 0; 35353083Ssheldonh 35453083Ssheldonh tm->tm_wday = i; 35553083Ssheldonh 356227753Stheraven if (*buf != 0 && 357227753Stheraven isspace_l((unsigned char)*buf, locale)) 358227753Stheraven while (*ptr != 0 && 359227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 36053083Ssheldonh ptr++; 36153083Ssheldonh break; 36253083Ssheldonh 36328021Sjoerg case 'd': 36428021Sjoerg case 'e': 36554316Ssheldonh /* 36654316Ssheldonh * The %e specifier is explicitly documented as not 36754316Ssheldonh * being zero-padded but there is no harm in allowing 36854316Ssheldonh * such padding. 36954316Ssheldonh * 37054316Ssheldonh * XXX The %e specifier may gobble one too many 37154316Ssheldonh * digits if used incorrectly. 37254316Ssheldonh */ 373227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 37428021Sjoerg return 0; 37528019Sjoerg 37654316Ssheldonh len = 2; 377227753Stheraven for (i = 0; len && *buf != 0 && 378227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 37928021Sjoerg i *= 10; 38028021Sjoerg i += *buf - '0'; 38154316Ssheldonh len--; 38228021Sjoerg } 38328021Sjoerg if (i > 31) 38428021Sjoerg return 0; 38528019Sjoerg 38628021Sjoerg tm->tm_mday = i; 38728019Sjoerg 388227753Stheraven if (*buf != 0 && 389227753Stheraven isspace_l((unsigned char)*buf, locale)) 390227753Stheraven while (*ptr != 0 && 391227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 39228021Sjoerg ptr++; 39328021Sjoerg break; 39428019Sjoerg 39528021Sjoerg case 'B': 39628021Sjoerg case 'b': 39728021Sjoerg case 'h': 39872168Sphantom for (i = 0; i < asizeof(tptr->month); i++) { 39953941Sache if (Oalternative) { 40053941Sache if (c == 'B') { 40172168Sphantom len = strlen(tptr->alt_month[i]); 402227753Stheraven if (strncasecmp_l(buf, 40372168Sphantom tptr->alt_month[i], 404227753Stheraven len, locale) == 0) 40553941Sache break; 40653941Sache } 40753941Sache } else { 40874409Sache len = strlen(tptr->month[i]); 409227753Stheraven if (strncasecmp_l(buf, tptr->month[i], 410227753Stheraven len, locale) == 0) 41174409Sache break; 412207830Sedwin } 413207830Sedwin } 414207830Sedwin /* 415207830Sedwin * Try the abbreviated month name if the full name 416207830Sedwin * wasn't found and Oalternative was not requested. 417207830Sedwin */ 418207830Sedwin if (i == asizeof(tptr->month) && !Oalternative) { 419207830Sedwin for (i = 0; i < asizeof(tptr->month); i++) { 42074409Sache len = strlen(tptr->mon[i]); 421227753Stheraven if (strncasecmp_l(buf, tptr->mon[i], 422227753Stheraven len, locale) == 0) 42374409Sache break; 42453941Sache } 42528021Sjoerg } 42672168Sphantom if (i == asizeof(tptr->month)) 42728021Sjoerg return 0; 42828019Sjoerg 42928021Sjoerg tm->tm_mon = i; 43028021Sjoerg buf += len; 43128021Sjoerg break; 43228019Sjoerg 43328021Sjoerg case 'm': 434227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 43528021Sjoerg return 0; 43628019Sjoerg 43754316Ssheldonh len = 2; 438227753Stheraven for (i = 0; len && *buf != 0 && 439227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 44028021Sjoerg i *= 10; 44128021Sjoerg i += *buf - '0'; 44254316Ssheldonh len--; 44328021Sjoerg } 44428021Sjoerg if (i < 1 || i > 12) 44528021Sjoerg return 0; 44628019Sjoerg 44728021Sjoerg tm->tm_mon = i - 1; 44828019Sjoerg 449227753Stheraven if (*buf != 0 && 450227753Stheraven isspace_l((unsigned char)*buf, locale)) 451227753Stheraven while (*ptr != 0 && 452227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 45328021Sjoerg ptr++; 45428021Sjoerg break; 45528019Sjoerg 45679664Sdd case 's': 45779664Sdd { 45879664Sdd char *cp; 459122830Snectar int sverrno; 460122830Snectar long n; 46179664Sdd time_t t; 46279664Sdd 463122830Snectar sverrno = errno; 464122830Snectar errno = 0; 465227753Stheraven n = strtol_l(buf, &cp, 10, locale); 466122830Snectar if (errno == ERANGE || (long)(t = n) != n) { 467122830Snectar errno = sverrno; 46879664Sdd return 0; 469122830Snectar } 470122830Snectar errno = sverrno; 47179664Sdd buf = cp; 47279664Sdd gmtime_r(&t, tm); 473112156Smtm *GMTp = 1; 47479664Sdd } 47579664Sdd break; 47679664Sdd 47728021Sjoerg case 'Y': 47828021Sjoerg case 'y': 479227753Stheraven if (*buf == 0 || 480227753Stheraven isspace_l((unsigned char)*buf, locale)) 48128021Sjoerg break; 48228019Sjoerg 483227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 48428021Sjoerg return 0; 48528019Sjoerg 48654316Ssheldonh len = (c == 'Y') ? 4 : 2; 487227753Stheraven for (i = 0; len && *buf != 0 && 488227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 48928021Sjoerg i *= 10; 49028021Sjoerg i += *buf - '0'; 49154316Ssheldonh len--; 49228021Sjoerg } 49328021Sjoerg if (c == 'Y') 49428021Sjoerg i -= 1900; 49546051Swes if (c == 'y' && i < 69) 49646042Swes i += 100; 49728021Sjoerg if (i < 0) 49828021Sjoerg return 0; 49928019Sjoerg 50028021Sjoerg tm->tm_year = i; 50128019Sjoerg 502227753Stheraven if (*buf != 0 && 503227753Stheraven isspace_l((unsigned char)*buf, locale)) 504227753Stheraven while (*ptr != 0 && 505227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 50628021Sjoerg ptr++; 50728021Sjoerg break; 50848550Sobrien 50948550Sobrien case 'Z': 51048550Sobrien { 51148550Sobrien const char *cp; 51248550Sobrien char *zonestr; 51348550Sobrien 514227753Stheraven for (cp = buf; *cp && 515227753Stheraven isupper_l((unsigned char)*cp, locale); ++cp) { 516227753Stheraven /*empty*/} 51748550Sobrien if (cp - buf) { 51848550Sobrien zonestr = alloca(cp - buf + 1); 51948550Sobrien strncpy(zonestr, buf, cp - buf); 52048550Sobrien zonestr[cp - buf] = '\0'; 52148550Sobrien tzset(); 52248550Sobrien if (0 == strcmp(zonestr, "GMT")) { 523112156Smtm *GMTp = 1; 52448550Sobrien } else if (0 == strcmp(zonestr, tzname[0])) { 52548614Sobrien tm->tm_isdst = 0; 52648550Sobrien } else if (0 == strcmp(zonestr, tzname[1])) { 52748614Sobrien tm->tm_isdst = 1; 52848550Sobrien } else { 52948614Sobrien return 0; 53048550Sobrien } 53148550Sobrien buf += cp - buf; 53248550Sobrien } 53348550Sobrien } 53448550Sobrien break; 535195015Sdelphij 536195015Sdelphij case 'z': 537195015Sdelphij { 538195015Sdelphij int sign = 1; 539195015Sdelphij 540195015Sdelphij if (*buf != '+') { 541195015Sdelphij if (*buf == '-') 542195015Sdelphij sign = -1; 543195015Sdelphij else 544195015Sdelphij return 0; 545195015Sdelphij } 546195015Sdelphij 547195015Sdelphij buf++; 548195015Sdelphij i = 0; 549195015Sdelphij for (len = 4; len > 0; len--) { 550227753Stheraven if (isdigit_l((unsigned char)*buf, locale)) { 551195015Sdelphij i *= 10; 552195015Sdelphij i += *buf - '0'; 553195015Sdelphij buf++; 554195015Sdelphij } else 555195015Sdelphij return 0; 556195015Sdelphij } 557195015Sdelphij 558195015Sdelphij tm->tm_hour -= sign * (i / 100); 559195015Sdelphij tm->tm_min -= sign * (i % 100); 560195015Sdelphij *GMTp = 1; 561195015Sdelphij } 562195015Sdelphij break; 56328021Sjoerg } 56428021Sjoerg } 56548614Sobrien return (char *)buf; 56648614Sobrien} 56728019Sjoerg 56848614Sobrien 56948614Sobrienchar * 570227753Stheravenstrptime_l(const char * __restrict buf, const char * __restrict fmt, 571227753Stheraven struct tm * __restrict tm, locale_t loc) 57248614Sobrien{ 57348614Sobrien char *ret; 574112156Smtm int gmt; 575227753Stheraven FIX_LOCALE(loc); 57648614Sobrien 577112156Smtm gmt = 0; 578227753Stheraven ret = _strptime(buf, fmt, tm, &gmt, loc); 579114285Smtm if (ret && gmt) { 580114285Smtm time_t t = timegm(tm); 58171579Sdeischen localtime_r(&t, tm); 58248550Sobrien } 58348614Sobrien 584112156Smtm return (ret); 58528019Sjoerg} 586227753Stheravenchar * 587227753Stheravenstrptime(const char * __restrict buf, const char * __restrict fmt, 588227753Stheraven struct tm * __restrict tm) 589227753Stheraven{ 590227753Stheraven return strptime_l(buf, fmt, tm, __get_locale()); 591227753Stheraven} 592