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