libroot: Replace strftime/strptime/wcsftime implementations with musl's.

Now that we have locale_t, we can use the musl versions of these functions.
This also fixes a licensing issue: the strptime implementation had an
advertising clause (although in upstream *BSD it was removed, so we
likely could have managed to remove it anyway.)
This commit is contained in:
Augustin Cavalier
2022-08-18 15:31:38 -04:00
parent 8ba3797e85
commit a028a54e52
19 changed files with 650 additions and 1275 deletions
-9
View File
@@ -33,10 +33,6 @@
#include <sys/cdefs.h>
/*
* Private header file for the strftime and strptime localization
* stuff.
*/
struct lc_time_t {
const char* mon[12];
const char* month[12];
@@ -53,10 +49,5 @@ struct lc_time_t {
const char* ampm_fmt;
};
__BEGIN_DECLS
const struct lc_time_t* __get_current_time_locale(void);
const struct lc_time_t* __get_time_locale(locale_t);
__END_DECLS
#endif /* !_TIMELOCAL_H_ */
@@ -260,3 +260,13 @@ uselocale(locale_t newLoc)
return oldLoc;
}
extern "C" locale_t
__current_locale_t()
{
locale_t locale = (locale_t)GetCurrentLocaleInfo();
if (locale == NULL)
locale = LC_GLOBAL_LOCALE;
return locale;
}
+2
View File
@@ -12,6 +12,7 @@ for architectureObject in [ MultiArchSubDirSetup ] {
<$(architecture)>posix_musl_regex.o
<$(architecture)>posix_musl_search.o
<$(architecture)>posix_musl_string.o
<$(architecture)>posix_musl_time.o
;
}
}
@@ -25,3 +26,4 @@ HaikuSubInclude misc ;
HaikuSubInclude regex ;
HaikuSubInclude search ;
HaikuSubInclude string ;
HaikuSubInclude time ;
@@ -0,0 +1,15 @@
/*
* Copyright 2022, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _LOCALE_IMPL_H
#define _LOCALE_IMPL_H
#include <locale.h>
#define __nl_langinfo_l nl_langinfo_l
locale_t __current_locale_t();
#define CURRENT_LOCALE (__current_locale_t())
#endif
@@ -0,0 +1,18 @@
SubDir HAIKU_TOP src system libroot posix musl time ;
SubDirSysHdrs [ FDirName $(SUBDIR) .. include ] ;
UseHeaders [ FDirName $(SUBDIR) .. internal ] ;
local architectureObject ;
for architectureObject in [ MultiArchSubDirSetup ] {
on $(architectureObject) {
local architecture = $(TARGET_PACKAGING_ARCH) ;
MergeObject <$(architecture)>posix_musl_time.o :
difftime.c
strftime.c
strptime.c
wcsftime.c
;
}
}
@@ -0,0 +1,6 @@
#include <time.h>
double difftime(time_t t1, time_t t0)
{
return t1-t0;
}
@@ -0,0 +1,285 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <langinfo.h>
#include <locale.h>
#include <time.h>
#include <limits.h>
#include "locale_impl.h"
#include "time_impl.h"
static int is_leap(int y)
{
/* Avoid overflow */
if (y>INT_MAX-1900) y -= 2000;
y += 1900;
return !(y%4) && ((y%100) || !(y%400));
}
static int week_num(const struct tm *tm)
{
int val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7;
/* If 1 Jan is just 1-3 days past Monday,
* the previous week is also in this year. */
if ((tm->tm_wday + 371U - tm->tm_yday - 2) % 7 <= 2)
val++;
if (!val) {
val = 52;
/* If 31 December of prev year a Thursday,
* or Friday of a leap year, then the
* prev year has 53 weeks. */
{
int dec31 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 7;
if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year%400-1)))
val++;
}
} else if (val == 53) {
/* If 1 January is not a Thursday, and not
* a Wednesday of a leap year, then this
* year has only 52 weeks. */
int jan1 = (tm->tm_wday + 371U - tm->tm_yday) % 7;
if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year)))
val = 1;
}
return val;
}
const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc, int pad)
{
nl_item item;
long long val;
const char *fmt = "-";
int width = 2, def_pad = '0';
switch (f) {
case 'a':
if (tm->tm_wday > 6U) goto string;
item = ABDAY_1 + tm->tm_wday;
goto nl_strcat;
case 'A':
if (tm->tm_wday > 6U) goto string;
item = DAY_1 + tm->tm_wday;
goto nl_strcat;
case 'h':
case 'b':
if (tm->tm_mon > 11U) goto string;
item = ABMON_1 + tm->tm_mon;
goto nl_strcat;
case 'B':
if (tm->tm_mon > 11U) goto string;
item = MON_1 + tm->tm_mon;
goto nl_strcat;
case 'c':
item = D_T_FMT;
goto nl_strftime;
case 'C':
val = (1900LL+tm->tm_year) / 100;
goto number;
case 'e':
def_pad = '_';
case 'd':
val = tm->tm_mday;
goto number;
case 'D':
fmt = "%m/%d/%y";
goto recu_strftime;
case 'F':
fmt = "%Y-%m-%d";
goto recu_strftime;
case 'g':
case 'G':
val = tm->tm_year + 1900LL;
if (tm->tm_yday < 3 && week_num(tm) != 1) val--;
else if (tm->tm_yday > 360 && week_num(tm) == 1) val++;
if (f=='g') val %= 100;
else width = 4;
goto number;
case 'H':
val = tm->tm_hour;
goto number;
case 'I':
val = tm->tm_hour;
if (!val) val = 12;
else if (val > 12) val -= 12;
goto number;
case 'j':
val = tm->tm_yday+1;
width = 3;
goto number;
case 'm':
val = tm->tm_mon+1;
goto number;
case 'M':
val = tm->tm_min;
goto number;
case 'n':
*l = 1;
return "\n";
case 'p':
item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
goto nl_strcat;
case 'r':
item = T_FMT_AMPM;
goto nl_strftime;
case 'R':
fmt = "%H:%M";
goto recu_strftime;
case 's':
val = __tm_to_secs(tm) - tm->__tm_gmtoff;
width = 1;
goto number;
case 'S':
val = tm->tm_sec;
goto number;
case 't':
*l = 1;
return "\t";
case 'T':
fmt = "%H:%M:%S";
goto recu_strftime;
case 'u':
val = tm->tm_wday ? tm->tm_wday : 7;
width = 1;
goto number;
case 'U':
val = (tm->tm_yday + 7U - tm->tm_wday) / 7;
goto number;
case 'W':
val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7;
goto number;
case 'V':
val = week_num(tm);
goto number;
case 'w':
val = tm->tm_wday;
width = 1;
goto number;
case 'x':
item = D_FMT;
goto nl_strftime;
case 'X':
item = T_FMT;
goto nl_strftime;
case 'y':
val = (tm->tm_year + 1900LL) % 100;
if (val < 0) val = -val;
goto number;
case 'Y':
val = tm->tm_year + 1900LL;
if (val >= 10000) {
*l = snprintf(*s, sizeof *s, "+%lld", val);
return *s;
}
width = 4;
goto number;
case 'z':
if (tm->tm_isdst < 0) {
*l = 0;
return "";
}
*l = snprintf(*s, sizeof *s, "%+.4ld",
tm->__tm_gmtoff/3600*100 + tm->__tm_gmtoff%3600/60);
return *s;
case 'Z':
if (tm->tm_isdst < 0) {
*l = 0;
return "";
}
fmt = __tm_to_tzname(tm);
goto string;
case '%':
*l = 1;
return "%";
default:
return 0;
}
number:
switch (pad ? pad : def_pad) {
case '-': *l = snprintf(*s, sizeof *s, "%lld", val); break;
case '_': *l = snprintf(*s, sizeof *s, "%*lld", width, val); break;
case '0':
default: *l = snprintf(*s, sizeof *s, "%0*lld", width, val); break;
}
return *s;
nl_strcat:
fmt = __nl_langinfo_l(item, loc);
string:
*l = strlen(fmt);
return fmt;
nl_strftime:
fmt = __nl_langinfo_l(item, loc);
recu_strftime:
*l = __strftime_l(*s, sizeof *s, fmt, tm, loc);
if (!*l) return 0;
return *s;
}
size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
{
size_t l, k;
char buf[100];
char *p;
const char *t;
int pad, plus;
unsigned long width;
for (l=0; l<n; f++) {
if (!*f) {
s[l] = 0;
return l;
}
if (*f != '%') {
s[l++] = *f;
continue;
}
f++;
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
width = strtoul(f, &p, 10);
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
width = 0;
}
f = p;
if (*f == 'E' || *f == 'O') f++;
t = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
if (!t) break;
if (width) {
/* Trim off any sign and leading zeros, then
* count remaining digits to determine behavior
* for the + flag. */
if (*t=='+' || *t=='-') t++, k--;
for (; *t=='0' && t[1]-'0'<10U; t++, k--);
if (width < k) width = k;
{
size_t d;
for (d=0; t[d]-'0'<10U; d++);
if (tm->tm_year < -1900) {
s[l++] = '-';
width--;
} else if (plus && d+(width-k) >= (*p=='C'?3:5)) {
s[l++] = '+';
width--;
}
for (; width > k && l < n; width--)
s[l++] = '0';
}
}
if (k > n-l) k = n-l;
memcpy(s+l, t, k);
l += k;
}
if (n) {
if (l==n) l=n-1;
s[l] = 0;
}
return 0;
}
size_t strftime(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm)
{
return __strftime_l(s, n, f, tm, CURRENT_LOCALE);
}
weak_alias(__strftime_l, strftime_l);
@@ -0,0 +1,207 @@
#include <stdlib.h>
#include <langinfo.h>
#include <time.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
#include <strings.h>
#include "time_impl.h"
char *strptime(const char *restrict s, const char *restrict f, struct tm *restrict tm)
{
int i, w, neg, adj, min, range, *dest, dummy;
const char *ex;
size_t len;
int want_century = 0, century = 0, relyear = 0;
while (*f) {
if (*f != '%') {
if (isspace(*f)) for (; *s && isspace(*s); s++);
else if (*s != *f) return 0;
else s++;
f++;
continue;
}
f++;
if (*f == '+') f++;
if (isdigit(*f)) {
char *new_f;
w=strtoul(f, &new_f, 10);
f = new_f;
} else {
w=-1;
}
adj=0;
switch (*f++) {
case 'a': case 'A':
dest = &tm->tm_wday;
min = ABDAY_1;
range = 7;
goto symbolic_range;
case 'b': case 'B': case 'h':
dest = &tm->tm_mon;
min = ABMON_1;
range = 12;
goto symbolic_range;
case 'c':
s = strptime(s, nl_langinfo(D_T_FMT), tm);
if (!s) return 0;
break;
case 'C':
dest = &century;
if (w<0) w=2;
want_century |= 2;
goto numeric_digits;
case 'd': case 'e':
dest = &tm->tm_mday;
min = 1;
range = 31;
goto numeric_range;
case 'D':
s = strptime(s, "%m/%d/%y", tm);
if (!s) return 0;
break;
case 'H':
dest = &tm->tm_hour;
min = 0;
range = 24;
goto numeric_range;
case 'I':
dest = &tm->tm_hour;
min = 1;
range = 12;
goto numeric_range;
case 'j':
dest = &tm->tm_yday;
min = 1;
range = 366;
adj = 1;
goto numeric_range;
case 'm':
dest = &tm->tm_mon;
min = 1;
range = 12;
adj = 1;
goto numeric_range;
case 'M':
dest = &tm->tm_min;
min = 0;
range = 60;
goto numeric_range;
case 'n': case 't':
for (; *s && isspace(*s); s++);
break;
case 'p':
ex = nl_langinfo(AM_STR);
len = strlen(ex);
if (!strncasecmp(s, ex, len)) {
tm->tm_hour %= 12;
s += len;
break;
}
ex = nl_langinfo(PM_STR);
len = strlen(ex);
if (!strncasecmp(s, ex, len)) {
tm->tm_hour %= 12;
tm->tm_hour += 12;
s += len;
break;
}
return 0;
case 'r':
s = strptime(s, nl_langinfo(T_FMT_AMPM), tm);
if (!s) return 0;
break;
case 'R':
s = strptime(s, "%H:%M", tm);
if (!s) return 0;
break;
case 'S':
dest = &tm->tm_sec;
min = 0;
range = 61;
goto numeric_range;
case 'T':
s = strptime(s, "%H:%M:%S", tm);
if (!s) return 0;
break;
case 'U':
case 'W':
/* Throw away result, for now. (FIXME?) */
dest = &dummy;
min = 0;
range = 54;
goto numeric_range;
case 'w':
dest = &tm->tm_wday;
min = 0;
range = 7;
goto numeric_range;
case 'x':
s = strptime(s, nl_langinfo(D_FMT), tm);
if (!s) return 0;
break;
case 'X':
s = strptime(s, nl_langinfo(T_FMT), tm);
if (!s) return 0;
break;
case 'y':
dest = &relyear;
w = 2;
want_century |= 1;
goto numeric_digits;
case 'Y':
dest = &tm->tm_year;
if (w<0) w=4;
adj = 1900;
want_century = 0;
goto numeric_digits;
case '%':
if (*s++ != '%') return 0;
break;
default:
return 0;
numeric_range:
if (!isdigit(*s)) return 0;
*dest = 0;
for (i=1; i<=min+range && isdigit(*s); i*=10)
*dest = *dest * 10 + *s++ - '0';
if (*dest - min >= (unsigned)range) return 0;
*dest -= adj;
switch((char *)dest - (char *)tm) {
case offsetof(struct tm, tm_yday):
;
}
goto update;
numeric_digits:
neg = 0;
if (*s == '+') s++;
else if (*s == '-') neg=1, s++;
if (!isdigit(*s)) return 0;
for (*dest=i=0; i<w && isdigit(*s); i++)
*dest = *dest * 10 + *s++ - '0';
if (neg) *dest = -*dest;
*dest -= adj;
goto update;
symbolic_range:
for (i=2*range-1; i>=0; i--) {
ex = nl_langinfo(min+i);
len = strlen(ex);
if (strncasecmp(s, ex, len)) continue;
s += len;
*dest = i % range;
break;
}
if (i<0) return 0;
goto update;
update:
//FIXME
;
}
}
if (want_century) {
tm->tm_year = relyear;
if (want_century & 2) tm->tm_year += century * 100 - 1900;
else if (tm->tm_year <= 68) tm->tm_year += 100;
}
return (char *)s;
}
@@ -0,0 +1,11 @@
#include <time.h>
#include <features.h>
#if __GNUC__ < 4
#define restrict
#endif
hidden size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc);
hidden const char *__strftime_fmt_1(char (*)[100], size_t *, int, const struct tm *, locale_t, int);
#include "time_impl_haiku.h"
@@ -0,0 +1,23 @@
time_t timegm(struct tm *tm);
static inline time_t
__tm_to_secs(const struct tm *tm)
{
struct tm tmp = *tm;
return timegm(&tmp);
}
static inline const char*
__tm_to_tzname(const struct tm *tm)
{
const void *p = tm->tm_zone;
if (p)
return p;
if (tm->tm_isdst >= 0)
return tzname[tm->tm_isdst != 0];
return "";
}
#define __tm_gmtoff tm_gmtoff
#define __tm_zone tm_zone
@@ -0,0 +1,72 @@
#include <wchar.h>
#include <stdlib.h>
#include <time.h>
#include <locale.h>
#include "locale_impl.h"
#include "time_impl.h"
size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, const struct tm *restrict tm, locale_t loc)
{
size_t l, k;
char buf[100];
wchar_t wbuf[100];
wchar_t *p;
const char *t_mb;
const wchar_t *t;
int pad, plus;
unsigned long width;
for (l=0; l<n; f++) {
if (!*f) {
s[l] = 0;
return l;
}
if (*f != '%') {
s[l++] = *f;
continue;
}
f++;
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
width = wcstoul(f, &p, 10);
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
width = 0;
}
f = p;
if (*f == 'E' || *f == 'O') f++;
t_mb = __strftime_fmt_1(&buf, &k, *f, tm, loc, pad);
if (!t_mb) break;
k = mbstowcs(wbuf, t_mb, sizeof wbuf / sizeof *wbuf);
if (k == (size_t)-1) return 0;
t = wbuf;
if (width) {
for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
width--;
if (plus && tm->tm_year >= 10000-1900)
s[l++] = '+';
else if (tm->tm_year < -1900)
s[l++] = '-';
else
width++;
for (; width > k && l < n; width--)
s[l++] = '0';
}
if (k >= n-l) k = n-l;
wmemcpy(s+l, t, k);
l += k;
}
if (n) {
if (l==n) l=n-1;
s[l] = 0;
}
return 0;
}
size_t wcsftime(wchar_t *restrict wcs, size_t n, const wchar_t *restrict f, const struct tm *restrict tm)
{
return __wcsftime_l(wcs, n, f, tm, CURRENT_LOCALE);
}
weak_alias(__wcsftime_l, wcsftime_l);
+1 -7
View File
@@ -1,13 +1,12 @@
SubDir HAIKU_TOP src system libroot posix time ;
# for localtime.c strftime.c
SubDirCcFlags -DNOID -DUSG_COMPAT -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone
SubDirCcFlags -DNOID -DUSG_COMPAT -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone
-DPCTS=1 -DSTD_INSPIRED ;
UsePrivateHeaders
libroot
[ FDirName libroot locale ]
[ FDirName libroot time ]
shared
;
@@ -23,18 +22,13 @@ for architectureObject in [ MultiArchSubDirSetup ] {
clock.cpp
clock_support.cpp
ctime.c
difftime.c
localtime_fading_out.c
localtime.cpp
nanosleep.c
stime.c
strftime.c
strptime.c
timelocal.cpp
time.c
timer_support.cpp
timespec_get.cpp
wcsftime.c
;
}
}
-16
View File
@@ -1,16 +0,0 @@
/*
** Copyright 2004, Axel Dörfler, [email protected]. All rights reserved.
** Distributed under the terms of the MIT License.
*/
#include <time.h>
#include <SupportDefs.h>
double
difftime(time_t time1, time_t time2)
{
return 1. * ((bigtime_t)time1 - (bigtime_t)time2);
}
-589
View File
@@ -1,589 +0,0 @@
#ifndef lint
#ifndef NOID
static char elsieid[] = "@(#)strftime.c 8.1";
/*
** Based on the UCB version with the ID appearing below.
** This is ANSIish only when "multibyte character == plain character".
*/
#endif /* !defined NOID */
#endif /* !defined lint */
#include "private.h"
/*
** Copyright (c) 1989 The Regents of the University of California.
** All rights reserved.
**
** Redistribution and use in source and binary forms are permitted
** provided that the above copyright notice and this paragraph are
** duplicated in all such forms and that any documentation,
** advertising materials, and other materials related to such
** distribution and use acknowledge that the software was developed
** by the University of California, Berkeley. The name of the
** University may not be used to endorse or promote products derived
** from this software without specific prior written permission.
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef LIBC_SCCS
#ifndef lint
static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
#endif /* !defined lint */
#endif /* !defined LIBC_SCCS */
#include "tzfile.h"
#include "fcntl.h"
#include "locale.h"
#include "timelocal.h"
static char * _add P((const char *, char *, const char *));
static char * _conv P((int, const char *, char *, const char *));
static char * _fmt P((const char *, const struct tm *, char *, const char *,
int *, const struct lc_time_t*));
static char * _yconv P((int, int, int, int, char *, const char *));
static size_t __strftime(char * const, const size_t, const char * const,
const struct tm * const, const struct lc_time_t*);
extern char * tzname[];
#ifndef YEAR_2000_NAME
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
#endif /* !defined YEAR_2000_NAME */
#define IN_NONE 0
#define IN_SOME 1
#define IN_THIS 2
#define IN_ALL 3
#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
size_t
strftime(char* const s, const size_t maxsize, const char* const format, const struct tm* const t)
{
return __strftime(s, maxsize, format, t, __get_current_time_locale());
}
size_t
strftime_l(char* const s, const size_t maxsize, const char* const format, const struct tm* const t,
locale_t locale)
{
return __strftime(s, maxsize, format, t, __get_time_locale(locale));
}
static size_t
__strftime(s, maxsize, format, t, locale)
char * const s;
const size_t maxsize;
const char * const format;
const struct tm * const t;
const struct lc_time_t* locale;
{
char * p;
int warn;
tzset();
warn = IN_NONE;
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, locale);
#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
(void) fprintf(stderr, "\n");
if (format == NULL)
(void) fprintf(stderr, "NULL strftime format ");
else (void) fprintf(stderr, "strftime format \"%s\" ",
format);
(void) fprintf(stderr, "yields only two digits of years in ");
if (warn == IN_SOME)
(void) fprintf(stderr, "some locales");
else if (warn == IN_THIS)
(void) fprintf(stderr, "the current locale");
else (void) fprintf(stderr, "all locales");
(void) fprintf(stderr, "\n");
}
#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
if (p == s + maxsize)
return 0;
*p = '\0';
return p - s;
}
static char *
_fmt(format, t, pt, ptlim, warnp, Locale)
const char * format;
const struct tm * const t;
char * pt;
const char * const ptlim;
int * warnp;
const struct lc_time_t* Locale;
{
for ( ; *format; ++format) {
if (*format == '%') {
label:
switch (*++format) {
case '\0':
--format;
break;
case '0':
// ignore '0'-modifier supported by glibc for compatibility
goto label;
case 'A':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : Locale->weekday[t->tm_wday],
pt, ptlim);
continue;
case 'a':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : Locale->wday[t->tm_wday],
pt, ptlim);
continue;
case 'B':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->month[t->tm_mon],
pt, ptlim);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : Locale->mon[t->tm_mon],
pt, ptlim);
continue;
case 'C':
/*
** %C used to do a...
** _fmt("%a %b %e %X %Y", t);
** ...whereas now POSIX 1003.2 calls for
** something completely different.
** (ado, 1993-05-24)
*/
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
pt, ptlim);
continue;
case 'c':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, Locale);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
continue;
case 'E':
case 'O':
/*
** C99 locale modifiers.
** The sequences
** %Ec %EC %Ex %EX %Ey %EY
** %Od %oe %OH %OI %Om %OM
** %OS %Ou %OU %OV %Ow %OW %Oy
** are supposed to provide alternate
** representations.
*/
goto label;
case 'e':
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
continue;
case 'H':
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
continue;
case 'I':
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
"%02d", pt, ptlim);
continue;
case 'j':
pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
continue;
case 'k':
/*
** This used to be...
** _conv(t->tm_hour % 12 ?
** t->tm_hour % 12 : 12, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbins'
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = _conv(t->tm_hour, "%2d", pt, ptlim);
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
pt = _add("kitchen sink", pt, ptlim);
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
/*
** This used to be...
** _conv(t->tm_hour, 2, ' ');
** ...and has been changed to the below to
** match SunOS 4.1.1 and Arnold Robbin's
** strftime version 3.0. That is, "%k" and
** "%l" have been swapped.
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
"%2d", pt, ptlim);
continue;
case 'M':
pt = _conv(t->tm_min, "%02d", pt, ptlim);
continue;
case 'm':
pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
continue;
case 'n':
pt = _add("\n", pt, ptlim);
continue;
case 'p':
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
Locale->pm :
Locale->am,
pt, ptlim);
continue;
case 'R':
pt = _fmt("%H:%M", t, pt, ptlim, warnp, Locale);
continue;
case 'r':
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, Locale);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
continue;
case 's':
{
struct tm tm;
char buf[INT_STRLEN_MAXIMUM(
time_t) + 1];
time_t mkt;
tm = *t;
mkt = mktime(&tm);
if (TYPE_SIGNED(time_t))
(void) sprintf(buf, "%ld",
(long) mkt);
else (void) sprintf(buf, "%lu",
(unsigned long) mkt);
pt = _add(buf, pt, ptlim);
}
continue;
case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
continue;
case 't':
pt = _add("\t", pt, ptlim);
continue;
case 'U':
pt = _conv((t->tm_yday + DAYSPERWEEK -
t->tm_wday) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'u':
/*
** From Arnold Robbins' strftime version 3.0:
** "ISO 8601: Weekday as a decimal number
** [1 (Monday) - 7]"
** (ado, 1993-05-24)
*/
pt = _conv((t->tm_wday == 0) ?
DAYSPERWEEK : t->tm_wday,
"%d", pt, ptlim);
continue;
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
case 'g': /* ISO 8601 year (two digits) */
/*
** From Arnold Robbins' strftime version 3.0: "the week number of the
** year (the first Monday as the first day of week 1) as a decimal number
** (01-53)."
** (ado, 1993-05-24)
**
** From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
** "Week 01 of a year is per definition the first week which has the
** Thursday in this year, which is equivalent to the week which contains
** the fourth day of January. In other words, the first week of a new year
** is the week which has the majority of its days in the new year. Week 01
** might also contain days from the previous year and the week before week
** 01 of a year is the last week (52 or 53) of the previous year even if
** it contains days from the new year. A week starts with Monday (day 1)
** and ends with Sunday (day 7). For example, the first week of the year
** 1997 lasts from 1996-12-30 to 1997-01-05..."
** (ado, 1996-01-02)
*/
{
int year;
int base;
int yday;
int wday;
int w;
year = t->tm_year;
base = TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
int len;
int bot;
int top;
len = isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
** What yday (-3 ... 3) does
** the ISO year begin on?
*/
bot = ((yday + 11 - wday) %
DAYSPERWEEK) - 3;
/*
** What yday does the NEXT
** ISO year begin on?
*/
top = bot -
(len % DAYSPERWEEK);
if (top < -3)
top += DAYSPERWEEK;
top += len;
if (yday >= top) {
++base;
w = 1;
break;
}
if (yday >= bot) {
w = 1 + ((yday - bot) /
DAYSPERWEEK);
break;
}
--base;
yday += isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
if ((w == 52 &&
t->tm_mon == TM_JANUARY) ||
(w == 1 &&
t->tm_mon == TM_DECEMBER))
w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V')
pt = _conv(w, "%02d",
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
pt = _yconv(year, base, 0, 1,
pt, ptlim);
} else pt = _yconv(year, base, 1, 1,
pt, ptlim);
}
continue;
case 'v':
/*
** From Arnold Robbins' strftime version 3.0:
** "date as dd-bbb-YYYY"
** (ado, 1993-05-24)
*/
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, Locale);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
(t->tm_wday ?
(t->tm_wday - 1) :
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
"%02d", pt, ptlim);
continue;
case 'w':
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, Locale);
continue;
case 'x':
{
int warn2 = IN_SOME;
pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, Locale);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'y':
*warnp = IN_ALL;
pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
pt, ptlim);
continue;
case 'Y':
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
pt, ptlim);
continue;
case 'Z':
#ifdef TM_ZONE
if (t->TM_ZONE != NULL)
pt = _add(t->TM_ZONE, pt, ptlim);
else
#endif /* defined TM_ZONE */
if (t->tm_isdst >= 0)
pt = _add(tzname[t->tm_isdst != 0],
pt, ptlim);
/*
** C99 says that %Z must be replaced by the
** empty string if the time zone is not
** determinable.
*/
continue;
case 'z':
{
int diff;
char const * sign;
if (t->tm_isdst < 0)
continue;
#ifdef TM_GMTOFF
diff = t->TM_GMTOFF;
#else /* !defined TM_GMTOFF */
/*
** C99 says that the UTC offset must
** be computed by looking only at
** tm_isdst. This requirement is
** incorrect, since it means the code
** must rely on magic (in this case
** altzone and timezone), and the
** magic might not have the correct
** offset. Doing things correctly is
** tricky and requires disobeying C99;
** see GNU C strftime for details.
** For now, punt and conform to the
** standard, even though it's incorrect.
**
** C99 says that %z must be replaced by the
** empty string if the time zone is not
** determinable, so output nothing if the
** appropriate variables are not available.
*/
if (t->tm_isdst == 0)
#ifdef USG_COMPAT
diff = -timezone;
#else /* !defined USG_COMPAT */
continue;
#endif /* !defined USG_COMPAT */
else
#ifdef ALTZONE
diff = -altzone;
#else /* !defined ALTZONE */
continue;
#endif /* !defined ALTZONE */
#endif /* !defined TM_GMTOFF */
if (diff < 0) {
sign = "-";
diff = -diff;
} else sign = "+";
pt = _add(sign, pt, ptlim);
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 +
(diff % MINSPERHOUR);
pt = _conv(diff, "%04d", pt, ptlim);
}
continue;
case '+':
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
warnp, Locale);
continue;
case '%':
/*
** X311J/88-090 (4.12.3.5): if conversion char is
** undefined, behavior is undefined. Print out the
** character itself as printf(3) also does.
*/
default:
break;
}
}
if (pt == ptlim)
break;
*pt++ = *format;
}
return pt;
}
static char *
_conv(n, format, pt, ptlim)
const int n;
const char * const format;
char * const pt;
const char * const ptlim;
{
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(void) sprintf(buf, format, n);
return _add(buf, pt, ptlim);
}
static char *
_add(str, pt, ptlim)
const char * str;
char * pt;
const char * const ptlim;
{
while (pt < ptlim && (*pt = *str++) != '\0')
++pt;
return pt;
}
/*
** POSIX and the C Standard are unclear or inconsistent about
** what %C and %y do if the year is negative or exceeds 9999.
** Use the convention that %C concatenated with %y yields the
** same output as %Y, and that %Y contains at least 4 bytes,
** with more only if necessary.
*/
static char *
_yconv(a, b, convert_top, convert_yy, pt, ptlim)
const int a;
const int b;
const int convert_top;
const int convert_yy;
char * pt;
const char * const ptlim;
{
register int lead;
register int trail;
#define DIVISOR 100
trail = a % DIVISOR + b % DIVISOR;
lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
trail %= DIVISOR;
if (trail < 0 && lead > 0) {
trail += DIVISOR;
--lead;
} else if (lead < 0 && trail > 0) {
trail -= DIVISOR;
++lead;
}
if (convert_top) {
if (lead == 0 && trail < 0)
pt = _add("-0", pt, ptlim);
else pt = _conv(lead, "%02d", pt, ptlim);
}
if (convert_yy)
pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt, ptlim);
return pt;
}
-502
View File
@@ -1,502 +0,0 @@
/*
* Copyright (c) 1994 Powerdog Industries. 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 Powerdog Industries.
* 4. The name of Powerdog Industries may not be used to endorse or
* promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``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 POWERDOG INDUSTRIES 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 <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "timelocal.h"
#include <errno_private.h>
static char * _strptime(const char *, const char *, struct tm *, int *);
#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
static char *
_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp)
{
char c;
const char *ptr;
int i,
len;
int Ealternative, Oalternative;
struct lc_time_t *tptr = __get_current_time_locale();
ptr = fmt;
while (*ptr != 0) {
c = *ptr++;
if (c != '%') {
if (isspace((unsigned char)c))
while (*buf != 0 && isspace((unsigned char)*buf))
buf++;
else if (c != *buf++)
return 0;
continue;
}
Ealternative = 0;
Oalternative = 0;
label:
c = *ptr++;
switch (c) {
case '%':
if (*buf++ != '%')
return 0;
break;
case '+':
buf = _strptime(buf, tptr->date_fmt, tm, GMTp);
if (buf == 0)
return 0;
break;
case 'C':
if (!isdigit((unsigned char)*buf))
return 0;
/* XXX This will break for 3-digit centuries. */
len = 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (i < 19)
return 0;
tm->tm_year = i * 100 - 1900;
break;
case 'c':
buf = _strptime(buf, tptr->c_fmt, tm, GMTp);
if (buf == 0)
return 0;
break;
case 'D':
buf = _strptime(buf, "%m/%d/%y", tm, GMTp);
if (buf == 0)
return 0;
break;
case 'E':
if (Ealternative || Oalternative)
break;
Ealternative++;
goto label;
case 'O':
if (Ealternative || Oalternative)
break;
Oalternative++;
goto label;
case 'F':
buf = _strptime(buf, "%Y-%m-%d", tm, GMTp);
if (buf == 0)
return 0;
break;
case 'R':
buf = _strptime(buf, "%H:%M", tm, GMTp);
if (buf == 0)
return 0;
break;
case 'r':
buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp);
if (buf == 0)
return 0;
break;
case 'T':
buf = _strptime(buf, "%H:%M:%S", tm, GMTp);
if (buf == 0)
return 0;
break;
case 'X':
buf = _strptime(buf, tptr->X_fmt, tm, GMTp);
if (buf == 0)
return 0;
break;
case 'x':
buf = _strptime(buf, tptr->x_fmt, tm, GMTp);
if (buf == 0)
return 0;
break;
case 'j':
if (!isdigit((unsigned char)*buf))
return 0;
len = 3;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (i < 1 || i > 366)
return 0;
tm->tm_yday = i - 1;
break;
case 'M':
case 'S':
if (*buf == 0 || isspace((unsigned char)*buf))
break;
if (!isdigit((unsigned char)*buf))
return 0;
len = 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (c == 'M') {
if (i > 59)
return 0;
tm->tm_min = i;
} else {
if (i > 60)
return 0;
tm->tm_sec = i;
}
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 'H':
case 'I':
case 'k':
case 'l':
/*
* Of these, %l is the only specifier explicitly
* documented as not being zero-padded. However,
* there is no harm in allowing zero-padding.
*
* XXX The %l specifier may gobble one too many
* digits if used incorrectly.
*/
if (!isdigit((unsigned char)*buf))
return 0;
len = 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (c == 'H' || c == 'k') {
if (i > 23)
return 0;
} else if (i > 12)
return 0;
tm->tm_hour = i;
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 'p':
/*
* XXX This is bogus if parsed before hour-related
* specifiers.
*/
len = strlen(tptr->am);
if (strncasecmp(buf, tptr->am, len) == 0) {
if (tm->tm_hour > 12)
return 0;
if (tm->tm_hour == 12)
tm->tm_hour = 0;
buf += len;
break;
}
len = strlen(tptr->pm);
if (strncasecmp(buf, tptr->pm, len) == 0) {
if (tm->tm_hour > 12)
return 0;
if (tm->tm_hour != 12)
tm->tm_hour += 12;
buf += len;
break;
}
return 0;
case 'A':
case 'a':
for (i = 0; i < asizeof(tptr->weekday); i++) {
len = strlen(tptr->weekday[i]);
if (strncasecmp(buf, tptr->weekday[i],
len) == 0)
break;
len = strlen(tptr->wday[i]);
if (strncasecmp(buf, tptr->wday[i],
len) == 0)
break;
}
if (i == asizeof(tptr->weekday))
return 0;
tm->tm_wday = i;
buf += len;
break;
case 'U':
case 'W':
/*
* 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 (!isdigit((unsigned char)*buf))
return 0;
len = 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (i > 53)
return 0;
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 'w':
if (!isdigit((unsigned char)*buf))
return 0;
i = *buf - '0';
if (i > 6)
return 0;
tm->tm_wday = i;
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 'd':
case 'e':
/*
* The %e specifier is explicitly documented as not
* being zero-padded but there is no harm in allowing
* such padding.
*
* XXX The %e specifier may gobble one too many
* digits if used incorrectly.
*/
if (!isdigit((unsigned char)*buf))
return 0;
len = 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (i > 31)
return 0;
tm->tm_mday = i;
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 'B':
case 'b':
case 'h':
for (i = 0; i < asizeof(tptr->month); i++) {
if (Oalternative) {
if (c == 'B') {
len = strlen(tptr->alt_month[i]);
if (strncasecmp(buf,
tptr->alt_month[i],
len) == 0)
break;
}
} else {
len = strlen(tptr->month[i]);
if (strncasecmp(buf, tptr->month[i],
len) == 0)
break;
len = strlen(tptr->mon[i]);
if (strncasecmp(buf, tptr->mon[i],
len) == 0)
break;
}
}
if (i == asizeof(tptr->month))
return 0;
tm->tm_mon = i;
buf += len;
break;
case 'm':
if (!isdigit((unsigned char)*buf))
return 0;
len = 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (i < 1 || i > 12)
return 0;
tm->tm_mon = i - 1;
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 's':
{
char *cp;
int sverrno;
long n;
time_t t;
sverrno = errno;
__set_errno(0);
n = strtol(buf, &cp, 10);
if (errno == ERANGE || (long)(t = n) != n) {
__set_errno(sverrno);
return 0;
}
__set_errno(sverrno);
buf = cp;
gmtime_r(&t, tm);
*GMTp = 1;
}
break;
case 'Y':
case 'y':
if (*buf == 0 || isspace((unsigned char)*buf))
break;
if (!isdigit((unsigned char)*buf))
return 0;
len = (c == 'Y') ? 4 : 2;
for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) {
i *= 10;
i += *buf - '0';
len--;
}
if (c == 'Y')
i -= 1900;
if (c == 'y' && i < 69)
i += 100;
tm->tm_year = i;
if (*buf != 0 && isspace((unsigned char)*buf))
while (*ptr != 0 && !isspace((unsigned char)*ptr))
ptr++;
break;
case 'Z':
{
const char *cp;
char *zonestr;
for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/}
if (cp - buf) {
zonestr = alloca(cp - buf + 1);
strncpy(zonestr, buf, cp - buf);
zonestr[cp - buf] = '\0';
tzset();
if (0 == strcmp(zonestr, "GMT")) {
*GMTp = 1;
} else if (0 == strcmp(zonestr, tzname[0])) {
tm->tm_isdst = 0;
} else if (0 == strcmp(zonestr, tzname[1])) {
tm->tm_isdst = 1;
} else {
return 0;
}
buf += cp - buf;
}
}
break;
default:
return 0;
}
}
return (char *)buf;
}
char *
strptime(const char * __restrict buf, const char * __restrict fmt,
struct tm * __restrict tm)
{
char *ret;
int gmt;
gmt = 0;
ret = _strptime(buf, fmt, tm, &gmt);
if (ret && gmt) {
time_t t = timegm(tm);
localtime_r(&t, tm);
}
return (ret);
}
@@ -1,40 +0,0 @@
/*
* Copyright 2010, Oliver Tappe, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "timelocal.h"
#include <stddef.h>
#include "LocaleBackend.h"
#include "PosixLCTimeInfo.h"
using BPrivate::Libroot::GetCurrentLocaleBackend;
using BPrivate::Libroot::LocaleBackend;
using BPrivate::Libroot::LocaleBackendData;
extern "C" const lc_time_t*
__get_current_time_locale(void)
{
if (GetCurrentLocaleBackend() != NULL)
return GetCurrentLocaleBackend()->LCTimeInfo();
return &BPrivate::Libroot::gPosixLCTimeInfo;
}
extern "C" const lc_time_t*
__get_time_locale(locale_t l)
{
LocaleBackendData* locale = (LocaleBackendData*)l;
LocaleBackend* backend = locale->backend;
if (backend != NULL)
return backend->LCTimeInfo();
return &BPrivate::Libroot::gPosixLCTimeInfo;
}
-112
View File
@@ -1,112 +0,0 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* 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.
*/
#include <sys/cdefs.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <errno_private.h>
#include <wchar_private.h>
/*
* Convert date and time to a wide-character string.
*
* This is the wide-character counterpart of strftime(). So that we do not
* have to duplicate the code of strftime(), we convert the format string to
* multibyte, call strftime(), then convert the result back into wide
* characters.
*
* This technique loses in the presence of stateful multibyte encoding if any
* of the conversions in the format string change conversion state. When
* stateful encoding is implemented, we will need to reset the state between
* format specifications in the format string.
*/
size_t
wcsftime(wchar_t *wcs, size_t maxsize, const wchar_t *format,
const struct tm *timeptr)
{
static const mbstate_t initial;
mbstate_t mbs;
char *dst, *sformat;
const char *dstp;
const wchar_t *formatp;
size_t n, sflen;
int sverrno;
sformat = dst = NULL;
/*
* Convert the supplied format string to a multibyte representation
* for strftime(), which only handles single-byte characters.
*/
mbs = initial;
formatp = format;
sflen = __wcsrtombs(NULL, &formatp, 0, &mbs);
if (sflen == (size_t)-1)
goto error;
if ((sformat = malloc(sflen + 1)) == NULL)
goto error;
mbs = initial;
__wcsrtombs(sformat, &formatp, sflen + 1, &mbs);
/*
* Allocate memory for longest multibyte sequence that will fit
* into the caller's buffer and call strftime() to fill it.
* Then, copy and convert the result back into wide characters in
* the caller's buffer.
*/
if (SIZE_MAX / MB_CUR_MAX <= maxsize) {
/* maxsize is prepostorously large - avoid int. overflow. */
__set_errno(EINVAL);
goto error;
}
if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
goto error;
if (strftime(dst, maxsize, sformat, timeptr) == 0)
goto error;
dstp = dst;
mbs = initial;
n = __mbsrtowcs(wcs, &dstp, maxsize, &mbs);
if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
goto error;
free(sformat);
free(dst);
return n;
error:
sverrno = errno;
free(sformat);
free(dst);
__set_errno(sverrno);
return 0;
}