1267677Spfg/*- 2268043Spfg * Copyright (c) 2014 Gary Mills 3268043Spfg * Copyright 2011, Nexenta Systems, Inc. All rights reserved. 428019Sjoerg * Copyright (c) 1994 Powerdog Industries. All rights reserved. 528019Sjoerg * 6227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation 7227753Stheraven * All rights reserved. 8227753Stheraven * Portions of this software were developed by David Chisnall 9227753Stheraven * under sponsorship from the FreeBSD Foundation. 10227753Stheraven * 1128021Sjoerg * Redistribution and use in source and binary forms, with or without 1228019Sjoerg * modification, are permitted provided that the following conditions 1328019Sjoerg * are met: 1428019Sjoerg * 1. Redistributions of source code must retain the above copyright 1528019Sjoerg * notice, this list of conditions and the following disclaimer. 1628019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1728019Sjoerg * notice, this list of conditions and the following disclaimer 1828019Sjoerg * in the documentation and/or other materials provided with the 1928019Sjoerg * distribution. 2028019Sjoerg * 2128019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 2228019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2328019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2428019Sjoerg * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 2528019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2628019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2728019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 2828019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2928019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 3028019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 3128019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32267677Spfg * 33267677Spfg * The views and conclusions contained in the software and documentation 34267677Spfg * are those of the authors and should not be interpreted as representing 35267677Spfg * official policies, either expressed or implied, of Powerdog Industries. 3628019Sjoerg */ 3728019Sjoerg 38111010Snectar#include <sys/cdefs.h> 3928019Sjoerg#ifndef lint 4028021Sjoerg#ifndef NOID 41111010Snectarstatic char copyright[] __unused = 4228019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 43111010Snectarstatic char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 4428021Sjoerg#endif /* !defined NOID */ 4528019Sjoerg#endif /* not lint */ 4692986Sobrien__FBSDID("$FreeBSD$"); 4728019Sjoerg 4871579Sdeischen#include "namespace.h" 4928019Sjoerg#include <time.h> 5028019Sjoerg#include <ctype.h> 51122830Snectar#include <errno.h> 5279664Sdd#include <stdlib.h> 5328019Sjoerg#include <string.h> 5448614Sobrien#include <pthread.h> 5571579Sdeischen#include "un-namespace.h" 5671579Sdeischen#include "libc_private.h" 5728021Sjoerg#include "timelocal.h" 5828019Sjoerg 59227753Stheravenstatic char * _strptime(const char *, const char *, struct tm *, int *, locale_t); 6048614Sobrien 61267798Spfg#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 6228019Sjoerg 6348614Sobrienstatic char * 64227753Stheraven_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, 65227753Stheraven locale_t locale) 6628019Sjoerg{ 6728021Sjoerg char c; 6828021Sjoerg const char *ptr; 69267798Spfg int i, len; 7053941Sache int Ealternative, Oalternative; 71227753Stheraven struct lc_time_T *tptr = __get_current_time_locale(locale); 7228019Sjoerg 7328021Sjoerg ptr = fmt; 7428021Sjoerg while (*ptr != 0) { 7528021Sjoerg if (*buf == 0) 7628021Sjoerg break; 7728019Sjoerg 7828021Sjoerg c = *ptr++; 7928019Sjoerg 8028021Sjoerg if (c != '%') { 81227753Stheraven if (isspace_l((unsigned char)c, locale)) 82227753Stheraven while (*buf != 0 && 83227753Stheraven isspace_l((unsigned char)*buf, locale)) 8428021Sjoerg buf++; 8528021Sjoerg else if (c != *buf++) 86267798Spfg return (NULL); 8728021Sjoerg continue; 8828021Sjoerg } 8928019Sjoerg 9053941Sache Ealternative = 0; 9153941Sache Oalternative = 0; 9253941Sachelabel: 9328021Sjoerg c = *ptr++; 9428021Sjoerg switch (c) { 9528021Sjoerg case 0: 9628021Sjoerg case '%': 9728021Sjoerg if (*buf++ != '%') 98267798Spfg return (NULL); 9928021Sjoerg break; 10028019Sjoerg 10153941Sache case '+': 102227753Stheraven buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale); 103267798Spfg if (buf == NULL) 104267798Spfg return (NULL); 10528021Sjoerg break; 10628019Sjoerg 10753941Sache case 'C': 108227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 109267798Spfg return (NULL); 11053941Sache 11154316Ssheldonh /* XXX This will break for 3-digit centuries. */ 11254316Ssheldonh len = 2; 113227753Stheraven for (i = 0; len && *buf != 0 && 114227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 11553941Sache i *= 10; 11653941Sache i += *buf - '0'; 11754316Ssheldonh len--; 11853941Sache } 11953941Sache if (i < 19) 120267798Spfg return (NULL); 12153941Sache 12253941Sache tm->tm_year = i * 100 - 1900; 12353941Sache break; 12453941Sache 12528021Sjoerg case 'c': 126227753Stheraven buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale); 127267798Spfg if (buf == NULL) 128267798Spfg return (NULL); 12928021Sjoerg break; 13028019Sjoerg 13128021Sjoerg case 'D': 132227753Stheraven buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale); 133267798Spfg if (buf == NULL) 134267798Spfg return (NULL); 13528021Sjoerg break; 13628019Sjoerg 13753941Sache case 'E': 13853960Sache if (Ealternative || Oalternative) 13953960Sache break; 14053941Sache Ealternative++; 14153941Sache goto label; 14253941Sache 14353941Sache case 'O': 14453960Sache if (Ealternative || Oalternative) 14553960Sache break; 14653941Sache Oalternative++; 14753941Sache goto label; 14853941Sache 14953960Sache case 'F': 150227753Stheraven buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale); 151267798Spfg if (buf == NULL) 152267798Spfg return (NULL); 15374412Sache break; 15474412Sache 15528021Sjoerg case 'R': 156227753Stheraven buf = _strptime(buf, "%H:%M", tm, GMTp, locale); 157267798Spfg if (buf == NULL) 158267798Spfg return (NULL); 15928021Sjoerg break; 16028019Sjoerg 16128021Sjoerg case 'r': 162227753Stheraven buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale); 163267798Spfg if (buf == NULL) 164267798Spfg return (NULL); 16528021Sjoerg break; 16628019Sjoerg 16728021Sjoerg case 'T': 168227753Stheraven buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale); 169267798Spfg if (buf == NULL) 170267798Spfg return (NULL); 17128021Sjoerg break; 17228019Sjoerg 17328021Sjoerg case 'X': 174227753Stheraven buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale); 175267798Spfg if (buf == NULL) 176267798Spfg return (NULL); 17728021Sjoerg break; 17828019Sjoerg 17928021Sjoerg case 'x': 180227753Stheraven buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale); 181267798Spfg if (buf == NULL) 182267798Spfg return (NULL); 18328021Sjoerg break; 18428019Sjoerg 18528021Sjoerg case 'j': 186227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 187267798Spfg return (NULL); 18828019Sjoerg 18954316Ssheldonh len = 3; 190227753Stheraven for (i = 0; len && *buf != 0 && 191227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++){ 19228021Sjoerg i *= 10; 19328021Sjoerg i += *buf - '0'; 19454316Ssheldonh len--; 19528021Sjoerg } 19653083Ssheldonh if (i < 1 || i > 366) 197267798Spfg return (NULL); 19828019Sjoerg 19953083Ssheldonh tm->tm_yday = i - 1; 20028021Sjoerg break; 20128019Sjoerg 20228021Sjoerg case 'M': 20328021Sjoerg case 'S': 204227753Stheraven if (*buf == 0 || 205227753Stheraven isspace_l((unsigned char)*buf, locale)) 20628021Sjoerg break; 20728019Sjoerg 208227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 209267798Spfg return (NULL); 21028019Sjoerg 21154316Ssheldonh len = 2; 212227753Stheraven for (i = 0; len && *buf != 0 && 213227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++){ 21428021Sjoerg i *= 10; 21528021Sjoerg i += *buf - '0'; 21654316Ssheldonh len--; 21728021Sjoerg } 21828019Sjoerg 21953083Ssheldonh if (c == 'M') { 22053083Ssheldonh if (i > 59) 221267798Spfg return (NULL); 22228021Sjoerg tm->tm_min = i; 22353083Ssheldonh } else { 22453083Ssheldonh if (i > 60) 225267798Spfg return (NULL); 22628021Sjoerg tm->tm_sec = i; 22753083Ssheldonh } 22828019Sjoerg 22928021Sjoerg break; 23028019Sjoerg 23128021Sjoerg case 'H': 23228021Sjoerg case 'I': 23328021Sjoerg case 'k': 23428021Sjoerg case 'l': 23554316Ssheldonh /* 23654316Ssheldonh * Of these, %l is the only specifier explicitly 23754316Ssheldonh * documented as not being zero-padded. However, 23854316Ssheldonh * there is no harm in allowing zero-padding. 23954316Ssheldonh * 24054316Ssheldonh * XXX The %l specifier may gobble one too many 24154316Ssheldonh * digits if used incorrectly. 24254316Ssheldonh */ 243227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 244267798Spfg return (NULL); 24528019Sjoerg 24654316Ssheldonh len = 2; 247227753Stheraven for (i = 0; len && *buf != 0 && 248227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 24928021Sjoerg i *= 10; 25028021Sjoerg i += *buf - '0'; 25154316Ssheldonh len--; 25228021Sjoerg } 25328021Sjoerg if (c == 'H' || c == 'k') { 25428021Sjoerg if (i > 23) 255267798Spfg return (NULL); 25654301Ssheldonh } else if (i > 12) 257267798Spfg return (NULL); 25828019Sjoerg 25928021Sjoerg tm->tm_hour = i; 26028019Sjoerg 26128021Sjoerg break; 26228019Sjoerg 26328021Sjoerg case 'p': 26454316Ssheldonh /* 26554316Ssheldonh * XXX This is bogus if parsed before hour-related 26654316Ssheldonh * specifiers. 26754316Ssheldonh */ 26872168Sphantom len = strlen(tptr->am); 269227753Stheraven if (strncasecmp_l(buf, tptr->am, len, locale) == 0) { 27028021Sjoerg if (tm->tm_hour > 12) 271267798Spfg return (NULL); 27228021Sjoerg if (tm->tm_hour == 12) 27328021Sjoerg tm->tm_hour = 0; 27428021Sjoerg buf += len; 27528021Sjoerg break; 27628021Sjoerg } 27728019Sjoerg 27872168Sphantom len = strlen(tptr->pm); 279227753Stheraven if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) { 28028021Sjoerg if (tm->tm_hour > 12) 281267798Spfg return (NULL); 28228021Sjoerg if (tm->tm_hour != 12) 28328021Sjoerg tm->tm_hour += 12; 28428021Sjoerg buf += len; 28528021Sjoerg break; 28628021Sjoerg } 28728019Sjoerg 288267798Spfg return (NULL); 28928019Sjoerg 29028021Sjoerg case 'A': 29128021Sjoerg case 'a': 29272168Sphantom for (i = 0; i < asizeof(tptr->weekday); i++) { 29374409Sache len = strlen(tptr->weekday[i]); 294227753Stheraven if (strncasecmp_l(buf, tptr->weekday[i], 295227753Stheraven len, locale) == 0) 29674409Sache break; 29774409Sache len = strlen(tptr->wday[i]); 298227753Stheraven if (strncasecmp_l(buf, tptr->wday[i], 299227753Stheraven len, locale) == 0) 30074409Sache break; 30128021Sjoerg } 30272168Sphantom if (i == asizeof(tptr->weekday)) 303267798Spfg return (NULL); 30428019Sjoerg 30528021Sjoerg tm->tm_wday = i; 30628021Sjoerg buf += len; 30728021Sjoerg break; 30828019Sjoerg 30953083Ssheldonh case 'U': 31053083Ssheldonh case 'W': 31153083Ssheldonh /* 31253083Ssheldonh * XXX This is bogus, as we can not assume any valid 31353083Ssheldonh * information present in the tm structure at this 31453083Ssheldonh * point to calculate a real value, so just check the 31553083Ssheldonh * range for now. 31653083Ssheldonh */ 317227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 318267798Spfg return (NULL); 31953083Ssheldonh 32054316Ssheldonh len = 2; 321227753Stheraven for (i = 0; len && *buf != 0 && 322227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 32353083Ssheldonh i *= 10; 32453083Ssheldonh i += *buf - '0'; 32554316Ssheldonh len--; 32653083Ssheldonh } 32753083Ssheldonh if (i > 53) 328267798Spfg return (NULL); 32953083Ssheldonh 33053083Ssheldonh break; 33153083Ssheldonh 33253083Ssheldonh case 'w': 333227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 334267798Spfg return (NULL); 33553083Ssheldonh 33654316Ssheldonh i = *buf - '0'; 33753083Ssheldonh if (i > 6) 338267798Spfg return (NULL); 33953083Ssheldonh 34053083Ssheldonh tm->tm_wday = i; 34153083Ssheldonh 34253083Ssheldonh break; 34353083Ssheldonh 34428021Sjoerg case 'e': 34554316Ssheldonh /* 346268043Spfg * With %e format, our strftime(3) adds a blank space 347268043Spfg * before single digits. 348268043Spfg */ 349268043Spfg if (*buf != 0 && 350268043Spfg isspace_l((unsigned char)*buf, locale)) 351268043Spfg buf++; 352268043Spfg /* FALLTHROUGH */ 353268043Spfg case 'd': 354268043Spfg /* 355268043Spfg * The %e specifier was once explicitly documented as 356268043Spfg * not being zero-padded but was later changed to 357268043Spfg * equivalent to %d. There is no harm in allowing 35854316Ssheldonh * such padding. 35954316Ssheldonh * 36054316Ssheldonh * XXX The %e specifier may gobble one too many 36154316Ssheldonh * digits if used incorrectly. 36254316Ssheldonh */ 363227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 364267798Spfg return (NULL); 36528019Sjoerg 36654316Ssheldonh len = 2; 367227753Stheraven for (i = 0; len && *buf != 0 && 368227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 36928021Sjoerg i *= 10; 37028021Sjoerg i += *buf - '0'; 37154316Ssheldonh len--; 37228021Sjoerg } 37328021Sjoerg if (i > 31) 374267798Spfg return (NULL); 37528019Sjoerg 37628021Sjoerg tm->tm_mday = i; 37728019Sjoerg 37828021Sjoerg break; 37928019Sjoerg 38028021Sjoerg case 'B': 38128021Sjoerg case 'b': 38228021Sjoerg case 'h': 38372168Sphantom for (i = 0; i < asizeof(tptr->month); i++) { 38453941Sache if (Oalternative) { 38553941Sache if (c == 'B') { 38672168Sphantom len = strlen(tptr->alt_month[i]); 387227753Stheraven if (strncasecmp_l(buf, 38872168Sphantom tptr->alt_month[i], 389227753Stheraven len, locale) == 0) 39053941Sache break; 39153941Sache } 39253941Sache } else { 39374409Sache len = strlen(tptr->month[i]); 394227753Stheraven if (strncasecmp_l(buf, tptr->month[i], 395227753Stheraven len, locale) == 0) 39674409Sache break; 397207830Sedwin } 398207830Sedwin } 399207830Sedwin /* 400207830Sedwin * Try the abbreviated month name if the full name 401207830Sedwin * wasn't found and Oalternative was not requested. 402207830Sedwin */ 403207830Sedwin if (i == asizeof(tptr->month) && !Oalternative) { 404207830Sedwin for (i = 0; i < asizeof(tptr->month); i++) { 40574409Sache len = strlen(tptr->mon[i]); 406227753Stheraven if (strncasecmp_l(buf, tptr->mon[i], 407227753Stheraven len, locale) == 0) 40874409Sache break; 40953941Sache } 41028021Sjoerg } 41172168Sphantom if (i == asizeof(tptr->month)) 412267798Spfg return (NULL); 41328019Sjoerg 41428021Sjoerg tm->tm_mon = i; 41528021Sjoerg buf += len; 41628021Sjoerg break; 41728019Sjoerg 41828021Sjoerg case 'm': 419227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 420267798Spfg return (NULL); 42128019Sjoerg 42254316Ssheldonh len = 2; 423227753Stheraven for (i = 0; len && *buf != 0 && 424227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 42528021Sjoerg i *= 10; 42628021Sjoerg i += *buf - '0'; 42754316Ssheldonh len--; 42828021Sjoerg } 42928021Sjoerg if (i < 1 || i > 12) 430267798Spfg return (NULL); 43128019Sjoerg 43228021Sjoerg tm->tm_mon = i - 1; 43328019Sjoerg 43428021Sjoerg break; 43528019Sjoerg 43679664Sdd case 's': 43779664Sdd { 43879664Sdd char *cp; 439122830Snectar int sverrno; 440122830Snectar long n; 44179664Sdd time_t t; 44279664Sdd 443122830Snectar sverrno = errno; 444122830Snectar errno = 0; 445227753Stheraven n = strtol_l(buf, &cp, 10, locale); 446122830Snectar if (errno == ERANGE || (long)(t = n) != n) { 447122830Snectar errno = sverrno; 448267798Spfg return (NULL); 449122830Snectar } 450122830Snectar errno = sverrno; 45179664Sdd buf = cp; 45279664Sdd gmtime_r(&t, tm); 453112156Smtm *GMTp = 1; 45479664Sdd } 45579664Sdd break; 45679664Sdd 45728021Sjoerg case 'Y': 45828021Sjoerg case 'y': 459227753Stheraven if (*buf == 0 || 460227753Stheraven isspace_l((unsigned char)*buf, locale)) 46128021Sjoerg break; 46228019Sjoerg 463227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 464267798Spfg return (NULL); 46528019Sjoerg 46654316Ssheldonh len = (c == 'Y') ? 4 : 2; 467227753Stheraven for (i = 0; len && *buf != 0 && 468227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 46928021Sjoerg i *= 10; 47028021Sjoerg i += *buf - '0'; 47154316Ssheldonh len--; 47228021Sjoerg } 47328021Sjoerg if (c == 'Y') 47428021Sjoerg i -= 1900; 47546051Swes if (c == 'y' && i < 69) 47646042Swes i += 100; 47728021Sjoerg if (i < 0) 478267798Spfg return (NULL); 47928019Sjoerg 48028021Sjoerg tm->tm_year = i; 48128019Sjoerg 48228021Sjoerg break; 48348550Sobrien 48448550Sobrien case 'Z': 48548550Sobrien { 48648550Sobrien const char *cp; 48748550Sobrien char *zonestr; 48848550Sobrien 489227753Stheraven for (cp = buf; *cp && 490227753Stheraven isupper_l((unsigned char)*cp, locale); ++cp) { 491227753Stheraven /*empty*/} 49248550Sobrien if (cp - buf) { 49348550Sobrien zonestr = alloca(cp - buf + 1); 49448550Sobrien strncpy(zonestr, buf, cp - buf); 49548550Sobrien zonestr[cp - buf] = '\0'; 49648550Sobrien tzset(); 49748550Sobrien if (0 == strcmp(zonestr, "GMT")) { 498112156Smtm *GMTp = 1; 49948550Sobrien } else if (0 == strcmp(zonestr, tzname[0])) { 50048614Sobrien tm->tm_isdst = 0; 50148550Sobrien } else if (0 == strcmp(zonestr, tzname[1])) { 50248614Sobrien tm->tm_isdst = 1; 50348550Sobrien } else { 504267798Spfg return (NULL); 50548550Sobrien } 50648550Sobrien buf += cp - buf; 50748550Sobrien } 50848550Sobrien } 50948550Sobrien break; 510195015Sdelphij 511195015Sdelphij case 'z': 512195015Sdelphij { 513195015Sdelphij int sign = 1; 514195015Sdelphij 515195015Sdelphij if (*buf != '+') { 516195015Sdelphij if (*buf == '-') 517195015Sdelphij sign = -1; 518195015Sdelphij else 519267798Spfg return (NULL); 520195015Sdelphij } 521195015Sdelphij 522195015Sdelphij buf++; 523195015Sdelphij i = 0; 524195015Sdelphij for (len = 4; len > 0; len--) { 525227753Stheraven if (isdigit_l((unsigned char)*buf, locale)) { 526195015Sdelphij i *= 10; 527195015Sdelphij i += *buf - '0'; 528195015Sdelphij buf++; 529195015Sdelphij } else 530267798Spfg return (NULL); 531195015Sdelphij } 532195015Sdelphij 533195015Sdelphij tm->tm_hour -= sign * (i / 100); 534195015Sdelphij tm->tm_min -= sign * (i % 100); 535195015Sdelphij *GMTp = 1; 536195015Sdelphij } 537195015Sdelphij break; 538268043Spfg 539268043Spfg case 'n': 540268043Spfg case 't': 541268043Spfg while (isspace_l((unsigned char)*buf, locale)) 542268043Spfg buf++; 543268043Spfg break; 54428021Sjoerg } 54528021Sjoerg } 546267798Spfg return ((char *)buf); 54748614Sobrien} 54828019Sjoerg 54948614Sobrien 55048614Sobrienchar * 551227753Stheravenstrptime_l(const char * __restrict buf, const char * __restrict fmt, 552227753Stheraven struct tm * __restrict tm, locale_t loc) 55348614Sobrien{ 55448614Sobrien char *ret; 555112156Smtm int gmt; 556227753Stheraven FIX_LOCALE(loc); 55748614Sobrien 558112156Smtm gmt = 0; 559227753Stheraven ret = _strptime(buf, fmt, tm, &gmt, loc); 560114285Smtm if (ret && gmt) { 561114285Smtm time_t t = timegm(tm); 56271579Sdeischen localtime_r(&t, tm); 56348550Sobrien } 56448614Sobrien 565112156Smtm return (ret); 56628019Sjoerg} 567227753Stheravenchar * 568227753Stheravenstrptime(const char * __restrict buf, const char * __restrict fmt, 569227753Stheraven struct tm * __restrict tm) 570227753Stheraven{ 571227753Stheraven return strptime_l(buf, fmt, tm, __get_locale()); 572227753Stheraven} 573