Merge "Sync strptime.c with upstream."

This commit is contained in:
Elliott Hughes 2023-01-23 22:04:29 +00:00 committed by Gerrit Code Review
commit 98c641b096
6 changed files with 658 additions and 402 deletions

View file

@ -252,7 +252,10 @@ cc_library_static {
srcs: [
"tzcode/**/*.c",
"tzcode/bionic.cpp",
"upstream-openbsd/lib/libc/time/wcsftime.c", // tzcode doesn't include wcsftime, so we use the OpenBSD one.
// tzcode doesn't include strptime or wcsftime, so we use the OpenBSD
// code (with some local changes in the strptime case).
"upstream-openbsd/lib/libc/locale/_def_time.c",
"upstream-openbsd/lib/libc/time/wcsftime.c",
],
cflags: [
@ -1198,6 +1201,7 @@ cc_library_static {
"bionic/termios.cpp",
"bionic/thread_private.cpp",
"bionic/threads.cpp",
"bionic/time_l.cpp",
"bionic/timespec_get.cpp",
"bionic/tmpfile.cpp",
"bionic/umount.cpp",

View file

@ -2579,6 +2579,36 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (c) 1994 Winning Strategies, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by Winning Strategies, Inc.
4. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (c) 1996 by Internet Software Consortium.
Permission to use, copy, modify, and distribute this software for any
@ -2779,41 +2809,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
All rights reserved.
This code was contributed to The NetBSD Foundation by Klaus Klein.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the NetBSD
Foundation, Inc. and its contributors.
4. Neither the name of The NetBSD Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (c) 1997, 1998, 1999, 2004 The NetBSD Foundation, Inc.
All rights reserved.
@ -2879,6 +2874,34 @@ POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
All rights reserved.
This code was contributed to The NetBSD Foundation by Klaus Klein.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (c) 1997, 2005 Todd C. Miller <Todd.Miller@courtesan.com>
Permission to use, copy, modify, and distribute this software for any

34
libc/bionic/time_l.cpp Normal file
View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <time.h>
//#include <xlocale.h>
char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t) {
return strptime(buf, fmt, tm);
}

106
libc/tzcode/localedef.h Normal file
View file

@ -0,0 +1,106 @@
/* $OpenBSD: localedef.h,v 1.1 2016/05/23 00:05:15 guenther Exp $ */
/* $NetBSD: localedef.h,v 1.4 1996/04/09 20:55:31 cgd Exp $ */
/*
* Copyright (c) 1994 Winning Strategies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LOCALEDEF_H_
#define _LOCALEDEF_H_
#include <sys/types.h>
typedef struct
{
char *yesexpr;
char *noexpr;
char *yesstr;
char *nostr;
} _MessagesLocale;
typedef struct
{
char *int_curr_symbol;
char *currency_symbol;
char *mon_decimal_point;
char *mon_thousands_sep;
char *mon_grouping;
char *positive_sign;
char *negative_sign;
char int_frac_digits;
char frac_digits;
char p_cs_precedes;
char p_sep_by_space;
char n_cs_precedes;
char n_sep_by_space;
char p_sign_posn;
char n_sign_posn;
char int_p_cs_precedes;
char int_p_sep_by_space;
char int_n_cs_precedes;
char int_n_sep_by_space;
char int_p_sign_posn;
char int_n_sign_posn;
} _MonetaryLocale;
typedef struct
{
const char *decimal_point;
const char *thousands_sep;
const char *grouping;
} _NumericLocale;
typedef struct {
const char *abday[7];
const char *day[7];
const char *abmon[12];
const char *mon[12];
const char *am_pm[2];
const char *d_t_fmt;
const char *d_fmt;
const char *t_fmt;
const char *t_fmt_ampm;
} _TimeLocale;
//__BEGIN_HIDDEN_DECLS
extern const _MessagesLocale *_CurrentMessagesLocale;
extern const _MessagesLocale _DefaultMessagesLocale;
extern const _MonetaryLocale *_CurrentMonetaryLocale;
extern const _MonetaryLocale _DefaultMonetaryLocale;
extern const _NumericLocale *_CurrentNumericLocale;
extern const _NumericLocale _DefaultNumericLocale;
extern const _TimeLocale *_CurrentTimeLocale;
extern const _TimeLocale _DefaultTimeLocale;
//__END_HIDDEN_DECLS
#endif /* !_LOCALEDEF_H_ */

View file

@ -1,8 +1,7 @@
/* $OpenBSD: strptime.c,v 1.11 2005/08/08 08:05:38 espie Exp $ */
/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
/* $OpenBSD: strptime.c,v 1.30 2019/05/12 12:49:52 schwarze Exp $ */
/* $NetBSD: strptime.c,v 1.12 1998/01/20 21:39:40 mycroft Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was contributed to The NetBSD Foundation by Klaus Klein.
@ -15,13 +14,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
@ -36,65 +28,40 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
//#include <sys/localedef.h>
#include <ctype.h>
#include <errno.h>
#include <locale.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include "localedef.h"
#include "private.h"
#include "tzfile.h"
static const struct {
const char *abday[7];
const char *day[7];
const char *abmon[12];
const char *mon[12];
const char *am_pm[2];
const char *d_t_fmt;
const char *d_fmt;
const char *t_fmt;
const char *t_fmt_ampm;
} _DefaultTimeLocale = {
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat",
},
{
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"
},
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
},
{
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"
},
{
"AM", "PM"
},
"%a %b %d %H:%M:%S %Y",
"%m/%d/%y",
"%H:%M:%S",
"%I:%M:%S %p"
};
// Android: ignore OpenBSD's DEF_WEAK() stuff.
#define DEF_WEAK(sym) /* */
// Android: this code is not pointer-sign clean.
#pragma clang diagnostic ignored "-Wpointer-sign"
#pragma clang diagnostic ignored "-Wunused-function"
#define _ctloc(x) (_DefaultTimeLocale.x)
#define _ctloc(x) (_CurrentTimeLocale->x)
/*
* We do not implement alternate representations. However, we always
* check whether a given modifier is allowed for a certain conversion.
*/
#define _ALT_E 0x01
#define _ALT_O 0x02
#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
#define _ALT_E 0x01
#define _ALT_O 0x02
#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
struct century_relyear {
int century;
int relyear;
};
/*
* We keep track of some of the fields we set in order to compute missing ones.
*/
#define FIELD_TM_MON (1 << 0)
#define FIELD_TM_MDAY (1 << 1)
#define FIELD_TM_WDAY (1 << 2)
#define FIELD_TM_YDAY (1 << 3)
#define FIELD_TM_YEAR (1 << 4)
static char gmt[] = { "GMT" };
static char utc[] = { "UTC" };
@ -106,9 +73,15 @@ static const char * const nadt[5] = {
"EDT", "CDT", "MDT", "PDT", "\0\0\0"
};
static int _conv_num(const unsigned char **, int *, int, int);
static unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
struct century_relyear *);
static const int mon_lengths[2][MONSPERYEAR] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static int _conv_num64(const unsigned char **, int64_t *, int64_t, int64_t);
static int _conv_num(const unsigned char **, int *, int, int);
static int leaps_thru_end_of(const int y);
static char *_strptime(const char *, const char *, struct tm *, int);
static const u_char *_find_string(const u_char *, int *, const char * const *,
const char * const *, int);
@ -116,335 +89,353 @@ static const u_char *_find_string(const u_char *, int *, const char * const *,
char *
strptime(const char *buf, const char *fmt, struct tm *tm)
{
struct century_relyear cr;
cr.century = TM_YEAR_BASE;
cr.relyear = -1;
return (char*)(_strptime((const unsigned char*)buf, fmt, tm, &cr));
return(_strptime(buf, fmt, tm, 1));
}
DEF_WEAK(strptime);
static unsigned char *
_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
static char *
_strptime(const char *buf, const char *fmt, struct tm *tm, int initialize)
{
unsigned char c;
const unsigned char *bp, *ep;
size_t len = 0;
int alt_format, i, offs;
int neg = 0;
unsigned char c;
const unsigned char *bp, *ep;
size_t len;
int alt_format, i, offs;
int neg = 0;
static int century, relyear, fields;
bp = (unsigned char *)buf;
while ((c = *fmt) != '\0') {
/* Clear `alternate' modifier prior to new conversion. */
alt_format = 0;
if (initialize) {
century = TM_YEAR_BASE;
relyear = -1;
fields = 0;
}
/* Eat up white-space. */
if (isspace(c)) {
while (isspace(*bp))
bp++;
bp = (const unsigned char *)buf;
while ((c = *fmt) != '\0') {
/* Clear `alternate' modifier prior to new conversion. */
alt_format = 0;
fmt++;
continue;
}
/* Eat up white-space. */
if (isspace(c)) {
while (isspace(*bp))
bp++;
if ((c = *fmt++) != '%')
goto literal;
fmt++;
continue;
}
if ((c = *fmt++) != '%')
goto literal;
again: switch (c = *fmt++) {
case '%': /* "%%" is converted to "%". */
again: switch (c = *fmt++) {
case '%': /* "%%" is converted to "%". */
literal:
if (c != *bp++)
return (NULL);
if (c != *bp++)
return (NULL);
break;
break;
/*
* "Alternative" modifiers. Just set the appropriate flag
* and start over again.
*/
case 'E': /* "%E?" alternative conversion modifier. */
_LEGAL_ALT(0);
alt_format |= _ALT_E;
goto again;
/*
* "Alternative" modifiers. Just set the appropriate flag
* and start over again.
*/
case 'E': /* "%E?" alternative conversion modifier. */
_LEGAL_ALT(0);
alt_format |= _ALT_E;
goto again;
case 'O': /* "%O?" alternative conversion modifier. */
_LEGAL_ALT(0);
alt_format |= _ALT_O;
goto again;
case 'O': /* "%O?" alternative conversion modifier. */
_LEGAL_ALT(0);
alt_format |= _ALT_O;
goto again;
/*
* "Complex" conversion rules, implemented through recursion.
*/
case 'c': /* Date and time, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, cr)))
return (NULL);
break;
/*
* "Complex" conversion rules, implemented through recursion.
*/
case 'c': /* Date and time, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(d_t_fmt), tm, 0)))
return (NULL);
break;
case 'D': /* The date as "%m/%d/%y". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
return (NULL);
break;
case 'D': /* The date as "%m/%d/%y". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%m/%d/%y", tm, 0)))
return (NULL);
break;
case 'F': /* The date as "%Y-%m-%d". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%Y-%m-%d", tm, cr)))
return (NULL);
continue;
case 'F': /* The date as "%Y-%m-%d". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%Y-%m-%d", tm, 0)))
return (NULL);
continue;
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
return (NULL);
break;
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, 0)))
return (NULL);
break;
case 'r': /* The time as "%I:%M:%S %p". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, cr)))
return (NULL);
break;
case 'r': /* The time as "%I:%M:%S %p". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, 0)))
return (NULL);
break;
case 'T': /* The time as "%H:%M:%S". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M:%S", tm, cr)))
return (NULL);
break;
case 'T': /* The time as "%H:%M:%S". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M:%S", tm, 0)))
return (NULL);
break;
case 'v': /* The date as "%e-%b-%Y". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%e-%b-%Y", tm, cr)))
return (NULL);
break;
case 'v': /* Android: the date as "%e-%b-%Y" for strftime() compat; glibc does this too. */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%e-%b-%Y", tm, 0)))
return (NULL);
break;
case 'X': /* The time, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
return (NULL);
break;
case 'X': /* The time, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, 0)))
return (NULL);
break;
case 'x': /* The date, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, cr)))
return (NULL);
break;
case 'x': /* The date, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, 0)))
return (NULL);
break;
/*
* "Elementary" conversion rules.
*/
case 'A': /* The day of week, using the locale's form. */
case 'a':
_LEGAL_ALT(0);
for (i = 0; i < 7; i++) {
/* Full name. */
len = strlen(_ctloc(day[i]));
if (strncasecmp(_ctloc(day[i]), (const char*)bp, len) == 0)
break;
/*
* "Elementary" conversion rules.
*/
case 'A': /* The day of week, using the locale's form. */
case 'a':
_LEGAL_ALT(0);
for (i = 0; i < 7; i++) {
/* Full name. */
len = strlen(_ctloc(day[i]));
if (strncasecmp(_ctloc(day[i]), bp, len) == 0)
break;
/* Abbreviated name. */
len = strlen(_ctloc(abday[i]));
if (strncasecmp(_ctloc(abday[i]), (const char*)bp, len) == 0)
break;
}
/* Abbreviated name. */
len = strlen(_ctloc(abday[i]));
if (strncasecmp(_ctloc(abday[i]), bp, len) == 0)
break;
}
/* Nothing matched. */
if (i == 7)
return (NULL);
/* Nothing matched. */
if (i == 7)
return (NULL);
tm->tm_wday = i;
bp += len;
break;
tm->tm_wday = i;
bp += len;
fields |= FIELD_TM_WDAY;
break;
case 'B': /* The month, using the locale's form. */
case 'b':
case 'h':
_LEGAL_ALT(0);
for (i = 0; i < 12; i++) {
/* Full name. */
len = strlen(_ctloc(mon[i]));
if (strncasecmp(_ctloc(mon[i]), (const char*)bp, len) == 0)
break;
case 'B': /* The month, using the locale's form. */
case 'b':
case 'h':
_LEGAL_ALT(0);
for (i = 0; i < 12; i++) {
/* Full name. */
len = strlen(_ctloc(mon[i]));
if (strncasecmp(_ctloc(mon[i]), bp, len) == 0)
break;
/* Abbreviated name. */
len = strlen(_ctloc(abmon[i]));
if (strncasecmp(_ctloc(abmon[i]), (const char*)bp, len) == 0)
break;
}
/* Abbreviated name. */
len = strlen(_ctloc(abmon[i]));
if (strncasecmp(_ctloc(abmon[i]), bp, len) == 0)
break;
}
/* Nothing matched. */
if (i == 12)
return (NULL);
/* Nothing matched. */
if (i == 12)
return (NULL);
tm->tm_mon = i;
bp += len;
break;
tm->tm_mon = i;
bp += len;
fields |= FIELD_TM_MON;
break;
case 'C': /* The century number. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 99)))
return (NULL);
case 'C': /* The century number. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 99)))
return (NULL);
cr->century = i * 100;
break;
century = i * 100;
break;
case 'd': /* The day of month. */
case 'e':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
return (NULL);
break;
case 'e': /* The day of month. */
if (isspace(*bp))
bp++;
/* FALLTHROUGH */
case 'd':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_mday, 1, 31)))
return (NULL);
fields |= FIELD_TM_MDAY;
break;
case 'k': /* The hour (24-hour clock representation). */
_LEGAL_ALT(0);
/* FALLTHROUGH */
case 'H':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
return (NULL);
break;
case 'k': /* The hour (24-hour clock representation). */
_LEGAL_ALT(0);
/* FALLTHROUGH */
case 'H':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
return (NULL);
break;
case 'l': /* The hour (12-hour clock representation). */
_LEGAL_ALT(0);
/* FALLTHROUGH */
case 'I':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
return (NULL);
break;
case 'l': /* The hour (12-hour clock representation). */
_LEGAL_ALT(0);
/* FALLTHROUGH */
case 'I':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
return (NULL);
break;
case 'j': /* The day of year. */
_LEGAL_ALT(0);
if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
return (NULL);
tm->tm_yday--;
break;
case 'j': /* The day of year. */
_LEGAL_ALT(0);
if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
return (NULL);
tm->tm_yday--;
fields |= FIELD_TM_YDAY;
break;
case 'M': /* The minute. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
return (NULL);
break;
case 'M': /* The minute. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
return (NULL);
break;
case 'm': /* The month. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
return (NULL);
tm->tm_mon--;
break;
case 'm': /* The month. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
return (NULL);
tm->tm_mon--;
fields |= FIELD_TM_MON;
break;
case 'P':
case 'p': /* The locale's equivalent of AM/PM. */
_LEGAL_ALT(0);
/* AM? */
len = strlen(_ctloc(am_pm[0]));
if (strncasecmp(_ctloc(am_pm[0]), (const char*)bp, len) == 0) {
if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */
return (NULL);
else if (tm->tm_hour == 12)
tm->tm_hour = 0;
case 'P': /* Android addition for strftime() compat; glibc does this too. */
case 'p': /* The locale's equivalent of AM/PM. */
_LEGAL_ALT(0);
/* AM? */
len = strlen(_ctloc(am_pm[0]));
if (strncasecmp(_ctloc(am_pm[0]), bp, len) == 0) {
if (tm->tm_hour > 12) /* i.e., 13:00 AM ?! */
return (NULL);
else if (tm->tm_hour == 12)
tm->tm_hour = 0;
bp += len;
break;
}
/* PM? */
len = strlen(_ctloc(am_pm[1]));
if (strncasecmp(_ctloc(am_pm[1]), (const char*)bp, len) == 0) {
if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */
return (NULL);
else if (tm->tm_hour < 12)
tm->tm_hour += 12;
bp += len;
break;
}
/* PM? */
len = strlen(_ctloc(am_pm[1]));
if (strncasecmp(_ctloc(am_pm[1]), bp, len) == 0) {
if (tm->tm_hour > 12) /* i.e., 13:00 PM ?! */
return (NULL);
else if (tm->tm_hour < 12)
tm->tm_hour += 12;
bp += len;
break;
}
bp += len;
break;
}
/* Nothing matched. */
return (NULL);
/* Nothing matched. */
return (NULL);
case 'S': /* The seconds. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
return (NULL);
break;
case 'S': /* The seconds. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_sec, 0, 60)))
return (NULL);
break;
case 's': /* Seconds since epoch */
{
// Android change based on FreeBSD's implementation.
int saved_errno = errno;
errno = 0;
const unsigned char* old_bp = bp;
long n = strtol((const char*) bp, (char**) &bp, 10);
errno = saved_errno;
time_t t = n;
if (bp == old_bp || errno == ERANGE ||
((long) t) != n) return NULL;
case 's':
{
// Android addition, based on FreeBSD's implementation.
int saved_errno = errno;
errno = 0;
const unsigned char* old_bp = bp;
long n = strtol((const char*) bp, (char**) &bp, 10);
time_t t = n;
if (bp == old_bp || errno == ERANGE || ((long) t) != n) {
errno = saved_errno;
return NULL;
}
errno = saved_errno;
if (localtime_r(&t, tm) == NULL) return NULL;
if (localtime_r(&t, tm) == NULL) return NULL;
}
break;
//int64_t i64;
//if (!(_conv_num64(&bp, &i64, 0, INT64_MAX)))
// return (NULL);
//if (!gmtime_r(&i64, tm))
// return (NULL);
fields = 0xffff; /* everything */
}
break;
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
_LEGAL_ALT(_ALT_O);
/*
* XXX This is bogus, as we can not assume any valid
* information present in the tm structure at this
* point to calculate a real value, so just check the
* range for now.
*/
if (!(_conv_num(&bp, &i, 0, 53)))
return (NULL);
break;
case 'w': /* The day of week, beginning on sunday. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
return (NULL);
fields |= FIELD_TM_WDAY;
break;
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
_LEGAL_ALT(_ALT_O);
/*
* XXX This is bogus, as we can not assume any valid
* information present in the tm structure at this
* point to calculate a real value, so just check the
* range for now.
*/
if (!(_conv_num(&bp, &i, 0, 53)))
return (NULL);
break;
case 'u': /* The day of week, monday = 1. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &i, 1, 7)))
return (NULL);
tm->tm_wday = i % 7;
fields |= FIELD_TM_WDAY;
continue;
case 'w': /* The day of week, beginning on sunday. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_wday, 0, 6)))
return (NULL);
break;
case 'g': /* The year corresponding to the ISO week
* number but without the century.
*/
if (!(_conv_num(&bp, &i, 0, 99)))
return (NULL);
continue;
case 'u': /* The day of week, monday = 1. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &i, 1, 7)))
return (NULL);
tm->tm_wday = i % 7;
continue;
case 'G': /* The year corresponding to the ISO week
* number with century.
*/
do
bp++;
while (isdigit(*bp));
continue;
case 'g': /* The year corresponding to the ISO week
* number but without the century.
*/
if (!(_conv_num(&bp, &i, 0, 99)))
return (NULL);
continue;
case 'V': /* The ISO 8601:1988 week number as decimal */
if (!(_conv_num(&bp, &i, 0, 53)))
return (NULL);
continue;
case 'G': /* The year corresponding to the ISO week
* number with century.
*/
do
bp++;
while (isdigit(*bp));
continue;
case 'Y': /* The year. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 9999)))
return (NULL);
case 'V': /* The ISO 8601:1988 week number as decimal */
if (!(_conv_num(&bp, &i, 0, 53)))
return (NULL);
continue;
relyear = -1;
tm->tm_year = i - TM_YEAR_BASE;
fields |= FIELD_TM_YEAR;
break;
case 'Y': /* The year. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 9999)))
return (NULL);
cr->relyear = -1;
tm->tm_year = i - TM_YEAR_BASE;
break;
case 'y': /* The year within the century (2 digits). */
_LEGAL_ALT(_ALT_E | _ALT_O);
if (!(_conv_num(&bp, &cr->relyear, 0, 99)))
return (NULL);
break;
case 'y': /* The year within the century (2 digits). */
_LEGAL_ALT(_ALT_E | _ALT_O);
if (!(_conv_num(&bp, &relyear, 0, 99)))
return (NULL);
break;
case 'Z':
tzset();
@ -548,42 +539,78 @@ literal:
tm->tm_zone = NULL; /* XXX */
continue;
/*
* Miscellaneous conversions.
*/
case 'n': /* Any kind of white-space. */
case 't':
_LEGAL_ALT(0);
while (isspace(*bp))
bp++;
break;
/*
* Miscellaneous conversions.
*/
case 'n': /* Any kind of white-space. */
case 't':
_LEGAL_ALT(0);
while (isspace(*bp))
bp++;
break;
default: /* Unknown/unsupported conversion. */
return (NULL);
}
default: /* Unknown/unsupported conversion. */
return (NULL);
}
}
}
/*
* We need to evaluate the two digit year spec (%y)
* last as we can get a century spec (%C) at any time.
*/
if (cr->relyear != -1) {
if (cr->century == TM_YEAR_BASE) {
if (cr->relyear <= 68)
tm->tm_year = cr->relyear + 2000 - TM_YEAR_BASE;
else
tm->tm_year = cr->relyear + 1900 - TM_YEAR_BASE;
} else {
tm->tm_year = cr->relyear + cr->century - TM_YEAR_BASE;
}
}
/*
* We need to evaluate the two digit year spec (%y)
* last as we can get a century spec (%C) at any time.
*/
if (relyear != -1) {
if (century == TM_YEAR_BASE) {
if (relyear <= 68)
tm->tm_year = relyear + 2000 - TM_YEAR_BASE;
else
tm->tm_year = relyear + 1900 - TM_YEAR_BASE;
} else {
tm->tm_year = relyear + century - TM_YEAR_BASE;
}
fields |= FIELD_TM_YEAR;
}
return (unsigned char*)bp;
/* Compute some missing values when possible. */
if (fields & FIELD_TM_YEAR) {
const int year = tm->tm_year + TM_YEAR_BASE;
const int *mon_lens = mon_lengths[isleap(year)];
if (!(fields & FIELD_TM_YDAY) &&
(fields & FIELD_TM_MON) && (fields & FIELD_TM_MDAY)) {
tm->tm_yday = tm->tm_mday - 1;
for (i = 0; i < tm->tm_mon; i++)
tm->tm_yday += mon_lens[i];
fields |= FIELD_TM_YDAY;
}
if (fields & FIELD_TM_YDAY) {
int days = tm->tm_yday;
if (!(fields & FIELD_TM_WDAY)) {
tm->tm_wday = EPOCH_WDAY +
((year - EPOCH_YEAR) % DAYSPERWEEK) *
(DAYSPERNYEAR % DAYSPERWEEK) +
leaps_thru_end_of(year - 1) -
leaps_thru_end_of(EPOCH_YEAR - 1) +
tm->tm_yday;
tm->tm_wday %= DAYSPERWEEK;
if (tm->tm_wday < 0)
tm->tm_wday += DAYSPERWEEK;
}
if (!(fields & FIELD_TM_MON)) {
tm->tm_mon = 0;
while (tm->tm_mon < MONSPERYEAR && days >= mon_lens[tm->tm_mon])
days -= mon_lens[tm->tm_mon++];
}
if (!(fields & FIELD_TM_MDAY))
tm->tm_mday = days + 1;
}
}
return ((char *)bp);
}
static int
_conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
{
@ -607,6 +634,29 @@ _conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
return (1);
}
static int
_conv_num64(const unsigned char **buf, int64_t *dest, int64_t llim, int64_t ulim)
{
int result = 0;
int64_t rulim = ulim;
if (**buf < '0' || **buf > '9')
return (0);
/* we use rulim to break out of the loop when we run out of digits */
do {
result *= 10;
result += *(*buf)++ - '0';
rulim /= 10;
} while ((result * 10 <= ulim) && rulim && **buf >= '0' && **buf <= '9');
if (result < llim || result > ulim)
return (0);
*dest = result;
return (1);
}
static const u_char *
_find_string(const u_char *bp, int *tgt, const char * const *n1,
const char * const *n2, int c)
@ -629,6 +679,9 @@ _find_string(const u_char *bp, int *tgt, const char * const *n1,
return NULL;
}
char* strptime_l(const char* buf, const char* fmt, struct tm* tm, locale_t l) {
return strptime(buf, fmt, tm);
static int
leaps_thru_end_of(const int y)
{
return (y >= 0) ? (y / 4 - y / 100 + y / 400) :
-(leaps_thru_end_of(-(y + 1)) + 1);
}

View file

@ -0,0 +1,36 @@
/* $OpenBSD: _def_time.c,v 1.6 2016/05/23 00:05:15 guenther Exp $ */
/*
* Written by J.T. Conklin <jtc@netbsd.org>.
* Public domain.
*/
#include <locale.h>
#include "localedef.h"
const _TimeLocale _DefaultTimeLocale =
{
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat",
},
{
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"
},
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
},
{
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"
},
{
"AM", "PM"
},
"%a %b %e %H:%M:%S %Y",
"%m/%d/%y",
"%H:%M:%S",
"%I:%M:%S %p"
};
const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale;