OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [misc/] [time/] [time.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.