The localtime_tz and mktime_tz extensions are now in bionic.
(cherry-pick of d03072ffde
. This change
was originally committed to AOSP, is in internal master, but was somehow
lost from AOSP.)
Bug: 7012465
Conflicts:
libcutils/Android.mk
Change-Id: I08ee8eb9b8ce5d3f9d8f2e67437d653e08697bc1
This commit is contained in:
parent
ef2ea99bfe
commit
def8d6a706
|
@ -17,45 +17,8 @@
|
|||
#ifndef _CUTILS_TZTIME_H
|
||||
#define _CUTILS_TZTIME_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
time_t mktime_tz(struct tm * const tmp, char const * tz);
|
||||
void localtime_tz(const time_t * const timep, struct tm * tmp, const char* tz);
|
||||
|
||||
#ifdef HAVE_ANDROID_OS
|
||||
|
||||
/* the following is defined in the Bionic C library on Android, but the
|
||||
* declarations are only available through a platform-private header
|
||||
*/
|
||||
// TODO: fix both callers to just include <bionic_time.h> themselves.
|
||||
#include <bionic_time.h>
|
||||
|
||||
#else /* !HAVE_ANDROID_OS */
|
||||
|
||||
struct strftime_locale {
|
||||
const char *mon[12]; /* short names */
|
||||
const char *month[12]; /* long names */
|
||||
const char *standalone_month[12]; /* long standalone names */
|
||||
const char *wday[7]; /* short names */
|
||||
const char *weekday[7]; /* long names */
|
||||
const char *X_fmt;
|
||||
const char *x_fmt;
|
||||
const char *c_fmt;
|
||||
const char *am;
|
||||
const char *pm;
|
||||
const char *date_fmt;
|
||||
};
|
||||
|
||||
size_t strftime_tz(char *s, size_t max, const char *format, const struct tm *tm, const struct strftime_locale *locale);
|
||||
|
||||
#endif /* !HAVE_ANDROID_OS */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CUTILS_TZTIME_H */
|
||||
|
||||
|
|
|
@ -77,12 +77,8 @@ else
|
|||
abort_socket.c \
|
||||
fs.c \
|
||||
selector.c \
|
||||
tztime.c \
|
||||
multiuser.c \
|
||||
zygote.c
|
||||
|
||||
commonHostSources += \
|
||||
tzstrftime.c
|
||||
endif
|
||||
|
||||
|
||||
|
|
|
@ -1,368 +0,0 @@
|
|||
#ifndef PRIVATE_H
|
||||
|
||||
#define PRIVATE_H
|
||||
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/*
|
||||
** This header is for use ONLY with the time conversion code.
|
||||
** There is no guarantee that it will remain unchanged,
|
||||
** or that it will remain at all.
|
||||
** Do NOT copy it to any system include directory.
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
/*
|
||||
** ID
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#ifndef NOID
|
||||
static char privatehid[] = "@(#)private.h 8.2";
|
||||
#endif /* !defined NOID */
|
||||
#endif /* !defined lint */
|
||||
|
||||
#define GRANDPARENTED "Local time zone must be set--see zic manual page"
|
||||
|
||||
/*
|
||||
** Defaults for preprocessor symbols.
|
||||
** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_ADJTIME
|
||||
#define HAVE_ADJTIME 1
|
||||
#endif /* !defined HAVE_ADJTIME */
|
||||
|
||||
#ifndef HAVE_GETTEXT
|
||||
#define HAVE_GETTEXT 0
|
||||
#endif /* !defined HAVE_GETTEXT */
|
||||
|
||||
#ifndef HAVE_INCOMPATIBLE_CTIME_R
|
||||
#define HAVE_INCOMPATIBLE_CTIME_R 0
|
||||
#endif /* !defined INCOMPATIBLE_CTIME_R */
|
||||
|
||||
#ifndef HAVE_SETTIMEOFDAY
|
||||
#define HAVE_SETTIMEOFDAY 3
|
||||
#endif /* !defined HAVE_SETTIMEOFDAY */
|
||||
|
||||
#ifndef HAVE_STRERROR
|
||||
#define HAVE_STRERROR 1
|
||||
#endif /* !defined HAVE_STRERROR */
|
||||
|
||||
#ifndef HAVE_SYMLINK
|
||||
#define HAVE_SYMLINK 1
|
||||
#endif /* !defined HAVE_SYMLINK */
|
||||
|
||||
#ifndef HAVE_SYS_STAT_H
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
#endif /* !defined HAVE_SYS_STAT_H */
|
||||
|
||||
#ifndef HAVE_SYS_WAIT_H
|
||||
#define HAVE_SYS_WAIT_H 1
|
||||
#endif /* !defined HAVE_SYS_WAIT_H */
|
||||
|
||||
#ifndef HAVE_UNISTD_H
|
||||
#define HAVE_UNISTD_H 1
|
||||
#endif /* !defined HAVE_UNISTD_H */
|
||||
|
||||
#ifndef HAVE_UTMPX_H
|
||||
#define HAVE_UTMPX_H 0
|
||||
#endif /* !defined HAVE_UTMPX_H */
|
||||
|
||||
#ifndef LOCALE_HOME
|
||||
#define LOCALE_HOME "/usr/lib/locale"
|
||||
#endif /* !defined LOCALE_HOME */
|
||||
|
||||
#if HAVE_INCOMPATIBLE_CTIME_R
|
||||
#define asctime_r _incompatible_asctime_r
|
||||
#define ctime_r _incompatible_ctime_r
|
||||
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
|
||||
|
||||
/*
|
||||
** Nested includes
|
||||
*/
|
||||
|
||||
#include "sys/types.h" /* for time_t */
|
||||
#include "stdio.h"
|
||||
#include "errno.h"
|
||||
#include "string.h"
|
||||
#include "limits.h" /* for CHAR_BIT et al. */
|
||||
#include "time.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
#if HAVE_GETTEXT
|
||||
#include "libintl.h"
|
||||
#endif /* HAVE_GETTEXT */
|
||||
|
||||
#if HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
|
||||
#endif /* HAVE_SYS_WAIT_H */
|
||||
|
||||
#ifndef WIFEXITED
|
||||
#define WIFEXITED(status) (((status) & 0xff) == 0)
|
||||
#endif /* !defined WIFEXITED */
|
||||
#ifndef WEXITSTATUS
|
||||
#define WEXITSTATUS(status) (((status) >> 8) & 0xff)
|
||||
#endif /* !defined WEXITSTATUS */
|
||||
|
||||
#if HAVE_UNISTD_H
|
||||
#include "unistd.h" /* for F_OK and R_OK */
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if !HAVE_UNISTD_H
|
||||
#ifndef F_OK
|
||||
#define F_OK 0
|
||||
#endif /* !defined F_OK */
|
||||
#ifndef R_OK
|
||||
#define R_OK 4
|
||||
#endif /* !defined R_OK */
|
||||
#endif /* !HAVE_UNISTD_H */
|
||||
|
||||
/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
|
||||
#define is_digit(c) ((unsigned)(c) - '0' <= 9)
|
||||
|
||||
/*
|
||||
** Define HAVE_STDINT_H's default value here, rather than at the
|
||||
** start, since __GLIBC__'s value depends on previously-included
|
||||
** files.
|
||||
** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
|
||||
*/
|
||||
#ifndef HAVE_STDINT_H
|
||||
#define HAVE_STDINT_H \
|
||||
(199901 <= __STDC_VERSION__ || \
|
||||
2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
|
||||
#endif /* !defined HAVE_STDINT_H */
|
||||
|
||||
#if HAVE_STDINT_H
|
||||
#include "stdint.h"
|
||||
#endif /* !HAVE_STDINT_H */
|
||||
|
||||
#ifndef INT_FAST64_MAX
|
||||
/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
|
||||
#if defined LLONG_MAX || defined __LONG_LONG_MAX__
|
||||
typedef long long int_fast64_t;
|
||||
#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
|
||||
#if (LONG_MAX >> 31) < 0xffffffff
|
||||
Please use a compiler that supports a 64-bit integer type (or wider);
|
||||
you may need to compile with "-DHAVE_STDINT_H".
|
||||
#endif /* (LONG_MAX >> 31) < 0xffffffff */
|
||||
typedef long int_fast64_t;
|
||||
#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
|
||||
#endif /* !defined INT_FAST64_MAX */
|
||||
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX 0x7fffffff
|
||||
#endif /* !defined INT32_MAX */
|
||||
#ifndef INT32_MIN
|
||||
#define INT32_MIN (-1 - INT32_MAX)
|
||||
#endif /* !defined INT32_MIN */
|
||||
|
||||
/*
|
||||
** Workarounds for compilers/systems.
|
||||
*/
|
||||
|
||||
/*
|
||||
** If your compiler lacks prototypes, "#define P(x) ()".
|
||||
*/
|
||||
|
||||
#ifndef P
|
||||
#define P(x) x
|
||||
#endif /* !defined P */
|
||||
|
||||
/*
|
||||
** SunOS 4.1.1 headers lack EXIT_SUCCESS.
|
||||
*/
|
||||
|
||||
#ifndef EXIT_SUCCESS
|
||||
#define EXIT_SUCCESS 0
|
||||
#endif /* !defined EXIT_SUCCESS */
|
||||
|
||||
/*
|
||||
** SunOS 4.1.1 headers lack EXIT_FAILURE.
|
||||
*/
|
||||
|
||||
#ifndef EXIT_FAILURE
|
||||
#define EXIT_FAILURE 1
|
||||
#endif /* !defined EXIT_FAILURE */
|
||||
|
||||
/*
|
||||
** SunOS 4.1.1 headers lack FILENAME_MAX.
|
||||
*/
|
||||
|
||||
#ifndef FILENAME_MAX
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
#ifdef unix
|
||||
#include "sys/param.h"
|
||||
#endif /* defined unix */
|
||||
#endif /* !defined MAXPATHLEN */
|
||||
|
||||
#ifdef MAXPATHLEN
|
||||
#define FILENAME_MAX MAXPATHLEN
|
||||
#endif /* defined MAXPATHLEN */
|
||||
#ifndef MAXPATHLEN
|
||||
#define FILENAME_MAX 1024 /* Pure guesswork */
|
||||
#endif /* !defined MAXPATHLEN */
|
||||
|
||||
#endif /* !defined FILENAME_MAX */
|
||||
|
||||
/*
|
||||
** SunOS 4.1.1 libraries lack remove.
|
||||
*/
|
||||
|
||||
#ifndef remove
|
||||
extern int unlink P((const char * filename));
|
||||
#define remove unlink
|
||||
#endif /* !defined remove */
|
||||
|
||||
/*
|
||||
** Some ancient errno.h implementations don't declare errno.
|
||||
** But some newer errno.h implementations define it as a macro.
|
||||
** Fix the former without affecting the latter.
|
||||
*/
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif /* !defined errno */
|
||||
|
||||
/*
|
||||
** Some time.h implementations don't declare asctime_r.
|
||||
** Others might define it as a macro.
|
||||
** Fix the former without affecting the latter.
|
||||
*/
|
||||
|
||||
#ifndef asctime_r
|
||||
extern char * asctime_r();
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Private function declarations.
|
||||
*/
|
||||
|
||||
char * icalloc P((int nelem, int elsize));
|
||||
char * icatalloc P((char * old, const char * new));
|
||||
char * icpyalloc P((const char * string));
|
||||
char * imalloc P((int n));
|
||||
void * irealloc P((void * pointer, int size));
|
||||
void icfree P((char * pointer));
|
||||
void ifree P((char * pointer));
|
||||
const char * scheck P((const char * string, const char * format));
|
||||
|
||||
/*
|
||||
** Finally, some convenience items.
|
||||
*/
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif /* !defined TRUE */
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif /* !defined FALSE */
|
||||
|
||||
#ifndef TYPE_BIT
|
||||
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
|
||||
#endif /* !defined TYPE_BIT */
|
||||
|
||||
#ifndef TYPE_SIGNED
|
||||
#define TYPE_SIGNED(type) (((type) -1) < 0)
|
||||
#endif /* !defined TYPE_SIGNED */
|
||||
|
||||
/*
|
||||
** Since the definition of TYPE_INTEGRAL contains floating point numbers,
|
||||
** it cannot be used in preprocessor directives.
|
||||
*/
|
||||
|
||||
#ifndef TYPE_INTEGRAL
|
||||
#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
|
||||
#endif /* !defined TYPE_INTEGRAL */
|
||||
|
||||
#ifndef INT_STRLEN_MAXIMUM
|
||||
/*
|
||||
** 302 / 1000 is log10(2.0) rounded up.
|
||||
** Subtract one for the sign bit if the type is signed;
|
||||
** add one for integer division truncation;
|
||||
** add one more for a minus sign if the type is signed.
|
||||
*/
|
||||
#define INT_STRLEN_MAXIMUM(type) \
|
||||
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
|
||||
1 + TYPE_SIGNED(type))
|
||||
#endif /* !defined INT_STRLEN_MAXIMUM */
|
||||
|
||||
/*
|
||||
** INITIALIZE(x)
|
||||
*/
|
||||
|
||||
#ifndef GNUC_or_lint
|
||||
#ifdef lint
|
||||
#define GNUC_or_lint
|
||||
#endif /* defined lint */
|
||||
#ifndef lint
|
||||
#ifdef __GNUC__
|
||||
#define GNUC_or_lint
|
||||
#endif /* defined __GNUC__ */
|
||||
#endif /* !defined lint */
|
||||
#endif /* !defined GNUC_or_lint */
|
||||
|
||||
#ifndef INITIALIZE
|
||||
#ifdef GNUC_or_lint
|
||||
#define INITIALIZE(x) ((x) = 0)
|
||||
#endif /* defined GNUC_or_lint */
|
||||
#ifndef GNUC_or_lint
|
||||
#define INITIALIZE(x)
|
||||
#endif /* !defined GNUC_or_lint */
|
||||
#endif /* !defined INITIALIZE */
|
||||
|
||||
/*
|
||||
** For the benefit of GNU folk...
|
||||
** `_(MSGID)' uses the current locale's message library string for MSGID.
|
||||
** The default is to use gettext if available, and use MSGID otherwise.
|
||||
*/
|
||||
|
||||
#ifndef _
|
||||
#if HAVE_GETTEXT
|
||||
#define _(msgid) gettext(msgid)
|
||||
#else /* !HAVE_GETTEXT */
|
||||
#define _(msgid) msgid
|
||||
#endif /* !HAVE_GETTEXT */
|
||||
#endif /* !defined _ */
|
||||
|
||||
#ifndef TZ_DOMAIN
|
||||
#define TZ_DOMAIN "tz"
|
||||
#endif /* !defined TZ_DOMAIN */
|
||||
|
||||
#if HAVE_INCOMPATIBLE_CTIME_R
|
||||
#undef asctime_r
|
||||
#undef ctime_r
|
||||
char *asctime_r P((struct tm const *, char *));
|
||||
char *ctime_r P((time_t const *, char *));
|
||||
#endif /* HAVE_INCOMPATIBLE_CTIME_R */
|
||||
|
||||
#ifndef YEARSPERREPEAT
|
||||
#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
|
||||
#endif /* !defined YEARSPERREPEAT */
|
||||
|
||||
/*
|
||||
** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
|
||||
*/
|
||||
|
||||
#ifndef AVGSECSPERYEAR
|
||||
#define AVGSECSPERYEAR 31556952L
|
||||
#endif /* !defined AVGSECSPERYEAR */
|
||||
|
||||
#ifndef SECSPERREPEAT
|
||||
#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
|
||||
#endif /* !defined SECSPERREPEAT */
|
||||
|
||||
#ifndef SECSPERREPEAT_BITS
|
||||
#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
|
||||
#endif /* !defined SECSPERREPEAT_BITS */
|
||||
|
||||
/*
|
||||
** UNIX was a registered trademark of The Open Group in 2003.
|
||||
*/
|
||||
|
||||
#endif /* !defined PRIVATE_H */
|
|
@ -1,180 +0,0 @@
|
|||
#ifndef TZFILE_H
|
||||
|
||||
#define TZFILE_H
|
||||
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/*
|
||||
** This header is for use ONLY with the time conversion code.
|
||||
** There is no guarantee that it will remain unchanged,
|
||||
** or that it will remain at all.
|
||||
** Do NOT copy it to any system include directory.
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
/*
|
||||
** ID
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
#ifndef NOID
|
||||
static char tzfilehid[] = "@(#)tzfile.h 8.1";
|
||||
#endif /* !defined NOID */
|
||||
#endif /* !defined lint */
|
||||
|
||||
/*
|
||||
** Information about time zone files.
|
||||
*/
|
||||
|
||||
#ifndef TZDIR
|
||||
#define TZDIR "/usr/share/zoneinfo" /* "/android/usr/share/zoneinfo" */ /* Time zone object file directory */
|
||||
#endif /* !defined TZDIR */
|
||||
|
||||
#ifndef TZDEFAULT
|
||||
#define TZDEFAULT "localtime"
|
||||
#endif /* !defined TZDEFAULT */
|
||||
|
||||
#ifndef TZDEFRULES
|
||||
#define TZDEFRULES "posixrules"
|
||||
#endif /* !defined TZDEFRULES */
|
||||
|
||||
/*
|
||||
** Each file begins with. . .
|
||||
*/
|
||||
|
||||
#define TZ_MAGIC "TZif"
|
||||
|
||||
struct tzhead {
|
||||
char tzh_magic[4]; /* TZ_MAGIC */
|
||||
char tzh_version[1]; /* '\0' or '2' as of 2005 */
|
||||
char tzh_reserved[15]; /* reserved--must be zero */
|
||||
char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
|
||||
char tzh_leapcnt[4]; /* coded number of leap seconds */
|
||||
char tzh_timecnt[4]; /* coded number of transition times */
|
||||
char tzh_typecnt[4]; /* coded number of local time types */
|
||||
char tzh_charcnt[4]; /* coded number of abbr. chars */
|
||||
};
|
||||
|
||||
/*
|
||||
** . . .followed by. . .
|
||||
**
|
||||
** tzh_timecnt (char [4])s coded transition times a la time(2)
|
||||
** tzh_timecnt (unsigned char)s types of local time starting at above
|
||||
** tzh_typecnt repetitions of
|
||||
** one (char [4]) coded UTC offset in seconds
|
||||
** one (unsigned char) used to set tm_isdst
|
||||
** one (unsigned char) that's an abbreviation list index
|
||||
** tzh_charcnt (char)s '\0'-terminated zone abbreviations
|
||||
** tzh_leapcnt repetitions of
|
||||
** one (char [4]) coded leap second transition times
|
||||
** one (char [4]) total correction after above
|
||||
** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
|
||||
** time is standard time, if FALSE,
|
||||
** transition time is wall clock time
|
||||
** if absent, transition times are
|
||||
** assumed to be wall clock time
|
||||
** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
|
||||
** time is UTC, if FALSE,
|
||||
** transition time is local time
|
||||
** if absent, transition times are
|
||||
** assumed to be local time
|
||||
*/
|
||||
|
||||
/*
|
||||
** If tzh_version is '2' or greater, the above is followed by a second instance
|
||||
** of tzhead and a second instance of the data in which each coded transition
|
||||
** time uses 8 rather than 4 chars,
|
||||
** then a POSIX-TZ-environment-variable-style string for use in handling
|
||||
** instants after the last transition time stored in the file
|
||||
** (with nothing between the newlines if there is no POSIX representation for
|
||||
** such instants).
|
||||
*/
|
||||
|
||||
/*
|
||||
** In the current implementation, "tzset()" refuses to deal with files that
|
||||
** exceed any of the limits below.
|
||||
*/
|
||||
|
||||
#ifndef TZ_MAX_TIMES
|
||||
#define TZ_MAX_TIMES 1200
|
||||
#endif /* !defined TZ_MAX_TIMES */
|
||||
|
||||
#ifndef TZ_MAX_TYPES
|
||||
#ifndef NOSOLAR
|
||||
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
|
||||
#endif /* !defined NOSOLAR */
|
||||
#ifdef NOSOLAR
|
||||
/*
|
||||
** Must be at least 14 for Europe/Riga as of Jan 12 1995,
|
||||
** as noted by Earl Chew.
|
||||
*/
|
||||
#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
|
||||
#endif /* !defined NOSOLAR */
|
||||
#endif /* !defined TZ_MAX_TYPES */
|
||||
|
||||
#ifndef TZ_MAX_CHARS
|
||||
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
|
||||
/* (limited by what unsigned chars can hold) */
|
||||
#endif /* !defined TZ_MAX_CHARS */
|
||||
|
||||
#ifndef TZ_MAX_LEAPS
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
#endif /* !defined TZ_MAX_LEAPS */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
/*
|
||||
** Since everything in isleap is modulo 400 (or a factor of 400), we know that
|
||||
** isleap(y) == isleap(y % 400)
|
||||
** and so
|
||||
** isleap(a + b) == isleap((a + b) % 400)
|
||||
** or
|
||||
** isleap(a + b) == isleap(a % 400 + b % 400)
|
||||
** This is true even if % means modulo rather than Fortran remainder
|
||||
** (which is allowed by C89 but not C99).
|
||||
** We use this to avoid addition overflow problems.
|
||||
*/
|
||||
|
||||
#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
|
||||
|
||||
#endif /* !defined TZFILE_H */
|
|
@ -1,842 +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 <stdio.h>
|
||||
#include <time.h>
|
||||
#include <tzfile.h>
|
||||
#include <limits.h>
|
||||
#include <cutils/tztime.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 <ctype.h>
|
||||
|
||||
#define P(x) x
|
||||
|
||||
static char * _add P((const char *, char *, const char *, int));
|
||||
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 strftime_locale *Locale));
|
||||
static char * _yconv P((int, int, int, int, char *, const char *, int));
|
||||
static char * getformat P((int, char *, char *, char *, char *));
|
||||
|
||||
extern char * tzname[];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* from private.h */
|
||||
|
||||
#ifndef TYPE_BIT
|
||||
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
|
||||
#endif /* !defined TYPE_BIT */
|
||||
|
||||
#ifndef TYPE_SIGNED
|
||||
#define TYPE_SIGNED(type) (((type) -1) < 0)
|
||||
#endif /* !defined TYPE_SIGNED */
|
||||
|
||||
#ifndef INT_STRLEN_MAXIMUM
|
||||
/*
|
||||
* ** 302 / 1000 is log10(2.0) rounded up.
|
||||
* ** Subtract one for the sign bit if the type is signed;
|
||||
* ** add one for integer division truncation;
|
||||
* ** add one more for a minus sign if the type is signed.
|
||||
* */
|
||||
#define INT_STRLEN_MAXIMUM(type) \
|
||||
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
|
||||
1 + TYPE_SIGNED(type))
|
||||
#endif /* !defined INT_STRLEN_MAXIMUM */
|
||||
|
||||
/* end of part from private.h */
|
||||
|
||||
|
||||
|
||||
|
||||
#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 FORCE_LOWER_CASE 0x100
|
||||
|
||||
size_t
|
||||
strftime_tz(s, maxsize, format, t, Locale)
|
||||
char * const s;
|
||||
const size_t maxsize;
|
||||
const char * const format;
|
||||
const struct tm * const t;
|
||||
const struct strftime_locale *Locale;
|
||||
{
|
||||
char * p;
|
||||
int warn;
|
||||
|
||||
warn = IN_NONE;
|
||||
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, Locale);
|
||||
#if 0
|
||||
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 *getformat(int modifier, char *normal, char *underscore,
|
||||
char *dash, char *zero) {
|
||||
switch (modifier) {
|
||||
case '_':
|
||||
return underscore;
|
||||
|
||||
case '-':
|
||||
return dash;
|
||||
|
||||
case '0':
|
||||
return zero;
|
||||
}
|
||||
|
||||
return normal;
|
||||
}
|
||||
|
||||
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 strftime_locale *Locale;
|
||||
{
|
||||
for ( ; *format; ++format) {
|
||||
if (*format == '%') {
|
||||
int modifier = 0;
|
||||
label:
|
||||
switch (*++format) {
|
||||
case '\0':
|
||||
--format;
|
||||
break;
|
||||
case 'A':
|
||||
pt = _add((t->tm_wday < 0 ||
|
||||
t->tm_wday >= DAYSPERWEEK) ?
|
||||
"?" : Locale->weekday[t->tm_wday],
|
||||
pt, ptlim, modifier);
|
||||
continue;
|
||||
case 'a':
|
||||
pt = _add((t->tm_wday < 0 ||
|
||||
t->tm_wday >= DAYSPERWEEK) ?
|
||||
"?" : Locale->wday[t->tm_wday],
|
||||
pt, ptlim, modifier);
|
||||
continue;
|
||||
case 'B':
|
||||
if (modifier == '-') {
|
||||
pt = _add((t->tm_mon < 0 ||
|
||||
t->tm_mon >= MONSPERYEAR) ?
|
||||
"?" : Locale->standalone_month[t->tm_mon],
|
||||
pt, ptlim, modifier);
|
||||
} else {
|
||||
pt = _add((t->tm_mon < 0 ||
|
||||
t->tm_mon >= MONSPERYEAR) ?
|
||||
"?" : Locale->month[t->tm_mon],
|
||||
pt, ptlim, modifier);
|
||||
}
|
||||
continue;
|
||||
case 'b':
|
||||
case 'h':
|
||||
pt = _add((t->tm_mon < 0 ||
|
||||
t->tm_mon >= MONSPERYEAR) ?
|
||||
"?" : Locale->mon[t->tm_mon],
|
||||
pt, ptlim, modifier);
|
||||
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, modifier);
|
||||
continue;
|
||||
case 'c':
|
||||
{
|
||||
int warn2 = IN_SOME;
|
||||
|
||||
pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, Locale);
|
||||
if (warn2 == IN_ALL)
|
||||
warn2 = IN_THIS;
|
||||
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,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%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 '_':
|
||||
case '-':
|
||||
case '0':
|
||||
case '^':
|
||||
case '#':
|
||||
modifier = *format;
|
||||
goto label;
|
||||
case 'e':
|
||||
pt = _conv(t->tm_mday,
|
||||
getformat(modifier, "%2d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'F':
|
||||
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, Locale);
|
||||
continue;
|
||||
case 'H':
|
||||
pt = _conv(t->tm_hour,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'I':
|
||||
pt = _conv((t->tm_hour % 12) ?
|
||||
(t->tm_hour % 12) : 12,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'j':
|
||||
pt = _conv(t->tm_yday + 1,
|
||||
getformat(modifier, "%03d", "%3d", "%d", "%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,
|
||||
getformat(modifier, "%2d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
#ifdef KITCHEN_SINK
|
||||
case 'K':
|
||||
/*
|
||||
** After all this time, still unclaimed!
|
||||
*/
|
||||
pt = _add("kitchen sink", pt, ptlim, modifier);
|
||||
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,
|
||||
getformat(modifier, "%2d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'M':
|
||||
pt = _conv(t->tm_min,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'm':
|
||||
pt = _conv(t->tm_mon + 1,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
continue;
|
||||
case 'n':
|
||||
pt = _add("\n", pt, ptlim, modifier);
|
||||
continue;
|
||||
case 'p':
|
||||
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
|
||||
Locale->pm :
|
||||
Locale->am,
|
||||
pt, ptlim, modifier);
|
||||
continue;
|
||||
case 'P':
|
||||
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
|
||||
Locale->pm :
|
||||
Locale->am,
|
||||
pt, ptlim, FORCE_LOWER_CASE);
|
||||
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,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%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, modifier);
|
||||
}
|
||||
continue;
|
||||
case 'T':
|
||||
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, Locale);
|
||||
continue;
|
||||
case 't':
|
||||
pt = _add("\t", pt, ptlim, modifier);
|
||||
continue;
|
||||
case 'U':
|
||||
pt = _conv((t->tm_yday + DAYSPERWEEK -
|
||||
t->tm_wday) / DAYSPERWEEK,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%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,
|
||||
getformat(modifier,
|
||||
"%02d",
|
||||
"%2d",
|
||||
"%d",
|
||||
"%02d"),
|
||||
pt, ptlim);
|
||||
else if (*format == 'g') {
|
||||
*warnp = IN_ALL;
|
||||
pt = _yconv(year, base, 0, 1,
|
||||
pt, ptlim, modifier);
|
||||
} else pt = _yconv(year, base, 1, 1,
|
||||
pt, ptlim, modifier);
|
||||
}
|
||||
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,
|
||||
getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%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, modifier);
|
||||
continue;
|
||||
case 'Y':
|
||||
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
|
||||
pt, ptlim, modifier);
|
||||
continue;
|
||||
case 'Z':
|
||||
#ifdef TM_ZONE
|
||||
if (t->TM_ZONE != NULL)
|
||||
pt = _add(t->TM_ZONE, pt, ptlim,
|
||||
modifier);
|
||||
else
|
||||
#endif /* defined TM_ZONE */
|
||||
if (t->tm_isdst >= 0)
|
||||
pt = _add(tzname[t->tm_isdst != 0],
|
||||
pt, ptlim, modifier);
|
||||
/*
|
||||
** 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, modifier);
|
||||
diff /= SECSPERMIN;
|
||||
diff = (diff / MINSPERHOUR) * 100 +
|
||||
(diff % MINSPERHOUR);
|
||||
pt = _conv(diff,
|
||||
getformat(modifier, "%04d",
|
||||
"%4d", "%d", "%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, 0);
|
||||
}
|
||||
|
||||
static char *
|
||||
_add(str, pt, ptlim, modifier)
|
||||
const char * str;
|
||||
char * pt;
|
||||
const char * const ptlim;
|
||||
int modifier;
|
||||
{
|
||||
int c;
|
||||
|
||||
switch (modifier) {
|
||||
case FORCE_LOWER_CASE:
|
||||
while (pt < ptlim && (*pt = tolower(*str++)) != '\0') {
|
||||
++pt;
|
||||
}
|
||||
break;
|
||||
|
||||
case '^':
|
||||
while (pt < ptlim && (*pt = toupper(*str++)) != '\0') {
|
||||
++pt;
|
||||
}
|
||||
break;
|
||||
|
||||
case '#':
|
||||
while (pt < ptlim && (c = *str++) != '\0') {
|
||||
if (isupper(c)) {
|
||||
c = tolower(c);
|
||||
} else if (islower(c)) {
|
||||
c = toupper(c);
|
||||
}
|
||||
*pt = c;
|
||||
++pt;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
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, modifier)
|
||||
const int a;
|
||||
const int b;
|
||||
const int convert_top;
|
||||
const int convert_yy;
|
||||
char * pt;
|
||||
const char * const ptlim;
|
||||
int modifier;
|
||||
{
|
||||
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, modifier);
|
||||
else pt = _conv(lead, getformat(modifier, "%02d",
|
||||
"%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
}
|
||||
if (convert_yy)
|
||||
pt = _conv(((trail < 0) ? -trail : trail),
|
||||
getformat(modifier, "%02d", "%2d", "%d", "%02d"),
|
||||
pt, ptlim);
|
||||
return pt;
|
||||
}
|
||||
|
||||
#ifdef LOCALE_HOME
|
||||
static struct lc_time_T *
|
||||
_loc P((void))
|
||||
{
|
||||
static const char locale_home[] = LOCALE_HOME;
|
||||
static const char lc_time[] = "LC_TIME";
|
||||
static char * locale_buf;
|
||||
|
||||
int fd;
|
||||
int oldsun; /* "...ain't got nothin' to do..." */
|
||||
char * lbuf;
|
||||
char * name;
|
||||
char * p;
|
||||
const char ** ap;
|
||||
const char * plim;
|
||||
char filename[FILENAME_MAX];
|
||||
struct stat st;
|
||||
size_t namesize;
|
||||
size_t bufsize;
|
||||
|
||||
/*
|
||||
** Use localebuf.mon[0] to signal whether locale is already set up.
|
||||
*/
|
||||
if (localebuf.mon[0])
|
||||
return &localebuf;
|
||||
name = setlocale(LC_TIME, (char *) NULL);
|
||||
if (name == NULL || *name == '\0')
|
||||
goto no_locale;
|
||||
/*
|
||||
** If the locale name is the same as our cache, use the cache.
|
||||
*/
|
||||
lbuf = locale_buf;
|
||||
if (lbuf != NULL && strcmp(name, lbuf) == 0) {
|
||||
p = lbuf;
|
||||
for (ap = (const char **) &localebuf;
|
||||
ap < (const char **) (&localebuf + 1);
|
||||
++ap)
|
||||
*ap = p += strlen(p) + 1;
|
||||
return &localebuf;
|
||||
}
|
||||
/*
|
||||
** Slurp the locale file into the cache.
|
||||
*/
|
||||
namesize = strlen(name) + 1;
|
||||
if (sizeof filename <
|
||||
((sizeof locale_home) + namesize + (sizeof lc_time)))
|
||||
goto no_locale;
|
||||
oldsun = 0;
|
||||
(void) sprintf(filename, "%s/%s/%s", locale_home, name, lc_time);
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
/*
|
||||
** Old Sun systems have a different naming and data convention.
|
||||
*/
|
||||
oldsun = 1;
|
||||
(void) sprintf(filename, "%s/%s/%s", locale_home,
|
||||
lc_time, name);
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0)
|
||||
goto no_locale;
|
||||
}
|
||||
if (fstat(fd, &st) != 0)
|
||||
goto bad_locale;
|
||||
if (st.st_size <= 0)
|
||||
goto bad_locale;
|
||||
bufsize = namesize + st.st_size;
|
||||
locale_buf = NULL;
|
||||
lbuf = (lbuf == NULL) ? malloc(bufsize) : realloc(lbuf, bufsize);
|
||||
if (lbuf == NULL)
|
||||
goto bad_locale;
|
||||
(void) strcpy(lbuf, name);
|
||||
p = lbuf + namesize;
|
||||
plim = p + st.st_size;
|
||||
if (read(fd, p, (size_t) st.st_size) != st.st_size)
|
||||
goto bad_lbuf;
|
||||
if (close(fd) != 0)
|
||||
goto bad_lbuf;
|
||||
/*
|
||||
** Parse the locale file into localebuf.
|
||||
*/
|
||||
if (plim[-1] != '\n')
|
||||
goto bad_lbuf;
|
||||
for (ap = (const char **) &localebuf;
|
||||
ap < (const char **) (&localebuf + 1);
|
||||
++ap) {
|
||||
if (p == plim)
|
||||
goto bad_lbuf;
|
||||
*ap = p;
|
||||
while (*p != '\n')
|
||||
++p;
|
||||
*p++ = '\0';
|
||||
}
|
||||
if (oldsun) {
|
||||
/*
|
||||
** SunOS 4 used an obsolescent format; see localdtconv(3).
|
||||
** c_fmt had the ``short format for dates and times together''
|
||||
** (SunOS 4 date, "%a %b %e %T %Z %Y" in the C locale);
|
||||
** date_fmt had the ``long format for dates''
|
||||
** (SunOS 4 strftime %C, "%A, %B %e, %Y" in the C locale).
|
||||
** Discard the latter in favor of the former.
|
||||
*/
|
||||
localebuf.date_fmt = localebuf.c_fmt;
|
||||
}
|
||||
/*
|
||||
** Record the successful parse in the cache.
|
||||
*/
|
||||
locale_buf = lbuf;
|
||||
|
||||
return &localebuf;
|
||||
|
||||
bad_lbuf:
|
||||
free(lbuf);
|
||||
bad_locale:
|
||||
(void) close(fd);
|
||||
no_locale:
|
||||
localebuf = C_time_locale;
|
||||
locale_buf = NULL;
|
||||
return &localebuf;
|
||||
}
|
||||
#endif /* defined LOCALE_HOME */
|
1950
libcutils/tztime.c
1950
libcutils/tztime.c
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue