1 /* 2 * Powerdog Industries kindly requests feedback from anyone modifying 3 * this function: 4 * 5 * Date: Thu, 05 Jun 1997 23:17:17 -0400 6 * From: Kevin Ruddy <kevin.ruddy@powerdog.com> 7 * To: James FitzGibbon <james@nexis.net> 8 * Subject: Re: Use of your strptime(3) code (fwd) 9 * 10 * The reason for the "no mod" clause was so that modifications would 11 * come back and we could integrate them and reissue so that a wider 12 * audience could use it (thereby spreading the wealth). This has 13 * made it possible to get strptime to work on many operating systems. 14 * I'm not sure why that's "plain unacceptable" to the FreeBSD team. 15 * 16 * Anyway, you can change it to "with or without modification" as 17 * you see fit. Enjoy. 18 * 19 * Kevin Ruddy 20 * Powerdog Industries, Inc. 21 */ 22 /* 23 * Copyright (c) 1994 Powerdog Industries. All rights reserved. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer 32 * in the documentation and/or other materials provided with the 33 * distribution. 34 * 3. All advertising materials mentioning features or use of this 35 * software must display the following acknowledgement: 36 * This product includes software developed by Powerdog Industries. 37 * 4. The name of Powerdog Industries may not be used to endorse or 38 * promote products derived from this software without specific prior 39 * written permission. 40 * 41 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY 42 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 44 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE 45 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 46 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 47 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 48 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 49 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 50 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 51 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 52 */ 53 54 #ifdef LIBC_RCS 55 static const char rcsid[] = 56 "$FreeBSD$"; 57 #endif 58 59 #ifndef lint 60 #ifndef NOID 61 static char copyright[] = 62 "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 63 static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; 64 #endif /* !defined NOID */ 65 #endif /* not lint */ 66 67 #include <time.h> 68 #include <ctype.h> 69 #include <string.h> 70 #ifdef _THREAD_SAFE 71 #include <pthread.h> 72 #include "pthread_private.h" 73 #endif 74 #include "timelocal.h" 75 76 static char * _strptime(const char *, const char *, struct tm *); 77 78 #ifdef _THREAD_SAFE 79 static struct pthread_mutex _gotgmt_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER; 80 static pthread_mutex_t gotgmt_mutex = &_gotgmt_mutexd; 81 #endif 82 static int got_GMT; 83 84 #define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 85 86 static char * 87 _strptime(const char *buf, const char *fmt, struct tm *tm) 88 { 89 char c; 90 const char *ptr; 91 int i, 92 len; 93 94 ptr = fmt; 95 while (*ptr != 0) { 96 if (*buf == 0) 97 break; 98 99 c = *ptr++; 100 101 if (c != '%') { 102 if (isspace((unsigned char)c)) 103 while (*buf != 0 && isspace((unsigned char)*buf)) 104 buf++; 105 else if (c != *buf++) 106 return 0; 107 continue; 108 } 109 110 c = *ptr++; 111 switch (c) { 112 case 0: 113 case '%': 114 if (*buf++ != '%') 115 return 0; 116 break; 117 118 case 'C': 119 buf = _strptime(buf, Locale->date_fmt, tm); 120 if (buf == 0) 121 return 0; 122 break; 123 124 case 'c': 125 buf = _strptime(buf, "%x %X", tm); 126 if (buf == 0) 127 return 0; 128 break; 129 130 case 'D': 131 buf = _strptime(buf, "%m/%d/%y", tm); 132 if (buf == 0) 133 return 0; 134 break; 135 136 case 'R': 137 buf = _strptime(buf, "%H:%M", tm); 138 if (buf == 0) 139 return 0; 140 break; 141 142 case 'r': 143 buf = _strptime(buf, "%I:%M:%S %p", tm); 144 if (buf == 0) 145 return 0; 146 break; 147 148 case 'T': 149 buf = _strptime(buf, "%H:%M:%S", tm); 150 if (buf == 0) 151 return 0; 152 break; 153 154 case 'X': 155 buf = _strptime(buf, Locale->X_fmt, tm); 156 if (buf == 0) 157 return 0; 158 break; 159 160 case 'x': 161 buf = _strptime(buf, Locale->x_fmt, tm); 162 if (buf == 0) 163 return 0; 164 break; 165 166 case 'j': 167 if (!isdigit((unsigned char)*buf)) 168 return 0; 169 170 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 171 i *= 10; 172 i += *buf - '0'; 173 } 174 if (i > 365) 175 return 0; 176 177 tm->tm_yday = i; 178 break; 179 180 case 'M': 181 case 'S': 182 if (*buf == 0 || isspace((unsigned char)*buf)) 183 break; 184 185 if (!isdigit((unsigned char)*buf)) 186 return 0; 187 188 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 189 i *= 10; 190 i += *buf - '0'; 191 } 192 if (i > 59) 193 return 0; 194 195 if (c == 'M') 196 tm->tm_min = i; 197 else 198 tm->tm_sec = i; 199 200 if (*buf != 0 && isspace((unsigned char)*buf)) 201 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 202 ptr++; 203 break; 204 205 case 'H': 206 case 'I': 207 case 'k': 208 case 'l': 209 if (!isdigit((unsigned char)*buf)) 210 return 0; 211 212 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 213 i *= 10; 214 i += *buf - '0'; 215 } 216 if (c == 'H' || c == 'k') { 217 if (i > 23) 218 return 0; 219 } else if (i > 11) 220 return 0; 221 222 tm->tm_hour = i; 223 224 if (*buf != 0 && isspace((unsigned char)*buf)) 225 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 226 ptr++; 227 break; 228 229 case 'p': 230 len = strlen(Locale->am); 231 if (strncasecmp(buf, Locale->am, len) == 0) { 232 if (tm->tm_hour > 12) 233 return 0; 234 if (tm->tm_hour == 12) 235 tm->tm_hour = 0; 236 buf += len; 237 break; 238 } 239 240 len = strlen(Locale->pm); 241 if (strncasecmp(buf, Locale->pm, len) == 0) { 242 if (tm->tm_hour > 12) 243 return 0; 244 if (tm->tm_hour != 12) 245 tm->tm_hour += 12; 246 buf += len; 247 break; 248 } 249 250 return 0; 251 252 case 'A': 253 case 'a': 254 for (i = 0; i < asizeof(Locale->weekday); i++) { 255 len = strlen(Locale->weekday[i]); 256 if (strncasecmp(buf, 257 Locale->weekday[i], 258 len) == 0) 259 break; 260 261 len = strlen(Locale->wday[i]); 262 if (strncasecmp(buf, 263 Locale->wday[i], 264 len) == 0) 265 break; 266 } 267 if (i == asizeof(Locale->weekday)) 268 return 0; 269 270 tm->tm_wday = i; 271 buf += len; 272 break; 273 274 case 'd': 275 case 'e': 276 if (!isdigit((unsigned char)*buf)) 277 return 0; 278 279 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 280 i *= 10; 281 i += *buf - '0'; 282 } 283 if (i > 31) 284 return 0; 285 286 tm->tm_mday = i; 287 288 if (*buf != 0 && isspace((unsigned char)*buf)) 289 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 290 ptr++; 291 break; 292 293 case 'B': 294 case 'b': 295 case 'h': 296 for (i = 0; i < asizeof(Locale->month); i++) { 297 len = strlen(Locale->month[i]); 298 if (strncasecmp(buf, 299 Locale->month[i], 300 len) == 0) 301 break; 302 303 len = strlen(Locale->mon[i]); 304 if (strncasecmp(buf, 305 Locale->mon[i], 306 len) == 0) 307 break; 308 } 309 if (i == asizeof(Locale->month)) 310 return 0; 311 312 tm->tm_mon = i; 313 buf += len; 314 break; 315 316 case 'm': 317 if (!isdigit((unsigned char)*buf)) 318 return 0; 319 320 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 321 i *= 10; 322 i += *buf - '0'; 323 } 324 if (i < 1 || i > 12) 325 return 0; 326 327 tm->tm_mon = i - 1; 328 329 if (*buf != 0 && isspace((unsigned char)*buf)) 330 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 331 ptr++; 332 break; 333 334 case 'Y': 335 case 'y': 336 if (*buf == 0 || isspace((unsigned char)*buf)) 337 break; 338 339 if (!isdigit((unsigned char)*buf)) 340 return 0; 341 342 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 343 i *= 10; 344 i += *buf - '0'; 345 } 346 if (c == 'Y') 347 i -= 1900; 348 if (c == 'y' && i < 69) 349 i += 100; 350 if (i < 0) 351 return 0; 352 353 tm->tm_year = i; 354 355 if (*buf != 0 && isspace((unsigned char)*buf)) 356 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 357 ptr++; 358 break; 359 360 case 'Z': 361 { 362 const char *cp; 363 char *zonestr; 364 365 for (cp = buf; *cp && isupper(*cp); ++cp) {/*empty*/} 366 if (cp - buf) { 367 zonestr = alloca(cp - buf + 1); 368 strncpy(zonestr, buf, cp - buf); 369 zonestr[cp - buf] = '\0'; 370 tzset(); 371 if (0 == strcmp(zonestr, "GMT")) { 372 got_GMT = 1; 373 } else if (0 == strcmp(zonestr, tzname[0])) { 374 tm->tm_isdst = 0; 375 } else if (0 == strcmp(zonestr, tzname[1])) { 376 tm->tm_isdst = 1; 377 } else { 378 return 0; 379 } 380 buf += cp - buf; 381 } 382 } 383 break; 384 } 385 } 386 return (char *)buf; 387 } 388 389 390 char * 391 strptime(const char *buf, const char *fmt, struct tm *tm) 392 { 393 char *ret; 394 395 #ifdef _THREAD_SAFE 396 pthread_mutex_lock(&gotgmt_mutex); 397 #endif 398 399 got_GMT = 0; 400 ret = _strptime(buf, fmt, tm); 401 if (ret && got_GMT) { 402 time_t t = timegm(tm); 403 localtime_r(&t, tm); 404 got_GMT = 0; 405 } 406 407 #ifdef _THREAD_SAFE 408 pthread_mutex_unlock(&gotgmt_mutex); 409 #endif 410 411 return ret; 412 } 413