strptime.c revision 79664
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
5428021Sjoerg#ifdef LIBC_RCS
5528021Sjoergstatic const char rcsid[] =
5650476Speter  "$FreeBSD: head/lib/libc/stdtime/strptime.c 79664 2001-07-13 13:59:24Z dd $";
5728021Sjoerg#endif
5828021Sjoerg
5928019Sjoerg#ifndef lint
6028021Sjoerg#ifndef NOID
6128019Sjoergstatic char copyright[] =
6228019Sjoerg"@(#) Copyright (c) 1994 Powerdog Industries.  All rights reserved.";
6328021Sjoergstatic char sccsid[] = "@(#)strptime.c	0.1 (Powerdog) 94/03/27";
6428021Sjoerg#endif /* !defined NOID */
6528019Sjoerg#endif /* not lint */
6628019Sjoerg
6771579Sdeischen#include "namespace.h"
6828019Sjoerg#include <time.h>
6928019Sjoerg#include <ctype.h>
7079664Sdd#include <limits.h>
7179664Sdd#include <stdlib.h>
7228019Sjoerg#include <string.h>
7348614Sobrien#include <pthread.h>
7471579Sdeischen#include "un-namespace.h"
7571579Sdeischen#include "libc_private.h"
7628021Sjoerg#include "timelocal.h"
7728019Sjoerg
7848614Sobrienstatic char * _strptime(const char *, const char *, struct tm *);
7948614Sobrien
8071579Sdeischenstatic pthread_mutex_t	gotgmt_mutex = PTHREAD_MUTEX_INITIALIZER;
8148614Sobrienstatic int got_GMT;
8248614Sobrien
8328021Sjoerg#define asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
8428019Sjoerg
8548614Sobrienstatic char *
8648614Sobrien_strptime(const char *buf, const char *fmt, struct tm *tm)
8728019Sjoerg{
8828021Sjoerg	char	c;
8928021Sjoerg	const char *ptr;
9028021Sjoerg	int	i,
9128021Sjoerg		len;
9253941Sache	int Ealternative, Oalternative;
9372168Sphantom	struct lc_time_T *tptr = __get_current_time_locale();
9428019Sjoerg
9528021Sjoerg	ptr = fmt;
9628021Sjoerg	while (*ptr != 0) {
9728021Sjoerg		if (*buf == 0)
9828021Sjoerg			break;
9928019Sjoerg
10028021Sjoerg		c = *ptr++;
10128019Sjoerg
10228021Sjoerg		if (c != '%') {
10328164Sache			if (isspace((unsigned char)c))
10428164Sache				while (*buf != 0 && isspace((unsigned char)*buf))
10528021Sjoerg					buf++;
10628021Sjoerg			else if (c != *buf++)
10728021Sjoerg				return 0;
10828021Sjoerg			continue;
10928021Sjoerg		}
11028019Sjoerg
11153941Sache		Ealternative = 0;
11253941Sache		Oalternative = 0;
11353941Sachelabel:
11428021Sjoerg		c = *ptr++;
11528021Sjoerg		switch (c) {
11628021Sjoerg		case 0:
11728021Sjoerg		case '%':
11828021Sjoerg			if (*buf++ != '%')
11928021Sjoerg				return 0;
12028021Sjoerg			break;
12128019Sjoerg
12253941Sache		case '+':
12372168Sphantom			buf = _strptime(buf, tptr->date_fmt, tm);
12428021Sjoerg			if (buf == 0)
12528021Sjoerg				return 0;
12628021Sjoerg			break;
12728019Sjoerg
12853941Sache		case 'C':
12953941Sache			if (!isdigit((unsigned char)*buf))
13053941Sache				return 0;
13153941Sache
13254316Ssheldonh			/* XXX This will break for 3-digit centuries. */
13354316Ssheldonh			len = 2;
13454316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
13553941Sache				i *= 10;
13653941Sache				i += *buf - '0';
13754316Ssheldonh				len--;
13853941Sache			}
13953941Sache			if (i < 19)
14053941Sache				return 0;
14153941Sache
14253941Sache			tm->tm_year = i * 100 - 1900;
14353941Sache			break;
14453941Sache
14528021Sjoerg		case 'c':
14672183Sache			buf = _strptime(buf, tptr->c_fmt, tm);
14728021Sjoerg			if (buf == 0)
14828021Sjoerg				return 0;
14928021Sjoerg			break;
15028019Sjoerg
15128021Sjoerg		case 'D':
15248614Sobrien			buf = _strptime(buf, "%m/%d/%y", tm);
15328021Sjoerg			if (buf == 0)
15428021Sjoerg				return 0;
15528021Sjoerg			break;
15628019Sjoerg
15753941Sache		case 'E':
15853960Sache			if (Ealternative || Oalternative)
15953960Sache				break;
16053941Sache			Ealternative++;
16153941Sache			goto label;
16253941Sache
16353941Sache		case 'O':
16453960Sache			if (Ealternative || Oalternative)
16553960Sache				break;
16653941Sache			Oalternative++;
16753941Sache			goto label;
16853941Sache
16953960Sache		case 'F':
17074578Sache			buf = _strptime(buf, "%Y-%m-%d", tm);
17174412Sache			if (buf == 0)
17274412Sache				return 0;
17374412Sache			break;
17474412Sache
17528021Sjoerg		case 'R':
17648614Sobrien			buf = _strptime(buf, "%H:%M", tm);
17728021Sjoerg			if (buf == 0)
17828021Sjoerg				return 0;
17928021Sjoerg			break;
18028019Sjoerg
18128021Sjoerg		case 'r':
18273359Sache			buf = _strptime(buf, tptr->ampm_fmt, tm);
18328021Sjoerg			if (buf == 0)
18428021Sjoerg				return 0;
18528021Sjoerg			break;
18628019Sjoerg
18728021Sjoerg		case 'T':
18848614Sobrien			buf = _strptime(buf, "%H:%M:%S", tm);
18928021Sjoerg			if (buf == 0)
19028021Sjoerg				return 0;
19128021Sjoerg			break;
19228019Sjoerg
19328021Sjoerg		case 'X':
19472168Sphantom			buf = _strptime(buf, tptr->X_fmt, tm);
19528021Sjoerg			if (buf == 0)
19628021Sjoerg				return 0;
19728021Sjoerg			break;
19828019Sjoerg
19928021Sjoerg		case 'x':
20072168Sphantom			buf = _strptime(buf, tptr->x_fmt, tm);
20128021Sjoerg			if (buf == 0)
20228021Sjoerg				return 0;
20328021Sjoerg			break;
20428019Sjoerg
20528021Sjoerg		case 'j':
20628164Sache			if (!isdigit((unsigned char)*buf))
20728021Sjoerg				return 0;
20828019Sjoerg
20954316Ssheldonh			len = 3;
21054316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
21128021Sjoerg				i *= 10;
21228021Sjoerg				i += *buf - '0';
21354316Ssheldonh				len--;
21428021Sjoerg			}
21553083Ssheldonh			if (i < 1 || i > 366)
21628021Sjoerg				return 0;
21728019Sjoerg
21853083Ssheldonh			tm->tm_yday = i - 1;
21928021Sjoerg			break;
22028019Sjoerg
22128021Sjoerg		case 'M':
22228021Sjoerg		case 'S':
22328164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
22428021Sjoerg				break;
22528019Sjoerg
22628164Sache			if (!isdigit((unsigned char)*buf))
22728021Sjoerg				return 0;
22828019Sjoerg
22954316Ssheldonh			len = 2;
23054316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
23128021Sjoerg				i *= 10;
23228021Sjoerg				i += *buf - '0';
23354316Ssheldonh				len--;
23428021Sjoerg			}
23528019Sjoerg
23653083Ssheldonh			if (c == 'M') {
23753083Ssheldonh				if (i > 59)
23853083Ssheldonh					return 0;
23928021Sjoerg				tm->tm_min = i;
24053083Ssheldonh			} else {
24153083Ssheldonh				if (i > 60)
24253083Ssheldonh					return 0;
24328021Sjoerg				tm->tm_sec = i;
24453083Ssheldonh			}
24528019Sjoerg
24628164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
24728164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
24828021Sjoerg					ptr++;
24928021Sjoerg			break;
25028019Sjoerg
25128021Sjoerg		case 'H':
25228021Sjoerg		case 'I':
25328021Sjoerg		case 'k':
25428021Sjoerg		case 'l':
25554316Ssheldonh			/*
25654316Ssheldonh			 * Of these, %l is the only specifier explicitly
25754316Ssheldonh			 * documented as not being zero-padded.  However,
25854316Ssheldonh			 * there is no harm in allowing zero-padding.
25954316Ssheldonh			 *
26054316Ssheldonh			 * XXX The %l specifier may gobble one too many
26154316Ssheldonh			 * digits if used incorrectly.
26254316Ssheldonh			 */
26328164Sache			if (!isdigit((unsigned char)*buf))
26428021Sjoerg				return 0;
26528019Sjoerg
26654316Ssheldonh			len = 2;
26754316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
26828021Sjoerg				i *= 10;
26928021Sjoerg				i += *buf - '0';
27054316Ssheldonh				len--;
27128021Sjoerg			}
27228021Sjoerg			if (c == 'H' || c == 'k') {
27328021Sjoerg				if (i > 23)
27428021Sjoerg					return 0;
27554301Ssheldonh			} else if (i > 12)
27628021Sjoerg				return 0;
27728019Sjoerg
27828021Sjoerg			tm->tm_hour = i;
27928019Sjoerg
28028164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
28128164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
28228021Sjoerg					ptr++;
28328021Sjoerg			break;
28428019Sjoerg
28528021Sjoerg		case 'p':
28654316Ssheldonh			/*
28754316Ssheldonh			 * XXX This is bogus if parsed before hour-related
28854316Ssheldonh			 * specifiers.
28954316Ssheldonh			 */
29072168Sphantom			len = strlen(tptr->am);
29172168Sphantom			if (strncasecmp(buf, tptr->am, len) == 0) {
29228021Sjoerg				if (tm->tm_hour > 12)
29328021Sjoerg					return 0;
29428021Sjoerg				if (tm->tm_hour == 12)
29528021Sjoerg					tm->tm_hour = 0;
29628021Sjoerg				buf += len;
29728021Sjoerg				break;
29828021Sjoerg			}
29928019Sjoerg
30072168Sphantom			len = strlen(tptr->pm);
30172168Sphantom			if (strncasecmp(buf, tptr->pm, len) == 0) {
30228021Sjoerg				if (tm->tm_hour > 12)
30328021Sjoerg					return 0;
30428021Sjoerg				if (tm->tm_hour != 12)
30528021Sjoerg					tm->tm_hour += 12;
30628021Sjoerg				buf += len;
30728021Sjoerg				break;
30828021Sjoerg			}
30928019Sjoerg
31028021Sjoerg			return 0;
31128019Sjoerg
31228021Sjoerg		case 'A':
31328021Sjoerg		case 'a':
31472168Sphantom			for (i = 0; i < asizeof(tptr->weekday); i++) {
31574409Sache				len = strlen(tptr->weekday[i]);
31674409Sache				if (strncasecmp(buf, tptr->weekday[i],
31774409Sache						len) == 0)
31874409Sache					break;
31974409Sache				len = strlen(tptr->wday[i]);
32074409Sache				if (strncasecmp(buf, tptr->wday[i],
32174409Sache						len) == 0)
32274409Sache					break;
32328021Sjoerg			}
32472168Sphantom			if (i == asizeof(tptr->weekday))
32528021Sjoerg				return 0;
32628019Sjoerg
32728021Sjoerg			tm->tm_wday = i;
32828021Sjoerg			buf += len;
32928021Sjoerg			break;
33028019Sjoerg
33153083Ssheldonh		case 'U':
33253083Ssheldonh		case 'W':
33353083Ssheldonh			/*
33453083Ssheldonh			 * XXX This is bogus, as we can not assume any valid
33553083Ssheldonh			 * information present in the tm structure at this
33653083Ssheldonh			 * point to calculate a real value, so just check the
33753083Ssheldonh			 * range for now.
33853083Ssheldonh			 */
33953083Ssheldonh			if (!isdigit((unsigned char)*buf))
34053083Ssheldonh				return 0;
34153083Ssheldonh
34254316Ssheldonh			len = 2;
34354316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
34453083Ssheldonh				i *= 10;
34553083Ssheldonh				i += *buf - '0';
34654316Ssheldonh				len--;
34753083Ssheldonh			}
34853083Ssheldonh			if (i > 53)
34953083Ssheldonh				return 0;
35053083Ssheldonh
35153083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
35253083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
35353083Ssheldonh					ptr++;
35453083Ssheldonh			break;
35553083Ssheldonh
35653083Ssheldonh		case 'w':
35753083Ssheldonh			if (!isdigit((unsigned char)*buf))
35853083Ssheldonh				return 0;
35953083Ssheldonh
36054316Ssheldonh			i = *buf - '0';
36153083Ssheldonh			if (i > 6)
36253083Ssheldonh				return 0;
36353083Ssheldonh
36453083Ssheldonh			tm->tm_wday = i;
36553083Ssheldonh
36653083Ssheldonh			if (*buf != 0 && isspace((unsigned char)*buf))
36753083Ssheldonh				while (*ptr != 0 && !isspace((unsigned char)*ptr))
36853083Ssheldonh					ptr++;
36953083Ssheldonh			break;
37053083Ssheldonh
37128021Sjoerg		case 'd':
37228021Sjoerg		case 'e':
37354316Ssheldonh			/*
37454316Ssheldonh			 * The %e specifier is explicitly documented as not
37554316Ssheldonh			 * being zero-padded but there is no harm in allowing
37654316Ssheldonh			 * such padding.
37754316Ssheldonh			 *
37854316Ssheldonh			 * XXX The %e specifier may gobble one too many
37954316Ssheldonh			 * digits if used incorrectly.
38054316Ssheldonh			 */
38128164Sache			if (!isdigit((unsigned char)*buf))
38228021Sjoerg				return 0;
38328019Sjoerg
38454316Ssheldonh			len = 2;
38554316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
38628021Sjoerg				i *= 10;
38728021Sjoerg				i += *buf - '0';
38854316Ssheldonh				len--;
38928021Sjoerg			}
39028021Sjoerg			if (i > 31)
39128021Sjoerg				return 0;
39228019Sjoerg
39328021Sjoerg			tm->tm_mday = i;
39428019Sjoerg
39528164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
39628164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
39728021Sjoerg					ptr++;
39828021Sjoerg			break;
39928019Sjoerg
40028021Sjoerg		case 'B':
40128021Sjoerg		case 'b':
40228021Sjoerg		case 'h':
40372168Sphantom			for (i = 0; i < asizeof(tptr->month); i++) {
40453941Sache				if (Oalternative) {
40553941Sache					if (c == 'B') {
40672168Sphantom						len = strlen(tptr->alt_month[i]);
40753941Sache						if (strncasecmp(buf,
40872168Sphantom								tptr->alt_month[i],
40953941Sache								len) == 0)
41053941Sache							break;
41153941Sache					}
41253941Sache				} else {
41374409Sache					len = strlen(tptr->month[i]);
41474409Sache					if (strncasecmp(buf, tptr->month[i],
41574409Sache							len) == 0)
41674409Sache						break;
41774409Sache					len = strlen(tptr->mon[i]);
41874409Sache					if (strncasecmp(buf, tptr->mon[i],
41974409Sache							len) == 0)
42074409Sache						break;
42153941Sache				}
42228021Sjoerg			}
42372168Sphantom			if (i == asizeof(tptr->month))
42428021Sjoerg				return 0;
42528019Sjoerg
42628021Sjoerg			tm->tm_mon = i;
42728021Sjoerg			buf += len;
42828021Sjoerg			break;
42928019Sjoerg
43028021Sjoerg		case 'm':
43128164Sache			if (!isdigit((unsigned char)*buf))
43228021Sjoerg				return 0;
43328019Sjoerg
43454316Ssheldonh			len = 2;
43554316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
43628021Sjoerg				i *= 10;
43728021Sjoerg				i += *buf - '0';
43854316Ssheldonh				len--;
43928021Sjoerg			}
44028021Sjoerg			if (i < 1 || i > 12)
44128021Sjoerg				return 0;
44228019Sjoerg
44328021Sjoerg			tm->tm_mon = i - 1;
44428019Sjoerg
44528164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
44628164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
44728021Sjoerg					ptr++;
44828021Sjoerg			break;
44928019Sjoerg
45079664Sdd		case 's':
45179664Sdd			{
45279664Sdd			char *cp;
45379664Sdd			time_t t;
45479664Sdd
45579664Sdd			t = strtol(buf, &cp, 10);
45679664Sdd			if (t == LONG_MAX)
45779664Sdd				return 0;
45879664Sdd			buf = cp;
45979664Sdd			gmtime_r(&t, tm);
46079664Sdd			got_GMT = 1;
46179664Sdd			}
46279664Sdd			break;
46379664Sdd
46428021Sjoerg		case 'Y':
46528021Sjoerg		case 'y':
46628164Sache			if (*buf == 0 || isspace((unsigned char)*buf))
46728021Sjoerg				break;
46828019Sjoerg
46928164Sache			if (!isdigit((unsigned char)*buf))
47028021Sjoerg				return 0;
47128019Sjoerg
47254316Ssheldonh			len = (c == 'Y') ? 4 : 2;
47354316Ssheldonh			for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
47428021Sjoerg				i *= 10;
47528021Sjoerg				i += *buf - '0';
47654316Ssheldonh				len--;
47728021Sjoerg			}
47828021Sjoerg			if (c == 'Y')
47928021Sjoerg				i -= 1900;
48046051Swes			if (c == 'y' && i < 69)
48146042Swes				i += 100;
48228021Sjoerg			if (i < 0)
48328021Sjoerg				return 0;
48428019Sjoerg
48528021Sjoerg			tm->tm_year = i;
48628019Sjoerg
48728164Sache			if (*buf != 0 && isspace((unsigned char)*buf))
48828164Sache				while (*ptr != 0 && !isspace((unsigned char)*ptr))
48928021Sjoerg					ptr++;
49028021Sjoerg			break;
49148550Sobrien
49248550Sobrien		case 'Z':
49348550Sobrien			{
49448550Sobrien			const char *cp;
49548550Sobrien			char *zonestr;
49648550Sobrien
49752860Sache			for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
49848550Sobrien			if (cp - buf) {
49948550Sobrien				zonestr = alloca(cp - buf + 1);
50048550Sobrien				strncpy(zonestr, buf, cp - buf);
50148550Sobrien				zonestr[cp - buf] = '\0';
50248550Sobrien				tzset();
50348550Sobrien				if (0 == strcmp(zonestr, "GMT")) {
50448614Sobrien				    got_GMT = 1;
50548550Sobrien				} else if (0 == strcmp(zonestr, tzname[0])) {
50648614Sobrien				    tm->tm_isdst = 0;
50748550Sobrien				} else if (0 == strcmp(zonestr, tzname[1])) {
50848614Sobrien				    tm->tm_isdst = 1;
50948550Sobrien				} else {
51048614Sobrien				    return 0;
51148550Sobrien				}
51248550Sobrien				buf += cp - buf;
51348550Sobrien			}
51448550Sobrien			}
51548550Sobrien			break;
51628021Sjoerg		}
51728021Sjoerg	}
51848614Sobrien	return (char *)buf;
51948614Sobrien}
52028019Sjoerg
52148614Sobrien
52248614Sobrienchar *
52348614Sobrienstrptime(const char *buf, const char *fmt, struct tm *tm)
52448614Sobrien{
52548614Sobrien	char *ret;
52648614Sobrien
52771579Sdeischen	if (__isthreaded)
52871579Sdeischen		_pthread_mutex_lock(&gotgmt_mutex);
52948614Sobrien
53048614Sobrien	got_GMT = 0;
53148614Sobrien	ret = _strptime(buf, fmt, tm);
53248614Sobrien	if (ret && got_GMT) {
53348550Sobrien		time_t t = timegm(tm);
53471579Sdeischen		localtime_r(&t, tm);
53548614Sobrien		got_GMT = 0;
53648550Sobrien	}
53748614Sobrien
53871579Sdeischen	if (__isthreaded)
53971579Sdeischen		_pthread_mutex_unlock(&gotgmt_mutex);
54048614Sobrien
54148614Sobrien	return ret;
54228019Sjoerg}
543