128019Sjoerg/* 228021Sjoerg * Powerdog Industries kindly requests feedback from anyone modifying 328021Sjoerg * this function: 428021Sjoerg * 528021Sjoerg * Date: Thu, 05 Jun 1997 23:17:17 -0400 628021Sjoerg * From: Kevin Ruddy <kevin.ruddy@powerdog.com> 728021Sjoerg * To: James FitzGibbon <james@nexis.net> 828021Sjoerg * Subject: Re: Use of your strptime(3) code (fwd) 928021Sjoerg * 1028021Sjoerg * The reason for the "no mod" clause was so that modifications would 1128021Sjoerg * come back and we could integrate them and reissue so that a wider 1228021Sjoerg * audience could use it (thereby spreading the wealth). This has 1328021Sjoerg * made it possible to get strptime to work on many operating systems. 1428021Sjoerg * I'm not sure why that's "plain unacceptable" to the FreeBSD team. 1528021Sjoerg * 1628021Sjoerg * Anyway, you can change it to "with or without modification" as 1728021Sjoerg * you see fit. Enjoy. 1828021Sjoerg * 1928021Sjoerg * Kevin Ruddy 2028021Sjoerg * Powerdog Industries, Inc. 2128021Sjoerg */ 2228021Sjoerg/* 2328019Sjoerg * Copyright (c) 1994 Powerdog Industries. All rights reserved. 2428019Sjoerg * 25227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation 26227753Stheraven * All rights reserved. 27227753Stheraven * Portions of this software were developed by David Chisnall 28227753Stheraven * under sponsorship from the FreeBSD Foundation. 29227753Stheraven * 3028021Sjoerg * Redistribution and use in source and binary forms, with or without 3128019Sjoerg * modification, are permitted provided that the following conditions 3228019Sjoerg * are met: 3328019Sjoerg * 1. Redistributions of source code must retain the above copyright 3428019Sjoerg * notice, this list of conditions and the following disclaimer. 3528019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 3628019Sjoerg * notice, this list of conditions and the following disclaimer 3728019Sjoerg * in the documentation and/or other materials provided with the 3828019Sjoerg * distribution. 3928019Sjoerg * 3. All advertising materials mentioning features or use of this 4028019Sjoerg * software must display the following acknowledgement: 4128019Sjoerg * This product includes software developed by Powerdog Industries. 4228019Sjoerg * 4. The name of Powerdog Industries may not be used to endorse or 4328019Sjoerg * promote products derived from this software without specific prior 4428019Sjoerg * written permission. 4528019Sjoerg * 4628019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 4728019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4828019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 4928019Sjoerg * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 5028019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 5128019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 5228019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 5328019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 5428019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 5528019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 5628019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5728019Sjoerg */ 5828019Sjoerg 59111010Snectar#include <sys/cdefs.h> 6028019Sjoerg#ifndef lint 6128021Sjoerg#ifndef NOID 62111010Snectarstatic char copyright[] __unused = 6328019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 64111010Snectarstatic char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 6528021Sjoerg#endif /* !defined NOID */ 6628019Sjoerg#endif /* not lint */ 6792986Sobrien__FBSDID("$FreeBSD$"); 6828019Sjoerg 6971579Sdeischen#include "namespace.h" 7028019Sjoerg#include <time.h> 7128019Sjoerg#include <ctype.h> 72122830Snectar#include <errno.h> 7379664Sdd#include <stdlib.h> 7428019Sjoerg#include <string.h> 7548614Sobrien#include <pthread.h> 7671579Sdeischen#include "un-namespace.h" 7771579Sdeischen#include "libc_private.h" 7828021Sjoerg#include "timelocal.h" 7928019Sjoerg 80227753Stheravenstatic char * _strptime(const char *, const char *, struct tm *, int *, locale_t); 8148614Sobrien 8228021Sjoerg#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 8328019Sjoerg 8448614Sobrienstatic char * 85227753Stheraven_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, 86227753Stheraven locale_t locale) 8728019Sjoerg{ 8828021Sjoerg char c; 8928021Sjoerg const char *ptr; 9028021Sjoerg int i, 9128021Sjoerg len; 9253941Sache int Ealternative, Oalternative; 93227753Stheraven struct lc_time_T *tptr = __get_current_time_locale(locale); 9428019Sjoerg 9528021Sjoerg ptr = fmt; 9628021Sjoerg while (*ptr != 0) { 9728021Sjoerg if (*buf == 0) 9828021Sjoerg break; 9928019Sjoerg 10028021Sjoerg c = *ptr++; 10128019Sjoerg 10228021Sjoerg if (c != '%') { 103227753Stheraven if (isspace_l((unsigned char)c, locale)) 104227753Stheraven while (*buf != 0 && 105227753Stheraven isspace_l((unsigned char)*buf, locale)) 10628021Sjoerg buf++; 10728021Sjoerg else if (c != *buf++) 10828021Sjoerg return 0; 10928021Sjoerg continue; 11028021Sjoerg } 11128019Sjoerg 11253941Sache Ealternative = 0; 11353941Sache Oalternative = 0; 11453941Sachelabel: 11528021Sjoerg c = *ptr++; 11628021Sjoerg switch (c) { 11728021Sjoerg case 0: 11828021Sjoerg case '%': 11928021Sjoerg if (*buf++ != '%') 12028021Sjoerg return 0; 12128021Sjoerg break; 12228019Sjoerg 12353941Sache case '+': 124227753Stheraven buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale); 12528021Sjoerg if (buf == 0) 12628021Sjoerg return 0; 12728021Sjoerg break; 12828019Sjoerg 12953941Sache case 'C': 130227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 13153941Sache return 0; 13253941Sache 13354316Ssheldonh /* XXX This will break for 3-digit centuries. */ 13454316Ssheldonh len = 2; 135227753Stheraven for (i = 0; len && *buf != 0 && 136227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 13753941Sache i *= 10; 13853941Sache i += *buf - '0'; 13954316Ssheldonh len--; 14053941Sache } 14153941Sache if (i < 19) 14253941Sache return 0; 14353941Sache 14453941Sache tm->tm_year = i * 100 - 1900; 14553941Sache break; 14653941Sache 14728021Sjoerg case 'c': 148227753Stheraven buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale); 14928021Sjoerg if (buf == 0) 15028021Sjoerg return 0; 15128021Sjoerg break; 15228019Sjoerg 15328021Sjoerg case 'D': 154227753Stheraven buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale); 15528021Sjoerg if (buf == 0) 15628021Sjoerg return 0; 15728021Sjoerg break; 15828019Sjoerg 15953941Sache case 'E': 16053960Sache if (Ealternative || Oalternative) 16153960Sache break; 16253941Sache Ealternative++; 16353941Sache goto label; 16453941Sache 16553941Sache case 'O': 16653960Sache if (Ealternative || Oalternative) 16753960Sache break; 16853941Sache Oalternative++; 16953941Sache goto label; 17053941Sache 17153960Sache case 'F': 172227753Stheraven buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale); 17374412Sache if (buf == 0) 17474412Sache return 0; 17574412Sache break; 17674412Sache 17728021Sjoerg case 'R': 178227753Stheraven buf = _strptime(buf, "%H:%M", tm, GMTp, locale); 17928021Sjoerg if (buf == 0) 18028021Sjoerg return 0; 18128021Sjoerg break; 18228019Sjoerg 18328021Sjoerg case 'r': 184227753Stheraven buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale); 18528021Sjoerg if (buf == 0) 18628021Sjoerg return 0; 18728021Sjoerg break; 18828019Sjoerg 18928021Sjoerg case 'T': 190227753Stheraven buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale); 19128021Sjoerg if (buf == 0) 19228021Sjoerg return 0; 19328021Sjoerg break; 19428019Sjoerg 19528021Sjoerg case 'X': 196227753Stheraven buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale); 19728021Sjoerg if (buf == 0) 19828021Sjoerg return 0; 19928021Sjoerg break; 20028019Sjoerg 20128021Sjoerg case 'x': 202227753Stheraven buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale); 20328021Sjoerg if (buf == 0) 20428021Sjoerg return 0; 20528021Sjoerg break; 20628019Sjoerg 20728021Sjoerg case 'j': 208227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 20928021Sjoerg return 0; 21028019Sjoerg 21154316Ssheldonh len = 3; 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 } 21853083Ssheldonh if (i < 1 || i > 366) 21928021Sjoerg return 0; 22028019Sjoerg 22153083Ssheldonh tm->tm_yday = i - 1; 22228021Sjoerg break; 22328019Sjoerg 22428021Sjoerg case 'M': 22528021Sjoerg case 'S': 226227753Stheraven if (*buf == 0 || 227227753Stheraven isspace_l((unsigned char)*buf, locale)) 22828021Sjoerg break; 22928019Sjoerg 230227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 23128021Sjoerg return 0; 23228019Sjoerg 23354316Ssheldonh len = 2; 234227753Stheraven for (i = 0; len && *buf != 0 && 235227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++){ 23628021Sjoerg i *= 10; 23728021Sjoerg i += *buf - '0'; 23854316Ssheldonh len--; 23928021Sjoerg } 24028019Sjoerg 24153083Ssheldonh if (c == 'M') { 24253083Ssheldonh if (i > 59) 24353083Ssheldonh return 0; 24428021Sjoerg tm->tm_min = i; 24553083Ssheldonh } else { 24653083Ssheldonh if (i > 60) 24753083Ssheldonh return 0; 24828021Sjoerg tm->tm_sec = i; 24953083Ssheldonh } 25028019Sjoerg 251227753Stheraven if (*buf != 0 && 252227753Stheraven isspace_l((unsigned char)*buf, locale)) 253227753Stheraven while (*ptr != 0 && 254227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 25528021Sjoerg ptr++; 25628021Sjoerg break; 25728019Sjoerg 25828021Sjoerg case 'H': 25928021Sjoerg case 'I': 26028021Sjoerg case 'k': 26128021Sjoerg case 'l': 26254316Ssheldonh /* 26354316Ssheldonh * Of these, %l is the only specifier explicitly 26454316Ssheldonh * documented as not being zero-padded. However, 26554316Ssheldonh * there is no harm in allowing zero-padding. 26654316Ssheldonh * 26754316Ssheldonh * XXX The %l specifier may gobble one too many 26854316Ssheldonh * digits if used incorrectly. 26954316Ssheldonh */ 270227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 27128021Sjoerg return 0; 27228019Sjoerg 27354316Ssheldonh len = 2; 274227753Stheraven for (i = 0; len && *buf != 0 && 275227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 27628021Sjoerg i *= 10; 27728021Sjoerg i += *buf - '0'; 27854316Ssheldonh len--; 27928021Sjoerg } 28028021Sjoerg if (c == 'H' || c == 'k') { 28128021Sjoerg if (i > 23) 28228021Sjoerg return 0; 28354301Ssheldonh } else if (i > 12) 28428021Sjoerg return 0; 28528019Sjoerg 28628021Sjoerg tm->tm_hour = i; 28728019Sjoerg 288227753Stheraven if (*buf != 0 && 289227753Stheraven isspace_l((unsigned char)*buf, locale)) 290227753Stheraven while (*ptr != 0 && 291227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 29228021Sjoerg ptr++; 29328021Sjoerg break; 29428019Sjoerg 29528021Sjoerg case 'p': 29654316Ssheldonh /* 29754316Ssheldonh * XXX This is bogus if parsed before hour-related 29854316Ssheldonh * specifiers. 29954316Ssheldonh */ 30072168Sphantom len = strlen(tptr->am); 301227753Stheraven if (strncasecmp_l(buf, tptr->am, len, locale) == 0) { 30228021Sjoerg if (tm->tm_hour > 12) 30328021Sjoerg return 0; 30428021Sjoerg if (tm->tm_hour == 12) 30528021Sjoerg tm->tm_hour = 0; 30628021Sjoerg buf += len; 30728021Sjoerg break; 30828021Sjoerg } 30928019Sjoerg 31072168Sphantom len = strlen(tptr->pm); 311227753Stheraven if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) { 31228021Sjoerg if (tm->tm_hour > 12) 31328021Sjoerg return 0; 31428021Sjoerg if (tm->tm_hour != 12) 31528021Sjoerg tm->tm_hour += 12; 31628021Sjoerg buf += len; 31728021Sjoerg break; 31828021Sjoerg } 31928019Sjoerg 32028021Sjoerg return 0; 32128019Sjoerg 32228021Sjoerg case 'A': 32328021Sjoerg case 'a': 32472168Sphantom for (i = 0; i < asizeof(tptr->weekday); i++) { 32574409Sache len = strlen(tptr->weekday[i]); 326227753Stheraven if (strncasecmp_l(buf, tptr->weekday[i], 327227753Stheraven len, locale) == 0) 32874409Sache break; 32974409Sache len = strlen(tptr->wday[i]); 330227753Stheraven if (strncasecmp_l(buf, tptr->wday[i], 331227753Stheraven len, locale) == 0) 33274409Sache break; 33328021Sjoerg } 33472168Sphantom if (i == asizeof(tptr->weekday)) 33528021Sjoerg return 0; 33628019Sjoerg 33728021Sjoerg tm->tm_wday = i; 33828021Sjoerg buf += len; 33928021Sjoerg break; 34028019Sjoerg 34153083Ssheldonh case 'U': 34253083Ssheldonh case 'W': 34353083Ssheldonh /* 34453083Ssheldonh * XXX This is bogus, as we can not assume any valid 34553083Ssheldonh * information present in the tm structure at this 34653083Ssheldonh * point to calculate a real value, so just check the 34753083Ssheldonh * range for now. 34853083Ssheldonh */ 349227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 35053083Ssheldonh return 0; 35153083Ssheldonh 35254316Ssheldonh len = 2; 353227753Stheraven for (i = 0; len && *buf != 0 && 354227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 35553083Ssheldonh i *= 10; 35653083Ssheldonh i += *buf - '0'; 35754316Ssheldonh len--; 35853083Ssheldonh } 35953083Ssheldonh if (i > 53) 36053083Ssheldonh return 0; 36153083Ssheldonh 362227753Stheraven if (*buf != 0 && 363227753Stheraven isspace_l((unsigned char)*buf, locale)) 364227753Stheraven while (*ptr != 0 && 365227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 36653083Ssheldonh ptr++; 36753083Ssheldonh break; 36853083Ssheldonh 36953083Ssheldonh case 'w': 370227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 37153083Ssheldonh return 0; 37253083Ssheldonh 37354316Ssheldonh i = *buf - '0'; 37453083Ssheldonh if (i > 6) 37553083Ssheldonh return 0; 37653083Ssheldonh 37753083Ssheldonh tm->tm_wday = i; 37853083Ssheldonh 379227753Stheraven if (*buf != 0 && 380227753Stheraven isspace_l((unsigned char)*buf, locale)) 381227753Stheraven while (*ptr != 0 && 382227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 38353083Ssheldonh ptr++; 38453083Ssheldonh break; 38553083Ssheldonh 38628021Sjoerg case 'd': 38728021Sjoerg case 'e': 38854316Ssheldonh /* 38954316Ssheldonh * The %e specifier is explicitly documented as not 39054316Ssheldonh * being zero-padded but there is no harm in allowing 39154316Ssheldonh * such padding. 39254316Ssheldonh * 39354316Ssheldonh * XXX The %e specifier may gobble one too many 39454316Ssheldonh * digits if used incorrectly. 39554316Ssheldonh */ 396227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 39728021Sjoerg return 0; 39828019Sjoerg 39954316Ssheldonh len = 2; 400227753Stheraven for (i = 0; len && *buf != 0 && 401227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 40228021Sjoerg i *= 10; 40328021Sjoerg i += *buf - '0'; 40454316Ssheldonh len--; 40528021Sjoerg } 40628021Sjoerg if (i > 31) 40728021Sjoerg return 0; 40828019Sjoerg 40928021Sjoerg tm->tm_mday = i; 41028019Sjoerg 411227753Stheraven if (*buf != 0 && 412227753Stheraven isspace_l((unsigned char)*buf, locale)) 413227753Stheraven while (*ptr != 0 && 414227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 41528021Sjoerg ptr++; 41628021Sjoerg break; 41728019Sjoerg 41828021Sjoerg case 'B': 41928021Sjoerg case 'b': 42028021Sjoerg case 'h': 42172168Sphantom for (i = 0; i < asizeof(tptr->month); i++) { 42253941Sache if (Oalternative) { 42353941Sache if (c == 'B') { 42472168Sphantom len = strlen(tptr->alt_month[i]); 425227753Stheraven if (strncasecmp_l(buf, 42672168Sphantom tptr->alt_month[i], 427227753Stheraven len, locale) == 0) 42853941Sache break; 42953941Sache } 43053941Sache } else { 43174409Sache len = strlen(tptr->month[i]); 432227753Stheraven if (strncasecmp_l(buf, tptr->month[i], 433227753Stheraven len, locale) == 0) 43474409Sache break; 435207830Sedwin } 436207830Sedwin } 437207830Sedwin /* 438207830Sedwin * Try the abbreviated month name if the full name 439207830Sedwin * wasn't found and Oalternative was not requested. 440207830Sedwin */ 441207830Sedwin if (i == asizeof(tptr->month) && !Oalternative) { 442207830Sedwin for (i = 0; i < asizeof(tptr->month); i++) { 44374409Sache len = strlen(tptr->mon[i]); 444227753Stheraven if (strncasecmp_l(buf, tptr->mon[i], 445227753Stheraven len, locale) == 0) 44674409Sache break; 44753941Sache } 44828021Sjoerg } 44972168Sphantom if (i == asizeof(tptr->month)) 45028021Sjoerg return 0; 45128019Sjoerg 45228021Sjoerg tm->tm_mon = i; 45328021Sjoerg buf += len; 45428021Sjoerg break; 45528019Sjoerg 45628021Sjoerg case 'm': 457227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 45828021Sjoerg return 0; 45928019Sjoerg 46054316Ssheldonh len = 2; 461227753Stheraven for (i = 0; len && *buf != 0 && 462227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 46328021Sjoerg i *= 10; 46428021Sjoerg i += *buf - '0'; 46554316Ssheldonh len--; 46628021Sjoerg } 46728021Sjoerg if (i < 1 || i > 12) 46828021Sjoerg return 0; 46928019Sjoerg 47028021Sjoerg tm->tm_mon = i - 1; 47128019Sjoerg 472227753Stheraven if (*buf != 0 && 473227753Stheraven isspace_l((unsigned char)*buf, locale)) 474227753Stheraven while (*ptr != 0 && 475227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 47628021Sjoerg ptr++; 47728021Sjoerg break; 47828019Sjoerg 47979664Sdd case 's': 48079664Sdd { 48179664Sdd char *cp; 482122830Snectar int sverrno; 483122830Snectar long n; 48479664Sdd time_t t; 48579664Sdd 486122830Snectar sverrno = errno; 487122830Snectar errno = 0; 488227753Stheraven n = strtol_l(buf, &cp, 10, locale); 489122830Snectar if (errno == ERANGE || (long)(t = n) != n) { 490122830Snectar errno = sverrno; 49179664Sdd return 0; 492122830Snectar } 493122830Snectar errno = sverrno; 49479664Sdd buf = cp; 49579664Sdd gmtime_r(&t, tm); 496112156Smtm *GMTp = 1; 49779664Sdd } 49879664Sdd break; 49979664Sdd 50028021Sjoerg case 'Y': 50128021Sjoerg case 'y': 502227753Stheraven if (*buf == 0 || 503227753Stheraven isspace_l((unsigned char)*buf, locale)) 50428021Sjoerg break; 50528019Sjoerg 506227753Stheraven if (!isdigit_l((unsigned char)*buf, locale)) 50728021Sjoerg return 0; 50828019Sjoerg 50954316Ssheldonh len = (c == 'Y') ? 4 : 2; 510227753Stheraven for (i = 0; len && *buf != 0 && 511227753Stheraven isdigit_l((unsigned char)*buf, locale); buf++) { 51228021Sjoerg i *= 10; 51328021Sjoerg i += *buf - '0'; 51454316Ssheldonh len--; 51528021Sjoerg } 51628021Sjoerg if (c == 'Y') 51728021Sjoerg i -= 1900; 51846051Swes if (c == 'y' && i < 69) 51946042Swes i += 100; 52028021Sjoerg if (i < 0) 52128021Sjoerg return 0; 52228019Sjoerg 52328021Sjoerg tm->tm_year = i; 52428019Sjoerg 525227753Stheraven if (*buf != 0 && 526227753Stheraven isspace_l((unsigned char)*buf, locale)) 527227753Stheraven while (*ptr != 0 && 528227753Stheraven !isspace_l((unsigned char)*ptr, locale)) 52928021Sjoerg ptr++; 53028021Sjoerg break; 53148550Sobrien 53248550Sobrien case 'Z': 53348550Sobrien { 53448550Sobrien const char *cp; 53548550Sobrien char *zonestr; 53648550Sobrien 537227753Stheraven for (cp = buf; *cp && 538227753Stheraven isupper_l((unsigned char)*cp, locale); ++cp) { 539227753Stheraven /*empty*/} 54048550Sobrien if (cp - buf) { 54148550Sobrien zonestr = alloca(cp - buf + 1); 54248550Sobrien strncpy(zonestr, buf, cp - buf); 54348550Sobrien zonestr[cp - buf] = '\0'; 54448550Sobrien tzset(); 54548550Sobrien if (0 == strcmp(zonestr, "GMT")) { 546112156Smtm *GMTp = 1; 54748550Sobrien } else if (0 == strcmp(zonestr, tzname[0])) { 54848614Sobrien tm->tm_isdst = 0; 54948550Sobrien } else if (0 == strcmp(zonestr, tzname[1])) { 55048614Sobrien tm->tm_isdst = 1; 55148550Sobrien } else { 55248614Sobrien return 0; 55348550Sobrien } 55448550Sobrien buf += cp - buf; 55548550Sobrien } 55648550Sobrien } 55748550Sobrien break; 558195015Sdelphij 559195015Sdelphij case 'z': 560195015Sdelphij { 561195015Sdelphij int sign = 1; 562195015Sdelphij 563195015Sdelphij if (*buf != '+') { 564195015Sdelphij if (*buf == '-') 565195015Sdelphij sign = -1; 566195015Sdelphij else 567195015Sdelphij return 0; 568195015Sdelphij } 569195015Sdelphij 570195015Sdelphij buf++; 571195015Sdelphij i = 0; 572195015Sdelphij for (len = 4; len > 0; len--) { 573227753Stheraven if (isdigit_l((unsigned char)*buf, locale)) { 574195015Sdelphij i *= 10; 575195015Sdelphij i += *buf - '0'; 576195015Sdelphij buf++; 577195015Sdelphij } else 578195015Sdelphij return 0; 579195015Sdelphij } 580195015Sdelphij 581195015Sdelphij tm->tm_hour -= sign * (i / 100); 582195015Sdelphij tm->tm_min -= sign * (i % 100); 583195015Sdelphij *GMTp = 1; 584195015Sdelphij } 585195015Sdelphij break; 58628021Sjoerg } 58728021Sjoerg } 58848614Sobrien return (char *)buf; 58948614Sobrien} 59028019Sjoerg 59148614Sobrien 59248614Sobrienchar * 593227753Stheravenstrptime_l(const char * __restrict buf, const char * __restrict fmt, 594227753Stheraven struct tm * __restrict tm, locale_t loc) 59548614Sobrien{ 59648614Sobrien char *ret; 597112156Smtm int gmt; 598227753Stheraven FIX_LOCALE(loc); 59948614Sobrien 600112156Smtm gmt = 0; 601227753Stheraven ret = _strptime(buf, fmt, tm, &gmt, loc); 602114285Smtm if (ret && gmt) { 603114285Smtm time_t t = timegm(tm); 60471579Sdeischen localtime_r(&t, tm); 60548550Sobrien } 60648614Sobrien 607112156Smtm return (ret); 60828019Sjoerg} 609227753Stheravenchar * 610227753Stheravenstrptime(const char * __restrict buf, const char * __restrict fmt, 611227753Stheraven struct tm * __restrict tm) 612227753Stheraven{ 613227753Stheraven return strptime_l(buf, fmt, tm, __get_locale()); 614227753Stheraven} 615