OSDN Git Service

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