| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#ifdef __cplusplus |
|
2
|
|
|
|
|
|
|
extern "C" { |
|
3
|
|
|
|
|
|
|
#endif |
|
4
|
|
|
|
|
|
|
#define PERL_NO_GET_CONTEXT |
|
5
|
|
|
|
|
|
|
#include "EXTERN.h" |
|
6
|
|
|
|
|
|
|
#include "perl.h" |
|
7
|
|
|
|
|
|
|
#include "XSUB.h" |
|
8
|
|
|
|
|
|
|
#include |
|
9
|
|
|
|
|
|
|
#ifdef __cplusplus |
|
10
|
|
|
|
|
|
|
} |
|
11
|
|
|
|
|
|
|
#endif |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
#define DAYS_PER_YEAR 365 |
|
15
|
|
|
|
|
|
|
#define DAYS_PER_QYEAR (4*DAYS_PER_YEAR+1) |
|
16
|
|
|
|
|
|
|
#define DAYS_PER_CENT (25*DAYS_PER_QYEAR-1) |
|
17
|
|
|
|
|
|
|
#define DAYS_PER_QCENT (4*DAYS_PER_CENT+1) |
|
18
|
|
|
|
|
|
|
#define SECS_PER_HOUR (60*60) |
|
19
|
|
|
|
|
|
|
#define SECS_PER_DAY (24*SECS_PER_HOUR) |
|
20
|
|
|
|
|
|
|
/* parentheses deliberately absent on these two, otherwise they don't work */ |
|
21
|
|
|
|
|
|
|
#define MONTH_TO_DAYS 153/5 |
|
22
|
|
|
|
|
|
|
#define DAYS_TO_MONTH 5/153 |
|
23
|
|
|
|
|
|
|
/* offset to bias by March (month 4) 1st between month/mday & year finding */ |
|
24
|
|
|
|
|
|
|
#define YEAR_ADJUST (4*MONTH_TO_DAYS+1) |
|
25
|
|
|
|
|
|
|
/* as used here, the algorithm leaves Sunday as day 1 unless we adjust it */ |
|
26
|
|
|
|
|
|
|
#define WEEKDAY_BIAS 6 /* (1+6)%7 makes Sunday 0 again */ |
|
27
|
|
|
|
|
|
|
#define TP_BUF_SIZE 160 |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
#ifdef WIN32 |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
/* |
|
32
|
|
|
|
|
|
|
* (1) The CRT maintains its own copy of the environment, separate from |
|
33
|
|
|
|
|
|
|
* the Win32API copy. |
|
34
|
|
|
|
|
|
|
* |
|
35
|
|
|
|
|
|
|
* (2) CRT getenv() retrieves from this copy. CRT putenv() updates this |
|
36
|
|
|
|
|
|
|
* copy, and then calls SetEnvironmentVariableA() to update the Win32API |
|
37
|
|
|
|
|
|
|
* copy. |
|
38
|
|
|
|
|
|
|
* |
|
39
|
|
|
|
|
|
|
* (3) win32_getenv() and win32_putenv() call GetEnvironmentVariableA() and |
|
40
|
|
|
|
|
|
|
* SetEnvironmentVariableA() directly, bypassing the CRT copy of the |
|
41
|
|
|
|
|
|
|
* environment. |
|
42
|
|
|
|
|
|
|
* |
|
43
|
|
|
|
|
|
|
* (4) The CRT strftime() "%Z" implementation calls __tzset(). That |
|
44
|
|
|
|
|
|
|
* calls CRT tzset(), but only the first time it is called, and in turn |
|
45
|
|
|
|
|
|
|
* that uses CRT getenv("TZ") to retrieve the timezone info from the CRT |
|
46
|
|
|
|
|
|
|
* local copy of the environment and hence gets the original setting as |
|
47
|
|
|
|
|
|
|
* perl never updates the CRT copy when assigning to $ENV{TZ}. |
|
48
|
|
|
|
|
|
|
* |
|
49
|
|
|
|
|
|
|
* Therefore, we need to retrieve the value of $ENV{TZ} and call CRT |
|
50
|
|
|
|
|
|
|
* putenv() to update the CRT copy of the environment (if it is different) |
|
51
|
|
|
|
|
|
|
* whenever we're about to call tzset(). |
|
52
|
|
|
|
|
|
|
* |
|
53
|
|
|
|
|
|
|
* In addition to all that, when perl is built with PERL_IMPLICIT_SYS |
|
54
|
|
|
|
|
|
|
* defined: |
|
55
|
|
|
|
|
|
|
* |
|
56
|
|
|
|
|
|
|
* (a) Each interpreter has its own copy of the environment inside the |
|
57
|
|
|
|
|
|
|
* perlhost structure. That allows applications that host multiple |
|
58
|
|
|
|
|
|
|
* independent Perl interpreters to isolate environment changes from |
|
59
|
|
|
|
|
|
|
* each other. (This is similar to how the perlhost mechanism keeps a |
|
60
|
|
|
|
|
|
|
* separate working directory for each Perl interpreter, so that calling |
|
61
|
|
|
|
|
|
|
* chdir() will not affect other interpreters.) |
|
62
|
|
|
|
|
|
|
* |
|
63
|
|
|
|
|
|
|
* (b) Only the first Perl interpreter instantiated within a process will |
|
64
|
|
|
|
|
|
|
* "write through" environment changes to the process environment. |
|
65
|
|
|
|
|
|
|
* |
|
66
|
|
|
|
|
|
|
* (c) Even the primary Perl interpreter won't update the CRT copy of the |
|
67
|
|
|
|
|
|
|
* the environment, only the Win32API copy (it calls win32_putenv()). |
|
68
|
|
|
|
|
|
|
* |
|
69
|
|
|
|
|
|
|
* As with CPerlHost::Getenv() and CPerlHost::Putenv() themselves, it makes |
|
70
|
|
|
|
|
|
|
* sense to only update the process environment when inside the main |
|
71
|
|
|
|
|
|
|
* interpreter, but we don't have access to CPerlHost's m_bTopLevel member |
|
72
|
|
|
|
|
|
|
* from here so we'll just have to check PL_curinterp instead. |
|
73
|
|
|
|
|
|
|
* |
|
74
|
|
|
|
|
|
|
* Therefore, we can simply #undef getenv() and putenv() so that those names |
|
75
|
|
|
|
|
|
|
* always refer to the CRT functions, and explicitly call win32_getenv() to |
|
76
|
|
|
|
|
|
|
* access perl's %ENV. |
|
77
|
|
|
|
|
|
|
* |
|
78
|
|
|
|
|
|
|
* We also #undef malloc() and free() to be sure we are using the CRT |
|
79
|
|
|
|
|
|
|
* functions otherwise under PERL_IMPLICIT_SYS they are redefined to calls |
|
80
|
|
|
|
|
|
|
* into VMem::Malloc() and VMem::Free() and all allocations will be freed |
|
81
|
|
|
|
|
|
|
* when the Perl interpreter is being destroyed so we'd end up with a pointer |
|
82
|
|
|
|
|
|
|
* into deallocated memory in environ[] if a program embedding a Perl |
|
83
|
|
|
|
|
|
|
* interpreter continues to operate even after the main Perl interpreter has |
|
84
|
|
|
|
|
|
|
* been destroyed. |
|
85
|
|
|
|
|
|
|
* |
|
86
|
|
|
|
|
|
|
* Note that we don't free() the malloc()ed memory unless and until we call |
|
87
|
|
|
|
|
|
|
* malloc() again ourselves because the CRT putenv() function simply puts its |
|
88
|
|
|
|
|
|
|
* pointer argument into the environ[] arrary (it doesn't make a copy of it) |
|
89
|
|
|
|
|
|
|
* so this memory must otherwise be leaked. |
|
90
|
|
|
|
|
|
|
*/ |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
#undef getenv |
|
93
|
|
|
|
|
|
|
#undef putenv |
|
94
|
|
|
|
|
|
|
# ifdef UNDER_CE |
|
95
|
|
|
|
|
|
|
# define getenv xcegetenv |
|
96
|
|
|
|
|
|
|
# define putenv xceputenv |
|
97
|
|
|
|
|
|
|
# endif |
|
98
|
|
|
|
|
|
|
#undef malloc |
|
99
|
|
|
|
|
|
|
#undef free |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
static void |
|
102
|
|
|
|
|
|
|
fix_win32_tzenv(void) |
|
103
|
|
|
|
|
|
|
{ |
|
104
|
|
|
|
|
|
|
static char* oldenv = NULL; |
|
105
|
|
|
|
|
|
|
char* newenv; |
|
106
|
|
|
|
|
|
|
const char* perl_tz_env = win32_getenv("TZ"); |
|
107
|
|
|
|
|
|
|
const char* crt_tz_env = getenv("TZ"); |
|
108
|
|
|
|
|
|
|
if (perl_tz_env == NULL) |
|
109
|
|
|
|
|
|
|
perl_tz_env = ""; |
|
110
|
|
|
|
|
|
|
if (crt_tz_env == NULL) |
|
111
|
|
|
|
|
|
|
crt_tz_env = ""; |
|
112
|
|
|
|
|
|
|
if (strcmp(perl_tz_env, crt_tz_env) != 0) { |
|
113
|
|
|
|
|
|
|
STRLEN perl_tz_env_len = strlen(perl_tz_env); |
|
114
|
|
|
|
|
|
|
newenv = (char*)malloc(perl_tz_env_len + 4); |
|
115
|
|
|
|
|
|
|
if (newenv != NULL) { |
|
116
|
|
|
|
|
|
|
/* putenv with old MS CRTs will cause a double free internally if you delete |
|
117
|
|
|
|
|
|
|
an env var with the CRT env that doesn't exist in Win32 env (perl %ENV only |
|
118
|
|
|
|
|
|
|
modifies the Win32 env, not CRT env), so always create the env var in Win32 |
|
119
|
|
|
|
|
|
|
env before deleting it with CRT env api, so the error branch never executes |
|
120
|
|
|
|
|
|
|
in __crtsetenv after SetEnvironmentVariableA executes inside __crtsetenv. |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
VC 9/2008 and up dont have this bug, older VC (msvcrt80.dll and older) and |
|
123
|
|
|
|
|
|
|
mingw (msvcrt.dll) have it see [perl #125529] |
|
124
|
|
|
|
|
|
|
*/ |
|
125
|
|
|
|
|
|
|
#if !(_MSC_VER >= 1500) |
|
126
|
|
|
|
|
|
|
if(!perl_tz_env_len) |
|
127
|
|
|
|
|
|
|
SetEnvironmentVariableA("TZ", ""); |
|
128
|
|
|
|
|
|
|
#endif |
|
129
|
|
|
|
|
|
|
sprintf(newenv, "TZ=%s", perl_tz_env); |
|
130
|
|
|
|
|
|
|
putenv(newenv); |
|
131
|
|
|
|
|
|
|
if (oldenv != NULL) |
|
132
|
|
|
|
|
|
|
free(oldenv); |
|
133
|
|
|
|
|
|
|
oldenv = newenv; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
#endif |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
/* |
|
141
|
|
|
|
|
|
|
* my_tzset - wrapper to tzset() with a fix to make it work (better) on Win32. |
|
142
|
|
|
|
|
|
|
* This code is duplicated in the POSIX module, so any changes made here |
|
143
|
|
|
|
|
|
|
* should be made there too. |
|
144
|
|
|
|
|
|
|
*/ |
|
145
|
|
|
|
|
|
|
static void |
|
146
|
47
|
|
|
|
|
|
my_tzset(pTHX) |
|
147
|
|
|
|
|
|
|
{ |
|
148
|
|
|
|
|
|
|
#ifdef WIN32 |
|
149
|
|
|
|
|
|
|
#if defined(USE_ITHREADS) && defined(PERL_IMPLICIT_SYS) |
|
150
|
|
|
|
|
|
|
if (PL_curinterp == aTHX) |
|
151
|
|
|
|
|
|
|
#endif |
|
152
|
|
|
|
|
|
|
fix_win32_tzenv(); |
|
153
|
|
|
|
|
|
|
#endif |
|
154
|
47
|
|
|
|
|
|
tzset(); |
|
155
|
47
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
/* |
|
158
|
|
|
|
|
|
|
* my_mini_mktime - normalise struct tm values without the localtime() |
|
159
|
|
|
|
|
|
|
* semantics (and overhead) of mktime(). Stolen shamelessly from Perl's |
|
160
|
|
|
|
|
|
|
* Perl_mini_mktime() in util.c - for details on the algorithm, see that |
|
161
|
|
|
|
|
|
|
* file. |
|
162
|
|
|
|
|
|
|
*/ |
|
163
|
|
|
|
|
|
|
static void |
|
164
|
27
|
|
|
|
|
|
my_mini_mktime(struct tm *ptm) |
|
165
|
|
|
|
|
|
|
{ |
|
166
|
|
|
|
|
|
|
int yearday; |
|
167
|
|
|
|
|
|
|
int secs; |
|
168
|
|
|
|
|
|
|
int month, mday, year, jday; |
|
169
|
|
|
|
|
|
|
int odd_cent, odd_year; |
|
170
|
|
|
|
|
|
|
|
|
171
|
27
|
|
|
|
|
|
year = 1900 + ptm->tm_year; |
|
172
|
27
|
|
|
|
|
|
month = ptm->tm_mon; |
|
173
|
27
|
|
|
|
|
|
mday = ptm->tm_mday; |
|
174
|
|
|
|
|
|
|
/* allow given yday with no month & mday to dominate the result */ |
|
175
|
27
|
50
|
|
|
|
|
if (ptm->tm_yday >= 0 && mday <= 0 && month <= 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
176
|
1
|
|
|
|
|
|
month = 0; |
|
177
|
1
|
|
|
|
|
|
mday = 0; |
|
178
|
1
|
|
|
|
|
|
jday = 1 + ptm->tm_yday; |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
else { |
|
181
|
26
|
|
|
|
|
|
jday = 0; |
|
182
|
|
|
|
|
|
|
} |
|
183
|
27
|
100
|
|
|
|
|
if (month >= 2) |
|
184
|
14
|
|
|
|
|
|
month+=2; |
|
185
|
|
|
|
|
|
|
else |
|
186
|
13
|
|
|
|
|
|
month+=14, year--; |
|
187
|
|
|
|
|
|
|
|
|
188
|
27
|
|
|
|
|
|
yearday = DAYS_PER_YEAR * year + year/4 - year/100 + year/400; |
|
189
|
27
|
|
|
|
|
|
yearday += month*MONTH_TO_DAYS + mday + jday; |
|
190
|
|
|
|
|
|
|
/* |
|
191
|
|
|
|
|
|
|
* Note that we don't know when leap-seconds were or will be, |
|
192
|
|
|
|
|
|
|
* so we have to trust the user if we get something which looks |
|
193
|
|
|
|
|
|
|
* like a sensible leap-second. Wild values for seconds will |
|
194
|
|
|
|
|
|
|
* be rationalised, however. |
|
195
|
|
|
|
|
|
|
*/ |
|
196
|
27
|
50
|
|
|
|
|
if ((unsigned) ptm->tm_sec <= 60) { |
|
197
|
27
|
|
|
|
|
|
secs = 0; |
|
198
|
|
|
|
|
|
|
} |
|
199
|
|
|
|
|
|
|
else { |
|
200
|
0
|
|
|
|
|
|
secs = ptm->tm_sec; |
|
201
|
0
|
|
|
|
|
|
ptm->tm_sec = 0; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
27
|
|
|
|
|
|
secs += 60 * ptm->tm_min; |
|
204
|
27
|
|
|
|
|
|
secs += SECS_PER_HOUR * ptm->tm_hour; |
|
205
|
27
|
50
|
|
|
|
|
if (secs < 0) { |
|
206
|
0
|
0
|
|
|
|
|
if (secs-(secs/SECS_PER_DAY*SECS_PER_DAY) < 0) { |
|
207
|
|
|
|
|
|
|
/* got negative remainder, but need positive time */ |
|
208
|
|
|
|
|
|
|
/* back off an extra day to compensate */ |
|
209
|
0
|
|
|
|
|
|
yearday += (secs/SECS_PER_DAY)-1; |
|
210
|
0
|
|
|
|
|
|
secs -= SECS_PER_DAY * (secs/SECS_PER_DAY - 1); |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
else { |
|
213
|
0
|
|
|
|
|
|
yearday += (secs/SECS_PER_DAY); |
|
214
|
0
|
|
|
|
|
|
secs -= SECS_PER_DAY * (secs/SECS_PER_DAY); |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
} |
|
217
|
27
|
50
|
|
|
|
|
else if (secs >= SECS_PER_DAY) { |
|
218
|
0
|
|
|
|
|
|
yearday += (secs/SECS_PER_DAY); |
|
219
|
0
|
|
|
|
|
|
secs %= SECS_PER_DAY; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
27
|
|
|
|
|
|
ptm->tm_hour = secs/SECS_PER_HOUR; |
|
222
|
27
|
|
|
|
|
|
secs %= SECS_PER_HOUR; |
|
223
|
27
|
|
|
|
|
|
ptm->tm_min = secs/60; |
|
224
|
27
|
|
|
|
|
|
secs %= 60; |
|
225
|
27
|
|
|
|
|
|
ptm->tm_sec += secs; |
|
226
|
|
|
|
|
|
|
/* done with time of day effects */ |
|
227
|
|
|
|
|
|
|
/* |
|
228
|
|
|
|
|
|
|
* The algorithm for yearday has (so far) left it high by 428. |
|
229
|
|
|
|
|
|
|
* To avoid mistaking a legitimate Feb 29 as Mar 1, we need to |
|
230
|
|
|
|
|
|
|
* bias it by 123 while trying to figure out what year it |
|
231
|
|
|
|
|
|
|
* really represents. Even with this tweak, the reverse |
|
232
|
|
|
|
|
|
|
* translation fails for years before A.D. 0001. |
|
233
|
|
|
|
|
|
|
* It would still fail for Feb 29, but we catch that one below. |
|
234
|
|
|
|
|
|
|
*/ |
|
235
|
27
|
|
|
|
|
|
jday = yearday; /* save for later fixup vis-a-vis Jan 1 */ |
|
236
|
27
|
|
|
|
|
|
yearday -= YEAR_ADJUST; |
|
237
|
27
|
|
|
|
|
|
year = (yearday / DAYS_PER_QCENT) * 400; |
|
238
|
27
|
|
|
|
|
|
yearday %= DAYS_PER_QCENT; |
|
239
|
27
|
|
|
|
|
|
odd_cent = yearday / DAYS_PER_CENT; |
|
240
|
27
|
|
|
|
|
|
year += odd_cent * 100; |
|
241
|
27
|
|
|
|
|
|
yearday %= DAYS_PER_CENT; |
|
242
|
27
|
|
|
|
|
|
year += (yearday / DAYS_PER_QYEAR) * 4; |
|
243
|
27
|
|
|
|
|
|
yearday %= DAYS_PER_QYEAR; |
|
244
|
27
|
|
|
|
|
|
odd_year = yearday / DAYS_PER_YEAR; |
|
245
|
27
|
|
|
|
|
|
year += odd_year; |
|
246
|
27
|
|
|
|
|
|
yearday %= DAYS_PER_YEAR; |
|
247
|
27
|
100
|
|
|
|
|
if (!yearday && (odd_cent==4 || odd_year==4)) { /* catch Feb 29 */ |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
248
|
1
|
|
|
|
|
|
month = 1; |
|
249
|
1
|
|
|
|
|
|
yearday = 29; |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
else { |
|
252
|
26
|
|
|
|
|
|
yearday += YEAR_ADJUST; /* recover March 1st crock */ |
|
253
|
26
|
|
|
|
|
|
month = yearday*DAYS_TO_MONTH; |
|
254
|
26
|
|
|
|
|
|
yearday -= month*MONTH_TO_DAYS; |
|
255
|
|
|
|
|
|
|
/* recover other leap-year adjustment */ |
|
256
|
26
|
100
|
|
|
|
|
if (month > 13) { |
|
257
|
10
|
|
|
|
|
|
month-=14; |
|
258
|
10
|
|
|
|
|
|
year++; |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
else { |
|
261
|
16
|
|
|
|
|
|
month-=2; |
|
262
|
|
|
|
|
|
|
} |
|
263
|
|
|
|
|
|
|
} |
|
264
|
27
|
|
|
|
|
|
ptm->tm_year = year - 1900; |
|
265
|
27
|
50
|
|
|
|
|
if (yearday) { |
|
266
|
27
|
|
|
|
|
|
ptm->tm_mday = yearday; |
|
267
|
27
|
|
|
|
|
|
ptm->tm_mon = month; |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
else { |
|
270
|
0
|
|
|
|
|
|
ptm->tm_mday = 31; |
|
271
|
0
|
|
|
|
|
|
ptm->tm_mon = month - 1; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
/* re-build yearday based on Jan 1 to get tm_yday */ |
|
274
|
27
|
|
|
|
|
|
year--; |
|
275
|
27
|
|
|
|
|
|
yearday = year*DAYS_PER_YEAR + year/4 - year/100 + year/400; |
|
276
|
27
|
|
|
|
|
|
yearday += 14*MONTH_TO_DAYS + 1; |
|
277
|
27
|
|
|
|
|
|
ptm->tm_yday = jday - yearday; |
|
278
|
|
|
|
|
|
|
/* fix tm_wday if not overridden by caller */ |
|
279
|
27
|
|
|
|
|
|
ptm->tm_wday = (jday + WEEKDAY_BIAS) % 7; |
|
280
|
27
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# if defined(WIN32) || (defined(__QNX__) && defined(__WATCOMC__)) |
|
283
|
|
|
|
|
|
|
# define strncasecmp(x,y,n) strnicmp(x,y,n) |
|
284
|
|
|
|
|
|
|
# endif |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
/* strptime.c 0.1 (Powerdog) 94/03/27 */ |
|
287
|
|
|
|
|
|
|
/* strptime copied from freebsd with the following copyright: */ |
|
288
|
|
|
|
|
|
|
/* |
|
289
|
|
|
|
|
|
|
* Copyright (c) 1994 Powerdog Industries. All rights reserved. |
|
290
|
|
|
|
|
|
|
* |
|
291
|
|
|
|
|
|
|
* Redistribution and use in source and binary forms, with or without |
|
292
|
|
|
|
|
|
|
* modification, are permitted provided that the following conditions |
|
293
|
|
|
|
|
|
|
* are met: |
|
294
|
|
|
|
|
|
|
* |
|
295
|
|
|
|
|
|
|
* 1. Redistributions of source code must retain the above copyright |
|
296
|
|
|
|
|
|
|
* notice, this list of conditions and the following disclaimer. |
|
297
|
|
|
|
|
|
|
* |
|
298
|
|
|
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
299
|
|
|
|
|
|
|
* notice, this list of conditions and the following disclaimer |
|
300
|
|
|
|
|
|
|
* in the documentation and/or other materials provided with the |
|
301
|
|
|
|
|
|
|
* distribution. |
|
302
|
|
|
|
|
|
|
* |
|
303
|
|
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY |
|
304
|
|
|
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
305
|
|
|
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
306
|
|
|
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE |
|
307
|
|
|
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
308
|
|
|
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
309
|
|
|
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
310
|
|
|
|
|
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
311
|
|
|
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
312
|
|
|
|
|
|
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
|
313
|
|
|
|
|
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
314
|
|
|
|
|
|
|
* |
|
315
|
|
|
|
|
|
|
* The views and conclusions contained in the software and documentation |
|
316
|
|
|
|
|
|
|
* are those of the authors and should not be interpreted as representing |
|
317
|
|
|
|
|
|
|
* official policies, either expressed or implied, of Powerdog Industries. |
|
318
|
|
|
|
|
|
|
*/ |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
#include |
|
321
|
|
|
|
|
|
|
#include |
|
322
|
|
|
|
|
|
|
#include |
|
323
|
|
|
|
|
|
|
static char * _strptime(pTHX_ const char *, const char *, struct tm *, |
|
324
|
|
|
|
|
|
|
int *got_GMT); |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
struct lc_time_T { |
|
329
|
|
|
|
|
|
|
char * mon[12]; |
|
330
|
|
|
|
|
|
|
char * month[12]; |
|
331
|
|
|
|
|
|
|
char * wday[7]; |
|
332
|
|
|
|
|
|
|
char * weekday[7]; |
|
333
|
|
|
|
|
|
|
char * am; |
|
334
|
|
|
|
|
|
|
char * pm; |
|
335
|
|
|
|
|
|
|
char * AM; |
|
336
|
|
|
|
|
|
|
char * PM; |
|
337
|
|
|
|
|
|
|
char * alt_month[12]; |
|
338
|
|
|
|
|
|
|
}; |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
static struct lc_time_T _C_time_locale; |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
#define Locale (&_C_time_locale) |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
static char * |
|
346
|
20
|
|
|
|
|
|
_strptime(pTHX_ const char *buf, const char *fmt, struct tm *tm, int *got_GMT) |
|
347
|
|
|
|
|
|
|
{ |
|
348
|
|
|
|
|
|
|
char c; |
|
349
|
|
|
|
|
|
|
const char *ptr; |
|
350
|
|
|
|
|
|
|
int i; |
|
351
|
|
|
|
|
|
|
size_t len; |
|
352
|
|
|
|
|
|
|
int Ealternative, Oalternative; |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
/* There seems to be a slightly improved version at |
|
355
|
|
|
|
|
|
|
* http://www.opensource.apple.com/source/Libc/Libc-583/stdtime/strptime-fbsd.c |
|
356
|
|
|
|
|
|
|
* which we may end up borrowing more from |
|
357
|
|
|
|
|
|
|
*/ |
|
358
|
20
|
|
|
|
|
|
ptr = fmt; |
|
359
|
135
|
100
|
|
|
|
|
while (*ptr != 0) { |
|
360
|
115
|
50
|
|
|
|
|
if (*buf == 0) |
|
361
|
0
|
|
|
|
|
|
break; |
|
362
|
|
|
|
|
|
|
|
|
363
|
115
|
|
|
|
|
|
c = *ptr++; |
|
364
|
|
|
|
|
|
|
|
|
365
|
115
|
100
|
|
|
|
|
if (c != '%') { |
|
366
|
47
|
100
|
|
|
|
|
if (isspace((unsigned char)c)) |
|
367
|
24
|
50
|
|
|
|
|
while (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
100
|
|
|
|
|
|
|
368
|
12
|
|
|
|
|
|
buf++; |
|
369
|
35
|
50
|
|
|
|
|
else if (c != *buf++) |
|
370
|
0
|
|
|
|
|
|
return 0; |
|
371
|
47
|
|
|
|
|
|
continue; |
|
372
|
|
|
|
|
|
|
} |
|
373
|
|
|
|
|
|
|
|
|
374
|
68
|
|
|
|
|
|
Ealternative = 0; |
|
375
|
68
|
|
|
|
|
|
Oalternative = 0; |
|
376
|
|
|
|
|
|
|
label: |
|
377
|
68
|
|
|
|
|
|
c = *ptr++; |
|
378
|
68
|
|
|
|
|
|
switch (c) { |
|
379
|
|
|
|
|
|
|
case 0: |
|
380
|
|
|
|
|
|
|
case '%': |
|
381
|
0
|
0
|
|
|
|
|
if (*buf++ != '%') |
|
382
|
0
|
|
|
|
|
|
return 0; |
|
383
|
0
|
|
|
|
|
|
break; |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
case '+': |
|
386
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%c", tm, got_GMT); |
|
387
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
388
|
0
|
|
|
|
|
|
return 0; |
|
389
|
0
|
|
|
|
|
|
break; |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
case 'C': |
|
392
|
0
|
0
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
393
|
0
|
|
|
|
|
|
return 0; |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
/* XXX This will break for 3-digit centuries. */ |
|
396
|
0
|
|
|
|
|
|
len = 2; |
|
397
|
0
|
0
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
398
|
0
|
|
|
|
|
|
i *= 10; |
|
399
|
0
|
|
|
|
|
|
i += *buf - '0'; |
|
400
|
0
|
|
|
|
|
|
len--; |
|
401
|
|
|
|
|
|
|
} |
|
402
|
0
|
0
|
|
|
|
|
if (i < 19) |
|
403
|
0
|
|
|
|
|
|
return 0; |
|
404
|
|
|
|
|
|
|
|
|
405
|
0
|
|
|
|
|
|
tm->tm_year = i * 100 - 1900; |
|
406
|
0
|
|
|
|
|
|
break; |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
case 'c': |
|
409
|
|
|
|
|
|
|
/* NOTE: c_fmt is intentionally ignored */ |
|
410
|
|
|
|
|
|
|
|
|
411
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%a %d %b %Y %I:%M:%S %p %Z", tm, got_GMT); |
|
412
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
413
|
0
|
|
|
|
|
|
return 0; |
|
414
|
0
|
|
|
|
|
|
break; |
|
415
|
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
case 'D': |
|
417
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%m/%d/%y", tm, got_GMT); |
|
418
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
419
|
0
|
|
|
|
|
|
return 0; |
|
420
|
0
|
|
|
|
|
|
break; |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
case 'E': |
|
423
|
0
|
0
|
|
|
|
|
if (Ealternative || Oalternative) |
|
|
|
0
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
break; |
|
425
|
0
|
|
|
|
|
|
Ealternative++; |
|
426
|
0
|
|
|
|
|
|
goto label; |
|
427
|
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
case 'O': |
|
429
|
0
|
0
|
|
|
|
|
if (Ealternative || Oalternative) |
|
|
|
0
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
break; |
|
431
|
0
|
|
|
|
|
|
Oalternative++; |
|
432
|
0
|
|
|
|
|
|
goto label; |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
case 'F': |
|
435
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%Y-%m-%d", tm, got_GMT); |
|
436
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
437
|
0
|
|
|
|
|
|
return 0; |
|
438
|
0
|
|
|
|
|
|
break; |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
case 'R': |
|
441
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%H:%M", tm, got_GMT); |
|
442
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
443
|
0
|
|
|
|
|
|
return 0; |
|
444
|
0
|
|
|
|
|
|
break; |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
case 'r': |
|
447
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%I:%M:%S %p", tm, got_GMT); |
|
448
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
449
|
0
|
|
|
|
|
|
return 0; |
|
450
|
0
|
|
|
|
|
|
break; |
|
451
|
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
case 'n': /* whitespace */ |
|
453
|
|
|
|
|
|
|
case 't': |
|
454
|
0
|
0
|
|
|
|
|
if (!isspace((unsigned char)*buf)) |
|
455
|
0
|
|
|
|
|
|
return 0; |
|
456
|
0
|
0
|
|
|
|
|
while (isspace((unsigned char)*buf)) |
|
457
|
0
|
|
|
|
|
|
buf++; |
|
458
|
0
|
|
|
|
|
|
break; |
|
459
|
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
case 'T': |
|
461
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%H:%M:%S", tm, got_GMT); |
|
462
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
463
|
0
|
|
|
|
|
|
return 0; |
|
464
|
0
|
|
|
|
|
|
break; |
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
case 'X': |
|
467
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%I:%M:%S %p", tm, got_GMT); |
|
468
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
469
|
0
|
|
|
|
|
|
return 0; |
|
470
|
0
|
|
|
|
|
|
break; |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
case 'x': |
|
473
|
0
|
|
|
|
|
|
buf = _strptime(aTHX_ buf, "%a %d %b %Y", tm, got_GMT); |
|
474
|
0
|
0
|
|
|
|
|
if (buf == 0) |
|
475
|
0
|
|
|
|
|
|
return 0; |
|
476
|
0
|
|
|
|
|
|
break; |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
case 'j': |
|
479
|
1
|
50
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
480
|
0
|
|
|
|
|
|
return 0; |
|
481
|
|
|
|
|
|
|
|
|
482
|
1
|
|
|
|
|
|
len = 3; |
|
483
|
4
|
100
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
484
|
3
|
|
|
|
|
|
i *= 10; |
|
485
|
3
|
|
|
|
|
|
i += *buf - '0'; |
|
486
|
3
|
|
|
|
|
|
len--; |
|
487
|
|
|
|
|
|
|
} |
|
488
|
1
|
50
|
|
|
|
|
if (i < 1 || i > 366) |
|
|
|
50
|
|
|
|
|
|
|
489
|
0
|
|
|
|
|
|
return 0; |
|
490
|
|
|
|
|
|
|
|
|
491
|
1
|
|
|
|
|
|
tm->tm_yday = i - 1; |
|
492
|
1
|
|
|
|
|
|
tm->tm_mday = 0; |
|
493
|
1
|
|
|
|
|
|
break; |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
case 'M': |
|
496
|
|
|
|
|
|
|
case 'S': |
|
497
|
5
|
50
|
|
|
|
|
if (*buf == 0 || isspace((unsigned char)*buf)) |
|
|
|
50
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
break; |
|
499
|
|
|
|
|
|
|
|
|
500
|
5
|
50
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
501
|
0
|
|
|
|
|
|
return 0; |
|
502
|
|
|
|
|
|
|
|
|
503
|
5
|
|
|
|
|
|
len = 2; |
|
504
|
15
|
100
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
505
|
10
|
|
|
|
|
|
i *= 10; |
|
506
|
10
|
|
|
|
|
|
i += *buf - '0'; |
|
507
|
10
|
|
|
|
|
|
len--; |
|
508
|
|
|
|
|
|
|
} |
|
509
|
|
|
|
|
|
|
|
|
510
|
5
|
100
|
|
|
|
|
if (c == 'M') { |
|
511
|
4
|
50
|
|
|
|
|
if (i > 59) |
|
512
|
0
|
|
|
|
|
|
return 0; |
|
513
|
4
|
|
|
|
|
|
tm->tm_min = i; |
|
514
|
|
|
|
|
|
|
} else { |
|
515
|
1
|
50
|
|
|
|
|
if (i > 60) |
|
516
|
0
|
|
|
|
|
|
return 0; |
|
517
|
1
|
|
|
|
|
|
tm->tm_sec = i; |
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
|
|
520
|
5
|
100
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
50
|
|
|
|
|
|
|
521
|
0
|
0
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
0
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
|
ptr++; |
|
523
|
5
|
|
|
|
|
|
break; |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
case 'H': |
|
526
|
|
|
|
|
|
|
case 'I': |
|
527
|
|
|
|
|
|
|
case 'k': |
|
528
|
|
|
|
|
|
|
case 'l': |
|
529
|
|
|
|
|
|
|
/* |
|
530
|
|
|
|
|
|
|
* Of these, %l is the only specifier explicitly |
|
531
|
|
|
|
|
|
|
* documented as not being zero-padded. However, |
|
532
|
|
|
|
|
|
|
* there is no harm in allowing zero-padding. |
|
533
|
|
|
|
|
|
|
* |
|
534
|
|
|
|
|
|
|
* XXX The %l specifier may gobble one too many |
|
535
|
|
|
|
|
|
|
* digits if used incorrectly. |
|
536
|
|
|
|
|
|
|
*/ |
|
537
|
11
|
50
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
538
|
0
|
|
|
|
|
|
return 0; |
|
539
|
|
|
|
|
|
|
|
|
540
|
11
|
|
|
|
|
|
len = 2; |
|
541
|
30
|
100
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
542
|
19
|
|
|
|
|
|
i *= 10; |
|
543
|
19
|
|
|
|
|
|
i += *buf - '0'; |
|
544
|
19
|
|
|
|
|
|
len--; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
11
|
50
|
|
|
|
|
if (c == 'H' || c == 'k') { |
|
|
|
0
|
|
|
|
|
|
|
547
|
11
|
50
|
|
|
|
|
if (i > 23) |
|
548
|
0
|
|
|
|
|
|
return 0; |
|
549
|
0
|
0
|
|
|
|
|
} else if (i > 12) |
|
550
|
0
|
|
|
|
|
|
return 0; |
|
551
|
|
|
|
|
|
|
|
|
552
|
11
|
|
|
|
|
|
tm->tm_hour = i; |
|
553
|
|
|
|
|
|
|
|
|
554
|
11
|
100
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
50
|
|
|
|
|
|
|
555
|
0
|
0
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
0
|
|
|
|
|
|
|
556
|
0
|
|
|
|
|
|
ptr++; |
|
557
|
11
|
|
|
|
|
|
break; |
|
558
|
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
case 'p': |
|
560
|
|
|
|
|
|
|
case 'P': |
|
561
|
|
|
|
|
|
|
/* |
|
562
|
|
|
|
|
|
|
* XXX This is bogus if parsed before hour-related |
|
563
|
|
|
|
|
|
|
* specifiers. |
|
564
|
|
|
|
|
|
|
*/ |
|
565
|
0
|
|
|
|
|
|
len = strlen(Locale->am); |
|
566
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, Locale->am, len) == 0 || |
|
|
|
0
|
|
|
|
|
|
|
567
|
0
|
|
|
|
|
|
strncasecmp(buf, Locale->AM, len) == 0) { |
|
568
|
0
|
0
|
|
|
|
|
if (tm->tm_hour > 12) |
|
569
|
0
|
|
|
|
|
|
return 0; |
|
570
|
0
|
0
|
|
|
|
|
if (tm->tm_hour == 12) |
|
571
|
0
|
|
|
|
|
|
tm->tm_hour = 0; |
|
572
|
0
|
|
|
|
|
|
buf += len; |
|
573
|
0
|
|
|
|
|
|
break; |
|
574
|
|
|
|
|
|
|
} |
|
575
|
|
|
|
|
|
|
|
|
576
|
0
|
|
|
|
|
|
len = strlen(Locale->pm); |
|
577
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, Locale->pm, len) == 0 || |
|
|
|
0
|
|
|
|
|
|
|
578
|
0
|
|
|
|
|
|
strncasecmp(buf, Locale->PM, len) == 0) { |
|
579
|
0
|
0
|
|
|
|
|
if (tm->tm_hour > 12) |
|
580
|
0
|
|
|
|
|
|
return 0; |
|
581
|
0
|
0
|
|
|
|
|
if (tm->tm_hour != 12) |
|
582
|
0
|
|
|
|
|
|
tm->tm_hour += 12; |
|
583
|
0
|
|
|
|
|
|
buf += len; |
|
584
|
0
|
|
|
|
|
|
break; |
|
585
|
|
|
|
|
|
|
} |
|
586
|
|
|
|
|
|
|
|
|
587
|
0
|
|
|
|
|
|
return 0; |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
case 'A': |
|
590
|
|
|
|
|
|
|
case 'a': |
|
591
|
0
|
0
|
|
|
|
|
for (i = 0; i < (int)asizeof(Locale->weekday); i++) { |
|
592
|
0
|
0
|
|
|
|
|
if (c == 'A') { |
|
593
|
0
|
|
|
|
|
|
len = strlen(Locale->weekday[i]); |
|
594
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, |
|
595
|
0
|
|
|
|
|
|
Locale->weekday[i], |
|
596
|
|
|
|
|
|
|
len) == 0) |
|
597
|
0
|
|
|
|
|
|
break; |
|
598
|
|
|
|
|
|
|
} else { |
|
599
|
0
|
|
|
|
|
|
len = strlen(Locale->wday[i]); |
|
600
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, |
|
601
|
0
|
|
|
|
|
|
Locale->wday[i], |
|
602
|
|
|
|
|
|
|
len) == 0) |
|
603
|
0
|
|
|
|
|
|
break; |
|
604
|
|
|
|
|
|
|
} |
|
605
|
|
|
|
|
|
|
} |
|
606
|
0
|
0
|
|
|
|
|
if (i == (int)asizeof(Locale->weekday)) |
|
607
|
0
|
|
|
|
|
|
return 0; |
|
608
|
|
|
|
|
|
|
|
|
609
|
0
|
|
|
|
|
|
tm->tm_wday = i; |
|
610
|
0
|
|
|
|
|
|
buf += len; |
|
611
|
0
|
|
|
|
|
|
break; |
|
612
|
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
case 'U': |
|
614
|
|
|
|
|
|
|
case 'V': |
|
615
|
|
|
|
|
|
|
case 'W': |
|
616
|
|
|
|
|
|
|
/* |
|
617
|
|
|
|
|
|
|
* XXX This is bogus, as we can not assume any valid |
|
618
|
|
|
|
|
|
|
* information present in the tm structure at this |
|
619
|
|
|
|
|
|
|
* point to calculate a real value, so just check the |
|
620
|
|
|
|
|
|
|
* range for now. |
|
621
|
|
|
|
|
|
|
*/ |
|
622
|
0
|
0
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
623
|
0
|
|
|
|
|
|
return 0; |
|
624
|
|
|
|
|
|
|
|
|
625
|
0
|
|
|
|
|
|
len = 2; |
|
626
|
0
|
0
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
627
|
0
|
|
|
|
|
|
i *= 10; |
|
628
|
0
|
|
|
|
|
|
i += *buf - '0'; |
|
629
|
0
|
|
|
|
|
|
len--; |
|
630
|
|
|
|
|
|
|
} |
|
631
|
0
|
0
|
|
|
|
|
if (i > 53) |
|
632
|
0
|
|
|
|
|
|
return 0; |
|
633
|
|
|
|
|
|
|
|
|
634
|
0
|
0
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
0
|
|
|
|
|
|
|
635
|
0
|
0
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
0
|
|
|
|
|
|
|
636
|
0
|
|
|
|
|
|
ptr++; |
|
637
|
0
|
|
|
|
|
|
break; |
|
638
|
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
case 'u': |
|
640
|
|
|
|
|
|
|
case 'w': |
|
641
|
0
|
0
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
642
|
0
|
|
|
|
|
|
return 0; |
|
643
|
|
|
|
|
|
|
|
|
644
|
0
|
|
|
|
|
|
i = *buf - '0'; |
|
645
|
0
|
0
|
|
|
|
|
if (i > 6 + (c == 'u')) |
|
|
|
0
|
|
|
|
|
|
|
646
|
0
|
|
|
|
|
|
return 0; |
|
647
|
0
|
0
|
|
|
|
|
if (i == 7) |
|
648
|
0
|
|
|
|
|
|
i = 0; |
|
649
|
|
|
|
|
|
|
|
|
650
|
0
|
|
|
|
|
|
tm->tm_wday = i; |
|
651
|
|
|
|
|
|
|
|
|
652
|
0
|
|
|
|
|
|
buf++; |
|
653
|
0
|
0
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
0
|
|
|
|
|
|
|
654
|
0
|
0
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
0
|
|
|
|
|
|
|
655
|
0
|
|
|
|
|
|
ptr++; |
|
656
|
0
|
|
|
|
|
|
break; |
|
657
|
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
case 'd': |
|
659
|
|
|
|
|
|
|
case 'e': |
|
660
|
|
|
|
|
|
|
/* |
|
661
|
|
|
|
|
|
|
* The %e specifier is explicitly documented as not |
|
662
|
|
|
|
|
|
|
* being zero-padded but there is no harm in allowing |
|
663
|
|
|
|
|
|
|
* such padding. |
|
664
|
|
|
|
|
|
|
* |
|
665
|
|
|
|
|
|
|
* XXX The %e specifier may gobble one too many |
|
666
|
|
|
|
|
|
|
* digits if used incorrectly. |
|
667
|
|
|
|
|
|
|
*/ |
|
668
|
16
|
50
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
669
|
0
|
|
|
|
|
|
return 0; |
|
670
|
|
|
|
|
|
|
|
|
671
|
16
|
|
|
|
|
|
len = 2; |
|
672
|
48
|
100
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
673
|
32
|
|
|
|
|
|
i *= 10; |
|
674
|
32
|
|
|
|
|
|
i += *buf - '0'; |
|
675
|
32
|
|
|
|
|
|
len--; |
|
676
|
|
|
|
|
|
|
} |
|
677
|
16
|
50
|
|
|
|
|
if (i > 31) |
|
678
|
0
|
|
|
|
|
|
return 0; |
|
679
|
|
|
|
|
|
|
|
|
680
|
16
|
|
|
|
|
|
tm->tm_mday = i; |
|
681
|
|
|
|
|
|
|
|
|
682
|
16
|
100
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
50
|
|
|
|
|
|
|
683
|
11
|
50
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
50
|
|
|
|
|
|
|
684
|
0
|
|
|
|
|
|
ptr++; |
|
685
|
16
|
|
|
|
|
|
break; |
|
686
|
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
case 'B': |
|
688
|
|
|
|
|
|
|
case 'b': |
|
689
|
|
|
|
|
|
|
case 'h': |
|
690
|
0
|
0
|
|
|
|
|
for (i = 0; i < (int)asizeof(Locale->month); i++) { |
|
691
|
0
|
0
|
|
|
|
|
if (Oalternative) { |
|
692
|
0
|
0
|
|
|
|
|
if (c == 'B') { |
|
693
|
0
|
|
|
|
|
|
len = strlen(Locale->alt_month[i]); |
|
694
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, |
|
695
|
0
|
|
|
|
|
|
Locale->alt_month[i], |
|
696
|
|
|
|
|
|
|
len) == 0) |
|
697
|
0
|
|
|
|
|
|
break; |
|
698
|
|
|
|
|
|
|
} |
|
699
|
|
|
|
|
|
|
} else { |
|
700
|
0
|
0
|
|
|
|
|
if (c == 'B') { |
|
701
|
0
|
|
|
|
|
|
len = strlen(Locale->month[i]); |
|
702
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, |
|
703
|
0
|
|
|
|
|
|
Locale->month[i], |
|
704
|
|
|
|
|
|
|
len) == 0) |
|
705
|
0
|
|
|
|
|
|
break; |
|
706
|
|
|
|
|
|
|
} else { |
|
707
|
0
|
|
|
|
|
|
len = strlen(Locale->mon[i]); |
|
708
|
0
|
0
|
|
|
|
|
if (strncasecmp(buf, |
|
709
|
0
|
|
|
|
|
|
Locale->mon[i], |
|
710
|
|
|
|
|
|
|
len) == 0) |
|
711
|
0
|
|
|
|
|
|
break; |
|
712
|
|
|
|
|
|
|
} |
|
713
|
|
|
|
|
|
|
} |
|
714
|
|
|
|
|
|
|
} |
|
715
|
0
|
0
|
|
|
|
|
if (i == (int)asizeof(Locale->month)) |
|
716
|
0
|
|
|
|
|
|
return 0; |
|
717
|
|
|
|
|
|
|
|
|
718
|
0
|
|
|
|
|
|
tm->tm_mon = i; |
|
719
|
0
|
|
|
|
|
|
buf += len; |
|
720
|
0
|
|
|
|
|
|
break; |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
case 'm': |
|
723
|
16
|
50
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
724
|
0
|
|
|
|
|
|
return 0; |
|
725
|
|
|
|
|
|
|
|
|
726
|
16
|
|
|
|
|
|
len = 2; |
|
727
|
48
|
100
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
728
|
32
|
|
|
|
|
|
i *= 10; |
|
729
|
32
|
|
|
|
|
|
i += *buf - '0'; |
|
730
|
32
|
|
|
|
|
|
len--; |
|
731
|
|
|
|
|
|
|
} |
|
732
|
16
|
50
|
|
|
|
|
if (i < 1 || i > 12) |
|
|
|
50
|
|
|
|
|
|
|
733
|
0
|
|
|
|
|
|
return 0; |
|
734
|
|
|
|
|
|
|
|
|
735
|
16
|
|
|
|
|
|
tm->tm_mon = i - 1; |
|
736
|
|
|
|
|
|
|
|
|
737
|
16
|
50
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
100
|
|
|
|
|
|
|
738
|
1
|
50
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
50
|
|
|
|
|
|
|
739
|
0
|
|
|
|
|
|
ptr++; |
|
740
|
16
|
|
|
|
|
|
break; |
|
741
|
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
case 's': |
|
743
|
|
|
|
|
|
|
{ |
|
744
|
|
|
|
|
|
|
char *cp; |
|
745
|
|
|
|
|
|
|
int sverrno; |
|
746
|
|
|
|
|
|
|
long n; |
|
747
|
|
|
|
|
|
|
time_t t; |
|
748
|
|
|
|
|
|
|
struct tm mytm; |
|
749
|
|
|
|
|
|
|
|
|
750
|
0
|
|
|
|
|
|
sverrno = errno; |
|
751
|
0
|
|
|
|
|
|
errno = 0; |
|
752
|
0
|
|
|
|
|
|
n = strtol(buf, &cp, 10); |
|
753
|
0
|
0
|
|
|
|
|
if (errno == ERANGE || (long)(t = n) != n) { |
|
|
|
0
|
|
|
|
|
|
|
754
|
0
|
|
|
|
|
|
errno = sverrno; |
|
755
|
0
|
|
|
|
|
|
return 0; |
|
756
|
|
|
|
|
|
|
} |
|
757
|
0
|
|
|
|
|
|
errno = sverrno; |
|
758
|
0
|
|
|
|
|
|
buf = cp; |
|
759
|
0
|
|
|
|
|
|
memset(&mytm, 0, sizeof(mytm)); |
|
760
|
|
|
|
|
|
|
|
|
761
|
0
|
0
|
|
|
|
|
if(*got_GMT == 1) |
|
762
|
0
|
|
|
|
|
|
mytm = *localtime(&t); |
|
763
|
|
|
|
|
|
|
else |
|
764
|
0
|
|
|
|
|
|
mytm = *gmtime(&t); |
|
765
|
|
|
|
|
|
|
|
|
766
|
0
|
|
|
|
|
|
tm->tm_sec = mytm.tm_sec; |
|
767
|
0
|
|
|
|
|
|
tm->tm_min = mytm.tm_min; |
|
768
|
0
|
|
|
|
|
|
tm->tm_hour = mytm.tm_hour; |
|
769
|
0
|
|
|
|
|
|
tm->tm_mday = mytm.tm_mday; |
|
770
|
0
|
|
|
|
|
|
tm->tm_mon = mytm.tm_mon; |
|
771
|
0
|
|
|
|
|
|
tm->tm_year = mytm.tm_year; |
|
772
|
0
|
|
|
|
|
|
tm->tm_wday = mytm.tm_wday; |
|
773
|
0
|
|
|
|
|
|
tm->tm_yday = mytm.tm_yday; |
|
774
|
0
|
|
|
|
|
|
tm->tm_isdst = mytm.tm_isdst; |
|
775
|
|
|
|
|
|
|
} |
|
776
|
0
|
|
|
|
|
|
break; |
|
777
|
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
case 'Y': |
|
779
|
|
|
|
|
|
|
case 'y': |
|
780
|
19
|
50
|
|
|
|
|
if (*buf == 0 || isspace((unsigned char)*buf)) |
|
|
|
50
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
break; |
|
782
|
|
|
|
|
|
|
|
|
783
|
19
|
50
|
|
|
|
|
if (!isdigit((unsigned char)*buf)) |
|
784
|
0
|
|
|
|
|
|
return 0; |
|
785
|
|
|
|
|
|
|
|
|
786
|
19
|
100
|
|
|
|
|
len = (c == 'Y') ? 4 : 2; |
|
787
|
93
|
100
|
|
|
|
|
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
788
|
74
|
|
|
|
|
|
i *= 10; |
|
789
|
74
|
|
|
|
|
|
i += *buf - '0'; |
|
790
|
74
|
|
|
|
|
|
len--; |
|
791
|
|
|
|
|
|
|
} |
|
792
|
19
|
100
|
|
|
|
|
if (c == 'Y') |
|
793
|
18
|
|
|
|
|
|
i -= 1900; |
|
794
|
19
|
100
|
|
|
|
|
if (c == 'y' && i < 69) |
|
|
|
50
|
|
|
|
|
|
|
795
|
1
|
|
|
|
|
|
i += 100; |
|
796
|
19
|
50
|
|
|
|
|
if (i < 0) |
|
797
|
0
|
|
|
|
|
|
return 0; |
|
798
|
|
|
|
|
|
|
|
|
799
|
19
|
|
|
|
|
|
tm->tm_year = i; |
|
800
|
|
|
|
|
|
|
|
|
801
|
19
|
100
|
|
|
|
|
if (*buf != 0 && isspace((unsigned char)*buf)) |
|
|
|
50
|
|
|
|
|
|
|
802
|
0
|
0
|
|
|
|
|
while (*ptr != 0 && !isspace((unsigned char)*ptr)) |
|
|
|
0
|
|
|
|
|
|
|
803
|
0
|
|
|
|
|
|
ptr++; |
|
804
|
19
|
|
|
|
|
|
break; |
|
805
|
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
case 'Z': |
|
807
|
|
|
|
|
|
|
{ |
|
808
|
|
|
|
|
|
|
const char *cp; |
|
809
|
|
|
|
|
|
|
char *zonestr; |
|
810
|
|
|
|
|
|
|
|
|
811
|
0
|
0
|
|
|
|
|
for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) |
|
|
|
0
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
{/*empty*/} |
|
813
|
0
|
0
|
|
|
|
|
if (cp - buf) { |
|
814
|
0
|
|
|
|
|
|
zonestr = (char *)malloc((size_t) (cp - buf + 1)); |
|
815
|
0
|
0
|
|
|
|
|
if (!zonestr) { |
|
816
|
0
|
|
|
|
|
|
errno = ENOMEM; |
|
817
|
0
|
|
|
|
|
|
return 0; |
|
818
|
|
|
|
|
|
|
} |
|
819
|
0
|
|
|
|
|
|
strncpy(zonestr, buf,(size_t) (cp - buf)); |
|
820
|
0
|
|
|
|
|
|
zonestr[cp - buf] = '\0'; |
|
821
|
0
|
|
|
|
|
|
my_tzset(aTHX); |
|
822
|
0
|
0
|
|
|
|
|
if (0 == strcmp(zonestr, "GMT")) { |
|
823
|
0
|
|
|
|
|
|
*got_GMT = 1; |
|
824
|
|
|
|
|
|
|
} |
|
825
|
0
|
|
|
|
|
|
free(zonestr); |
|
826
|
0
|
0
|
|
|
|
|
if (!*got_GMT) return 0; |
|
827
|
0
|
|
|
|
|
|
buf += cp - buf; |
|
828
|
|
|
|
|
|
|
} |
|
829
|
|
|
|
|
|
|
} |
|
830
|
0
|
|
|
|
|
|
break; |
|
831
|
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
case 'z': |
|
833
|
|
|
|
|
|
|
{ |
|
834
|
0
|
|
|
|
|
|
int sign = 1; |
|
835
|
|
|
|
|
|
|
|
|
836
|
0
|
0
|
|
|
|
|
if (*buf != '+') { |
|
837
|
0
|
0
|
|
|
|
|
if (*buf == '-') |
|
838
|
0
|
|
|
|
|
|
sign = -1; |
|
839
|
|
|
|
|
|
|
else |
|
840
|
0
|
|
|
|
|
|
return 0; |
|
841
|
|
|
|
|
|
|
} |
|
842
|
|
|
|
|
|
|
|
|
843
|
0
|
|
|
|
|
|
buf++; |
|
844
|
0
|
|
|
|
|
|
i = 0; |
|
845
|
0
|
0
|
|
|
|
|
for (len = 4; len > 0; len--) { |
|
846
|
0
|
0
|
|
|
|
|
if (isdigit((int)*buf)) { |
|
847
|
0
|
|
|
|
|
|
i *= 10; |
|
848
|
0
|
|
|
|
|
|
i += *buf - '0'; |
|
849
|
0
|
|
|
|
|
|
buf++; |
|
850
|
|
|
|
|
|
|
} else |
|
851
|
0
|
|
|
|
|
|
return 0; |
|
852
|
|
|
|
|
|
|
} |
|
853
|
|
|
|
|
|
|
|
|
854
|
0
|
|
|
|
|
|
tm->tm_hour -= sign * (i / 100); |
|
855
|
0
|
|
|
|
|
|
tm->tm_min -= sign * (i % 100); |
|
856
|
0
|
|
|
|
|
|
*got_GMT = 1; |
|
857
|
|
|
|
|
|
|
} |
|
858
|
0
|
|
|
|
|
|
break; |
|
859
|
|
|
|
|
|
|
} |
|
860
|
|
|
|
|
|
|
} |
|
861
|
20
|
|
|
|
|
|
return (char *)buf; |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
/* Saves alot of machine code. |
|
865
|
|
|
|
|
|
|
Takes a (auto) SP, which may or may not have been PUSHed before, puts |
|
866
|
|
|
|
|
|
|
tm struct members on Perl stack, then returns new, advanced, SP to caller. |
|
867
|
|
|
|
|
|
|
Assign the return of push_common_tm to your SP, so you can continue to PUSH |
|
868
|
|
|
|
|
|
|
or do a PUTBACK and return eventually. |
|
869
|
|
|
|
|
|
|
!!!! push_common_tm does not touch PL_stack_sp !!!! |
|
870
|
|
|
|
|
|
|
!!!! do not use PUTBACK then SPAGAIN semantics around push_common_tm !!!! |
|
871
|
|
|
|
|
|
|
!!!! You must mortalize whatever push_common_tm put on stack yourself to |
|
872
|
|
|
|
|
|
|
avoid leaking !!!! |
|
873
|
|
|
|
|
|
|
*/ |
|
874
|
|
|
|
|
|
|
static SV ** |
|
875
|
33
|
|
|
|
|
|
push_common_tm(pTHX_ SV ** SP, struct tm *mytm) |
|
876
|
|
|
|
|
|
|
{ |
|
877
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_sec)); |
|
878
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_min)); |
|
879
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_hour)); |
|
880
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_mday)); |
|
881
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_mon)); |
|
882
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_year)); |
|
883
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_wday)); |
|
884
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_yday)); |
|
885
|
33
|
|
|
|
|
|
PUSHs(newSViv(mytm->tm_isdst)); |
|
886
|
33
|
|
|
|
|
|
return SP; |
|
887
|
|
|
|
|
|
|
} |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
/* specialized common end of 2 XSUBs |
|
890
|
|
|
|
|
|
|
SV ** SP -- pass your (auto) SP, which has not been PUSHed before, but was |
|
891
|
|
|
|
|
|
|
reset to 0 (PPCODE only or SP -= items or XSprePUSH) |
|
892
|
|
|
|
|
|
|
tm *mytm -- a tm *, will be proprocessed with my_mini_mktime |
|
893
|
|
|
|
|
|
|
return -- none, after calling return_11part_tm, you must call "return;" |
|
894
|
|
|
|
|
|
|
no exceptions |
|
895
|
|
|
|
|
|
|
*/ |
|
896
|
|
|
|
|
|
|
static void |
|
897
|
27
|
|
|
|
|
|
return_11part_tm(pTHX_ SV ** SP, struct tm *mytm) |
|
898
|
|
|
|
|
|
|
{ |
|
899
|
27
|
|
|
|
|
|
my_mini_mktime(mytm); |
|
900
|
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
/* warn("tm: %d-%d-%d %d:%d:%d\n", mytm->tm_year, mytm->tm_mon, mytm->tm_mday, mytm->tm_hour, mytm->tm_min, mytm->tm_sec); */ |
|
902
|
27
|
50
|
|
|
|
|
EXTEND(SP, 11); |
|
903
|
27
|
|
|
|
|
|
SP = push_common_tm(aTHX_ SP, mytm); |
|
904
|
|
|
|
|
|
|
/* epoch */ |
|
905
|
27
|
|
|
|
|
|
PUSHs(newSViv(0)); |
|
906
|
|
|
|
|
|
|
/* islocal */ |
|
907
|
27
|
|
|
|
|
|
PUSHs(newSViv(0)); |
|
908
|
27
|
|
|
|
|
|
PUTBACK; |
|
909
|
|
|
|
|
|
|
{ |
|
910
|
27
|
|
|
|
|
|
SV ** endsp = SP; /* the SV * under SP needs to be mortaled */ |
|
911
|
27
|
|
|
|
|
|
SP -= (11 - 1); /* subtract 0 based count of SVs to mortal */ |
|
912
|
|
|
|
|
|
|
/* mortal target of SP, then increment before function call |
|
913
|
|
|
|
|
|
|
so SP is already calculated before next comparison to not stall CPU */ |
|
914
|
|
|
|
|
|
|
do { |
|
915
|
297
|
|
|
|
|
|
sv_2mortal(*SP++); |
|
916
|
297
|
100
|
|
|
|
|
} while(SP <= endsp); |
|
917
|
|
|
|
|
|
|
} |
|
918
|
27
|
|
|
|
|
|
return; |
|
919
|
|
|
|
|
|
|
} |
|
920
|
|
|
|
|
|
|
|
|
921
|
|
|
|
|
|
|
|
|
922
|
20
|
|
|
|
|
|
static void _populate_C_time_locale(pTHX_ HV* locales ) |
|
923
|
|
|
|
|
|
|
{ |
|
924
|
20
|
|
|
|
|
|
AV* alt_names = (AV *) SvRV( *hv_fetch(locales, "alt_month", 9, 0) ); |
|
925
|
20
|
|
|
|
|
|
AV* long_names = (AV *) SvRV( *hv_fetch(locales, "month", 5, 0) ); |
|
926
|
20
|
|
|
|
|
|
AV* short_names = (AV *) SvRV( *hv_fetch(locales, "mon", 3, 0) ); |
|
927
|
|
|
|
|
|
|
int i; |
|
928
|
|
|
|
|
|
|
|
|
929
|
260
|
100
|
|
|
|
|
for (i = 0; i < 1 + (int) av_len( long_names ); i++) { |
|
930
|
240
|
50
|
|
|
|
|
Locale->alt_month[i] = SvPV_nolen( (SV *) *av_fetch(alt_names, i, 0) ); |
|
931
|
240
|
50
|
|
|
|
|
Locale->month[i] = SvPV_nolen( (SV *) *av_fetch(long_names, i, 0) ); |
|
932
|
240
|
50
|
|
|
|
|
Locale->mon[i] = SvPV_nolen( (SV *) *av_fetch(short_names, i, 0) ); |
|
933
|
|
|
|
|
|
|
} |
|
934
|
|
|
|
|
|
|
|
|
935
|
20
|
|
|
|
|
|
long_names = (AV *) SvRV( *hv_fetch(locales, "weekday", 7, 0) ); |
|
936
|
20
|
|
|
|
|
|
short_names = (AV *) SvRV( *hv_fetch(locales, "wday", 4, 0) ); |
|
937
|
|
|
|
|
|
|
|
|
938
|
160
|
100
|
|
|
|
|
for (i = 0; i < 1 + (int) av_len( long_names ); i++) { |
|
939
|
140
|
50
|
|
|
|
|
Locale->wday[i] = SvPV_nolen( (SV *) *av_fetch(short_names, i, 0) ); |
|
940
|
140
|
50
|
|
|
|
|
Locale->weekday[i] = SvPV_nolen( (SV *) *av_fetch(long_names, i, 0) ); |
|
941
|
|
|
|
|
|
|
} |
|
942
|
|
|
|
|
|
|
|
|
943
|
20
|
50
|
|
|
|
|
Locale->am = SvPV_nolen( (SV *) *hv_fetch(locales, "am", 2, 0) ); |
|
944
|
20
|
50
|
|
|
|
|
Locale->pm = SvPV_nolen( (SV *) *hv_fetch(locales, "pm", 2, 0) ); |
|
945
|
20
|
50
|
|
|
|
|
Locale->AM = SvPV_nolen( (SV *) *hv_fetch(locales, "AM", 2, 0) ); |
|
946
|
20
|
50
|
|
|
|
|
Locale->PM = SvPV_nolen( (SV *) *hv_fetch(locales, "PM", 2, 0) ); |
|
947
|
|
|
|
|
|
|
|
|
948
|
20
|
|
|
|
|
|
return; |
|
949
|
|
|
|
|
|
|
} |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
MODULE = Time::Piece PACKAGE = Time::Piece |
|
952
|
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
PROTOTYPES: ENABLE |
|
954
|
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
void |
|
956
|
|
|
|
|
|
|
_strftime(fmt, epoch, islocal = 1) |
|
957
|
|
|
|
|
|
|
char * fmt |
|
958
|
|
|
|
|
|
|
time_t epoch |
|
959
|
|
|
|
|
|
|
int islocal |
|
960
|
|
|
|
|
|
|
CODE: |
|
961
|
|
|
|
|
|
|
{ |
|
962
|
|
|
|
|
|
|
char tmpbuf[TP_BUF_SIZE]; |
|
963
|
|
|
|
|
|
|
struct tm mytm; |
|
964
|
|
|
|
|
|
|
size_t len; |
|
965
|
|
|
|
|
|
|
|
|
966
|
40
|
100
|
|
|
|
|
if(islocal == 1) |
|
967
|
5
|
|
|
|
|
|
mytm = *localtime(&epoch); |
|
968
|
|
|
|
|
|
|
else |
|
969
|
35
|
|
|
|
|
|
mytm = *gmtime(&epoch); |
|
970
|
|
|
|
|
|
|
|
|
971
|
40
|
|
|
|
|
|
len = strftime(tmpbuf, TP_BUF_SIZE, fmt, &mytm); |
|
972
|
|
|
|
|
|
|
/* |
|
973
|
|
|
|
|
|
|
** The following is needed to handle to the situation where |
|
974
|
|
|
|
|
|
|
** tmpbuf overflows. Basically we want to allocate a buffer |
|
975
|
|
|
|
|
|
|
** and try repeatedly. The reason why it is so complicated |
|
976
|
|
|
|
|
|
|
** is that getting a return value of 0 from strftime can indicate |
|
977
|
|
|
|
|
|
|
** one of the following: |
|
978
|
|
|
|
|
|
|
** 1. buffer overflowed, |
|
979
|
|
|
|
|
|
|
** 2. illegal conversion specifier, or |
|
980
|
|
|
|
|
|
|
** 3. the format string specifies nothing to be returned(not |
|
981
|
|
|
|
|
|
|
** an error). This could be because format is an empty string |
|
982
|
|
|
|
|
|
|
** or it specifies %p that yields an empty string in some locale. |
|
983
|
|
|
|
|
|
|
** If there is a better way to make it portable, go ahead by |
|
984
|
|
|
|
|
|
|
** all means. |
|
985
|
|
|
|
|
|
|
*/ |
|
986
|
40
|
50
|
|
|
|
|
if ((len > 0 && len < TP_BUF_SIZE) || (len == 0 && *fmt == '\0')) |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
987
|
40
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVpv(tmpbuf, len)); |
|
988
|
|
|
|
|
|
|
else { |
|
989
|
|
|
|
|
|
|
/* Possibly buf overflowed - try again with a bigger buf */ |
|
990
|
0
|
|
|
|
|
|
size_t fmtlen = strlen(fmt); |
|
991
|
0
|
|
|
|
|
|
size_t bufsize = fmtlen + TP_BUF_SIZE; |
|
992
|
|
|
|
|
|
|
char* buf; |
|
993
|
|
|
|
|
|
|
size_t buflen; |
|
994
|
|
|
|
|
|
|
|
|
995
|
0
|
|
|
|
|
|
New(0, buf, bufsize, char); |
|
996
|
0
|
0
|
|
|
|
|
while (buf) { |
|
997
|
0
|
|
|
|
|
|
buflen = strftime(buf, bufsize, fmt, &mytm); |
|
998
|
0
|
0
|
|
|
|
|
if (buflen > 0 && buflen < bufsize) |
|
|
|
0
|
|
|
|
|
|
|
999
|
0
|
|
|
|
|
|
break; |
|
1000
|
|
|
|
|
|
|
/* heuristic to prevent out-of-memory errors */ |
|
1001
|
0
|
0
|
|
|
|
|
if (bufsize > 100*fmtlen) { |
|
1002
|
0
|
|
|
|
|
|
Safefree(buf); |
|
1003
|
0
|
|
|
|
|
|
buf = NULL; |
|
1004
|
0
|
|
|
|
|
|
break; |
|
1005
|
|
|
|
|
|
|
} |
|
1006
|
0
|
|
|
|
|
|
bufsize *= 2; |
|
1007
|
0
|
|
|
|
|
|
Renew(buf, bufsize, char); |
|
1008
|
|
|
|
|
|
|
} |
|
1009
|
0
|
0
|
|
|
|
|
if (buf) { |
|
1010
|
0
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVpv(buf, buflen)); |
|
1011
|
0
|
|
|
|
|
|
Safefree(buf); |
|
1012
|
|
|
|
|
|
|
} |
|
1013
|
|
|
|
|
|
|
else |
|
1014
|
0
|
|
|
|
|
|
ST(0) = sv_2mortal(newSVpv(tmpbuf, len)); |
|
1015
|
|
|
|
|
|
|
} |
|
1016
|
|
|
|
|
|
|
} |
|
1017
|
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
void |
|
1019
|
|
|
|
|
|
|
_tzset() |
|
1020
|
|
|
|
|
|
|
PPCODE: |
|
1021
|
47
|
|
|
|
|
|
PUTBACK; /* makes rest of this function tailcall friendly */ |
|
1022
|
47
|
|
|
|
|
|
my_tzset(aTHX); |
|
1023
|
47
|
|
|
|
|
|
return; /* skip XSUBPP's PUTBACK */ |
|
1024
|
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
void |
|
1026
|
|
|
|
|
|
|
_strptime ( string, format, got_GMT, SV* localization ) |
|
1027
|
|
|
|
|
|
|
char * string |
|
1028
|
|
|
|
|
|
|
char * format |
|
1029
|
|
|
|
|
|
|
int got_GMT |
|
1030
|
|
|
|
|
|
|
PREINIT: |
|
1031
|
|
|
|
|
|
|
struct tm mytm; |
|
1032
|
|
|
|
|
|
|
char * remainder; |
|
1033
|
|
|
|
|
|
|
HV * locales; |
|
1034
|
|
|
|
|
|
|
PPCODE: |
|
1035
|
20
|
|
|
|
|
|
memset(&mytm, 0, sizeof(mytm)); |
|
1036
|
|
|
|
|
|
|
|
|
1037
|
|
|
|
|
|
|
/* sensible defaults. */ |
|
1038
|
20
|
|
|
|
|
|
mytm.tm_mday = 1; |
|
1039
|
20
|
|
|
|
|
|
mytm.tm_year = 70; |
|
1040
|
20
|
|
|
|
|
|
mytm.tm_wday = 4; |
|
1041
|
20
|
|
|
|
|
|
mytm.tm_isdst = -1; /* -1 means we don't know */ |
|
1042
|
|
|
|
|
|
|
|
|
1043
|
20
|
50
|
|
|
|
|
if( SvTYPE(SvRV( localization )) == SVt_PVHV ){ |
|
1044
|
20
|
|
|
|
|
|
locales = (HV *)SvRV(localization); |
|
1045
|
|
|
|
|
|
|
} |
|
1046
|
|
|
|
|
|
|
else{ |
|
1047
|
0
|
|
|
|
|
|
croak("_strptime requires a Hash Reference of locales"); |
|
1048
|
|
|
|
|
|
|
} |
|
1049
|
|
|
|
|
|
|
|
|
1050
|
|
|
|
|
|
|
/* populate our locale data struct (used for %[AaBbPp] flags) */ |
|
1051
|
20
|
|
|
|
|
|
_populate_C_time_locale(aTHX_ locales ); |
|
1052
|
|
|
|
|
|
|
|
|
1053
|
20
|
|
|
|
|
|
remainder = (char *)_strptime(aTHX_ string, format, &mytm, &got_GMT); |
|
1054
|
20
|
50
|
|
|
|
|
if (remainder == NULL) { |
|
1055
|
0
|
|
|
|
|
|
croak("Error parsing time"); |
|
1056
|
|
|
|
|
|
|
} |
|
1057
|
20
|
50
|
|
|
|
|
if (*remainder != '\0') { |
|
1058
|
0
|
|
|
|
|
|
warn("Garbage at end of string in strptime: %s", remainder); |
|
1059
|
0
|
|
|
|
|
|
warn("Perhaps a format flag did not match the actual input?"); |
|
1060
|
|
|
|
|
|
|
} |
|
1061
|
|
|
|
|
|
|
|
|
1062
|
20
|
|
|
|
|
|
return_11part_tm(aTHX_ SP, &mytm); |
|
1063
|
20
|
|
|
|
|
|
return; |
|
1064
|
|
|
|
|
|
|
|
|
1065
|
|
|
|
|
|
|
void |
|
1066
|
|
|
|
|
|
|
_mini_mktime(int sec, int min, int hour, int mday, int mon, int year) |
|
1067
|
|
|
|
|
|
|
PREINIT: |
|
1068
|
|
|
|
|
|
|
struct tm mytm; |
|
1069
|
|
|
|
|
|
|
time_t t; |
|
1070
|
|
|
|
|
|
|
PPCODE: |
|
1071
|
7
|
|
|
|
|
|
t = 0; |
|
1072
|
7
|
|
|
|
|
|
mytm = *gmtime(&t); |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
7
|
|
|
|
|
|
mytm.tm_sec = sec; |
|
1075
|
7
|
|
|
|
|
|
mytm.tm_min = min; |
|
1076
|
7
|
|
|
|
|
|
mytm.tm_hour = hour; |
|
1077
|
7
|
|
|
|
|
|
mytm.tm_mday = mday; |
|
1078
|
7
|
|
|
|
|
|
mytm.tm_mon = mon; |
|
1079
|
7
|
|
|
|
|
|
mytm.tm_year = year; |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
7
|
|
|
|
|
|
return_11part_tm(aTHX_ SP, &mytm); |
|
1082
|
7
|
|
|
|
|
|
return; |
|
1083
|
|
|
|
|
|
|
|
|
1084
|
|
|
|
|
|
|
void |
|
1085
|
|
|
|
|
|
|
_crt_localtime(time_t sec) |
|
1086
|
|
|
|
|
|
|
ALIAS: |
|
1087
|
|
|
|
|
|
|
_crt_gmtime = 1 |
|
1088
|
|
|
|
|
|
|
PREINIT: |
|
1089
|
|
|
|
|
|
|
struct tm mytm; |
|
1090
|
|
|
|
|
|
|
PPCODE: |
|
1091
|
6
|
100
|
|
|
|
|
if(ix) mytm = *gmtime(&sec); |
|
1092
|
3
|
|
|
|
|
|
else mytm = *localtime(&sec); |
|
1093
|
|
|
|
|
|
|
/* Need to get: $s,$n,$h,$d,$m,$y */ |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
6
|
50
|
|
|
|
|
EXTEND(SP, 10); |
|
1096
|
6
|
|
|
|
|
|
SP = push_common_tm(aTHX_ SP, &mytm); |
|
1097
|
6
|
|
|
|
|
|
PUSHs(newSViv(mytm.tm_isdst)); |
|
1098
|
6
|
|
|
|
|
|
PUTBACK; |
|
1099
|
|
|
|
|
|
|
{ |
|
1100
|
6
|
|
|
|
|
|
SV ** endsp = SP; /* the SV * under SP needs to be mortaled */ |
|
1101
|
6
|
|
|
|
|
|
SP -= (10 - 1); /* subtract 0 based count of SVs to mortal */ |
|
1102
|
|
|
|
|
|
|
/* mortal target of SP, then increment before function call |
|
1103
|
|
|
|
|
|
|
so SP is already calculated before next comparison to not stall CPU */ |
|
1104
|
|
|
|
|
|
|
do { |
|
1105
|
60
|
|
|
|
|
|
sv_2mortal(*SP++); |
|
1106
|
60
|
100
|
|
|
|
|
} while(SP <= endsp); |
|
1107
|
|
|
|
|
|
|
} |
|
1108
|
6
|
|
|
|
|
|
return; |
|
1109
|
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
SV* |
|
1111
|
|
|
|
|
|
|
_get_localization() |
|
1112
|
|
|
|
|
|
|
INIT: |
|
1113
|
0
|
|
|
|
|
|
HV* locales = newHV(); |
|
1114
|
0
|
|
|
|
|
|
AV* wdays = newAV(); |
|
1115
|
0
|
|
|
|
|
|
AV* weekdays = newAV(); |
|
1116
|
0
|
|
|
|
|
|
AV* mons = newAV(); |
|
1117
|
0
|
|
|
|
|
|
AV* months = newAV(); |
|
1118
|
|
|
|
|
|
|
SV** tmp; |
|
1119
|
|
|
|
|
|
|
size_t len; |
|
1120
|
|
|
|
|
|
|
char buf[TP_BUF_SIZE]; |
|
1121
|
|
|
|
|
|
|
size_t i; |
|
1122
|
0
|
|
|
|
|
|
time_t t = 1325386800; /*1325386800 = Sun, 01 Jan 2012 03:00:00 GMT*/ |
|
1123
|
0
|
|
|
|
|
|
struct tm mytm = *gmtime(&t); |
|
1124
|
|
|
|
|
|
|
CODE: |
|
1125
|
|
|
|
|
|
|
|
|
1126
|
0
|
0
|
|
|
|
|
for(i = 0; i < 7; ++i){ |
|
1127
|
|
|
|
|
|
|
|
|
1128
|
0
|
|
|
|
|
|
len = strftime(buf, TP_BUF_SIZE, "%a", &mytm); |
|
1129
|
0
|
|
|
|
|
|
av_push(wdays, (SV *) newSVpvn(buf, len)); |
|
1130
|
|
|
|
|
|
|
|
|
1131
|
0
|
|
|
|
|
|
len = strftime(buf, TP_BUF_SIZE, "%A", &mytm); |
|
1132
|
0
|
|
|
|
|
|
av_push(weekdays, (SV *) newSVpvn(buf, len)); |
|
1133
|
|
|
|
|
|
|
|
|
1134
|
0
|
|
|
|
|
|
++mytm.tm_wday; |
|
1135
|
|
|
|
|
|
|
} |
|
1136
|
|
|
|
|
|
|
|
|
1137
|
0
|
0
|
|
|
|
|
for(i = 0; i < 12; ++i){ |
|
1138
|
|
|
|
|
|
|
|
|
1139
|
0
|
|
|
|
|
|
len = strftime(buf, TP_BUF_SIZE, "%b", &mytm); |
|
1140
|
0
|
|
|
|
|
|
av_push(mons, (SV *) newSVpvn(buf, len)); |
|
1141
|
|
|
|
|
|
|
|
|
1142
|
0
|
|
|
|
|
|
len = strftime(buf, TP_BUF_SIZE, "%B", &mytm); |
|
1143
|
0
|
|
|
|
|
|
av_push(months, (SV *) newSVpvn(buf, len)); |
|
1144
|
|
|
|
|
|
|
|
|
1145
|
0
|
|
|
|
|
|
++mytm.tm_mon; |
|
1146
|
|
|
|
|
|
|
} |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "wday", 4, newRV_noinc((SV *) wdays), 0); |
|
1149
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "weekday", 7, newRV_noinc((SV *) weekdays), 0); |
|
1150
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "mon", 3, newRV_noinc((SV *) mons), 0); |
|
1151
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "month", 5, newRV_noinc((SV *) months), 0); |
|
1152
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "alt_month", 9, newRV((SV *) months), 0); |
|
1153
|
|
|
|
|
|
|
|
|
1154
|
0
|
|
|
|
|
|
len = strftime(buf, TP_BUF_SIZE, "%p", &mytm); |
|
1155
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "AM", 2, newSVpvn(buf,len), 0); |
|
1156
|
0
|
|
|
|
|
|
mytm.tm_hour = 18; |
|
1157
|
0
|
|
|
|
|
|
len = strftime(buf, TP_BUF_SIZE, "%p", &mytm); |
|
1158
|
0
|
|
|
|
|
|
tmp = hv_store(locales, "PM", 2, newSVpvn(buf,len), 0); |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
0
|
0
|
|
|
|
|
if(tmp == NULL || !SvOK( (SV *) *tmp)){ |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1161
|
0
|
|
|
|
|
|
croak("Failed to get localization."); |
|
1162
|
|
|
|
|
|
|
} |
|
1163
|
|
|
|
|
|
|
|
|
1164
|
0
|
|
|
|
|
|
RETVAL = newRV_noinc((SV *)locales); |
|
1165
|
|
|
|
|
|
|
OUTPUT: |
|
1166
|
|
|
|
|
|
|
RETVAL |