diff options
| author | Garrett Wollman <wollman@FreeBSD.org> | 1996-07-18 18:05:09 +0000 |
|---|---|---|
| committer | Garrett Wollman <wollman@FreeBSD.org> | 1996-07-18 18:05:09 +0000 |
| commit | 979a211643ccba0ec4121184236acd4ffa1a8dea (patch) | |
| tree | 556604079b0f29ac467efe87fa5772892d0018b8 | |
| parent | 89e2ea2b0f066d599b1e71a3e3844cdf1661d784 (diff) | |
Notes
| -rw-r--r-- | lib/libc/stdtime/asctime.c | 7 | ||||
| -rw-r--r-- | lib/libc/stdtime/difftime.c | 15 | ||||
| -rw-r--r-- | lib/libc/stdtime/localtime.c | 443 | ||||
| -rw-r--r-- | lib/libc/stdtime/private.h | 255 | ||||
| -rw-r--r-- | lib/libc/stdtime/strftime.c | 487 | ||||
| -rw-r--r-- | lib/libc/stdtime/tzfile.h | 23 |
6 files changed, 809 insertions, 421 deletions
diff --git a/lib/libc/stdtime/asctime.c b/lib/libc/stdtime/asctime.c index 60877028c74b..a1834b65a273 100644 --- a/lib/libc/stdtime/asctime.c +++ b/lib/libc/stdtime/asctime.c @@ -1,6 +1,11 @@ +/* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)asctime.c 7.5"; +static char elsieid[] = "@(#)asctime.c 7.7"; #endif /* !defined NOID */ #endif /* !defined lint */ diff --git a/lib/libc/stdtime/difftime.c b/lib/libc/stdtime/difftime.c index 68f9d7eb96c5..f178524f5152 100644 --- a/lib/libc/stdtime/difftime.c +++ b/lib/libc/stdtime/difftime.c @@ -1,6 +1,11 @@ +/* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)difftime.c 7.4"; +static char elsieid[] = "@(#)difftime.c 7.7"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -43,9 +48,7 @@ const time_t time0; /* ** Repair delta overflow. */ - hibit = 1; - while ((hibit <<= 1) > 0) - continue; + hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1); /* ** The following expression rounds twice, which means ** the result may not be the closest to the true answer. @@ -65,10 +68,10 @@ const time_t time0; ** This problem occurs only with very large differences. ** It's too painful to fix this portably. ** We are not alone in this problem; - ** many C compilers round twice when converting + ** some C compilers round twice when converting ** large unsigned types to small floating types, ** so if time_t is unsigned the "return delta" above - ** has the same double-rounding problem. + ** has the same double-rounding problem with those compilers. */ return delta - 2 * (long_double) hibit; } diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index 54031479f1dc..541f49ffdfe9 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -1,6 +1,11 @@ +/* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)localtime.c 7.19"; +static char elsieid[] = "@(#)localtime.c 7.57"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -16,7 +21,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 +36,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 +55,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 +89,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 +126,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 +156,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 +195,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 int i; + 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 +218,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 +226,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 +247,7 @@ settzname() sp->types[i]]; tzname[ttisp->tt_isdst] = - (char *) &sp->chars[ttisp->tt_abbrind]; + &sp->chars[ttisp->tt_abbrind]; } } @@ -234,7 +263,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 +291,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 +382,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; } @@ -361,7 +420,7 @@ register const char * strp; { register char c; - while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' && + while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') ++strp; return strp; @@ -384,15 +443,15 @@ const int max; register char c; register int num; - if (strp == NULL || !isdigit(*strp)) + if (strp == NULL || !is_digit(c = *strp)) return NULL; num = 0; - while ((c = *strp) != '\0' && isdigit(c)) { + do { num = num * 10 + (c - '0'); if (num > max) return NULL; /* illegal value */ - ++strp; - } + c = *++strp; + } while (is_digit(c)); if (num < min) return NULL; /* illegal value */ *nump = num; @@ -414,10 +473,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 +491,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; @@ -447,14 +513,13 @@ getoffset(strp, offsetp) register const char * strp; long * const offsetp; { - register int neg; + register int neg = 0; if (*strp == '-') { neg = 1; ++strp; - } else if (isdigit(*strp) || *strp++ == '+') - neg = 0; - else return NULL; /* illegal offset */ + } else if (*strp == '+') + ++strp; strp = getsecs(strp, offsetp); if (strp == NULL) return NULL; /* illegal time */ @@ -499,7 +564,7 @@ register struct rule * const rulep; if (*strp++ != '.') return NULL; strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1); - } else if (isdigit(*strp)) { + } else if (is_digit(*strp)) { /* ** Day of year. */ @@ -536,6 +601,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 +692,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 +701,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 +788,90 @@ 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 +901,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 +934,7 @@ tzsetwall() } void -tzset() +tzset P((void)) { register const char * name; @@ -861,7 +943,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 +967,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 +990,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,7 +1024,7 @@ 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 = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ @@ -948,8 +1034,7 @@ struct tm * localtime(timep) const time_t * const timep; { - static struct tm tm; - + tzset(); localsub(timep, 0L, &tm); return &tm; } @@ -980,11 +1065,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 +1083,6 @@ struct tm * gmtime(timep) const time_t * const timep; { - static struct tm tm; - gmtsub(timep, 0L, &tm); return &tm; } @@ -1011,8 +1094,6 @@ offtime(timep, offset) const time_t * const timep; const long offset; { - static struct tm tm; - gmtsub(timep, offset, &tm); return &tm; } @@ -1074,7 +1155,7 @@ register struct tm * const tmp; days = -24855; rem = -11648; } -#endif /* mc68k */ +#endif /* defined mc68k */ rem += (offset - corr); while (rem < 0) { rem += SECSPERDAY; @@ -1087,30 +1168,27 @@ register struct tm * const tmp; tmp->tm_hour = (int) (rem / SECSPERHOUR); rem = rem % SECSPERHOUR; tmp->tm_min = (int) (rem / SECSPERMIN); - tmp->tm_sec = (int) (rem % SECSPERMIN); - if (hit) - /* - ** A positive leap second requires a special - ** representation. This uses "... ??:59:60" et seq. - */ - tmp->tm_sec += hit; + /* + ** A positive leap second requires a special + ** representation. This uses "... ??:59:60" et seq. + */ + tmp->tm_sec = (int) (rem % SECSPERMIN) + hit; tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK); if (tmp->tm_wday < 0) tmp->tm_wday += DAYSPERWEEK; y = EPOCH_YEAR; - if (days >= 0) - for ( ; ; ) { - yleap = isleap(y); - if (days < (long) year_lengths[yleap]) - break; - ++y; - days = days - (long) year_lengths[yleap]; - } - else do { - --y; - yleap = isleap(y); - days = days + (long) year_lengths[yleap]; - } while (days < 0); +#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) + while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) { + register int newy; + + newy = y + days / DAYSPERNYEAR; + if (days < 0) + --newy; + days -= (newy - y) * DAYSPERNYEAR + + LEAPS_THRU_END_OF(newy - 1) - + LEAPS_THRU_END_OF(y - 1); + y = newy; + } tmp->tm_year = y - TM_YEAR_BASE; tmp->tm_yday = (int) days; ip = mon_lengths[yleap]; @@ -1127,13 +1205,20 @@ 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)); } /* ** Adapted from code provided by Robert Elz, who writes: ** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). +** Kridle's (so its said...) from a long time ago. +** [kridle@xinet.com as of 1996-01-16.] ** It does a binary search of the time_t space. Since time_t's are ** just 32 bits, its a max of 32 iterations (even at 64 bits it ** would still be very reasonable). @@ -1152,8 +1237,8 @@ increment_overflow(number, delta) int * number; int delta; { - int number0; - + int number0; + number0 = *number; *number += delta; return (*number < number0) != (delta < 0); @@ -1193,7 +1278,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; { @@ -1223,10 +1308,12 @@ int * const okayp; while (yourtm.tm_mday <= 0) { if (increment_overflow(&yourtm.tm_year, -1)) return WRONG; - yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)]; + i = yourtm.tm_year + (1 < yourtm.tm_mon); + yourtm.tm_mday += year_lengths[isleap(i)]; } while (yourtm.tm_mday > DAYSPERLYEAR) { - yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)]; + i = yourtm.tm_year + (1 < yourtm.tm_mon); + yourtm.tm_mday -= year_lengths[isleap(i)]; if (increment_overflow(&yourtm.tm_year, 1)) return WRONG; } @@ -1261,17 +1348,16 @@ int * const okayp; yourtm.tm_sec = 0; } /* - ** Calculate the number of magnitude bits in a time_t - ** (this works regardless of whether time_t is - ** signed or unsigned, though lint complains if unsigned). + ** Divide the search space in half + ** (this works whether time_t is signed or unsigned). */ - for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) - continue; + bits = TYPE_BIT(time_t) - 1; /* - ** If time_t is signed, then 0 is the median value, - ** if time_t is unsigned, then 1 << bits is median. + ** If time_t is signed, then 0 is just above the median, + ** assuming two's complement arithmetic. + ** If time_t is unsigned, then (1 << bits) is just above the median. */ - t = (t < 0) ? 0 : ((time_t) 1 << bits); + t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); for ( ; ; ) { (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); @@ -1279,10 +1365,10 @@ int * const okayp; if (bits-- < 0) return WRONG; if (bits < 0) - --t; + --t; /* may be needed if new t is minimal */ else if (dir > 0) - t -= (time_t) 1 << bits; - else t += (time_t) 1 << bits; + t -= ((time_t) 1) << bits; + else t += ((time_t) 1) << bits; continue; } if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) @@ -1303,10 +1389,10 @@ int * const okayp; if (sp == NULL) return WRONG; #endif /* defined ALL_STATE */ - for (i = 0; i < sp->typecnt; ++i) { + for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; - for (j = 0; j < sp->typecnt; ++j) { + for (j = sp->typecnt - 1; j >= 0; --j) { if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) continue; newt = t + sp->ttis[j].tt_gmtoff - @@ -1338,7 +1424,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; @@ -1377,10 +1463,10 @@ const long offset; if (sp == NULL) return WRONG; #endif /* defined ALL_STATE */ - for (samei = 0; samei < sp->typecnt; ++samei) { + for (samei = sp->typecnt - 1; samei >= 0; --samei) { if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; - for (otheri = 0; otheri < sp->typecnt; ++otheri) { + for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) { if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) continue; tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - @@ -1401,6 +1487,7 @@ time_t mktime(tmp) struct tm * const tmp; { + tzset(); return time1(tmp, localsub, 0L); } @@ -1475,8 +1562,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 +1576,7 @@ time_t time2posix(t) time_t t; { + tzset(); return t - leapcorr(&t); } @@ -1501,6 +1587,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 5af259c62604..f81bf4867bdb 100644 --- a/lib/libc/stdtime/private.h +++ b/lib/libc/stdtime/private.h @@ -3,6 +3,11 @@ #define PRIVATE_H /* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + +/* ** 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. @@ -16,36 +21,91 @@ #ifndef lint #ifndef NOID -static char privatehid[] = "@(#)private.h 7.5"; +static char privatehid[] = "@(#)private.h 7.43"; #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_GETTEXT +#define HAVE_GETTEXT 0 +#endif /* !defined HAVE_GETTEXT */ + +#ifndef HAVE_SETTIMEOFDAY +#define HAVE_SETTIMEOFDAY 3 +#endif /* !defined HAVE_SETTIMEOFDAY */ + +#ifndef HAVE_STRERROR +#define HAVE_STRERROR 0 +#endif /* !defined HAVE_STRERROR */ + +#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 */ + +/* +** Nested includes +*/ + +#include "sys/types.h" /* for time_t */ +#include "stdio.h" +#include "errno.h" +#include "string.h" +#include "limits.h" /* for CHAR_BIT */ +#include "time.h" +#include "stdlib.h" + +#if HAVE_GETTEXT - 0 +#include "libintl.h" +#endif /* HAVE_GETTEXT - 0 */ + +#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) */ + +/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */ +#define is_digit(c) ((unsigned)(c) - '0' <= 9) /* -** 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 @@ -53,36 +113,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 @@ -101,62 +154,27 @@ 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 */ +/* +** SunOS 4.1.1 libraries lack remove. +*/ -#endif /* !defined __STDC__ */ +#ifndef remove +extern int unlink P((const char * filename)); +#define remove unlink +#endif /* !defined remove */ /* -** Ensure that these are declared--redundantly declaring them shouldn't hurt. +** 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 */ -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)); - -#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 @@ -166,20 +184,69 @@ extern void free P((char * buf)); #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 */ + #ifndef INT_STRLEN_MAXIMUM /* ** 302 / 1000 is log10(2.0) rounded up. -** Subtract one for the sign bit; +** Subtract one for the sign bit if the type is signed; ** add one for integer division truncation; -** add one more for a minus sign. +** add one more for a minus sign if the type is signed. */ #define INT_STRLEN_MAXIMUM(type) \ - ((sizeof(type) * CHAR_BIT - 1) * 302 / 1000 + 2) + ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 100 + 1 + TYPE_SIGNED(type)) #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 */ + +/* +** 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 - 0 +#define _(msgid) gettext(msgid) +#else /* !(HAVE_GETTEXT - 0) */ +#define _(msgid) msgid +#endif /* !(HAVE_GETTEXT - 0) */ +#endif /* !defined _ */ + +#ifndef TZ_DOMAIN +#define TZ_DOMAIN "tz" +#endif /* !defined TZ_DOMAIN */ + +/* +** UNIX was a registered trademark of UNIX System Laboratories in 1993. */ #endif /* !defined PRIVATE_H */ diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c index 821bc7957467..a5ba85c90473 100644 --- a/lib/libc/stdtime/strftime.c +++ b/lib/libc/stdtime/strftime.c @@ -1,10 +1,9 @@ #ifndef lint #ifndef NOID -static char elsieid[] = "@(#)strftime.c 7.19"; +static char elsieid[] = "@(#)strftime.c 7.47"; /* ** 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". +** This is ANSIish only when "multibyte character == plain character". */ #endif /* !defined NOID */ #endif /* !defined lint */ @@ -12,64 +11,122 @@ static char elsieid[] = "@(#)strftime.c 7.19"; #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. - */ +** 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"; +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" -static const char afmt[][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" -}; -static const char Afmt[][10] = { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", - "Saturday" +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[][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", - "Oct", "Nov", "Dec" -}; -static const char Bfmt[][10] = { - "January", "February", "March", "April", "May", "June", "July", - "August", "September", "October", "November", "December" + +#ifdef LOCALE_HOME +#include "sys/stat.h" +static struct lc_time_T localebuf; +static struct lc_time_T * _loc P((void)); +#define Locale _loc() +#endif /* defined LOCALE_HOME */ +#ifndef LOCALE_HOME +#define Locale (&C_time_locale) +#endif /* !defined LOCALE_HOME */ + +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 + ** Note that + ** "%a %b %d %H:%M:%S %Y" + ** is used by Solaris 2.3. + */ + "%D %X", /* %m/%d/%y %H:%M:%S */ + + /* am */ + "AM", + + /* pm */ + "PM", + + /* date_fmt */ + "%a %b %e %H:%M:%S %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 * _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 *)); 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; + char * p; - p = _fmt(format, t, s, s + maxsize); + tzset(); +#ifdef LOCALE_HOME + localebuf.mon[0] = 0; +#endif /* defined LOCALE_HOME */ + p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize); if (p == s + maxsize) return 0; *p = '\0'; @@ -78,37 +135,38 @@ strftime(s, maxsize, format, t) static char * _fmt(format, t, pt, ptlim) - const char *format; - const struct tm *t; - char *pt; - const char *ptlim; +const char * format; +const struct tm * const t; +char * pt; +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': /* @@ -121,27 +179,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': @@ -220,7 +261,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': @@ -232,8 +275,24 @@ label: 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': - case 'X': pt = _fmt("%H:%M:%S", t, pt, ptlim); continue; case 't': @@ -253,66 +312,86 @@ label: pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday, "%d", pt, ptlim); continue; - case 'V': - /* - ** 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). The method for - ** determining the week number is as specified - ** by ISO 8601 (to wit: if the week containing - ** January 1 has four or more days in the new - ** year, then it is week 1, otherwise it is - ** week 53 of the previous year and the next - ** week is week 1)." - ** (ado, 5/24/93) - */ - /* - ** XXX--If January 1 falls on a Friday, - ** January 1-3 are part of week 53 of the - ** previous year. By analogy, if January - ** 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. - */ + 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 i; + int year; + int yday; + int wday; + int w; - i = (t->tm_yday + 10 - (t->tm_wday ? - (t->tm_wday - 1) : 6)) / 7; - if (i == 0) { + year = t->tm_year + TM_YEAR_BASE; + yday = t->tm_yday; + wday = t->tm_wday; + for ( ; ; ) { + int len; + int bot; + int top; + + len = isleap(year) ? + DAYSPERLYEAR : + DAYSPERNYEAR; /* - ** What day of the week does - ** January 1 fall on? + ** What yday (-3 ... 3) does + ** the ISO year begin on? */ - i = t->tm_wday - - (t->tm_yday - 1); + bot = ((yday + 11 - wday) % + DAYSPERWEEK) - 3; /* - ** Fri Jan 1: 53 - ** Sun Jan 1: 52 - ** Sat Jan 1: 53 if previous - ** year a leap - ** year, else 52 + ** What yday does the NEXT + ** ISO year begin on? */ - if (i == TM_FRIDAY) - i = 53; - else if (i == TM_SUNDAY) - i = 52; - else i = isleap(t->tm_year + - TM_YEAR_BASE) ? - 53 : 52; + top = bot - + (len % DAYSPERWEEK); + if (top < -3) + top += DAYSPERWEEK; + top += len; + if (yday >= top) { + ++year; + w = 1; + break; + } + if (yday >= bot) { + w = 1 + ((yday - bot) / + DAYSPERWEEK); + break; + } + --year; + yday += isleap(year) ? + DAYSPERLYEAR : + DAYSPERNYEAR; + } #ifdef XPG4_1994_04_09 - /* - ** As of 4/9/94, though, - ** XPG4 calls for 53 - ** unconditionally. - */ - i = 53; + if (w == 52 && t->tm_mon == TM_JANUARY) + w = 53; #endif /* defined XPG4_1994_04_09 */ - } - pt = _conv(i, "%02d", pt, ptlim); + if (*format == 'V') + pt = _conv(w, "%02d", + pt, ptlim); + else if (*format == 'G') + pt = _conv(year, "%02d", + pt, ptlim); + else pt = _conv(year, "%04d", + pt, ptlim); } continue; case 'v': @@ -332,6 +411,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); @@ -342,7 +427,7 @@ label: continue; case 'Z': #ifdef TM_ZONE - if (t->TM_ZONE) + if (t->TM_ZONE != NULL) pt = _add(t->TM_ZONE, pt, ptlim); else #endif /* defined TM_ZONE */ @@ -351,6 +436,9 @@ label: 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 @@ -370,12 +458,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); @@ -383,11 +471,134 @@ _conv(n, format, pt, ptlim) static char * _add(str, pt, ptlim) - const char *str; - char *pt; - const char *ptlim; +const char * str; +char * pt; +const char * const ptlim; { while (pt < ptlim && (*pt = *str++) != '\0') ++pt; 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; + static char locale_buf_C[] = "C"; + + 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 || 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'; + } + 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 = locale_buf_C; + return &localebuf; +} +#endif /* defined LOCALE_HOME */ diff --git a/lib/libc/stdtime/tzfile.h b/lib/libc/stdtime/tzfile.h index 45b4d7d606a7..cb9b6a1a11e1 100644 --- a/lib/libc/stdtime/tzfile.h +++ b/lib/libc/stdtime/tzfile.h @@ -3,6 +3,11 @@ #define TZFILE_H /* +** This file is in the public domain, so clarified as of +** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). +*/ + +/* ** 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. @@ -16,7 +21,7 @@ #ifndef lint #ifndef NOID -static char tzfilehid[] = "@(#)tzfile.h 7.4"; +static char tzfilehid[] = "@(#)tzfile.h 7.8"; #endif /* !defined NOID */ #endif /* !defined lint */ @@ -41,7 +46,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 +73,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 +100,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 */ @@ -143,7 +158,7 @@ struct tzhead { ** that will probably do. */ -#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) #ifndef USG |
