14297a3b0SGarrett D'Amore /* 2*25f48f67SGordon Ross * Copyright 2011, 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: 85aec55ebSGarrett 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. 115aec55ebSGarrett 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. 285aec55ebSGarrett D'Amore * 295aec55ebSGarrett D'Amore * The views and conclusions contained in the software and documentation 305aec55ebSGarrett D'Amore * are those of the authors and should not be interpreted as representing 315aec55ebSGarrett D'Amore * official policies, either expressed or implied, of Powerdog Industries. 324297a3b0SGarrett D'Amore */ 335aec55ebSGarrett 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 466eaad1d3SGarrett D'Amore #define F_GMT (1 << 0) 476eaad1d3SGarrett D'Amore #define F_ZERO (1 << 1) 486eaad1d3SGarrett D'Amore #define F_RECURSE (1 << 2) 496eaad1d3SGarrett D'Amore 504297a3b0SGarrett D'Amore static char * 516eaad1d3SGarrett D'Amore __strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp) 524297a3b0SGarrett D'Amore { 534297a3b0SGarrett D'Amore char c; 544297a3b0SGarrett D'Amore const char *ptr; 556eaad1d3SGarrett D'Amore int i, len, recurse = 0; 564297a3b0SGarrett D'Amore int Ealternative, Oalternative; 574297a3b0SGarrett D'Amore struct lc_time_T *tptr = __get_current_time_locale(); 584297a3b0SGarrett D'Amore 596eaad1d3SGarrett D'Amore if (*flagsp & F_RECURSE) 606eaad1d3SGarrett D'Amore recurse = 1; 616eaad1d3SGarrett D'Amore *flagsp |= F_RECURSE; 626eaad1d3SGarrett D'Amore 636eaad1d3SGarrett D'Amore if (*flagsp & F_ZERO) 646eaad1d3SGarrett D'Amore (void) memset(tm, 0, sizeof (*tm)); 656eaad1d3SGarrett D'Amore *flagsp &= ~F_ZERO; 666eaad1d3SGarrett D'Amore 674297a3b0SGarrett D'Amore ptr = fmt; 684297a3b0SGarrett D'Amore while (*ptr != 0) { 694297a3b0SGarrett D'Amore if (*buf == 0) 704297a3b0SGarrett D'Amore break; 714297a3b0SGarrett D'Amore 724297a3b0SGarrett D'Amore c = *ptr++; 734297a3b0SGarrett D'Amore 744297a3b0SGarrett D'Amore if (c != '%') { 756eaad1d3SGarrett D'Amore if (isspace(c)) 766eaad1d3SGarrett D'Amore while (isspace(*buf)) 774297a3b0SGarrett D'Amore buf++; 784297a3b0SGarrett D'Amore else if (c != *buf++) 796eaad1d3SGarrett D'Amore return (NULL); 804297a3b0SGarrett D'Amore continue; 814297a3b0SGarrett D'Amore } 824297a3b0SGarrett D'Amore 834297a3b0SGarrett D'Amore Ealternative = 0; 844297a3b0SGarrett D'Amore Oalternative = 0; 854297a3b0SGarrett D'Amore label: 864297a3b0SGarrett D'Amore c = *ptr++; 874297a3b0SGarrett D'Amore switch (c) { 884297a3b0SGarrett D'Amore case 0: 894297a3b0SGarrett D'Amore case '%': 904297a3b0SGarrett D'Amore if (*buf++ != '%') 916eaad1d3SGarrett D'Amore return (NULL); 924297a3b0SGarrett D'Amore break; 934297a3b0SGarrett D'Amore 944297a3b0SGarrett D'Amore case '+': 956eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->date_fmt, tm, flagsp); 966eaad1d3SGarrett D'Amore if (buf == NULL) 976eaad1d3SGarrett D'Amore return (NULL); 984297a3b0SGarrett D'Amore break; 994297a3b0SGarrett D'Amore 1004297a3b0SGarrett D'Amore case 'C': 1016eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 1026eaad1d3SGarrett D'Amore return (NULL); 1034297a3b0SGarrett D'Amore 1044297a3b0SGarrett D'Amore /* XXX This will break for 3-digit centuries. */ 1054297a3b0SGarrett D'Amore len = 2; 1066eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 1074297a3b0SGarrett D'Amore i *= 10; 1084297a3b0SGarrett D'Amore i += *buf - '0'; 1094297a3b0SGarrett D'Amore len--; 1104297a3b0SGarrett D'Amore } 1114297a3b0SGarrett D'Amore if (i < 19) 1126eaad1d3SGarrett D'Amore return (NULL); 1134297a3b0SGarrett D'Amore 1144297a3b0SGarrett D'Amore tm->tm_year = i * 100 - 1900; 1154297a3b0SGarrett D'Amore break; 1164297a3b0SGarrett D'Amore 1174297a3b0SGarrett D'Amore case 'c': 1186eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->c_fmt, tm, flagsp); 1196eaad1d3SGarrett D'Amore if (buf == NULL) 1206eaad1d3SGarrett D'Amore return (NULL); 1214297a3b0SGarrett D'Amore break; 1224297a3b0SGarrett D'Amore 1234297a3b0SGarrett D'Amore case 'D': 1246eaad1d3SGarrett D'Amore buf = __strptime(buf, "%m/%d/%y", tm, flagsp); 1256eaad1d3SGarrett D'Amore if (buf == NULL) 1266eaad1d3SGarrett D'Amore return (NULL); 1274297a3b0SGarrett D'Amore break; 1284297a3b0SGarrett D'Amore 1294297a3b0SGarrett D'Amore case 'E': 1304297a3b0SGarrett D'Amore if (Ealternative || Oalternative) 1314297a3b0SGarrett D'Amore break; 1324297a3b0SGarrett D'Amore Ealternative++; 1334297a3b0SGarrett D'Amore goto label; 1344297a3b0SGarrett D'Amore 1354297a3b0SGarrett D'Amore case 'O': 1364297a3b0SGarrett D'Amore if (Ealternative || Oalternative) 1374297a3b0SGarrett D'Amore break; 1384297a3b0SGarrett D'Amore Oalternative++; 1394297a3b0SGarrett D'Amore goto label; 1404297a3b0SGarrett D'Amore 1414297a3b0SGarrett D'Amore case 'F': 1426eaad1d3SGarrett D'Amore buf = __strptime(buf, "%Y-%m-%d", tm, flagsp); 1436eaad1d3SGarrett D'Amore if (buf == NULL) 1446eaad1d3SGarrett D'Amore return (NULL); 1454297a3b0SGarrett D'Amore break; 1464297a3b0SGarrett D'Amore 1474297a3b0SGarrett D'Amore case 'R': 1486eaad1d3SGarrett D'Amore buf = __strptime(buf, "%H:%M", tm, flagsp); 1496eaad1d3SGarrett D'Amore if (buf == NULL) 1506eaad1d3SGarrett D'Amore return (NULL); 1514297a3b0SGarrett D'Amore break; 1524297a3b0SGarrett D'Amore 1534297a3b0SGarrett D'Amore case 'r': 1546eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp); 1556eaad1d3SGarrett D'Amore if (buf == NULL) 1566eaad1d3SGarrett D'Amore return (NULL); 1574297a3b0SGarrett D'Amore break; 1584297a3b0SGarrett D'Amore 1594297a3b0SGarrett D'Amore case 'T': 1606eaad1d3SGarrett D'Amore buf = __strptime(buf, "%H:%M:%S", tm, flagsp); 1616eaad1d3SGarrett D'Amore if (buf == NULL) 1626eaad1d3SGarrett D'Amore return (NULL); 1634297a3b0SGarrett D'Amore break; 1644297a3b0SGarrett D'Amore 1654297a3b0SGarrett D'Amore case 'X': 1666eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->X_fmt, tm, flagsp); 1676eaad1d3SGarrett D'Amore if (buf == NULL) 1686eaad1d3SGarrett D'Amore return (NULL); 1694297a3b0SGarrett D'Amore break; 1704297a3b0SGarrett D'Amore 1714297a3b0SGarrett D'Amore case 'x': 1726eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->x_fmt, tm, flagsp); 1736eaad1d3SGarrett D'Amore if (buf == NULL) 1746eaad1d3SGarrett D'Amore return (NULL); 1754297a3b0SGarrett D'Amore break; 1764297a3b0SGarrett D'Amore 1774297a3b0SGarrett D'Amore case 'j': 1786eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 1796eaad1d3SGarrett D'Amore return (NULL); 1804297a3b0SGarrett D'Amore 1814297a3b0SGarrett D'Amore len = 3; 1826eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 1834297a3b0SGarrett D'Amore i *= 10; 1844297a3b0SGarrett D'Amore i += *buf - '0'; 1854297a3b0SGarrett D'Amore len--; 1864297a3b0SGarrett D'Amore } 1874297a3b0SGarrett D'Amore if (i < 1 || i > 366) 1886eaad1d3SGarrett D'Amore return (NULL); 1894297a3b0SGarrett D'Amore 1904297a3b0SGarrett D'Amore tm->tm_yday = i - 1; 1914297a3b0SGarrett D'Amore break; 1924297a3b0SGarrett D'Amore 1934297a3b0SGarrett D'Amore case 'M': 1944297a3b0SGarrett D'Amore case 'S': 1956eaad1d3SGarrett D'Amore if (*buf == 0 || isspace(*buf)) 1964297a3b0SGarrett D'Amore break; 1974297a3b0SGarrett D'Amore 1986eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 1996eaad1d3SGarrett D'Amore return (NULL); 2004297a3b0SGarrett D'Amore 2014297a3b0SGarrett D'Amore len = 2; 2026eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 2034297a3b0SGarrett D'Amore i *= 10; 2044297a3b0SGarrett D'Amore i += *buf - '0'; 2054297a3b0SGarrett D'Amore len--; 2064297a3b0SGarrett D'Amore } 2074297a3b0SGarrett D'Amore 2084297a3b0SGarrett D'Amore if (c == 'M') { 2094297a3b0SGarrett D'Amore if (i > 59) 2106eaad1d3SGarrett D'Amore return (NULL); 2114297a3b0SGarrett D'Amore tm->tm_min = i; 2124297a3b0SGarrett D'Amore } else { 2134297a3b0SGarrett D'Amore if (i > 60) 2146eaad1d3SGarrett D'Amore return (NULL); 2154297a3b0SGarrett D'Amore tm->tm_sec = i; 2164297a3b0SGarrett D'Amore } 2174297a3b0SGarrett D'Amore 2186eaad1d3SGarrett D'Amore if (isspace(*buf)) 2196eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 2204297a3b0SGarrett D'Amore ptr++; 2214297a3b0SGarrett D'Amore break; 2224297a3b0SGarrett D'Amore 2234297a3b0SGarrett D'Amore case 'H': 2244297a3b0SGarrett D'Amore case 'I': 2254297a3b0SGarrett D'Amore case 'k': 2264297a3b0SGarrett D'Amore case 'l': 2274297a3b0SGarrett D'Amore /* 2284297a3b0SGarrett D'Amore * Of these, %l is the only specifier explicitly 2294297a3b0SGarrett D'Amore * documented as not being zero-padded. However, 2304297a3b0SGarrett D'Amore * there is no harm in allowing zero-padding. 2314297a3b0SGarrett D'Amore * 2324297a3b0SGarrett D'Amore * XXX The %l specifier may gobble one too many 2334297a3b0SGarrett D'Amore * digits if used incorrectly. 2344297a3b0SGarrett D'Amore */ 2356eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 2366eaad1d3SGarrett D'Amore return (NULL); 2374297a3b0SGarrett D'Amore 2384297a3b0SGarrett D'Amore len = 2; 2396eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 2404297a3b0SGarrett D'Amore i *= 10; 2414297a3b0SGarrett D'Amore i += *buf - '0'; 2424297a3b0SGarrett D'Amore len--; 2434297a3b0SGarrett D'Amore } 2444297a3b0SGarrett D'Amore if (c == 'H' || c == 'k') { 2454297a3b0SGarrett D'Amore if (i > 23) 2466eaad1d3SGarrett D'Amore return (NULL); 2474297a3b0SGarrett D'Amore } else if (i > 12) 2486eaad1d3SGarrett D'Amore return (NULL); 2494297a3b0SGarrett D'Amore 2504297a3b0SGarrett D'Amore tm->tm_hour = i; 2514297a3b0SGarrett D'Amore 2526eaad1d3SGarrett D'Amore if (isspace(*buf)) 2536eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 2544297a3b0SGarrett D'Amore ptr++; 2554297a3b0SGarrett D'Amore break; 2564297a3b0SGarrett D'Amore 2574297a3b0SGarrett D'Amore case 'p': 2584297a3b0SGarrett D'Amore /* 2594297a3b0SGarrett D'Amore * XXX This is bogus if parsed before hour-related 2604297a3b0SGarrett D'Amore * specifiers. 2614297a3b0SGarrett D'Amore */ 2624297a3b0SGarrett D'Amore len = strlen(tptr->am); 2634297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->am, len) == 0) { 2644297a3b0SGarrett D'Amore if (tm->tm_hour > 12) 2656eaad1d3SGarrett D'Amore return (NULL); 2664297a3b0SGarrett D'Amore if (tm->tm_hour == 12) 2674297a3b0SGarrett D'Amore tm->tm_hour = 0; 2684297a3b0SGarrett D'Amore buf += len; 2694297a3b0SGarrett D'Amore break; 2704297a3b0SGarrett D'Amore } 2714297a3b0SGarrett D'Amore 2724297a3b0SGarrett D'Amore len = strlen(tptr->pm); 2734297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->pm, len) == 0) { 2744297a3b0SGarrett D'Amore if (tm->tm_hour > 12) 2756eaad1d3SGarrett D'Amore return (NULL); 2764297a3b0SGarrett D'Amore if (tm->tm_hour != 12) 2774297a3b0SGarrett D'Amore tm->tm_hour += 12; 2784297a3b0SGarrett D'Amore buf += len; 2794297a3b0SGarrett D'Amore break; 2804297a3b0SGarrett D'Amore } 2814297a3b0SGarrett D'Amore 2826eaad1d3SGarrett D'Amore return (NULL); 2834297a3b0SGarrett D'Amore 2844297a3b0SGarrett D'Amore case 'A': 2854297a3b0SGarrett D'Amore case 'a': 2864297a3b0SGarrett D'Amore for (i = 0; i < asizeof(tptr->weekday); i++) { 2874297a3b0SGarrett D'Amore len = strlen(tptr->weekday[i]); 2884297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->weekday[i], len) == 2894297a3b0SGarrett D'Amore 0) 2904297a3b0SGarrett D'Amore break; 2914297a3b0SGarrett D'Amore len = strlen(tptr->wday[i]); 2924297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->wday[i], len) == 0) 2934297a3b0SGarrett D'Amore break; 2944297a3b0SGarrett D'Amore } 2954297a3b0SGarrett D'Amore if (i == asizeof(tptr->weekday)) 2966eaad1d3SGarrett D'Amore return (NULL); 2974297a3b0SGarrett D'Amore 2984297a3b0SGarrett D'Amore tm->tm_wday = i; 2994297a3b0SGarrett D'Amore buf += len; 3004297a3b0SGarrett D'Amore break; 3014297a3b0SGarrett D'Amore 3024297a3b0SGarrett D'Amore case 'U': 3034297a3b0SGarrett D'Amore case 'W': 3044297a3b0SGarrett D'Amore /* 3054297a3b0SGarrett D'Amore * XXX This is bogus, as we can not assume any valid 3064297a3b0SGarrett D'Amore * information present in the tm structure at this 3074297a3b0SGarrett D'Amore * point to calculate a real value, so just check the 3084297a3b0SGarrett D'Amore * range for now. 3094297a3b0SGarrett D'Amore */ 3106eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 3116eaad1d3SGarrett D'Amore return (NULL); 3124297a3b0SGarrett D'Amore 3134297a3b0SGarrett D'Amore len = 2; 3146eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 3154297a3b0SGarrett D'Amore i *= 10; 3164297a3b0SGarrett D'Amore i += *buf - '0'; 3174297a3b0SGarrett D'Amore len--; 3184297a3b0SGarrett D'Amore } 3194297a3b0SGarrett D'Amore if (i > 53) 3206eaad1d3SGarrett D'Amore return (NULL); 3214297a3b0SGarrett D'Amore 3226eaad1d3SGarrett D'Amore if (isspace(*buf)) 3236eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 3244297a3b0SGarrett D'Amore ptr++; 3254297a3b0SGarrett D'Amore break; 3264297a3b0SGarrett D'Amore 3274297a3b0SGarrett D'Amore case 'w': 3286eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 3296eaad1d3SGarrett D'Amore return (NULL); 3304297a3b0SGarrett D'Amore 3314297a3b0SGarrett D'Amore i = *buf - '0'; 3324297a3b0SGarrett D'Amore if (i > 6) 3336eaad1d3SGarrett D'Amore return (NULL); 3344297a3b0SGarrett D'Amore 3354297a3b0SGarrett D'Amore tm->tm_wday = i; 3364297a3b0SGarrett D'Amore 3376eaad1d3SGarrett D'Amore if (isspace(*buf)) 3386eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 3394297a3b0SGarrett D'Amore ptr++; 3404297a3b0SGarrett D'Amore break; 3414297a3b0SGarrett D'Amore 3424297a3b0SGarrett D'Amore case 'e': 343*25f48f67SGordon Ross /* 344*25f48f67SGordon Ross * The %e format has a space before single digits 345*25f48f67SGordon Ross * which we need to skip. 346*25f48f67SGordon Ross */ 347*25f48f67SGordon Ross if (isspace(*buf)) 348*25f48f67SGordon Ross buf++; 349*25f48f67SGordon Ross /* FALLTHROUGH */ 350*25f48f67SGordon Ross case 'd': 3514297a3b0SGarrett D'Amore /* 3524297a3b0SGarrett D'Amore * The %e specifier is explicitly documented as not 3534297a3b0SGarrett D'Amore * being zero-padded but there is no harm in allowing 3544297a3b0SGarrett D'Amore * such padding. 3554297a3b0SGarrett D'Amore * 3564297a3b0SGarrett D'Amore * XXX The %e specifier may gobble one too many 3574297a3b0SGarrett D'Amore * digits if used incorrectly. 3584297a3b0SGarrett D'Amore */ 3596eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 3606eaad1d3SGarrett D'Amore return (NULL); 3614297a3b0SGarrett D'Amore 3624297a3b0SGarrett D'Amore len = 2; 3636eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 3644297a3b0SGarrett D'Amore i *= 10; 3654297a3b0SGarrett D'Amore i += *buf - '0'; 3664297a3b0SGarrett D'Amore len--; 3674297a3b0SGarrett D'Amore } 3684297a3b0SGarrett D'Amore if (i > 31) 3696eaad1d3SGarrett D'Amore return (NULL); 3704297a3b0SGarrett D'Amore 3714297a3b0SGarrett D'Amore tm->tm_mday = i; 3724297a3b0SGarrett D'Amore 3736eaad1d3SGarrett D'Amore if (isspace(*buf)) 3746eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 3754297a3b0SGarrett D'Amore ptr++; 3764297a3b0SGarrett D'Amore break; 3774297a3b0SGarrett D'Amore 3784297a3b0SGarrett D'Amore case 'B': 3794297a3b0SGarrett D'Amore case 'b': 3804297a3b0SGarrett D'Amore case 'h': 3814297a3b0SGarrett D'Amore for (i = 0; i < asizeof(tptr->month); i++) { 3824297a3b0SGarrett D'Amore len = strlen(tptr->month[i]); 3834297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->month[i], len) == 0) 3844297a3b0SGarrett D'Amore break; 3854297a3b0SGarrett D'Amore } 3864297a3b0SGarrett D'Amore /* 3874297a3b0SGarrett D'Amore * Try the abbreviated month name if the full name 3884297a3b0SGarrett D'Amore * wasn't found. 3894297a3b0SGarrett D'Amore */ 3904297a3b0SGarrett D'Amore if (i == asizeof(tptr->month)) { 3914297a3b0SGarrett D'Amore for (i = 0; i < asizeof(tptr->month); i++) { 3924297a3b0SGarrett D'Amore len = strlen(tptr->mon[i]); 3934297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->mon[i], 3944297a3b0SGarrett D'Amore len) == 0) 3954297a3b0SGarrett D'Amore break; 3964297a3b0SGarrett D'Amore } 3974297a3b0SGarrett D'Amore } 3984297a3b0SGarrett D'Amore if (i == asizeof(tptr->month)) 3996eaad1d3SGarrett D'Amore return (NULL); 4004297a3b0SGarrett D'Amore 4014297a3b0SGarrett D'Amore tm->tm_mon = i; 4024297a3b0SGarrett D'Amore buf += len; 4034297a3b0SGarrett D'Amore break; 4044297a3b0SGarrett D'Amore 4054297a3b0SGarrett D'Amore case 'm': 4066eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 4076eaad1d3SGarrett D'Amore return (NULL); 4084297a3b0SGarrett D'Amore 4094297a3b0SGarrett D'Amore len = 2; 4106eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 4114297a3b0SGarrett D'Amore i *= 10; 4124297a3b0SGarrett D'Amore i += *buf - '0'; 4134297a3b0SGarrett D'Amore len--; 4144297a3b0SGarrett D'Amore } 4154297a3b0SGarrett D'Amore if (i < 1 || i > 12) 4166eaad1d3SGarrett D'Amore return (NULL); 4174297a3b0SGarrett D'Amore 4184297a3b0SGarrett D'Amore tm->tm_mon = i - 1; 4194297a3b0SGarrett D'Amore 4206eaad1d3SGarrett D'Amore if (isspace(*buf)) 4216eaad1d3SGarrett D'Amore while (*ptr != NULL && !isspace(*ptr)) 4224297a3b0SGarrett D'Amore ptr++; 4234297a3b0SGarrett D'Amore break; 4244297a3b0SGarrett D'Amore 4256eaad1d3SGarrett D'Amore case 's': 4266eaad1d3SGarrett D'Amore { 4276eaad1d3SGarrett D'Amore char *cp; 4286eaad1d3SGarrett D'Amore int sverrno; 4296eaad1d3SGarrett D'Amore time_t t; 4306eaad1d3SGarrett D'Amore 4316eaad1d3SGarrett D'Amore sverrno = errno; 4326eaad1d3SGarrett D'Amore errno = 0; 4336eaad1d3SGarrett D'Amore t = strtol(buf, &cp, 10); 4346eaad1d3SGarrett D'Amore if (errno == ERANGE) { 4356eaad1d3SGarrett D'Amore errno = sverrno; 4366eaad1d3SGarrett D'Amore return (NULL); 4376eaad1d3SGarrett D'Amore } 4386eaad1d3SGarrett D'Amore errno = sverrno; 4396eaad1d3SGarrett D'Amore buf = cp; 4406eaad1d3SGarrett D'Amore (void) gmtime_r(&t, tm); 4416eaad1d3SGarrett D'Amore *flagsp |= F_GMT; 4426eaad1d3SGarrett D'Amore } 4436eaad1d3SGarrett D'Amore break; 4446eaad1d3SGarrett D'Amore 4454297a3b0SGarrett D'Amore case 'Y': 4464297a3b0SGarrett D'Amore case 'y': 4476eaad1d3SGarrett D'Amore if (*buf == NULL || isspace(*buf)) 4484297a3b0SGarrett D'Amore break; 4494297a3b0SGarrett D'Amore 4506eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 4516eaad1d3SGarrett D'Amore return (NULL); 4524297a3b0SGarrett D'Amore 4534297a3b0SGarrett D'Amore len = (c == 'Y') ? 4 : 2; 4546eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 4554297a3b0SGarrett D'Amore i *= 10; 4564297a3b0SGarrett D'Amore i += *buf - '0'; 4574297a3b0SGarrett D'Amore len--; 4584297a3b0SGarrett D'Amore } 4594297a3b0SGarrett D'Amore if (c == 'Y') 4604297a3b0SGarrett D'Amore i -= 1900; 4614297a3b0SGarrett D'Amore if (c == 'y' && i < 69) 4624297a3b0SGarrett D'Amore i += 100; 4634297a3b0SGarrett D'Amore if (i < 0) 4646eaad1d3SGarrett D'Amore return (NULL); 4654297a3b0SGarrett D'Amore 4664297a3b0SGarrett D'Amore tm->tm_year = i; 4674297a3b0SGarrett D'Amore 4686eaad1d3SGarrett D'Amore if (isspace(*buf)) 4696eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 4704297a3b0SGarrett D'Amore ptr++; 4714297a3b0SGarrett D'Amore break; 4724297a3b0SGarrett D'Amore 4734297a3b0SGarrett D'Amore case 'Z': 4744297a3b0SGarrett D'Amore { 4754297a3b0SGarrett D'Amore const char *cp = buf; 4764297a3b0SGarrett D'Amore char *zonestr; 4774297a3b0SGarrett D'Amore 4786eaad1d3SGarrett D'Amore while (isupper(*cp)) 4794297a3b0SGarrett D'Amore ++cp; 4804297a3b0SGarrett D'Amore if (cp - buf) { 4814297a3b0SGarrett D'Amore zonestr = alloca(cp - buf + 1); 4824297a3b0SGarrett D'Amore (void) strncpy(zonestr, buf, cp - buf); 4834297a3b0SGarrett D'Amore zonestr[cp - buf] = '\0'; 4844297a3b0SGarrett D'Amore tzset(); 4856eaad1d3SGarrett D'Amore if (strcmp(zonestr, "GMT") == 0) { 4866eaad1d3SGarrett D'Amore *flagsp |= F_GMT; 4876eaad1d3SGarrett D'Amore } else if (0 == strcmp(zonestr, tzname[0])) { 4884297a3b0SGarrett D'Amore tm->tm_isdst = 0; 4894297a3b0SGarrett D'Amore } else if (0 == strcmp(zonestr, tzname[1])) { 4904297a3b0SGarrett D'Amore tm->tm_isdst = 1; 4914297a3b0SGarrett D'Amore } else { 4926eaad1d3SGarrett D'Amore return (NULL); 4934297a3b0SGarrett D'Amore } 4944297a3b0SGarrett D'Amore buf += cp - buf; 4954297a3b0SGarrett D'Amore } 4964297a3b0SGarrett D'Amore } 4974297a3b0SGarrett D'Amore break; 4984297a3b0SGarrett D'Amore 4996eaad1d3SGarrett D'Amore case 'z': 5006eaad1d3SGarrett D'Amore { 5016eaad1d3SGarrett D'Amore int sign = 1; 5026eaad1d3SGarrett D'Amore 5036eaad1d3SGarrett D'Amore if (*buf != '+') { 5046eaad1d3SGarrett D'Amore if (*buf == '-') 5056eaad1d3SGarrett D'Amore sign = -1; 5066eaad1d3SGarrett D'Amore else 5076eaad1d3SGarrett D'Amore return (NULL); 5086eaad1d3SGarrett D'Amore } 5096eaad1d3SGarrett D'Amore buf++; 5106eaad1d3SGarrett D'Amore i = 0; 5116eaad1d3SGarrett D'Amore for (len = 4; len > 0; len--) { 5126eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 5136eaad1d3SGarrett D'Amore return (NULL); 5146eaad1d3SGarrett D'Amore i *= 10; 5156eaad1d3SGarrett D'Amore i += *buf - '0'; 5166eaad1d3SGarrett D'Amore buf++; 5176eaad1d3SGarrett D'Amore } 5186eaad1d3SGarrett D'Amore 5196eaad1d3SGarrett D'Amore tm->tm_hour -= sign * (i / 100); 5206eaad1d3SGarrett D'Amore tm->tm_min -= sign * (i % 100); 5216eaad1d3SGarrett D'Amore *flagsp |= F_GMT; 5226eaad1d3SGarrett D'Amore } 5236eaad1d3SGarrett D'Amore break; 5246eaad1d3SGarrett D'Amore } 5256eaad1d3SGarrett D'Amore } 5266eaad1d3SGarrett D'Amore 5276eaad1d3SGarrett D'Amore if (!recurse) { 5286eaad1d3SGarrett D'Amore if (buf && (*flagsp & F_GMT)) { 5296eaad1d3SGarrett D'Amore time_t t = timegm(tm); 5306eaad1d3SGarrett D'Amore (void) localtime_r(&t, tm); 5314297a3b0SGarrett D'Amore } 5324297a3b0SGarrett D'Amore } 5336eaad1d3SGarrett D'Amore 5344297a3b0SGarrett D'Amore return ((char *)buf); 5354297a3b0SGarrett D'Amore } 5364297a3b0SGarrett D'Amore 5374297a3b0SGarrett D'Amore char * 5384297a3b0SGarrett D'Amore strptime(const char *buf, const char *fmt, struct tm *tm) 5394297a3b0SGarrett D'Amore { 5406eaad1d3SGarrett D'Amore int flags = F_ZERO; 5414297a3b0SGarrett D'Amore 5426eaad1d3SGarrett D'Amore return (__strptime(buf, fmt, tm, &flags)); 5434297a3b0SGarrett D'Amore } 5444297a3b0SGarrett D'Amore 5454297a3b0SGarrett D'Amore /* 5464297a3b0SGarrett D'Amore * This is used by Solaris, and is a variant that does not clear the 5474297a3b0SGarrett D'Amore * incoming tm. It is triggered by -D_STRPTIME_DONTZERO. 5484297a3b0SGarrett D'Amore */ 5494297a3b0SGarrett D'Amore char * 5504297a3b0SGarrett D'Amore __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm) 5514297a3b0SGarrett D'Amore { 5526eaad1d3SGarrett D'Amore int flags = 0; 5536eaad1d3SGarrett D'Amore 5546eaad1d3SGarrett D'Amore return (__strptime(buf, fmt, tm, &flags)); 5554297a3b0SGarrett D'Amore } 556