1 /* Copyright (C) 2002-2004 Manuel Novoa III <mjn3@codepoet.org>
2 *
3 * GNU Library General Public License (LGPL) version 2 or later.
4 *
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
7
8 /* June 15, 2002 Initial Notes:
9 *
10 * Note: It is assumed throught that time_t is either long or unsigned long.
11 * Similarly, clock_t is assumed to be long int.
12 *
13 * Warning: Assumptions are made about the layout of struct tm! It is
14 * assumed that the initial fields of struct tm are (in order):
15 * tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday, tm_yday
16 *
17 * Reached the inital goal of supporting the ANSI/ISO C99 time functions
18 * as well as SUSv3's strptime. All timezone info is obtained from the
19 * TZ env variable.
20 *
21 * Differences from glibc worth noting:
22 *
23 * Leap seconds are not considered here.
24 *
25 * glibc stores additional timezone info the struct tm, whereas we don't.
26 *
27 * Alternate digits and era handling are not currently implemented.
28 * The modifiers are accepted, and tested for validity with the following
29 * specifier, but are ignored otherwise.
30 *
31 * strftime does not implement glibc extension modifiers or widths for
32 * conversion specifiers. However it does implement the glibc
33 * extension specifiers %l, %k, and %s. It also recognizes %P, but
34 * treats it as a synonym for %p; i.e. doesn't convert to lower case.
35 *
36 * strptime implements the glibc extension specifiers. However, it follows
37 * SUSv3 in requiring at least one non-alphanumeric char between
38 * conversion specifiers. Also, strptime only sets struct tm fields
39 * for which format specifiers appear and does not try to infer other
40 * fields (such as wday) as glibc's version does.
41 *
42 * TODO - Since glibc's %l and %k can space-pad their output in strftime,
43 * it might be reasonable to eat whitespace first for those specifiers.
44 * This could be done by pushing " %I" and " %H" respectively so that
45 * leading whitespace is consumed. This is really only an issue if %l
46 * or %k occurs at the start of the format string.
47 *
48 * TODO - Implement getdate? tzfile? struct tm extensions?
49 *
50 * TODO - Rework _time_mktime to remove the dependency on long long.
51 */
52
53 /* Oct 28, 2002
54 *
55 * Fixed allowed char check for std and dst TZ fields.
56 *
57 * Added several options concerned with timezone support. The names will
58 * probably change once Erik gets the new config system in place.
59 *
60 * Defining __TIME_TZ_FILE causes tzset() to attempt to read the TZ value
61 * from the file /etc/TZ if the TZ env variable isn't set. The file contents
62 * must be the intended value of TZ, followed by a newline. No other chars,
63 * spacing, etc is allowed. As an example, an easy way for me to init
64 * /etc/TZ appropriately would be: echo CST6CDT > /etc/TZ
65 *
66 * Defining __TIME_TZ_FILE_ONCE will cause all further accesses of /etc/TZ
67 * to be skipped once a legal value has been read.
68 *
69 * Defining __TIME_TZ_OPT_SPEED will cause a tzset() to keep a copy of the
70 * last TZ setting string and do a "fast out" if the current string is the
71 * same.
72 *
73 * Nov 21, 2002 Fix an error return case in _time_mktime.
74 *
75 * Nov 26, 2002 Fix bug in setting daylight and timezone when no (valid) TZ.
76 * Bug reported by Arne Bernin <arne@alamut.de> in regards to freeswan.
77 *
78 * July 27, 2003 Adjust the struct tm extension field support.
79 * Change __tm_zone back to a ptr and add the __tm_tzname[] buffer for
80 * __tm_zone to point to. This gets around complaints from g++.
81 * Who knows... it might even fix the PPC timezone init problem.
82 *
83 * July 29, 2003 Fix a bug in mktime behavior when tm_isdst was -1.
84 * Bug reported by "Sid Wade" <sid@vivato.net> in regards to busybox.
85 *
86 * NOTE: uClibc mktime behavior is different than glibc's when
87 * the struct tm has tm_isdst == -1 and also had fields outside of
88 * the normal ranges.
89 *
90 * Apparently, glibc examines (at least) tm_sec and guesses the app's
91 * intention of assuming increasing or decreasing time when entering an
92 * ambiguous time period at the dst<->st boundaries.
93 *
94 * The uClibc behavior is to always normalize the struct tm and then
95 * try to determing the dst setting.
96 *
97 * As long as tm_isdst != -1 or the time specifiec by struct tm is
98 * unambiguous (not falling in the dst<->st transition region) both
99 * uClibc and glibc should produce the same result for mktime.
100 *
101 * Oct 31, 2003 Kill the seperate __tm_zone and __tm_tzname[] and which
102 * doesn't work if you want the memcpy the struct. Sigh... I didn't
103 * think about that. So now, when the extensions are enabled, we
104 * malloc space when necessary and keep the timezone names in a linked
105 * list.
106 *
107 * Fix a dst-related bug which resulted in use of uninitialized data.
108 *
109 * Nov 15, 2003 I forgot to update the thread locking in the last dst fix.
110 *
111 * Dec 14, 2003 Fix some dst issues in _time_mktime().
112 * Normalize the tm_isdst value to -1, 0, or 1.
113 * If no dst for this timezone, then reset tm_isdst to 0.
114 *
115 * May 7, 2004
116 * Change clock() to allow wrapping.
117 * Add timegm() function.
118 * Make lookup_tzname() static (as it should have been).
119 * Have strftime() get timezone information from the passed struct
120 * for the %z and %Z conversions when using struct tm extensions.
121 *
122 * Jul 24, 2004
123 * Fix 2 bugs in strftime related to glibc struct tm extensions.
124 * 1) Need to negate tm_gmtoff field value when used. (bug 336).
125 * 2) Deal with NULL ptr case for tm_zone field, which was causing
126 * segfaults in both the NIST/PCTS tests and the Python 2.4.1
127 * self-test suite.
128 * NOTE: We set uninitialized timezone names to "???", and this
129 * differs (intentionally) from glibc's behavior.
130 */
131
132 #include <stdio.h>
133 #include <stdlib.h>
134 #include <stddef.h>
135 #include <string.h>
136 #include <time.h>
137 #include <sys/time.h>
138 #include <limits.h>
139 #include <assert.h>
140 #include <errno.h>
141 #include <ctype.h>
142 #include <langinfo.h>
143 #include <locale.h>
144 #include <fcntl.h>
145 #include <unistd.h>
146 #include <bits/uClibc_uintmaxtostr.h>
147 #include <bits/uClibc_mutex.h>
148
149 #ifdef __UCLIBC_HAS_WCHAR__
150 #include <wchar.h>
151 #endif
152
153 #ifndef __isleap
154 #define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
155 #endif
156
157 #ifndef TZNAME_MAX
158 #define TZNAME_MAX _POSIX_TZNAME_MAX
159 #endif
160
161 #if defined (L_tzset) || defined (L_localtime_r) || defined(L_strftime) || \
162 defined(L__time_mktime) || defined(L__time_mktime_tzi) || \
163 ((defined(L_strftime) || defined(L_strftime_l)) && \
164 defined(__UCLIBC_HAS_XLOCALE__))
165
166 void _time_tzset(int use_old_rules) attribute_hidden;
167
168 #ifndef L__time_mktime
169
170 /* Jan 1, 2007 Z - tm = 0,0,0,1,0,107,1,0,0 */
171
172 static const time_t new_rule_starts = 1167609600;
173
174 #endif
175 #endif
176
177 /**********************************************************************/
178 /* The era code is currently unfinished. */
179 /* #define ENABLE_ERA_CODE */
180
181 #define TZ_BUFLEN (2*TZNAME_MAX + 56)
182
183 #ifdef __UCLIBC_HAS_TZ_FILE__
184
185 #include <sys/stat.h>
186 #include "paths.h"
187 /* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
188 /* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
189
190 #else /* __UCLIBC_HAS_TZ_FILE__ */
191
192 /* Probably no longer needed. */
193 #undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
194
195 #endif /* __UCLIBC_HAS_TZ_FILE__ */
196
197 /**********************************************************************/
198
199 extern struct tm __time_tm attribute_hidden;
200
201 typedef struct {
202 long gmt_offset;
203 long dst_offset;
204 short day; /* for J or normal */
205 short week;
206 short month;
207 short rule_type; /* J, M, \0 */
208 char tzname[TZNAME_MAX+1];
209 } rule_struct;
210
211 __UCLIBC_MUTEX_EXTERN(_time_tzlock) attribute_hidden;
212
213 extern rule_struct _time_tzinfo[2] attribute_hidden;
214
215 extern struct tm *_time_t2tm(const time_t *__restrict timer,
216 int offset, struct tm *__restrict result) attribute_hidden;
217
218 extern time_t _time_mktime(struct tm *timeptr, int store_on_success) attribute_hidden;
219
220 extern struct tm *__time_localtime_tzi(const time_t *__restrict timer,
221 struct tm *__restrict result,
222 rule_struct *tzi) attribute_hidden;
223
224 extern time_t _time_mktime_tzi(struct tm *timeptr, int store_on_success,
225 rule_struct *tzi) attribute_hidden;
226
227 /**********************************************************************/
228 #ifdef L_asctime
229
230 static char __time_str[26];
231
asctime(const struct tm * ptm)232 char *asctime(const struct tm *ptm)
233 {
234 return asctime_r(ptm, __time_str);
235 }
236 libc_hidden_def(asctime)
237
238 #endif
239 /**********************************************************************/
240 #ifdef L_asctime_r
241
242 /* Strictly speaking, this implementation isn't correct. ANSI/ISO specifies
243 * that the implementation of asctime() be equivalent to
244 *
245 * char *asctime(const struct tm *timeptr)
246 * {
247 * static char wday_name[7][3] = {
248 * "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
249 * };
250 * static char mon_name[12][3] = {
251 * "Jan", "Feb", "Mar", "Apr", "May", "Jun",
252 * "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
253 * };
254 * static char result[26];
255 *
256 * sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
257 * wday_name[timeptr->tm_wday],
258 * mon_name[timeptr->tm_mon],
259 * timeptr->tm_mday, timeptr->tm_hour,
260 * timeptr->tm_min, timeptr->tm_sec,
261 * 1900 + timeptr->tm_year);
262 * return result;
263 * }
264 *
265 * but the above is either inherently unsafe, or carries with it the implicit
266 * assumption that all fields of timeptr fall within their usual ranges, and
267 * that the tm_year value falls in the range [-2899,8099] to avoid overflowing
268 * the static buffer.
269 *
270 * If we take the implicit assumption as given, then the implementation below
271 * is still incorrect for tm_year values < -900, as there will be either
272 * 0-padding and/or a missing negative sign for the year conversion . But given
273 * the usual use of asctime(), I think it isn't unreasonable to restrict correct
274 * operation to the domain of years between 1000 and 9999.
275 */
276
277 /* This is generally a good thing, but if you're _sure_ any data passed will be
278 * in range, you can #undef this. */
279 #define SAFE_ASCTIME_R 1
280
281 static const unsigned char at_data[] = {
282 'S', 'u', 'n', 'M', 'o', 'n', 'T', 'u', 'e', 'W', 'e', 'd',
283 'T', 'h', 'u', 'F', 'r', 'i', 'S', 'a', 't',
284
285 'J', 'a', 'n', 'F', 'e', 'b', 'M', 'a', 'r', 'A', 'p', 'r',
286 'M', 'a', 'y', 'J', 'u', 'n', 'J', 'u', 'l', 'A', 'u', 'g',
287 'S', 'e', 'p', 'O', 'c', 't', 'N', 'o', 'v', 'D', 'e', 'c',
288
289 #ifdef SAFE_ASCTIME_R
290 '?', '?', '?',
291 #endif
292 ' ', '?', '?', '?',
293 ' ', '0',
294 offsetof(struct tm, tm_mday),
295 ' ', '0',
296 offsetof(struct tm, tm_hour),
297 ':', '0',
298 offsetof(struct tm, tm_min),
299 ':', '0',
300 offsetof(struct tm, tm_sec),
301 ' ', '?', '?', '?', '?', '\n', 0
302 };
303
asctime_r(register const struct tm * __restrict ptm,register char * __restrict buffer)304 char *asctime_r(register const struct tm *__restrict ptm,
305 register char *__restrict buffer)
306 {
307 int tmp;
308
309 assert(ptm);
310 assert(buffer);
311
312 #ifdef SAFE_ASCTIME_R
313 memcpy(buffer, at_data + 3*(7 + 12), sizeof(at_data) - 3*(7 + 12));
314
315 if (((unsigned int)(ptm->tm_wday)) <= 6) {
316 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
317 }
318
319 if (((unsigned int)(ptm->tm_mon)) <= 11) {
320 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
321 }
322 #else
323 assert(((unsigned int)(ptm->tm_wday)) <= 6);
324 assert(((unsigned int)(ptm->tm_mon)) <= 11);
325
326 memcpy(buffer, at_data + 3*(7 + 12) - 3, sizeof(at_data) + 3 - 3*(7 + 12));
327
328 memcpy(buffer, at_data + 3 * ptm->tm_wday, 3);
329 memcpy(buffer + 4, at_data + 3*7 + 3 * ptm->tm_mon, 3);
330 #endif
331
332 #ifdef SAFE_ASCTIME_R
333 buffer += 19;
334 tmp = ptm->tm_year + 1900;
335 if (((unsigned int) tmp) < 10000) {
336 buffer += 4;
337 do {
338 *buffer = '0' + (tmp % 10);
339 tmp /= 10;
340 } while (*--buffer == '?');
341 }
342 /* Not sure if we should even bother ...
343 } else {
344 __set_errno(EOVERFLOW);
345 return NULL;
346 }
347 */
348 #else /* SAFE_ASCTIME_R */
349 buffer += 23;
350 tmp = ptm->tm_year + 1900;
351 assert( ((unsigned int) tmp) < 10000 );
352 /* Not sure if we should even bother ...
353 if ( ((unsigned int) tmp) >= 10000 ) {
354 __set_errno(EOVERFLOW);
355 return NULL;
356 }
357 */
358 do {
359 *buffer = '0' + (tmp % 10);
360 tmp /= 10;
361 } while (*--buffer == '?');
362 #endif /* SAFE_ASCTIME_R */
363
364 do {
365 --buffer;
366 tmp = *((int *)(((const char *) ptm) + (int) *buffer));
367 #ifdef SAFE_ASCTIME_R
368 if (((unsigned int) tmp) >= 100) { /* Just check 2 digit non-neg. */
369 buffer[-1] = *buffer = '?';
370 } else
371 #else
372 assert(((unsigned int) tmp) < 100); /* Just check 2 digit non-neg. */
373 #endif
374 {
375 *buffer = '0' + (tmp % 10);
376 #ifdef __BCC__
377 buffer[-1] = '0' + (tmp/10);
378 #else
379 buffer[-1] += (tmp/10);
380 #endif
381 }
382 } while ((buffer -= 2)[-2] == '0');
383
384 if (*++buffer == '0') { /* Space-pad day of month. */
385 *buffer = ' ';
386 }
387
388 return buffer - 8;
389 }
libc_hidden_def(asctime_r)390 libc_hidden_def(asctime_r)
391
392 #endif
393 /**********************************************************************/
394 #ifdef L_clock
395
396 #include <sys/times.h>
397
398 #ifndef __BCC__
399 #if CLOCKS_PER_SEC != 1000000L
400 #error unexpected value for CLOCKS_PER_SEC!
401 #endif
402 #endif
403
404 #ifdef __UCLIBC_CLK_TCK_CONST
405 # if __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC
406 # error __UCLIBC_CLK_TCK_CONST > CLOCKS_PER_SEC!
407 # elif __UCLIBC_CLK_TCK_CONST < 1
408 # error __UCLIBC_CLK_TCK_CONST < 1!
409 # endif
410 #endif
411
412 /* Note: SUSv3 notes
413 *
414 * On XSI-conformant systems, CLOCKS_PER_SEC is defined to be one million.
415 *
416 * The value returned by clock() may wrap around on some implementations.
417 * For example, on a machine with 32-bit values for clock_t, it wraps
418 * after 2147 seconds.
419 *
420 * This implies that we should bitwise and with LONG_MAX.
421 */
422
423 clock_t clock(void)
424 {
425 struct tms xtms;
426 unsigned long t;
427
428 times(&xtms);
429
430 t = ((unsigned long) xtms.tms_utime) + xtms.tms_stime;
431
432 #ifndef __UCLIBC_CLK_TCK_CONST
433
434 # error __UCLIBC_CLK_TCK_CONST not defined!
435
436 #elif ((CLOCKS_PER_SEC % __UCLIBC_CLK_TCK_CONST) == 0)
437
438 /* CLOCKS_PER_SEC == k * __UCLIBC_CLK_TCK_CONST for some integer k >= 1. */
439 return ((t * (CLOCKS_PER_SEC/__UCLIBC_CLK_TCK_CONST)) & LONG_MAX);
440
441 #else
442
443 /* Unlike the previous case, the scaling factor is not an integer.
444 * So when tms_utime, tms_stime, or their sum wraps, some of the
445 * "visible" bits in the return value are affected. Nothing we
446 * can really do about this though other than handle tms_utime and
447 * tms_stime seperately and then sum. But since that doesn't really
448 * buy us much, we don't bother. */
449
450 return ((((t / __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
451 + ((((t % __UCLIBC_CLK_TCK_CONST) * CLOCKS_PER_SEC)
452 / __UCLIBC_CLK_TCK_CONST))
453 ) & LONG_MAX);
454
455 #endif
456 }
457
458 #endif
459 /**********************************************************************/
460 #ifdef L_ctime
461
ctime(const time_t * t)462 char *ctime(const time_t *t)
463 {
464 /* ANSI/ISO/SUSv3 say that ctime is equivalent to the following:
465 * return asctime(localtime(t));
466 * I don't think "equivalent" means "it uses the same internal buffer",
467 * it means "gives the same resultant string".
468 *
469 * I doubt anyone ever uses weird code like:
470 * struct tm *ptm = localtime(t1); ...; ctime(t2); use(ptm);
471 * which relies on the assumption that ctime's and localtime's
472 * internal static struct tm is the same.
473 *
474 * Using localtime_r instead of localtime avoids linking in
475 * localtime's static buffer:
476 */
477 struct tm xtm;
478 memset(&xtm, 0, sizeof(xtm));
479
480 return asctime(localtime_r(t, &xtm));
481 }
libc_hidden_def(ctime)482 libc_hidden_def(ctime)
483 #endif
484 /**********************************************************************/
485 #ifdef L_ctime_r
486
487 char *ctime_r(const time_t *t, char *buf)
488 {
489 struct tm xtm;
490
491 return asctime_r(localtime_r(t, &xtm), buf);
492 }
493
494 #endif
495 /**********************************************************************/
496 #ifdef L_difftime
497
498 #include <float.h>
499
500 #if FLT_RADIX != 2
501 #error difftime implementation assumptions violated for you arch!
502 #endif
503
difftime(time_t time1,time_t time0)504 double difftime(time_t time1, time_t time0)
505 {
506 #if (LONG_MAX >> DBL_MANT_DIG) == 0
507
508 /* time_t fits in the mantissa of a double. */
509 return (double)time1 - (double)time0;
510
511 #elif ((LONG_MAX >> DBL_MANT_DIG) >> DBL_MANT_DIG) == 0
512
513 /* time_t can overflow the mantissa of a double. */
514 time_t t1, t0, d;
515
516 d = ((time_t) 1) << DBL_MANT_DIG;
517 t1 = time1 / d;
518 time1 -= (t1 * d);
519 t0 = time0 / d;
520 time0 -= (t0*d);
521
522 /* Since FLT_RADIX==2 and d is a power of 2, the only possible
523 * rounding error in the expression below would occur from the
524 * addition. */
525 return (((double) t1) - t0) * d + (((double) time1) - time0);
526
527 #else
528 #error difftime needs special implementation on your arch.
529 #endif
530 }
531
532 #endif
533 /**********************************************************************/
534 #ifdef L_gmtime
535
gmtime(const time_t * timer)536 struct tm *gmtime(const time_t *timer)
537 {
538 register struct tm *ptm = &__time_tm;
539
540 _time_t2tm(timer, 0, ptm); /* Can return NULL... */
541
542 return ptm;
543 }
544
545 #endif
546 /**********************************************************************/
547 #ifdef L_gmtime_r
548
gmtime_r(const time_t * __restrict timer,struct tm * __restrict result)549 struct tm *gmtime_r(const time_t *__restrict timer,
550 struct tm *__restrict result)
551 {
552 return _time_t2tm(timer, 0, result);
553 }
554
555 #endif
556 /**********************************************************************/
557 #ifdef L_localtime
558
localtime(const time_t * timer)559 struct tm *localtime(const time_t *timer)
560 {
561 register struct tm *ptm = &__time_tm;
562
563 /* In this implementation, tzset() is called by localtime_r(). */
564
565 localtime_r(timer, ptm); /* Can return NULL... */
566
567 return ptm;
568 }
libc_hidden_def(localtime)569 libc_hidden_def(localtime)
570
571 #endif
572 /**********************************************************************/
573 #ifdef L_localtime_r
574
575 struct tm *localtime_r(register const time_t *__restrict timer,
576 register struct tm *__restrict result)
577 {
578 __UCLIBC_MUTEX_LOCK(_time_tzlock);
579
580 _time_tzset(*timer < new_rule_starts);
581
582 __time_localtime_tzi(timer, result, _time_tzinfo);
583
584 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
585
586 return result;
587 }
588 libc_hidden_def(localtime_r)
589
590 #endif
591 /**********************************************************************/
592 #ifdef L__time_localtime_tzi
593
594 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
595
596 struct ll_tzname_item;
597
598 typedef struct ll_tzname_item {
599 struct ll_tzname_item *next;
600 char tzname[1];
601 } ll_tzname_item_t;
602
603 /* Structures form a list "UTC" -> "???" -> "tzname1" -> "tzname2"... */
604 static struct {
605 struct ll_tzname_item *next;
606 char tzname[4];
607 } ll_tzname_UNKNOWN = { NULL, "???" };
608 static const struct {
609 struct ll_tzname_item *next;
610 char tzname[4];
611 } ll_tzname_UTC = { (void*)&ll_tzname_UNKNOWN, "UTC" };
612
lookup_tzname(const char * key)613 static const char *lookup_tzname(const char *key)
614 {
615 int len;
616 ll_tzname_item_t *p = (void*) &ll_tzname_UTC;
617
618 do {
619 if (strcmp(p->tzname, key) == 0)
620 return p->tzname;
621 p = p->next;
622 } while (p != NULL);
623
624 /* Hmm... a new name. */
625 len = strnlen(key, TZNAME_MAX+1);
626 if (len < TZNAME_MAX+1) { /* Verify legal length */
627 p = malloc(sizeof(ll_tzname_item_t) + len);
628 if (p != NULL) {
629 /* Insert as 3rd item in the list. */
630 p->next = ll_tzname_UNKNOWN.next;
631 ll_tzname_UNKNOWN.next = p;
632 return strcpy(p->tzname, key);
633 }
634 }
635
636 /* Either invalid or couldn't alloc. */
637 return ll_tzname_UNKNOWN.tzname;
638 }
639
640 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
641
642 static const unsigned char day_cor[] = { /* non-leap */
643 31, 31, 34, 34, 35, 35, 36, 36, 36, 37, 37, 38, 38
644 /* 0, 0, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7 */
645 /* 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */
646 };
647
648 /* Note: timezone locking is done by localtime_r. */
649
tm_isdst(register const struct tm * __restrict ptm,register rule_struct * r)650 static int tm_isdst(register const struct tm *__restrict ptm,
651 register rule_struct *r)
652 {
653 long sec;
654 int i, isdst, isleap, day, day0, monlen, mday;
655 int oday = oday; /* ok to be uninitialized, shutting up compiler warning */
656
657 isdst = 0;
658 if (r[1].tzname[0] != 0) {
659 /* First, get the current seconds offset from the start of the year.
660 * Fields of ptm are assumed to be in their normal ranges. */
661 sec = ptm->tm_sec
662 + 60 * (ptm->tm_min
663 + 60 * (long)(ptm->tm_hour
664 + 24 * ptm->tm_yday));
665 /* Do some prep work. */
666 i = (ptm->tm_year % 400) + 1900; /* Make sure we don't overflow. */
667 isleap = __isleap(i);
668 --i;
669 day0 = (1
670 + i /* Normal years increment 1 wday. */
671 + (i/4)
672 - (i/100)
673 + (i/400) ) % 7;
674 i = 0;
675 do {
676 day = r->day; /* Common for 'J' and # case. */
677 if (r->rule_type == 'J') {
678 if (!isleap || (day < (31+29))) {
679 --day;
680 }
681 } else if (r->rule_type == 'M') {
682 /* Find 0-based day number for 1st of the month. */
683 day = 31 * r->month - day_cor[r->month - 1];
684 if (isleap && (day >= 59)) {
685 ++day;
686 }
687 monlen = 31 + day_cor[r->month - 1] - day_cor[r->month];
688 if (isleap && (r->month == 2)) {
689 ++monlen;
690 }
691 /* Weekday (0 is Sunday) of 1st of the month
692 * is (day0 + day) % 7. */
693 mday = r->day - ((day0 + day) % 7);
694 if (mday >= 0) {
695 mday -= 7; /* Back up into prev month since r->week > 0. */
696 }
697 mday += 7 * r->week;
698 if (mday >= monlen) {
699 mday -= 7;
700 }
701 /* So, 0-based day number is... */
702 day += mday;
703 }
704
705 if (i != 0) {
706 /* Adjust sec since dst->std change time is in dst. */
707 sec += (r[-1].gmt_offset - r->gmt_offset);
708 if (oday > day) {
709 ++isdst; /* Year starts in dst. */
710 }
711 }
712 oday = day;
713
714 /* Now convert day to seconds and add offset and compare. */
715 if (sec >= (day * 86400L) + r->dst_offset) {
716 ++isdst;
717 }
718 ++r;
719 } while (++i < 2);
720 }
721
722 return (isdst & 1);
723 }
724
__time_localtime_tzi(register const time_t * __restrict timer,register struct tm * __restrict result,rule_struct * tzi)725 struct tm attribute_hidden *__time_localtime_tzi(register const time_t *__restrict timer,
726 register struct tm *__restrict result,
727 rule_struct *tzi)
728 {
729 time_t x[1];
730 long offset;
731 int days, dst;
732
733 dst = 0;
734 do {
735 days = -7;
736 offset = 604800L - tzi[dst].gmt_offset;
737 if (*timer > (LONG_MAX - 604800L)) {
738 days = -days;
739 offset = -offset;
740 }
741 *x = *timer + offset;
742
743 _time_t2tm(x, days, result);
744 result->tm_isdst = dst;
745 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
746 # ifdef __USE_BSD
747 result->tm_gmtoff = - tzi[dst].gmt_offset;
748 result->tm_zone = lookup_tzname(tzi[dst].tzname);
749 # else
750 result->__tm_gmtoff = - tzi[dst].gmt_offset;
751 result->__tm_zone = lookup_tzname(tzi[dst].tzname);
752 # endif
753 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
754 } while ((++dst < 2)
755 && ((result->tm_isdst = tm_isdst(result, tzi)) != 0));
756
757 return result;
758 }
759
760 #endif
761 /**********************************************************************/
762 #ifdef L_mktime
763
mktime(struct tm * timeptr)764 time_t mktime(struct tm *timeptr)
765 {
766 return _time_mktime(timeptr, 1);
767 }
768
769 /* Another name for `mktime'. */
770 /* time_t timelocal(struct tm *tp) */
strong_alias(mktime,timelocal)771 strong_alias(mktime,timelocal)
772
773 #endif
774 /**********************************************************************/
775 #ifdef L_timegm
776 /* Like `mktime' but timeptr represents Universal Time, not local time. */
777
778 time_t timegm(struct tm *timeptr)
779 {
780 rule_struct gmt_tzinfo[2];
781
782 memset(gmt_tzinfo, 0, sizeof(gmt_tzinfo));
783 strcpy(gmt_tzinfo[0].tzname, "GMT"); /* Match glibc behavior here. */
784
785 return _time_mktime_tzi(timeptr, 1, gmt_tzinfo);
786 }
787
788 #endif
789 /**********************************************************************/
790 #if defined(L_strftime) || defined(L_strftime_l)
791
792 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
793
strftime(char * __restrict s,size_t maxsize,const char * __restrict format,const struct tm * __restrict timeptr)794 size_t strftime(char *__restrict s, size_t maxsize,
795 const char *__restrict format,
796 const struct tm *__restrict timeptr)
797 {
798 return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
799 }
800
801 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
802
803 #define NO_E_MOD 0x80
804 #define NO_O_MOD 0x40
805
806 #define ILLEGAL_SPEC 0x3f
807
808 #define INT_SPEC 0x00 /* must be 0x00!! */
809 #define STRING_SPEC 0x10 /* must be 0x10!! */
810 #define CALC_SPEC 0x20
811 #define STACKED_SPEC 0x30
812
813 #define MASK_SPEC 0x30
814
815 /* Compatibility:
816 *
817 * No alternate digit (%O?) handling. Always uses 0-9.
818 * Alternate locale format (%E?) handling is broken for nontrivial ERAs.
819 * glibc's %P is currently faked by %p. This means it doesn't do lower case.
820 * glibc's %k, %l, and %s are handled.
821 * glibc apparently allows (and ignores) extraneous 'E' and 'O' modifiers,
822 * while they are flagged as illegal conversions here.
823 */
824
825 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
826 static const unsigned char spec[] = {
827 /* A */ 0x03 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
828 /* B */ 0x04 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
829 /* C */ 0x0a | INT_SPEC | NO_O_MOD,
830 /* D */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
831 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
832 /* F */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
833 /* G */ 0x03 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
834 /* H */ 0x0b | INT_SPEC | NO_E_MOD,
835 /* I */ 0x0c | INT_SPEC | NO_E_MOD,
836 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
837 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
838 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
839 /* M */ 0x0d | INT_SPEC | NO_E_MOD,
840 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
841 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
842 /* P */ 0x05 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc ; use %p */
843 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
844 /* R */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
845 /* S */ 0x0e | INT_SPEC | NO_E_MOD,
846 /* T */ 0x05 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
847 /* U */ 0x04 | CALC_SPEC | NO_E_MOD,
848 /* V */ 0x05 | CALC_SPEC | NO_E_MOD,
849 /* W */ 0x06 | CALC_SPEC | NO_E_MOD,
850 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
851 /* Y */ 0x0f | INT_SPEC | NO_O_MOD,
852 /* Z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
853 '?', /* 26 */
854 '?', /* 27 */
855 '?', /* 28 */
856 '?', /* 29 */
857 0, /* 30 */
858 0, /* 31 */
859 /* a */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
860 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
861 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
862 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
863 /* e */ 0x01 | INT_SPEC | NO_E_MOD,
864 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
865 /* g */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
866 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* same as b */
867 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
868 /* j */ 0x08 | INT_SPEC | NO_E_MOD | NO_O_MOD,
869 /* k */ 0x03 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
870 /* l */ 0x04 | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
871 /* m */ 0x05 | INT_SPEC | NO_E_MOD,
872 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
873 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
874 /* p */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
875 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
876 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
877 /* s */ 0x07 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
878 /* t */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
879 /* u */ 0x07 | INT_SPEC | NO_E_MOD,
880 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
881 /* w */ 0x02 | INT_SPEC | NO_E_MOD,
882 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
883 /* y */ 0x09 | INT_SPEC,
884 /* z */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD,
885
886
887 /* WARNING!!! These are dependent on the layout of struct tm!!! */
888 #define FIELD_MAX (26+6+26)
889 60 /* 61? */, 59, 23, 31, 11, 0 /* 9999 */, 6, 0 /* 365 */,
890
891 #define TP_OFFSETS (FIELD_MAX+8)
892 3, /* d */
893 3, /* e */
894 6, /* w */
895 2, /* k */
896 2, /* l */
897 4, /* m */
898 0, /* CURRENTLY UNUSED */
899 /* NOTE: u,j,y order must be preserved as 6,7,5 seq is used in the code! */
900 #define CALC_OFFSETS (TP_OFFSETS + 7)
901 6, /* u */
902 7, /* j */
903 5, /* y */
904 5, /* C */
905 2, /* H */
906 2, /* I */
907 1, /* M */
908 0, /* S */
909 5, /* Y */
910 6, /* a */
911 4, /* b, h */
912 2, /* p */
913 6, /* A */
914 4, /* B */
915 2, /* P */
916
917 #define TP_CODES (TP_OFFSETS + 16 + 6)
918 2 | 16, /* d */
919 2, /* e */
920 0 | 16, /* w */
921 2, /* k */
922 2 | 32 | 0, /* l */
923 2 | 16 | 1, /* m */
924 0, /* CURRENTLY UNUSED */
925 0 | 16 | 8 , /* u */
926 4 | 16 | 1, /* j */
927 2 | 128 | 32 | 16 , /* y */
928 2 | 128 | 64 | 32 | 16 , /* C */
929 2 | 16, /* H */
930 2 | 32 | 16 | 0, /* I */
931 2 | 16, /* M */
932 2 | 16, /* S */
933 6 | 16, /* Y */
934 2, /* a */
935 2, /* b, h */
936 2 | 64, /* p */
937 2, /* A */
938 2, /* B */
939 2 | 64, /* P */
940
941 #define STRINGS_NL_ITEM_START (TP_CODES + 16 + 6)
942 _NL_ITEM_INDEX(ABDAY_1), /* a */
943 _NL_ITEM_INDEX(ABMON_1), /* b, h */
944 _NL_ITEM_INDEX(AM_STR), /* p */
945 _NL_ITEM_INDEX(DAY_1), /* A */
946 _NL_ITEM_INDEX(MON_1), /* B */
947 _NL_ITEM_INDEX(AM_STR), /* P -- wrong! need lower case */
948
949 #define STACKED_STRINGS_START (STRINGS_NL_ITEM_START+6)
950 6, 7, 8, 16, 24, 29, /* 6 - offsets from offset-count to strings */
951 '\n', 0, /* 2 */
952 '\t', 0, /* 2 */
953 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
954 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
955 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
956 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
957
958 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 43)
959 _NL_ITEM_INDEX(D_T_FMT), /* c */
960 _NL_ITEM_INDEX(D_FMT), /* x */
961 _NL_ITEM_INDEX(T_FMT), /* X */
962 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
963 #ifdef ENABLE_ERA_CODE
964 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
965 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
966 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
967 #endif
968 };
969
load_field(int k,const struct tm * __restrict timeptr)970 static int load_field(int k, const struct tm *__restrict timeptr)
971 {
972 int r;
973 int r_max;
974
975 r = ((int *) timeptr)[k];
976
977 r_max = spec[FIELD_MAX + k];
978
979 if (k == 7) {
980 r_max = 365;
981 } else if (k == 5) {
982 r += 1900;
983 r_max = 9999;
984 }
985
986 if ((((unsigned int) r) > r_max) || ((k == 3) && !r)) {
987 r = -1;
988 }
989
990 return r;
991 }
992
993 #define MAX_PUSH 4
994
995 #ifdef __UCLIBC_MJN3_ONLY__
996 #warning TODO: Check multibyte format string validity.
997 #endif
998
__XL_NPP(strftime)999 size_t __XL_NPP(strftime)(char *__restrict s, size_t maxsize,
1000 const char *__restrict format,
1001 const struct tm *__restrict timeptr __LOCALE_PARAM )
1002 {
1003 long tzo;
1004 register const char *p;
1005 register const char *o;
1006 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1007 const rule_struct *rsp;
1008 #endif
1009 const char *stack[MAX_PUSH];
1010 size_t count;
1011 size_t o_count;
1012 int field_val = 0, i = 0, j, lvl;
1013 int x[3]; /* wday, yday, year */
1014 int isofm, days;
1015 char buf[__UIM_BUFLEN_LONG];
1016 unsigned char mod;
1017 unsigned char code;
1018
1019 /* We'll, let's get this out of the way. */
1020 _time_tzset(_time_mktime((struct tm *) timeptr, 0) < new_rule_starts);
1021
1022 lvl = 0;
1023 p = format;
1024 count = maxsize;
1025
1026 LOOP:
1027 if (!count) {
1028 return 0;
1029 }
1030 if (!*p) {
1031 if (lvl == 0) {
1032 *s = 0; /* nul-terminate */
1033 return maxsize - count;
1034 }
1035 p = stack[--lvl];
1036 goto LOOP;
1037 }
1038
1039 o_count = 1;
1040 if ((*(o = p) == '%') && (*++p != '%')) {
1041 o_count = 2;
1042 mod = ILLEGAL_SPEC;
1043 if ((*p == 'O') || (*p == 'E')) { /* modifier */
1044 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1045 ++o_count;
1046 ++p;
1047 }
1048 if ((((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1049 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1050 ) {
1051 if (!*p) {
1052 --p;
1053 --o_count;
1054 }
1055 goto OUTPUT;
1056 }
1057 code &= ILLEGAL_SPEC; /* modifiers are preserved in mod var. */
1058
1059 if ((code & MASK_SPEC) == STACKED_SPEC) {
1060 if (lvl == MAX_PUSH) {
1061 goto OUTPUT; /* Stack full so treat as illegal spec. */
1062 }
1063 stack[lvl++] = ++p;
1064 if ((code &= 0xf) < 8) {
1065 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1066 p += *((unsigned char *)p);
1067 goto LOOP;
1068 }
1069 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1070 + (code & 7);
1071 #ifdef ENABLE_ERA_CODE
1072 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1073 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1074 (int)(((unsigned char *)p)[4]))
1075 __LOCALE_ARG
1076 )))
1077 ) {
1078 p = o;
1079 goto LOOP;
1080 }
1081 #endif
1082 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1083 (int)(*((unsigned char *)p)))
1084 __LOCALE_ARG
1085 );
1086 goto LOOP;
1087 }
1088
1089 o = ((const char *) spec) + 26; /* set to "????" */
1090 if ((code & MASK_SPEC) == CALC_SPEC) {
1091
1092 if (*p == 's') {
1093 time_t t;
1094
1095 /* Use a cast to silence the warning since *timeptr won't
1096 * be changed. */
1097 if ((t = _time_mktime((struct tm *) timeptr, 0))
1098 == ((time_t) -1)
1099 ) {
1100 o_count = 1;
1101 goto OUTPUT;
1102 }
1103 #ifdef TIME_T_IS_UNSIGNED
1104 o = _uintmaxtostr(buf + sizeof(buf) - 1,
1105 (uintmax_t) t,
1106 10, __UIM_DECIMAL);
1107 #else
1108 o = _uintmaxtostr(buf + sizeof(buf) - 1,
1109 (uintmax_t) t,
1110 -10, __UIM_DECIMAL);
1111 #endif
1112 o_count = sizeof(buf);
1113 goto OUTPUT;
1114 } else if (((*p) | 0x20) == 'z') { /* 'z' or 'Z' */
1115
1116 if (timeptr->tm_isdst < 0) {
1117 /* SUSv3 specifies this behavior for 'z', but we'll also
1118 * treat it as "no timezone info" for 'Z' too. */
1119 o_count = 0;
1120 goto OUTPUT;
1121 }
1122
1123 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1124
1125 # ifdef __USE_BSD
1126 # define RSP_TZNAME timeptr->tm_zone
1127 # define RSP_GMT_OFFSET (-timeptr->tm_gmtoff)
1128 # else
1129 # define RSP_TZNAME timeptr->__tm_zone
1130 # define RSP_GMT_OFFSET (-timeptr->__tm_gmtoff)
1131 # endif
1132
1133 #else
1134
1135 #define RSP_TZNAME rsp->tzname
1136 #define RSP_GMT_OFFSET rsp->gmt_offset
1137
1138 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1139
1140 rsp = _time_tzinfo;
1141 if (timeptr->tm_isdst > 0) {
1142 ++rsp;
1143 }
1144 #endif
1145
1146 if (*p == 'Z') {
1147 o = RSP_TZNAME;
1148 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1149 /* Sigh... blasted glibc extensions. Of course we can't
1150 * count on the pointer being valid. Best we can do is
1151 * handle NULL, which looks to be all that glibc does.
1152 * At least that catches the memset() with 0 case.
1153 * NOTE: We handle this case differently than glibc!
1154 * It uses system timezone name (based on tm_isdst) in this
1155 * case... although it always seems to use the embedded
1156 * tm_gmtoff value. What we'll do instead is treat the
1157 * timezone name as unknown/invalid and return "???". */
1158 if (!o) {
1159 o = "???";
1160 }
1161 #endif
1162 assert(o != NULL);
1163 #if 0
1164 if (!o) { /* PARANOIA */
1165 o = spec+30; /* empty string */
1166 }
1167 #endif
1168 o_count = SIZE_MAX;
1169 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
1170 goto OUTPUT;
1171 #endif
1172 } else { /* z */
1173 *s = '+';
1174 if ((tzo = -RSP_GMT_OFFSET) < 0) {
1175 tzo = -tzo;
1176 *s = '-';
1177 }
1178 ++s;
1179 --count;
1180
1181 i = tzo / 60;
1182 field_val = ((i / 60) * 100) + (i % 60);
1183
1184 i = 16 + 6; /* 0-fill, width = 4 */
1185 }
1186 #ifndef __UCLIBC_HAS_TM_EXTENSIONS__
1187 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
1188 if (*p == 'Z') {
1189 goto OUTPUT;
1190 }
1191 #endif
1192 } else {
1193 /* TODO: don't need year for U, W */
1194 for (i=0 ; i < 3 ; i++) {
1195 if ((x[i] = load_field(spec[CALC_OFFSETS+i],timeptr)) < 0) {
1196 goto OUTPUT;
1197 }
1198 }
1199
1200 i = 16 + 2; /* 0-fill, width = 2 */
1201
1202 if ((*p == 'U') || (*p == 'W')) {
1203 field_val = ((x[1] - x[0]) + 7);
1204 if (*p == 'W') {
1205 ++field_val;
1206 }
1207 field_val /= 7;
1208 if ((*p == 'W') && !x[0]) {
1209 --field_val;
1210 }
1211 } else { /* ((*p == 'g') || (*p == 'G') || (*p == 'V')) */
1212 ISO_LOOP:
1213 isofm = (((x[1] - x[0]) + 11) % 7) - 3; /* [-3,3] */
1214
1215 if (x[1] < isofm) { /* belongs to previous year */
1216 --x[2];
1217 x[1] += 365 + __isleap(x[2]);
1218 goto ISO_LOOP;
1219 }
1220
1221 field_val = ((x[1] - isofm) / 7) + 1; /* week # */
1222 days = 365 + __isleap(x[2]);
1223 isofm = ((isofm + 7*53 + 3 - days)) % 7 + days - 3; /* next year */
1224 if (x[1] >= isofm) { /* next year */
1225 x[1] -= days;
1226 ++x[2];
1227 goto ISO_LOOP;
1228 }
1229
1230 if (*p != 'V') { /* need year */
1231 field_val = x[2]; /* TODO: what if x[2] now 10000 ?? */
1232 if (*p == 'g') {
1233 field_val %= 100;
1234 } else {
1235 i = 16 + 6; /* 0-fill, width = 4 */
1236 }
1237 }
1238 }
1239 }
1240 } else {
1241 i = TP_OFFSETS + (code & 0x1f);
1242 if ((field_val = load_field(spec[i], timeptr)) < 0) {
1243 goto OUTPUT;
1244 }
1245
1246 i = spec[i+(TP_CODES - TP_OFFSETS)];
1247
1248 j = (i & 128) ? 100: 12;
1249 if (i & 64) {
1250 field_val /= j;;
1251 }
1252 if (i & 32) {
1253 field_val %= j;
1254 if (((i & 128) + field_val) == 0) { /* mod 12? == 0 */
1255 field_val = j; /* set to 12 */
1256 }
1257 }
1258 field_val += (i & 1);
1259 if ((i & 8) && !field_val) {
1260 field_val += 7;
1261 }
1262 }
1263
1264 if ((code & MASK_SPEC) == STRING_SPEC) {
1265 o_count = SIZE_MAX;
1266 field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
1267 o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG);
1268 } else {
1269 o_count = ((i >> 1) & 3) + 1;
1270 o = buf + o_count;
1271 do {
1272 *(char *)(--o) = '0' + (field_val % 10);
1273 field_val /= 10;
1274 } while (o > buf);
1275 if (*buf == '0') {
1276 *buf = ' ' + (i & 16);
1277 }
1278 }
1279 }
1280
1281 OUTPUT:
1282 ++p;
1283 while (o_count && count && *o) {
1284 *s++ = *o++;
1285 --o_count;
1286 --count;
1287 }
1288 goto LOOP;
1289 }
1290 # ifdef L_strftime_l
libc_hidden_def(strftime_l)1291 libc_hidden_def(strftime_l)
1292 # endif
1293
1294 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1295
1296 #endif
1297 /**********************************************************************/
1298 #if defined(L_strptime) || defined(L_strptime_l)
1299
1300 #define ISDIGIT(C) __isdigit_char((C))
1301
1302 #ifdef __UCLIBC_DO_XLOCALE
1303 #define ISSPACE(C) isspace_l((C), locale_arg)
1304 #else
1305 #define ISSPACE(C) isspace((C))
1306 #endif
1307
1308 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
1309
1310 char *strptime(const char *__restrict buf, const char *__restrict format,
1311 struct tm *__restrict tm)
1312 {
1313 return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
1314 }
1315
1316 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1317
1318 /* TODO:
1319 * 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
1320 * Both work for glibc. So, should we always strip spaces?
1321 * 2) %Z
1322 */
1323
1324 /* Notes:
1325 * There are several differences between this strptime and glibc's strptime.
1326 * 1) glibc strips leading space before numeric conversions.
1327 * 2) glibc will read fields without whitespace in between. SUSv3 states
1328 * that you must have whitespace between conversion operators. Besides,
1329 * how do you know how long a number should be if there are leading 0s?
1330 * 3) glibc attempts to compute some the struct tm fields based on the
1331 * data retrieved; tm_wday in particular. I don't as I consider it
1332 * another glibc attempt at mind-reading...
1333 */
1334
1335 #define NO_E_MOD 0x80
1336 #define NO_O_MOD 0x40
1337
1338 #define ILLEGAL_SPEC 0x3f
1339
1340 #define INT_SPEC 0x00 /* must be 0x00!! */
1341 #define STRING_SPEC 0x10 /* must be 0x10!! */
1342 #define CALC_SPEC 0x20
1343 #define STACKED_SPEC 0x30
1344
1345 #define MASK_SPEC 0x30
1346
1347 /* Warning: Assumes ASCII values! (as do lots of other things in the lib...) */
1348 static const unsigned char spec[] = {
1349 /* A */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1350 /* B */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1351 /* C */ 0x08 | INT_SPEC | NO_O_MOD,
1352 /* D */ 0x01 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1353 /* E */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1354 /* F */ 0x02 | STACKED_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1355 /* G */ 0x0f | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1356 /* H */ 0x06 | INT_SPEC | NO_E_MOD,
1357 /* I */ 0x07 | INT_SPEC | NO_E_MOD,
1358 /* J */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1359 /* K */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1360 /* L */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1361 /* M */ 0x04 | INT_SPEC | NO_E_MOD,
1362 /* N */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1363 /* O */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1364 /* P */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1365 /* Q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1366 /* R */ 0x03 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1367 /* S */ 0x05 | INT_SPEC | NO_E_MOD,
1368 /* T */ 0x04 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1369 /* U */ 0x0c | INT_SPEC | NO_E_MOD,
1370 /* V */ 0x0d | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1371 /* W */ 0x0c | INT_SPEC | NO_E_MOD,
1372 /* X */ 0x0a | STACKED_SPEC | NO_O_MOD,
1373 /* Y */ 0x0a | INT_SPEC | NO_O_MOD,
1374 /* Z */ 0x02 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1375
1376 /* WARNING! This assumes orderings:
1377 * AM,PM
1378 * ABDAY_1-ABDAY-7,DAY_1-DAY_7
1379 * ABMON_1-ABMON_12,MON_1-MON12
1380 * Also, there are exactly 6 bytes between 'Z' and 'a'.
1381 */
1382 #define STRINGS_NL_ITEM_START (26)
1383 _NL_ITEM_INDEX(AM_STR), /* p (P) */
1384 _NL_ITEM_INDEX(ABMON_1), /* B, b */
1385 _NL_ITEM_INDEX(ABDAY_1), /* A, a */
1386 2,
1387 24,
1388 14,
1389
1390 /* a */ 0x02 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1391 /* b */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1392 /* c */ 0x08 | STACKED_SPEC | NO_O_MOD,
1393 /* d */ 0x00 | INT_SPEC | NO_E_MOD,
1394 /* e */ 0x00 | INT_SPEC | NO_E_MOD,
1395 /* f */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1396 /* g */ 0x0e | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1397 /* h */ 0x01 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1398 /* i */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1399 /* j */ 0x01 | INT_SPEC | NO_E_MOD | NO_O_MOD,
1400 /* k */ 0x06 | INT_SPEC | NO_E_MOD, /* glibc */
1401 /* l */ 0x07 | INT_SPEC | NO_E_MOD, /* glibc */
1402 /* m */ 0x02 | INT_SPEC | NO_E_MOD,
1403 /* n */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1404 /* o */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1405 /* p */ 0x00 | STRING_SPEC | NO_E_MOD | NO_O_MOD,
1406 /* q */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1407 /* r */ 0x0b | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1408 /* s */ 0x00 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1409 /* t */ 0x00 | STACKED_SPEC | NO_E_MOD | NO_O_MOD,
1410 /* u */ 0x0b | INT_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1411 /* v */ ILLEGAL_SPEC | NO_E_MOD | NO_O_MOD,
1412 /* w */ 0x03 | INT_SPEC | NO_E_MOD,
1413 /* x */ 0x09 | STACKED_SPEC | NO_O_MOD,
1414 /* y */ 0x09 | INT_SPEC,
1415 /* z */ 0x01 | CALC_SPEC | NO_E_MOD | NO_O_MOD, /* glibc */
1416
1417 #define INT_FIELD_START (26+6+26)
1418 /* (field #) << 3 + lower bound (0|1) + correction 0:none, 2:-1, 4:-1900
1419 * followed by upper bound prior to correction with 1=>366 and 2=>9999. */
1420 /* d, e */ (3 << 3) + 1 + 0, 31,
1421 /* j */ (7 << 3) + 1 + 2, /* 366 */ 1,
1422 /* m */ (4 << 3) + 1 + 2, 12,
1423 /* w */ (6 << 3) + 0 + 0, 6,
1424 /* M */ (1 << 3) + 0 + 0, 59,
1425 /* S */ 0 + 0 + 0, 60,
1426 /* H (k) */ (2 << 3) + 0 + 0, 23,
1427 /* I (l) */ (9 << 3) + 1 + 0, 12, /* goes with 8 -- am/pm */
1428 /* C */ (10<< 3) + 0 + 0, 99,
1429 /* y */ (11<< 3) + 0 + 0, 99,
1430 /* Y */ (5 << 3) + 0 + 4, /* 9999 */ 2,
1431 /* u */ (6 << 3) + 1 + 0, 7,
1432 /* The following are processed and range-checked, but ignored otherwise. */
1433 /* U, W */ (12<< 3) + 0 + 0, 53,
1434 /* V */ (12<< 3) + 1 + 0, 53,
1435 /* g */ (12<< 3) + 0 + 0, 99,
1436 /* G */ (12<< 3) + 0 /*+ 4*/, /* 9999 */ 2, /* Note: -1 or 10000? */
1437
1438 #define STACKED_STRINGS_START (INT_FIELD_START+32)
1439 5, 6, 14, 22, 27, /* 5 - offsets from offset-count to strings */
1440 ' ', 0, /* 2 - %n or %t */
1441 '%', 'm', '/', '%', 'd', '/', '%', 'y', 0, /* 9 - %D */
1442 '%', 'Y', '-', '%', 'm', '-', '%', 'd', 0, /* 9 - %F (glibc extension) */
1443 '%', 'H', ':', '%', 'M', 0, /* 6 - %R*/
1444 '%', 'H', ':', '%', 'M', ':', '%', 'S', 0, /* 9 - %T */
1445
1446 #define STACKED_STRINGS_NL_ITEM_START (STACKED_STRINGS_START + 40)
1447 _NL_ITEM_INDEX(D_T_FMT), /* c */
1448 _NL_ITEM_INDEX(D_FMT), /* x */
1449 _NL_ITEM_INDEX(T_FMT), /* X */
1450 _NL_ITEM_INDEX(T_FMT_AMPM), /* r */
1451 #ifdef ENABLE_ERA_CODE
1452 _NL_ITEM_INDEX(ERA_D_T_FMT), /* Ec */
1453 _NL_ITEM_INDEX(ERA_D_FMT), /* Ex */
1454 _NL_ITEM_INDEX(ERA_T_FMT), /* EX */
1455 #endif
1456 };
1457
1458 #define MAX_PUSH 4
1459
1460 char *__XL_NPP(strptime)(const char *__restrict buf, const char *__restrict format,
1461 struct tm *__restrict tm __LOCALE_PARAM)
1462 {
1463 register const char *p;
1464 char *o;
1465 const char *stack[MAX_PUSH];
1466 int i, j, lvl;
1467 int fields[13];
1468 unsigned char mod;
1469 unsigned char code;
1470
1471 i = 0;
1472 do {
1473 fields[i] = INT_MIN;
1474 } while (++i < 13);
1475
1476 lvl = 0;
1477 p = format;
1478
1479 LOOP:
1480 if (!*p) {
1481 if (lvl == 0) { /* Done. */
1482 if (fields[6] == 7) { /* Cleanup for %u here since just once. */
1483 fields[6] = 0; /* Don't use mod in case unset. */
1484 }
1485
1486 i = 0;
1487 do { /* Store the values into tm. */
1488 if (fields[i] != INT_MIN) {
1489 ((int *) tm)[i] = fields[i];
1490 }
1491 } while (++i < 8);
1492
1493 return (char *) buf; /* Success. */
1494 }
1495 p = stack[--lvl];
1496 goto LOOP;
1497 }
1498
1499 if ((*p == '%') && (*++p != '%')) {
1500 mod = ILLEGAL_SPEC;
1501 if ((*p == 'O') || (*p == 'E')) { /* Modifier? */
1502 mod |= ((*p == 'O') ? NO_O_MOD : NO_E_MOD);
1503 ++p;
1504 }
1505
1506 if (!*p
1507 || (((unsigned char)(((*p) | 0x20) - 'a')) >= 26)
1508 || (((code = spec[(int)(*p - 'A')]) & mod) >= ILLEGAL_SPEC)
1509 ) {
1510 return NULL; /* Illegal spec. */
1511 }
1512
1513 if ((code & MASK_SPEC) == STACKED_SPEC) {
1514 if (lvl == MAX_PUSH) {
1515 return NULL; /* Stack full so treat as illegal spec. */
1516 }
1517 stack[lvl++] = ++p;
1518 if ((code &= 0xf) < 8) {
1519 p = ((const char *) spec) + STACKED_STRINGS_START + code;
1520 p += *((unsigned char *)p);
1521 goto LOOP;
1522 }
1523
1524 p = ((const char *) spec) + STACKED_STRINGS_NL_ITEM_START
1525 + (code & 7);
1526 #ifdef ENABLE_ERA_CODE
1527 if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
1528 && (*(o = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1529 (int)(((unsigned char *)p)[4]))
1530 __LOCALE_ARG
1531 )))
1532 ) {
1533 p = o;
1534 goto LOOP;
1535 }
1536 #endif
1537 p = __XL_NPP(nl_langinfo)(_NL_ITEM(LC_TIME,
1538 (int)(*((unsigned char *)p)))
1539 __LOCALE_ARG
1540 );
1541 goto LOOP;
1542 }
1543
1544 ++p;
1545
1546 if ((code & MASK_SPEC) == STRING_SPEC) {
1547 code &= 0xf;
1548 j = spec[STRINGS_NL_ITEM_START + 3 + code];
1549 i = _NL_ITEM(LC_TIME, spec[STRINGS_NL_ITEM_START + code]);
1550 /* Go backwards to check full names before abreviations. */
1551 do {
1552 --j;
1553 o = __XL_NPP(nl_langinfo)(i+j __LOCALE_ARG);
1554 if (!__XL_NPP(strncasecmp)(buf, o, strlen(o) __LOCALE_ARG) && *o) {
1555 do { /* Found a match. */
1556 ++buf;
1557 } while (*++o);
1558 if (!code) { /* am/pm */
1559 fields[8] = j * 12;
1560 if (fields[9] >= 0) { /* We have a previous %I or %l. */
1561 fields[2] = fields[9] + fields[8];
1562 }
1563 } else { /* day (4) or month (6) */
1564 fields[2 + (code << 1)]
1565 = j % (spec[STRINGS_NL_ITEM_START + 3 + code] >> 1);
1566 }
1567 goto LOOP;
1568 }
1569 } while (j);
1570 return NULL; /* Failed to match. */
1571 }
1572
1573 if ((code & MASK_SPEC) == CALC_SPEC) {
1574 if ((code &= 0xf) < 1) { /* s or z*/
1575 time_t t;
1576
1577 o = (char *) buf;
1578 i = errno;
1579 __set_errno(0);
1580 if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
1581 #ifdef TIME_T_IS_UNSIGNED
1582 t = __XL_NPP(strtoul)(buf, &o, 10 __LOCALE_ARG);
1583 #else
1584 t = __XL_NPP(strtol)(buf, &o, 10 __LOCALE_ARG);
1585 #endif
1586 }
1587 if ((o == buf) || errno) { /* Not a number or overflow. */
1588 return NULL;
1589 }
1590 __set_errno(i); /* Restore errno. */
1591 buf = o;
1592
1593 if (!code) { /* s */
1594 localtime_r(&t, tm); /* TODO: check for failure? */
1595 i = 0;
1596 do { /* Now copy values from tm to fields. */
1597 fields[i] = ((int *) tm)[i];
1598 } while (++i < 8);
1599 }
1600 }
1601 /* TODO: glibc treats %Z as a nop. For now, do the same. */
1602 goto LOOP;
1603 }
1604
1605 assert((code & MASK_SPEC) == INT_SPEC);
1606 {
1607 register const unsigned char *x;
1608 code &= 0xf;
1609 x = spec + INT_FIELD_START + (code << 1);
1610 if ((j = x[1]) < 3) { /* upper bound (inclusive) */
1611 j = ((j==1) ? 366 : 9999);
1612 }
1613 i = -1;
1614 while (ISDIGIT(*buf)) {
1615 if (i < 0) {
1616 i = 0;
1617 }
1618 if ((i = 10*i + (*buf - '0')) > j) { /* Overflow. */
1619 return NULL;
1620 }
1621 ++buf;
1622 }
1623 if (i < (*x & 1)) { /* This catches no-digit case too. */
1624 return NULL;
1625 }
1626 if (*x & 2) {
1627 --i;
1628 }
1629 if (*x & 4) {
1630 i -= 1900;
1631 }
1632
1633 if (*x == (9 << 3) + 1 + 0) { /* %I or %l */
1634 if (i == 12) {
1635 i = 0;
1636 }
1637 if (fields[8] >= 0) { /* We have a previous %p or %P. */
1638 fields[2] = i + fields[8];
1639 }
1640 }
1641
1642 fields[(*x) >> 3] = i;
1643
1644 if (((unsigned char)(*x - (10 << 3) + 0 + 0)) <= 8) { /* %C or %y */
1645 if ((j = fields[10]) < 0) { /* No %C, so i must be %y data. */
1646 if (i <= 68) { /* Map [0-68] to 2000+i */
1647 i += 100;
1648 }
1649 } else { /* Have %C data, but what about %y? */
1650 if ((i = fields[11]) < 0) { /* No %y data. */
1651 i = 0; /* Treat %y val as 0 following glibc's example. */
1652 }
1653 i += 100*(j - 19);
1654 }
1655 fields[5] = i;
1656 }
1657 }
1658 goto LOOP;
1659 } else if (ISSPACE(*p)) {
1660 ++p;
1661 while (ISSPACE(*buf)) {
1662 ++buf;
1663 }
1664 goto LOOP;
1665 } else if (*buf++ == *p++) {
1666 goto LOOP;
1667 }
1668 return NULL;
1669 }
1670 # ifdef L_strptime_l
1671 libc_hidden_def(strptime_l)
1672 # endif
1673
1674 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
1675
1676 #endif
1677 /**********************************************************************/
1678 #ifdef L_time
1679
1680 #ifndef __BCC__
1681 #error The uClibc version of time is in sysdeps/linux/common.
1682 #endif
1683
time(register time_t * tloc)1684 time_t time(register time_t *tloc)
1685 {
1686 struct timeval tv;
1687 register struct timeval *p = &tv;
1688
1689 gettimeofday(p, NULL); /* This should never fail... */
1690
1691 if (tloc) {
1692 *tloc = p->tv_sec;
1693 }
1694
1695 return p->tv_sec;
1696 }
1697
1698 #endif
1699 /**********************************************************************/
1700 #ifdef L_tzset
1701
1702 static const char vals[] = {
1703 'T', 'Z', 0, /* 3 */
1704 'U', 'T', 'C', 0, /* 4 */
1705 25, 60, 60, 1, /* 4 */
1706 '.', 1, /* M */
1707 5, '.', 1,
1708 6, 0, 0, /* Note: overloaded for non-M non-J case... */
1709 0, 1, 0, /* J */
1710 ',', 'M', '4', '.', '1', '.', '0',
1711 ',', 'M', '1', '0', '.', '5', '.', '0', 0,
1712 ',', 'M', '3', '.', '2', '.', '0',
1713 ',', 'M', '1', '1', '.', '1', '.', '0', 0
1714 };
1715
1716 #define TZ vals
1717 #define UTC (vals + 3)
1718 #define RANGE (vals + 7)
1719 #define RULE (vals + 11 - 1)
1720 #define DEFAULT_RULES (vals + 22)
1721 #define DEFAULT_2007_RULES (vals + 38)
1722
1723 /* Initialize to UTC. */
1724 int daylight = 0;
1725 long timezone = 0;
1726 char *tzname[2] = { (char *) UTC, (char *) (UTC-1) };
1727
1728 __UCLIBC_MUTEX_INIT(_time_tzlock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
1729
1730 rule_struct _time_tzinfo[2];
1731
getoffset(register const char * e,long * pn)1732 static const char *getoffset(register const char *e, long *pn)
1733 {
1734 register const char *s = RANGE-1;
1735 long n;
1736 int f;
1737
1738 n = 0;
1739 f = -1;
1740 do {
1741 ++s;
1742 if (__isdigit_char(*e)) {
1743 f = *e++ - '0';
1744 }
1745 if (__isdigit_char(*e)) {
1746 f = 10 * f + (*e++ - '0');
1747 }
1748 if (((unsigned int)f) >= *s) {
1749 return NULL;
1750 }
1751 n = (*s) * n + f;
1752 f = 0;
1753 if (*e == ':') {
1754 ++e;
1755 --f;
1756 }
1757 } while (*s > 1);
1758
1759 *pn = n;
1760 return e;
1761 }
1762
getnumber(register const char * e,int * pn)1763 static const char *getnumber(register const char *e, int *pn)
1764 {
1765 #ifdef __BCC__
1766 /* bcc can optimize the counter if it thinks it is a pointer... */
1767 register const char *n = (const char *) 3;
1768 int f;
1769
1770 f = 0;
1771 while (n && __isdigit_char(*e)) {
1772 f = 10 * f + (*e++ - '0');
1773 --n;
1774 }
1775
1776 *pn = f;
1777 return (n == (const char *) 3) ? NULL : e;
1778 #else /* __BCC__ */
1779 int n, f;
1780
1781 n = 3;
1782 f = 0;
1783 while (n && __isdigit_char(*e)) {
1784 f = 10 * f + (*e++ - '0');
1785 --n;
1786 }
1787
1788 *pn = f;
1789 return (n == 3) ? NULL : e;
1790 #endif /* __BCC__ */
1791 }
1792
1793
1794 #ifdef __UCLIBC_MJN3_ONLY__
1795 #warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
1796 #endif
1797
1798 #ifdef __UCLIBC_HAS_TZ_FILE__
1799
1800 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1801 static smallint TZ_file_read; /* Let BSS initialization set this to 0. */
1802 #endif
1803
read_TZ_file(char * buf)1804 static char *read_TZ_file(char *buf)
1805 {
1806 int r;
1807 int fd;
1808 char *p = NULL;
1809
1810 fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY);
1811 if (fd >= 0) {
1812 #if 0
1813 /* TZ are small *files*. On files, short reads
1814 * only occur on EOF (unlike, say, pipes).
1815 * The code below is pedanticallly more correct,
1816 * but this way we always read at least twice:
1817 * 1st read is short, 2nd one is zero bytes.
1818 */
1819 size_t todo = TZ_BUFLEN;
1820 p = buf;
1821 do {
1822 r = read(fd, p, todo);
1823 if (r < 0)
1824 goto ERROR;
1825 if (r == 0)
1826 break;
1827 p += r;
1828 todo -= r;
1829 } while (todo);
1830 #else
1831 /* Shorter, and does one fewer read syscall */
1832 r = read(fd, buf, TZ_BUFLEN);
1833 if (r < 0)
1834 goto ERROR;
1835 p = buf + r;
1836 #endif
1837 if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline */
1838 p[-1] = 0;
1839 p = buf;
1840 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1841 TZ_file_read = 1;
1842 #endif
1843 } else {
1844 ERROR:
1845 p = NULL;
1846 }
1847 close(fd);
1848 }
1849 #ifdef __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__
1850 else {
1851 fd = open("/etc/localtime", O_RDONLY);
1852 if (fd >= 0) {
1853 r = read(fd, buf, TZ_BUFLEN);
1854 if (r != TZ_BUFLEN
1855 || strncmp(buf, "TZif", 4) != 0
1856 || (unsigned char)buf[4] < 2
1857 || lseek(fd, -TZ_BUFLEN, SEEK_END) < 0
1858 ) {
1859 goto ERROR;
1860 }
1861 /* tzfile.h from tzcode database says about TZif2+ files:
1862 **
1863 ** If tzh_version is '2' or greater, the above is followed by a second instance
1864 ** of tzhead and a second instance of the data in which each coded transition
1865 ** time uses 8 rather than 4 chars,
1866 ** then a POSIX-TZ-environment-variable-style string for use in handling
1867 ** instants after the last transition time stored in the file
1868 ** (with nothing between the newlines if there is no POSIX representation for
1869 ** such instants).
1870 */
1871 r = read(fd, buf, TZ_BUFLEN);
1872 if (r <= 0 || buf[--r] != '\n')
1873 goto ERROR;
1874 buf[r] = 0;
1875 while (r != 0) {
1876 if (buf[--r] == '\n') {
1877 p = buf + r + 1;
1878 #ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
1879 TZ_file_read = 1;
1880 #endif
1881 break;
1882 }
1883 } /* else ('\n' not found): p remains NULL */
1884 close(fd);
1885 }
1886 }
1887 #endif /* __UCLIBC_FALLBACK_TO_ETC_LOCALTIME__ */
1888 return p;
1889 }
1890
1891 #endif /* __UCLIBC_HAS_TZ_FILE__ */
1892
tzset(void)1893 void tzset(void)
1894 {
1895 _time_tzset((time(NULL)) < new_rule_starts);
1896 }
1897
_time_tzset(int use_old_rules)1898 void _time_tzset(int use_old_rules)
1899 {
1900 register const char *e;
1901 register char *s;
1902 long off = 0;
1903 short *p;
1904 rule_struct new_rules[2];
1905 int n, count, f;
1906 char c;
1907 #ifdef __UCLIBC_HAS_TZ_FILE__
1908 char buf[TZ_BUFLEN];
1909 #endif
1910 #ifdef __UCLIBC_HAS_TZ_CACHING__
1911 static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
1912 #endif
1913
1914 /* Put this inside the lock to prevent the possibility of two different
1915 * timezones being used in a threaded app. */
1916 __UCLIBC_MUTEX_LOCK(_time_tzlock);
1917
1918 e = getenv(TZ); /* TZ env var always takes precedence. */
1919
1920 #if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
1921 if (e) {
1922 /* Never use TZfile if TZ env var is set. */
1923 TZ_file_read = 0;
1924 }
1925 if (TZ_file_read) {
1926 /* We already parsed TZfile before, skip everything. */
1927 goto FAST_DONE;
1928 }
1929 #endif
1930
1931 /* Warning!!! Since uClibc doesn't do lib locking, the following is
1932 * potentially unsafe in a multi-threaded program since it is remotely
1933 * possible that another thread could call setenv() for TZ and overwrite
1934 * the string being parsed. So, don't do that... */
1935
1936 #ifdef __UCLIBC_HAS_TZ_FILE__
1937 if (!e)
1938 e = read_TZ_file(buf);
1939 #endif
1940 if (!e /* TZ env var not set and no TZfile (or bad TZfile) */
1941 || !*e /* or set to empty string. */
1942 ) {
1943 goto ILLEGAL;
1944 }
1945
1946 if (*e == ':') { /* Ignore leading ':'. */
1947 ++e;
1948 }
1949
1950 #ifdef __UCLIBC_HAS_TZ_CACHING__
1951 if (strcmp(e, oldval) == 0) {
1952 /* Same string as last time... nothing to do. */
1953 goto FAST_DONE;
1954 }
1955 /* Make a copy of the TZ env string. It won't be nul-terminated if
1956 * it is too long, but it that case it will be illegal and will be reset
1957 * to the empty string anyway. */
1958 strncpy(oldval, e, TZ_BUFLEN);
1959 #endif
1960
1961 count = 0;
1962 new_rules[1].tzname[0] = 0;
1963 LOOP:
1964 /* Get std or dst name. */
1965 c = 0;
1966 if (*e == '<') {
1967 ++e;
1968 c = '>';
1969 }
1970
1971 s = new_rules[count].tzname;
1972 n = 0;
1973 while (*e
1974 && isascii(*e) /* SUSv3 requires char in portable char set. */
1975 && (isalpha(*e)
1976 || (c && (isalnum(*e) || (*e == '+') || (*e == '-')))
1977 )
1978 ) {
1979 *s++ = *e++;
1980 if (++n > TZNAME_MAX) {
1981 goto ILLEGAL;
1982 }
1983 }
1984 *s = 0;
1985
1986 if ((n < 3) /* Check for minimum length. */
1987 || (c && (*e++ != c)) /* Match any quoting '<'. */
1988 ) {
1989 goto ILLEGAL;
1990 }
1991
1992 /* Get offset */
1993 s = (char *) e;
1994 if ((*e != '-') && (*e != '+')) {
1995 if (count && !__isdigit_char(*e)) {
1996 off -= 3600; /* Default to 1 hour ahead of std. */
1997 goto SKIP_OFFSET;
1998 }
1999 --e;
2000 }
2001
2002 ++e;
2003 e = getoffset(e, &off);
2004 if (!e) {
2005 goto ILLEGAL;
2006 }
2007
2008 if (*s == '-') {
2009 off = -off; /* Save off in case needed for dst default. */
2010 }
2011 SKIP_OFFSET:
2012 new_rules[count].gmt_offset = off;
2013
2014 if (!count) {
2015 new_rules[1].gmt_offset = off; /* Shouldn't be needed... */
2016 if (*e) {
2017 ++count;
2018 goto LOOP;
2019 }
2020 } else { /* OK, we have dst, so get some rules. */
2021 count = 0;
2022 if (!*e) { /* No rules so default to US rules. */
2023 e = use_old_rules ? DEFAULT_RULES : DEFAULT_2007_RULES;
2024 #ifdef DEBUG_TZSET
2025 if (e == DEFAULT_RULES)
2026 printf("tzset: Using old rules.\n");
2027 else if (e == DEFAULT_2007_RULES)
2028 printf("tzset: Using new rules\n");
2029 else
2030 printf("tzset: Using undefined rules\n");
2031 #endif
2032 }
2033
2034 do {
2035 if (*e++ != ',') {
2036 goto ILLEGAL;
2037 }
2038
2039 n = 365;
2040 s = (char *) RULE;
2041 c = *e++;
2042 if (c == 'M') {
2043 n = 12;
2044 } else if (c == 'J') {
2045 s += 8;
2046 } else {
2047 --e;
2048 c = 0;
2049 s += 6;
2050 }
2051
2052 p = &new_rules[count].rule_type;
2053 *p = c;
2054 if (c != 'M') {
2055 p -= 2;
2056 }
2057
2058 do {
2059 ++s;
2060 e = getnumber(e, &f);
2061 if (!e
2062 || ((unsigned int)(f - s[1]) > n)
2063 || (*s && (*e++ != *s))
2064 ) {
2065 goto ILLEGAL;
2066 }
2067 *--p = f;
2068 s += 2;
2069 n = *s;
2070 } while (n > 0);
2071
2072 off = 2 * 60 * 60; /* Default to 2:00:00 */
2073 if (*e == '/') {
2074 ++e;
2075 e = getoffset(e, &off);
2076 if (!e) {
2077 goto ILLEGAL;
2078 }
2079 }
2080 new_rules[count].dst_offset = off;
2081 } while (++count < 2);
2082
2083 if (*e) {
2084 ILLEGAL:
2085 #ifdef __UCLIBC_HAS_TZ_CACHING__
2086 oldval[0] = 0; /* oldval = "" */
2087 #endif
2088 memset(_time_tzinfo, 0, sizeof(_time_tzinfo));
2089 strcpy(_time_tzinfo[0].tzname, UTC);
2090 goto DONE;
2091 }
2092 }
2093
2094 memcpy(_time_tzinfo, new_rules, sizeof(new_rules));
2095 DONE:
2096 tzname[0] = _time_tzinfo[0].tzname;
2097 tzname[1] = _time_tzinfo[1].tzname;
2098 daylight = !!_time_tzinfo[1].tzname[0];
2099 timezone = _time_tzinfo[0].gmt_offset;
2100
2101 #if (defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)) || \
2102 defined(__UCLIBC_HAS_TZ_CACHING__)
2103 FAST_DONE:
2104 #endif
2105 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2106 }
libc_hidden_def(tzset)2107 libc_hidden_def(tzset)
2108 #endif
2109 /**********************************************************************/
2110 /* #ifdef L_utime */
2111
2112 /* utime is a syscall in both linux and elks. */
2113 /* int utime(const char *path, const struct utimbuf *times) */
2114
2115 /* #endif */
2116 /**********************************************************************/
2117 /* Non-SUSv3 */
2118 /**********************************************************************/
2119 #ifdef L_utimes
2120
2121 #ifndef __BCC__
2122 #error The uClibc version of utimes is in sysdeps/linux/common.
2123 #endif
2124
2125 #include <utime.h>
2126
2127 int utimes(const char *filename, register const struct timeval *tvp)
2128 {
2129 register struct utimbuf *p = NULL;
2130 struct utimbuf utb;
2131
2132 if (tvp) {
2133 p = &utb;
2134 p->actime = tvp[0].tv_sec;
2135 p->modtime = tvp[1].tv_sec;
2136 }
2137 return utime(filename, p);
2138 }
2139
2140 #endif
2141 /**********************************************************************/
2142 #ifdef L__time_t2tm
2143
2144 static const uint16_t _vals[] = {
2145 60, 60, 24, 7 /* special */, 36524, 1461, 365, 0
2146 };
2147
2148 static const unsigned char days[] = {
2149 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2150 29,
2151 };
2152
2153 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2154 static const char utc_string[] = "UTC";
2155 #endif
2156
2157 /* Notes:
2158 * If time_t is 32 bits, then no overflow is possible.
2159 * It time_t is > 32 bits, this needs to be adjusted to deal with overflow.
2160 */
2161
2162 /* Note: offset is the correction in _days_ to *timer! */
2163
_time_t2tm(const time_t * __restrict timer,int offset,struct tm * __restrict result)2164 struct tm attribute_hidden *_time_t2tm(const time_t *__restrict timer,
2165 int offset, struct tm *__restrict result)
2166 {
2167 register int *p;
2168 time_t t1, t, v;
2169 int wday = wday; /* ok to be uninitialized, shutting up warning */
2170
2171 {
2172 register const uint16_t *vp;
2173 t = *timer;
2174 p = (int *) result;
2175 p[7] = 0;
2176 vp = _vals;
2177 do {
2178 if ((v = *vp) == 7) {
2179 /* Overflow checking, assuming time_t is long int... */
2180 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2181 #if (INT_MAX == 2147483647L) && (LONG_MAX == 9223372036854775807L)
2182 /* Valid range for t is [-784223472856L, 784223421720L].
2183 * Outside of this range, the tm_year field will overflow. */
2184 if (((unsigned long)(t + offset- -784223472856L))
2185 > (784223421720L - -784223472856L)
2186 ) {
2187 return NULL;
2188 }
2189 #else
2190 #error overflow conditions unknown
2191 #endif
2192 #endif
2193
2194 /* We have days since the epoch, so caluclate the weekday. */
2195 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2196 wday = (t + 4) % (*vp); /* t is unsigned */
2197 #else
2198 wday = ((int)((t % (*vp)) + 11)) % ((int)(*vp)); /* help bcc */
2199 #endif
2200 /* Set divisor to days in 400 years. Be kind to bcc... */
2201 v = ((time_t)(vp[1])) << 2;
2202 ++v;
2203 /* Change to days since 1/1/1601 so that for 32 bit time_t
2204 * values, we'll have t >= 0. This should be changed for
2205 * archs with larger time_t types.
2206 * Also, correct for offset since a multiple of 7. */
2207
2208 /* TODO: Does this still work on archs with time_t > 32 bits? */
2209 t += (135140L - 366) + offset; /* 146097 - (365*30 + 7) -366 */
2210 }
2211 #if defined(__BCC__) && TIME_T_IS_UNSIGNED
2212 t -= ((t1 = t / v) * v);
2213 #else
2214 if ((t -= ((t1 = t / v) * v)) < 0) {
2215 t += v;
2216 --t1;
2217 }
2218 #endif
2219
2220 if ((*vp == 7) && (t == v-1)) {
2221 --t; /* Correct for 400th year leap case */
2222 ++p[4]; /* Stash the extra day... */
2223 }
2224
2225 #if defined(__BCC__) && 0
2226 *p = t1;
2227 if (v <= 60) {
2228 *p = t;
2229 t = t1;
2230 }
2231 ++p;
2232 #else
2233 if (v <= 60) {
2234 *p++ = t;
2235 t = t1;
2236 } else {
2237 *p++ = t1;
2238 }
2239 #endif
2240 } while (*++vp);
2241 }
2242
2243 if (p[-1] == 4) {
2244 --p[-1];
2245 t = 365;
2246 }
2247
2248 *p += ((int) t); /* result[7] .. tm_yday */
2249
2250 p -= 2; /* at result[5] */
2251
2252 #if (LONG_MAX > INT_MAX) && (LONG_MAX > 2147483647L)
2253 /* Protect against overflow. TODO: Unecessary if int arith wraps? */
2254 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + (p[1] - 299); /* tm_year */
2255 #else
2256 *p = ((((p[-2]<<2) + p[-1])*25 + p[0])<< 2) + p[1] - 299; /* tm_year */
2257 #endif
2258
2259 p[1] = wday; /* result[6] .. tm_wday */
2260
2261 {
2262 register const unsigned char *d = days;
2263
2264 wday = 1900 + *p;
2265 if (__isleap(wday)) {
2266 d += 11;
2267 }
2268
2269 wday = p[2] + 1; /* result[7] .. tm_yday */
2270 *--p = 0; /* at result[4] .. tm_mon */
2271 while (wday > *d) {
2272 wday -= *d;
2273 if (*d == 29) {
2274 d -= 11; /* Backup to non-leap Feb. */
2275 }
2276 ++d;
2277 ++*p; /* Increment tm_mon. */
2278 }
2279 p[-1] = wday; /* result[3] .. tm_mday */
2280 }
2281 /* TODO -- should this be 0? */
2282 p[4] = 0; /* result[8] .. tm_isdst */
2283 #ifdef __UCLIBC_HAS_TM_EXTENSIONS__
2284 # ifdef __USE_BSD
2285 result->tm_gmtoff = 0;
2286 result->tm_zone = utc_string;
2287 # else
2288 result->__tm_gmtoff = 0;
2289 result->__tm_zone = utc_string;
2290 # endif
2291 #endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
2292
2293 return result;
2294 }
2295
2296 #endif
2297 /**********************************************************************/
2298 #ifdef L___time_tm
2299
2300 struct tm __time_tm; /* Global shared by gmtime() and localtime(). */
2301
2302 #endif
2303 /**********************************************************************/
2304 #ifdef L__time_mktime
2305
_time_mktime(struct tm * timeptr,int store_on_success)2306 time_t attribute_hidden _time_mktime(struct tm *timeptr, int store_on_success)
2307 {
2308 time_t t;
2309
2310 __UCLIBC_MUTEX_LOCK(_time_tzlock);
2311
2312 tzset();
2313
2314 t = _time_mktime_tzi(timeptr, store_on_success, _time_tzinfo);
2315
2316 __UCLIBC_MUTEX_UNLOCK(_time_tzlock);
2317
2318 return t;
2319 }
2320
2321 #endif
2322 /**********************************************************************/
2323 #ifdef L__time_mktime_tzi
2324
2325 static const unsigned char __vals[] = {
2326 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, /* non-leap */
2327 29,
2328 };
2329
_time_mktime_tzi(struct tm * timeptr,int store_on_success,rule_struct * tzi)2330 time_t attribute_hidden _time_mktime_tzi(struct tm *timeptr, int store_on_success,
2331 rule_struct *tzi)
2332 {
2333 #ifdef __BCC__
2334 long days, secs;
2335 #else
2336 long long secs;
2337 #endif
2338 time_t t;
2339 struct tm x;
2340 /* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
2341 register int *p = (int *) &x;
2342 register const unsigned char *s;
2343 int d, default_dst;
2344
2345 memcpy(p, timeptr, sizeof(struct tm));
2346
2347 if (!tzi[1].tzname[0]) { /* No dst in this timezone, */
2348 p[8] = 0; /* so set tm_isdst to 0. */
2349 }
2350
2351 default_dst = 0;
2352 if (p[8]) { /* Either dst or unknown? */
2353 default_dst = 1; /* Assume advancing (even if unknown). */
2354 p[8] = ((p[8] > 0) ? 1 : -1); /* Normalize so abs() <= 1. */
2355 }
2356
2357 d = 400;
2358 p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
2359 if ((p[4] -= 12 * p[7]) < 0) {
2360 p[4] += 12;
2361 --p[5];
2362 }
2363
2364 s = __vals;
2365 d = (p[5] += 1900); /* Correct year. Now between 1900 and 2300. */
2366 if (__isleap(d)) {
2367 s += 11;
2368 }
2369
2370 p[7] = 0;
2371 d = p[4];
2372 while (d) {
2373 p[7] += *s;
2374 if (*s == 29) {
2375 s -= 11; /* Backup to non-leap Feb. */
2376 }
2377 ++s;
2378 --d;
2379 }
2380
2381 _time_tzset (x.tm_year < 2007); /* tm_year was expanded above */
2382
2383 #ifdef __BCC__
2384 d = p[5] - 1;
2385 days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
2386 secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
2387 + tzi[default_dst].gmt_offset;
2388 DST_CORRECT:
2389 if (secs < 0) {
2390 secs += 120009600L;
2391 days -= 1389;
2392 }
2393 if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
2394 t = ((time_t)(-1));
2395 goto DONE;
2396 }
2397 secs += (days * 86400L);
2398 #else
2399 d = p[5] - 1;
2400 d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
2401 secs = p[0]
2402 + tzi[default_dst].gmt_offset
2403 + 60*( p[1]
2404 + 60*(p[2]
2405 + 24*(((146073L * ((long long)(p[6])) + d)
2406 + p[3]) + p[7])));
2407
2408 DST_CORRECT:
2409 if (((unsigned long long)(secs - LONG_MIN))
2410 > (((unsigned long long)LONG_MAX) - LONG_MIN)
2411 ) {
2412 t = ((time_t)(-1));
2413 goto DONE;
2414 }
2415 #endif
2416
2417 d = ((struct tm *)p)->tm_isdst;
2418 t = secs;
2419
2420 __time_localtime_tzi(&t, (struct tm *)p, tzi);
2421
2422 if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
2423 goto DONE;
2424 }
2425
2426 if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
2427 #ifdef __BCC__
2428 secs -= (days * 86400L);
2429 #endif
2430 secs += (tzi[1-default_dst].gmt_offset
2431 - tzi[default_dst].gmt_offset);
2432 goto DST_CORRECT;
2433 }
2434
2435
2436 if (store_on_success) {
2437 memcpy(timeptr, p, sizeof(struct tm));
2438 }
2439
2440
2441 DONE:
2442 return t;
2443 }
2444
2445 #endif
2446 /**********************************************************************/
2447 #if defined(L_wcsftime) || defined(L_wcsftime_l)
2448
2449 #if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
2450
wcsftime(wchar_t * __restrict s,size_t maxsize,const wchar_t * __restrict format,const struct tm * __restrict timeptr)2451 size_t wcsftime(wchar_t *__restrict s, size_t maxsize,
2452 const wchar_t *__restrict format,
2453 const struct tm *__restrict timeptr)
2454 {
2455 return wcsftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
2456 }
2457
2458 #else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
2459
__XL_NPP(wcsftime)2460 size_t __XL_NPP(wcsftime)(wchar_t *__restrict s, size_t maxsize,
2461 const wchar_t *__restrict format,
2462 const struct tm *__restrict timeptr __LOCALE_PARAM )
2463 {
2464 #warning wcsftime always fails
2465 return 0; /* always fail */
2466 }
2467 #ifdef L_wcsftime_l
libc_hidden_def(wcsftime_l)2468 libc_hidden_def(wcsftime_l)
2469 #endif
2470
2471 #endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
2472
2473 #endif
2474 /**********************************************************************/
2475 #ifdef L_dysize
2476 /* Return the number of days in YEAR. */
2477
2478 int dysize(int year)
2479 {
2480 return __isleap(year) ? 366 : 365;
2481 }
2482
2483 #endif
2484 /**********************************************************************/
2485