diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-02-12 00:22:29 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-02-12 00:22:29 -0500 |
commit | 0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 (patch) | |
tree | 6eaef0d8a720fa3da580de87b647fff796fe80b3 /src/time | |
download | musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.gz musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.bz2 musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.xz musl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.zip |
initial check-in, version 0.5.0v0.5.0
Diffstat (limited to 'src/time')
-rw-r--r-- | src/time/__asctime.c | 27 | ||||
-rw-r--r-- | src/time/__time.h | 9 | ||||
-rw-r--r-- | src/time/__time_to_tm.c | 81 | ||||
-rw-r--r-- | src/time/__tm_to_time.c | 33 | ||||
-rw-r--r-- | src/time/asctime.c | 9 | ||||
-rw-r--r-- | src/time/asctime_r.c | 8 | ||||
-rw-r--r-- | src/time/clock.c | 9 | ||||
-rw-r--r-- | src/time/clock_gettime.c | 7 | ||||
-rw-r--r-- | src/time/ctime.c | 6 | ||||
-rw-r--r-- | src/time/ctime_r.c | 8 | ||||
-rw-r--r-- | src/time/difftime.c | 6 | ||||
-rw-r--r-- | src/time/gettimeofday.c | 9 | ||||
-rw-r--r-- | src/time/gmtime.c | 11 | ||||
-rw-r--r-- | src/time/gmtime_r.c | 10 | ||||
-rw-r--r-- | src/time/localtime.c | 12 | ||||
-rw-r--r-- | src/time/localtime_r.c | 11 | ||||
-rw-r--r-- | src/time/mktime.c | 24 | ||||
-rw-r--r-- | src/time/nanosleep.c | 13 | ||||
-rw-r--r-- | src/time/strftime.c | 172 | ||||
-rw-r--r-- | src/time/strptime.c | 178 | ||||
-rw-r--r-- | src/time/time.c | 12 | ||||
-rw-r--r-- | src/time/times.c | 7 | ||||
-rw-r--r-- | src/time/timezone.s | 27 | ||||
-rw-r--r-- | src/time/tzset.c | 173 | ||||
-rw-r--r-- | src/time/utime.c | 12 |
25 files changed, 874 insertions, 0 deletions
diff --git a/src/time/__asctime.c b/src/time/__asctime.c new file mode 100644 index 00000000..18535802 --- /dev/null +++ b/src/time/__asctime.c @@ -0,0 +1,27 @@ +#include <time.h> +#include <stdio.h> +#include <langinfo.h> + +const char *__langinfo(nl_item); + +char *__asctime(const struct tm *tm, char *buf) +{ + /* FIXME: change __langinfo to __C_langinfo once we have locales */ + if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", + __langinfo(ABDAY_1+tm->tm_wday), + __langinfo(ABMON_1+tm->tm_mon), + tm->tm_mday, tm->tm_hour, + tm->tm_min, tm->tm_sec, + 1900 + tm->tm_year) >= 26) + { + /* ISO C requires us to use the above format string, + * even if it will not fit in the buffer. Thus asctime_r + * is _supposed_ to crash if the fields in tm are too large. + * We follow this behavior and crash "gracefully" to warn + * application developers that they may not be so lucky + * on other implementations (e.g. stack smashing..). + */ + *(int*)0 = 0; + } + return buf; +} diff --git a/src/time/__time.h b/src/time/__time.h new file mode 100644 index 00000000..967e5180 --- /dev/null +++ b/src/time/__time.h @@ -0,0 +1,9 @@ +time_t __tm_to_time(struct tm *); +struct tm *__time_to_tm(time_t, struct tm *); +void __tzset(void); +struct tm *__dst_adjust(struct tm *tm); + +extern long __timezone; +extern int __daylight; +extern int __dst_offset; +extern char *__tzname[2]; diff --git a/src/time/__time_to_tm.c b/src/time/__time_to_tm.c new file mode 100644 index 00000000..a1ebc452 --- /dev/null +++ b/src/time/__time_to_tm.c @@ -0,0 +1,81 @@ +#include <time.h> + +/* C defines the rounding for division in a nonsensical way */ +#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) + +#define DAYS_PER_400Y (365*400 + 97) +#define DAYS_PER_100Y (365*100 + 24) +#define DAYS_PER_4Y (365*4 + 1) + +/* FIXME: use lldiv once it's fixed to compute quot,rem together */ +struct tm *__time_to_tm(time_t t, struct tm *tm) +{ + /* months are march-based */ + static const int days_thru_month[] = {31,61,92,122,153,184,214,245,275,306,337,366}; + long long bigday; + unsigned int day, year4, year100; + int year, year400; + int month; + int leap; + int hour, min, sec; + int wday, mday, yday; + + /* start from 2000-03-01 (multiple of 400 years) */ + t += -946684800 - 86400*(31+29); + + bigday = Q(t, 86400); + sec = t-bigday*86400; + + hour = sec/3600; + sec -= hour*3600; + min = sec/60; + sec -= min*60; + + /* 2000-03-01 was a wednesday */ + wday = (3+bigday)%7; + if (wday < 0) wday += 7; + + t = -946684800LL - 86400*(31+29) + 9000000; + + year400 = Q(bigday, DAYS_PER_400Y); + day = bigday-year400*DAYS_PER_400Y; + + year100 = day/DAYS_PER_100Y; + if (year100 == 4) year100--; + day -= year100*DAYS_PER_100Y; + + year4 = day/DAYS_PER_4Y; + if (year4 == 25) year4--; + day -= year4*DAYS_PER_4Y; + + year = day/365; + if (year == 4) year--; + day -= year*365; + + leap = !year && (year4 || !year100); + yday = day + 31+28 + leap; + if (yday >= 365+leap) yday -= 365+leap; + + year += 4*year4 + 100*year100 + 400*year400 + 2000-1900; + + for (month=0; days_thru_month[month] <= day; month++); + if (month) day -= days_thru_month[month-1]; + month += 2; + if (month >= 12) { + month -= 12; + year++; + } + + mday = day+1; + + tm->tm_sec = sec; + tm->tm_min = min; + tm->tm_hour= hour; + tm->tm_mday= mday; + tm->tm_mon = month; + tm->tm_year= year; + tm->tm_wday= wday; + tm->tm_yday= yday; + + return tm; +} diff --git a/src/time/__tm_to_time.c b/src/time/__tm_to_time.c new file mode 100644 index 00000000..3fa15fad --- /dev/null +++ b/src/time/__tm_to_time.c @@ -0,0 +1,33 @@ +#include <time.h> + +/* C defines the rounding for division in a nonsensical way */ +#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) + +time_t __tm_to_time(struct tm *tm) +{ + time_t year = tm->tm_year + -100; + int month = tm->tm_mon; + int day = tm->tm_mday; + int z4, z100, z400; + + /* normalize month */ + if (month >= 12) { + year += month/12; + month %= 12; + } else if (month < 0) { + year += month/12; + month %= 12; + if (month) { + month += 12; + year--; + } + } + z4 = Q(year - (month < 2), 4); + z100 = Q(z4, 25); + z400 = Q(z100, 4); + day += year*365 + z4 - z100 + z400 + + month[(int []){0,31,59,90,120,151,181,212,243,273,304,335}]; + return (long long)day*86400 + + tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec + - -946684800; /* the dawn of time :) */ +} diff --git a/src/time/asctime.c b/src/time/asctime.c new file mode 100644 index 00000000..3102eb87 --- /dev/null +++ b/src/time/asctime.c @@ -0,0 +1,9 @@ +#include <time.h> + +char *__asctime(const struct tm *, char *); + +char *asctime(const struct tm *tm) +{ + static char buf[26]; + return __asctime(tm, buf); +} diff --git a/src/time/asctime_r.c b/src/time/asctime_r.c new file mode 100644 index 00000000..e51b8804 --- /dev/null +++ b/src/time/asctime_r.c @@ -0,0 +1,8 @@ +#include <time.h> + +char *__asctime(const struct tm *, char *); + +char *asctime_r(const struct tm *tm, char *buf) +{ + return __asctime(tm, buf); +} diff --git a/src/time/clock.c b/src/time/clock.c new file mode 100644 index 00000000..2feddb36 --- /dev/null +++ b/src/time/clock.c @@ -0,0 +1,9 @@ +#include <time.h> +#include <sys/times.h> + +/* this function assumes 100 hz linux and corrects for it */ +clock_t clock() +{ + struct tms tms; + return (unsigned long)times(&tms)*10000; +} diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c new file mode 100644 index 00000000..dab09d50 --- /dev/null +++ b/src/time/clock_gettime.c @@ -0,0 +1,7 @@ +#include <time.h> +#include "syscall.h" + +int clock_gettime(clockid_t clk, struct timespec *ts) +{ + return syscall2(__NR_clock_gettime, clk, (long)ts); +} diff --git a/src/time/ctime.c b/src/time/ctime.c new file mode 100644 index 00000000..185ec554 --- /dev/null +++ b/src/time/ctime.c @@ -0,0 +1,6 @@ +#include <time.h> + +char *ctime(const time_t *t) +{ + return asctime(localtime(t)); +} diff --git a/src/time/ctime_r.c b/src/time/ctime_r.c new file mode 100644 index 00000000..d2260a16 --- /dev/null +++ b/src/time/ctime_r.c @@ -0,0 +1,8 @@ +#include <time.h> + +char *ctime_r(const time_t *t, char *buf) +{ + struct tm tm; + localtime_r(t, &tm); + return asctime_r(&tm, buf); +} diff --git a/src/time/difftime.c b/src/time/difftime.c new file mode 100644 index 00000000..80a18cc0 --- /dev/null +++ b/src/time/difftime.c @@ -0,0 +1,6 @@ +#include <time.h> + +double difftime(time_t t1, time_t t0) +{ + return t1-t0; +} diff --git a/src/time/gettimeofday.c b/src/time/gettimeofday.c new file mode 100644 index 00000000..2b8a287d --- /dev/null +++ b/src/time/gettimeofday.c @@ -0,0 +1,9 @@ +#define SYSCALL_RETURN_ERRNO +#include <sys/time.h> +#include "syscall.h" + +int gettimeofday(struct timeval *tv, void *tz) +{ + syscall2(__NR_gettimeofday, (long)tv, 0); + return 0; +} diff --git a/src/time/gmtime.c b/src/time/gmtime.c new file mode 100644 index 00000000..d4d5d1f1 --- /dev/null +++ b/src/time/gmtime.c @@ -0,0 +1,11 @@ +#include <time.h> + +#include "__time.h" + +struct tm *gmtime(const time_t *t) +{ + static struct tm tm; + __time_to_tm(*t, &tm); + tm.tm_isdst = 0; + return &tm; +} diff --git a/src/time/gmtime_r.c b/src/time/gmtime_r.c new file mode 100644 index 00000000..5b565a65 --- /dev/null +++ b/src/time/gmtime_r.c @@ -0,0 +1,10 @@ +#include <time.h> + +#include "__time.h" + +struct tm *gmtime_r(const time_t *t, struct tm *result) +{ + __time_to_tm(*t, result); + result->tm_isdst = 0; + return result; +} diff --git a/src/time/localtime.c b/src/time/localtime.c new file mode 100644 index 00000000..abd5e84d --- /dev/null +++ b/src/time/localtime.c @@ -0,0 +1,12 @@ +#include <time.h> + +#include "__time.h" + +struct tm *localtime(const time_t *t) +{ + static struct tm tm; + __tzset(); + __time_to_tm(*t - __timezone, &tm); + tm.tm_isdst = -1; + return __dst_adjust(&tm); +} diff --git a/src/time/localtime_r.c b/src/time/localtime_r.c new file mode 100644 index 00000000..2bf10378 --- /dev/null +++ b/src/time/localtime_r.c @@ -0,0 +1,11 @@ +#include <time.h> + +#include "__time.h" + +struct tm *localtime_r(const time_t *t, struct tm *result) +{ + __tzset(); + __time_to_tm(*t - __timezone, result); + result->tm_isdst = -1; + return __dst_adjust(result); +} diff --git a/src/time/mktime.c b/src/time/mktime.c new file mode 100644 index 00000000..858cd50d --- /dev/null +++ b/src/time/mktime.c @@ -0,0 +1,24 @@ +#include <time.h> + +#include "__time.h" + +time_t mktime(struct tm *tm) +{ + int isdst = tm->tm_isdst; + time_t t, lt; + + __tzset(); + + tm->tm_sec += __timezone; + if (isdst > 0) tm->tm_sec += __dst_offset; + + t = __tm_to_time(tm); + + lt = t - __timezone; + if (isdst > 0) lt -= __dst_offset; + __time_to_tm(lt, tm); + + __dst_adjust(tm); + + return t; +} diff --git a/src/time/nanosleep.c b/src/time/nanosleep.c new file mode 100644 index 00000000..5ac4c359 --- /dev/null +++ b/src/time/nanosleep.c @@ -0,0 +1,13 @@ +#include <unistd.h> +#include <time.h> +#include "syscall.h" +#include "libc.h" + +int nanosleep(const struct timespec *req, struct timespec *rem) +{ + int ret; + CANCELPT_BEGIN; + ret = syscall2(__NR_nanosleep, (long)req, (long)rem); + CANCELPT_END; + return ret; +} diff --git a/src/time/strftime.c b/src/time/strftime.c new file mode 100644 index 00000000..f1b94631 --- /dev/null +++ b/src/time/strftime.c @@ -0,0 +1,172 @@ +#include <stdio.h> +#include <stdlib.h> +#include <langinfo.h> +#include <time.h> +#include "__time.h" + +// FIXME: integer overflows + +const char *__langinfo(nl_item); + +size_t strftime(char *s, size_t n, const char *f, const struct tm *tm) +{ + nl_item item; + int val; + const char *fmt; + size_t l; + for (l=0; *f && l<n; f++) { + if (*f == '%') { +do_fmt: + switch (*++f) { + case '%': + goto literal; + case 'E': + case 'O': + goto do_fmt; + case 'a': + item = ABDAY_1 + tm->tm_wday; + goto nl_strcat; + case 'A': + item = DAY_1 + tm->tm_wday; + goto nl_strcat; + case 'h': + case 'b': + item = ABMON_1 + tm->tm_mon; + goto nl_strcat; + case 'B': + item = MON_1 + tm->tm_mon; + goto nl_strcat; + case 'c': + item = D_T_FMT; + goto nl_strftime; + case 'C': + val = (1900+tm->tm_year) / 100; + fmt = "%02d"; + goto number; + case 'd': + val = tm->tm_mday; + fmt = "%02d"; + goto number; + case 'D': + fmt = "%m/%d/%y"; + goto recu_strftime; + case 'e': + val = tm->tm_mday; + fmt = "%2d"; + goto number; + case 'F': + fmt = "%Y-%m-%d"; + goto recu_strftime; + case 'g': + // FIXME + val = 0; //week_based_year(tm)%100; + fmt = "%02d"; + goto number; + case 'G': + // FIXME + val = 0; //week_based_year(tm); + fmt = "%04d"; + goto number; + case 'H': + val = tm->tm_hour; + fmt = "%02d"; + goto number; + case 'I': + val = tm->tm_hour; + if (!val) val = 12; + else if (val > 12) val -= 12; + fmt = "%02d"; + goto number; + case 'j': + val = tm->tm_yday+1; + fmt = "%03d"; + goto number; + case 'm': + val = tm->tm_mon+1; + fmt = "%02d"; + goto number; + case 'M': + val = tm->tm_min; + fmt = "%02d"; + goto number; + case 'n': + s[l++] = '\n'; + continue; + case 'p': + item = tm->tm_hour >= 12 ? PM_STR : AM_STR; + goto nl_strcat; + case 'r': + item = T_FMT_AMPM; + goto nl_strftime; + case 'R': + fmt = "%H:%M"; + goto recu_strftime; + case 'S': + val = tm->tm_sec; + fmt = "%02d"; + goto number; + case 't': + s[l++] = '\t'; + continue; + case 'T': + fmt = "%H:%M:%S"; + goto recu_strftime; + case 'u': + val = tm->tm_wday ? tm->tm_wday : 7; + fmt = "%d"; + goto number; + case 'U': + case 'V': + case 'W': + // FIXME: week number mess.. + continue; + case 'w': + val = tm->tm_wday; + fmt = "%d"; + goto number; + case 'x': + item = D_FMT; + goto nl_strftime; + case 'X': + item = T_FMT; + goto nl_strftime; + case 'y': + val = tm->tm_year % 100; + fmt = "%02d"; + goto number; + case 'Y': + val = tm->tm_year + 1900; + fmt = "%04d"; + goto number; + case 'z': + if (tm->tm_isdst < 0) continue; + val = -__timezone - (tm->tm_isdst ? __dst_offset : 0); + l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60); + continue; + case 'Z': + if (tm->tm_isdst < 0 || !__tzname[0] || !__tzname[0][0]) + continue; + l += snprintf(s+l, n-l, "%s", __tzname[!!tm->tm_isdst]); + continue; + default: + return 0; + } + } +literal: + s[l++] = *f; + continue; +number: + l += snprintf(s+l, n-l, fmt, val); + continue; +nl_strcat: + l += snprintf(s+l, n-l, "%s", __langinfo(item)); + continue; +nl_strftime: + fmt = __langinfo(item); +recu_strftime: + l += strftime(s+l, n-l, fmt, tm); + } + if (l >= n) return 0; + s[l] = 0; + return l; +} diff --git a/src/time/strptime.c b/src/time/strptime.c new file mode 100644 index 00000000..db72e610 --- /dev/null +++ b/src/time/strptime.c @@ -0,0 +1,178 @@ +#include <stdio.h> +#include <stdlib.h> +#include <langinfo.h> +#include <time.h> + +const char *__langinfo(nl_item); + +char *strptime(const char *s, const char *f, struct tm *tm) +{ + return NULL; +} + +#if 0 + +char *strptime(const char *s, const char *f, struct tm *tm) +{ + nl_item item; + int *dest; + const char *fmt; + for (; *f; f++) { + if (isspace(*f)) goto whitespace; + if (*f == '%') { +do_fmt: + switch (*++f) { + case '%': + goto literal; + case 'E': + case 'O': + goto do_fmt; + case 'a': + item = ABDAY_1 + tm->tm_wday; + goto nl_strcat; + case 'A': + item = DAY_1 + tm->tm_wday; + goto nl_strcat; + case 'h': + case 'b': + item = ABMON_1 + tm->tm_mon; + goto nl_strcat; + case 'B': + item = MON_1 + tm->tm_mon; + goto nl_strcat; + case 'c': + item = D_T_FMT; + goto nl_strftime; + case 'C': + val = (1900+tm->tm_year) / 100; + fmt = "%02d"; + goto number; + case 'd': + val = tm->tm_mday; + fmt = "%02d"; + goto number; + case 'D': + fmt = "%m/%d/%y"; + goto recu_strftime; + case 'e': + val = tm->tm_mday; + fmt = "%2d"; + goto number; + case 'F': + fmt = "%Y-%m-%d"; + goto recu_strftime; + case 'g': + // FIXME + val = 0; //week_based_year(tm)%100; + fmt = "%02d"; + goto number; + case 'G': + // FIXME + val = 0; //week_based_year(tm); + fmt = "%04d"; + goto number; + case 'H': + val = tm->tm_hour; + fmt = "%02d"; + goto number; + case 'I': + val = tm->tm_hour; + if (!val) val = 12; + else if (val > 12) val -= 12; + fmt = "%02d"; + goto number; + case 'j': + val = tm->tm_yday+1; + fmt = "%03d"; + goto number; + case 'm': + val = tm->tm_mon+1; + fmt = "%02d"; + goto number; + case 'M': + val = tm->tm_min; + fmt = "%02d"; + goto number; + case 'n': + case 't': + goto whitespace; + case 'p': + item = tm->tm_hour >= 12 ? PM_STR : AM_STR; + goto nl_strcat; + case 'r': + item = T_FMT_AMPM; + goto nl_strftime; + case 'R': + fmt = "%H:%M"; + goto recu_strftime; + case 'S': + val = tm->tm_sec; + fmt = "%02d"; + goto number; + case 'T': + fmt = "%H:%M:%S"; + goto recu_strftime; + case 'u': + val = tm->tm_wday ? tm->tm_wday : 7; + fmt = "%d"; + goto number; + case 'U': + case 'V': + case 'W': + // FIXME: week number mess.. + continue; + case 'w': + val = tm->tm_wday; + fmt = "%d"; + goto number; + case 'x': + item = D_FMT; + goto nl_strftime; + case 'X': + item = T_FMT; + goto nl_strftime; + case 'y': + val = tm->tm_year % 100; + fmt = "%02d"; + goto number; + case 'Y': + val = tm->tm_year + 1900; + fmt = "%04d"; + goto number; + case 'z': + if (tm->tm_isdst < 0) continue; + val = timezone + (tm->tm_isdst) ? __dst_offset : 0; + l += snprintf(s+l, n-l, "%+02d%02d", val/60, abs(val%60)); + continue; + case 'Z': + if (tm->tm_isdst < 0 || !tzname[0] || !tzname[0][0]) + continue; + l += snprintf(s+l, n-l, "%s", tzname[!!tm->tm_isdst]); + continue; + } + default: + return NULL; + } +literal: + if (*s++ != *f) return NULL; + continue; +whitespace: + while(isspace(*s)) s++; + continue; +number: + l += snprintf(s+l, n-l, fmt, val); + continue; +nl_strcat: + l += snprintf(s+l, n-l, "%s", __langinfo(item)); + continue; +nl_strftime: + fmt = __langinfo(item); +recu_strftime: + l += strftime(s+l, n-l, fmt, tm); + } + if (l >= n) return 0; + s[l] = 0; + return l; +} + +#endif diff --git a/src/time/time.c b/src/time/time.c new file mode 100644 index 00000000..3457dade --- /dev/null +++ b/src/time/time.c @@ -0,0 +1,12 @@ +#define SYSCALL_RETURN_ERRNO +#include <time.h> +#include <sys/time.h> +#include "syscall.h" + +time_t time(time_t *t) +{ + struct timeval tv; + syscall2(__NR_gettimeofday, (long)&tv, 0); + if (t) *t = tv.tv_sec; + return tv.tv_sec; +} diff --git a/src/time/times.c b/src/time/times.c new file mode 100644 index 00000000..e9b5a823 --- /dev/null +++ b/src/time/times.c @@ -0,0 +1,7 @@ +#include <sys/times.h> +#include "syscall.h" + +clock_t times(struct tms *tms) +{ + return syscall1(__NR_times, (long)&tms); +} diff --git a/src/time/timezone.s b/src/time/timezone.s new file mode 100644 index 00000000..4e167b0b --- /dev/null +++ b/src/time/timezone.s @@ -0,0 +1,27 @@ +.data + +.global timezone +.global __timezone +.global daylight +.global __daylight +.global tzname +.global __tzname + +__timezone: +timezone: + .long 0 +.size timezone,.-timezone +.size __timezone,.-__timezone + +__daylight: +daylight: + .long 0 +.size daylight,.-daylight +.size __daylight,.-__daylight + +__tzname: +tzname: + .long 0 + .long 0 +.size tzname,.-tzname +.size __tzname,.-__tzname diff --git a/src/time/tzset.c b/src/time/tzset.c new file mode 100644 index 00000000..6d69957e --- /dev/null +++ b/src/time/tzset.c @@ -0,0 +1,173 @@ +#include <time.h> +#include <ctype.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include "libc.h" + +#include "__time.h" + +long __timezone = 0; +int __daylight = 0; +char *__tzname[2] = { 0, 0 }; +int __dst_offset = 0; + +weak_alias(__timezone, timezone); +weak_alias(__daylight, daylight); +weak_alias(__tzname, tzname); +weak_alias(__dst_offset, dst_offset); + +static char std_name[TZNAME_MAX+1]; +static char dst_name[TZNAME_MAX+1]; + +/* all elements are zero-based */ +static struct rule { + char month; + char week; + short day; + int time; +} __dst_start, __dst_end; + +static void zname(char *d, char **s) +{ + int i; + for (i=0; i<TZNAME_MAX && isalpha(d[i]=**s); i++, (*s)++); + d[i] = 0; +} + +static int hhmmss(char **s) +{ + int ofs = strtol(*s, s, 10)*3600; + if (ofs >= 0) { + if (**s == ':') ofs += strtol(*s+1, s, 10)*60; + if (**s == ':') ofs += strtol(*s+1, s, 10); + } else { + if (**s == ':') ofs -= strtol(*s+1, s, 10)*60; + if (**s == ':') ofs -= strtol(*s+1, s, 10); + } + return ofs; +} + +static int dstrule(struct rule *rule, char **s) +{ + if (**s != ',') return -1; + switch (*++*s) { + case 'J': + rule->month = 'J'; + rule->day = strtol(*s+1, s, 10)-1; + break; + case 'M': + rule->month = strtol(*s+1, s, 10)-1; + if (**s != '.' || rule->month < 0 || rule->month > 11) + return -1; + rule->week = strtol(*s+1, s, 10)-1; + if (**s != '.' || rule->week < 0 || rule->week > 4) + return -1; + rule->day = strtol(*s+1, s, 10); + if (rule->day < 0 || rule->day > 6) + return -1; + break; + default: + rule->month = 'L'; + rule->day = strtol(*s+1, s, 10); + break; + } + if (**s == '/') { + (*s)++; + rule->time = hhmmss(s); + } else rule->time = 7200; + return 0; +} + +void tzset(void) +{ + char *z, *a; + + strcpy(std_name, "GMT"); + strcpy(dst_name, "GMT"); + __tzname[0] = std_name; + __tzname[1] = dst_name; + __timezone = 0; + __daylight = 0; + + if (!(z = getenv("TZ")) || !isalpha(*z)) return; + + zname(std_name, &z); + __timezone = hhmmss(&z); + + zname(dst_name, &z); + if (dst_name[0]) __daylight=1; + a = z; + __dst_offset = hhmmss(&z) - __timezone; + if (z==a) __dst_offset = -3600; + + if (dstrule(&__dst_start, &z) || dstrule(&__dst_end, &z)) + __daylight = 0; +} + +void __tzset(void) +{ + static int lock, init; + if (init) return; + LOCK(&lock); + if (!init) tzset(); + init=1; + UNLOCK(&lock); +} + +static int is_leap(int year) +{ + year -= 100; + return !(year&3) && ((year%100) || !(year%400)); +} + +static int cutoff_yday(struct tm *tm, struct rule *rule) +{ + static const char days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31}; + static const int first_day[] = {0,31,59,90,120,151,181,212,243,273,304,335}; + int yday, mday, leap; + + switch (rule->month) { + case 'J': + return rule->day + (tm->tm_mon > 1 && is_leap(tm->tm_year)); + case 'L': + return rule->day; + default: + yday = first_day[rule->month]; + leap = is_leap(tm->tm_year); + if (rule->month > 1 && leap) yday++; + mday = (rule->day - (yday + tm->tm_wday - tm->tm_yday) + 1400)%7 + 7*rule->week; + if (mday >= days_in_month[rule->month] + (leap && rule->month == 1)) + mday -= 7; + return mday + yday; + } +} + +struct tm *__dst_adjust(struct tm *tm) +{ + time_t t; + int start, end, secs; + int after_start, before_end; + + if (tm->tm_isdst >= 0) return tm; + if (!__daylight) { + tm->tm_isdst = 0; + return tm; + } + + secs = tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec; + start = cutoff_yday(tm, &__dst_start); + end = cutoff_yday(tm, &__dst_end); + + after_start = (tm->tm_yday > start || (tm->tm_yday == start && secs >= __dst_start.time)); + before_end = (tm->tm_yday < end || (tm->tm_yday == end && secs < __dst_end.time)); + + if ((after_start && before_end) || ((end < start) && (after_start || before_end))) { + tm->tm_sec -= __dst_offset; + tm->tm_isdst = 1; + t = __tm_to_time(tm); + return __time_to_tm(t, tm); + } else tm->tm_isdst = 0; + + return tm; +} diff --git a/src/time/utime.c b/src/time/utime.c new file mode 100644 index 00000000..56e9e13a --- /dev/null +++ b/src/time/utime.c @@ -0,0 +1,12 @@ +#include <utime.h> +#include "syscall.h" + +int utime(const char *path, const struct utimbuf *times) +{ + long ktimes[2]; + if (times) { + ktimes[0] = times->actime; + ktimes[1] = times->modtime; + } + return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0); +} |