strptime.c revision 92986
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 *
2528021Sjoerg * Redistribution and use in source and binary forms, with or without
2628019Sjoerg * modification, are permitted provided that the following conditions
2728019Sjoerg * are met:
2828019Sjoerg * 1. Redistributions of source code must retain the above copyright
2928019Sjoerg *    notice, this list of conditions and the following disclaimer.
3028019Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
3128019Sjoerg *    notice, this list of conditions and the following disclaimer
3228019Sjoerg *    in the documentation and/or other materials provided with the
3328019Sjoerg *    distribution.
3428019Sjoerg * 3. All advertising materials mentioning features or use of this
3528019Sjoerg *    software must display the following acknowledgement:
3628019Sjoerg *      This product includes software developed by Powerdog Industries.
3728019Sjoerg * 4. The name of Powerdog Industries may not be used to endorse or
3828019Sjoerg *    promote products derived from this software without specific prior
3928019Sjoerg *    written permission.
4028019Sjoerg *
4128019Sjoerg * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
4228019Sjoerg * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4328019Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4428019Sjoerg * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
4528019Sjoerg * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4628019Sjoerg * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
4728019Sjoerg * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4828019Sjoerg * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4928019Sjoerg * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
5028019Sjoerg * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
5128019Sjoerg * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5228019Sjoerg */
5328019Sjoerg
5428019Sjoerg#ifndef lint
5528021Sjoerg#ifndef NOID
5628019Sjoergstatic char copyright[] =
5728019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
5828021Sjoergstatic char sccsid[] = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
5928021Sjoerg#endif /* !defined NOID */
6028019Sjoerg#endif /* not lint */
6192986Sobrien#include <sys/cdefs.h>
6292986Sobrien__FBSDID("$FreeBSD: head/lib/libc/stdtime/strptime.c 92986 2002-03-22 21:53:29Z obrien $");
6328019Sjoerg
6471579Sdeischen#include "namespace.h"
6528019Sjoerg#include <time.h>
6628019Sjoerg#include <ctype.h>
6779664Sdd#include <limits.h>
6879664Sdd#include <stdlib.h>
6928019Sjoerg#include <string.h>
7048614Sobrien#include <pthread.h>
7171579Sdeischen#include "un-namespace.h"
7271579Sdeischen#include "libc_private.h"
7328021Sjoerg#include "timelocal.h"
7428019Sjoerg
7548614Sobrienstatic char * _strptime(const char *, const char *, struct tm *);
7648614Sobrien
7771579Sdeischenstatic pthread_mutex_t	gotgmt_mutex = PTHREAD_MUTEX_INITIALIZER;
7848614Sobrienstatic int got_GMT;
7948614Sobrien
8028021Sjoerg#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
8128019Sjoerg
8248614Sobrienstatic char *
8348614Sobrien_strptime(const char *buf, const char *fmt, struct tm *tm)
8428019Sjoerg{
8528021Sjoerg	char	c;
8628021Sjoerg	const char *ptr;
8728021Sjoerg	int	i,
8828021Sjoerg		len;
8953941Sache	int Ealternative, Oalternative;
9072168Sphantom	struct lc_time_T *tptr = __get_current_time_locale();
9128019Sjoerg
9228021Sjoerg	ptr = fmt;
9328021Sjoerg	while (*ptr != 0) {
9428021Sjoerg		if (*buf == 0)
9528021Sjoerg			break;
9628019Sjoerg
9728021Sjoerg		c = *ptr++;
9828019Sjoerg
9928021Sjoerg		if (c != '%') {
10028164Sache			if (isspace((unsigned char)c))
10128164Sache				while (*buf != 0 && isspace((unsigned char)*buf))
10228021Sjoerg					buf++;
10328021Sjoerg			else if (c != *buf++)
10428021Sjoerg				return 0;
10528021Sjoerg			continue;
10628021Sjoerg		}
10728019Sjoerg
10853941Sache		Ealternative = 0;
10953941Sache		Oalternative = 0;
11053941Sachelabel:
11128021Sjoerg		c = *ptr++;
11228021Sjoerg		switch (c) {
11328021Sjoerg		case 0:
11428021Sjoerg		case '%':
11528021Sjoerg			if (*buf++ != '%')
11628021Sjoerg				return 0;
11728021Sjoerg			break;
11828019Sjoerg
11953941Sache		case '+':
12072168Sphantom			buf = _strptime(buf, tptr->date_fmt, tm);
12128021Sjoerg			if (buf == 0)
12228021Sjoerg				return 0;
12328021Sjoerg			break;
12428019Sjoerg
12553941Sache		case 'C':
12653941Sache			if (!isdigit((unsigned char)*buf))
12753941Sache				return 0;
12853941Sache
12954316Ssheldonh			/* XXX This will break for 3-digit centuries. */
13054316Ssheldonh			len = 2;
13154316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
13253941Sache				i *= 10;
13353941Sache				i += *buf - '0';
13454316Ssheldonh				len--;
13553941Sache			}
13653941Sache			if (i < 19)
13753941Sache				return 0;
13853941Sache
13953941Sache			tm->tm_year = i * 100 - 1900;
14053941Sache			break;
14153941Sache
14228021Sjoerg		case 'c':
14372183Sache			buf = _strptime(buf, tptr->c_fmt, tm);
14428021Sjoerg			if (buf == 0)
14528021Sjoerg				return 0;
14628021Sjoerg			break;
14728019Sjoerg
14828021Sjoerg		case 'D':
14948614Sobrien			buf = _strptime(buf, "%m/%d/%y", tm);
15028021Sjoerg			if (buf == 0)
15128021Sjoerg				return 0;
15228021Sjoerg			break;
15328019Sjoerg
15453941Sache		case 'E':
15553960Sache			if (Ealternative || Oalternative)
15653960Sache				break;
15753941Sache			Ealternative++;
15853941Sache			goto label;
15953941Sache
16053941Sache		case 'O':
16153960Sache			if (Ealternative || Oalternative)
16253960Sache				break;
16353941Sache			Oalternative++;
16453941Sache			goto label;
16553941Sache
16653960Sache		case 'F':
16774578Sache			buf = _strptime(buf, "%Y-%m-%d", tm);
16874412Sache			if (buf == 0)
16974412Sache				return 0;
17074412Sache			break;
17174412Sache
17228021Sjoerg		case 'R':
17348614Sobrien			buf = _strptime(buf, "%H:%M", tm);
17428021Sjoerg			if (buf == 0)
17528021Sjoerg				return 0;
17628021Sjoerg			break;
17728019Sjoerg
17828021Sjoerg		case 'r':
17973359Sache			buf = _strptime(buf, tptr->ampm_fmt, tm);
18028021Sjoerg			if (buf == 0)
18128021Sjoerg				return 0;
18228021Sjoerg			break;
18328019Sjoerg
18428021Sjoerg		case 'T':
18548614Sobrien			buf = _strptime(buf, "%H:%M:%S", tm);
18628021Sjoerg			if (buf == 0)
18728021Sjoerg				return 0;
18828021Sjoerg			break;
18928019Sjoerg
19028021Sjoerg		case 'X':
19172168Sphantom			buf = _strptime(buf, tptr->X_fmt, tm);
19228021Sjoerg			if (buf == 0)
19328021Sjoerg				return 0;
19428021Sjoerg			break;
19528019Sjoerg
19628021Sjoerg		case 'x':
19772168Sphantom			buf = _strptime(buf, tptr->x_fmt, tm);
19828021Sjoerg			if (buf == 0)
19928021Sjoerg				return 0;
20028021Sjoerg			break;
20128019Sjoerg
20228021Sjoerg		case 'j':
20328164Sache			if (!isdigit((unsigned char)*buf))
20428021Sjoerg				return 0;
20528019Sjoerg
20654316Ssheldonh			len = 3;
20754316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
20828021Sjoerg				i *= 10;
20928021Sjoerg				i += *buf - '0';
21054316Ssheldonh				len--;
21128021Sjoerg			}
21253083Ssheldonh			if (i < 1 || i > 366)
21328021Sjoerg				return 0;
21428019Sjoerg
21553083Ssheldonh			tm->tm_yday = i - 1;
21628021Sjoerg			break;
21728019Sjoerg
21828021Sjoerg		case 'M':
21928021Sjoerg		case 'S':
22028164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
22128021Sjoerg				break;
22228019Sjoerg
22328164Sache			if (!isdigit((unsigned char)*buf))
22428021Sjoerg				return 0;
22528019Sjoerg
22654316Ssheldonh			len = 2;
22754316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
22828021Sjoerg				i *= 10;
22928021Sjoerg				i += *buf - '0';
23054316Ssheldonh				len--;
23128021Sjoerg			}
23228019Sjoerg
23353083Ssheldonh			if (c == 'M') {
23453083Ssheldonh				if (i > 59)
23553083Ssheldonh					return 0;
23628021Sjoerg				tm->tm_min = i;
23753083Ssheldonh			} else {
23853083Ssheldonh				if (i > 60)
23953083Ssheldonh					return 0;
24028021Sjoerg				tm->tm_sec = i;
24153083Ssheldonh			}
24228019Sjoerg
24328164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
24428164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
24528021Sjoerg					ptr++;
24628021Sjoerg			break;
24728019Sjoerg
24828021Sjoerg		case 'H':
24928021Sjoerg		case 'I':
25028021Sjoerg		case 'k':
25128021Sjoerg		case 'l':
25254316Ssheldonh			/*
25354316Ssheldonh			 * Of these, %l is the only specifier explicitly
25454316Ssheldonh			 * documented as not being zero-padded.  However,
25554316Ssheldonh			 * there is no harm in allowing zero-padding.
25654316Ssheldonh			 *
25754316Ssheldonh			 * XXX The %l specifier may gobble one too many
25854316Ssheldonh			 * digits if used incorrectly.
25954316Ssheldonh			 */
26028164Sache			if (!isdigit((unsigned char)*buf))
26128021Sjoerg				return 0;
26228019Sjoerg
26354316Ssheldonh			len = 2;
26454316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
26528021Sjoerg				i *= 10;
26628021Sjoerg				i += *buf - '0';
26754316Ssheldonh				len--;
26828021Sjoerg			}
26928021Sjoerg			if (c == 'H' || c == 'k') {
27028021Sjoerg				if (i > 23)
27128021Sjoerg					return 0;
27254301Ssheldonh			} else if (i > 12)
27328021Sjoerg				return 0;
27428019Sjoerg
27528021Sjoerg			tm->tm_hour = i;
27628019Sjoerg
27728164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
27828164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
27928021Sjoerg					ptr++;
28028021Sjoerg			break;
28128019Sjoerg
28228021Sjoerg		case 'p':
28354316Ssheldonh			/*
28454316Ssheldonh			 * XXX This is bogus if parsed before hour-related
28554316Ssheldonh			 * specifiers.
28654316Ssheldonh			 */
28772168Sphantom			len = strlen(tptr->am);
28872168Sphantom			if (strncasecmp(buf, tptr->am, len) == 0) {
28928021Sjoerg				if (tm->tm_hour > 12)
29028021Sjoerg					return 0;
29128021Sjoerg				if (tm->tm_hour == 12)
29228021Sjoerg					tm->tm_hour = 0;
29328021Sjoerg				buf += len;
29428021Sjoerg				break;
29528021Sjoerg			}
29628019Sjoerg
29772168Sphantom			len = strlen(tptr->pm);
29872168Sphantom			if (strncasecmp(buf, tptr->pm, len) == 0) {
29928021Sjoerg				if (tm->tm_hour > 12)
30028021Sjoerg					return 0;
30128021Sjoerg				if (tm->tm_hour != 12)
30228021Sjoerg					tm->tm_hour += 12;
30328021Sjoerg				buf += len;
30428021Sjoerg				break;
30528021Sjoerg			}
30628019Sjoerg
30728021Sjoerg			return 0;
30828019Sjoerg
30928021Sjoerg		case 'A':
31028021Sjoerg		case 'a':
31172168Sphantom			for (i = 0; i < asizeof(tptr->weekday); i++) {
31274409Sache				len = strlen(tptr->weekday[i]);
31374409Sache				if (strncasecmp(buf, tptr->weekday[i],
31474409Sache						len) == 0)
31574409Sache					break;
31674409Sache				len = strlen(tptr->wday[i]);
31774409Sache				if (strncasecmp(buf, tptr->wday[i],
31874409Sache						len) == 0)
31974409Sache					break;
32028021Sjoerg			}
32172168Sphantom			if (i == asizeof(tptr->weekday))
32228021Sjoerg				return 0;
32328019Sjoerg
32428021Sjoerg			tm->tm_wday = i;
32528021Sjoerg			buf += len;
32628021Sjoerg			break;
32728019Sjoerg
32853083Ssheldonh		case 'U':
32953083Ssheldonh		case 'W':
33053083Ssheldonh			/*
33153083Ssheldonh			 * XXX This is bogus, as we can not assume any valid
33253083Ssheldonh			 * information present in the tm structure at this
33353083Ssheldonh			 * point to calculate a real value, so just check the
33453083Ssheldonh			 * range for now.
33553083Ssheldonh			 */
33653083Ssheldonh			if (!isdigit((unsigned char)*buf))
33753083Ssheldonh				return 0;
33853083Ssheldonh
33954316Ssheldonh			len = 2;
34054316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
34153083Ssheldonh				i *= 10;
34253083Ssheldonh				i += *buf - '0';
34354316Ssheldonh				len--;
34453083Ssheldonh			}
34553083Ssheldonh			if (i > 53)
34653083Ssheldonh				return 0;
34753083Ssheldonh
34853083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
34953083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
35053083Ssheldonh					ptr++;
35153083Ssheldonh			break;
35253083Ssheldonh
35353083Ssheldonh		case 'w':
35453083Ssheldonh			if (!isdigit((unsigned char)*buf))
35553083Ssheldonh				return 0;
35653083Ssheldonh
35754316Ssheldonh			i = *buf - '0';
35853083Ssheldonh			if (i > 6)
35953083Ssheldonh				return 0;
36053083Ssheldonh
36153083Ssheldonh			tm->tm_wday = i;
36253083Ssheldonh
36353083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
36453083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
36553083Ssheldonh					ptr++;
36653083Ssheldonh			break;
36753083Ssheldonh
36828021Sjoerg		case 'd':
36928021Sjoerg		case 'e':
37054316Ssheldonh			/*
37154316Ssheldonh			 * The %e specifier is explicitly documented as not
37254316Ssheldonh			 * being zero-padded but there is no harm in allowing
37354316Ssheldonh			 * such padding.
37454316Ssheldonh			 *
37554316Ssheldonh			 * XXX The %e specifier may gobble one too many
37654316Ssheldonh			 * digits if used incorrectly.
37754316Ssheldonh			 */
37828164Sache			if (!isdigit((unsigned char)*buf))
37928021Sjoerg				return 0;
38028019Sjoerg
38154316Ssheldonh			len = 2;
38254316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
38328021Sjoerg				i *= 10;
38428021Sjoerg				i += *buf - '0';
38554316Ssheldonh				len--;
38628021Sjoerg			}
38728021Sjoerg			if (i > 31)
38828021Sjoerg				return 0;
38928019Sjoerg
39028021Sjoerg			tm->tm_mday = i;
39128019Sjoerg
39228164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
39328164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
39428021Sjoerg					ptr++;
39528021Sjoerg			break;
39628019Sjoerg
39728021Sjoerg		case 'B':
39828021Sjoerg		case 'b':
39928021Sjoerg		case 'h':
40072168Sphantom			for (i = 0; i < asizeof(tptr->month); i++) {
40153941Sache				if (Oalternative) {
40253941Sache					if (c == 'B') {
40372168Sphantom						len = strlen(tptr->alt_month[i]);
40453941Sache						if (strncasecmp(buf,
40572168Sphantom								tptr->alt_month[i],
40653941Sache								len) == 0)
40753941Sache							break;
40853941Sache					}
40953941Sache				} else {
41074409Sache					len = strlen(tptr->month[i]);
41174409Sache					if (strncasecmp(buf, tptr->month[i],
41274409Sache							len) == 0)
41374409Sache						break;
41474409Sache					len = strlen(tptr->mon[i]);
41574409Sache					if (strncasecmp(buf, tptr->mon[i],
41674409Sache							len) == 0)
41774409Sache						break;
41853941Sache				}
41928021Sjoerg			}
42072168Sphantom			if (i == asizeof(tptr->month))
42128021Sjoerg				return 0;
42228019Sjoerg
42328021Sjoerg			tm->tm_mon = i;
42428021Sjoerg			buf += len;
42528021Sjoerg			break;
42628019Sjoerg
42728021Sjoerg		case 'm':
42828164Sache			if (!isdigit((unsigned char)*buf))
42928021Sjoerg				return 0;
43028019Sjoerg
43154316Ssheldonh			len = 2;
43254316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
43328021Sjoerg				i *= 10;
43428021Sjoerg				i += *buf - '0';
43554316Ssheldonh				len--;
43628021Sjoerg			}
43728021Sjoerg			if (i < 1 || i > 12)
43828021Sjoerg				return 0;
43928019Sjoerg
44028021Sjoerg			tm->tm_mon = i - 1;
44128019Sjoerg
44228164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
44328164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
44428021Sjoerg					ptr++;
44528021Sjoerg			break;
44628019Sjoerg
44779664Sdd		case 's':
44879664Sdd			{
44979664Sdd			char *cp;
45079664Sdd			time_t t;
45179664Sdd
45279664Sdd			t = strtol(buf, &cp, 10);
45379664Sdd			if (t == LONG_MAX)
45479664Sdd				return 0;
45579664Sdd			buf = cp;
45679664Sdd			gmtime_r(&t, tm);
45779664Sdd			got_GMT = 1;
45879664Sdd			}
45979664Sdd			break;
46079664Sdd
46128021Sjoerg		case 'Y':
46228021Sjoerg		case 'y':
46328164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
46428021Sjoerg				break;
46528019Sjoerg
46628164Sache			if (!isdigit((unsigned char)*buf))
46728021Sjoerg				return 0;
46828019Sjoerg
46954316Ssheldonh			len = (c == 'Y') ? 4 : 2;
47054316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
47128021Sjoerg				i *= 10;
47228021Sjoerg				i += *buf - '0';
47354316Ssheldonh				len--;
47428021Sjoerg			}
47528021Sjoerg			if (c == 'Y')
47628021Sjoerg				i -= 1900;
47746051Swes			if (c == 'y' && i < 69)
47846042Swes				i += 100;
47928021Sjoerg			if (i < 0)
48028021Sjoerg				return 0;
48128019Sjoerg
48228021Sjoerg			tm->tm_year = i;
48328019Sjoerg
48428164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
48528164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
48628021Sjoerg					ptr++;
48728021Sjoerg			break;
48848550Sobrien
48948550Sobrien		case 'Z':
49048550Sobrien			{
49148550Sobrien			const char *cp;
49248550Sobrien			char *zonestr;
49348550Sobrien
49452860Sache			for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
49548550Sobrien			if (cp - buf) {
49648550Sobrien				zonestr = alloca(cp - buf + 1);
49748550Sobrien				strncpy(zonestr, buf, cp - buf);
49848550Sobrien				zonestr[cp - buf] = '\0';
49948550Sobrien				tzset();
50048550Sobrien				if (0 == strcmp(zonestr, "GMT")) {
50148614Sobrien				    got_GMT = 1;
50248550Sobrien				} else if (0 == strcmp(zonestr, tzname[0])) {
50348614Sobrien				    tm->tm_isdst = 0;
50448550Sobrien				} else if (0 == strcmp(zonestr, tzname[1])) {
50548614Sobrien				    tm->tm_isdst = 1;
50648550Sobrien				} else {
50748614Sobrien				    return 0;
50848550Sobrien				}
50948550Sobrien				buf += cp - buf;
51048550Sobrien			}
51148550Sobrien			}
51248550Sobrien			break;
51328021Sjoerg		}
51428021Sjoerg	}
51548614Sobrien	return (char *)buf;
51648614Sobrien}
51728019Sjoerg
51848614Sobrien
51948614Sobrienchar *
52048614Sobrienstrptime(const char *buf, const char *fmt, struct tm *tm)
52148614Sobrien{
52248614Sobrien	char *ret;
52348614Sobrien
52471579Sdeischen	if (__isthreaded)
52571579Sdeischen		_pthread_mutex_lock(&gotgmt_mutex);
52648614Sobrien
52748614Sobrien	got_GMT = 0;
52848614Sobrien	ret = _strptime(buf, fmt, tm);
52948614Sobrien	if (ret && got_GMT) {
53048550Sobrien		time_t t = timegm(tm);
53171579Sdeischen		localtime_r(&t, tm);
53248614Sobrien		got_GMT = 0;
53348550Sobrien	}
53448614Sobrien
53571579Sdeischen	if (__isthreaded)
53671579Sdeischen		_pthread_mutex_unlock(&gotgmt_mutex);
53748614Sobrien
53848614Sobrien	return ret;
53928019Sjoerg}
540