strptime.c revision 53083
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 55static const char rcsid[] = 56 "$FreeBSD: head/lib/libc/stdtime/strptime.c 53083 1999-11-10 14:40:59Z sheldonh $"; 57#endif 58 59#ifndef lint 60#ifndef NOID 61static char copyright[] = 62"@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; 63static 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 76static char * _strptime(const char *, const char *, struct tm *); 77 78#ifdef _THREAD_SAFE 79static struct pthread_mutex _gotgmt_mutexd = PTHREAD_MUTEX_STATIC_INITIALIZER; 80static pthread_mutex_t gotgmt_mutex = &_gotgmt_mutexd; 81#endif 82static int got_GMT; 83 84#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) 85 86static 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 < 1 || i > 366) 175 return 0; 176 177 tm->tm_yday = i - 1; 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 193 if (c == 'M') { 194 if (i > 59) 195 return 0; 196 tm->tm_min = i; 197 } else { 198 if (i > 60) 199 return 0; 200 tm->tm_sec = i; 201 } 202 203 if (*buf != 0 && isspace((unsigned char)*buf)) 204 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 205 ptr++; 206 break; 207 208 case 'H': 209 case 'I': 210 case 'k': 211 case 'l': 212 if (!isdigit((unsigned char)*buf)) 213 return 0; 214 215 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 216 i *= 10; 217 i += *buf - '0'; 218 } 219 if (c == 'H' || c == 'k') { 220 if (i > 23) 221 return 0; 222 } else if (i > 11) 223 return 0; 224 225 tm->tm_hour = i; 226 227 if (*buf != 0 && isspace((unsigned char)*buf)) 228 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 229 ptr++; 230 break; 231 232 case 'p': 233 len = strlen(Locale->am); 234 if (strncasecmp(buf, Locale->am, len) == 0) { 235 if (tm->tm_hour > 12) 236 return 0; 237 if (tm->tm_hour == 12) 238 tm->tm_hour = 0; 239 buf += len; 240 break; 241 } 242 243 len = strlen(Locale->pm); 244 if (strncasecmp(buf, Locale->pm, len) == 0) { 245 if (tm->tm_hour > 12) 246 return 0; 247 if (tm->tm_hour != 12) 248 tm->tm_hour += 12; 249 buf += len; 250 break; 251 } 252 253 return 0; 254 255 case 'A': 256 case 'a': 257 for (i = 0; i < asizeof(Locale->weekday); i++) { 258 len = strlen(Locale->weekday[i]); 259 if (strncasecmp(buf, 260 Locale->weekday[i], 261 len) == 0) 262 break; 263 264 len = strlen(Locale->wday[i]); 265 if (strncasecmp(buf, 266 Locale->wday[i], 267 len) == 0) 268 break; 269 } 270 if (i == asizeof(Locale->weekday)) 271 return 0; 272 273 tm->tm_wday = i; 274 buf += len; 275 break; 276 277 case 'U': 278 case 'W': 279 /* 280 * XXX This is bogus, as we can not assume any valid 281 * information present in the tm structure at this 282 * point to calculate a real value, so just check the 283 * range for now. 284 */ 285 if (!isdigit((unsigned char)*buf)) 286 return 0; 287 288 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 289 i *= 10; 290 i += *buf - '0'; 291 } 292 if (i > 53) 293 return 0; 294 295 if (*buf != 0 && isspace((unsigned char)*buf)) 296 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 297 ptr++; 298 break; 299 300 case 'w': 301 if (!isdigit((unsigned char)*buf)) 302 return 0; 303 304 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 305 i *= 10; 306 i += *buf - '0'; 307 } 308 if (i > 6) 309 return 0; 310 311 tm->tm_wday = i; 312 313 if (*buf != 0 && isspace((unsigned char)*buf)) 314 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 315 ptr++; 316 break; 317 318 case 'd': 319 case 'e': 320 if (!isdigit((unsigned char)*buf)) 321 return 0; 322 323 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 324 i *= 10; 325 i += *buf - '0'; 326 } 327 if (i > 31) 328 return 0; 329 330 tm->tm_mday = i; 331 332 if (*buf != 0 && isspace((unsigned char)*buf)) 333 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 334 ptr++; 335 break; 336 337 case 'B': 338 case 'b': 339 case 'h': 340 for (i = 0; i < asizeof(Locale->month); i++) { 341 len = strlen(Locale->month[i]); 342 if (strncasecmp(buf, 343 Locale->month[i], 344 len) == 0) 345 break; 346 347 len = strlen(Locale->mon[i]); 348 if (strncasecmp(buf, 349 Locale->mon[i], 350 len) == 0) 351 break; 352 } 353 if (i == asizeof(Locale->month)) 354 return 0; 355 356 tm->tm_mon = i; 357 buf += len; 358 break; 359 360 case 'm': 361 if (!isdigit((unsigned char)*buf)) 362 return 0; 363 364 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 365 i *= 10; 366 i += *buf - '0'; 367 } 368 if (i < 1 || i > 12) 369 return 0; 370 371 tm->tm_mon = i - 1; 372 373 if (*buf != 0 && isspace((unsigned char)*buf)) 374 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 375 ptr++; 376 break; 377 378 case 'Y': 379 case 'y': 380 if (*buf == 0 || isspace((unsigned char)*buf)) 381 break; 382 383 if (!isdigit((unsigned char)*buf)) 384 return 0; 385 386 for (i = 0; *buf != 0 && isdigit((unsigned char)*buf); buf++) { 387 i *= 10; 388 i += *buf - '0'; 389 } 390 if (c == 'Y') 391 i -= 1900; 392 if (c == 'y' && i < 69) 393 i += 100; 394 if (i < 0) 395 return 0; 396 397 tm->tm_year = i; 398 399 if (*buf != 0 && isspace((unsigned char)*buf)) 400 while (*ptr != 0 && !isspace((unsigned char)*ptr)) 401 ptr++; 402 break; 403 404 case 'Z': 405 { 406 const char *cp; 407 char *zonestr; 408 409 for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/} 410 if (cp - buf) { 411 zonestr = alloca(cp - buf + 1); 412 strncpy(zonestr, buf, cp - buf); 413 zonestr[cp - buf] = '\0'; 414 tzset(); 415 if (0 == strcmp(zonestr, "GMT")) { 416 got_GMT = 1; 417 } else if (0 == strcmp(zonestr, tzname[0])) { 418 tm->tm_isdst = 0; 419 } else if (0 == strcmp(zonestr, tzname[1])) { 420 tm->tm_isdst = 1; 421 } else { 422 return 0; 423 } 424 buf += cp - buf; 425 } 426 } 427 break; 428 } 429 } 430 return (char *)buf; 431} 432 433 434char * 435strptime(const char *buf, const char *fmt, struct tm *tm) 436{ 437 char *ret; 438 439#ifdef _THREAD_SAFE 440 pthread_mutex_lock(&gotgmt_mutex); 441#endif 442 443 got_GMT = 0; 444 ret = _strptime(buf, fmt, tm); 445 if (ret && got_GMT) { 446 time_t t = timegm(tm); 447 localtime_r(&t, tm); 448 got_GMT = 0; 449 } 450 451#ifdef _THREAD_SAFE 452 pthread_mutex_unlock(&gotgmt_mutex); 453#endif 454 455 return ret; 456} 457