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].
This commit is contained in:
Joerg Wunsch 1997-08-09 15:43:59 +00:00
parent d76419833c
commit 37486f035f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=28021
8 changed files with 600 additions and 448 deletions

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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 <fcntl.h>
#include <locale.h>
#include <sys/stat.h>
#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;
}

View File

@ -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 <time.h>
.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 .

View File

@ -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 <kevin.ruddy@powerdog.com>
* To: James FitzGibbon <james@nexis.net>
* 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 <time.h>
#include <ctype.h>
#include <locale.h>
#include <string.h>
#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;
}

View File

@ -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 <sys/types.h>
#include <sys/stat.h>
#include <sys/syslimits.h>
#include <fcntl.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@ -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)