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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 = ¢ury;
|
||||
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,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
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user