14297a3b0SGarrett D'Amore /*
26b5e5868SGarrett D'Amore  * Copyright 2010, Nexenta Systems, Inc.  All rights reserved.
34297a3b0SGarrett D'Amore  * Copyright (c) 1994 Powerdog Industries.  All rights reserved.
44297a3b0SGarrett D'Amore  *
54297a3b0SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
64297a3b0SGarrett D'Amore  * modification, are permitted provided that the following conditions
74297a3b0SGarrett D'Amore  * are met:
8*5aec55ebSGarrett D'Amore  *
94297a3b0SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright
104297a3b0SGarrett D'Amore  *    notice, this list of conditions and the following disclaimer.
11*5aec55ebSGarrett D'Amore  *
124297a3b0SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright
134297a3b0SGarrett D'Amore  *    notice, this list of conditions and the following disclaimer
144297a3b0SGarrett D'Amore  *    in the documentation and/or other materials provided with the
154297a3b0SGarrett D'Amore  *    distribution.
164297a3b0SGarrett D'Amore  *
174297a3b0SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
184297a3b0SGarrett D'Amore  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194297a3b0SGarrett D'Amore  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
204297a3b0SGarrett D'Amore  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
214297a3b0SGarrett D'Amore  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
224297a3b0SGarrett D'Amore  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
234297a3b0SGarrett D'Amore  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
244297a3b0SGarrett D'Amore  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
254297a3b0SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
264297a3b0SGarrett D'Amore  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
274297a3b0SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*5aec55ebSGarrett D'Amore  *
29*5aec55ebSGarrett D'Amore  * The views and conclusions contained in the software and documentation
30*5aec55ebSGarrett D'Amore  * are those of the authors and should not be interpreted as representing
31*5aec55ebSGarrett D'Amore  * official policies, either expressed or implied, of Powerdog Industries.
324297a3b0SGarrett D'Amore  */
33*5aec55ebSGarrett D'Amore 
344297a3b0SGarrett D'Amore #include "lint.h"
354297a3b0SGarrett D'Amore #include <time.h>
364297a3b0SGarrett D'Amore #include <ctype.h>
374297a3b0SGarrett D'Amore #include <errno.h>
384297a3b0SGarrett D'Amore #include <stdlib.h>
394297a3b0SGarrett D'Amore #include <string.h>
404297a3b0SGarrett D'Amore #include <pthread.h>
414297a3b0SGarrett D'Amore #include <alloca.h>
424297a3b0SGarrett D'Amore #include "timelocal.h"
434297a3b0SGarrett D'Amore 
444297a3b0SGarrett D'Amore #define	asizeof(a)	(sizeof (a) / sizeof ((a)[0]))
454297a3b0SGarrett D'Amore 
464297a3b0SGarrett D'Amore static char *
474297a3b0SGarrett D'Amore __strptime(const char *buf, const char *fmt, struct tm *tm)
484297a3b0SGarrett D'Amore {
494297a3b0SGarrett D'Amore 	char	c;
504297a3b0SGarrett D'Amore 	const char *ptr;
514297a3b0SGarrett D'Amore 	int	i, len;
524297a3b0SGarrett D'Amore 	int Ealternative, Oalternative;
534297a3b0SGarrett D'Amore 	struct lc_time_T *tptr = __get_current_time_locale();
544297a3b0SGarrett D'Amore 
554297a3b0SGarrett D'Amore 	ptr = fmt;
564297a3b0SGarrett D'Amore 	while (*ptr != 0) {
574297a3b0SGarrett D'Amore 		if (*buf == 0)
584297a3b0SGarrett D'Amore 			break;
594297a3b0SGarrett D'Amore 
604297a3b0SGarrett D'Amore 		c = *ptr++;
614297a3b0SGarrett D'Amore 
624297a3b0SGarrett D'Amore 		if (c != '%') {
634297a3b0SGarrett D'Amore 			if (isspace((unsigned char)c))
644297a3b0SGarrett D'Amore 				while (*buf != 0 &&
654297a3b0SGarrett D'Amore 				    isspace((unsigned char)*buf))
664297a3b0SGarrett D'Amore 					buf++;
674297a3b0SGarrett D'Amore 			else if (c != *buf++)
684297a3b0SGarrett D'Amore 				return (0);
694297a3b0SGarrett D'Amore 			continue;
704297a3b0SGarrett D'Amore 		}
714297a3b0SGarrett D'Amore 
724297a3b0SGarrett D'Amore 		Ealternative = 0;
734297a3b0SGarrett D'Amore 		Oalternative = 0;
744297a3b0SGarrett D'Amore label:
754297a3b0SGarrett D'Amore 		c = *ptr++;
764297a3b0SGarrett D'Amore 		switch (c) {
774297a3b0SGarrett D'Amore 		case 0:
784297a3b0SGarrett D'Amore 		case '%':
794297a3b0SGarrett D'Amore 			if (*buf++ != '%')
804297a3b0SGarrett D'Amore 				return (0);
814297a3b0SGarrett D'Amore 			break;
824297a3b0SGarrett D'Amore 
834297a3b0SGarrett D'Amore 		case '+':
844297a3b0SGarrett D'Amore 			buf = __strptime(buf, tptr->date_fmt, tm);
854297a3b0SGarrett D'Amore 			if (buf == 0)
864297a3b0SGarrett D'Amore 				return (0);
874297a3b0SGarrett D'Amore 			break;
884297a3b0SGarrett D'Amore 
894297a3b0SGarrett D'Amore 		case 'C':
904297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
914297a3b0SGarrett D'Amore 				return (0);
924297a3b0SGarrett D'Amore 
934297a3b0SGarrett D'Amore 			/* XXX This will break for 3-digit centuries. */
944297a3b0SGarrett D'Amore 			len = 2;
954297a3b0SGarrett D'Amore 			for (i = 0;
964297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
974297a3b0SGarrett D'Amore 			    buf++) {
984297a3b0SGarrett D'Amore 				i *= 10;
994297a3b0SGarrett D'Amore 				i += *buf - '0';
1004297a3b0SGarrett D'Amore 				len--;
1014297a3b0SGarrett D'Amore 			}
1024297a3b0SGarrett D'Amore 			if (i < 19)
1034297a3b0SGarrett D'Amore 				return (0);
1044297a3b0SGarrett D'Amore 
1054297a3b0SGarrett D'Amore 			tm->tm_year = i * 100 - 1900;
1064297a3b0SGarrett D'Amore 			break;
1074297a3b0SGarrett D'Amore 
1084297a3b0SGarrett D'Amore 		case 'c':
1094297a3b0SGarrett D'Amore 			buf = __strptime(buf, tptr->c_fmt, tm);
1104297a3b0SGarrett D'Amore 			if (buf == 0)
1114297a3b0SGarrett D'Amore 				return (0);
1124297a3b0SGarrett D'Amore 			break;
1134297a3b0SGarrett D'Amore 
1144297a3b0SGarrett D'Amore 		case 'D':
1154297a3b0SGarrett D'Amore 			buf = __strptime(buf, "%m/%d/%y", tm);
1164297a3b0SGarrett D'Amore 			if (buf == 0)
1174297a3b0SGarrett D'Amore 				return (0);
1184297a3b0SGarrett D'Amore 			break;
1194297a3b0SGarrett D'Amore 
1204297a3b0SGarrett D'Amore 		case 'E':
1214297a3b0SGarrett D'Amore 			if (Ealternative || Oalternative)
1224297a3b0SGarrett D'Amore 				break;
1234297a3b0SGarrett D'Amore 			Ealternative++;
1244297a3b0SGarrett D'Amore 			goto label;
1254297a3b0SGarrett D'Amore 
1264297a3b0SGarrett D'Amore 		case 'O':
1274297a3b0SGarrett D'Amore 			if (Ealternative || Oalternative)
1284297a3b0SGarrett D'Amore 				break;
1294297a3b0SGarrett D'Amore 			Oalternative++;
1304297a3b0SGarrett D'Amore 			goto label;
1314297a3b0SGarrett D'Amore 
1324297a3b0SGarrett D'Amore 		case 'F':
1334297a3b0SGarrett D'Amore 			buf = __strptime(buf, "%Y-%m-%d", tm);
1344297a3b0SGarrett D'Amore 			if (buf == 0)
1354297a3b0SGarrett D'Amore 				return (0);
1364297a3b0SGarrett D'Amore 			break;
1374297a3b0SGarrett D'Amore 
1384297a3b0SGarrett D'Amore 		case 'R':
1394297a3b0SGarrett D'Amore 			buf = __strptime(buf, "%H:%M", tm);
1404297a3b0SGarrett D'Amore 			if (buf == 0)
1414297a3b0SGarrett D'Amore 				return (0);
1424297a3b0SGarrett D'Amore 			break;
1434297a3b0SGarrett D'Amore 
1444297a3b0SGarrett D'Amore 		case 'r':
1454297a3b0SGarrett D'Amore 			buf = __strptime(buf, tptr->ampm_fmt, tm);
1464297a3b0SGarrett D'Amore 			if (buf == 0)
1474297a3b0SGarrett D'Amore 				return (0);
1484297a3b0SGarrett D'Amore 			break;
1494297a3b0SGarrett D'Amore 
1504297a3b0SGarrett D'Amore 		case 'T':
1514297a3b0SGarrett D'Amore 			buf = __strptime(buf, "%H:%M:%S", tm);
1524297a3b0SGarrett D'Amore 			if (buf == 0)
1534297a3b0SGarrett D'Amore 				return (0);
1544297a3b0SGarrett D'Amore 			break;
1554297a3b0SGarrett D'Amore 
1564297a3b0SGarrett D'Amore 		case 'X':
1574297a3b0SGarrett D'Amore 			buf = __strptime(buf, tptr->X_fmt, tm);
1584297a3b0SGarrett D'Amore 			if (buf == 0)
1594297a3b0SGarrett D'Amore 				return (0);
1604297a3b0SGarrett D'Amore 			break;
1614297a3b0SGarrett D'Amore 
1624297a3b0SGarrett D'Amore 		case 'x':
1634297a3b0SGarrett D'Amore 			buf = __strptime(buf, tptr->x_fmt, tm);
1644297a3b0SGarrett D'Amore 			if (buf == 0)
1654297a3b0SGarrett D'Amore 				return (0);
1664297a3b0SGarrett D'Amore 			break;
1674297a3b0SGarrett D'Amore 
1684297a3b0SGarrett D'Amore 		case 'j':
1694297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
1704297a3b0SGarrett D'Amore 				return (0);
1714297a3b0SGarrett D'Amore 
1724297a3b0SGarrett D'Amore 			len = 3;
1734297a3b0SGarrett D'Amore 			for (i = 0;
1744297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
1754297a3b0SGarrett D'Amore 			    buf++) {
1764297a3b0SGarrett D'Amore 				i *= 10;
1774297a3b0SGarrett D'Amore 				i += *buf - '0';
1784297a3b0SGarrett D'Amore 				len--;
1794297a3b0SGarrett D'Amore 			}
1804297a3b0SGarrett D'Amore 			if (i < 1 || i > 366)
1814297a3b0SGarrett D'Amore 				return (0);
1824297a3b0SGarrett D'Amore 
1834297a3b0SGarrett D'Amore 			tm->tm_yday = i - 1;
1844297a3b0SGarrett D'Amore 			break;
1854297a3b0SGarrett D'Amore 
1864297a3b0SGarrett D'Amore 		case 'M':
1874297a3b0SGarrett D'Amore 		case 'S':
1884297a3b0SGarrett D'Amore 			if (*buf == 0 || isspace((unsigned char)*buf))
1894297a3b0SGarrett D'Amore 				break;
1904297a3b0SGarrett D'Amore 
1914297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
1924297a3b0SGarrett D'Amore 				return (0);
1934297a3b0SGarrett D'Amore 
1944297a3b0SGarrett D'Amore 			len = 2;
1954297a3b0SGarrett D'Amore 			for (i = 0;
1964297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
1974297a3b0SGarrett D'Amore 			    buf++) {
1984297a3b0SGarrett D'Amore 				i *= 10;
1994297a3b0SGarrett D'Amore 				i += *buf - '0';
2004297a3b0SGarrett D'Amore 				len--;
2014297a3b0SGarrett D'Amore 			}
2024297a3b0SGarrett D'Amore 
2034297a3b0SGarrett D'Amore 			if (c == 'M') {
2044297a3b0SGarrett D'Amore 				if (i > 59)
2054297a3b0SGarrett D'Amore 					return (0);
2064297a3b0SGarrett D'Amore 				tm->tm_min = i;
2074297a3b0SGarrett D'Amore 			} else {
2084297a3b0SGarrett D'Amore 				if (i > 60)
2094297a3b0SGarrett D'Amore 					return (0);
2104297a3b0SGarrett D'Amore 				tm->tm_sec = i;
2114297a3b0SGarrett D'Amore 			}
2124297a3b0SGarrett D'Amore 
2134297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
2144297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
2154297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
2164297a3b0SGarrett D'Amore 					ptr++;
2174297a3b0SGarrett D'Amore 			break;
2184297a3b0SGarrett D'Amore 
2194297a3b0SGarrett D'Amore 		case 'H':
2204297a3b0SGarrett D'Amore 		case 'I':
2214297a3b0SGarrett D'Amore 		case 'k':
2224297a3b0SGarrett D'Amore 		case 'l':
2234297a3b0SGarrett D'Amore 			/*
2244297a3b0SGarrett D'Amore 			 * Of these, %l is the only specifier explicitly
2254297a3b0SGarrett D'Amore 			 * documented as not being zero-padded.  However,
2264297a3b0SGarrett D'Amore 			 * there is no harm in allowing zero-padding.
2274297a3b0SGarrett D'Amore 			 *
2284297a3b0SGarrett D'Amore 			 * XXX The %l specifier may gobble one too many
2294297a3b0SGarrett D'Amore 			 * digits if used incorrectly.
2304297a3b0SGarrett D'Amore 			 */
2314297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
2324297a3b0SGarrett D'Amore 				return (0);
2334297a3b0SGarrett D'Amore 
2344297a3b0SGarrett D'Amore 			len = 2;
2354297a3b0SGarrett D'Amore 			for (i = 0;
2364297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
2374297a3b0SGarrett D'Amore 			    buf++) {
2384297a3b0SGarrett D'Amore 				i *= 10;
2394297a3b0SGarrett D'Amore 				i += *buf - '0';
2404297a3b0SGarrett D'Amore 				len--;
2414297a3b0SGarrett D'Amore 			}
2424297a3b0SGarrett D'Amore 			if (c == 'H' || c == 'k') {
2434297a3b0SGarrett D'Amore 				if (i > 23)
2444297a3b0SGarrett D'Amore 					return (0);
2454297a3b0SGarrett D'Amore 			} else if (i > 12)
2464297a3b0SGarrett D'Amore 				return (0);
2474297a3b0SGarrett D'Amore 
2484297a3b0SGarrett D'Amore 			tm->tm_hour = i;
2494297a3b0SGarrett D'Amore 
2504297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
2514297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
2524297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
2534297a3b0SGarrett D'Amore 					ptr++;
2544297a3b0SGarrett D'Amore 			break;
2554297a3b0SGarrett D'Amore 
2564297a3b0SGarrett D'Amore 		case 'p':
2574297a3b0SGarrett D'Amore 			/*
2584297a3b0SGarrett D'Amore 			 * XXX This is bogus if parsed before hour-related
2594297a3b0SGarrett D'Amore 			 * specifiers.
2604297a3b0SGarrett D'Amore 			 */
2614297a3b0SGarrett D'Amore 			len = strlen(tptr->am);
2624297a3b0SGarrett D'Amore 			if (strncasecmp(buf, tptr->am, len) == 0) {
2634297a3b0SGarrett D'Amore 				if (tm->tm_hour > 12)
2644297a3b0SGarrett D'Amore 					return (0);
2654297a3b0SGarrett D'Amore 				if (tm->tm_hour == 12)
2664297a3b0SGarrett D'Amore 					tm->tm_hour = 0;
2674297a3b0SGarrett D'Amore 				buf += len;
2684297a3b0SGarrett D'Amore 				break;
2694297a3b0SGarrett D'Amore 			}
2704297a3b0SGarrett D'Amore 
2714297a3b0SGarrett D'Amore 			len = strlen(tptr->pm);
2724297a3b0SGarrett D'Amore 			if (strncasecmp(buf, tptr->pm, len) == 0) {
2734297a3b0SGarrett D'Amore 				if (tm->tm_hour > 12)
2744297a3b0SGarrett D'Amore 					return (0);
2754297a3b0SGarrett D'Amore 				if (tm->tm_hour != 12)
2764297a3b0SGarrett D'Amore 					tm->tm_hour += 12;
2774297a3b0SGarrett D'Amore 				buf += len;
2784297a3b0SGarrett D'Amore 				break;
2794297a3b0SGarrett D'Amore 			}
2804297a3b0SGarrett D'Amore 
2814297a3b0SGarrett D'Amore 			return (0);
2824297a3b0SGarrett D'Amore 
2834297a3b0SGarrett D'Amore 		case 'A':
2844297a3b0SGarrett D'Amore 		case 'a':
2854297a3b0SGarrett D'Amore 			for (i = 0; i < asizeof(tptr->weekday); i++) {
2864297a3b0SGarrett D'Amore 				len = strlen(tptr->weekday[i]);
2874297a3b0SGarrett D'Amore 				if (strncasecmp(buf, tptr->weekday[i], len) ==
2884297a3b0SGarrett D'Amore 				    0)
2894297a3b0SGarrett D'Amore 					break;
2904297a3b0SGarrett D'Amore 				len = strlen(tptr->wday[i]);
2914297a3b0SGarrett D'Amore 				if (strncasecmp(buf, tptr->wday[i], len) == 0)
2924297a3b0SGarrett D'Amore 					break;
2934297a3b0SGarrett D'Amore 			}
2944297a3b0SGarrett D'Amore 			if (i == asizeof(tptr->weekday))
2954297a3b0SGarrett D'Amore 				return (0);
2964297a3b0SGarrett D'Amore 
2974297a3b0SGarrett D'Amore 			tm->tm_wday = i;
2984297a3b0SGarrett D'Amore 			buf += len;
2994297a3b0SGarrett D'Amore 			break;
3004297a3b0SGarrett D'Amore 
3014297a3b0SGarrett D'Amore 		case 'U':
3024297a3b0SGarrett D'Amore 		case 'W':
3034297a3b0SGarrett D'Amore 			/*
3044297a3b0SGarrett D'Amore 			 * XXX This is bogus, as we can not assume any valid
3054297a3b0SGarrett D'Amore 			 * information present in the tm structure at this
3064297a3b0SGarrett D'Amore 			 * point to calculate a real value, so just check the
3074297a3b0SGarrett D'Amore 			 * range for now.
3084297a3b0SGarrett D'Amore 			 */
3094297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
3104297a3b0SGarrett D'Amore 				return (0);
3114297a3b0SGarrett D'Amore 
3124297a3b0SGarrett D'Amore 			len = 2;
3134297a3b0SGarrett D'Amore 			for (i = 0;
3144297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
3154297a3b0SGarrett D'Amore 			    buf++) {
3164297a3b0SGarrett D'Amore 				i *= 10;
3174297a3b0SGarrett D'Amore 				i += *buf - '0';
3184297a3b0SGarrett D'Amore 				len--;
3194297a3b0SGarrett D'Amore 			}
3204297a3b0SGarrett D'Amore 			if (i > 53)
3214297a3b0SGarrett D'Amore 				return (0);
3224297a3b0SGarrett D'Amore 
3234297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
3244297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
3254297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
3264297a3b0SGarrett D'Amore 					ptr++;
3274297a3b0SGarrett D'Amore 			break;
3284297a3b0SGarrett D'Amore 
3294297a3b0SGarrett D'Amore 		case 'w':
3304297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
3314297a3b0SGarrett D'Amore 				return (0);
3324297a3b0SGarrett D'Amore 
3334297a3b0SGarrett D'Amore 			i = *buf - '0';
3344297a3b0SGarrett D'Amore 			if (i > 6)
3354297a3b0SGarrett D'Amore 				return (0);
3364297a3b0SGarrett D'Amore 
3374297a3b0SGarrett D'Amore 			tm->tm_wday = i;
3384297a3b0SGarrett D'Amore 
3394297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
3404297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
3414297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
3424297a3b0SGarrett D'Amore 					ptr++;
3434297a3b0SGarrett D'Amore 			break;
3444297a3b0SGarrett D'Amore 
3454297a3b0SGarrett D'Amore 		case 'd':
3464297a3b0SGarrett D'Amore 		case 'e':
3474297a3b0SGarrett D'Amore 			/*
3484297a3b0SGarrett D'Amore 			 * The %e specifier is explicitly documented as not
3494297a3b0SGarrett D'Amore 			 * being zero-padded but there is no harm in allowing
3504297a3b0SGarrett D'Amore 			 * such padding.
3514297a3b0SGarrett D'Amore 			 *
3524297a3b0SGarrett D'Amore 			 * XXX The %e specifier may gobble one too many
3534297a3b0SGarrett D'Amore 			 * digits if used incorrectly.
3544297a3b0SGarrett D'Amore 			 */
3554297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
3564297a3b0SGarrett D'Amore 				return (0);
3574297a3b0SGarrett D'Amore 
3584297a3b0SGarrett D'Amore 			len = 2;
3594297a3b0SGarrett D'Amore 			for (i = 0;
3604297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
3614297a3b0SGarrett D'Amore 			    buf++) {
3624297a3b0SGarrett D'Amore 				i *= 10;
3634297a3b0SGarrett D'Amore 				i += *buf - '0';
3644297a3b0SGarrett D'Amore 				len--;
3654297a3b0SGarrett D'Amore 			}
3664297a3b0SGarrett D'Amore 			if (i > 31)
3674297a3b0SGarrett D'Amore 				return (0);
3684297a3b0SGarrett D'Amore 
3694297a3b0SGarrett D'Amore 			tm->tm_mday = i;
3704297a3b0SGarrett D'Amore 
3714297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
3724297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
3734297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
3744297a3b0SGarrett D'Amore 					ptr++;
3754297a3b0SGarrett D'Amore 			break;
3764297a3b0SGarrett D'Amore 
3774297a3b0SGarrett D'Amore 		case 'B':
3784297a3b0SGarrett D'Amore 		case 'b':
3794297a3b0SGarrett D'Amore 		case 'h':
3804297a3b0SGarrett D'Amore 			for (i = 0; i < asizeof(tptr->month); i++) {
3814297a3b0SGarrett D'Amore 				len = strlen(tptr->month[i]);
3824297a3b0SGarrett D'Amore 				if (strncasecmp(buf, tptr->month[i], len) == 0)
3834297a3b0SGarrett D'Amore 					break;
3844297a3b0SGarrett D'Amore 			}
3854297a3b0SGarrett D'Amore 			/*
3864297a3b0SGarrett D'Amore 			 * Try the abbreviated month name if the full name
3874297a3b0SGarrett D'Amore 			 * wasn't found.
3884297a3b0SGarrett D'Amore 			 */
3894297a3b0SGarrett D'Amore 			if (i == asizeof(tptr->month)) {
3904297a3b0SGarrett D'Amore 				for (i = 0; i < asizeof(tptr->month); i++) {
3914297a3b0SGarrett D'Amore 					len = strlen(tptr->mon[i]);
3924297a3b0SGarrett D'Amore 					if (strncasecmp(buf, tptr->mon[i],
3934297a3b0SGarrett D'Amore 					    len) == 0)
3944297a3b0SGarrett D'Amore 						break;
3954297a3b0SGarrett D'Amore 				}
3964297a3b0SGarrett D'Amore 			}
3974297a3b0SGarrett D'Amore 			if (i == asizeof(tptr->month))
3984297a3b0SGarrett D'Amore 				return (0);
3994297a3b0SGarrett D'Amore 
4004297a3b0SGarrett D'Amore 			tm->tm_mon = i;
4014297a3b0SGarrett D'Amore 			buf += len;
4024297a3b0SGarrett D'Amore 			break;
4034297a3b0SGarrett D'Amore 
4044297a3b0SGarrett D'Amore 		case 'm':
4054297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
4064297a3b0SGarrett D'Amore 				return (0);
4074297a3b0SGarrett D'Amore 
4084297a3b0SGarrett D'Amore 			len = 2;
4094297a3b0SGarrett D'Amore 			for (i = 0;
4104297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
4114297a3b0SGarrett D'Amore 			    buf++) {
4124297a3b0SGarrett D'Amore 				i *= 10;
4134297a3b0SGarrett D'Amore 				i += *buf - '0';
4144297a3b0SGarrett D'Amore 				len--;
4154297a3b0SGarrett D'Amore 			}
4164297a3b0SGarrett D'Amore 			if (i < 1 || i > 12)
4174297a3b0SGarrett D'Amore 				return (0);
4184297a3b0SGarrett D'Amore 
4194297a3b0SGarrett D'Amore 			tm->tm_mon = i - 1;
4204297a3b0SGarrett D'Amore 
4214297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
4224297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
4234297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
4244297a3b0SGarrett D'Amore 					ptr++;
4254297a3b0SGarrett D'Amore 			break;
4264297a3b0SGarrett D'Amore 
4274297a3b0SGarrett D'Amore 		case 'Y':
4284297a3b0SGarrett D'Amore 		case 'y':
4294297a3b0SGarrett D'Amore 			if (*buf == 0 || isspace((unsigned char)*buf))
4304297a3b0SGarrett D'Amore 				break;
4314297a3b0SGarrett D'Amore 
4324297a3b0SGarrett D'Amore 			if (!isdigit((unsigned char)*buf))
4334297a3b0SGarrett D'Amore 				return (0);
4344297a3b0SGarrett D'Amore 
4354297a3b0SGarrett D'Amore 			len = (c == 'Y') ? 4 : 2;
4364297a3b0SGarrett D'Amore 			for (i = 0;
4374297a3b0SGarrett D'Amore 			    len && isdigit((unsigned char)*buf);
4384297a3b0SGarrett D'Amore 			    buf++) {
4394297a3b0SGarrett D'Amore 				i *= 10;
4404297a3b0SGarrett D'Amore 				i += *buf - '0';
4414297a3b0SGarrett D'Amore 				len--;
4424297a3b0SGarrett D'Amore 			}
4434297a3b0SGarrett D'Amore 			if (c == 'Y')
4444297a3b0SGarrett D'Amore 				i -= 1900;
4454297a3b0SGarrett D'Amore 			if (c == 'y' && i < 69)
4464297a3b0SGarrett D'Amore 				i += 100;
4474297a3b0SGarrett D'Amore 			if (i < 0)
4484297a3b0SGarrett D'Amore 				return (0);
4494297a3b0SGarrett D'Amore 
4504297a3b0SGarrett D'Amore 			tm->tm_year = i;
4514297a3b0SGarrett D'Amore 
4524297a3b0SGarrett D'Amore 			if (*buf != 0 && isspace((unsigned char)*buf))
4534297a3b0SGarrett D'Amore 				while (*ptr != 0 &&
4544297a3b0SGarrett D'Amore 				    !isspace((unsigned char)*ptr))
4554297a3b0SGarrett D'Amore 					ptr++;
4564297a3b0SGarrett D'Amore 			break;
4574297a3b0SGarrett D'Amore 
4584297a3b0SGarrett D'Amore 		case 'Z':
4594297a3b0SGarrett D'Amore 			{
4604297a3b0SGarrett D'Amore 			const char *cp = buf;
4614297a3b0SGarrett D'Amore 			char *zonestr;
4624297a3b0SGarrett D'Amore 
4634297a3b0SGarrett D'Amore 			while (isupper((unsigned char)*cp))
4644297a3b0SGarrett D'Amore 				++cp;
4654297a3b0SGarrett D'Amore 			if (cp - buf) {
4664297a3b0SGarrett D'Amore 				zonestr = alloca(cp - buf + 1);
4674297a3b0SGarrett D'Amore 				(void) strncpy(zonestr, buf, cp - buf);
4684297a3b0SGarrett D'Amore 				zonestr[cp - buf] = '\0';
4694297a3b0SGarrett D'Amore 				tzset();
4704297a3b0SGarrett D'Amore 				/*
4714297a3b0SGarrett D'Amore 				 * Once upon a time this supported "GMT",
4724297a3b0SGarrett D'Amore 				 * for GMT, but we removed this as Solaris
4734297a3b0SGarrett D'Amore 				 * doesn't have it, and we lack the needed
4744297a3b0SGarrett D'Amore 				 * timegm function.
4754297a3b0SGarrett D'Amore 				 */
4764297a3b0SGarrett D'Amore 				if (0 == strcmp(zonestr, tzname[0])) {
4774297a3b0SGarrett D'Amore 					tm->tm_isdst = 0;
4784297a3b0SGarrett D'Amore 				} else if (0 == strcmp(zonestr, tzname[1])) {
4794297a3b0SGarrett D'Amore 					tm->tm_isdst = 1;
4804297a3b0SGarrett D'Amore 				} else {
4814297a3b0SGarrett D'Amore 					return (0);
4824297a3b0SGarrett D'Amore 				}
4834297a3b0SGarrett D'Amore 				buf += cp - buf;
4844297a3b0SGarrett D'Amore 			}
4854297a3b0SGarrett D'Amore 			}
4864297a3b0SGarrett D'Amore 			break;
4874297a3b0SGarrett D'Amore 
4884297a3b0SGarrett D'Amore 		/*
4894297a3b0SGarrett D'Amore 		 * Note that there used to be support %z and %s, but these
4904297a3b0SGarrett D'Amore 		 * are not supported by Solaris, so we have removed them.
4914297a3b0SGarrett D'Amore 		 * They would have required timegm() which is missing.
4924297a3b0SGarrett D'Amore 		 */
4934297a3b0SGarrett D'Amore 		}
4944297a3b0SGarrett D'Amore 	}
4954297a3b0SGarrett D'Amore 	return ((char *)buf);
4964297a3b0SGarrett D'Amore }
4974297a3b0SGarrett D'Amore 
4984297a3b0SGarrett D'Amore char *
4994297a3b0SGarrett D'Amore strptime(const char *buf, const char *fmt, struct tm *tm)
5004297a3b0SGarrett D'Amore {
5014297a3b0SGarrett D'Amore 	/* Legacy Solaris strptime clears the incoming tm structure. */
5024297a3b0SGarrett D'Amore 	(void) memset(tm, 0, sizeof (*tm));
5034297a3b0SGarrett D'Amore 
5044297a3b0SGarrett D'Amore 	return (__strptime(buf, fmt, tm));
5054297a3b0SGarrett D'Amore }
5064297a3b0SGarrett D'Amore 
5074297a3b0SGarrett D'Amore /*
5084297a3b0SGarrett D'Amore  * This is used by Solaris, and is a variant that does not clear the
5094297a3b0SGarrett D'Amore  * incoming tm.  It is triggered by -D_STRPTIME_DONTZERO.
5104297a3b0SGarrett D'Amore  */
5114297a3b0SGarrett D'Amore char *
5124297a3b0SGarrett D'Amore __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
5134297a3b0SGarrett D'Amore {
5144297a3b0SGarrett D'Amore 	return (__strptime(buf, fmt, tm));
5154297a3b0SGarrett D'Amore }
516