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: 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 46*6eaad1d3SGarrett D'Amore #define F_GMT (1 << 0) 47*6eaad1d3SGarrett D'Amore #define F_ZERO (1 << 1) 48*6eaad1d3SGarrett D'Amore #define F_RECURSE (1 << 2) 49*6eaad1d3SGarrett D'Amore 504297a3b0SGarrett D'Amore static char * 51*6eaad1d3SGarrett 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; 55*6eaad1d3SGarrett 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 59*6eaad1d3SGarrett D'Amore if (*flagsp & F_RECURSE) 60*6eaad1d3SGarrett D'Amore recurse = 1; 61*6eaad1d3SGarrett D'Amore *flagsp |= F_RECURSE; 62*6eaad1d3SGarrett D'Amore 63*6eaad1d3SGarrett D'Amore if (*flagsp & F_ZERO) 64*6eaad1d3SGarrett D'Amore (void) memset(tm, 0, sizeof (*tm)); 65*6eaad1d3SGarrett D'Amore *flagsp &= ~F_ZERO; 66*6eaad1d3SGarrett 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 != '%') { 75*6eaad1d3SGarrett D'Amore if (isspace(c)) 76*6eaad1d3SGarrett D'Amore while (isspace(*buf)) 774297a3b0SGarrett D'Amore buf++; 784297a3b0SGarrett D'Amore else if (c != *buf++) 79*6eaad1d3SGarrett 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++ != '%') 91*6eaad1d3SGarrett D'Amore return (NULL); 924297a3b0SGarrett D'Amore break; 934297a3b0SGarrett D'Amore 944297a3b0SGarrett D'Amore case '+': 95*6eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->date_fmt, tm, flagsp); 96*6eaad1d3SGarrett D'Amore if (buf == NULL) 97*6eaad1d3SGarrett D'Amore return (NULL); 984297a3b0SGarrett D'Amore break; 994297a3b0SGarrett D'Amore 1004297a3b0SGarrett D'Amore case 'C': 101*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 102*6eaad1d3SGarrett D'Amore return (NULL); 1034297a3b0SGarrett D'Amore 1044297a3b0SGarrett D'Amore /* XXX This will break for 3-digit centuries. */ 1054297a3b0SGarrett D'Amore len = 2; 106*6eaad1d3SGarrett 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) 112*6eaad1d3SGarrett 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': 118*6eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->c_fmt, tm, flagsp); 119*6eaad1d3SGarrett D'Amore if (buf == NULL) 120*6eaad1d3SGarrett D'Amore return (NULL); 1214297a3b0SGarrett D'Amore break; 1224297a3b0SGarrett D'Amore 1234297a3b0SGarrett D'Amore case 'D': 124*6eaad1d3SGarrett D'Amore buf = __strptime(buf, "%m/%d/%y", tm, flagsp); 125*6eaad1d3SGarrett D'Amore if (buf == NULL) 126*6eaad1d3SGarrett 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': 142*6eaad1d3SGarrett D'Amore buf = __strptime(buf, "%Y-%m-%d", tm, flagsp); 143*6eaad1d3SGarrett D'Amore if (buf == NULL) 144*6eaad1d3SGarrett D'Amore return (NULL); 1454297a3b0SGarrett D'Amore break; 1464297a3b0SGarrett D'Amore 1474297a3b0SGarrett D'Amore case 'R': 148*6eaad1d3SGarrett D'Amore buf = __strptime(buf, "%H:%M", tm, flagsp); 149*6eaad1d3SGarrett D'Amore if (buf == NULL) 150*6eaad1d3SGarrett D'Amore return (NULL); 1514297a3b0SGarrett D'Amore break; 1524297a3b0SGarrett D'Amore 1534297a3b0SGarrett D'Amore case 'r': 154*6eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp); 155*6eaad1d3SGarrett D'Amore if (buf == NULL) 156*6eaad1d3SGarrett D'Amore return (NULL); 1574297a3b0SGarrett D'Amore break; 1584297a3b0SGarrett D'Amore 1594297a3b0SGarrett D'Amore case 'T': 160*6eaad1d3SGarrett D'Amore buf = __strptime(buf, "%H:%M:%S", tm, flagsp); 161*6eaad1d3SGarrett D'Amore if (buf == NULL) 162*6eaad1d3SGarrett D'Amore return (NULL); 1634297a3b0SGarrett D'Amore break; 1644297a3b0SGarrett D'Amore 1654297a3b0SGarrett D'Amore case 'X': 166*6eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->X_fmt, tm, flagsp); 167*6eaad1d3SGarrett D'Amore if (buf == NULL) 168*6eaad1d3SGarrett D'Amore return (NULL); 1694297a3b0SGarrett D'Amore break; 1704297a3b0SGarrett D'Amore 1714297a3b0SGarrett D'Amore case 'x': 172*6eaad1d3SGarrett D'Amore buf = __strptime(buf, tptr->x_fmt, tm, flagsp); 173*6eaad1d3SGarrett D'Amore if (buf == NULL) 174*6eaad1d3SGarrett D'Amore return (NULL); 1754297a3b0SGarrett D'Amore break; 1764297a3b0SGarrett D'Amore 1774297a3b0SGarrett D'Amore case 'j': 178*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 179*6eaad1d3SGarrett D'Amore return (NULL); 1804297a3b0SGarrett D'Amore 1814297a3b0SGarrett D'Amore len = 3; 182*6eaad1d3SGarrett 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) 188*6eaad1d3SGarrett 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': 195*6eaad1d3SGarrett D'Amore if (*buf == 0 || isspace(*buf)) 1964297a3b0SGarrett D'Amore break; 1974297a3b0SGarrett D'Amore 198*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 199*6eaad1d3SGarrett D'Amore return (NULL); 2004297a3b0SGarrett D'Amore 2014297a3b0SGarrett D'Amore len = 2; 202*6eaad1d3SGarrett 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) 210*6eaad1d3SGarrett D'Amore return (NULL); 2114297a3b0SGarrett D'Amore tm->tm_min = i; 2124297a3b0SGarrett D'Amore } else { 2134297a3b0SGarrett D'Amore if (i > 60) 214*6eaad1d3SGarrett D'Amore return (NULL); 2154297a3b0SGarrett D'Amore tm->tm_sec = i; 2164297a3b0SGarrett D'Amore } 2174297a3b0SGarrett D'Amore 218*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 219*6eaad1d3SGarrett 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 */ 235*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 236*6eaad1d3SGarrett D'Amore return (NULL); 2374297a3b0SGarrett D'Amore 2384297a3b0SGarrett D'Amore len = 2; 239*6eaad1d3SGarrett 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) 246*6eaad1d3SGarrett D'Amore return (NULL); 2474297a3b0SGarrett D'Amore } else if (i > 12) 248*6eaad1d3SGarrett D'Amore return (NULL); 2494297a3b0SGarrett D'Amore 2504297a3b0SGarrett D'Amore tm->tm_hour = i; 2514297a3b0SGarrett D'Amore 252*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 253*6eaad1d3SGarrett 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) 265*6eaad1d3SGarrett 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) 275*6eaad1d3SGarrett 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 282*6eaad1d3SGarrett 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)) 296*6eaad1d3SGarrett 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 */ 310*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 311*6eaad1d3SGarrett D'Amore return (NULL); 3124297a3b0SGarrett D'Amore 3134297a3b0SGarrett D'Amore len = 2; 314*6eaad1d3SGarrett 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) 320*6eaad1d3SGarrett D'Amore return (NULL); 3214297a3b0SGarrett D'Amore 322*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 323*6eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 3244297a3b0SGarrett D'Amore ptr++; 3254297a3b0SGarrett D'Amore break; 3264297a3b0SGarrett D'Amore 3274297a3b0SGarrett D'Amore case 'w': 328*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 329*6eaad1d3SGarrett D'Amore return (NULL); 3304297a3b0SGarrett D'Amore 3314297a3b0SGarrett D'Amore i = *buf - '0'; 3324297a3b0SGarrett D'Amore if (i > 6) 333*6eaad1d3SGarrett D'Amore return (NULL); 3344297a3b0SGarrett D'Amore 3354297a3b0SGarrett D'Amore tm->tm_wday = i; 3364297a3b0SGarrett D'Amore 337*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 338*6eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 3394297a3b0SGarrett D'Amore ptr++; 3404297a3b0SGarrett D'Amore break; 3414297a3b0SGarrett D'Amore 3424297a3b0SGarrett D'Amore case 'd': 3434297a3b0SGarrett D'Amore case 'e': 3444297a3b0SGarrett D'Amore /* 3454297a3b0SGarrett D'Amore * The %e specifier is explicitly documented as not 3464297a3b0SGarrett D'Amore * being zero-padded but there is no harm in allowing 3474297a3b0SGarrett D'Amore * such padding. 3484297a3b0SGarrett D'Amore * 3494297a3b0SGarrett D'Amore * XXX The %e specifier may gobble one too many 3504297a3b0SGarrett D'Amore * digits if used incorrectly. 3514297a3b0SGarrett D'Amore */ 352*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 353*6eaad1d3SGarrett D'Amore return (NULL); 3544297a3b0SGarrett D'Amore 3554297a3b0SGarrett D'Amore len = 2; 356*6eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 3574297a3b0SGarrett D'Amore i *= 10; 3584297a3b0SGarrett D'Amore i += *buf - '0'; 3594297a3b0SGarrett D'Amore len--; 3604297a3b0SGarrett D'Amore } 3614297a3b0SGarrett D'Amore if (i > 31) 362*6eaad1d3SGarrett D'Amore return (NULL); 3634297a3b0SGarrett D'Amore 3644297a3b0SGarrett D'Amore tm->tm_mday = i; 3654297a3b0SGarrett D'Amore 366*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 367*6eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 3684297a3b0SGarrett D'Amore ptr++; 3694297a3b0SGarrett D'Amore break; 3704297a3b0SGarrett D'Amore 3714297a3b0SGarrett D'Amore case 'B': 3724297a3b0SGarrett D'Amore case 'b': 3734297a3b0SGarrett D'Amore case 'h': 3744297a3b0SGarrett D'Amore for (i = 0; i < asizeof(tptr->month); i++) { 3754297a3b0SGarrett D'Amore len = strlen(tptr->month[i]); 3764297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->month[i], len) == 0) 3774297a3b0SGarrett D'Amore break; 3784297a3b0SGarrett D'Amore } 3794297a3b0SGarrett D'Amore /* 3804297a3b0SGarrett D'Amore * Try the abbreviated month name if the full name 3814297a3b0SGarrett D'Amore * wasn't found. 3824297a3b0SGarrett D'Amore */ 3834297a3b0SGarrett D'Amore if (i == asizeof(tptr->month)) { 3844297a3b0SGarrett D'Amore for (i = 0; i < asizeof(tptr->month); i++) { 3854297a3b0SGarrett D'Amore len = strlen(tptr->mon[i]); 3864297a3b0SGarrett D'Amore if (strncasecmp(buf, tptr->mon[i], 3874297a3b0SGarrett D'Amore len) == 0) 3884297a3b0SGarrett D'Amore break; 3894297a3b0SGarrett D'Amore } 3904297a3b0SGarrett D'Amore } 3914297a3b0SGarrett D'Amore if (i == asizeof(tptr->month)) 392*6eaad1d3SGarrett D'Amore return (NULL); 3934297a3b0SGarrett D'Amore 3944297a3b0SGarrett D'Amore tm->tm_mon = i; 3954297a3b0SGarrett D'Amore buf += len; 3964297a3b0SGarrett D'Amore break; 3974297a3b0SGarrett D'Amore 3984297a3b0SGarrett D'Amore case 'm': 399*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 400*6eaad1d3SGarrett D'Amore return (NULL); 4014297a3b0SGarrett D'Amore 4024297a3b0SGarrett D'Amore len = 2; 403*6eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 4044297a3b0SGarrett D'Amore i *= 10; 4054297a3b0SGarrett D'Amore i += *buf - '0'; 4064297a3b0SGarrett D'Amore len--; 4074297a3b0SGarrett D'Amore } 4084297a3b0SGarrett D'Amore if (i < 1 || i > 12) 409*6eaad1d3SGarrett D'Amore return (NULL); 4104297a3b0SGarrett D'Amore 4114297a3b0SGarrett D'Amore tm->tm_mon = i - 1; 4124297a3b0SGarrett D'Amore 413*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 414*6eaad1d3SGarrett D'Amore while (*ptr != NULL && !isspace(*ptr)) 4154297a3b0SGarrett D'Amore ptr++; 4164297a3b0SGarrett D'Amore break; 4174297a3b0SGarrett D'Amore 418*6eaad1d3SGarrett D'Amore case 's': 419*6eaad1d3SGarrett D'Amore { 420*6eaad1d3SGarrett D'Amore char *cp; 421*6eaad1d3SGarrett D'Amore int sverrno; 422*6eaad1d3SGarrett D'Amore time_t t; 423*6eaad1d3SGarrett D'Amore 424*6eaad1d3SGarrett D'Amore sverrno = errno; 425*6eaad1d3SGarrett D'Amore errno = 0; 426*6eaad1d3SGarrett D'Amore t = strtol(buf, &cp, 10); 427*6eaad1d3SGarrett D'Amore if (errno == ERANGE) { 428*6eaad1d3SGarrett D'Amore errno = sverrno; 429*6eaad1d3SGarrett D'Amore return (NULL); 430*6eaad1d3SGarrett D'Amore } 431*6eaad1d3SGarrett D'Amore errno = sverrno; 432*6eaad1d3SGarrett D'Amore buf = cp; 433*6eaad1d3SGarrett D'Amore (void) gmtime_r(&t, tm); 434*6eaad1d3SGarrett D'Amore *flagsp |= F_GMT; 435*6eaad1d3SGarrett D'Amore } 436*6eaad1d3SGarrett D'Amore break; 437*6eaad1d3SGarrett D'Amore 4384297a3b0SGarrett D'Amore case 'Y': 4394297a3b0SGarrett D'Amore case 'y': 440*6eaad1d3SGarrett D'Amore if (*buf == NULL || isspace(*buf)) 4414297a3b0SGarrett D'Amore break; 4424297a3b0SGarrett D'Amore 443*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 444*6eaad1d3SGarrett D'Amore return (NULL); 4454297a3b0SGarrett D'Amore 4464297a3b0SGarrett D'Amore len = (c == 'Y') ? 4 : 2; 447*6eaad1d3SGarrett D'Amore for (i = 0; len && isdigit(*buf); buf++) { 4484297a3b0SGarrett D'Amore i *= 10; 4494297a3b0SGarrett D'Amore i += *buf - '0'; 4504297a3b0SGarrett D'Amore len--; 4514297a3b0SGarrett D'Amore } 4524297a3b0SGarrett D'Amore if (c == 'Y') 4534297a3b0SGarrett D'Amore i -= 1900; 4544297a3b0SGarrett D'Amore if (c == 'y' && i < 69) 4554297a3b0SGarrett D'Amore i += 100; 4564297a3b0SGarrett D'Amore if (i < 0) 457*6eaad1d3SGarrett D'Amore return (NULL); 4584297a3b0SGarrett D'Amore 4594297a3b0SGarrett D'Amore tm->tm_year = i; 4604297a3b0SGarrett D'Amore 461*6eaad1d3SGarrett D'Amore if (isspace(*buf)) 462*6eaad1d3SGarrett D'Amore while (*ptr != 0 && !isspace(*ptr)) 4634297a3b0SGarrett D'Amore ptr++; 4644297a3b0SGarrett D'Amore break; 4654297a3b0SGarrett D'Amore 4664297a3b0SGarrett D'Amore case 'Z': 4674297a3b0SGarrett D'Amore { 4684297a3b0SGarrett D'Amore const char *cp = buf; 4694297a3b0SGarrett D'Amore char *zonestr; 4704297a3b0SGarrett D'Amore 471*6eaad1d3SGarrett D'Amore while (isupper(*cp)) 4724297a3b0SGarrett D'Amore ++cp; 4734297a3b0SGarrett D'Amore if (cp - buf) { 4744297a3b0SGarrett D'Amore zonestr = alloca(cp - buf + 1); 4754297a3b0SGarrett D'Amore (void) strncpy(zonestr, buf, cp - buf); 4764297a3b0SGarrett D'Amore zonestr[cp - buf] = '\0'; 4774297a3b0SGarrett D'Amore tzset(); 478*6eaad1d3SGarrett D'Amore if (strcmp(zonestr, "GMT") == 0) { 479*6eaad1d3SGarrett D'Amore *flagsp |= F_GMT; 480*6eaad1d3SGarrett D'Amore } else if (0 == strcmp(zonestr, tzname[0])) { 4814297a3b0SGarrett D'Amore tm->tm_isdst = 0; 4824297a3b0SGarrett D'Amore } else if (0 == strcmp(zonestr, tzname[1])) { 4834297a3b0SGarrett D'Amore tm->tm_isdst = 1; 4844297a3b0SGarrett D'Amore } else { 485*6eaad1d3SGarrett D'Amore return (NULL); 4864297a3b0SGarrett D'Amore } 4874297a3b0SGarrett D'Amore buf += cp - buf; 4884297a3b0SGarrett D'Amore } 4894297a3b0SGarrett D'Amore } 4904297a3b0SGarrett D'Amore break; 4914297a3b0SGarrett D'Amore 492*6eaad1d3SGarrett D'Amore case 'z': 493*6eaad1d3SGarrett D'Amore { 494*6eaad1d3SGarrett D'Amore int sign = 1; 495*6eaad1d3SGarrett D'Amore 496*6eaad1d3SGarrett D'Amore if (*buf != '+') { 497*6eaad1d3SGarrett D'Amore if (*buf == '-') 498*6eaad1d3SGarrett D'Amore sign = -1; 499*6eaad1d3SGarrett D'Amore else 500*6eaad1d3SGarrett D'Amore return (NULL); 501*6eaad1d3SGarrett D'Amore } 502*6eaad1d3SGarrett D'Amore buf++; 503*6eaad1d3SGarrett D'Amore i = 0; 504*6eaad1d3SGarrett D'Amore for (len = 4; len > 0; len--) { 505*6eaad1d3SGarrett D'Amore if (!isdigit(*buf)) 506*6eaad1d3SGarrett D'Amore return (NULL); 507*6eaad1d3SGarrett D'Amore i *= 10; 508*6eaad1d3SGarrett D'Amore i += *buf - '0'; 509*6eaad1d3SGarrett D'Amore buf++; 510*6eaad1d3SGarrett D'Amore } 511*6eaad1d3SGarrett D'Amore 512*6eaad1d3SGarrett D'Amore tm->tm_hour -= sign * (i / 100); 513*6eaad1d3SGarrett D'Amore tm->tm_min -= sign * (i % 100); 514*6eaad1d3SGarrett D'Amore *flagsp |= F_GMT; 515*6eaad1d3SGarrett D'Amore } 516*6eaad1d3SGarrett D'Amore break; 517*6eaad1d3SGarrett D'Amore } 518*6eaad1d3SGarrett D'Amore } 519*6eaad1d3SGarrett D'Amore 520*6eaad1d3SGarrett D'Amore if (!recurse) { 521*6eaad1d3SGarrett D'Amore if (buf && (*flagsp & F_GMT)) { 522*6eaad1d3SGarrett D'Amore time_t t = timegm(tm); 523*6eaad1d3SGarrett D'Amore (void) localtime_r(&t, tm); 5244297a3b0SGarrett D'Amore } 5254297a3b0SGarrett D'Amore } 526*6eaad1d3SGarrett D'Amore 5274297a3b0SGarrett D'Amore return ((char *)buf); 5284297a3b0SGarrett D'Amore } 5294297a3b0SGarrett D'Amore 5304297a3b0SGarrett D'Amore char * 5314297a3b0SGarrett D'Amore strptime(const char *buf, const char *fmt, struct tm *tm) 5324297a3b0SGarrett D'Amore { 533*6eaad1d3SGarrett D'Amore int flags = F_ZERO; 5344297a3b0SGarrett D'Amore 535*6eaad1d3SGarrett D'Amore return (__strptime(buf, fmt, tm, &flags)); 5364297a3b0SGarrett D'Amore } 5374297a3b0SGarrett D'Amore 5384297a3b0SGarrett D'Amore /* 5394297a3b0SGarrett D'Amore * This is used by Solaris, and is a variant that does not clear the 5404297a3b0SGarrett D'Amore * incoming tm. It is triggered by -D_STRPTIME_DONTZERO. 5414297a3b0SGarrett D'Amore */ 5424297a3b0SGarrett D'Amore char * 5434297a3b0SGarrett D'Amore __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm) 5444297a3b0SGarrett D'Amore { 545*6eaad1d3SGarrett D'Amore int flags = 0; 546*6eaad1d3SGarrett D'Amore 547*6eaad1d3SGarrett D'Amore return (__strptime(buf, fmt, tm, &flags)); 5484297a3b0SGarrett D'Amore } 549