blob: 7e8e23499a80f5b94fe0935dc027368e37bc44ac [file] [log] [blame]
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -07001/* $OpenBSD: strptime.c,v 1.11 2005/08/08 08:05:38 espie Exp $ */
2/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08003
4/*-
5 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code was contributed to The NetBSD Foundation by Klaus Klein.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39//#include <sys/localedef.h>
40#include <ctype.h>
Elliott Hughes81baaf22018-02-28 15:22:48 -080041#include <errno.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080042#include <locale.h>
Elliott Hughes81baaf22018-02-28 15:22:48 -080043#include <stdlib.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080044#include <string.h>
45#include <time.h>
46#include "tzfile.h"
47
48static const struct {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070049 const char *abday[7];
50 const char *day[7];
51 const char *abmon[12];
52 const char *mon[12];
53 const char *am_pm[2];
54 const char *d_t_fmt;
55 const char *d_fmt;
56 const char *t_fmt;
57 const char *t_fmt_ampm;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080058} _DefaultTimeLocale = {
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070059 {
60 "Sun","Mon","Tue","Wed","Thu","Fri","Sat",
61 },
62 {
63 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
64 "Friday", "Saturday"
65 },
66 {
67 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
68 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
69 },
70 {
71 "January", "February", "March", "April", "May", "June", "July",
72 "August", "September", "October", "November", "December"
73 },
74 {
75 "AM", "PM"
76 },
77 "%a %b %d %H:%M:%S %Y",
78 "%m/%d/%y",
79 "%H:%M:%S",
80 "%I:%M:%S %p"
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080081};
82
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070083#define _ctloc(x) (_DefaultTimeLocale.x)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080084
85/*
86 * We do not implement alternate representations. However, we always
87 * check whether a given modifier is allowed for a certain conversion.
88 */
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -070089#define _ALT_E 0x01
90#define _ALT_O 0x02
91#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080092
93
Glenn Kastenb138e4f2011-01-09 10:33:23 -080094struct century_relyear {
95 int century;
96 int relyear;
97};
Elliott Hughesd065c042020-09-01 19:02:44 -070098
99static char gmt[] = { "GMT" };
100static char utc[] = { "UTC" };
101/* RFC-822/RFC-2822 */
102static const char * const nast[5] = {
103 "EST", "CST", "MST", "PST", "\0\0\0"
104};
105static const char * const nadt[5] = {
106 "EDT", "CDT", "MDT", "PDT", "\0\0\0"
107};
108
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700109static int _conv_num(const unsigned char **, int *, int, int);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800110static unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
111 struct century_relyear *);
Elliott Hughesd065c042020-09-01 19:02:44 -0700112static const u_char *_find_string(const u_char *, int *, const char * const *,
113 const char * const *, int);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800114
115
116char *
117strptime(const char *buf, const char *fmt, struct tm *tm)
118{
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800119 struct century_relyear cr;
120 cr.century = TM_YEAR_BASE;
121 cr.relyear = -1;
122 return (char*)(_strptime((const unsigned char*)buf, fmt, tm, &cr));
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800123}
124
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700125static unsigned char *
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800126_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800127{
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700128 unsigned char c;
Elliott Hughesd065c042020-09-01 19:02:44 -0700129 const unsigned char *bp, *ep;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700130 size_t len = 0;
Elliott Hughesd065c042020-09-01 19:02:44 -0700131 int alt_format, i, offs;
132 int neg = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800133
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700134 bp = (unsigned char *)buf;
135 while ((c = *fmt) != '\0') {
136 /* Clear `alternate' modifier prior to new conversion. */
137 alt_format = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800138
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700139 /* Eat up white-space. */
140 if (isspace(c)) {
141 while (isspace(*bp))
142 bp++;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800143
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700144 fmt++;
145 continue;
146 }
Elliott Hughes81baaf22018-02-28 15:22:48 -0800147
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700148 if ((c = *fmt++) != '%')
149 goto literal;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800150
151
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700152again: switch (c = *fmt++) {
153 case '%': /* "%%" is converted to "%". */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800154literal:
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700155 if (c != *bp++)
156 return (NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800157
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700158 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800159
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700160 /*
161 * "Alternative" modifiers. Just set the appropriate flag
162 * and start over again.
163 */
164 case 'E': /* "%E?" alternative conversion modifier. */
165 _LEGAL_ALT(0);
166 alt_format |= _ALT_E;
167 goto again;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800168
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700169 case 'O': /* "%O?" alternative conversion modifier. */
170 _LEGAL_ALT(0);
171 alt_format |= _ALT_O;
172 goto again;
Elliott Hughes81baaf22018-02-28 15:22:48 -0800173
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700174 /*
175 * "Complex" conversion rules, implemented through recursion.
176 */
177 case 'c': /* Date and time, using the locale's format. */
178 _LEGAL_ALT(_ALT_E);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800179 if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700180 return (NULL);
181 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800182
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700183 case 'D': /* The date as "%m/%d/%y". */
184 _LEGAL_ALT(0);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800185 if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700186 return (NULL);
187 break;
Elliott Hughes81baaf22018-02-28 15:22:48 -0800188
Elliott Hughesa1fb15b2019-03-26 19:07:40 -0700189 case 'F': /* The date as "%Y-%m-%d". */
190 _LEGAL_ALT(0);
191 if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
192 return (NULL);
193 continue;
194
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700195 case 'R': /* The time as "%H:%M". */
196 _LEGAL_ALT(0);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800197 if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700198 return (NULL);
199 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800200
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700201 case 'r': /* The time as "%I:%M:%S %p". */
202 _LEGAL_ALT(0);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800203 if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700204 return (NULL);
205 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800206
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700207 case 'T': /* The time as "%H:%M:%S". */
208 _LEGAL_ALT(0);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800209 if (!(bp = _strptime(bp, "%H:%M:%S", tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700210 return (NULL);
211 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800212
Elliott Hughesa1fb15b2019-03-26 19:07:40 -0700213 case 'v': /* The date as "%e-%b-%Y". */
214 _LEGAL_ALT(0);
215 if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
216 return (NULL);
217 break;
218
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700219 case 'X': /* The time, using the locale's format. */
220 _LEGAL_ALT(_ALT_E);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800221 if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700222 return (NULL);
223 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800224
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700225 case 'x': /* The date, using the locale's format. */
226 _LEGAL_ALT(_ALT_E);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800227 if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, cr)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700228 return (NULL);
229 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800230
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700231 /*
232 * "Elementary" conversion rules.
233 */
234 case 'A': /* The day of week, using the locale's form. */
235 case 'a':
236 _LEGAL_ALT(0);
237 for (i = 0; i < 7; i++) {
238 /* Full name. */
239 len = strlen(_ctloc(day[i]));
240 if (strncasecmp(_ctloc(day[i]), (const char*)bp, len) == 0)
241 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800242
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700243 /* Abbreviated name. */
244 len = strlen(_ctloc(abday[i]));
245 if (strncasecmp(_ctloc(abday[i]), (const char*)bp, len) == 0)
246 break;
247 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800248
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700249 /* Nothing matched. */
250 if (i == 7)
251 return (NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800252
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700253 tm->tm_wday = i;
254 bp += len;
255 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800256
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700257 case 'B': /* The month, using the locale's form. */
258 case 'b':
259 case 'h':
260 _LEGAL_ALT(0);
261 for (i = 0; i < 12; i++) {
262 /* Full name. */
263 len = strlen(_ctloc(mon[i]));
264 if (strncasecmp(_ctloc(mon[i]), (const char*)bp, len) == 0)
265 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800266
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700267 /* Abbreviated name. */
268 len = strlen(_ctloc(abmon[i]));
269 if (strncasecmp(_ctloc(abmon[i]), (const char*)bp, len) == 0)
270 break;
271 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800272
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700273 /* Nothing matched. */
274 if (i == 12)
275 return (NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800276
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700277 tm->tm_mon = i;
278 bp += len;
279 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800280
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700281 case 'C': /* The century number. */
282 _LEGAL_ALT(_ALT_E);
283 if (!(_conv_num(&bp, &i, 0, 99)))
284 return (NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800285
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800286 cr->century = i * 100;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700287 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800288
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700289 case 'd': /* The day of month. */
290 case 'e':
291 _LEGAL_ALT(_ALT_O);
292 if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
293 return (NULL);
294 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800295
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700296 case 'k': /* The hour (24-hour clock representation). */
297 _LEGAL_ALT(0);
298 /* FALLTHROUGH */
299 case 'H':
300 _LEGAL_ALT(_ALT_O);
301 if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
302 return (NULL);
303 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800304
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700305 case 'l': /* The hour (12-hour clock representation). */
306 _LEGAL_ALT(0);
307 /* FALLTHROUGH */
308 case 'I':
309 _LEGAL_ALT(_ALT_O);
310 if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
311 return (NULL);
312 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800313
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700314 case 'j': /* The day of year. */
315 _LEGAL_ALT(0);
316 if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
317 return (NULL);
318 tm->tm_yday--;
319 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800320
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700321 case 'M': /* The minute. */
322 _LEGAL_ALT(_ALT_O);
323 if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
324 return (NULL);
325 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800326
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700327 case 'm': /* The month. */
328 _LEGAL_ALT(_ALT_O);
329 if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
330 return (NULL);
331 tm->tm_mon--;
332 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800333
Elliott Hughesa1fb15b2019-03-26 19:07:40 -0700334 case 'P':
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700335 case 'p': /* The locale's equivalent of AM/PM. */
336 _LEGAL_ALT(0);
337 /* AM? */
338 len = strlen(_ctloc(am_pm[0]));
339 if (strncasecmp(_ctloc(am_pm[0]), (const char*)bp, len) == 0) {
340 if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */
341 return (NULL);
342 else if (tm->tm_hour == 12)
343 tm->tm_hour = 0;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800344
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700345 bp += len;
346 break;
347 }
348 /* PM? */
349 len = strlen(_ctloc(am_pm[1]));
350 if (strncasecmp(_ctloc(am_pm[1]), (const char*)bp, len) == 0) {
351 if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */
352 return (NULL);
353 else if (tm->tm_hour < 12)
354 tm->tm_hour += 12;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800355
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700356 bp += len;
357 break;
358 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800359
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700360 /* Nothing matched. */
361 return (NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800362
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700363 case 'S': /* The seconds. */
364 _LEGAL_ALT(_ALT_O);
365 if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
366 return (NULL);
367 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800368
Elliott Hughes81baaf22018-02-28 15:22:48 -0800369 case 's':
370 {
371 // Android addition, based on FreeBSD's implementation.
372 int saved_errno = errno;
373 errno = 0;
374 const unsigned char* old_bp = bp;
375 long n = strtol((const char*) bp, (char**) &bp, 10);
376 time_t t = n;
377 if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
378 errno = saved_errno;
379 return NULL;
380 }
381 errno = saved_errno;
382
383 if (localtime_r(&t, tm) == NULL) return NULL;
384 }
385 break;
386
387
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700388 case 'U': /* The week of year, beginning on sunday. */
389 case 'W': /* The week of year, beginning on monday. */
390 _LEGAL_ALT(_ALT_O);
391 /*
392 * XXX This is bogus, as we can not assume any valid
393 * information present in the tm structure at this
394 * point to calculate a real value, so just check the
395 * range for now.
396 */
397 if (!(_conv_num(&bp, &i, 0, 53)))
398 return (NULL);
399 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800400
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700401 case 'w': /* The day of week, beginning on sunday. */
402 _LEGAL_ALT(_ALT_O);
403 if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
404 return (NULL);
405 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800406
Elliott Hughesa1fb15b2019-03-26 19:07:40 -0700407 case 'u': /* The day of week, monday = 1. */
408 _LEGAL_ALT(_ALT_O);
409 if (!(_conv_num(&bp, &i, 1, 7)))
410 return (NULL);
411 tm->tm_wday = i % 7;
412 continue;
413
414 case 'g': /* The year corresponding to the ISO week
415 * number but without the century.
416 */
417 if (!(_conv_num(&bp, &i, 0, 99)))
418 return (NULL);
419 continue;
420
421 case 'G': /* The year corresponding to the ISO week
422 * number with century.
423 */
424 do
425 bp++;
426 while (isdigit(*bp));
427 continue;
428
429 case 'V': /* The ISO 8601:1988 week number as decimal */
430 if (!(_conv_num(&bp, &i, 0, 53)))
431 return (NULL);
432 continue;
433
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700434 case 'Y': /* The year. */
435 _LEGAL_ALT(_ALT_E);
436 if (!(_conv_num(&bp, &i, 0, 9999)))
437 return (NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800438
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800439 cr->relyear = -1;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700440 tm->tm_year = i - TM_YEAR_BASE;
441 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800442
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700443 case 'y': /* The year within the century (2 digits). */
444 _LEGAL_ALT(_ALT_E | _ALT_O);
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800445 if (!(_conv_num(&bp, &cr->relyear, 0, 99)))
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700446 return (NULL);
447 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800448
Elliott Hughesd065c042020-09-01 19:02:44 -0700449 case 'Z':
450 tzset();
451 if (strncmp((const char *)bp, gmt, 3) == 0) {
452 tm->tm_isdst = 0;
453 tm->tm_gmtoff = 0;
454 tm->tm_zone = gmt;
455 bp += 3;
456 } else if (strncmp((const char *)bp, utc, 3) == 0) {
457 tm->tm_isdst = 0;
458 tm->tm_gmtoff = 0;
459 tm->tm_zone = utc;
460 bp += 3;
461 } else {
462 ep = _find_string(bp, &i,
463 (const char * const *)tzname,
464 NULL, 2);
465 if (ep == NULL)
466 return (NULL);
467
468 tm->tm_isdst = i;
469 tm->tm_gmtoff = -(timezone);
470 tm->tm_zone = tzname[i];
471 bp = ep;
472 }
473 continue;
474
475 case 'z':
476 /*
477 * We recognize all ISO 8601 formats:
478 * Z = Zulu time/UTC
479 * [+-]hhmm
480 * [+-]hh:mm
481 * [+-]hh
482 * We recognize all RFC-822/RFC-2822 formats:
483 * UT|GMT
484 * North American : UTC offsets
485 * E[DS]T = Eastern : -4 | -5
486 * C[DS]T = Central : -5 | -6
487 * M[DS]T = Mountain: -6 | -7
488 * P[DS]T = Pacific : -7 | -8
489 */
490 while (isspace(*bp))
491 bp++;
492
493 switch (*bp++) {
494 case 'G':
495 if (*bp++ != 'M')
496 return NULL;
497 /*FALLTHROUGH*/
498 case 'U':
499 if (*bp++ != 'T')
500 return NULL;
501 /*FALLTHROUGH*/
502 case 'Z':
503 tm->tm_isdst = 0;
504 tm->tm_gmtoff = 0;
505 tm->tm_zone = utc;
506 continue;
507 case '+':
508 neg = 0;
509 break;
510 case '-':
511 neg = 1;
512 break;
513 default:
514 --bp;
515 ep = _find_string(bp, &i, nast, NULL, 4);
516 if (ep != NULL) {
517 tm->tm_gmtoff = (-5 - i) * SECSPERHOUR;
518 tm->tm_zone = (char *)nast[i];
519 bp = ep;
520 continue;
521 }
522 ep = _find_string(bp, &i, nadt, NULL, 4);
523 if (ep != NULL) {
524 tm->tm_isdst = 1;
525 tm->tm_gmtoff = (-4 - i) * SECSPERHOUR;
526 tm->tm_zone = (char *)nadt[i];
527 bp = ep;
528 continue;
529 }
530 return NULL;
531 }
532 if (!isdigit(bp[0]) || !isdigit(bp[1]))
533 return NULL;
534 offs = ((bp[0]-'0') * 10 + (bp[1]-'0')) * SECSPERHOUR;
535 bp += 2;
536 if (*bp == ':')
537 bp++;
538 if (isdigit(*bp)) {
539 offs += (*bp++ - '0') * 10 * SECSPERMIN;
540 if (!isdigit(*bp))
541 return NULL;
542 offs += (*bp++ - '0') * SECSPERMIN;
543 }
544 if (neg)
545 offs = -offs;
546 tm->tm_isdst = 0; /* XXX */
547 tm->tm_gmtoff = offs;
548 tm->tm_zone = NULL; /* XXX */
549 continue;
550
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700551 /*
552 * Miscellaneous conversions.
553 */
554 case 'n': /* Any kind of white-space. */
555 case 't':
556 _LEGAL_ALT(0);
557 while (isspace(*bp))
558 bp++;
559 break;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800560
561
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700562 default: /* Unknown/unsupported conversion. */
563 return (NULL);
564 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800565
566
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700567 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800568
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700569 /*
570 * We need to evaluate the two digit year spec (%y)
571 * last as we can get a century spec (%C) at any time.
572 */
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800573 if (cr->relyear != -1) {
574 if (cr->century == TM_YEAR_BASE) {
575 if (cr->relyear <= 68)
576 tm->tm_year = cr->relyear + 2000 - TM_YEAR_BASE;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700577 else
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800578 tm->tm_year = cr->relyear + 1900 - TM_YEAR_BASE;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700579 } else {
Glenn Kastenb138e4f2011-01-09 10:33:23 -0800580 tm->tm_year = cr->relyear + cr->century - TM_YEAR_BASE;
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700581 }
582 }
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800583
The Android Open Source Projectedbe7fc2009-03-18 22:20:24 -0700584 return (unsigned char*)bp;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800585}
586
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800587static int
588_conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
589{
Elliott Hughesd065c042020-09-01 19:02:44 -0700590 int result = 0;
591 int rulim = ulim;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800592
Elliott Hughesd065c042020-09-01 19:02:44 -0700593 if (**buf < '0' || **buf > '9')
594 return (0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800595
Elliott Hughesd065c042020-09-01 19:02:44 -0700596 /* we use rulim to break out of the loop when we run out of digits */
597 do {
598 result *= 10;
599 result += *(*buf)++ - '0';
600 rulim /= 10;
601 } while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800602
Elliott Hughesd065c042020-09-01 19:02:44 -0700603 if (result < llim || result > ulim)
604 return (0);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800605
Elliott Hughesd065c042020-09-01 19:02:44 -0700606 *dest = result;
607 return (1);
608}
609
610static const u_char *
611_find_string(const u_char *bp, int *tgt, const char * const *n1,
612 const char * const *n2, int c)
613{
614 int i;
615 unsigned int len;
616
617 /* check full name - then abbreviated ones */
618 for (; n1 != NULL; n1 = n2, n2 = NULL) {
619 for (i = 0; i < c; i++, n1++) {
620 len = strlen(*n1);
621 if (strncasecmp(*n1, (const char *)bp, len) == 0) {
622 *tgt = i;
623 return bp + len;
624 }
625 }
626 }
627
628 /* Nothing matched */
629 return NULL;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800630}
Elliott Hughes3376c232018-02-13 23:14:12 -0800631
632char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t l) {
633 return strptime(buf, fmt, tm);
634}