OSDN Git Service

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