10413bfcaSPedro F. Giffuni /*- 2cd9dcb03SPedro F. Giffuni * Copyright (c) 2014 Gary Mills 3cd9dcb03SPedro F. Giffuni * Copyright 2011, Nexenta Systems, Inc. All rights reserved. 4d7641983SJoerg Wunsch * Copyright (c) 1994 Powerdog Industries. All rights reserved. 5d7641983SJoerg Wunsch * 63c87aa1dSDavid Chisnall * Copyright (c) 2011 The FreeBSD Foundation 73c87aa1dSDavid Chisnall * All rights reserved. 83c87aa1dSDavid Chisnall * Portions of this software were developed by David Chisnall 93c87aa1dSDavid Chisnall * under sponsorship from the FreeBSD Foundation. 103c87aa1dSDavid Chisnall * 1137486f03SJoerg Wunsch * Redistribution and use in source and binary forms, with or without 12d7641983SJoerg Wunsch * modification, are permitted provided that the following conditions 13d7641983SJoerg Wunsch * are met: 14d7641983SJoerg Wunsch * 1. Redistributions of source code must retain the above copyright 15d7641983SJoerg Wunsch * notice, this list of conditions and the following disclaimer. 16d7641983SJoerg Wunsch * 2. Redistributions in binary form must reproduce the above copyright 17d7641983SJoerg Wunsch * notice, this list of conditions and the following disclaimer 18d7641983SJoerg Wunsch * in the documentation and/or other materials provided with the 19d7641983SJoerg Wunsch * distribution. 20d7641983SJoerg Wunsch * 21d7641983SJoerg Wunsch * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 22d7641983SJoerg Wunsch * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23d7641983SJoerg Wunsch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24d7641983SJoerg Wunsch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 25d7641983SJoerg Wunsch * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26d7641983SJoerg Wunsch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27d7641983SJoerg Wunsch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28d7641983SJoerg Wunsch * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29d7641983SJoerg Wunsch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30d7641983SJoerg Wunsch * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31d7641983SJoerg Wunsch * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 320413bfcaSPedro F. Giffuni * 330413bfcaSPedro F. Giffuni * The views and conclusions contained in the software and documentation 340413bfcaSPedro F. Giffuni * are those of the authors and should not be interpreted as representing 350413bfcaSPedro F. Giffuni * official policies, either expressed or implied, of Powerdog Industries. 36d7641983SJoerg Wunsch */ 37d7641983SJoerg Wunsch 38e0554a53SJacques Vidrine #include <sys/cdefs.h> 39d7641983SJoerg Wunsch #ifndef lint 4037486f03SJoerg Wunsch #ifndef NOID 41e0554a53SJacques Vidrine static char copyright[] __unused = 42d7641983SJoerg Wunsch "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 43e0554a53SJacques Vidrine static char sccsid[] __unused = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 4437486f03SJoerg Wunsch #endif /* !defined NOID */ 45d7641983SJoerg Wunsch #endif /* not lint */ 46333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 47d7641983SJoerg Wunsch 48d201fe46SDaniel Eischen #include "namespace.h" 49d7641983SJoerg Wunsch #include <time.h> 50d7641983SJoerg Wunsch #include <ctype.h> 51c91e947dSJacques Vidrine #include <errno.h> 52427fc5edSDima Dorfman #include <stdlib.h> 53d7641983SJoerg Wunsch #include <string.h> 54cb7a4779SDavid E. O'Brien #include <pthread.h> 55d201fe46SDaniel Eischen #include "un-namespace.h" 56d201fe46SDaniel Eischen #include "libc_private.h" 5737486f03SJoerg Wunsch #include "timelocal.h" 58d7641983SJoerg Wunsch 593c87aa1dSDavid Chisnall static char * _strptime(const char *, const char *, struct tm *, int *, locale_t); 60cb7a4779SDavid E. O'Brien 61d7641983SJoerg Wunsch #define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 62d7641983SJoerg Wunsch 63cb7a4779SDavid E. O'Brien static char * 643c87aa1dSDavid Chisnall _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, 653c87aa1dSDavid Chisnall locale_t locale) 66d7641983SJoerg Wunsch { 6737486f03SJoerg Wunsch char c; 6837486f03SJoerg Wunsch const char *ptr; 693624c752SPedro F. Giffuni int i, len; 701d6c9941SAndrey A. Chernov int Ealternative, Oalternative; 713c87aa1dSDavid Chisnall struct lc_time_T *tptr = __get_current_time_locale(locale); 72d7641983SJoerg Wunsch 73d7641983SJoerg Wunsch ptr = fmt; 74d7641983SJoerg Wunsch while (*ptr != 0) { 75d7641983SJoerg Wunsch if (*buf == 0) 76d7641983SJoerg Wunsch break; 77d7641983SJoerg Wunsch 78d7641983SJoerg Wunsch c = *ptr++; 79d7641983SJoerg Wunsch 80d7641983SJoerg Wunsch if (c != '%') { 813c87aa1dSDavid Chisnall if (isspace_l((unsigned char)c, locale)) 823c87aa1dSDavid Chisnall while (*buf != 0 && 833c87aa1dSDavid Chisnall isspace_l((unsigned char)*buf, locale)) 84d7641983SJoerg Wunsch buf++; 85d7641983SJoerg Wunsch else if (c != *buf++) 863624c752SPedro F. Giffuni return (NULL); 87d7641983SJoerg Wunsch continue; 88d7641983SJoerg Wunsch } 89d7641983SJoerg Wunsch 901d6c9941SAndrey A. Chernov Ealternative = 0; 911d6c9941SAndrey A. Chernov Oalternative = 0; 921d6c9941SAndrey A. Chernov label: 93d7641983SJoerg Wunsch c = *ptr++; 94d7641983SJoerg Wunsch switch (c) { 95d7641983SJoerg Wunsch case 0: 96d7641983SJoerg Wunsch case '%': 97d7641983SJoerg Wunsch if (*buf++ != '%') 983624c752SPedro F. Giffuni return (NULL); 99d7641983SJoerg Wunsch break; 100d7641983SJoerg Wunsch 1011d6c9941SAndrey A. Chernov case '+': 1023c87aa1dSDavid Chisnall buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale); 1033624c752SPedro F. Giffuni if (buf == NULL) 1043624c752SPedro F. Giffuni return (NULL); 105d7641983SJoerg Wunsch break; 106d7641983SJoerg Wunsch 1071d6c9941SAndrey A. Chernov case 'C': 1083c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 1093624c752SPedro F. Giffuni return (NULL); 1101d6c9941SAndrey A. Chernov 111398592ffSSheldon Hearn /* XXX This will break for 3-digit centuries. */ 112398592ffSSheldon Hearn len = 2; 1133c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 1143c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++) { 1151d6c9941SAndrey A. Chernov i *= 10; 1161d6c9941SAndrey A. Chernov i += *buf - '0'; 117398592ffSSheldon Hearn len--; 1181d6c9941SAndrey A. Chernov } 1191d6c9941SAndrey A. Chernov if (i < 19) 1203624c752SPedro F. Giffuni return (NULL); 1211d6c9941SAndrey A. Chernov 1221d6c9941SAndrey A. Chernov tm->tm_year = i * 100 - 1900; 1231d6c9941SAndrey A. Chernov break; 1241d6c9941SAndrey A. Chernov 125d7641983SJoerg Wunsch case 'c': 1263c87aa1dSDavid Chisnall buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale); 1273624c752SPedro F. Giffuni if (buf == NULL) 1283624c752SPedro F. Giffuni return (NULL); 129d7641983SJoerg Wunsch break; 130d7641983SJoerg Wunsch 131d7641983SJoerg Wunsch case 'D': 1323c87aa1dSDavid Chisnall buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale); 1333624c752SPedro F. Giffuni if (buf == NULL) 1343624c752SPedro F. Giffuni return (NULL); 135d7641983SJoerg Wunsch break; 136d7641983SJoerg Wunsch 1371d6c9941SAndrey A. Chernov case 'E': 138c63a4303SAndrey A. Chernov if (Ealternative || Oalternative) 139c63a4303SAndrey A. Chernov break; 1401d6c9941SAndrey A. Chernov Ealternative++; 1411d6c9941SAndrey A. Chernov goto label; 1421d6c9941SAndrey A. Chernov 1431d6c9941SAndrey A. Chernov case 'O': 144c63a4303SAndrey A. Chernov if (Ealternative || Oalternative) 145c63a4303SAndrey A. Chernov break; 1461d6c9941SAndrey A. Chernov Oalternative++; 1471d6c9941SAndrey A. Chernov goto label; 1481d6c9941SAndrey A. Chernov 149c63a4303SAndrey A. Chernov case 'F': 1503c87aa1dSDavid Chisnall buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale); 1513624c752SPedro F. Giffuni if (buf == NULL) 1523624c752SPedro F. Giffuni return (NULL); 153c63a4303SAndrey A. Chernov break; 154c63a4303SAndrey A. Chernov 155d7641983SJoerg Wunsch case 'R': 1563c87aa1dSDavid Chisnall buf = _strptime(buf, "%H:%M", tm, GMTp, locale); 1573624c752SPedro F. Giffuni if (buf == NULL) 1583624c752SPedro F. Giffuni return (NULL); 159d7641983SJoerg Wunsch break; 160d7641983SJoerg Wunsch 161d7641983SJoerg Wunsch case 'r': 1623c87aa1dSDavid Chisnall buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale); 1633624c752SPedro F. Giffuni if (buf == NULL) 1643624c752SPedro F. Giffuni return (NULL); 165d7641983SJoerg Wunsch break; 166d7641983SJoerg Wunsch 167d7641983SJoerg Wunsch case 'T': 1683c87aa1dSDavid Chisnall buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale); 1693624c752SPedro F. Giffuni if (buf == NULL) 1703624c752SPedro F. Giffuni return (NULL); 171d7641983SJoerg Wunsch break; 172d7641983SJoerg Wunsch 173d7641983SJoerg Wunsch case 'X': 1743c87aa1dSDavid Chisnall buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale); 1753624c752SPedro F. Giffuni if (buf == NULL) 1763624c752SPedro F. Giffuni return (NULL); 177d7641983SJoerg Wunsch break; 178d7641983SJoerg Wunsch 179d7641983SJoerg Wunsch case 'x': 1803c87aa1dSDavid Chisnall buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale); 1813624c752SPedro F. Giffuni if (buf == NULL) 1823624c752SPedro F. Giffuni return (NULL); 183d7641983SJoerg Wunsch break; 184d7641983SJoerg Wunsch 185d7641983SJoerg Wunsch case 'j': 1863c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 1873624c752SPedro F. Giffuni return (NULL); 188d7641983SJoerg Wunsch 189398592ffSSheldon Hearn len = 3; 1903c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 1913c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++){ 192d7641983SJoerg Wunsch i *= 10; 193d7641983SJoerg Wunsch i += *buf - '0'; 194398592ffSSheldon Hearn len--; 195d7641983SJoerg Wunsch } 19633dbb0a6SSheldon Hearn if (i < 1 || i > 366) 1973624c752SPedro F. Giffuni return (NULL); 198d7641983SJoerg Wunsch 19933dbb0a6SSheldon Hearn tm->tm_yday = i - 1; 200d7641983SJoerg Wunsch break; 201d7641983SJoerg Wunsch 202d7641983SJoerg Wunsch case 'M': 203d7641983SJoerg Wunsch case 'S': 2043c87aa1dSDavid Chisnall if (*buf == 0 || 2053c87aa1dSDavid Chisnall isspace_l((unsigned char)*buf, locale)) 206d7641983SJoerg Wunsch break; 207d7641983SJoerg Wunsch 2083c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 2093624c752SPedro F. Giffuni return (NULL); 210d7641983SJoerg Wunsch 211398592ffSSheldon Hearn len = 2; 2123c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 2133c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++){ 214d7641983SJoerg Wunsch i *= 10; 215d7641983SJoerg Wunsch i += *buf - '0'; 216398592ffSSheldon Hearn len--; 217d7641983SJoerg Wunsch } 21833dbb0a6SSheldon Hearn 21933dbb0a6SSheldon Hearn if (c == 'M') { 220d7641983SJoerg Wunsch if (i > 59) 2213624c752SPedro F. Giffuni return (NULL); 222d7641983SJoerg Wunsch tm->tm_min = i; 22333dbb0a6SSheldon Hearn } else { 22433dbb0a6SSheldon Hearn if (i > 60) 2253624c752SPedro F. Giffuni return (NULL); 226d7641983SJoerg Wunsch tm->tm_sec = i; 22733dbb0a6SSheldon Hearn } 228d7641983SJoerg Wunsch 229d7641983SJoerg Wunsch break; 230d7641983SJoerg Wunsch 231d7641983SJoerg Wunsch case 'H': 232d7641983SJoerg Wunsch case 'I': 233d7641983SJoerg Wunsch case 'k': 234d7641983SJoerg Wunsch case 'l': 235398592ffSSheldon Hearn /* 236398592ffSSheldon Hearn * Of these, %l is the only specifier explicitly 237398592ffSSheldon Hearn * documented as not being zero-padded. However, 238398592ffSSheldon Hearn * there is no harm in allowing zero-padding. 239398592ffSSheldon Hearn * 240398592ffSSheldon Hearn * XXX The %l specifier may gobble one too many 241398592ffSSheldon Hearn * digits if used incorrectly. 242398592ffSSheldon Hearn */ 2433c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 2443624c752SPedro F. Giffuni return (NULL); 245d7641983SJoerg Wunsch 246398592ffSSheldon Hearn len = 2; 2473c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 2483c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++) { 249d7641983SJoerg Wunsch i *= 10; 250d7641983SJoerg Wunsch i += *buf - '0'; 251398592ffSSheldon Hearn len--; 252d7641983SJoerg Wunsch } 253d7641983SJoerg Wunsch if (c == 'H' || c == 'k') { 254d7641983SJoerg Wunsch if (i > 23) 2553624c752SPedro F. Giffuni return (NULL); 256882f32c1SSheldon Hearn } else if (i > 12) 2573624c752SPedro F. Giffuni return (NULL); 258d7641983SJoerg Wunsch 259d7641983SJoerg Wunsch tm->tm_hour = i; 260d7641983SJoerg Wunsch 261d7641983SJoerg Wunsch break; 262d7641983SJoerg Wunsch 263d7641983SJoerg Wunsch case 'p': 264398592ffSSheldon Hearn /* 265398592ffSSheldon Hearn * XXX This is bogus if parsed before hour-related 266398592ffSSheldon Hearn * specifiers. 267398592ffSSheldon Hearn */ 268930cd711SAlexey Zelkin len = strlen(tptr->am); 2693c87aa1dSDavid Chisnall if (strncasecmp_l(buf, tptr->am, len, locale) == 0) { 270d7641983SJoerg Wunsch if (tm->tm_hour > 12) 2713624c752SPedro F. Giffuni return (NULL); 272d7641983SJoerg Wunsch if (tm->tm_hour == 12) 273d7641983SJoerg Wunsch tm->tm_hour = 0; 274d7641983SJoerg Wunsch buf += len; 275d7641983SJoerg Wunsch break; 276d7641983SJoerg Wunsch } 277d7641983SJoerg Wunsch 278930cd711SAlexey Zelkin len = strlen(tptr->pm); 2793c87aa1dSDavid Chisnall if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) { 280d7641983SJoerg Wunsch if (tm->tm_hour > 12) 2813624c752SPedro F. Giffuni return (NULL); 282d7641983SJoerg Wunsch if (tm->tm_hour != 12) 283d7641983SJoerg Wunsch tm->tm_hour += 12; 284d7641983SJoerg Wunsch buf += len; 285d7641983SJoerg Wunsch break; 286d7641983SJoerg Wunsch } 287d7641983SJoerg Wunsch 2883624c752SPedro F. Giffuni return (NULL); 289d7641983SJoerg Wunsch 290d7641983SJoerg Wunsch case 'A': 291d7641983SJoerg Wunsch case 'a': 292930cd711SAlexey Zelkin for (i = 0; i < asizeof(tptr->weekday); i++) { 293930cd711SAlexey Zelkin len = strlen(tptr->weekday[i]); 2943c87aa1dSDavid Chisnall if (strncasecmp_l(buf, tptr->weekday[i], 2953c87aa1dSDavid Chisnall len, locale) == 0) 296d7641983SJoerg Wunsch break; 297930cd711SAlexey Zelkin len = strlen(tptr->wday[i]); 2983c87aa1dSDavid Chisnall if (strncasecmp_l(buf, tptr->wday[i], 2993c87aa1dSDavid Chisnall len, locale) == 0) 300d7641983SJoerg Wunsch break; 301d7641983SJoerg Wunsch } 302930cd711SAlexey Zelkin if (i == asizeof(tptr->weekday)) 3033624c752SPedro F. Giffuni return (NULL); 304d7641983SJoerg Wunsch 305d7641983SJoerg Wunsch tm->tm_wday = i; 306d7641983SJoerg Wunsch buf += len; 307d7641983SJoerg Wunsch break; 308d7641983SJoerg Wunsch 30933dbb0a6SSheldon Hearn case 'U': 31033dbb0a6SSheldon Hearn case 'W': 31133dbb0a6SSheldon Hearn /* 31233dbb0a6SSheldon Hearn * XXX This is bogus, as we can not assume any valid 31333dbb0a6SSheldon Hearn * information present in the tm structure at this 31433dbb0a6SSheldon Hearn * point to calculate a real value, so just check the 31533dbb0a6SSheldon Hearn * range for now. 31633dbb0a6SSheldon Hearn */ 3173c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 3183624c752SPedro F. Giffuni return (NULL); 31933dbb0a6SSheldon Hearn 320398592ffSSheldon Hearn len = 2; 3213c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 3223c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++) { 32333dbb0a6SSheldon Hearn i *= 10; 32433dbb0a6SSheldon Hearn i += *buf - '0'; 325398592ffSSheldon Hearn len--; 32633dbb0a6SSheldon Hearn } 32733dbb0a6SSheldon Hearn if (i > 53) 3283624c752SPedro F. Giffuni return (NULL); 32933dbb0a6SSheldon Hearn 33033dbb0a6SSheldon Hearn break; 33133dbb0a6SSheldon Hearn 33233dbb0a6SSheldon Hearn case 'w': 3333c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 3343624c752SPedro F. Giffuni return (NULL); 33533dbb0a6SSheldon Hearn 336398592ffSSheldon Hearn i = *buf - '0'; 33733dbb0a6SSheldon Hearn if (i > 6) 3383624c752SPedro F. Giffuni return (NULL); 33933dbb0a6SSheldon Hearn 34033dbb0a6SSheldon Hearn tm->tm_wday = i; 34133dbb0a6SSheldon Hearn 34233dbb0a6SSheldon Hearn break; 34333dbb0a6SSheldon Hearn 344d7641983SJoerg Wunsch case 'e': 345398592ffSSheldon Hearn /* 346cd9dcb03SPedro F. Giffuni * With %e format, our strftime(3) adds a blank space 347cd9dcb03SPedro F. Giffuni * before single digits. 348cd9dcb03SPedro F. Giffuni */ 349cd9dcb03SPedro F. Giffuni if (*buf != 0 && 350cd9dcb03SPedro F. Giffuni isspace_l((unsigned char)*buf, locale)) 351cd9dcb03SPedro F. Giffuni buf++; 352cd9dcb03SPedro F. Giffuni /* FALLTHROUGH */ 353cd9dcb03SPedro F. Giffuni case 'd': 354cd9dcb03SPedro F. Giffuni /* 355cd9dcb03SPedro F. Giffuni * The %e specifier was once explicitly documented as 356cd9dcb03SPedro F. Giffuni * not being zero-padded but was later changed to 357cd9dcb03SPedro F. Giffuni * equivalent to %d. There is no harm in allowing 358398592ffSSheldon Hearn * such padding. 359398592ffSSheldon Hearn * 360398592ffSSheldon Hearn * XXX The %e specifier may gobble one too many 361398592ffSSheldon Hearn * digits if used incorrectly. 362398592ffSSheldon Hearn */ 3633c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 3643624c752SPedro F. Giffuni return (NULL); 365d7641983SJoerg Wunsch 366398592ffSSheldon Hearn len = 2; 3673c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 3683c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++) { 369d7641983SJoerg Wunsch i *= 10; 370d7641983SJoerg Wunsch i += *buf - '0'; 371398592ffSSheldon Hearn len--; 372d7641983SJoerg Wunsch } 373d7641983SJoerg Wunsch if (i > 31) 3743624c752SPedro F. Giffuni return (NULL); 375d7641983SJoerg Wunsch 376d7641983SJoerg Wunsch tm->tm_mday = i; 377d7641983SJoerg Wunsch 378d7641983SJoerg Wunsch break; 379d7641983SJoerg Wunsch 380d7641983SJoerg Wunsch case 'B': 381d7641983SJoerg Wunsch case 'b': 382d7641983SJoerg Wunsch case 'h': 383930cd711SAlexey Zelkin for (i = 0; i < asizeof(tptr->month); i++) { 3841d6c9941SAndrey A. Chernov if (Oalternative) { 3851d6c9941SAndrey A. Chernov if (c == 'B') { 386930cd711SAlexey Zelkin len = strlen(tptr->alt_month[i]); 3873c87aa1dSDavid Chisnall if (strncasecmp_l(buf, 388930cd711SAlexey Zelkin tptr->alt_month[i], 3893c87aa1dSDavid Chisnall len, locale) == 0) 3901d6c9941SAndrey A. Chernov break; 3911d6c9941SAndrey A. Chernov } 3921d6c9941SAndrey A. Chernov } else { 393930cd711SAlexey Zelkin len = strlen(tptr->month[i]); 3943c87aa1dSDavid Chisnall if (strncasecmp_l(buf, tptr->month[i], 3953c87aa1dSDavid Chisnall len, locale) == 0) 396d7641983SJoerg Wunsch break; 3973d74e220SEdwin Groothuis } 3983d74e220SEdwin Groothuis } 3993d74e220SEdwin Groothuis /* 4003d74e220SEdwin Groothuis * Try the abbreviated month name if the full name 4013d74e220SEdwin Groothuis * wasn't found and Oalternative was not requested. 4023d74e220SEdwin Groothuis */ 4033d74e220SEdwin Groothuis if (i == asizeof(tptr->month) && !Oalternative) { 4043d74e220SEdwin Groothuis for (i = 0; i < asizeof(tptr->month); i++) { 405930cd711SAlexey Zelkin len = strlen(tptr->mon[i]); 4063c87aa1dSDavid Chisnall if (strncasecmp_l(buf, tptr->mon[i], 4073c87aa1dSDavid Chisnall len, locale) == 0) 408d7641983SJoerg Wunsch break; 409d7641983SJoerg Wunsch } 4101d6c9941SAndrey A. Chernov } 411930cd711SAlexey Zelkin if (i == asizeof(tptr->month)) 4123624c752SPedro F. Giffuni return (NULL); 413d7641983SJoerg Wunsch 414d7641983SJoerg Wunsch tm->tm_mon = i; 415d7641983SJoerg Wunsch buf += len; 416d7641983SJoerg Wunsch break; 417d7641983SJoerg Wunsch 418d7641983SJoerg Wunsch case 'm': 4193c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 4203624c752SPedro F. Giffuni return (NULL); 421d7641983SJoerg Wunsch 422398592ffSSheldon Hearn len = 2; 4233c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 4243c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++) { 425d7641983SJoerg Wunsch i *= 10; 426d7641983SJoerg Wunsch i += *buf - '0'; 427398592ffSSheldon Hearn len--; 428d7641983SJoerg Wunsch } 429d7641983SJoerg Wunsch if (i < 1 || i > 12) 4303624c752SPedro F. Giffuni return (NULL); 431d7641983SJoerg Wunsch 432d7641983SJoerg Wunsch tm->tm_mon = i - 1; 433d7641983SJoerg Wunsch 434d7641983SJoerg Wunsch break; 435d7641983SJoerg Wunsch 436427fc5edSDima Dorfman case 's': 437427fc5edSDima Dorfman { 438427fc5edSDima Dorfman char *cp; 439c91e947dSJacques Vidrine int sverrno; 440c91e947dSJacques Vidrine long n; 441427fc5edSDima Dorfman time_t t; 442427fc5edSDima Dorfman 443c91e947dSJacques Vidrine sverrno = errno; 444c91e947dSJacques Vidrine errno = 0; 4453c87aa1dSDavid Chisnall n = strtol_l(buf, &cp, 10, locale); 446c91e947dSJacques Vidrine if (errno == ERANGE || (long)(t = n) != n) { 447c91e947dSJacques Vidrine errno = sverrno; 4483624c752SPedro F. Giffuni return (NULL); 449c91e947dSJacques Vidrine } 450c91e947dSJacques Vidrine errno = sverrno; 451427fc5edSDima Dorfman buf = cp; 452427fc5edSDima Dorfman gmtime_r(&t, tm); 453fe71e0b8SMike Makonnen *GMTp = 1; 454427fc5edSDima Dorfman } 455427fc5edSDima Dorfman break; 456427fc5edSDima Dorfman 457d7641983SJoerg Wunsch case 'Y': 458d7641983SJoerg Wunsch case 'y': 4593c87aa1dSDavid Chisnall if (*buf == 0 || 4603c87aa1dSDavid Chisnall isspace_l((unsigned char)*buf, locale)) 461d7641983SJoerg Wunsch break; 462d7641983SJoerg Wunsch 4633c87aa1dSDavid Chisnall if (!isdigit_l((unsigned char)*buf, locale)) 4643624c752SPedro F. Giffuni return (NULL); 465d7641983SJoerg Wunsch 466398592ffSSheldon Hearn len = (c == 'Y') ? 4 : 2; 4673c87aa1dSDavid Chisnall for (i = 0; len && *buf != 0 && 4683c87aa1dSDavid Chisnall isdigit_l((unsigned char)*buf, locale); buf++) { 469d7641983SJoerg Wunsch i *= 10; 470d7641983SJoerg Wunsch i += *buf - '0'; 471398592ffSSheldon Hearn len--; 472d7641983SJoerg Wunsch } 473d7641983SJoerg Wunsch if (c == 'Y') 474d7641983SJoerg Wunsch i -= 1900; 475aba0410bSWes Peters if (c == 'y' && i < 69) 476a00b1d8fSWes Peters i += 100; 477d7641983SJoerg Wunsch if (i < 0) 4783624c752SPedro F. Giffuni return (NULL); 479d7641983SJoerg Wunsch 480d7641983SJoerg Wunsch tm->tm_year = i; 481d7641983SJoerg Wunsch 482d7641983SJoerg Wunsch break; 483b47f20dfSDavid E. O'Brien 484b47f20dfSDavid E. O'Brien case 'Z': 485b47f20dfSDavid E. O'Brien { 486b47f20dfSDavid E. O'Brien const char *cp; 487b47f20dfSDavid E. O'Brien char *zonestr; 488b47f20dfSDavid E. O'Brien 4893c87aa1dSDavid Chisnall for (cp = buf; *cp && 4903c87aa1dSDavid Chisnall isupper_l((unsigned char)*cp, locale); ++cp) { 4913c87aa1dSDavid Chisnall /*empty*/} 492b47f20dfSDavid E. O'Brien if (cp - buf) { 493b47f20dfSDavid E. O'Brien zonestr = alloca(cp - buf + 1); 494b47f20dfSDavid E. O'Brien strncpy(zonestr, buf, cp - buf); 495b47f20dfSDavid E. O'Brien zonestr[cp - buf] = '\0'; 496b47f20dfSDavid E. O'Brien tzset(); 497b47f20dfSDavid E. O'Brien if (0 == strcmp(zonestr, "GMT")) { 498fe71e0b8SMike Makonnen *GMTp = 1; 499b47f20dfSDavid E. O'Brien } else if (0 == strcmp(zonestr, tzname[0])) { 500b47f20dfSDavid E. O'Brien tm->tm_isdst = 0; 501b47f20dfSDavid E. O'Brien } else if (0 == strcmp(zonestr, tzname[1])) { 502b47f20dfSDavid E. O'Brien tm->tm_isdst = 1; 503b47f20dfSDavid E. O'Brien } else { 5043624c752SPedro F. Giffuni return (NULL); 505b47f20dfSDavid E. O'Brien } 506b47f20dfSDavid E. O'Brien buf += cp - buf; 507b47f20dfSDavid E. O'Brien } 508b47f20dfSDavid E. O'Brien } 509b47f20dfSDavid E. O'Brien break; 51040523da7SXin LI 51140523da7SXin LI case 'z': 51240523da7SXin LI { 51340523da7SXin LI int sign = 1; 51440523da7SXin LI 51540523da7SXin LI if (*buf != '+') { 51640523da7SXin LI if (*buf == '-') 51740523da7SXin LI sign = -1; 51840523da7SXin LI else 5193624c752SPedro F. Giffuni return (NULL); 52040523da7SXin LI } 52140523da7SXin LI 52240523da7SXin LI buf++; 52340523da7SXin LI i = 0; 52440523da7SXin LI for (len = 4; len > 0; len--) { 5253c87aa1dSDavid Chisnall if (isdigit_l((unsigned char)*buf, locale)) { 52640523da7SXin LI i *= 10; 52740523da7SXin LI i += *buf - '0'; 52840523da7SXin LI buf++; 52940523da7SXin LI } else 5303624c752SPedro F. Giffuni return (NULL); 53140523da7SXin LI } 53240523da7SXin LI 53340523da7SXin LI tm->tm_hour -= sign * (i / 100); 53440523da7SXin LI tm->tm_min -= sign * (i % 100); 53540523da7SXin LI *GMTp = 1; 53640523da7SXin LI } 53740523da7SXin LI break; 538cd9dcb03SPedro F. Giffuni 539cd9dcb03SPedro F. Giffuni case 'n': 540cd9dcb03SPedro F. Giffuni case 't': 541cd9dcb03SPedro F. Giffuni while (isspace_l((unsigned char)*buf, locale)) 542cd9dcb03SPedro F. Giffuni buf++; 543cd9dcb03SPedro F. Giffuni break; 544d7641983SJoerg Wunsch } 545d7641983SJoerg Wunsch } 5463624c752SPedro F. Giffuni return ((char *)buf); 547cb7a4779SDavid E. O'Brien } 548d7641983SJoerg Wunsch 549cb7a4779SDavid E. O'Brien 550cb7a4779SDavid E. O'Brien char * 5513c87aa1dSDavid Chisnall strptime_l(const char * __restrict buf, const char * __restrict fmt, 5523c87aa1dSDavid Chisnall struct tm * __restrict tm, locale_t loc) 553cb7a4779SDavid E. O'Brien { 554cb7a4779SDavid E. O'Brien char *ret; 555fe71e0b8SMike Makonnen int gmt; 5563c87aa1dSDavid Chisnall FIX_LOCALE(loc); 557cb7a4779SDavid E. O'Brien 558fe71e0b8SMike Makonnen gmt = 0; 5593c87aa1dSDavid Chisnall ret = _strptime(buf, fmt, tm, &gmt, loc); 5606c688436SMike Makonnen if (ret && gmt) { 5616c688436SMike Makonnen time_t t = timegm(tm); 562b47f20dfSDavid E. O'Brien localtime_r(&t, tm); 563b47f20dfSDavid E. O'Brien } 564cb7a4779SDavid E. O'Brien 565fe71e0b8SMike Makonnen return (ret); 566d7641983SJoerg Wunsch } 5673c87aa1dSDavid Chisnall char * 5683c87aa1dSDavid Chisnall strptime(const char * __restrict buf, const char * __restrict fmt, 5693c87aa1dSDavid Chisnall struct tm * __restrict tm) 5703c87aa1dSDavid Chisnall { 5713c87aa1dSDavid Chisnall return strptime_l(buf, fmt, tm, __get_locale()); 5723c87aa1dSDavid Chisnall } 573