1/*
2 * Copyright 2010, Oliver Tappe, zooey@hirschkaefer.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <errno.h>
8#include <stdlib.h>
9#include <string.h>
10#include <time.h>
11
12#include <syscalls.h>
13
14#include <StorageDefs.h>
15
16#include <errno_private.h>
17#include "LocaleBackend.h"
18
19
20using BPrivate::Libroot::GetCurrentLocaleBackend;
21using BPrivate::Libroot::LocaleBackend;
22
23
24static char sStandardTZName[64] 		= { "GMT" };
25static char sDaylightSavingTZName[64]	= { "GMT" };
26
27
28char* tzname[2] = {
29	sStandardTZName,
30	sDaylightSavingTZName
31};
32long timezone = 0;
33int daylight = 0;
34
35
36// These three functions are used as a fallback when the locale backend could not
37// be loaded, or for the POSIX locale. They are implemented in localtime_fallback.c.
38extern "C" struct tm* __gmtime_r_fallback(const time_t* timep, struct tm* tmp);
39extern "C" time_t __mktime_fallback(struct tm* tmp);
40extern "C" time_t __timegm_fallback(struct tm* tmp);
41
42
43extern "C" void
44tzset(void)
45{
46	if (GetCurrentLocaleBackend() == NULL && LocaleBackend::LoadBackend() != B_OK)
47		return;
48
49	char timeZoneID[B_FILE_NAME_LENGTH] = { "GMT" };
50	_kern_get_timezone(NULL, timeZoneID, sizeof(timeZoneID));
51
52	GetCurrentLocaleBackend()->TZSet(timeZoneID, getenv("TZ"));
53}
54
55
56extern "C" struct tm*
57localtime(const time_t* inTime)
58{
59	static tm tm;
60
61	return localtime_r(inTime, &tm);
62}
63
64
65extern "C" struct tm*
66localtime_r(const time_t* inTime, struct tm* tmOut)
67{
68	if (inTime == NULL) {
69		__set_errno(EINVAL);
70		return NULL;
71	}
72
73	tzset();
74
75	LocaleBackend* backend = GetCurrentLocaleBackend();
76
77	if (backend != NULL) {
78		status_t status = backend->Localtime(inTime, tmOut);
79
80		if (status != B_OK)
81			__set_errno(EOVERFLOW);
82
83		return tmOut;
84	}
85
86	// without a locale backend, there are no timezones, so we fall back to
87	// using a basic gmtime_r implementation.
88	return __gmtime_r_fallback(inTime, tmOut);
89}
90
91
92extern "C" struct tm*
93gmtime(const time_t* inTime)
94{
95	static tm tm;
96
97	return gmtime_r(inTime, &tm);
98}
99
100
101extern "C" struct tm*
102gmtime_r(const time_t* inTime, struct tm* tmOut)
103{
104	if (inTime == NULL) {
105		__set_errno(EINVAL);
106		return NULL;
107	}
108
109	tzset();
110
111	LocaleBackend* backend = GetCurrentLocaleBackend();
112
113	if (backend != NULL) {
114		status_t status = backend->Gmtime(inTime, tmOut);
115
116		if (status != B_OK)
117			__set_errno(EOVERFLOW);
118
119		return tmOut;
120	}
121
122	// without a locale backend, we fall back to using a basic gmtime_r
123	// implementation.
124	return __gmtime_r_fallback(inTime, tmOut);
125}
126
127
128extern "C" time_t
129mktime(struct tm* inTm)
130{
131	if (inTm == NULL) {
132		__set_errno(EINVAL);
133		return -1;
134	}
135
136	tzset();
137
138	LocaleBackend* backend = GetCurrentLocaleBackend();
139
140	if (backend != NULL) {
141		time_t timeOut;
142		status_t status = backend->Mktime(inTm, timeOut);
143
144		if (status != B_OK) {
145			__set_errno(EOVERFLOW);
146			return -1;
147		}
148
149		return timeOut;
150	}
151
152	// without a locale backend, we fall back to using a basic gmtime_r
153	// implementation.
154	return __mktime_fallback(inTm);
155}
156
157
158extern "C" time_t
159timegm(struct tm* inTm)
160{
161	if (inTm == NULL) {
162		__set_errno(EINVAL);
163		return -1;
164	}
165	tzset();
166
167	LocaleBackend* backend = GetCurrentLocaleBackend();
168
169	if (backend != NULL) {
170		time_t timeOut;
171		status_t status = backend->Timegm(inTm, timeOut);
172
173		if (status != B_OK) {
174			__set_errno(EOVERFLOW);
175			return -1;
176		}
177
178		return timeOut;
179	}
180
181	// without a locale backend, we fall back to using a basic timegm
182	// implementation.
183	return __timegm_fallback(inTm);
184}
185