OSDN Git Service

347c8990c8883ebcb830663d5c4ae1bf92c61b84
[uclinux-h8/uClibc.git] / libc / misc / time / time.c
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
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
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 }
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
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 }
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
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
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
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
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 }
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
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
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
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
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) */
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
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
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
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
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
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
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
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
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
1893 void tzset(void)
1894 {
1895         _time_tzset((time(NULL)) < new_rule_starts);
1896 }
1897
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 }
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
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
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
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
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
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
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 /**********************************************************************/