| #include "local.h" |
| #include "lock.h" |
| #include "stat.h" |
| #include <errno.h> |
| #include <stdio.h> |
| #include <windows.h> |
| |
| #define _FT_OFFSET_IN_SEC (11644473600ULL) |
| #define _FT_OFFSET_IN_USEC (_FT_OFFSET_IN_SEC*1000000ULL) |
| |
| #if _WCE >= 3 |
| void GetCurrentFT(FILETIME *); |
| #endif |
| |
| int daylight; |
| long int timezone; |
| char *tzname[2]; |
| |
| static char __tzname_std[11]; |
| static char __tzname_dst[11]; |
| static char *prev_tzenv = NULL; |
| |
| unsigned long int _dstbias; |
| |
| typedef struct __tzrule_struct { |
| char ch; |
| int m; |
| int n; |
| int d; |
| int s; |
| time_t change; |
| long offset; /* Match type of timezone. */ |
| } __tzrule_t; |
| |
| typedef struct __tzinfo_struct { |
| int __tznorth; |
| int __tzyear; |
| __tzrule_t __tzrule[2]; |
| } __tzinfo_t; |
| |
| static __tzinfo_t tzinfo = { 1, 0, { |
| { 'J', 0, 0, 0, 0, (time_t)0, 0L }, |
| {'J', 0, 0, 0, 0, (time_t)0, 0L } |
| } |
| }; |
| |
| static const int mon_lengths[2][MONSPERYEAR] = { |
| {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, |
| {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} |
| }; |
| |
| static const int year_lengths[2] = { |
| 365, |
| 366 |
| }; |
| |
| static void __tz_lock() { |
| #ifndef __SINGLE_THREAD__ |
| __lock_acquire(__tz_lock_object); |
| #endif |
| } |
| |
| static void __tz_unlock() { |
| #ifndef __SINGLE_THREAD__ |
| __lock_release(__tz_lock_object); |
| #endif |
| } |
| |
| static __tzinfo_t *_gettzinfo() { |
| return &tzinfo; |
| } |
| |
| static int __tzcalc_limits(int year) { |
| int days, year_days, years; |
| int i, j; |
| __tzinfo_t *tz = _gettzinfo(); |
| |
| if (year < EPOCH_YEAR) return 0; |
| |
| tz->__tzyear = year; |
| |
| years = (year - EPOCH_YEAR); |
| |
| year_days = years * 365 + |
| (years - 1 + EPOCH_YEARS_SINCE_LEAP) / 4 - (years - 1 + EPOCH_YEARS_SINCE_CENTURY) / 100 + |
| (years - 1 + EPOCH_YEARS_SINCE_LEAP_CENTURY) / 400; |
| |
| for(i = 0; i < 2; i++) { |
| if(tz->__tzrule[i].ch == 'J') { |
| days = year_days + tz->__tzrule[i].d + (__isleap(year) && tz->__tzrule[i].d >= 60); |
| } else if(tz->__tzrule[i].ch == 'D') { |
| days = year_days + tz->__tzrule[i].d; |
| } else { |
| int yleap = __isleap(year); |
| int m_day, m_wday, wday_diff; |
| const int *ip = mon_lengths[yleap]; |
| |
| days = year_days; |
| |
| for(j = 1; j < tz->__tzrule[i].m; j++) days += ip[j-1]; |
| |
| m_wday = (EPOCH_WDAY + days) % DAYSPERWEEK; |
| |
| wday_diff = tz->__tzrule[i].d - m_wday; |
| if(wday_diff < 0) wday_diff += DAYSPERWEEK; |
| m_day = (tz->__tzrule[i].n - 1) * DAYSPERWEEK + wday_diff; |
| |
| while(m_day >= ip[j-1]) m_day -= DAYSPERWEEK; |
| |
| days += m_day; |
| } |
| |
| /* store the change-over time in GMT form by adding offset */ |
| tz->__tzrule[i].change = days * SECSPERDAY + tz->__tzrule[i].s + tz->__tzrule[i].offset; |
| } |
| |
| tz->__tznorth = (tz->__tzrule[0].change < tz->__tzrule[1].change); |
| |
| return 1; |
| } |
| |
| static void _tzset_hook() { |
| TIME_ZONE_INFORMATION tzinfo; |
| int defused; |
| |
| /* No race condition here, because this function is called |
| wrapped in a lock. see _tzset_r. */ |
| static int alloced = 0; |
| if(!alloced) { |
| static char tzname0[64]; |
| static char tzname1[64]; |
| //strcpy(tzname0, _tzname[0]); |
| //strcpy(tzname1, _tzname[1]); |
| tzname[0] = tzname0; |
| tzname[1] = tzname1; |
| alloced = 1; |
| } |
| |
| if(GetTimeZoneInformation(&tzinfo) == 0xFFFFFFFF) return; |
| |
| timezone = tzinfo.Bias * 60L; |
| |
| if(tzinfo.StandardDate.wMonth != 0) timezone += (tzinfo.StandardBias * 60L); |
| |
| if((tzinfo.DaylightDate.wMonth != 0) && (tzinfo.DaylightBias != 0)) { |
| daylight = 1; |
| _dstbias = (tzinfo.DaylightBias - tzinfo.StandardBias) * 60L; |
| } else { |
| daylight = 0; |
| _dstbias = 0; |
| } |
| |
| if((WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_SEPCHARS, tzinfo.StandardName, -1, tzname[0], 63, NULL, &defused) != 0) && |
| (!defused)) { |
| tzname[0][63] = '\0'; |
| } else { |
| tzname[0][0] = '\0'; |
| } |
| |
| if((WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_SEPCHARS, tzinfo.DaylightName, -1, tzname[1], 63, NULL, &defused) != 0) && |
| (!defused)) { |
| tzname[1][63] = '\0'; |
| } else { |
| tzname[1][0] = '\0'; |
| } |
| } |
| |
| void tzset() { |
| char *tzenv; |
| unsigned short hh, mm, ss, m, w, d; |
| int sign, n; |
| int i, ch; |
| __tzinfo_t *tz = _gettzinfo(); |
| |
| if(!(tzenv = getenv("TZ"))) { |
| __tz_lock(); |
| _tzset_hook(); |
| __tz_unlock(); |
| return; |
| } |
| |
| __tz_lock(); |
| |
| if(prev_tzenv && strcmp(tzenv, prev_tzenv) == 0) { |
| __tz_unlock(); |
| return; |
| } |
| |
| free(prev_tzenv); |
| prev_tzenv = malloc(strlen(tzenv) + 1); |
| if(prev_tzenv) strcpy(prev_tzenv, tzenv); |
| |
| /* ignore implementation-specific format specifier */ |
| if(*tzenv == ':') tzenv++; |
| |
| if(sscanf(tzenv, "%10[^0-9,+-]%n", __tzname_std, &n) <= 0) { |
| __tz_unlock(); |
| return; |
| } |
| |
| tzenv += n; |
| |
| sign = 1; |
| if (*tzenv == '-') { |
| sign = -1; |
| ++tzenv; |
| } else if(*tzenv == '+') ++tzenv; |
| |
| mm = 0; |
| ss = 0; |
| |
| if(sscanf(tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) < 1) { |
| __tz_unlock(); |
| return; |
| } |
| |
| tz->__tzrule[0].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh); |
| tzname[0] = __tzname_std; |
| tzenv += n; |
| |
| if(sscanf(tzenv, "%10[^0-9,+-]%n", __tzname_dst, &n) <= 0) { |
| tzname[1] = tzname[0]; |
| __tz_unlock(); |
| return; |
| } else tzname[1] = __tzname_dst; |
| |
| tzenv += n; |
| |
| /* otherwise we have a dst name, look for the offset */ |
| sign = 1; |
| if(*tzenv == '-') { |
| sign = -1; |
| ++tzenv; |
| } else if(*tzenv == '+') ++tzenv; |
| |
| hh = 0; |
| mm = 0; |
| ss = 0; |
| |
| if(sscanf(tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0) { |
| tz->__tzrule[1].offset = tz->__tzrule[0].offset - 3600; |
| } else { |
| tz->__tzrule[1].offset = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh); |
| } |
| |
| tzenv += n; |
| |
| for (i = 0; i < 2; ++i) { |
| if (*tzenv == ',') tzenv++; |
| |
| if (*tzenv == 'M') { |
| if(sscanf(tzenv, "M%hu%n.%hu%n.%hu%n", &m, &n, &w, &n, &d, &n) != 3 || |
| m < 1 || m > 12 || w < 1 || w > 5 || d > 6) { |
| __tz_unlock(); |
| return; |
| } |
| |
| tz->__tzrule[i].ch = 'M'; |
| tz->__tzrule[i].m = m; |
| tz->__tzrule[i].n = w; |
| tz->__tzrule[i].d = d; |
| |
| tzenv += n; |
| } else { |
| char *end; |
| if(*tzenv == 'J') { |
| ch = 'J'; |
| ++tzenv; |
| } else ch = 'D'; |
| |
| d = strtoul(tzenv, &end, 10); |
| |
| /* if unspecified, default to US settings */ |
| if(end == tzenv) { |
| if(i == 0) { |
| tz->__tzrule[0].ch = 'M'; |
| tz->__tzrule[0].m = 4; |
| tz->__tzrule[0].n = 1; |
| tz->__tzrule[0].d = 0; |
| } else { |
| tz->__tzrule[1].ch = 'M'; |
| tz->__tzrule[1].m = 10; |
| tz->__tzrule[1].n = 5; |
| tz->__tzrule[1].d = 0; |
| } |
| } else { |
| tz->__tzrule[i].ch = ch; |
| tz->__tzrule[i].d = d; |
| } |
| tzenv = end; |
| } |
| |
| /* default time is 02:00:00 am */ |
| hh = 2; |
| mm = 0; |
| ss = 0; |
| n = 0; |
| |
| if(*tzenv == '/') |
| sscanf (tzenv, "/%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n); |
| |
| tz->__tzrule[i].s = ss + SECSPERMIN * mm + SECSPERHOUR * hh; |
| |
| tzenv += n; |
| } |
| |
| __tzcalc_limits (tz->__tzyear); |
| timezone = tz->__tzrule[0].offset; |
| daylight = tz->__tzrule[0].offset != tz->__tzrule[1].offset; |
| |
| __tz_unlock(); |
| } |
| |
| time_t __filetime_to_time_t(FILETIME ft) { |
| ULARGE_INTEGER li; |
| li.LowPart = ft.dwLowDateTime; |
| li.HighPart = ft.dwHighDateTime; |
| |
| // 100-nanosec to seconds |
| li.QuadPart /= 10000000; |
| |
| // FILETIME is from 1601-01-01 T 00:00:00 |
| // time_t is from 1970-01-01 T 00:00:00 |
| // 1970 - 1601 = 369 year (89 leap years) |
| // |
| // ((369y*365d) + 89d) *24h *60min *60sec |
| // = 11644473600 seconds |
| li.QuadPart -= _FT_OFFSET_IN_SEC; |
| return li.LowPart; |
| } |
| |
| FILETIME __time_t_to_filetime(time_t tt/*, int flag*/) { |
| ULARGE_INTEGER li; |
| li.QuadPart = tt; |
| li.QuadPart += _FT_OFFSET_IN_SEC; |
| li.QuadPart *= 10000000; |
| |
| FILETIME ft; |
| ft.dwLowDateTime = li.LowPart; |
| ft.dwHighDateTime = li.HighPart; |
| return ft; |
| } |
| |
| void __filetime_to_timeval(const FILETIME *ft, struct timeval *tv) { |
| tv->tv_sec = __filetime_to_time_t(*ft); |
| tv->tv_usec = (ft->dwLowDateTime / 10) % 1000000; |
| } |
| |
| void __timeval_to_filetime(const struct timeval *tv, FILETIME *ft) { |
| ULARGE_INTEGER li; |
| li.QuadPart = tv->tv_sec * 1000000ULL; |
| li.QuadPart += tv->tv_usec; |
| li.QuadPart += _FT_OFFSET_IN_USEC; |
| li.QuadPart *= 10; |
| ft->dwLowDateTime = li.LowPart; |
| ft->dwHighDateTime = li.HighPart; |
| } |
| |
| time_t time(time_t *t) { |
| time_t r; |
| if(!t) t = &r; |
| FILETIME ft; |
| #if _WCE >= 3 |
| GetCurrentFT(&ft); |
| #else |
| SYSTEMTIME st; |
| GetSystemTime(&st); |
| if(!SystemTimeToFileTime(&st, &ft)) return -1; |
| #endif |
| *t = __filetime_to_time_t(ft); |
| return *t; |
| } |
| |
| struct tm *gmtime_r(const time_t *timep, struct tm *r) { |
| if(!r) return NULL; |
| struct tm *ts = gmtime(timep); |
| if(!ts) return NULL; |
| memcpy(r, ts, sizeof(struct tm)); |
| return r; |
| } |
| |
| struct tm *localtime_r(const time_t *timep, struct tm *r) { |
| if(!r) return NULL; |
| struct tm *ts = localtime(timep); |
| if(!ts) return NULL; |
| memcpy(r, ts, sizeof(struct tm)); |
| return r; |
| } |