From 37486f035f98e16b7c9b023c66c5fc42a6de1835 Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Sat, 9 Aug 1997 15:43:59 +0000 Subject: [PATCH] Import strptime(3) into libc. We've got permission by Kevin Ruddy to modify the original `no modifications' copyright message, and i've included his mail into the source file. The common localization functions between strptime(3) and strftime(3) have been broken out into timelocal.[ch]. --- include/time.h | 1 + lib/libc/stdtime/Makefile.inc | 5 +- lib/libc/stdtime/strftime.3 | 3 +- lib/libc/stdtime/strftime.c | 179 +----------- lib/libc/stdtime/strptime.3 | 85 ++++++ lib/libc/stdtime/strptime.c | 527 +++++++++++++++++----------------- lib/libc/stdtime/timelocal.c | 197 +++++++++++++ lib/libc/stdtime/timelocal.h | 51 ++++ 8 files changed, 600 insertions(+), 448 deletions(-) create mode 100644 lib/libc/stdtime/strptime.3 create mode 100644 lib/libc/stdtime/timelocal.c create mode 100644 lib/libc/stdtime/timelocal.h diff --git a/include/time.h b/include/time.h index dfc4e5976e86..29cae4cd975d 100644 --- a/include/time.h +++ b/include/time.h @@ -135,6 +135,7 @@ void tzset __P((void)); #endif /* not ANSI */ #if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +const char *strptime __P((const char *, const char *, struct tm *)); char *timezone __P((int, int)); void tzsetwall __P((void)); time_t timelocal __P((struct tm * const)); diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc index cdd4b8a3209c..246be284987c 100644 --- a/lib/libc/stdtime/Makefile.inc +++ b/lib/libc/stdtime/Makefile.inc @@ -1,14 +1,15 @@ # Makefile.inc,v 1.2 1994/09/13 21:26:01 wollman Exp -# $Id$ +# $Id: Makefile.inc,v 1.4 1997/05/03 03:50:04 jb Exp $ .PATH: ${.CURDIR}/../libc/stdtime -SRCS+= asctime.c localtime.c strftime.c difftime.c +SRCS+= asctime.c localtime.c strftime.c difftime.c timelocal.c strptime.c # Only build man pages with libc. .if ${LIB} == "c" MAN5+= stdtime/tzfile.5 MAN3+= stdtime/ctime.3 stdtime/strftime.3 stdtime/time2posix.3 +MAN3+= stdtime/strptime.3 MLINKS+=ctime.3 asctime.3 ctime.3 difftime.3 ctime.3 gmtime.3 \ ctime.3 localtime.3 ctime.3 mktime.3 diff --git a/lib/libc/stdtime/strftime.3 b/lib/libc/stdtime/strftime.3 index 27c826a0455e..7ce1b2475295 100644 --- a/lib/libc/stdtime/strftime.3 +++ b/lib/libc/stdtime/strftime.3 @@ -198,7 +198,8 @@ is replaced by .Xr date 1 , .Xr printf 1 , .Xr ctime 3 , -.Xr printf 3 +.Xr printf 3 , +.Xr strptime 3 .Sh STANDARDS The .Fn strftime diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c index b44ff683dbb2..126da8518167 100644 --- a/lib/libc/stdtime/strftime.c +++ b/lib/libc/stdtime/strftime.c @@ -17,7 +17,7 @@ #ifdef LIBC_RCS static const char rcsid[] = - "$Id$"; + "$Id: strftime.c,v 1.17 1997/02/22 15:03:19 peter Exp $"; #endif #ifndef lint @@ -40,72 +40,8 @@ static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; #include "tzfile.h" #include -#include #include -#include "setlocale.h" - -struct lc_time_T { - const char * mon[12]; - const char * month[12]; - const char * wday[7]; - const char * weekday[7]; - const char * X_fmt; - const char * x_fmt; - const char * c_fmt; - const char * am; - const char * pm; - const char * date_fmt; -}; - -static struct lc_time_T localebuf; -static int using_locale; - -#define Locale (using_locale ? &localebuf : &C_time_locale) - -static const struct lc_time_T C_time_locale = { - { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }, { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - }, { - "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat" - }, { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday" - }, - - /* X_fmt */ - "%H:%M:%S", - - /* - ** x_fmt - ** Since the C language standard calls for - ** "date, using locale's date format," anything goes. - ** Using just numbers (as here) makes Quakers happier; - ** it's also compatible with SVR4. - */ - "%m/%d/%y", - - /* - ** c_fmt (ctime-compatible) - ** Note that - ** "%a %b %d %H:%M:%S %Y" - ** is used by Solaris 2.3. - */ - "%a %b %e %X %Y", - - /* am */ - "AM", - - /* pm */ - "PM", - - /* date_fmt */ - "%a %b %e %X %Z %Y" -}; +#include "timelocal.h" static char * _add P((const char *, char *, const char *)); static char * _conv P((int, const char *, char *, const char *)); @@ -461,114 +397,3 @@ _add(str, pt, ptlim) ++pt; return pt; } - -int -__time_load_locale(const char *name) -{ - static char * locale_buf; - static char locale_buf_C[] = "C"; - - int fd; - char * lbuf; - char * p; - const char ** ap; - const char * plim; - char filename[PATH_MAX]; - struct stat st; - size_t namesize; - size_t bufsize; - int save_using_locale; - - save_using_locale = using_locale; - using_locale = 0; - - if (name == NULL) - goto no_locale; - - if (!strcmp(name, "C") || !strcmp(name, "POSIX")) - return 0; - - /* - ** If the locale name is the same as our cache, use the cache. - */ - lbuf = locale_buf; - if (lbuf != NULL && strcmp(name, lbuf) == 0) { - p = lbuf; - for (ap = (const char **) &localebuf; - ap < (const char **) (&localebuf + 1); - ++ap) - *ap = p += strlen(p) + 1; - using_locale = 1; - return 0; - } - /* - ** Slurp the locale file into the cache. - */ - namesize = strlen(name) + 1; - - if (!_PathLocale) - goto no_locale; - /* Range checking not needed, 'name' size is limited */ - strcpy(filename, _PathLocale); - strcat(filename, "/"); - strcat(filename, name); - strcat(filename, "/LC_TIME"); - fd = open(filename, O_RDONLY); - if (fd < 0) - goto no_locale; - if (fstat(fd, &st) != 0) - goto bad_locale; - if (st.st_size <= 0) - goto bad_locale; - bufsize = namesize + st.st_size; - locale_buf = NULL; - lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? - malloc(bufsize) : realloc(lbuf, bufsize); - if (lbuf == NULL) - goto bad_locale; - (void) strcpy(lbuf, name); - p = lbuf + namesize; - plim = p + st.st_size; - if (read(fd, p, (size_t) st.st_size) != st.st_size) - goto bad_lbuf; - if (close(fd) != 0) - goto bad_lbuf; - /* - ** Parse the locale file into localebuf. - */ - if (plim[-1] != '\n') - goto bad_lbuf; - for (ap = (const char **) &localebuf; - ap < (const char **) (&localebuf + 1); - ++ap) { - if (p == plim) - goto reset_locale; - *ap = p; - while (*p != '\n') - ++p; - *p++ = '\0'; - } - /* - ** Record the successful parse in the cache. - */ - locale_buf = lbuf; - - using_locale = 1; - return 0; - -reset_locale: - /* - * XXX - This may not be the correct thing to do in this case. - * setlocale() assumes that we left the old locale alone. - */ - locale_buf = locale_buf_C; - localebuf = C_time_locale; - save_using_locale = 0; -bad_lbuf: - free(lbuf); -bad_locale: - (void) close(fd); -no_locale: - using_locale = save_using_locale; - return -1; -} diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3 new file mode 100644 index 000000000000..bdda0e348cd1 --- /dev/null +++ b/lib/libc/stdtime/strptime.3 @@ -0,0 +1,85 @@ +.\" +.\" Copyright (c) 1997 Joerg Wunsch +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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. +.\" +.\" $Id$ +.\" " +.Dd May 8, 1997 +.Dt STRPTIME 3 +.Os +.Sh NAME +.Nm strptime +.Nd parse date and time string +.Sh SYNOPSIS +.Fd #include +.Ft const char * +.Fn strptime "const char *buf" "const char *format" "struct tm *timeptr" +.Sh DESCRIPTION +The +.Fn strptime +function parses the string in the buffer +.Fa buf +according to the string pointed to by +.Fa format , +and fills in the elements of the structure pointed to by +.Fa timeptr . +Thus, it can be considered the reverse operation of +.Xr strftime 3 . +.Pp +The +.Fa format +string consists of zero or more conversion specifications and +ordinary characters. +All ordinary characters are matched exactly with the buffer, where +white space in the format string will match any amount of white space +in the buffer. +All conversion specifications are identical to those described in +.Xr strftime 3 . +.Sh RETURN VALUES +Upon successful completion, +.Fn strptime +returns the pointer to the first character in +.Fa buf +that has not been required to satisfy the specified conversions in +.Fa format . +It returns +.Dv NULL +if one of the conversions failed. +.Sh SEE ALSO +.Xr date 1 , +.Xr scanf 3 , +.Xr strftime 3 +.Sh AUTHORS +The +.Fn strptime +function has been contributed by Powerdog Industries. +.Pp +This man page was written by +.ie t J\(:org Wunsch. +.el Joerg Wunsch. +.Sh HISTORY +The +.Fn strptime +function appeared in +.Fx 3.0 . diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c index ced9e3ab00e5..088084849458 100644 --- a/lib/libc/stdtime/strptime.c +++ b/lib/libc/stdtime/strptime.c @@ -1,7 +1,28 @@ +/* + * Powerdog Industries kindly requests feedback from anyone modifying + * this function: + * + * Date: Thu, 05 Jun 1997 23:17:17 -0400 + * From: Kevin Ruddy + * To: James FitzGibbon + * Subject: Re: Use of your strptime(3) code (fwd) + * + * The reason for the "no mod" clause was so that modifications would + * come back and we could integrate them and reissue so that a wider + * audience could use it (thereby spreading the wealth). This has + * made it possible to get strptime to work on many operating systems. + * I'm not sure why that's "plain unacceptable" to the FreeBSD team. + * + * Anyway, you can change it to "with or without modification" as + * you see fit. Enjoy. + * + * Kevin Ruddy + * Powerdog Industries, Inc. + */ /* * Copyright (c) 1994 Powerdog Industries. All rights reserved. * - * Redistribution and use in source and binary forms, without + * 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 @@ -30,329 +51,299 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef LIBC_RCS +static const char rcsid[] = + "$Id$"; +#endif + #ifndef lint +#ifndef NOID static char copyright[] = "@(#) Copyright (c) 1994 Powerdog Industries. All rights reserved."; -static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; +static char sccsid[] = "@(#)strptime.c 0.1 (Powerdog) 94/03/27"; +#endif /* !defined NOID */ #endif /* not lint */ #include #include -#include #include +#include "timelocal.h" -#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) +#define asizeof(a) (sizeof (a) / sizeof ((a)[0])) -/* #ifndef sun */ -struct dtconv { - char *abbrev_month_names[12]; - char *month_names[12]; - char *abbrev_weekday_names[7]; - char *weekday_names[7]; - char *time_format; - char *sdate_format; - char *dtime_format; - char *am_string; - char *pm_string; - char *ldate_format; -}; -/* #endif */ - -static struct dtconv En_US = { - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }, - { "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" }, - { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }, - { "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday" }, - "%H:%M:%S", - "%m/%d/%y", - "%a %b %e %T %Z %Y", - "AM", - "PM", - "%A, %B, %e, %Y" -}; - -#ifdef SUNOS4 -extern int strncasecmp(); -#endif - -char * -strptime(char *buf, char *fmt, struct tm *tm) +const char * +strptime(const char *buf, const char *fmt, struct tm *tm) { - char c, - *ptr; - int i, - len; + char c; + const char *ptr; + int i, + len; - ptr = fmt; - while (*ptr != 0) { - if (*buf == 0) - break; + ptr = fmt; + while (*ptr != 0) { + if (*buf == 0) + break; - c = *ptr++; + c = *ptr++; - if (c != '%') { - if (isspace(c)) - while (*buf != 0 && isspace(*buf)) - buf++; - else if (c != *buf++) - return 0; - continue; - } + if (c != '%') { + if (isspace(c)) + while (*buf != 0 && isspace(*buf)) + buf++; + else if (c != *buf++) + return 0; + continue; + } - c = *ptr++; - switch (c) { - case 0: - case '%': - if (*buf++ != '%') - return 0; - break; + c = *ptr++; + switch (c) { + case 0: + case '%': + if (*buf++ != '%') + return 0; + break; - case 'C': - buf = strptime(buf, En_US.ldate_format, tm); - if (buf == 0) - return 0; - break; + case 'C': + buf = strptime(buf, Locale->date_fmt, tm); + if (buf == 0) + return 0; + break; - case 'c': - buf = strptime(buf, "%x %X", tm); - if (buf == 0) - return 0; - break; + case 'c': + buf = strptime(buf, "%x %X", tm); + if (buf == 0) + return 0; + break; - case 'D': - buf = strptime(buf, "%m/%d/%y", tm); - if (buf == 0) - return 0; - break; + case 'D': + buf = strptime(buf, "%m/%d/%y", tm); + if (buf == 0) + return 0; + break; - case 'R': - buf = strptime(buf, "%H:%M", tm); - if (buf == 0) - return 0; - break; + case 'R': + buf = strptime(buf, "%H:%M", tm); + if (buf == 0) + return 0; + break; - case 'r': - buf = strptime(buf, "%I:%M:%S %p", tm); - if (buf == 0) - return 0; - break; + case 'r': + buf = strptime(buf, "%I:%M:%S %p", tm); + if (buf == 0) + return 0; + break; - case 'T': - buf = strptime(buf, "%H:%M:%S", tm); - if (buf == 0) - return 0; - break; + case 'T': + buf = strptime(buf, "%H:%M:%S", tm); + if (buf == 0) + return 0; + break; - case 'X': - buf = strptime(buf, En_US.time_format, tm); - if (buf == 0) - return 0; - break; + case 'X': + buf = strptime(buf, Locale->X_fmt, tm); + if (buf == 0) + return 0; + break; - case 'x': - buf = strptime(buf, En_US.sdate_format, tm); - if (buf == 0) - return 0; - break; + case 'x': + buf = strptime(buf, Locale->x_fmt, tm); + if (buf == 0) + return 0; + break; - case 'j': - if (!isdigit(*buf)) - return 0; + case 'j': + if (!isdigit(*buf)) + return 0; - for (i = 0; *buf != 0 && isdigit(*buf); buf++) { - i *= 10; - i += *buf - '0'; - } - if (i > 365) - return 0; + for (i = 0; *buf != 0 && isdigit(*buf); buf++) { + i *= 10; + i += *buf - '0'; + } + if (i > 365) + return 0; - tm->tm_yday = i; - break; + tm->tm_yday = i; + break; - case 'M': - case 'S': - if (*buf == 0 || isspace(*buf)) - break; + case 'M': + case 'S': + if (*buf == 0 || isspace(*buf)) + break; - if (!isdigit(*buf)) - return 0; + if (!isdigit(*buf)) + return 0; - for (i = 0; *buf != 0 && isdigit(*buf); buf++) { - i *= 10; - i += *buf - '0'; - } - if (i > 59) - return 0; + for (i = 0; *buf != 0 && isdigit(*buf); buf++) { + i *= 10; + i += *buf - '0'; + } + if (i > 59) + return 0; - if (c == 'M') - tm->tm_min = i; - else - tm->tm_sec = i; + if (c == 'M') + tm->tm_min = i; + else + tm->tm_sec = i; - if (*buf != 0 && isspace(*buf)) - while (*ptr != 0 && !isspace(*ptr)) - ptr++; - break; + if (*buf != 0 && isspace(*buf)) + while (*ptr != 0 && !isspace(*ptr)) + ptr++; + break; - case 'H': - case 'I': - case 'k': - case 'l': - if (!isdigit(*buf)) - return 0; + case 'H': + case 'I': + case 'k': + case 'l': + if (!isdigit(*buf)) + return 0; - for (i = 0; *buf != 0 && isdigit(*buf); buf++) { - i *= 10; - i += *buf - '0'; - } - if (c == 'H' || c == 'k') { - if (i > 23) - return 0; - } else if (i > 11) - return 0; + for (i = 0; *buf != 0 && isdigit(*buf); buf++) { + i *= 10; + i += *buf - '0'; + } + if (c == 'H' || c == 'k') { + if (i > 23) + return 0; + } else if (i > 11) + return 0; - tm->tm_hour = i; + tm->tm_hour = i; - if (*buf != 0 && isspace(*buf)) - while (*ptr != 0 && !isspace(*ptr)) - ptr++; - break; + if (*buf != 0 && isspace(*buf)) + while (*ptr != 0 && !isspace(*ptr)) + ptr++; + break; - case 'p': - len = strlen(En_US.am_string); - if (strncasecmp(buf, En_US.am_string, len) == 0) { - if (tm->tm_hour > 12) - return 0; - if (tm->tm_hour == 12) - tm->tm_hour = 0; - buf += len; - break; - } + case 'p': + len = strlen(Locale->am); + if (strncasecmp(buf, Locale->am, len) == 0) { + if (tm->tm_hour > 12) + return 0; + if (tm->tm_hour == 12) + tm->tm_hour = 0; + buf += len; + break; + } - len = strlen(En_US.pm_string); - if (strncasecmp(buf, En_US.pm_string, len) == 0) { - if (tm->tm_hour > 12) - return 0; - if (tm->tm_hour != 12) - tm->tm_hour += 12; - buf += len; - break; - } + len = strlen(Locale->pm); + if (strncasecmp(buf, Locale->pm, len) == 0) { + if (tm->tm_hour > 12) + return 0; + if (tm->tm_hour != 12) + tm->tm_hour += 12; + buf += len; + break; + } - return 0; + return 0; - case 'A': - case 'a': - for (i = 0; i < asizeof(En_US.weekday_names); i++) { - len = strlen(En_US.weekday_names[i]); - if (strncasecmp(buf, - En_US.weekday_names[i], - len) == 0) - break; + case 'A': + case 'a': + for (i = 0; i < asizeof(Locale->weekday); i++) { + len = strlen(Locale->weekday[i]); + if (strncasecmp(buf, + Locale->weekday[i], + len) == 0) + break; - len = strlen(En_US.abbrev_weekday_names[i]); - if (strncasecmp(buf, - En_US.abbrev_weekday_names[i], - len) == 0) - break; - } - if (i == asizeof(En_US.weekday_names)) - return 0; + len = strlen(Locale->wday[i]); + if (strncasecmp(buf, + Locale->wday[i], + len) == 0) + break; + } + if (i == asizeof(Locale->weekday)) + return 0; - tm->tm_wday = i; - buf += len; - break; + tm->tm_wday = i; + buf += len; + break; - case 'd': - case 'e': - if (!isdigit(*buf)) - return 0; + case 'd': + case 'e': + if (!isdigit(*buf)) + return 0; - for (i = 0; *buf != 0 && isdigit(*buf); buf++) { - i *= 10; - i += *buf - '0'; - } - if (i > 31) - return 0; + for (i = 0; *buf != 0 && isdigit(*buf); buf++) { + i *= 10; + i += *buf - '0'; + } + if (i > 31) + return 0; - tm->tm_mday = i; + tm->tm_mday = i; - if (*buf != 0 && isspace(*buf)) - while (*ptr != 0 && !isspace(*ptr)) - ptr++; - break; + if (*buf != 0 && isspace(*buf)) + while (*ptr != 0 && !isspace(*ptr)) + ptr++; + break; - case 'B': - case 'b': - case 'h': - for (i = 0; i < asizeof(En_US.month_names); i++) { - len = strlen(En_US.month_names[i]); - if (strncasecmp(buf, - En_US.month_names[i], - len) == 0) - break; + case 'B': + case 'b': + case 'h': + for (i = 0; i < asizeof(Locale->month); i++) { + len = strlen(Locale->month[i]); + if (strncasecmp(buf, + Locale->month[i], + len) == 0) + break; - len = strlen(En_US.abbrev_month_names[i]); - if (strncasecmp(buf, - En_US.abbrev_month_names[i], - len) == 0) - break; - } - if (i == asizeof(En_US.month_names)) - return 0; + len = strlen(Locale->mon[i]); + if (strncasecmp(buf, + Locale->mon[i], + len) == 0) + break; + } + if (i == asizeof(Locale->month)) + return 0; - tm->tm_mon = i; - buf += len; - break; + tm->tm_mon = i; + buf += len; + break; - case 'm': - if (!isdigit(*buf)) - return 0; + case 'm': + if (!isdigit(*buf)) + return 0; - for (i = 0; *buf != 0 && isdigit(*buf); buf++) { - i *= 10; - i += *buf - '0'; - } - if (i < 1 || i > 12) - return 0; + for (i = 0; *buf != 0 && isdigit(*buf); buf++) { + i *= 10; + i += *buf - '0'; + } + if (i < 1 || i > 12) + return 0; - tm->tm_mon = i - 1; + tm->tm_mon = i - 1; - if (*buf != 0 && isspace(*buf)) - while (*ptr != 0 && !isspace(*ptr)) - ptr++; - break; + if (*buf != 0 && isspace(*buf)) + while (*ptr != 0 && !isspace(*ptr)) + ptr++; + break; - case 'Y': - case 'y': - if (*buf == 0 || isspace(*buf)) - break; + case 'Y': + case 'y': + if (*buf == 0 || isspace(*buf)) + break; - if (!isdigit(*buf)) - return 0; + if (!isdigit(*buf)) + return 0; - for (i = 0; *buf != 0 && isdigit(*buf); buf++) { - i *= 10; - i += *buf - '0'; - } - if (c == 'Y') - i -= 1900; - if (i < 0) - return 0; + for (i = 0; *buf != 0 && isdigit(*buf); buf++) { + i *= 10; + i += *buf - '0'; + } + if (c == 'Y') + i -= 1900; + if (i < 0) + return 0; - tm->tm_year = i; + tm->tm_year = i; - if (*buf != 0 && isspace(*buf)) - while (*ptr != 0 && !isspace(*ptr)) - ptr++; - break; - } - } + if (*buf != 0 && isspace(*buf)) + while (*ptr != 0 && !isspace(*ptr)) + ptr++; + break; + } + } - return buf; + return buf; } - diff --git a/lib/libc/stdtime/timelocal.c b/lib/libc/stdtime/timelocal.c new file mode 100644 index 000000000000..ef40035c09f4 --- /dev/null +++ b/lib/libc/stdtime/timelocal.c @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 1997 FreeBSD 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "setlocale.h" +#include "timelocal.h" + +struct lc_time_T _time_localebuf; +int _time_using_locale; + +const struct lc_time_T _C_time_locale = { + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" + }, { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }, + + /* X_fmt */ + "%H:%M:%S", + + /* + ** x_fmt + ** Since the C language standard calls for + ** "date, using locale's date format," anything goes. + ** Using just numbers (as here) makes Quakers happier; + ** it's also compatible with SVR4. + */ + "%m/%d/%y", + + /* + ** c_fmt (ctime-compatible) + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%a %b %e %X %Y", + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %X %Z %Y" +}; + + +int +__time_load_locale(const char *name) +{ + static char * locale_buf; + static char locale_buf_C[] = "C"; + + int fd; + char * lbuf; + char * p; + const char ** ap; + const char * plim; + char filename[PATH_MAX]; + struct stat st; + size_t namesize; + size_t bufsize; + int save_using_locale; + + save_using_locale = _time_using_locale; + _time_using_locale = 0; + + if (name == NULL) + goto no_locale; + + if (!strcmp(name, "C") || !strcmp(name, "POSIX")) + return 0; + + /* + ** If the locale name is the same as our cache, use the cache. + */ + lbuf = locale_buf; + if (lbuf != NULL && strcmp(name, lbuf) == 0) { + p = lbuf; + for (ap = (const char **) &_time_localebuf; + ap < (const char **) (&_time_localebuf + 1); + ++ap) + *ap = p += strlen(p) + 1; + _time_using_locale = 1; + return 0; + } + /* + ** Slurp the locale file into the cache. + */ + namesize = strlen(name) + 1; + + if (!_PathLocale) + goto no_locale; + /* Range checking not needed, 'name' size is limited */ + strcpy(filename, _PathLocale); + strcat(filename, "/"); + strcat(filename, name); + strcat(filename, "/LC_TIME"); + fd = open(filename, O_RDONLY); + if (fd < 0) + goto no_locale; + if (fstat(fd, &st) != 0) + goto bad_locale; + if (st.st_size <= 0) + goto bad_locale; + bufsize = namesize + st.st_size; + locale_buf = NULL; + lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? + malloc(bufsize) : realloc(lbuf, bufsize); + if (lbuf == NULL) + goto bad_locale; + (void) strcpy(lbuf, name); + p = lbuf + namesize; + plim = p + st.st_size; + if (read(fd, p, (size_t) st.st_size) != st.st_size) + goto bad_lbuf; + if (close(fd) != 0) + goto bad_lbuf; + /* + ** Parse the locale file into localebuf. + */ + if (plim[-1] != '\n') + goto bad_lbuf; + for (ap = (const char **) &_time_localebuf; + ap < (const char **) (&_time_localebuf + 1); + ++ap) { + if (p == plim) + goto reset_locale; + *ap = p; + while (*p != '\n') + ++p; + *p++ = '\0'; + } + /* + ** Record the successful parse in the cache. + */ + locale_buf = lbuf; + + _time_using_locale = 1; + return 0; + +reset_locale: + /* + * XXX - This may not be the correct thing to do in this case. + * setlocale() assumes that we left the old locale alone. + */ + locale_buf = locale_buf_C; + _time_localebuf = _C_time_locale; + save_using_locale = 0; +bad_lbuf: + free(lbuf); +bad_locale: + (void) close(fd); +no_locale: + _time_using_locale = save_using_locale; + return -1; +} diff --git a/lib/libc/stdtime/timelocal.h b/lib/libc/stdtime/timelocal.h new file mode 100644 index 000000000000..8593aee3ec3e --- /dev/null +++ b/lib/libc/stdtime/timelocal.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 1997 FreeBSD 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id$ + */ + +/* + * Private header file for the strftime and strptime localization + * stuff. + */ +struct lc_time_T { + const char * mon[12]; + const char * month[12]; + const char * wday[7]; + const char * weekday[7]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; +}; + +extern struct lc_time_T _time_localebuf; +extern int _time_using_locale; +extern const struct lc_time_T _C_time_locale; + +#define Locale (_time_using_locale ? &_time_localebuf : &_C_time_locale) +