diff options
| author | David Greenman <dg@FreeBSD.org> | 1995-08-28 05:07:13 +0000 |
|---|---|---|
| committer | David Greenman <dg@FreeBSD.org> | 1995-08-28 05:07:13 +0000 |
| commit | fe249e9798eddc97d49d279679a936813e6b1f56 (patch) | |
| tree | 3ea3797c01f5da4427d4f95b45af5a54082b1775 /lib/libc/stdtime | |
| parent | 1d6005f288c8f474daedafb5fdbed13e12af971f (diff) | |
Notes
Diffstat (limited to 'lib/libc/stdtime')
| -rw-r--r-- | lib/libc/stdtime/localtime.c | 340 | ||||
| -rw-r--r-- | lib/libc/stdtime/private.h | 189 | ||||
| -rw-r--r-- | lib/libc/stdtime/strftime.3 | 70 | ||||
| -rw-r--r-- | lib/libc/stdtime/strftime.c | 333 | ||||
| -rw-r--r-- | lib/libc/stdtime/tzfile.h | 16 |
5 files changed, 615 insertions, 333 deletions
diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index e0a7e9a84f7c..d6337ff8055d 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -1,6 +1,6 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)localtime.c 7.19"; +static char elsieid[] = "@(#)localtime.c 7.44"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -16,7 +16,9 @@ static char elsieid[] = "@(#)localtime.c 7.19"; #include "tzfile.h" #include "fcntl.h" -#define ACCESS_MODE O_RDONLY +/* +** SunOS 4.1.1 headers lack O_BINARY. +*/ #ifdef O_BINARY #define OPEN_MODE (O_RDONLY | O_BINARY) @@ -29,9 +31,9 @@ static char elsieid[] = "@(#)localtime.c 7.19"; /* ** Someone might make incorrect use of a time zone abbreviation: ** 1. They might reference tzname[0] before calling tzset (explicitly -** or implicitly). +** or implicitly). ** 2. They might reference tzname[1] before calling tzset (explicitly -** or implicitly). +** or implicitly). ** 3. They might reference tzname[1] after setting to a time zone ** in which Daylight Saving Time is never observed. ** 4. They might reference tzname[0] after setting to a time zone @@ -48,13 +50,16 @@ static char elsieid[] = "@(#)localtime.c 7.19"; #define WILDABBR " " #endif /* !defined WILDABBR */ -static const char GMT[] = "GMT"; +static char wildabbr[] = "WILDABBR"; + +static const char gmt[] = "GMT"; struct ttinfo { /* time type information */ long tt_gmtoff; /* GMT offset in seconds */ int tt_isdst; /* used to set tm_isdst */ int tt_abbrind; /* abbreviation list index */ int tt_ttisstd; /* TRUE if transition is std time */ + int tt_ttisgmt; /* TRUE if transition is GMT */ }; struct lsinfo { /* leap second information */ @@ -79,7 +84,7 @@ struct state { time_t ats[TZ_MAX_TIMES]; unsigned char types[TZ_MAX_TIMES]; struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof GMT), + char chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt), (2 * (MY_TZNAME_MAX + 1)))]; struct lsinfo lsis[TZ_MAX_LEAPS]; }; @@ -116,9 +121,13 @@ static int increment_overflow P((int * number, int delta)); static int normalize_overflow P((int * tensptr, int * unitsptr, int base)); static void settzname P((void)); -static time_t time1 P((struct tm * tmp, void (* funcp)(), +static time_t time1 P((struct tm * tmp, + void(*funcp) P((const time_t *, + long, struct tm *)), long offset)); -static time_t time2 P((struct tm *tmp, void (* funcp)(), +static time_t time2 P((struct tm *tmp, + void(*funcp) P((const time_t *, + long, struct tm*)), long offset, int * okayp)); static void timesub P((const time_t * timep, long offset, const struct state * sp, struct tm * tmp)); @@ -142,14 +151,29 @@ static struct state gmtmem; #define gmtptr (&gmtmem) #endif /* State Farm */ +#ifndef TZ_STRLEN_MAX +#define TZ_STRLEN_MAX 255 +#endif /* !defined TZ_STRLEN_MAX */ + +static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; static int gmt_is_set; char * tzname[2] = { - WILDABBR, - WILDABBR + wildabbr, + wildabbr }; +/* +** Section 4.12.3 of X3.159-1989 requires that +** Except for the strftime function, these functions [asctime, +** ctime, gmtime, localtime] return values in one of two static +** objects: a broken-down time structure and an array of char. +** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. +*/ + +static struct tm tm; + #ifdef USG_COMPAT time_t timezone = 0; int daylight = 0; @@ -166,20 +190,20 @@ const char * const codep; register long result; register int i; - result = 0; + result = (codep[0] & 0x80) ? ~0L : 0L; for (i = 0; i < 4; ++i) result = (result << 8) | (codep[i] & 0xff); return result; } static void -settzname() +settzname P((void)) { - register const struct state * const sp = lclptr; + register struct state * const sp = lclptr; register int i; - tzname[0] = WILDABBR; - tzname[1] = WILDABBR; + tzname[0] = wildabbr; + tzname[1] = wildabbr; #ifdef USG_COMPAT daylight = 0; timezone = 0; @@ -189,7 +213,7 @@ settzname() #endif /* defined ALTZONE */ #ifdef ALL_STATE if (sp == NULL) { - tzname[0] = tzname[1] = GMT; + tzname[0] = tzname[1] = gmt; return; } #endif /* defined ALL_STATE */ @@ -197,7 +221,7 @@ settzname() register const struct ttinfo * const ttisp = &sp->ttis[i]; tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; + &sp->chars[ttisp->tt_abbrind]; #ifdef USG_COMPAT if (ttisp->tt_isdst) daylight = 1; @@ -218,7 +242,7 @@ settzname() sp->types[i]]; tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; + &sp->chars[ttisp->tt_abbrind]; } } @@ -234,7 +258,14 @@ register struct state * const sp; if (name == NULL && (name = TZDEFAULT) == NULL) return -1; { - register int doaccess; + register int doaccess; + /* + ** Section 4.9.1 of the C standard says that + ** "FILENAME_MAX expands to an integral constant expression + ** that is the sie needed for an array of char large enough + ** to hold the longest file name string that the implementation + ** guarantees can be opened." + */ char fullname[FILENAME_MAX + 1]; if (name[0] == ':') @@ -255,39 +286,49 @@ register struct state * const sp; doaccess = TRUE; name = fullname; } - if (doaccess && access(name, ACCESS_MODE) != 0) + if (doaccess && access(name, R_OK) != 0) return -1; if ((fid = open(name, OPEN_MODE)) == -1) return -1; } { - register const struct tzhead * tzhp; - char buf[sizeof *sp + sizeof *tzhp]; - int ttisstdcnt; + struct tzhead * tzhp; + char buf[sizeof *sp + sizeof *tzhp]; + int ttisstdcnt; + int ttisgmtcnt; i = read(fid, buf, sizeof buf); - if (close(fid) != 0 || i < sizeof *tzhp) + if (close(fid) != 0) return -1; - tzhp = (struct tzhead *) buf; - ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt); - sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt); - sp->timecnt = (int) detzcode(tzhp->tzh_timecnt); - sp->typecnt = (int) detzcode(tzhp->tzh_typecnt); - sp->charcnt = (int) detzcode(tzhp->tzh_charcnt); + p = buf; + p += sizeof tzhp->tzh_reserved; + ttisstdcnt = (int) detzcode(p); + p += 4; + ttisgmtcnt = (int) detzcode(p); + p += 4; + sp->leapcnt = (int) detzcode(p); + p += 4; + sp->timecnt = (int) detzcode(p); + p += 4; + sp->typecnt = (int) detzcode(p); + p += 4; + sp->charcnt = (int) detzcode(p); + p += 4; if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS || sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES || sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES || sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS || - (ttisstdcnt != sp->typecnt && ttisstdcnt != 0)) + (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) || + (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0)) return -1; - if (i < sizeof *tzhp + - sp->timecnt * (4 + sizeof (char)) + - sp->typecnt * (4 + 2 * sizeof (char)) + - sp->charcnt * sizeof (char) + - sp->leapcnt * 2 * 4 + - ttisstdcnt * sizeof (char)) + if (i - (p - buf) < sp->timecnt * 4 + /* ats */ + sp->timecnt + /* types */ + sp->typecnt * (4 + 2) + /* ttinfos */ + sp->charcnt + /* chars */ + sp->leapcnt * (4 + 4) + /* lsinfos */ + ttisstdcnt + /* ttisstds */ + ttisgmtcnt) /* ttisgmts */ return -1; - p = buf + sizeof *tzhp; for (i = 0; i < sp->timecnt; ++i) { sp->ats[i] = detzcode(p); p += 4; @@ -336,6 +377,19 @@ register struct state * const sp; return -1; } } + for (i = 0; i < sp->typecnt; ++i) { + register struct ttinfo * ttisp; + + ttisp = &sp->ttis[i]; + if (ttisgmtcnt == 0) + ttisp->tt_ttisgmt = FALSE; + else { + ttisp->tt_ttisgmt = *p++; + if (ttisp->tt_ttisgmt != TRUE && + ttisp->tt_ttisgmt != FALSE) + return -1; + } + } } return 0; } @@ -414,10 +468,16 @@ long * const secsp; { int num; - strp = getnum(strp, &num, 0, HOURSPERDAY); + /* + ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like + ** "M10.4.6/26", which does not conform to Posix, + ** but which specifies the equivalent of + ** ``02:00 on the first Sunday on or after 23 Oct''. + */ + strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1); if (strp == NULL) return NULL; - *secsp = num * SECSPERHOUR; + *secsp = num * (long) SECSPERHOUR; if (*strp == ':') { ++strp; strp = getnum(strp, &num, 0, MINSPERHOUR - 1); @@ -426,7 +486,8 @@ long * const secsp; *secsp += num * SECSPERMIN; if (*strp == ':') { ++strp; - strp = getnum(strp, &num, 0, SECSPERMIN - 1); + /* `SECSPERMIN' allows for leap seconds. */ + strp = getnum(strp, &num, 0, SECSPERMIN); if (strp == NULL) return NULL; *secsp += num; @@ -536,6 +597,7 @@ const long offset; register int i; int d, m1, yy0, yy1, yy2, dow; + INITIALIZE(value); leapyear = isleap(year); switch (rulep->r_type) { @@ -626,8 +688,8 @@ const int lastditch; { const char * stdname; const char * dstname; - int stdlen; - int dstlen; + size_t stdlen; + size_t dstlen; long stdoffset; long dstoffset; register time_t * atp; @@ -635,6 +697,7 @@ const int lastditch; register char * cp; register int load_result; + INITIALIZE(dstname); stdname = name; if (lastditch) { stdlen = strlen(name); /* length of standard zone name */ @@ -721,82 +784,88 @@ const int lastditch; SECSPERDAY; } } else { - int sawstd; - int sawdst; - long stdfix; - long dstfix; - long oldfix; - int isdst; + register long theirstdoffset; + register long theirdstoffset; + register long theiroffset; + register int isdst; register int i; + register int j; if (*name != '\0') return -1; if (load_result != 0) return -1; /* - ** Compute the difference between the real and - ** prototype standard and summer time offsets - ** from GMT, and put the real standard and summer - ** time offsets into the rules in place of the - ** prototype offsets. + ** Initial values of theirstdoffset and theirdstoffset. */ - sawstd = FALSE; - sawdst = FALSE; - stdfix = 0; - dstfix = 0; - for (i = 0; i < sp->typecnt; ++i) { - if (sp->ttis[i].tt_isdst) { - oldfix = dstfix; - dstfix = sp->ttis[i].tt_gmtoff + - dstoffset; - if (sawdst && (oldfix != dstfix)) - return -1; - sp->ttis[i].tt_gmtoff = -dstoffset; - sp->ttis[i].tt_abbrind = stdlen + 1; - sawdst = TRUE; - } else { - oldfix = stdfix; - stdfix = sp->ttis[i].tt_gmtoff + - stdoffset; - if (sawstd && (oldfix != stdfix)) - return -1; - sp->ttis[i].tt_gmtoff = -stdoffset; - sp->ttis[i].tt_abbrind = 0; - sawstd = TRUE; + theirstdoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (!sp->ttis[j].tt_isdst) { + theirstdoffset = -sp->ttis[j].tt_gmtoff; + break; + } + } + theirdstoffset = 0; + for (i = 0; i < sp->timecnt; ++i) { + j = sp->types[i]; + if (sp->ttis[j].tt_isdst) { + theirdstoffset = -sp->ttis[j].tt_gmtoff; + break; } } /* - ** Make sure we have both standard and summer time. + ** Initially we're assumed to be in standard time. */ - if (!sawdst || !sawstd) - return -1; + isdst = FALSE; + theiroffset = theirstdoffset; /* - ** Now correct the transition times by shifting - ** them by the difference between the real and - ** prototype offsets. Note that this difference - ** can be different in standard and summer time; - ** the prototype probably has a 1-hour difference - ** between standard and summer time, but a different - ** difference can be specified in TZ. + ** Now juggle transition times and types + ** tracking offsets as you do. */ - isdst = FALSE; /* we start in standard time */ for (i = 0; i < sp->timecnt; ++i) { - register const struct ttinfo * ttisp; - - /* - ** If summer time is in effect, and the - ** transition time was not specified as - ** standard time, add the summer time - ** offset to the transition time; - ** otherwise, add the standard time offset - ** to the transition time. - */ - ttisp = &sp->ttis[sp->types[i]]; - sp->ats[i] += - (isdst && !ttisp->tt_ttisstd) ? - dstfix : stdfix; - isdst = ttisp->tt_isdst; + j = sp->types[i]; + sp->types[i] = sp->ttis[j].tt_isdst; + if (sp->ttis[j].tt_ttisgmt) { + /* No adjustment to transition time */ + } else { + /* + ** If summer time is in effect, and the + ** transition time was not specified as + ** standard time, add the summer time + ** offset to the transition time; + ** otherwise, add the standard time + ** offset to the transition time. + */ + /* + ** Transitions from DST to DDST + ** will effectively disappear since + ** POSIX provides for only one DST + ** offset. + */ + if (isdst && !sp->ttis[j].tt_ttisstd) { + sp->ats[i] += dstoffset - + theirdstoffset; + } else { + sp->ats[i] += stdoffset - + theirstdoffset; + } + } + theiroffset = -sp->ttis[j].tt_gmtoff; + if (sp->ttis[j].tt_isdst) + theirdstoffset = theiroffset; + else theirstdoffset = theiroffset; } + /* + ** Finally, fill in ttis. + ** ttisstd and ttisgmt need not be handled. + */ + sp->ttis[0].tt_gmtoff = -stdoffset; + sp->ttis[0].tt_isdst = FALSE; + sp->ttis[0].tt_abbrind = 0; + sp->ttis[1].tt_gmtoff = -dstoffset; + sp->ttis[1].tt_isdst = TRUE; + sp->ttis[1].tt_abbrind = stdlen + 1; } } else { dstlen = 0; @@ -826,17 +895,24 @@ static void gmtload(sp) struct state * const sp; { - if (tzload(GMT, sp) != 0) - (void) tzparse(GMT, sp, TRUE); + if (tzload(gmt, sp) != 0) + (void) tzparse(gmt, sp, TRUE); } #ifndef STD_INSPIRED +/* +** A non-static declaration of tzsetwall in a system header file +** may cause a warning about this upcoming static declaration... +*/ static #endif /* !defined STD_INSPIRED */ void -tzsetwall() +tzsetwall P((void)) { - lcl_is_set = TRUE; + if (lcl_is_set < 0) + return; + lcl_is_set = -1; + #ifdef ALL_STATE if (lclptr == NULL) { lclptr = (struct state *) malloc(sizeof *lclptr); @@ -852,7 +928,7 @@ tzsetwall() } void -tzset() +tzset P((void)) { register const char * name; @@ -861,7 +937,13 @@ tzset() tzsetwall(); return; } - lcl_is_set = TRUE; + + if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) + return; + lcl_is_set = (strlen(name) < sizeof(lcl_TZname)); + if (lcl_is_set) + (void) strcpy(lcl_TZname, name); + #ifdef ALL_STATE if (lclptr == NULL) { lclptr = (struct state *) malloc(sizeof *lclptr); @@ -879,7 +961,7 @@ tzset() lclptr->timecnt = 0; lclptr->ttis[0].tt_gmtoff = 0; lclptr->ttis[0].tt_abbrind = 0; - (void) strcpy(lclptr->chars, GMT); + (void) strcpy(lclptr->chars, gmt); } else if (tzload(name, lclptr) != 0) if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) (void) gmtload(lclptr); @@ -902,13 +984,11 @@ const time_t * const timep; const long offset; struct tm * const tmp; { - register const struct state * sp; + register struct state * sp; register const struct ttinfo * ttisp; register int i; const time_t t = *timep; - if (!lcl_is_set) - tzset(); sp = lclptr; #ifdef ALL_STATE if (sp == NULL) { @@ -938,9 +1018,9 @@ struct tm * const tmp; */ timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; - tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind]; + tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE - tmp->TM_ZONE = (char *)&sp->chars[ttisp->tt_abbrind]; + tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ } @@ -948,8 +1028,7 @@ struct tm * localtime(timep) const time_t * const timep; { - static struct tm tm; - + tzset(); localsub(timep, 0L, &tm); return &tm; } @@ -980,11 +1059,11 @@ struct tm * const tmp; ** but this is no time for a treasure hunt. */ if (offset != 0) - tmp->TM_ZONE = WILDABBR; + tmp->TM_ZONE = wildabbr; else { #ifdef ALL_STATE if (gmtptr == NULL) - tmp->TM_ZONE = GMT; + tmp->TM_ZONE = gmt; else tmp->TM_ZONE = gmtptr->chars; #endif /* defined ALL_STATE */ #ifndef ALL_STATE @@ -998,8 +1077,6 @@ struct tm * gmtime(timep) const time_t * const timep; { - static struct tm tm; - gmtsub(timep, 0L, &tm); return &tm; } @@ -1011,8 +1088,6 @@ offtime(timep, offset) const time_t * const timep; const long offset; { - static struct tm tm; - gmtsub(timep, offset, &tm); return &tm; } @@ -1074,7 +1149,7 @@ register struct tm * const tmp; days = -24855; rem = -11648; } -#endif /* mc68k */ +#endif /* defined mc68k */ rem += (offset - corr); while (rem < 0) { rem += SECSPERDAY; @@ -1127,6 +1202,12 @@ char * ctime(timep) const time_t * const timep; { +/* +** Section 4.12.3.2 of X3.159-1989 requires that +** The ctime funciton converts the calendar time pointed to by timer +** to local time in the form of a string. It is equivalent to +** asctime(localtime(timer)) +*/ return asctime(localtime(timep)); } @@ -1152,7 +1233,7 @@ increment_overflow(number, delta) int * number; int delta; { - int number0; + int number0; number0 = *number; *number += delta; @@ -1193,7 +1274,7 @@ register const struct tm * const btmp; static time_t time2(tmp, funcp, offset, okayp) struct tm * const tmp; -void (* const funcp)(); +void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; int * const okayp; { @@ -1338,7 +1419,7 @@ label: static time_t time1(tmp, funcp, offset) struct tm * const tmp; -void (* const funcp)(); +void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; { register time_t t; @@ -1401,6 +1482,7 @@ time_t mktime(tmp) struct tm * const tmp; { + tzset(); return time1(tmp, localsub, 0L); } @@ -1475,8 +1557,6 @@ time_t * timep; register struct lsinfo * lp; register int i; - if (!lcl_is_set) - (void) tzset(); sp = lclptr; i = sp->leapcnt; while (--i >= 0) { @@ -1491,6 +1571,7 @@ time_t time2posix(t) time_t t; { + tzset(); return t - leapcorr(&t); } @@ -1501,6 +1582,7 @@ time_t t; time_t x; time_t y; + tzset(); /* ** For a positive leap second hit, the result ** is not unique. For a negative leap second diff --git a/lib/libc/stdtime/private.h b/lib/libc/stdtime/private.h index 8ddb74ddbeba..3ed6e0ba07d6 100644 --- a/lib/libc/stdtime/private.h +++ b/lib/libc/stdtime/private.h @@ -26,36 +26,69 @@ #ifndef lint #ifndef NOID -static char privatehid[] = "@(#)private.h 7.5"; +/*static char privatehid[] = "@(#)private.h 7.33";*/ #endif /* !defined NOID */ #endif /* !defined lint */ /* -** const +** Defaults for preprocessor symbols. +** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'. */ -#ifndef const -#ifndef __STDC__ -#define const -#endif /* !defined __STDC__ */ -#endif /* !defined const */ +#ifndef HAVE_ADJTIME +#define HAVE_ADJTIME 1 +#endif /* !defined HAVE_ADJTIME */ + +#ifndef HAVE_SETTIMEOFDAY +#define HAVE_SETTIMEOFDAY 3 +#endif /* !defined HAVE_SETTIMEOFDAY */ + +#ifndef HAVE_UNISTD_H +#define HAVE_UNISTD_H 1 +#endif /* !defined HAVE_UNISTD_H */ + +/* +** Nested includes +*/ + +#include "sys/types.h" /* for time_t */ +#include "stdio.h" +#include "ctype.h" +#include "errno.h" +#include "string.h" +#include "limits.h" /* for CHAR_BIT */ +#include "time.h" +#include "stdlib.h" + +#if HAVE_UNISTD_H - 0 +#include "unistd.h" /* for F_OK and R_OK */ +#endif /* HAVE_UNISTD_H - 0 */ + +#if !(HAVE_UNISTD_H - 0) +#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 - 0) */ /* -** void +** Workarounds for compilers/systems. */ -#ifndef void +/* +** SunOS 4.1.1 cc lacks const. +*/ + +#ifndef const #ifndef __STDC__ -#ifndef vax -#ifndef sun -#define void char -#endif /* !defined sun */ -#endif /* !defined vax */ +#define const #endif /* !defined __STDC__ */ -#endif /* !defined void */ +#endif /* !defined const */ /* -** P((args)) +** SunOS 4.1.1 cc lacks prototypes. */ #ifndef P @@ -63,36 +96,29 @@ static char privatehid[] = "@(#)private.h 7.5"; #define P(x) x #endif /* defined __STDC__ */ #ifndef __STDC__ -#define ASTERISK * -#define P(x) ( /ASTERISK x ASTERISK/ ) +#define P(x) () #endif /* !defined __STDC__ */ #endif /* !defined P */ /* -** genericptr_t +** SunOS 4.1.1 headers lack EXIT_SUCCESS. */ -#ifdef __STDC__ -typedef void * genericptr_t; -#endif /* defined __STDC__ */ -#ifndef __STDC__ -typedef char * genericptr_t; -#endif /* !defined __STDC__ */ +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif /* !defined EXIT_SUCCESS */ -#include "sys/types.h" /* for time_t */ -#include "stdio.h" -#include "ctype.h" -#include "errno.h" -#include "string.h" -#include "limits.h" /* for CHAR_BIT */ -#ifndef _TIME_ -#include "time.h" -#endif /* !defined _TIME_ */ +/* +** SunOS 4.1.1 headers lack EXIT_FAILURE. +*/ -#ifndef remove -extern int unlink P((const char * filename)); -#define remove unlink -#endif /* !defined remove */ +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif /* !defined EXIT_FAILURE */ + +/* +** SunOS 4.1.1 headers lack FILENAME_MAX. +*/ #ifndef FILENAME_MAX @@ -111,62 +137,18 @@ extern int unlink P((const char * filename)); #endif /* !defined FILENAME_MAX */ -#ifndef EXIT_SUCCESS -#define EXIT_SUCCESS 0 -#endif /* !defined EXIT_SUCCESS */ - -#ifndef EXIT_FAILURE -#define EXIT_FAILURE 1 -#endif /* !defined EXIT_FAILURE */ - -#ifdef __STDC__ - -#define alloc_size_t size_t -#define qsort_size_t size_t -#define fwrite_size_t size_t - -#endif /* defined __STDC__ */ -#ifndef __STDC__ - -#ifndef alloc_size_t -#define alloc_size_t unsigned -#endif /* !defined alloc_size_t */ - -#ifndef qsort_size_t -#ifdef USG -#define qsort_size_t unsigned -#endif /* defined USG */ -#ifndef USG -#define qsort_size_t int -#endif /* !defined USG */ -#endif /* !defined qsort_size_t */ - -#ifndef fwrite_size_t -#define fwrite_size_t int -#endif /* !defined fwrite_size_t */ - -#ifndef USG -extern char * sprintf P((char * buf, const char * format, ...)); -#endif /* !defined USG */ - -#endif /* !defined __STDC__ */ - /* -** Ensure that these are declared--redundantly declaring them shouldn't hurt. +** SunOS 4.1.1 libraries lack remove. */ -extern char * getenv P((const char * name)); -extern genericptr_t malloc P((alloc_size_t size)); -extern genericptr_t calloc P((alloc_size_t nelem, alloc_size_t elsize)); -extern genericptr_t realloc P((genericptr_t oldptr, alloc_size_t newsize)); +#ifndef remove +extern int unlink P((const char * filename)); +#define remove unlink +#endif /* !defined remove */ -#ifdef USG -extern void exit P((int s)); -extern void qsort P((genericptr_t base, qsort_size_t nelem, - qsort_size_t elsize, int (*comp)())); -extern void perror P((const char * string)); -extern void free P((char * buf)); -#endif /* defined USG */ +/* +** Finally, some convenience items. +*/ #ifndef TRUE #define TRUE 1 @@ -188,8 +170,31 @@ extern void free P((char * buf)); #endif /* !defined INT_STRLEN_MAXIMUM */ /* -** UNIX is a registered trademark of AT&T. -** VAX is a trademark of Digital Equipment Corporation. +** 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 */ + +/* +** UNIX was a registered trademark of UNIX System Laboratories in 1993. */ #endif /* !defined PRIVATE_H */ diff --git a/lib/libc/stdtime/strftime.3 b/lib/libc/stdtime/strftime.3 index fd510ba7730e..b0647b3b1521 100644 --- a/lib/libc/stdtime/strftime.3 +++ b/lib/libc/stdtime/strftime.3 @@ -81,33 +81,44 @@ Each conversion specification is replaced by the characters as follows which are then copied into the buffer. .Bl -tag -width "xxxx" .It Cm \&%A -is replaced by the full weekday name. +is replaced by national representation of the full weekday name. .It Cm %a -is replaced by the abbreviated weekday name, where the abbreviation +is replaced by national representation of +the abbreviated weekday name, where the abbreviation is the first three characters. .It Cm \&%B -is replaced by the full month name. -.It Cm %b or %h -is replaced by the abbreviated month name, where the abbreviation is +is replaced by national representation of the full month name. +.It Cm %b +is replaced by national representation of +the abbreviated month name, where the abbreviation is the first three characters. .It Cm \&%C -is equivalent to -.Dq Li %a %b %e %H:%M:%S %Y -(the format produced by -.Xr asctime 3 . +is replaced by (year / 100) as decimal number; single +digits are preceded by a zero. .It Cm %c +is replaced by national representation of time and date +(the format is similar with produced by +.Xr asctime 3 ) . +.It Cm \&%D is equivalent to .Dq Li %m/%d/%y . -.It Cm \&%D -is replaced by the date in the format -.Dq Ql mm/dd/yy . .It Cm %d is replaced by the day of the month as a decimal number (01-31). +.It Cm \&%E* +POSIX locale extensions. +The sequences +%Ec %EC %Ex %Ey %EY +%Od %Oe %OH %OI %Om %OM +%OS %Ou %OU %OV %Ow %OW %Oy +are supposed to provide alternate +representations. .It Cm %e is replaced by the day of month as a decimal number (1-31); single digits are preceded by a blank. .It Cm \&%H is replaced by the hour (24-hour clock) as a decimal number (00-23). +.It Cm %h +the same as %b. .It Cm \&%I is replaced by the hour (12-hour clock) as a decimal number (01-12). .It Cm %j @@ -124,46 +135,63 @@ is replaced by the minute as a decimal number (00-59). is replaced by the month as a decimal number (01-12). .It Cm %n is replaced by a newline. +.It Cm \&%O* +the same as %E*. .It Cm %p -is replaced by either -.Dq Tn AM +is replaced by national representation of either +"ante meridiem" or -.Dq Tn PM +"post meridiem" as appropriate. .It Cm \&%R is equivalent to -.Dq Li %H:%M +.Dq Li %H:%M . .It Cm %r is equivalent to .Dq Li %I:%M:%S %p . -.It Cm %t -is replaced by a tab. .It Cm \&%S is replaced by the second as a decimal number (00-60). .It Cm %s is replaced by the number of seconds since the Epoch, UTC (see .Xr mktime 3 ) . -.It Cm \&%T No or Cm \&%X +.It Cm \&%T is equivalent to .Dq Li %H:%M:%S . +.It Cm %t +is replaced by a tab. .It Cm \&%U is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number (00-53). +.It Cm %u +is replaced by the weekday (Monday as the first day of the week) +as a decimal number (1-7). +.It Cm \&%V +is replaced by the week number of the year (the first +Monday as the first day of week 1) as a +decimal number (01-53). +.It Cm %v +is equivalent to +.Dq Li %e-%b-%Y . .It Cm \&%W is replaced by the week number of the year (Monday as the first day of the week) as a decimal number (00-53). .It Cm %w is replaced by the weekday (Sunday as the first day of the week) as a decimal number (0-6). +.It Cm \&%X +is replaced by national representation of the time. .It Cm %x -is equivalent to -.Dq Li %m/%d/%y %H:%M:%S . +is replaced by national representation of the date. .It Cm \&%Y is replaced by the year with century as a decimal number. .It Cm %y is replaced by the year without century as a decimal number (00-99). .It Cm \&%Z is replaced by the time zone name. +.It Cm %+ +is replaced by national representation of the date and time +(the format is similar with produced by +.Xr date 1 ) . .It Cm %% is replaced by .Ql % . diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c index 1c50d65d4a68..832417541b9d 100644 --- a/lib/libc/stdtime/strftime.c +++ b/lib/libc/stdtime/strftime.c @@ -1,16 +1,3 @@ -#ifndef lint -#ifndef NOID -static char elsieid[] = "@(#)strftime.c 7.19"; -/* -** Based on the UCB version with the ID appearing below. -** This is ANSIish only when time is treated identically in all locales and -** 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. @@ -28,49 +15,121 @@ static char elsieid[] = "@(#)strftime.c 7.19"; * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +#ifdef LIBC_RCS +static const char rcsid[] = + "$Id: strftime.c,v 1.5 1995/08/07 23:35:41 ache Exp $"; +#endif + +#ifndef lint +#ifndef NOID +static const char elsieid[] = "@(#)strftime.c 7.38"; +/* +** 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" + #ifndef LIBC_SCCS #ifndef lint -static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89"; +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 <rune.h> /* for _PATH_LOCALE */ +#include <sys/stat.h> -static const char afmt[][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" -}; -static const char Afmt[][10] = { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", - "Saturday" -}; -static const char bfmt[][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", - "Oct", "Nov", "Dec" +#define LOCALE_HOME _PATH_LOCALE + +struct lc_time_T { + const char * mon[12]; + const char * month[12]; + const char * wday[7]; + const char * weekday[7]; + const char * X_fmt; + const char * x_fmt; + const char * c_fmt; + const char * am; + const char * pm; + const char * date_fmt; }; -static const char Bfmt[][10] = { - "January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December" + +static struct lc_time_T localebuf; +static struct lc_time_T * _loc P((void)); +static int using_locale; + +#define Locale (using_locale ? &localebuf : &C_time_locale) + +static const struct lc_time_T C_time_locale = { + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }, { + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" + }, { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }, + + /* X_fmt */ + "%H:%M:%S", + + /* + ** x_fmt + ** Since the C language standard calls for + ** "date, using locale's date format," anything goes. + ** Using just numbers (as here) makes Quakers happier; + ** it's also compatible with SVR4. + */ + "%m/%d/%y", + + /* + ** c_fmt (ctime-compatible) + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%a %b %e %X %Y", + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %X %Z %Y" }; -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 *)); -static char *_secs P((const struct tm *, char *, const char *)); +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 *)); +static char * _secs P((const struct tm *, char *, const char *)); size_t strftime P((char *, size_t, const char *, const struct tm *)); -extern char *tzname[]; +extern char * tzname[]; size_t strftime(s, maxsize, format, t) - char *s; - size_t maxsize; - const char *format; - const struct tm *t; + char *const s; + const size_t maxsize; + const char *const format; + const struct tm *const t; { char *p; - p = _fmt(format, t, s, s + maxsize); + tzset(); + p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize); if (p == s + maxsize) return 0; *p = '\0'; @@ -80,36 +139,37 @@ strftime(s, maxsize, format, t) static char * _fmt(format, t, pt, ptlim) const char *format; - const struct tm *t; + const struct tm *const t; char *pt; - const char *ptlim; + const char *const ptlim; { - for (; *format; ++format) { + for ( ; *format; ++format) { if (*format == '%') { label: - switch(*++format) { + switch (*++format) { case '\0': --format; break; case 'A': pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ? - "?" : Afmt[t->tm_wday], pt, ptlim); + "?" : Locale->weekday[t->tm_wday], + pt, ptlim); continue; case 'a': pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ? - "?" : afmt[t->tm_wday], pt, ptlim); + "?" : Locale->wday[t->tm_wday], + pt, ptlim); continue; case 'B': pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ? - "?" : Bfmt[t->tm_mon], pt, ptlim); + "?" : Locale->month[t->tm_mon], + pt, ptlim); continue; case 'b': case 'h': pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ? - "?" : bfmt[t->tm_mon], pt, ptlim); - continue; - case 'c': - pt = _fmt("%D %X", t, pt, ptlim); + "?" : Locale->mon[t->tm_mon], + pt, ptlim); continue; case 'C': /* @@ -122,27 +182,10 @@ label: pt = _conv((t->tm_year + TM_YEAR_BASE) / 100, "%02d", pt, ptlim); continue; - case 'D': - pt = _fmt("%m/%d/%y", t, pt, ptlim); + case 'c': + pt = _fmt(Locale->c_fmt, t, pt, ptlim); continue; - case 'x': - /* - ** Version 3.0 of strftime from Arnold Robbins - ** (arnold@skeeve.atl.ga.us) does the - ** equivalent of... - ** _fmt("%a %b %e %Y"); - ** ...for %x; since the X3J11 C language - ** standard calls for "date, using locale's - ** date format," anything goes. Using just - ** numbers (as here) makes Quakers happier. - ** Word from Paul Eggert (eggert@twinsun.com) - ** is that %Y-%m-%d is the ISO standard date - ** format, specified in ISO 2014 and later - ** ISO 8601:1988, with a summary available in - ** pub/doc/ISO/english/ISO8601.ps.Z on - ** ftp.uni-erlangen.de. - ** (ado, 5/30/93) - */ + case 'D': pt = _fmt("%m/%d/%y", t, pt, ptlim); continue; case 'd': @@ -221,7 +264,9 @@ label: pt = _add("\n", pt, ptlim); continue; case 'p': - pt = _add(t->tm_hour >= 12 ? "PM" : "AM", + pt = _add((t->tm_hour >= 12) ? + Locale->pm : + Locale->am, pt, ptlim); continue; case 'R': @@ -237,7 +282,6 @@ label: pt = _secs(t, pt, ptlim); continue; case 'T': - case 'X': pt = _fmt("%H:%M:%S", t, pt, ptlim); continue; case 't': @@ -278,11 +322,12 @@ label: ** 1 falls on a Thursday, are December 29-31 ** of the PREVIOUS year part of week 1??? ** (ado 5/24/93) - ** + */ + /* ** You are understood not to expect this. */ { - int i; + int i; i = (t->tm_yday + 10 - (t->tm_wday ? (t->tm_wday - 1) : 6)) / 7; @@ -297,7 +342,7 @@ label: ** Fri Jan 1: 53 ** Sun Jan 1: 52 ** Sat Jan 1: 53 if previous - ** year a leap + ** year a leap ** year, else 52 */ if (i == TM_FRIDAY) @@ -336,6 +381,12 @@ label: case 'w': pt = _conv(t->tm_wday, "%d", pt, ptlim); continue; + case 'X': + pt = _fmt(Locale->X_fmt, t, pt, ptlim); + continue; + case 'x': + pt = _fmt(Locale->x_fmt, t, pt, ptlim); + continue; case 'y': pt = _conv((t->tm_year + TM_YEAR_BASE) % 100, "%02d", pt, ptlim); @@ -345,16 +396,17 @@ label: pt, ptlim); continue; case 'Z': -#ifdef TM_ZONE - if (t->TM_ZONE) - pt = _add(t->TM_ZONE, pt, ptlim); + if (t->tm_zone != NULL) + pt = _add(t->tm_zone, pt, ptlim); else -#endif /* defined TM_ZONE */ if (t->tm_isdst == 0 || t->tm_isdst == 1) { pt = _add(tzname[t->tm_isdst], pt, ptlim); } else pt = _add("?", pt, ptlim); continue; + case '+': + pt = _fmt(Locale->date_fmt, t, pt, ptlim); + continue; case '%': /* * X311J/88-090 (4.12.3.5): if conversion char is @@ -374,12 +426,12 @@ label: static char * _conv(n, format, pt, ptlim) - int n; - const char *format; - char *pt; - const char *ptlim; + const int n; + const char *const format; + char *const pt; + const char *const ptlim; { - char buf[INT_STRLEN_MAXIMUM(int) + 1]; + char buf[INT_STRLEN_MAXIMUM(int) + 1]; (void) sprintf(buf, format, n); return _add(buf, pt, ptlim); @@ -391,25 +443,130 @@ _secs(t, pt, ptlim) char *pt; const char *ptlim; { - static char buf[INT_STRLEN_MAXIMUM(int) + 1]; + char buf[INT_STRLEN_MAXIMUM(int) + 1]; register time_t s; - register char *p; struct tm tmp; /* Make a copy, mktime(3) modifies the tm struct. */ tmp = *t; s = mktime(&tmp); - (void) sprintf(buf, "%d", s); - return(_add(buf, pt, ptlim)); + (void) sprintf(buf, "%ld", s); + return _add(buf, pt, ptlim); } - + static char * _add(str, pt, ptlim) const char *str; char *pt; - const char *ptlim; + const char *const ptlim; { while (pt < ptlim && (*pt = *str++) != '\0') ++pt; return pt; } + +extern char *_PathLocale; + +int +__time_load_locale(const char *name) +{ + static const char lc_time[] = "LC_TIME"; + static char * locale_buf; + static char locale_buf_C[] = "C"; + + int fd; + char * lbuf; + char * p; + const char ** ap; + const char * plim; + char filename[FILENAME_MAX]; + struct stat st; + size_t namesize; + size_t bufsize; + + using_locale = 0; + + if (!strcmp(name, "C") || !strcmp(name, "POSIX")) + return 0; + + 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; + using_locale = 1; + return 0; + } + /* + ** Slurp the locale file into the cache. + */ + namesize = strlen(name) + 1; + + snprintf(filename, sizeof filename, + "%s/%s/%s", + _PathLocale, name, lc_time); + fd = open(filename, O_RDONLY); + if (fd < 0) { + goto no_locale; + } + if (fstat(fd, &st) != 0) + goto bad_locale; + if (st.st_size <= 0) + goto bad_locale; + bufsize = namesize + st.st_size; + locale_buf = NULL; + lbuf = (lbuf == NULL || lbuf == locale_buf_C) ? + malloc(bufsize) : realloc(lbuf, bufsize); + if (lbuf == NULL) + goto bad_locale; + (void) strcpy(lbuf, name); + p = lbuf + namesize; + plim = p + st.st_size; + if (read(fd, p, (size_t) st.st_size) != st.st_size) + goto bad_lbuf; + if (close(fd) != 0) + goto bad_lbuf; + /* + ** Parse the locale file into localebuf. + */ + if (plim[-1] != '\n') + goto bad_lbuf; + for (ap = (const char **) &localebuf; + ap < (const char **) (&localebuf + 1); + ++ap) { + if (p == plim) + goto bad_lbuf; + *ap = p; + while (*p != '\n') + ++p; + *p++ = '\0'; + } + /* + ** Record the successful parse in the cache. + */ + locale_buf = lbuf; + + using_locale = 1; + return 0; + +bad_lbuf: + free(lbuf); +bad_locale: + (void) close(fd); +no_locale: + /* + * XXX - This may not be the correct thing to do in this case. + * setlocale() assumes that we left the old locale alone. + */ + locale_buf = locale_buf_C; + localebuf = C_time_locale; + return -1; +} diff --git a/lib/libc/stdtime/tzfile.h b/lib/libc/stdtime/tzfile.h index 9b98306080bb..4ba002569dfc 100644 --- a/lib/libc/stdtime/tzfile.h +++ b/lib/libc/stdtime/tzfile.h @@ -16,7 +16,7 @@ #ifndef lint #ifndef NOID -static char tzfilehid[] = "@(#)tzfile.h 7.4"; +/*static char tzfilehid[] = "@(#)tzfile.h 7.6";*/ #endif /* !defined NOID */ #endif /* !defined lint */ @@ -41,7 +41,8 @@ static char tzfilehid[] = "@(#)tzfile.h 7.4"; */ struct tzhead { - char tzh_reserved[24]; /* reserved for future use */ + char tzh_reserved[20]; /* reserved for future use */ + 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 */ @@ -67,6 +68,11 @@ struct tzhead { ** 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 GMT, if FALSE, +** transition time is local time +** if absent, transition times are +** assumed to be local time */ /* @@ -89,7 +95,11 @@ struct tzhead { #define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ #endif /* !defined NOSOLAR */ #ifdef NOSOLAR -#define TZ_MAX_TYPES 10 /* Maximum number of local time types */ +/* +** Must be at least 14 for Europe/Riga as of Jan 12 1995, +** as noted by Earl Chew <earl@hpato.aus.hp.com>. +*/ +#define TZ_MAX_TYPES 20 /* Maximum number of local time types */ #endif /* !defined NOSOLAR */ #endif /* !defined TZ_MAX_TYPES */ |
