Print this page
3141 strptime() doesn't support %t
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libc/port/locale/strptime.c
+++ new/usr/src/lib/libc/port/locale/strptime.c
1 1 /*
2 + * Copyright (c) 2014 Gary Mills
2 3 * Copyright 2011, Nexenta Systems, Inc. All rights reserved.
3 4 * Copyright (c) 1994 Powerdog Industries. All rights reserved.
4 5 *
5 6 * Redistribution and use in source and binary forms, with or without
6 7 * modification, are permitted provided that the following conditions
7 8 * are met:
8 9 *
9 10 * 1. Redistributions of source code must retain the above copyright
10 11 * notice, this list of conditions and the following disclaimer.
11 12 *
12 13 * 2. Redistributions in binary form must reproduce the above copyright
13 14 * notice, this list of conditions and the following disclaimer
14 15 * in the documentation and/or other materials provided with the
15 16 * distribution.
16 17 *
17 18 * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY
18 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE
21 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 25 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 27 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 29 *
29 30 * The views and conclusions contained in the software and documentation
30 31 * are those of the authors and should not be interpreted as representing
31 32 * official policies, either expressed or implied, of Powerdog Industries.
32 33 */
33 34
34 35 #include "lint.h"
35 36 #include <time.h>
36 37 #include <ctype.h>
37 38 #include <errno.h>
38 39 #include <stdlib.h>
39 40 #include <string.h>
40 41 #include <pthread.h>
41 42 #include <alloca.h>
42 43 #include "timelocal.h"
43 44
44 45 #define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
45 46
46 47 #define F_GMT (1 << 0)
47 48 #define F_ZERO (1 << 1)
48 49 #define F_RECURSE (1 << 2)
49 50
50 51 static char *
51 52 __strptime(const char *buf, const char *fmt, struct tm *tm, int *flagsp)
52 53 {
53 54 char c;
54 55 const char *ptr;
55 56 int i, len, recurse = 0;
56 57 int Ealternative, Oalternative;
57 58 struct lc_time_T *tptr = __get_current_time_locale();
58 59
59 60 if (*flagsp & F_RECURSE)
60 61 recurse = 1;
61 62 *flagsp |= F_RECURSE;
62 63
63 64 if (*flagsp & F_ZERO)
64 65 (void) memset(tm, 0, sizeof (*tm));
65 66 *flagsp &= ~F_ZERO;
66 67
67 68 ptr = fmt;
68 69 while (*ptr != 0) {
69 70 if (*buf == 0)
70 71 break;
71 72
72 73 c = *ptr++;
73 74
74 75 if (c != '%') {
75 76 if (isspace(c))
76 77 while (isspace(*buf))
77 78 buf++;
78 79 else if (c != *buf++)
79 80 return (NULL);
80 81 continue;
81 82 }
82 83
83 84 Ealternative = 0;
84 85 Oalternative = 0;
85 86 label:
86 87 c = *ptr++;
87 88 switch (c) {
88 89 case 0:
89 90 case '%':
90 91 if (*buf++ != '%')
91 92 return (NULL);
92 93 break;
93 94
94 95 case '+':
95 96 buf = __strptime(buf, tptr->date_fmt, tm, flagsp);
96 97 if (buf == NULL)
97 98 return (NULL);
98 99 break;
99 100
100 101 case 'C':
101 102 if (!isdigit(*buf))
102 103 return (NULL);
103 104
104 105 /* XXX This will break for 3-digit centuries. */
105 106 len = 2;
106 107 for (i = 0; len && isdigit(*buf); buf++) {
107 108 i *= 10;
108 109 i += *buf - '0';
109 110 len--;
110 111 }
111 112 if (i < 19)
112 113 return (NULL);
113 114
114 115 tm->tm_year = i * 100 - 1900;
115 116 break;
116 117
117 118 case 'c':
118 119 buf = __strptime(buf, tptr->c_fmt, tm, flagsp);
119 120 if (buf == NULL)
120 121 return (NULL);
121 122 break;
122 123
123 124 case 'D':
124 125 buf = __strptime(buf, "%m/%d/%y", tm, flagsp);
125 126 if (buf == NULL)
126 127 return (NULL);
127 128 break;
128 129
129 130 case 'E':
130 131 if (Ealternative || Oalternative)
131 132 break;
132 133 Ealternative++;
133 134 goto label;
134 135
135 136 case 'O':
136 137 if (Ealternative || Oalternative)
137 138 break;
138 139 Oalternative++;
139 140 goto label;
140 141
141 142 case 'F':
142 143 buf = __strptime(buf, "%Y-%m-%d", tm, flagsp);
143 144 if (buf == NULL)
144 145 return (NULL);
145 146 break;
146 147
147 148 case 'R':
148 149 buf = __strptime(buf, "%H:%M", tm, flagsp);
149 150 if (buf == NULL)
150 151 return (NULL);
151 152 break;
152 153
153 154 case 'r':
154 155 buf = __strptime(buf, tptr->ampm_fmt, tm, flagsp);
155 156 if (buf == NULL)
156 157 return (NULL);
157 158 break;
158 159
159 160 case 'T':
160 161 buf = __strptime(buf, "%H:%M:%S", tm, flagsp);
161 162 if (buf == NULL)
162 163 return (NULL);
163 164 break;
164 165
165 166 case 'X':
166 167 buf = __strptime(buf, tptr->X_fmt, tm, flagsp);
167 168 if (buf == NULL)
168 169 return (NULL);
169 170 break;
170 171
171 172 case 'x':
172 173 buf = __strptime(buf, tptr->x_fmt, tm, flagsp);
173 174 if (buf == NULL)
174 175 return (NULL);
175 176 break;
176 177
177 178 case 'j':
178 179 if (!isdigit(*buf))
179 180 return (NULL);
180 181
181 182 len = 3;
182 183 for (i = 0; len && isdigit(*buf); buf++) {
183 184 i *= 10;
184 185 i += *buf - '0';
185 186 len--;
186 187 }
187 188 if (i < 1 || i > 366)
188 189 return (NULL);
189 190
190 191 tm->tm_yday = i - 1;
191 192 break;
192 193
193 194 case 'M':
194 195 case 'S':
195 196 if (*buf == 0 || isspace(*buf))
196 197 break;
197 198
198 199 if (!isdigit(*buf))
199 200 return (NULL);
200 201
201 202 len = 2;
202 203 for (i = 0; len && isdigit(*buf); buf++) {
203 204 i *= 10;
204 205 i += *buf - '0';
205 206 len--;
206 207 }
207 208
↓ open down ↓ |
196 lines elided |
↑ open up ↑ |
208 209 if (c == 'M') {
209 210 if (i > 59)
210 211 return (NULL);
211 212 tm->tm_min = i;
212 213 } else {
213 214 if (i > 60)
214 215 return (NULL);
215 216 tm->tm_sec = i;
216 217 }
217 218
218 - if (isspace(*buf))
219 - while (*ptr != 0 && !isspace(*ptr))
220 - ptr++;
221 219 break;
222 220
223 221 case 'H':
224 222 case 'I':
225 223 case 'k':
226 224 case 'l':
227 225 /*
228 226 * Of these, %l is the only specifier explicitly
229 227 * documented as not being zero-padded. However,
230 228 * there is no harm in allowing zero-padding.
231 229 *
232 230 * XXX The %l specifier may gobble one too many
233 231 * digits if used incorrectly.
234 232 */
235 233 if (!isdigit(*buf))
236 234 return (NULL);
237 235
238 236 len = 2;
239 237 for (i = 0; len && isdigit(*buf); buf++) {
240 238 i *= 10;
241 239 i += *buf - '0';
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
242 240 len--;
243 241 }
244 242 if (c == 'H' || c == 'k') {
245 243 if (i > 23)
246 244 return (NULL);
247 245 } else if (i > 12)
248 246 return (NULL);
249 247
250 248 tm->tm_hour = i;
251 249
252 - if (isspace(*buf))
253 - while (*ptr != 0 && !isspace(*ptr))
254 - ptr++;
255 250 break;
256 251
257 252 case 'p':
258 253 /*
259 254 * XXX This is bogus if parsed before hour-related
260 255 * specifiers.
261 256 */
262 257 len = strlen(tptr->am);
263 258 if (strncasecmp(buf, tptr->am, len) == 0) {
264 259 if (tm->tm_hour > 12)
265 260 return (NULL);
266 261 if (tm->tm_hour == 12)
267 262 tm->tm_hour = 0;
268 263 buf += len;
269 264 break;
270 265 }
271 266
272 267 len = strlen(tptr->pm);
273 268 if (strncasecmp(buf, tptr->pm, len) == 0) {
274 269 if (tm->tm_hour > 12)
275 270 return (NULL);
276 271 if (tm->tm_hour != 12)
277 272 tm->tm_hour += 12;
278 273 buf += len;
279 274 break;
280 275 }
281 276
282 277 return (NULL);
283 278
284 279 case 'A':
285 280 case 'a':
286 281 for (i = 0; i < asizeof(tptr->weekday); i++) {
287 282 len = strlen(tptr->weekday[i]);
288 283 if (strncasecmp(buf, tptr->weekday[i], len) ==
289 284 0)
290 285 break;
291 286 len = strlen(tptr->wday[i]);
292 287 if (strncasecmp(buf, tptr->wday[i], len) == 0)
293 288 break;
294 289 }
295 290 if (i == asizeof(tptr->weekday))
296 291 return (NULL);
297 292
298 293 tm->tm_wday = i;
299 294 buf += len;
300 295 break;
301 296
302 297 case 'U':
303 298 case 'W':
304 299 /*
305 300 * XXX This is bogus, as we can not assume any valid
306 301 * information present in the tm structure at this
307 302 * point to calculate a real value, so just check the
308 303 * range for now.
309 304 */
310 305 if (!isdigit(*buf))
311 306 return (NULL);
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
312 307
313 308 len = 2;
314 309 for (i = 0; len && isdigit(*buf); buf++) {
315 310 i *= 10;
316 311 i += *buf - '0';
317 312 len--;
318 313 }
319 314 if (i > 53)
320 315 return (NULL);
321 316
322 - if (isspace(*buf))
323 - while (*ptr != 0 && !isspace(*ptr))
324 - ptr++;
325 317 break;
326 318
327 319 case 'w':
328 320 if (!isdigit(*buf))
329 321 return (NULL);
330 322
331 323 i = *buf - '0';
332 324 if (i > 6)
333 325 return (NULL);
334 326
335 327 tm->tm_wday = i;
336 328
337 - if (isspace(*buf))
338 - while (*ptr != 0 && !isspace(*ptr))
339 - ptr++;
340 329 break;
341 330
331 + case 'd':
342 332 case 'e':
343 333 /*
344 334 * The %e format has a space before single digits
345 335 * which we need to skip.
346 336 */
347 337 if (isspace(*buf))
348 338 buf++;
349 - /* FALLTHROUGH */
350 - case 'd':
351 339 /*
352 340 * The %e specifier is explicitly documented as not
353 341 * being zero-padded but there is no harm in allowing
354 342 * such padding.
355 343 *
356 344 * XXX The %e specifier may gobble one too many
357 345 * digits if used incorrectly.
358 346 */
359 347 if (!isdigit(*buf))
360 348 return (NULL);
361 349
362 350 len = 2;
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
363 351 for (i = 0; len && isdigit(*buf); buf++) {
364 352 i *= 10;
365 353 i += *buf - '0';
366 354 len--;
367 355 }
368 356 if (i > 31)
369 357 return (NULL);
370 358
371 359 tm->tm_mday = i;
372 360
373 - if (isspace(*buf))
374 - while (*ptr != 0 && !isspace(*ptr))
375 - ptr++;
376 361 break;
377 362
378 363 case 'B':
379 364 case 'b':
380 365 case 'h':
381 366 for (i = 0; i < asizeof(tptr->month); i++) {
382 367 len = strlen(tptr->month[i]);
383 368 if (strncasecmp(buf, tptr->month[i], len) == 0)
384 369 break;
385 370 }
386 371 /*
387 372 * Try the abbreviated month name if the full name
388 373 * wasn't found.
389 374 */
390 375 if (i == asizeof(tptr->month)) {
391 376 for (i = 0; i < asizeof(tptr->month); i++) {
392 377 len = strlen(tptr->mon[i]);
393 378 if (strncasecmp(buf, tptr->mon[i],
394 379 len) == 0)
395 380 break;
396 381 }
397 382 }
398 383 if (i == asizeof(tptr->month))
399 384 return (NULL);
400 385
401 386 tm->tm_mon = i;
402 387 buf += len;
403 388 break;
404 389
405 390 case 'm':
406 391 if (!isdigit(*buf))
407 392 return (NULL);
408 393
409 394 len = 2;
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
410 395 for (i = 0; len && isdigit(*buf); buf++) {
411 396 i *= 10;
412 397 i += *buf - '0';
413 398 len--;
414 399 }
415 400 if (i < 1 || i > 12)
416 401 return (NULL);
417 402
418 403 tm->tm_mon = i - 1;
419 404
420 - if (isspace(*buf))
421 - while (*ptr != NULL && !isspace(*ptr))
422 - ptr++;
423 405 break;
424 406
425 407 case 's':
426 408 {
427 409 char *cp;
428 410 int sverrno;
429 411 time_t t;
430 412
431 413 sverrno = errno;
432 414 errno = 0;
433 415 t = strtol(buf, &cp, 10);
434 416 if (errno == ERANGE) {
435 417 errno = sverrno;
436 418 return (NULL);
437 419 }
438 420 errno = sverrno;
439 421 buf = cp;
440 422 (void) gmtime_r(&t, tm);
441 423 *flagsp |= F_GMT;
442 424 }
443 425 break;
444 426
445 427 case 'Y':
446 428 case 'y':
447 429 if (*buf == NULL || isspace(*buf))
448 430 break;
449 431
450 432 if (!isdigit(*buf))
451 433 return (NULL);
452 434
453 435 len = (c == 'Y') ? 4 : 2;
454 436 for (i = 0; len && isdigit(*buf); buf++) {
455 437 i *= 10;
456 438 i += *buf - '0';
457 439 len--;
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
458 440 }
459 441 if (c == 'Y')
460 442 i -= 1900;
461 443 if (c == 'y' && i < 69)
462 444 i += 100;
463 445 if (i < 0)
464 446 return (NULL);
465 447
466 448 tm->tm_year = i;
467 449
468 - if (isspace(*buf))
469 - while (*ptr != 0 && !isspace(*ptr))
470 - ptr++;
471 450 break;
472 451
473 452 case 'Z':
474 453 {
475 454 const char *cp = buf;
476 455 char *zonestr;
477 456
478 457 while (isupper(*cp))
479 458 ++cp;
480 459 if (cp - buf) {
481 460 zonestr = alloca(cp - buf + 1);
482 461 (void) strncpy(zonestr, buf, cp - buf);
483 462 zonestr[cp - buf] = '\0';
484 463 tzset();
485 464 if (strcmp(zonestr, "GMT") == 0) {
486 465 *flagsp |= F_GMT;
487 466 } else if (0 == strcmp(zonestr, tzname[0])) {
488 467 tm->tm_isdst = 0;
489 468 } else if (0 == strcmp(zonestr, tzname[1])) {
490 469 tm->tm_isdst = 1;
491 470 } else {
492 471 return (NULL);
493 472 }
494 473 buf += cp - buf;
495 474 }
496 475 }
497 476 break;
498 477
499 478 case 'z':
500 479 {
501 480 int sign = 1;
502 481
503 482 if (*buf != '+') {
504 483 if (*buf == '-')
505 484 sign = -1;
506 485 else
507 486 return (NULL);
508 487 }
509 488 buf++;
510 489 i = 0;
511 490 for (len = 4; len > 0; len--) {
512 491 if (!isdigit(*buf))
513 492 return (NULL);
↓ open down ↓ |
33 lines elided |
↑ open up ↑ |
514 493 i *= 10;
515 494 i += *buf - '0';
516 495 buf++;
517 496 }
518 497
519 498 tm->tm_hour -= sign * (i / 100);
520 499 tm->tm_min -= sign * (i % 100);
521 500 *flagsp |= F_GMT;
522 501 }
523 502 break;
503 + case 'n':
504 + case 't':
505 + while (isspace(*buf))
506 + buf++;
507 + break;
524 508 }
525 509 }
526 510
527 511 if (!recurse) {
528 512 if (buf && (*flagsp & F_GMT)) {
529 513 time_t t = timegm(tm);
530 514 (void) localtime_r(&t, tm);
531 515 }
532 516 }
533 517
534 518 return ((char *)buf);
535 519 }
536 520
537 521 char *
538 522 strptime(const char *buf, const char *fmt, struct tm *tm)
539 523 {
540 524 int flags = F_ZERO;
541 525
542 526 return (__strptime(buf, fmt, tm, &flags));
543 527 }
544 528
545 529 /*
546 530 * This is used by Solaris, and is a variant that does not clear the
547 531 * incoming tm. It is triggered by -D_STRPTIME_DONTZERO.
548 532 */
549 533 char *
550 534 __strptime_dontzero(const char *buf, const char *fmt, struct tm *tm)
551 535 {
552 536 int flags = 0;
553 537
554 538 return (__strptime(buf, fmt, tm, &flags));
555 539 }
↓ open down ↓ |
22 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX