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