OSDN Git Service

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