Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / time / tzset_r.c
bloba6f15f6df3a1d22d53fed135435906d741163bf8
1 #include <_ansi.h>
2 #include <reent.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/time.h>
8 #include "local.h"
10 #define sscanf siscanf /* avoid to pull in FP functions. */
12 #define TZNAME_MIN 3 /* POSIX min TZ abbr size local def */
13 #define TZNAME_MAX 10 /* POSIX max TZ abbr size local def */
15 static char __tzname_std[TZNAME_MAX + 2];
16 static char __tzname_dst[TZNAME_MAX + 2];
17 static char *prev_tzenv = NULL;
19 void
20 _tzset_unlocked_r (struct _reent *reent_ptr)
22 char *tzenv;
23 unsigned short hh, mm, ss, m, w, d;
24 int sign, n;
25 int i, ch;
26 long offset0, offset1;
27 __tzinfo_type *tz = __gettzinfo ();
28 struct __tzrule_struct default_tzrule = {'J', 0, 0, 0, 0, (time_t)0, 0L };
30 if ((tzenv = _getenv_r (reent_ptr, "TZ")) == NULL)
32 _timezone = 0;
33 _daylight = 0;
34 _tzname[0] = "GMT";
35 _tzname[1] = "GMT";
36 tz->__tzrule[0] = default_tzrule;
37 tz->__tzrule[1] = default_tzrule;
38 free(prev_tzenv);
39 prev_tzenv = NULL;
40 return;
43 if (prev_tzenv != NULL && strcmp(tzenv, prev_tzenv) == 0)
44 return;
46 free(prev_tzenv);
47 prev_tzenv = _malloc_r (reent_ptr, strlen(tzenv) + 1);
48 if (prev_tzenv != NULL)
49 strcpy (prev_tzenv, tzenv);
51 /* default to unnamed UTC in case of error */
52 _timezone = 0;
53 _daylight = 0;
54 _tzname[0] = "";
55 _tzname[1] = "";
56 tz->__tzrule[0] = default_tzrule;
57 tz->__tzrule[1] = default_tzrule;
59 /* ignore implementation-specific format specifier */
60 if (*tzenv == ':')
61 ++tzenv;
63 /* allow POSIX angle bracket < > quoted signed alphanumeric tz abbr e.g. <MESZ+0330> */
64 if (*tzenv == '<')
66 ++tzenv;
68 /* quit if no items, too few or too many chars, or no close quote '>' */
69 if (sscanf (tzenv, "%11[-+0-9A-Za-z]%n", __tzname_std, &n) <= 0
70 || n < TZNAME_MIN || TZNAME_MAX < n || '>' != tzenv[n])
71 return;
73 ++tzenv; /* bump for close quote '>' */
75 else
77 /* allow POSIX unquoted alphabetic tz abbr e.g. MESZ */
78 if (sscanf (tzenv, "%11[A-Za-z]%n", __tzname_std, &n) <= 0
79 || n < TZNAME_MIN || TZNAME_MAX < n)
80 return;
83 tzenv += n;
85 sign = 1;
86 if (*tzenv == '-')
88 sign = -1;
89 ++tzenv;
91 else if (*tzenv == '+')
92 ++tzenv;
94 mm = 0;
95 ss = 0;
97 if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) < 1)
98 return;
100 offset0 = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
101 tzenv += n;
103 /* allow POSIX angle bracket < > quoted signed alphanumeric tz abbr e.g. <MESZ+0330> */
104 if (*tzenv == '<')
106 ++tzenv;
108 /* quit if no items, too few or too many chars, or no close quote '>' */
109 if (sscanf (tzenv, "%11[-+0-9A-Za-z]%n", __tzname_dst, &n) <= 0 && tzenv[0] == '>')
110 { /* No dst */
111 _tzname[0] = __tzname_std;
112 _tzname[1] = _tzname[0];
113 tz->__tzrule[0].offset = offset0;
114 _timezone = offset0;
115 return;
117 else if (n < TZNAME_MIN || TZNAME_MAX < n || '>' != tzenv[n])
118 { /* error */
119 return;
122 ++tzenv; /* bump for close quote '>' */
124 else
126 /* allow POSIX unquoted alphabetic tz abbr e.g. MESZ */
127 if (sscanf (tzenv, "%11[A-Za-z]%n", __tzname_dst, &n) <= 0)
128 { /* No dst */
129 _tzname[0] = __tzname_std;
130 _tzname[1] = _tzname[0];
131 tz->__tzrule[0].offset = offset0;
132 _timezone = offset0;
133 return;
135 else if (n < TZNAME_MIN || TZNAME_MAX < n)
136 { /* error */
137 return;
141 tzenv += n;
143 /* otherwise we have a dst name, look for the offset */
144 sign = 1;
145 if (*tzenv == '-')
147 sign = -1;
148 ++tzenv;
150 else if (*tzenv == '+')
151 ++tzenv;
153 hh = 0;
154 mm = 0;
155 ss = 0;
157 n = 0;
158 if (sscanf (tzenv, "%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0)
159 offset1 = offset0 - 3600;
160 else
161 offset1 = sign * (ss + SECSPERMIN * mm + SECSPERHOUR * hh);
163 tzenv += n;
165 for (i = 0; i < 2; ++i)
167 if (*tzenv == ',')
168 ++tzenv;
170 if (*tzenv == 'M')
172 if (sscanf (tzenv, "M%hu%n.%hu%n.%hu%n", &m, &n, &w, &n, &d, &n) != 3 ||
173 m < 1 || m > 12 || w < 1 || w > 5 || d > 6)
174 return;
176 tz->__tzrule[i].ch = 'M';
177 tz->__tzrule[i].m = m;
178 tz->__tzrule[i].n = w;
179 tz->__tzrule[i].d = d;
181 tzenv += n;
183 else
185 char *end;
186 if (*tzenv == 'J')
188 ch = 'J';
189 ++tzenv;
191 else
192 ch = 'D';
194 d = strtoul (tzenv, &end, 10);
196 /* if unspecified, default to US settings */
197 /* From 1987-2006, US was M4.1.0,M10.5.0, but starting in 2007 is
198 * M3.2.0,M11.1.0 (2nd Sunday March through 1st Sunday November) */
199 if (end == tzenv)
201 if (i == 0)
203 tz->__tzrule[0].ch = 'M';
204 tz->__tzrule[0].m = 3;
205 tz->__tzrule[0].n = 2;
206 tz->__tzrule[0].d = 0;
208 else
210 tz->__tzrule[1].ch = 'M';
211 tz->__tzrule[1].m = 11;
212 tz->__tzrule[1].n = 1;
213 tz->__tzrule[1].d = 0;
216 else
218 tz->__tzrule[i].ch = ch;
219 tz->__tzrule[i].d = d;
222 tzenv = end;
225 /* default time is 02:00:00 am */
226 hh = 2;
227 mm = 0;
228 ss = 0;
229 n = 0;
231 if (*tzenv == '/')
232 if (sscanf (tzenv, "/%hu%n:%hu%n:%hu%n", &hh, &n, &mm, &n, &ss, &n) <= 0)
234 /* error in time format, restore tz rules to default and return */
235 tz->__tzrule[0] = default_tzrule;
236 tz->__tzrule[1] = default_tzrule;
237 return;
240 tz->__tzrule[i].s = ss + SECSPERMIN * mm + SECSPERHOUR * hh;
242 tzenv += n;
245 tz->__tzrule[0].offset = offset0;
246 tz->__tzrule[1].offset = offset1;
247 _tzname[0] = __tzname_std;
248 _tzname[1] = __tzname_dst;
249 __tzcalc_limits (tz->__tzyear);
250 _timezone = tz->__tzrule[0].offset;
251 _daylight = tz->__tzrule[0].offset != tz->__tzrule[1].offset;
254 void
255 _tzset_r (struct _reent *reent_ptr)
257 TZ_LOCK;
258 _tzset_unlocked_r (reent_ptr);
259 TZ_UNLOCK;