libc/lib_strptime:change code format & add notes

Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
anjiahao 2022-04-11 15:44:59 +08:00 committed by Xiang Xiao
parent 96ea9b71ed
commit e6f77aeb9a
3 changed files with 446 additions and 232 deletions

24
LICENSE
View File

@ -5181,6 +5181,29 @@ 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.
libs/libc/time/lib_strptime.c
=======================================
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.
libs/libc/unistd/lib_gethostname.c
libs/libc/unistd/lib_sethostname.c
include/sys/uio.h
@ -5822,3 +5845,4 @@ 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.

View File

@ -201,7 +201,7 @@ FAR struct tm *localtime_r(FAR const time_t *timep, FAR struct tm *result);
size_t strftime(FAR char *s, size_t max, FAR const char *format,
FAR const struct tm *tm) strftimelike(3);
FAR char *strptime(FAR const char *s, FAR const char *format,
FAR struct tm *tm);
FAR struct tm *tm);
FAR char *asctime(FAR const struct tm *tp);
FAR char *asctime_r(FAR const struct tm *tp, FAR char *buf);

View File

@ -1,7 +1,9 @@
/* $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 $ */
/*-
/****************************************************************************
* libs/libc/time/lib_strptime.c
*
* $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 $
*
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
@ -23,412 +25,600 @@
* 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.
*/
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <ctype.h>
#include <locale.h>
#include <strings.h>
#include <time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define TM_YEAR_BASE 1900
#define _ctloc(x) (g_defaulttimelocale.x)
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"
};
#define _ctloc(x) (_DefaultTimeLocale.x)
/*
* We do not implement alternate representations. However, we always
/* 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 _ALT_E 0x01
#define _ALT_O 0x02
#define _LEGAL_ALT(x) { if (alt_format & ~(x)) return (0); }
/****************************************************************************
* Private Data
****************************************************************************/
struct century_relyear {
int century;
int relyear;
};
static int _conv_num(const unsigned char **, int *, int, int);
static unsigned char *_strptime(const unsigned char *, const char *, struct tm *,
struct century_relyear *);
char *
strptime(const char *buf, const char *fmt, struct tm *tm)
static const struct
{
struct century_relyear cr;
cr.century = TM_YEAR_BASE;
cr.relyear = -1;
return (char*)(_strptime((const unsigned char*)buf, fmt, tm, &cr));
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;
} g_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"
};
struct century_relyear
{
int century;
int relyear;
};
/****************************************************************************
* Private Functions
****************************************************************************/
static int _conv_num(FAR const unsigned char **buf, FAR int *dest,
int llim, int ulim)
{
int result = 0;
int rulim = ulim;
while (isspace(**buf))
{
(*buf)++;
}
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 unsigned char *
_strptime(const unsigned char *buf, const char *fmt, struct tm *tm, struct century_relyear *cr)
static FAR const unsigned char *_strptime(FAR const unsigned char *buf,
FAR const char *fmt,
FAR struct tm *tm,
FAR struct century_relyear *cr)
{
unsigned char c;
const unsigned char *bp;
size_t len = 0;
int alt_format, i;
unsigned char c;
FAR const unsigned char *bp;
size_t len = 0;
int alt_format;
int i;
bp = (unsigned char *)buf;
while ((c = *fmt) != '\0') {
/* Clear `alternate' modifier prior to new conversion. */
alt_format = 0;
bp = buf;
while ((c = *fmt) != '\0')
{
/* Clear `alternate' modifier prior to new conversion. */
/* Eat up white-space. */
if (isspace(c)) {
while (isspace(*bp))
bp++;
alt_format = 0;
fmt++;
continue;
/* Eat up white-space. */
if (isspace(c))
{
while (isspace(*bp))
bp++;
fmt++;
continue;
}
if ((c = *fmt++) != '%')
goto literal;
if ((c = *fmt++) != '%')
{
goto literal;
}
again: switch (c = *fmt++) {
case '%': /* "%%" is converted to "%". */
literal:
if (c != *bp++)
return (NULL);
again:
switch (c = *fmt++)
{
case '%': /* "%%" is converted to "%". */
literal:
if (c != *bp++)
{
return NULL;
}
break;
break;
/*
* "Alternative" modifiers. Just set the appropriate flag
* and start over again.
*/
case 'E': /* "%E?" alternative conversion modifier. */
/* "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. */
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. */
/* "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);
{
return NULL;
}
break;
case 'D': /* The date as "%m/%d/%y". */
case 'D': /* The date as "%m/%d/%y". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%m/%d/%y", tm, cr)))
return (NULL);
{
return NULL;
}
break;
case 'R': /* The time as "%H:%M". */
case 'R': /* The time as "%H:%M". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M", tm, cr)))
return (NULL);
{
return NULL;
}
break;
case 'r': /* The time as "%I:%M:%S %p". */
case 'r': /* The time as "%I:%M:%S %p". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%I:%M:%S %p", tm, cr)))
return (NULL);
{
return NULL;
}
break;
case 'T': /* The time as "%H:%M:%S". */
case 'T': /* The time as "%H:%M:%S". */
_LEGAL_ALT(0);
if (!(bp = _strptime(bp, "%H:%M:%S", tm, cr)))
return (NULL);
{
return NULL;
}
break;
case 'X': /* The time, using the locale's format. */
case 'X': /* The time, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(t_fmt), tm, cr)))
return (NULL);
{
return NULL;
}
break;
case 'x': /* The date, using the locale's format. */
case 'x': /* The date, using the locale's format. */
_LEGAL_ALT(_ALT_E);
if (!(bp = _strptime(bp, _ctloc(d_fmt), tm, cr)))
return (NULL);
{
return NULL;
}
break;
/*
* "Elementary" conversion rules.
*/
case 'A': /* The day of week, using the locale's form. */
case 'a':
/* "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++) {
for (i = 0; i < 7; i++)
{
/* Full name. */
len = strlen(_ctloc(day[i]));
if (strncasecmp(_ctloc(day[i]), (const char*)bp, len) == 0)
break;
if (strncasecmp(_ctloc(day[i]),
(const char *)bp, len) == 0)
break;
/* Abbreviated name. */
len = strlen(_ctloc(abday[i]));
if (strncasecmp(_ctloc(abday[i]), (const char*)bp, len) == 0)
break;
}
if (strncasecmp(_ctloc(abday[i]),
(const char *)bp, len) == 0)
break;
}
/* Nothing matched. */
if (i == 7)
return (NULL);
{
return NULL;
}
tm->tm_wday = i;
bp += len;
break;
case 'B': /* The month, using the locale's form. */
case 'b':
case 'h':
case 'B': /* The month, using the locale's form. */
case 'b':
case 'h':
_LEGAL_ALT(0);
for (i = 0; i < 12; i++) {
for (i = 0; i < 12; i++)
{
/* Full name. */
len = strlen(_ctloc(mon[i]));
if (strncasecmp(_ctloc(mon[i]), (const char*)bp, len) == 0)
if (strncasecmp(_ctloc(mon[i]),
(const char *)bp, len) == 0)
{
break;
}
/* Abbreviated name. */
len = strlen(_ctloc(abmon[i]));
if (strncasecmp(_ctloc(abmon[i]), (const char*)bp, len) == 0)
if (strncasecmp(_ctloc(abmon[i]),
(const char *)bp, len) == 0)
{
break;
}
}
}
/* Nothing matched. */
if (i == 12)
return (NULL);
{
return NULL;
}
tm->tm_mon = i;
bp += len;
break;
case 'C': /* The century number. */
case 'C': /* The century number. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 99)))
{
return (NULL);
}
cr->century = i * 100;
break;
case 'd': /* The day of month. */
case 'e':
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 'k': /* The hour (24-hour clock representation). */
case 'k': /* The hour (24-hour clock representation). */
_LEGAL_ALT(0);
/* FALLTHROUGH */
case 'H':
case 'H':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_hour, 0, 23)))
return (NULL);
{
return NULL;
}
break;
case 'l': /* The hour (12-hour clock representation). */
case 'l': /* The hour (12-hour clock representation). */
_LEGAL_ALT(0);
/* FALLTHROUGH */
case 'I':
case 'I':
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_hour, 1, 12)))
{
return (NULL);
}
break;
case 'j': /* The day of year. */
case 'j': /* The day of year. */
_LEGAL_ALT(0);
if (!(_conv_num(&bp, &tm->tm_yday, 1, 366)))
return (NULL);
{
return NULL;
}
tm->tm_yday--;
break;
case 'M': /* The minute. */
case 'M': /* The minute. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_min, 0, 59)))
return (NULL);
{
return NULL;
}
break;
case 'm': /* The month. */
case 'm': /* The month. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_mon, 1, 12)))
return (NULL);
{
return NULL;
}
tm->tm_mon--;
break;
case 'p': /* The locale's equivalent of AM/PM. */
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);
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;
}
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);
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;
}
}
/* Nothing matched. */
return (NULL);
case 'S': /* The seconds. */
return NULL;
case 'S': /* The seconds. */
_LEGAL_ALT(_ALT_O);
if (!(_conv_num(&bp, &tm->tm_sec, 0, 61)))
return (NULL);
{
return NULL;
}
break;
case 'U': /* The week of year, beginning on sunday. */
case 'W': /* The week of year, beginning on monday. */
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;
/* 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.
*/
case 'w': /* The day of week, beginning on sunday. */
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);
{
return NULL;
}
break;
case 'Y': /* The year. */
case 'Y': /* The year. */
_LEGAL_ALT(_ALT_E);
if (!(_conv_num(&bp, &i, 0, 9999)))
return (NULL);
{
return NULL;
}
cr->relyear = -1;
tm->tm_year = i - TM_YEAR_BASE;
break;
case 'y': /* The year within the century (2 digits). */
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);
{
return NULL;
}
break;
/*
* Miscellaneous conversions.
*/
case 'n': /* Any kind of white-space. */
case 't':
/* 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);
}
}
/*
* 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;
default: /* Unknown/unsupported conversion. */
return NULL;
}
}
return (unsigned char*)bp;
/* 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;
}
}
return bp;
}
/****************************************************************************
* Public Functions
****************************************************************************/
static int
_conv_num(const unsigned char **buf, int *dest, int llim, int ulim)
/****************************************************************************
* Name: strptime
*
* Description:
* Convert a string to a time type according to a specific time format
* The strptime() function processes the input string from left to
* right. Each of the three possible input elements (whitespace,
* literal, or format) are handled one after the other. If the
* input cannot be matched to the format string, the function stops.
* The remainder of the format and input strings are not processed.
* The supported input field descriptors are listed below. In case
* a text string (such as the name of a day of the week or a month
* name) is to be matched, the comparison is case insensitive. In
* case a number is to be matched, leading zeros are permitted but
* not required.
* %a The abbreviated weekday name according to the current locale.
* %A The full weekday name according to the current locale.
* %b The abbreviated month name according to the current locale.
* %B The full month name according to the current locale.
* %C The century number (year/100) as a 2-digit integer. (SU)
* %d The day of the month as a decimal number (range 01 to 31).
* %e Like %d, the day of the month as a decimal number, but a leading
* zero is replaced by a space.
* %h Equivalent to %b. (SU)
* %H The hour as a decimal number using a 24-hour clock
* (range 00 to 23).
* %I The hour as a decimal number using a 12-hour clock
* (range 01 to 12).
* %j The day of the year as a decimal number (range 001 to 366).
* %k The hour (24-hour clock) as a decimal number (range 0 to 23);
* single digits are preceded by a blank. (See also %H.) (TZ)
* %l The hour (12-hour clock) as a decimal number (range 1 to 12);
* single digits are preceded by a blank. (See also %I.) (TZ)
* %m The month as a decimal number (range 01 to 12).
* %M The minute as a decimal number (range 00 to 59).
* %n A newline character. (SU)
* %p Either "AM" or "PM" according to the given time value, or the
* corresponding strings for the current locale. Noon is treated
* as "PM" and midnight as "AM".
* %P Like %p but in lowercase: "am" or "pm" or a corresponding string
* for the current locale. (GNU)
* %S The second as a decimal number (range 00 to 60). (The range is
* up to 60 to allow for occasional leap seconds.)
* %t A tab character. (SU)
* %y The year as a decimal number without a century (range 00 to 99).
* %Y The year as a decimal number including the century.
* %% A literal '%' character.
*
* Returned Value:
* The return value of the function is a pointer to the first
* character not processed in this function call. In case the input
* string contains more characters than required by the format
* string, the return value points right after the last consumed
* input character. In case the whole input string is consumed, the
* return value points to the null byte at the end of the string.
* If strptime() fails to match all of the format string and
* therefore an error occurred, the function returns NULL.
*
****************************************************************************/
FAR char *strptime(FAR const char *buf, FAR const char *fmt,
FAR struct tm *tm)
{
int result = 0;
int rulim = ulim;
while (isspace(**buf))
(*buf)++;
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);
struct century_relyear cr;
cr.century = TM_YEAR_BASE;
cr.relyear = -1;
return (FAR char *)(_strptime((FAR const unsigned char *)buf,
fmt, tm, &cr));
}