diff -crN -x *~ ../tzcode2001c/Makefile thread-safe-2/Makefile *** ../tzcode2001c/Makefile Tue Jun 5 13:48:21 2001 --- thread-safe-2/Makefile Mon Jun 18 15:49:47 2001 *************** *** 83,88 **** --- 83,89 ---- # Non-default libraries needed to link. # Add -lintl if you want to use `gettext' on Solaris. + # Add -lpthread if you're compiling with non-weak POSIX threads in libpthread. LDLIBS= # Add the following to the end of the "CFLAGS=" line as needed. *************** *** 211,216 **** --- 212,220 ---- CFLAGS= + # The threading model for this system. "dummy" or "posix" + THREADMODEL= dummy + # If you want zic's -s option used when installing, uncomment the next line # ZFLAGS= -s *************** *** 242,260 **** cc= cc CC= $(cc) -DTZDIR=\"$(TZDIR)\" ! TZCSRCS= zic.c localtime.c asctime.c scheck.c ialloc.c ! TZCOBJS= zic.o localtime.o asctime.o scheck.o ialloc.o ! TZDSRCS= zdump.c localtime.c asctime.c ialloc.c ! TZDOBJS= zdump.o localtime.o asctime.o ialloc.o ! DATESRCS= date.c localtime.c logwtmp.c strftime.c asctime.c ! DATEOBJS= date.o localtime.o logwtmp.o strftime.o asctime.o ! LIBSRCS= localtime.c asctime.c difftime.c ! LIBOBJS= localtime.o asctime.o difftime.o ! HEADERS= tzfile.h private.h NONLIBSRCS= zic.c zdump.c scheck.c ialloc.c NEWUCBSRCS= date.c logwtmp.c strftime.c ! SOURCES= $(HEADERS) $(LIBSRCS) $(NONLIBSRCS) $(NEWUCBSRCS) tzselect.ksh MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \ tzfile.5 tzselect.8 zic.8 zdump.8 DOCS= README Theory $(MANS) date.1 Makefile PRIMARY_YDATA= africa antarctica asia australasia \ --- 246,274 ---- cc= cc CC= $(cc) -DTZDIR=\"$(TZDIR)\" ! THREADSRC= tzthread-$(THREADMODEL).c ! THREADOBJ= tzthread-$(THREADMODEL).o ! THREADHDR= tzthread-$(THREADMODEL).h ! ! CFLAGS += -DTZTHREAD_HEADER_H=\"$(THREADHDR)\" ! ! TZCSRCS= zic.c localtime.c $(THREADSRC) asctime.c scheck.c ialloc.c ! TZCOBJS= zic.o localtime.o $(THREADOBJ) asctime.o scheck.o ialloc.o ! TZDSRCS= zdump.c localtime.c $(THREADSRC) asctime.c ialloc.c ! TZDOBJS= zdump.o localtime.o $(THREADOBJ) asctime.o ialloc.o ! DATESRCS= date.c localtime.c $(THREADSRC) logwtmp.c strftime.c asctime.c ! DATEOBJS= date.o localtime.o $(THREADOBJ) logwtmp.o strftime.o asctime.o ! LIBSRCS= localtime.c $(THREADSRC) asctime.c difftime.c ! LIBOBJS= localtime.o $(THREADOBJ) asctime.o difftime.o ! HEADERS= tzfile.h private.h struct_tzinfo.h tzthread-dummy.h \ ! tzthread-posix.h tztimeext.h ! VARLIBSRCS= tzthread-dummy.c tzthread-posix.c NONLIBSRCS= zic.c zdump.c scheck.c ialloc.c NEWUCBSRCS= date.c logwtmp.c strftime.c ! SOURCES= $(HEADERS) $(LIBSRCS) $(VARLIBSRCS) $(NONLIBSRCS) \ ! $(NEWUCBSRCS) tzselect.ksh MANS= newctime.3 newstrftime.3 newtzset.3 time2posix.3 \ + tz_prep.3 time_make.3 pthread_settz.3 \ tzfile.5 tzselect.8 zic.8 zdump.8 DOCS= README Theory $(MANS) date.1 Makefile PRIMARY_YDATA= africa antarctica asia australasia \ *************** *** 353,359 **** ar r ,lib.a logwtmp.o if [ -x /usr/ucb/ranlib -o -x /usr/bin/ranlib ] ; \ then ranlib ,lib.a ; fi ! $(CC) $(CFLAGS) date.o localtime.o asctime.o strftime.o \ $(LDLIBS) -lc ,lib.a -o $@ rm -f ,lib.a --- 367,373 ---- ar r ,lib.a logwtmp.o if [ -x /usr/ucb/ranlib -o -x /usr/bin/ranlib ] ; \ then ranlib ,lib.a ; fi ! $(CC) $(CFLAGS) date.o localtime.o $(THREADOBJ) asctime.o strftime.o \ $(LDLIBS) -lc ,lib.a -o $@ rm -f ,lib.a *************** *** 396,404 **** date.o: private.h difftime.o: private.h ialloc.o: private.h ! localtime.o: private.h tzfile.h scheck.o: private.h ! strftime.o: tzfile.h zic.o: private.h tzfile.h .KEEP_STATE: --- 410,419 ---- date.o: private.h difftime.o: private.h ialloc.o: private.h ! localtime.o: private.h tzfile.h tztimeext.h struct_tzinfo.h $(THREADHDR) scheck.o: private.h ! strftime.o: tzfile.h private.h struct_tzinfo.h zic.o: private.h tzfile.h + $(THREADOBJ): private.h tzfile.h struct_tzinfo.h $(THREADHDR) .KEEP_STATE: diff -crN -x *~ ../tzcode2001c/asctime.c thread-safe-2/asctime.c *** ../tzcode2001c/asctime.c Tue Jun 5 13:49:48 2001 --- thread-safe-2/asctime.c Mon Jun 18 15:46:04 2001 *************** *** 14,19 **** --- 14,21 ---- #include "private.h" #include "tzfile.h" + #include TZTHREAD_HEADER_H + /* ** A la ISO/IEC 9945-1, ANSI/IEEE Std 1003.1, Second Edition, 1996-07-12. */ *************** *** 60,74 **** asctime(timeptr) register const struct tm * timeptr; { ! /* ! ** Big enough for something such as ! ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n ! ** (two three-character abbreviations, five strings denoting integers, ! ** three explicit spaces, two explicit colons, a newline, ! ** and a trailing ASCII nul). ! */ ! static char result[3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) + ! 3 + 2 + 1 + 1]; return asctime_r(timeptr, result); } --- 62,68 ---- asctime(timeptr) register const struct tm * timeptr; { ! char *result = GET_ASCTIME_BUF(); return asctime_r(timeptr, result); } diff -crN -x *~ ../tzcode2001c/localtime.c thread-safe-2/localtime.c *** ../tzcode2001c/localtime.c Tue Jun 5 13:59:55 2001 --- thread-safe-2/localtime.c Mon Jun 18 16:26:37 2001 *************** *** 21,26 **** --- 21,32 ---- #include "tzfile.h" #include "fcntl.h" + #include "struct_tzinfo.h" + + #include "tztimeext.h" + + #include TZTHREAD_HEADER_H + /* ** SunOS 4.1.1 headers lack O_BINARY. */ *************** *** 70,110 **** #define TZDEFRULESTRING ",M4.1.0,M10.5.0" #endif /* !defined TZDEFDST */ - struct ttinfo { /* time type information */ - long tt_gmtoff; /* UTC 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 UTC */ - }; - - struct lsinfo { /* leap second information */ - time_t ls_trans; /* transition time */ - long ls_corr; /* correction to apply */ - }; - - #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - - #ifdef TZNAME_MAX - #define MY_TZNAME_MAX TZNAME_MAX - #endif /* defined TZNAME_MAX */ - #ifndef TZNAME_MAX - #define MY_TZNAME_MAX 255 - #endif /* !defined TZNAME_MAX */ - - struct state { - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - 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), - (2 * (MY_TZNAME_MAX + 1)))]; - struct lsinfo lsis[TZ_MAX_LEAPS]; - }; - struct rule { int r_type; /* type of rule--see below */ int r_day; /* day number of rule */ --- 76,81 ---- *************** *** 128,175 **** static const char * getsecs P((const char * strp, long * secsp)); static const char * getoffset P((const char * strp, long * offsetp)); static const char * getrule P((const char * strp, struct rule * rulep)); ! static void gmtload P((struct state * sp)); ! static void gmtsub P((const time_t * timep, long offset, ! struct tm * tmp)); ! static void localsub P((const time_t * timep, long offset, ! struct tm * tmp)); 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) P((const time_t *, ! long, struct tm *)), long offset)); ! static time_t time2 P((struct tm *tmp, ! void(*funcp) P((const time_t *, ! long, struct tm*)), ! long offset, int * okayp)); ! static time_t time2sub P((struct tm *tmp, ! void(*funcp) P((const time_t *, ! long, struct tm*)), ! long offset, int * okayp, int do_norm_secs)); static void timesub P((const time_t * timep, long offset, ! const struct state * sp, struct tm * tmp)); static int tmcomp P((const struct tm * atmp, const struct tm * btmp)); static time_t transtime P((time_t janfirst, int year, const struct rule * rulep, long offset)); ! static int tzload P((const char * name, struct state * sp)); ! static int tzparse P((const char * name, struct state * sp, int lastditch)); - #ifdef ALL_STATE - static struct state * lclptr; - static struct state * gmtptr; - #endif /* defined ALL_STATE */ - - #ifndef ALL_STATE - static struct state lclmem; - static struct state gmtmem; - #define lclptr (&lclmem) - #define gmtptr (&gmtmem) - #endif /* State Farm */ #ifndef TZ_STRLEN_MAX #define TZ_STRLEN_MAX 255 --- 99,145 ---- static const char * getsecs P((const char * strp, long * secsp)); static const char * getoffset P((const char * strp, long * offsetp)); static const char * getrule P((const char * strp, struct rule * rulep)); ! static void gmtload P((struct tzinfo * sp)); ! static void nulltzsub P((const time_t * timep, ! long offset, struct tm * tmp)); ! static void tzsub P((const time_t * timep, ! const struct tzinfo *tz, ! long offset, struct tm * tmp, int)); static int increment_overflow P((int * number, int delta)); static int normalize_overflow P((int * tensptr, int * unitsptr, int base)); ! static void settzname P((const struct tzinfo * const)); ! static int time1 P((time_t * timep, ! struct tm * tmp, ! const struct tzinfo * tz, ! long offset, ! int accomodate_gap)); ! static int time2 P((time_t * timep, ! struct tm *tmp, ! const struct tzinfo * tz, long offset)); ! static int time2sub P((time_t * timep, ! struct tm *tmp, ! const struct tzinfo * tz, ! long offset, int do_norm_secs)); static void timesub P((const time_t * timep, long offset, ! const struct tzinfo * sp, struct tm * tmp)); static int tmcomp P((const struct tm * atmp, const struct tm * btmp)); static time_t transtime P((time_t janfirst, int year, const struct rule * rulep, long offset)); ! static int tzload P((const char * name, struct tzinfo * sp)); ! static int tzparse P((const char * name, struct tzinfo * sp, int lastditch)); + static void tzsetwall_basic P((struct tzinfo * const sp)); + static void tzset_basic P((struct tzinfo * const sp)); + #ifndef STD_INSPIRED + static void tzsetwall P((void)); + #endif + #ifdef STD_INSPIRED + static long leapcorr P((time_t *, const struct tzinfo *)); + #endif #ifndef TZ_STRLEN_MAX #define TZ_STRLEN_MAX 255 *************** *** 184,189 **** --- 154,164 ---- wildabbr }; + #define MIN_TIME (TYPE_SIGNED(time_t) ? \ + (((time_t) 1) << (TYPE_BIT(time_t) - 1)) : 0) + + #define MAX_TIME (~MIN_TIME) + /* ** Section 4.12.3 of X3.159-1989 requires that ** Except for the strftime function, these functions [asctime, *************** *** 192,199 **** ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this. */ - static struct tm tm; - #ifdef USG_COMPAT time_t timezone = 0; int daylight = 0; --- 167,172 ---- *************** *** 217,225 **** } static void ! settzname P((void)) { - register struct state * const sp = lclptr; register int i; tzname[0] = wildabbr; --- 190,198 ---- } static void ! settzname(sp) ! const struct tzinfo * const sp; { register int i; tzname[0] = wildabbr; *************** *** 231,242 **** #ifdef ALTZONE altzone = 0; #endif /* defined ALTZONE */ - #ifdef ALL_STATE if (sp == NULL) { tzname[0] = tzname[1] = gmt; return; } - #endif /* defined ALL_STATE */ for (i = 0; i < sp->typecnt; ++i) { register const struct ttinfo * const ttisp = &sp->ttis[i]; --- 204,213 ---- *************** *** 269,275 **** static int tzload(name, sp) register const char * name; ! register struct state * const sp; { register const char * p; register int i; --- 240,246 ---- static int tzload(name, sp) register const char * name; ! register struct tzinfo * const sp; { register const char * p; register int i; *************** *** 698,704 **** static int tzparse(name, sp, lastditch) const char * name; ! register struct state * const sp; const int lastditch; { const char * stdname; --- 669,675 ---- static int tzparse(name, sp, lastditch) const char * name; ! register struct tzinfo * const sp; const int lastditch; { const char * stdname; *************** *** 910,921 **** static void gmtload(sp) ! struct state * const sp; { if (tzload(gmt, sp) != 0) (void) tzparse(gmt, sp, TRUE); } #ifndef STD_INSPIRED /* ** A non-static declaration of tzsetwall in a system header file --- 881,934 ---- static void gmtload(sp) ! struct tzinfo * const sp; { if (tzload(gmt, sp) != 0) (void) tzparse(gmt, sp, TRUE); } + + static void + gmtset(sp) + struct tzinfo * const sp; + { + /* + ** Fast-path the common-case (no locking needed once gmt is set). + */ + if (gmt_is_set) { + return; + } + + LOCK_GMTPTR(); + /* + ** Another thread might have set it, so check gmt_is_set again. + */ + if (!gmt_is_set) { + gmt_is_set = TRUE; + if (sp != NULL) + gmtload(sp); + } + UNLOCK_GMTPTR(); + } + + + static void + tzsetwall_basic(sp) + struct tzinfo * const sp; + { + if (lcl_is_set < 0) + return; + lcl_is_set = -1; + + if (sp == NULL) { + settzname(NULL); /* all we can do */ + return; + } + if (tzload((char *) NULL, sp) != 0) + gmtload(sp); + settzname(sp); + } + #ifndef STD_INSPIRED /* ** A non-static declaration of tzsetwall in a system header file *************** *** 926,957 **** void tzsetwall P((void)) { ! if (lcl_is_set < 0) ! return; ! lcl_is_set = -1; ! #ifdef ALL_STATE ! if (lclptr == NULL) { ! lclptr = (struct state *) malloc(sizeof *lclptr); ! if (lclptr == NULL) { ! settzname(); /* all we can do */ ! return; ! } } ! #endif /* defined ALL_STATE */ ! if (tzload((char *) NULL, lclptr) != 0) ! gmtload(lclptr); ! settzname(); } ! void ! tzset P((void)) { register const char * name; name = getenv("TZ"); if (name == NULL) { ! tzsetwall(); return; } --- 939,967 ---- void tzsetwall P((void)) { ! struct tzinfo * sp; ! int process_wide; ! LOCK_LCLPTR(); ! sp = GET_LCLPTR(&process_wide); ! if (!process_wide) { ! UNLOCK_LCLPTR(); ! return; } ! ! tzsetwall_basic(sp); ! UNLOCK_LCLPTR(); } ! static void ! tzset_basic(lclptr) ! struct tzinfo * const lclptr; { register const char * name; name = getenv("TZ"); if (name == NULL) { ! tzsetwall_basic(lclptr); return; } *************** *** 961,975 **** if (lcl_is_set) (void) strcpy(lcl_TZname, name); - #ifdef ALL_STATE if (lclptr == NULL) { ! lclptr = (struct state *) malloc(sizeof *lclptr); ! if (lclptr == NULL) { ! settzname(); /* all we can do */ ! return; ! } } - #endif /* defined ALL_STATE */ if (*name == '\0') { /* ** User wants it fast rather than right. --- 971,980 ---- if (lcl_is_set) (void) strcpy(lcl_TZname, name); if (lclptr == NULL) { ! settzname(NULL); /* all we can do */ ! return; } if (*name == '\0') { /* ** User wants it fast rather than right. *************** *** 984,995 **** } else if (tzload(name, lclptr) != 0) if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) (void) gmtload(lclptr); ! settzname(); } /* ** The easy way to behave "as if no library function calls" localtime ! ** is to not call it--so we drop its guts into "localsub", which can be ** freely called. (And no, the PANS doesn't require the above behavior-- ** but it *is* desirable.) ** --- 989,1041 ---- } else if (tzload(name, lclptr) != 0) if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) (void) gmtload(lclptr); ! settzname(lclptr); ! } ! ! void ! tzset P((void)) ! { ! struct tzinfo * lclptr; ! int process_wide; ! ! LOCK_LCLPTR(); ! lclptr = GET_LCLPTR(&process_wide); ! if (!process_wide) { ! UNLOCK_LCLPTR(); ! return; ! } ! ! tzset_basic(lclptr); ! UNLOCK_LCLPTR(); ! } ! ! const struct ttinfo * ! _tz_getttype(timep, sp) ! const time_t * const timep; ! const struct tzinfo * sp; ! { ! register int i; ! const time_t t = *timep; ! ! if (sp->timecnt == 0 || t < sp->ats[0]) { ! i = 0; ! while (sp->ttis[i].tt_isdst) ! if (++i >= sp->typecnt) { ! i = 0; ! break; ! } ! } else { ! for (i = 1; i < sp->timecnt; ++i) ! if (t < sp->ats[i]) ! break; ! i = sp->types[i - 1]; ! } ! return &sp->ttis[i]; } /* ** The easy way to behave "as if no library function calls" localtime ! ** is to not call it--so we drop its guts into "tzsub", which can be ** freely called. (And no, the PANS doesn't require the above behavior-- ** but it *is* desirable.) ** *************** *** 998,1045 **** /*ARGSUSED*/ static void ! localsub(timep, offset, tmp) const time_t * const timep; const long offset; struct tm * const tmp; { - register struct state * sp; register const struct ttinfo * ttisp; - register int i; const time_t t = *timep; - sp = lclptr; - #ifdef ALL_STATE if (sp == NULL) { ! gmtsub(timep, offset, tmp); return; } ! #endif /* defined ALL_STATE */ ! if (sp->timecnt == 0 || t < sp->ats[0]) { ! i = 0; ! while (sp->ttis[i].tt_isdst) ! if (++i >= sp->typecnt) { ! i = 0; ! break; ! } ! } else { ! for (i = 1; i < sp->timecnt; ++i) ! if (t < sp->ats[i]) ! break; ! i = sp->types[i - 1]; ! } ! ttisp = &sp->ttis[i]; /* ** To get (wrong) behavior that's compatible with System V Release 2.0 ** you'd replace the statement below with ! ** t += ttisp->tt_gmtoff; ** timesub(&t, 0L, sp, tmp); */ ! timesub(&t, ttisp->tt_gmtoff, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; ! tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; #ifdef TM_ZONE ! tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; #endif /* defined TM_ZONE */ } --- 1044,1089 ---- /*ARGSUSED*/ static void ! tzsub(timep, sp, offset, tmp, alter_tzname) const time_t * const timep; + const struct tzinfo * const sp; const long offset; struct tm * const tmp; + int alter_tzname; { register const struct ttinfo * ttisp; const time_t t = *timep; if (sp == NULL) { ! nulltzsub(timep, offset, tmp); return; } ! ttisp = _tz_getttype(timep, sp); /* ** To get (wrong) behavior that's compatible with System V Release 2.0 ** you'd replace the statement below with ! ** t += ttisp->tt_gmtoff + offset; ** timesub(&t, 0L, sp, tmp); + ** + ** ttisp->tt_gmtoff and offset should never both be non-zero + ** simultaneously. */ ! timesub(&t, ttisp->tt_gmtoff + offset, sp, tmp); tmp->tm_isdst = ttisp->tt_isdst; ! if (alter_tzname) { ! tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind]; ! } #ifdef TM_ZONE ! /* ! ** Could get fancy here and deliver something such as ! ** "UTC+xxxx" or "UTC-xxxx" if offset is non-zero, ! ** but this is no time for a treasure hunt. ! */ ! if (offset != 0) ! tmp->TM_ZONE = wildabbr; ! else { ! tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind]; ! } #endif /* defined TM_ZONE */ } *************** *** 1047,1055 **** localtime(timep) const time_t * const timep; { ! tzset(); ! localsub(timep, 0L, &tm); ! return &tm; } /* --- 1091,1114 ---- localtime(timep) const time_t * const timep; { ! struct tm * tm; ! struct tzinfo * tz; ! int process_wide; ! tm = GET_TM_BUF(); ! if (tm == NULL) ! return NULL; ! ! LOCK_LCLPTR(); ! tz = GET_LCLPTR(&process_wide); ! if (tz == NULL) { ! UNLOCK_LCLPTR(); ! return NULL; ! } ! if (process_wide) ! tzset_basic(tz); ! tzsub(timep, tz, 0L, tm, process_wide); ! UNLOCK_LCLPTR(); ! return tm; } /* *************** *** 1060,1088 **** const time_t * const timep; struct tm * tm; { ! localsub(timep, 0L, tm); return tm; } /* ! ** gmtsub is to gmtime as localsub is to localtime. */ static void ! gmtsub(timep, offset, tmp) const time_t * const timep; const long offset; struct tm * const tmp; { ! if (!gmt_is_set) { ! gmt_is_set = TRUE; ! #ifdef ALL_STATE ! gmtptr = (struct state *) malloc(sizeof *gmtptr); ! if (gmtptr != NULL) ! #endif /* defined ALL_STATE */ ! gmtload(gmtptr); ! } ! timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as --- 1119,1150 ---- const time_t * const timep; struct tm * tm; { ! struct tzinfo * tz; ! int process_wide; ! LOCK_LCLPTR(); ! tz = GET_LCLPTR(&process_wide); ! if (tz == NULL) { ! UNLOCK_LCLPTR(); ! return NULL; ! } ! if (process_wide) ! tzset_basic(tz); ! tzsub(timep, tz, 0L, tm, process_wide); ! UNLOCK_LCLPTR(); return tm; } /* ! ** nulltzsub is a stripped-down version of tzsub used if tz is NULL. */ static void ! nulltzsub(timep, offset, tmp) const time_t * const timep; const long offset; struct tm * const tmp; { ! timesub(timep, offset, NULL, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as *************** *** 1092,1105 **** if (offset != 0) tmp->TM_ZONE = wildabbr; else { ! #ifdef ALL_STATE ! if (gmtptr == NULL) ! tmp->TM_ZONE = gmt; ! else tmp->TM_ZONE = gmtptr->chars; ! #endif /* defined ALL_STATE */ ! #ifndef ALL_STATE ! tmp->TM_ZONE = gmtptr->chars; ! #endif /* State Farm */ } #endif /* defined TM_ZONE */ } --- 1154,1160 ---- if (offset != 0) tmp->TM_ZONE = wildabbr; else { ! tmp->TM_ZONE = gmt; } #endif /* defined TM_ZONE */ } *************** *** 1108,1115 **** gmtime(timep) const time_t * const timep; { ! gmtsub(timep, 0L, &tm); ! return &tm; } /* --- 1163,1181 ---- gmtime(timep) const time_t * const timep; { ! struct tm * tm; ! struct tzinfo * tz; ! tm = GET_TM_BUF(); ! if (tm == NULL) ! return NULL; ! ! tz = GET_GMTPTR(); ! if (tz == NULL) ! return NULL; ! gmtset(tz); ! tzsub(timep, tz, 0L, tm, 0); ! ! return tm; } /* *************** *** 1120,1126 **** const time_t * const timep; struct tm * tm; { ! gmtsub(timep, 0L, tm); return tm; } --- 1186,1199 ---- const time_t * const timep; struct tm * tm; { ! struct tzinfo * tz; ! ! tz = GET_GMTPTR(); ! if (tz == NULL) ! return NULL; ! gmtset(tz); ! tzsub(timep, tz, 0L, tm, 0); ! return tm; } *************** *** 1131,1138 **** const time_t * const timep; const long offset; { ! gmtsub(timep, offset, &tm); ! return &tm; } #endif /* defined STD_INSPIRED */ --- 1204,1223 ---- const time_t * const timep; const long offset; { ! struct tm * tm; ! struct tzinfo * tz; ! ! tm = GET_TM_BUF(); ! if (tm == NULL) ! return NULL; ! ! tz = GET_GMTPTR(); ! if (tz == NULL) ! return NULL; ! gmtset(tz); ! tzsub(timep, tz, offset, tm, 0); ! ! return tm; } #endif /* defined STD_INSPIRED */ *************** *** 1141,1147 **** timesub(timep, offset, sp, tmp) const time_t * const timep; const long offset; ! register const struct state * const sp; register struct tm * const tmp; { register const struct lsinfo * lp; --- 1226,1232 ---- timesub(timep, offset, sp, tmp) const time_t * const timep; const long offset; ! register const struct tzinfo * const sp; register struct tm * const tmp; { register const struct lsinfo * lp; *************** *** 1156,1167 **** corr = 0; hit = 0; - #ifdef ALL_STATE i = (sp == NULL) ? 0 : sp->leapcnt; - #endif /* defined ALL_STATE */ - #ifndef ALL_STATE - i = sp->leapcnt; - #endif /* State Farm */ while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) { --- 1241,1247 ---- *************** *** 1322,1336 **** return result; } ! static time_t ! time2sub(tmp, funcp, offset, okayp, do_norm_secs) struct tm * const tmp; ! void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; - int * const okayp; const int do_norm_secs; { - register const struct state * sp; register int dir; register int bits; register int i, j ; --- 1402,1415 ---- return result; } ! static int ! time2sub(timep, tmp, sp, offset, do_norm_secs) ! time_t * timep; struct tm * const tmp; ! const struct tzinfo * sp; const long offset; const int do_norm_secs; { register int dir; register int bits; register int i, j ; *************** *** 1339,1366 **** time_t t; struct tm yourtm, mytm; - *okayp = FALSE; yourtm = *tmp; if (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) ! return WRONG; } if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) ! return WRONG; if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) ! return WRONG; if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) ! return WRONG; /* ** Turn yourtm.tm_year into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) ! return WRONG; while (yourtm.tm_mday <= 0) { if (increment_overflow(&yourtm.tm_year, -1)) ! return WRONG; i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(i)]; } --- 1418,1444 ---- time_t t; struct tm yourtm, mytm; yourtm = *tmp; if (do_norm_secs) { if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) ! return ERANGE; } if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) ! return ERANGE; if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) ! return ERANGE; if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR)) ! return ERANGE; /* ** Turn yourtm.tm_year into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE)) ! return ERANGE; while (yourtm.tm_mday <= 0) { if (increment_overflow(&yourtm.tm_year, -1)) ! return ERANGE; i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday += year_lengths[isleap(i)]; } *************** *** 1368,1374 **** i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(i)]; if (increment_overflow(&yourtm.tm_year, 1)) ! return WRONG; } for ( ; ; ) { i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; --- 1446,1452 ---- i = yourtm.tm_year + (1 < yourtm.tm_mon); yourtm.tm_mday -= year_lengths[isleap(i)]; if (increment_overflow(&yourtm.tm_year, 1)) ! return ERANGE; } for ( ; ; ) { i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon]; *************** *** 1378,1388 **** if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (increment_overflow(&yourtm.tm_year, 1)) ! return WRONG; } } if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) ! return WRONG; if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { /* ** We can't set tm_sec to 0, because that might push the --- 1456,1466 ---- if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; if (increment_overflow(&yourtm.tm_year, 1)) ! return ERANGE; } } if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE)) ! return ERANGE; if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) { /* ** We can't set tm_sec to 0, because that might push the *************** *** 1393,1399 **** ** which is a safer assumption than using 58 would be. */ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) ! return WRONG; saved_seconds = yourtm.tm_sec; yourtm.tm_sec = SECSPERMIN - 1; } else { --- 1471,1477 ---- ** which is a safer assumption than using 58 would be. */ if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) ! return ERANGE; saved_seconds = yourtm.tm_sec; yourtm.tm_sec = SECSPERMIN - 1; } else { *************** *** 1412,1424 **** */ t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); for ( ; ; ) { ! (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); if (dir != 0) { ! if (bits-- < 0) ! return WRONG; ! if (bits < 0) ! --t; /* may be needed if new t is minimal */ else if (dir > 0) t -= ((time_t) 1) << bits; else t += ((time_t) 1) << bits; --- 1490,1517 ---- */ t = TYPE_SIGNED(time_t) ? 0 : (((time_t) 1) << bits); for ( ; ; ) { ! tzsub(&t, sp, offset, &mytm, 0); dir = tmcomp(&mytm, &yourtm); if (dir != 0) { ! if (bits-- < 0) { ! /* ! ** Assume that MAX_TIME and MIN_TIME aren't ! ** near a leap-forward interval. ! ** With signed 32-bit time_t, they're in ! ** January and December respectively, ! ** so it's unlikely. ! */ ! if (t == MAX_TIME || t == MIN_TIME) ! return ERANGE; ! return EINVAL; ! } ! if (bits < 0) { ! /* may be needed if new t is minimal, ! ** since we started above the median. ! */ ! if (dir > 0) ! --t; ! } else if (dir > 0) t -= ((time_t) 1) << bits; else t += ((time_t) 1) << bits; *************** *** 1435,1447 **** /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ - sp = (const struct state *) - (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); - #ifdef ALL_STATE if (sp == NULL) ! return WRONG; ! #endif /* defined ALL_STATE */ for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; --- 1528,1535 ---- /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ if (sp == NULL) ! return EINVAL; for (i = sp->typecnt - 1; i >= 0; --i) { if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) continue; *************** *** 1450,1456 **** continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; ! (*funcp)(&newt, offset, &mytm); if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) --- 1538,1544 ---- continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; ! tzsub(&newt, sp, offset, &mytm, 0); if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) *************** *** 1462,1524 **** goto label; } } ! return WRONG; } label: newt = t + saved_seconds; if ((newt < t) != (saved_seconds < 0)) ! return WRONG; t = newt; ! (*funcp)(&t, offset, tmp); ! *okayp = TRUE; ! return t; } ! static time_t ! time2(tmp, funcp, offset, okayp) struct tm * const tmp; ! void (* const funcp) P((const time_t*, long, struct tm*)); const long offset; - int * const okayp; { time_t t; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ ! t = time2sub(tmp, funcp, offset, okayp, FALSE); ! return *okayp ? t : time2sub(tmp, funcp, offset, okayp, TRUE); } ! static time_t ! time1(tmp, funcp, offset) struct tm * const tmp; ! void (* const funcp) P((const time_t *, long, struct tm *)); const long offset; { ! register time_t t; ! register const struct state * sp; register int samei, otheri; ! int okay; if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; ! t = time2(tmp, funcp, offset, &okay); #ifdef PCTS ! /* ! ** PCTS code courtesy Grant Sullivan (grant@osf.org). ! */ ! if (okay) ! return t; ! if (tmp->tm_isdst < 0) ! tmp->tm_isdst = 0; /* reset to std and try again */ ! #endif /* defined PCTS */ ! #ifndef PCTS ! if (okay || tmp->tm_isdst < 0) ! return t; #endif /* !defined PCTS */ /* ** We're supposed to assume that somebody took a time of one type ** and did some math on it that yielded a "struct tm" that's bad. --- 1550,1621 ---- goto label; } } ! return EINVAL; } label: newt = t + saved_seconds; if ((newt < t) != (saved_seconds < 0)) ! return ERANGE; t = newt; ! tzsub(&t, sp, offset, tmp, 0); ! *timep = t; ! return 0; } ! static int ! time2(timep, tmp, tz, offset) ! time_t * timep; struct tm * const tmp; ! const struct tzinfo * tz; const long offset; { time_t t; + int err; /* ** First try without normalization of seconds ** (in case tm_sec contains a value associated with a leap second). ** If that fails, try with normalization of seconds. */ ! err = time2sub(&t, tmp, tz, offset, FALSE); ! if (err == 0) { ! *timep = t; ! return 0; ! } ! return time2sub(timep, tmp, tz, offset, TRUE); } ! static int ! time1(timep, tmp, sp, offset, accomodate_gap) ! time_t * timep; struct tm * const tmp; ! const struct tzinfo * sp; const long offset; + int accomodate_gap; { ! time_t t; register int samei, otheri; ! int err; if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; ! err = time2(&t, tmp, sp, offset); ! if (err == 0) { ! *timep = t; ! return 0; ! } ! if (tmp->tm_isdst < 0) { #ifdef PCTS ! /* ! ** PCTS code courtesy Grant Sullivan (grant@osf.org). ! */ ! if (accomodate_gap) ! /* reset to std and try again */ ! tmp->tm_isdst = 0; ! else #endif /* !defined PCTS */ + return (err != 0 ? err : EINVAL); + } /* ** We're supposed to assume that somebody took a time of one type ** and did some math on it that yielded a "struct tm" that's bad. *************** *** 1528,1539 **** /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ - sp = (const struct state *) (((void *) funcp == (void *) localsub) ? - lclptr : gmtptr); - #ifdef ALL_STATE if (sp == NULL) ! return WRONG; ! #endif /* defined ALL_STATE */ for (samei = sp->typecnt - 1; samei >= 0; --samei) { if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; --- 1625,1632 ---- /* ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's. */ if (sp == NULL) ! return (err != 0 ? err : EINVAL); for (samei = sp->typecnt - 1; samei >= 0; --samei) { if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) continue; *************** *** 1543,1565 **** tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; ! t = time2(tmp, funcp, offset, &okay); ! if (okay) ! return t; tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; } } ! return WRONG; } time_t mktime(tmp) struct tm * const tmp; { ! tzset(); ! return time1(tmp, localsub, 0L); } #ifdef STD_INSPIRED --- 1636,1670 ---- tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; ! err = time2(&t, tmp, sp, offset); ! if (err == 0) { ! *timep = t; ! return 0; ! } tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; tmp->tm_isdst = !tmp->tm_isdst; } } ! return (err != 0 ? err : EINVAL); } time_t mktime(tmp) struct tm * const tmp; { ! time_t mktime_return_value; ! int err; ! struct tzinfo *tz; ! int process_wide; ! ! LOCK_LCLPTR(); ! tz = GET_LCLPTR(&process_wide); ! if (process_wide) ! tzset_basic(tz); ! err = time1(&mktime_return_value, tmp, tz, 0L, 1); ! UNLOCK_LCLPTR(); ! return (err == 0 ? mktime_return_value : WRONG); } #ifdef STD_INSPIRED *************** *** 1576,1583 **** timegm(tmp) struct tm * const tmp; { tmp->tm_isdst = 0; ! return time1(tmp, gmtsub, 0L); } time_t --- 1681,1692 ---- timegm(tmp) struct tm * const tmp; { + time_t timegm_return_value; + int err; + tmp->tm_isdst = 0; ! err = time1(&timegm_return_value, tmp, GET_GMTPTR(), 0L, 1); ! return (err == 0 ? timegm_return_value : WRONG); } time_t *************** *** 1585,1594 **** struct tm * const tmp; const long offset; { tmp->tm_isdst = 0; ! return time1(tmp, gmtsub, offset); } #endif /* defined STD_INSPIRED */ #ifdef CMUCS --- 1694,1811 ---- struct tm * const tmp; const long offset; { + time_t timeoff_return_value; + int err; + tmp->tm_isdst = 0; ! err = time1(&timeoff_return_value, tmp, GET_GMTPTR(), offset, 1); ! return (err == 0 ? timeoff_return_value : WRONG); ! } ! ! ! /* ! ** Thread-safety functions ! */ ! ! int ! tz_prep(tz_p, name) ! struct tzinfo** tz_p; ! const char * name; ! { ! struct tzinfo * result; ! ! result = (struct tzinfo *) malloc(sizeof(struct tzinfo)); ! if (result == NULL) { ! return errno; ! } ! ! if (name != NULL && *name == '\0') { ! /* Zero-length string. Indicates GMT. */ ! #ifdef TZCODE_GMT_USAGE ! /* ! ** Traditional tzcode usage is that the zero-length string ! ** means GMT without leap seconds. ! */ ! result->leapcnt = 0; /* so, we're off a little */ ! result->timecnt = 0; ! result->typecnt = 0; ! result->ttis[0].tt_isdst = 0; ! result->ttis[0].tt_gmtoff = 0; ! result->ttis[0].tt_abbrind = 0; ! (void) strcpy(result->chars, gmt); ! #else ! gmtload(result); ! #endif ! } ! else { ! /* ! ** 1. Try to tzload. ! ** 2. If name is non-NULL and doesn't begin with :, ! ** try to tzparse. ! ** 3. Fail ENOENT. ! */ ! if (tzload(name, result) != 0) { ! if (name != NULL && name[0] != ':') { ! if (tzparse(name, result, FALSE) != 0) { ! goto noentry; ! } ! } ! else { ! goto noentry; ! } ! } ! } ! ! *tz_p = result; ! return 0; ! ! noentry: ! free(result); ! return ENOENT; } + + void + tz_free(tz) + struct tzinfo* tz; + { + free(tz); + } + + + int + time_make(timep, tmp, tz) + time_t * timep; + struct tm *tmp; + const struct tzinfo *tz; + { + return time1(timep, tmp, tz, 0L, 0); + } + + + int time_breakup(tmp, timep, tz) + struct tm * tmp; + const time_t * timep; + const struct tzinfo * tz; + { + tzsub(timep, tz, 0L, tmp, 0); + return 0; + } + + + int + pthread_settz(tz) + const struct tzinfo * tz; + { + if (tz != NULL) { + return SET_THREAD_LCLPTR(tz); + } + else { + return CLEAR_THREAD_LCLPTR(); + } + } + + #endif /* defined STD_INSPIRED */ #ifdef CMUCS *************** *** 1626,1640 **** */ static long ! leapcorr(timep) ! time_t * timep; { ! register struct state * sp; ! register struct lsinfo * lp; register int i; ! sp = lclptr; ! i = sp->leapcnt; while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) --- 1843,1856 ---- */ static long ! leapcorr(timep, sp) ! time_t * timep; ! const struct tzinfo * const sp; { ! register const struct lsinfo * lp; register int i; ! i = (sp == NULL ? 0 : sp->leapcnt); while (--i >= 0) { lp = &sp->lsis[i]; if (*timep >= lp->ls_trans) *************** *** 1647,1654 **** time2posix(t) time_t t; { ! tzset(); ! return t - leapcorr(&t); } time_t --- 1863,1873 ---- time2posix(t) time_t t; { ! const struct tzinfo * sp; ! ! sp = GET_GMTPTR(); ! gmtset(sp); ! return t - leapcorr(&t, sp); } time_t *************** *** 1657,1683 **** { time_t x; time_t y; - tzset(); /* ** For a positive leap second hit, the result ** is not unique. For a negative leap second ** hit, the corresponding time doesn't exist, ** so we return an adjacent second. */ ! x = t + leapcorr(&t); ! y = x - leapcorr(&x); if (y < t) { do { x++; ! y = x - leapcorr(&x); } while (y < t); if (t != y) return x - 1; } else if (y > t) { do { --x; ! y = x - leapcorr(&x); } while (y > t); if (t != y) return x + 1; --- 1876,1905 ---- { time_t x; time_t y; + const struct tzinfo * sp; + + sp = GET_GMTPTR(); + gmtset(sp); /* ** For a positive leap second hit, the result ** is not unique. For a negative leap second ** hit, the corresponding time doesn't exist, ** so we return an adjacent second. */ ! x = t + leapcorr(&t, sp); ! y = x - leapcorr(&x, sp); if (y < t) { do { x++; ! y = x - leapcorr(&x, sp); } while (y < t); if (t != y) return x - 1; } else if (y > t) { do { --x; ! y = x - leapcorr(&x, sp); } while (y > t); if (t != y) return x + 1; diff -crN -x *~ ../tzcode2001c/private.h thread-safe-2/private.h *** ../tzcode2001c/private.h Tue Jun 5 13:48:21 2001 --- thread-safe-2/private.h Mon Jun 18 15:59:54 2001 *************** *** 206,211 **** --- 206,215 ---- void ifree P((char * pointer)); char * scheck P((const char *string, const char *format)); + struct tzinfo; + const struct ttinfo * _tz_getttype P((const time_t * const timep, + const struct tzinfo * sp)); + /* ** Finally, some convenience items. *************** *** 237,242 **** --- 241,256 ---- #define INT_STRLEN_MAXIMUM(type) \ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type)) #endif /* !defined INT_STRLEN_MAXIMUM */ + + /* + ** Big enough for something such as + ** ??? ???-2147483648 -2147483648:-2147483648:-2147483648 -2147483648\n + ** (two three-character abbreviations, five strings denoting integers, + ** three explicit spaces, two explicit colons, a newline, + ** and a trailing ASCII nul). + */ + + #define ASCTIME_BUF_SIZE (3 * 2 + 5 * INT_STRLEN_MAXIMUM(int) + 3 + 2 + 1 + 1) /* ** INITIALIZE(x) diff -crN -x *~ ../tzcode2001c/pthread_settz.3 thread-safe-2/pthread_settz.3 *** ../tzcode2001c/pthread_settz.3 Wed Dec 31 19:00:00 1969 --- thread-safe-2/pthread_settz.3 Mon Jun 18 15:46:08 2001 *************** *** 0 **** --- 1,100 ---- + .TH PTHREAD_SETTZ 3 + .SH NAME + pthread_settz \- locally set the time zone for the current POSIX thread + .SH SYNOPSIS + .nf + .B #include + .B #include + .PP + .B int pthread_settz(tz) + .B const struct tzinfo *tz; + .PP + .B cc ... -ltz -lpthread + .fi + .SH DESCRIPTION + .B Pthread_settz() + sets the time zone object to be used for time functions called from the + current POSIX thread to the time zone object specified by + .IR tz , + if it is non-\fBNULL\fR. If + .IR tz + is + .BR NULL , + the time zone for the current POSIX thread is reset to the global time zone + object. The time zone setting for all other threads remains the same. + .PP + Once + .B pthread_settz() + has been called with a non-\fBNULL\fR value, all calls to the functions + .BR localtime(3) , + .BR localtime_r(3) , + .BR ctime(3) , + .BR ctime_r(3) , + .BR asctime(3) , + .BR asctime_r(3) , + .BR mktime(3) , + and + .BR strftime(3) + in the thread from which + .B pthread_settz() + was called will use the time zone specified by + .IR tz , + rather than the process-wide time zone. + .PP + .B pthread_settz() + does not alter the global variable + .BR tzname . + No function which normally implicitly sets + .B tzname + will do so while a thread-local time zone is in effect. + .PP + Calls to + .B tzset(3) + or + .BR tzsetwall(3) , + while a thread-local time zone is in effect, will alter the global time + zone, but will not affect the local time zone. + .PP + .B pthread_settz() + may allocate a thread-specific data key, which may count towards the number + of keys + .B PTHREAD_KEYS_MAX + that can be allocated by + .BR pthread_key_create() . + .SH RETURN VALUES + Upon successful completion, + .B pthread_settz() + function returns a value of + .BR 0 . + Otherwise, an error number is returned to indicate an error. + .SH ERRORS + .B pthread_settz() + may fail if: + .IP \fBENOMEM\fR + Insufficient memory exists to store the time zone information for the + thread. + .PP + .IP \fBEAGAIN\fR + The system lacked the necessary resources to associate the time zone + information with the thread. + .SH SEE ALSO + getenv(3), + newctime(3), + newstrftime(3), + newtzset(3), + pthread_key_create(3), + time(2), + time_make(3), + tz_prep(3), + tzfile(5) + .SH NOTES + This function allows existing code which uses the ISO C APIs to work + correctly, unmodified, in a threaded environment. However, code which uses + use the extended parts of the POSIX APIs (involving global variables, or + .BR tzset() ) + may not work correctly unmodified. + .PP + No parallel function + .B pthread_gettz() + is defined. + .\" @(#)pthread_settz.3 1.0 diff -crN -x *~ ../tzcode2001c/strftime.c thread-safe-2/strftime.c *** ../tzcode2001c/strftime.c Tue Jun 5 13:49:50 2001 --- thread-safe-2/strftime.c Mon Jun 18 16:11:40 2001 *************** *** 9,14 **** --- 9,15 ---- #endif /* !defined lint */ #include "private.h" + #include "struct_tzinfo.h" /* ** Copyright (c) 1989 The Regents of the University of California. *************** *** 37,42 **** --- 38,47 ---- #include "fcntl.h" #include "locale.h" + #include "tztimeext.h" + + #include TZTHREAD_HEADER_H + struct lc_time_T { const char * mon[MONSPERYEAR]; const char * month[MONSPERYEAR]; *************** *** 108,114 **** static char * _add P((const char *, char *, const char *)); static char * _conv P((int, const char *, char *, const char *)); ! static char * _fmt P((const char *, const struct tm *, char *, const char *, int *)); size_t strftime P((char *, size_t, const char *, const struct tm *)); --- 113,119 ---- static char * _add P((const char *, char *, const char *)); static char * _conv P((int, const char *, char *, const char *)); ! static char * _fmt P((const char *, const struct tm *, char *, const char *, int *, const struct tzinfo *)); size_t strftime P((char *, size_t, const char *, const struct tm *)); *************** *** 125,145 **** #define IN_ALL 3 size_t ! strftime(s, maxsize, format, t) char * const s; const size_t maxsize; const char * const format; const struct tm * const t; { char * p; int warn; - tzset(); #ifdef LOCALE_HOME localebuf.mon[0] = 0; #endif /* defined LOCALE_HOME */ warn = IN_NONE; ! p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn); #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { (void) fprintf(stderr, "\n"); --- 130,151 ---- #define IN_ALL 3 size_t ! strftime_z(s, maxsize, format, t, tz) char * const s; const size_t maxsize; const char * const format; const struct tm * const t; + const struct tzinfo * tz; { char * p; int warn; #ifdef LOCALE_HOME localebuf.mon[0] = 0; #endif /* defined LOCALE_HOME */ warn = IN_NONE; ! p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, ! tz); #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { (void) fprintf(stderr, "\n"); *************** *** 156,174 **** (void) fprintf(stderr, "\n"); } #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */ ! if (p == s + maxsize) return 0; *p = '\0'; return p - s; } static char * ! _fmt(format, t, pt, ptlim, warnp) const char * format; const struct tm * const t; char * pt; const char * const ptlim; int * warnp; { for ( ; *format; ++format) { if (*format == '%') { --- 162,206 ---- (void) fprintf(stderr, "\n"); } #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */ ! if (p >= s + maxsize) ! /* XXX */ return 0; *p = '\0'; return p - s; } + + size_t + strftime(s, maxsize, format, t) + char * const s; + const size_t maxsize; + const char * const format; + const struct tm * const t; + { + struct tzinfo * lclptr; + int dummy; + size_t ret; + tzset(); + + LOCK_LCLPTR(); + lclptr = GET_LCLPTR(&dummy); + + ret = strftime_z(s, maxsize, format, t, lclptr); + UNLOCK_LCLPTR(); + + if (ret > maxsize) + ret = 0; + return ret; + } + static char * ! _fmt(format, t, pt, ptlim, warnp, tz) const char * format; const struct tm * const t; char * pt; const char * const ptlim; int * warnp; + const struct tzinfo * tz; { for ( ; *format; ++format) { if (*format == '%') { *************** *** 217,223 **** { int warn2 = IN_SOME; ! pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) --- 249,255 ---- { int warn2 = IN_SOME; ! pt = _fmt(Locale->c_fmt, t, pt, ptlim, warnp, tz); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) *************** *** 225,231 **** } continue; case 'D': ! pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); continue; case 'd': pt = _conv(t->tm_mday, "%02d", pt, ptlim); --- 257,263 ---- } continue; case 'D': ! pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, tz); continue; case 'd': pt = _conv(t->tm_mday, "%02d", pt, ptlim); *************** *** 246,252 **** pt = _conv(t->tm_mday, "%2d", pt, ptlim); continue; case 'F': ! pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); continue; case 'H': pt = _conv(t->tm_hour, "%02d", pt, ptlim); --- 278,284 ---- pt = _conv(t->tm_mday, "%2d", pt, ptlim); continue; case 'F': ! pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, tz); continue; case 'H': pt = _conv(t->tm_hour, "%02d", pt, ptlim); *************** *** 310,319 **** pt, ptlim); continue; case 'R': ! pt = _fmt("%H:%M", t, pt, ptlim, warnp); continue; case 'r': ! pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp); continue; case 'S': pt = _conv(t->tm_sec, "%02d", pt, ptlim); --- 342,351 ---- pt, ptlim); continue; case 'R': ! pt = _fmt("%H:%M", t, pt, ptlim, warnp, tz); continue; case 'r': ! pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp, tz); continue; case 'S': pt = _conv(t->tm_sec, "%02d", pt, ptlim); *************** *** 336,342 **** } continue; case 'T': ! pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); continue; case 't': pt = _add("\t", pt, ptlim); --- 368,374 ---- } continue; case 'T': ! pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, tz); continue; case 't': pt = _add("\t", pt, ptlim); *************** *** 449,455 **** ** "date as dd-bbb-YYYY" ** (ado, 1993-05-24) */ ! pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); continue; case 'W': pt = _conv((t->tm_yday + DAYSPERWEEK - --- 481,487 ---- ** "date as dd-bbb-YYYY" ** (ado, 1993-05-24) */ ! pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, tz); continue; case 'W': pt = _conv((t->tm_yday + DAYSPERWEEK - *************** *** 462,474 **** pt = _conv(t->tm_wday, "%d", pt, ptlim); continue; case 'X': ! pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp); continue; case 'x': { int warn2 = IN_SOME; ! pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) --- 494,506 ---- pt = _conv(t->tm_wday, "%d", pt, ptlim); continue; case 'X': ! pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp, tz); continue; case 'x': { int warn2 = IN_SOME; ! pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2, tz); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) *************** *** 490,498 **** pt = _add(t->TM_ZONE, pt, ptlim); else #endif /* defined TM_ZONE */ ! if (t->tm_isdst >= 0) ! pt = _add(tzname[t->tm_isdst != 0], pt, ptlim); /* ** C99 says that %Z must be replaced by the ** empty string if the time zone is not --- 522,539 ---- pt = _add(t->TM_ZONE, pt, ptlim); else #endif /* defined TM_ZONE */ ! if (t->tm_isdst >= 0) { ! time_t tval; ! struct tm tcopy = *t; ! const struct ttinfo * ttisp; ! ! if (time_make(&tval, &tcopy, tz) != 0) ! continue; ! ttisp = _tz_getttype(&tval, tz); ! ! pt = _add(&tz->chars[ttisp->tt_abbrind], pt, ptlim); + } /* ** C99 says that %Z must be replaced by the ** empty string if the time zone is not *************** *** 514,545 **** ** 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 = "-"; --- 555,579 ---- ** be computed by looking only at ** tm_isdst. This requirement is ** incorrect, since it means the code ! ** must rely on magic, and the ** magic might not have the correct ! ** offset. ! ** We perform hopefully-correct magic by ! ** peeking inside the struct tzinfo ! ** structure, in an encapsulation ! ** violation, to find the appropriate ! ** transition type. */ ! { ! time_t tval; ! struct tm tcopy = *t; ! const struct ttinfo * ttisp; ! ! if (time_make(&tval, &tcopy, tz) != 0) ! continue; ! ttisp = _tz_getttype(&tval, tz); ! diff = ttisp->tt_gmtoff; ! } #endif /* !defined TM_GMTOFF */ if (diff < 0) { sign = "-"; *************** *** 553,559 **** continue; case '+': pt = _fmt(Locale->date_fmt, t, pt, ptlim, ! warnp); continue; case '%': /* --- 587,593 ---- continue; case '+': pt = _fmt(Locale->date_fmt, t, pt, ptlim, ! warnp, tz); continue; case '%': /* *************** *** 603,609 **** 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..." */ --- 637,642 ---- *************** *** 664,671 **** 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); --- 697,703 ---- 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); *************** *** 714,720 **** (void) close(fd); no_locale: localebuf = C_time_locale; ! locale_buf = locale_buf_C; return &localebuf; } #endif /* defined LOCALE_HOME */ --- 746,752 ---- (void) close(fd); no_locale: localebuf = C_time_locale; ! locale_buf = NULL; return &localebuf; } #endif /* defined LOCALE_HOME */ diff -crN -x *~ ../tzcode2001c/struct_tzinfo.h thread-safe-2/struct_tzinfo.h *** ../tzcode2001c/struct_tzinfo.h Wed Dec 31 19:00:00 1969 --- thread-safe-2/struct_tzinfo.h Mon Jun 18 15:46:07 2001 *************** *** 0 **** --- 1,58 ---- + #ifndef STRUCT_TIMEZONE_H + + #define STRUCT_TIMEZONE_H + + #include "private.h" + #include "tzfile.h" + + /* + ** This file is in the public domain, so clarified as of + ** 1996-06-05 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. + ** Do NOT copy it to any system include directory. + ** Thank you! + */ + + struct ttinfo { /* time type information */ + long tt_gmtoff; /* UTC 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 UTC */ + }; + + struct lsinfo { /* leap second information */ + time_t ls_trans; /* transition time */ + long ls_corr; /* correction to apply */ + }; + + #define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) + + #ifdef TZNAME_MAX + #define MY_TZNAME_MAX TZNAME_MAX + #endif /* defined TZNAME_MAX */ + #ifndef TZNAME_MAX + #define MY_TZNAME_MAX 255 + #endif /* !defined TZNAME_MAX */ + + struct tzinfo { + int leapcnt; + int timecnt; + int typecnt; + int charcnt; + 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"), + (2 * (MY_TZNAME_MAX + 1)))]; + struct lsinfo lsis[TZ_MAX_LEAPS]; + }; + + + + #endif /* !defined STRUCT_TIMEZONE_H */ diff -crN -x *~ ../tzcode2001c/time_make.3 thread-safe-2/time_make.3 *** ../tzcode2001c/time_make.3 Wed Dec 31 19:00:00 1969 --- thread-safe-2/time_make.3 Mon Jun 18 15:46:08 2001 *************** *** 0 **** --- 1,277 ---- + .TH TIME_MAKE 3 + .SH NAME + time_make, time_breakup, strftime_z \- manipulate time-zone-dependent + time conversions in a thread-safe manner + .SH SYNOPSIS + .nf + .B #include + .B #include + .PP + .B int time_make(clock, tm, tz) + .B time_t *clock; + .B struct tm *tm; + .B const struct tzinfo *tz; + .PP + .B int time_breakup(result, clock, tz) + .B struct tm *result; + .B const time_t *clock; + .B const struct tzinfo *tz; + .PP + .B size_t strftime_z(buf, maxsize, format, timeptr, tz) + .B char * restrict buf; + .B size_t maxsize; + .B const char * restrict format; + .B const struct tm * restrict timeptr; + .B const struct tzinfo * restrict tz; + .PP + .B cc ... -ltz + .fi + .SH DESCRIPTION + .B Time_make() + interprets the broken-down time in + .I *tm + as a local time in the timezone specified in + .IR *tz, + and writes the corresponding value into + .IR *clock, + using the same encoding as that of the values returned by the + .I time function. + .PP + The original values of the + .B tm_wday + and + .B tm_yday + components of + .I *tm + are ignored, and the original values of the other components are not + restricted to their normal ranges. (A positive or zero value for + .B tm_isdst + causes + .B time_make() + to presume initially that summer time (for example, Daylight Saving Time) is + or is not in effect for the specified time, respectively. A negative value + for + .B tm_isdst + causes the + .B time_make() + function to attempt to divine whether summer time is in effect for the + specified time.) + .PP + On successful completion, the values of the + .B tm_wday + and + .B tm_yday + components of + .I *tm + are set appropriately, and the other components are set to represent the + specified calendar time, but with their values forced to their normal + ranges; the final value of + .B tm_mday + is not set until + .B tm_mon + and + .B tm_year + are determined. + .PP + .B Time_breakup() + converts the time value in + .I *clock + to a broken-out time for the value, which it places in + .IR *result , + after adjusting for the time zone specified in + .IR *tz . + .PP + .B Strftime_z() + formats the information from + .I timeptr + into the buffer + .I buf + according to the string pointed to by + .IR format . + The + .I format + string follows the same specification as for the function strftime(3), + except that the values for the conversion specifiers + .B %Z + and + .B %z + are obtained from the time zone + .IR tz . + If + .B strftime_z() + is passed a + .B struct tm + created by a call to + .B time_make() + or + .B time_breakup() + which was given a different time zone object than + .IR tz , + or if it is passed a + .B struct tm + created by + .BR localtime() , + .BR localtime_r() , + .BR gmtime() , + .BR gmtime_r() , + .BR mktime() , + or + .BR timegm() , + the behavior of the + .B %Z + and + .B %z + conversion specifiers is undefined. + .SH RETURN VALUES + The + .B time_make() + function returns a value of + .B 0 + on sucessful completion, sets + .IR *clock , + and normalizes + .IR *tm . + On failure, it returns an error number, and leaves + .I *clock + and + .I *tm + in an indeterminate state. + .PP + The + .B time_breakup() + function returns + .BR 0 , + and fills in + .IR *result , + always. + .PP + On successful completion, + .B strftime_z() + fills in + .I buf + and returns the number of bytes converted. On failure, + .B strftime_z() + returns the number of bytes of buffer that would be required to fully + perform the conversion (including the terminating + .BR NUL ), + and leaves + .I buf + in an indeterminate state. + .SH ERRORS + .B time_make() + shall fail if: + .IP \fBERANGE\fR + .I *tm + does not represent a time representable by a time_t value. + .PP + .B time_make() + may fail if: + .IP \fBEINVAL\fR + .I *tm + does not represent a possible time in the timezone + .IR *tz . + (For instance, it indicates a time occuring during a leap-forward interval.) + .PP + No error status codes are defined for + .BR time_breakup() . + .PP + .B Strftime_z() + does not set or return error statuses. + .SH SEE ALSO + getenv(3), + newctime(3), + newstrftime(3), + newtzset(3), + pthread_settz(3), + time(2), + tz_prep(3), + tzfile(5) + .SH NOTES + .B time_make() + is a generalization of the ISO C function + .B mktime(3) + and the BSD/tzcode function + .BR timegm(3) . + .B time_breakup() + is a generalization of the ISO C functions + .B localtime(3) + and + .BR gmtime(3) , + and the POSIX functions + .B localtime_r(3) + and + .BR gmtime_r(3) . + .B strftime_z() + is a generalization of the ISO C function + .BR strftime(3) . + .PP + Depending on how + .B tzcode + was compiled, + .B time_make() + may handle impossible time values (e.g., values that fall during a + leap-forward interval) by failing and returning + .BR EINVAL , + or by normalizing + .I *tm + to a nearby valid time. + .PP + The return value of + .B strftime_z() + on error has changed from that of + .BR strftime() . + .B Strftime() + returns + .B 0 + if + .I buf + is not large enough. + .BR Strftime_z() , + instead, follows the example of ISO C 99's + .BR snprintf(3) , + by returning the number of bytes that would be required to fully convert the + format string. This allows an appropriately-sized buffer to be allocated in + one step, rather than requiring a binary search. Error returns can be + easily detected by checking (\fIret\fR <= \fImaxbuf\fR). + .PP + The names and calling conventions of + .B time_make() + and + .B time_breakup() + are inspired by Markus Kuhn's proposed + .B xtime_make() + and + .B xtime_breakup() + functions. The + .B xtime_* + functions represent time using + .BR "struct xtime" , + which is a much more sophisticated and better-defined representation of time + than + .BR time_t . + The + .B time_* + functions are designed to be less ambitious while still leaving room + for these future improvements. + .PP + Following Kuhn, + .B time_make() + corrects a flaw of + .B mktime() + and + .BR timegm() . + Those functions use the value + .B (time_t)-1 + to represent an error return status. However, this value can also be a + correct translation of a + .B struct tm + representing the time "December 31, 1969, 23:59:59 GMT" (assuming POSIX + .B time_t + values), + and these cases are not distinguished. Instead, + .B time_make() + uses an out-of-band method to indicate error conditions, leaving + the entire + .B time_t + space free to represent valid values. + .\" @(#)time_make.3 1.0 diff -crN -x *~ ../tzcode2001c/tz_prep.3 thread-safe-2/tz_prep.3 *** ../tzcode2001c/tz_prep.3 Wed Dec 31 19:00:00 1969 --- thread-safe-2/tz_prep.3 Mon Jun 18 15:46:08 2001 *************** *** 0 **** --- 1,120 ---- + .TH TZ_PREP 3 + .SH NAME + tz_prep, tz_free \- create and destroy time zone objects + .SH SYNOPSIS + .nf + .B #include + .B #include + .PP + .B int tz_prep(tz, tzstring) + .B struct tzinfo** tz; + .B const char *tzstring; + .PP + .B void tz_free() + .B struct tzinfo* tzobj; + .PP + .B cc ... -ltz + .fi + .SH DESCRIPTION + The + .B tz_prep() + function creates a new time zone object, corresponding to the + given time zone name + .IR tzstring . + .I tzstring + is a pointer to a string, or + .BR NULL . + .PP + If + .I tzstring + is + .BR NULL , + the returned time zone will represent the system's best approximation of its + current wall clock time. If + .I tzstring + is the zero-length string \fB""\fR, the returned time zone will represent the + system's best approximation of Coordinated Universal Time (UTC). + .PP + All other values of + .I tzstring + are interpreted in the same manner as the + .B TZ + environment variable, as specified in environ(7). + .PP + The + .B tz_free() + function frees a time zone object allocated by + .BR tz_prep() . + .SH RETURN VALUES + On successful completion, + .B tz_prep() + returns a value of + .BR 0 + and fills in + .IR *tz . + On failure, an error number is returned and no resources are allocated. + .PP + The + .B tz_free() + function returns no value. + .SH ERRORS + The + .B tz_prep() + function will fail if: + .IP \fBENOMEM\fR + Not enough memory is available to create the time zone object. + .IP \fBENOENT\fR + No known time zone corresponds to tzname. + .PP + The + .B tz_prep() + function may fail if there is a problem with the system time + zone database which caused retrieval of the time zone information to fail + unexpectedly. In this case any appropriate error number may be returned. + .PP + The + .B tz_free() + function does not return any errors. + .SH FILES + .ta \w'/usr/local/etc/zoneinfo/posixrules\0\0'u + /usr/local/etc/zoneinfo time zone information directory + .br + /usr/local/etc/zoneinfo/localtime local time zone file + .br + /usr/local/etc/zoneinfo/posixrules used with POSIX-style TZ's + .br + /usr/local/etc/zoneinfo/GMT for UTC leap seconds + .sp + If + .B /usr/local/etc/zoneinfo/GMT + is absent, + UTC leap seconds are loaded from + .BR /usr/local/etc/zoneinfo/posixrules . + .SH SEE ALSO + environ(7), + getenv(3), + newlocaltime(3), + newstrftime(3), + newtzset(3), + pthread_settz(3), + time(2), + time_make(3), + tzfile(5) + .SH NOTES + This interface is designed so that calling + \fBtz_prep\fR(\fBgetenv\fR(\fB"TZ"\fR)) + will return an object describing the default time zone object that + non-thread-aware versions of the time functions will use by default, + provided + .B TZ + (if set) is set to a valid time zone name. + .PP + .B tzset() + interprets a + .B TZ + value of the empty string \fB""\fR as meaning "UTC without leap-seconds". + .BR tz_prep() , + however, defines it to mean the standard UTC value, with whatever + leap-second support the system uses by default. On POSIX-compliant systems, + which may not use leap second support by default, these will be equivalent. + .\" @(#)tz_prep.3 1.0 diff -crN -x *~ ../tzcode2001c/tzthread-dummy.c thread-safe-2/tzthread-dummy.c *** ../tzcode2001c/tzthread-dummy.c Wed Dec 31 19:00:00 1969 --- thread-safe-2/tzthread-dummy.c Mon Jun 18 16:15:27 2001 *************** *** 0 **** --- 1,42 ---- + /* + ** This file is in the public domain. Contributed by Jonathan Lennox + ** + */ + + #include "private.h" + #include "tzthread-dummy.h" + #include "struct_tzinfo.h" + + /* + ** "Dummy" definitions of the TZ thread-safety operations. For use in + ** a non-threaded environment. + */ + + #ifdef ALL_STATE + struct tzinfo * _tz_lclptr; + struct tzinfo * _tz_gmtptr; + + struct tzinfo * _tz_alloc_lclptr P((void)) + { + _tz_lclptr = (struct tzinfo *) malloc(sizeof *_tz_lclptr); + return _tz_lclptr; + } + + + struct tzinfo * _tz_alloc_gmtptr P((void)) + { + _tz_gmtptr = (struct tzinfo *) malloc(sizeof *_tz_gmtptr); + return _tz_gmtptr; + } + + #else /* !defined ALL_STATE */ + + struct tzinfo _tz_lclmem; + struct tzinfo _tz_gmtmem; + + #endif /* !defined ALL_STATE */ + + struct tm _tz_tm; + + char _tz_asctime_buf[ASCTIME_BUF_SIZE]; + diff -crN -x *~ ../tzcode2001c/tzthread-dummy.h thread-safe-2/tzthread-dummy.h *** ../tzcode2001c/tzthread-dummy.h Wed Dec 31 19:00:00 1969 --- thread-safe-2/tzthread-dummy.h Mon Jun 18 16:15:17 2001 *************** *** 0 **** --- 1,127 ---- + #ifndef TZTHREAD_DUMMY_H + #define TZTHREAD_DUMMY_H + + /* + ** This file is in the public domain. Contributed by Jonathan Lennox + ** + */ + + #include "private.h" + + /* + ** Thread primitives for tzcode. TZcode requires the following primitive + ** functions to be defined (probably as macros): + ** void LOCK_LCLPTR(void) - serialize references to the process-wide or + ** thread-specific local timezone object. + ** void LOCK_GMTPTR(void) - serialize references to write to the global + ** UTC timezone object. + ** void UNLOCK_LCLPTR(void) - Unlock the local timezone object. + ** void UNLOCK_GMTPTR(void) - Unlock the UTC timezone object. + ** + ** struct tzinfo * GET_LCLPTR(int *process) + ** - Return the current local timezone object. + ** The argument 'process' is filled in with + ** a boolean value indicating whether the + ** returned object is process-wide (true) + ** or thread-specific (false). + ** This will only be called when the local + ** pointer is locked. + ** The thread primitive is not responsible for + ** filling in the value, only for assuring that + ** sizeof(struct tzinfo) bytes are available. + ** This function returns NULL on failure. + ** + ** struct tzinfo * GET_GMTPTR(void) + ** - Return the UTC timezone object. + ** This *can* be called when the GMT pointer + ** is not locked. This function is responsible + ** for any resulting serialization necessary. + ** Any attempts to write to the object *will* + ** lock the object first, however. + ** The thread primitive is not responsible for + ** filling in the value, only for assuring that + ** sizeof(struct tzinfo) bytes are available. + ** This function returns NULL on failure. + ** + ** struct tm *GET_TM_BUF(void) - Get a pointer to a struct tm, suitable for + ** use as a return value for the localtime() + ** family of functions. In a threaded + ** environment, this buffer should be thread- + ** local. + ** + ** int SET_THREAD_LCLPTR(const struct tzinfo *) + ** - Set the thread-specific local timezone + ** object to (a copy of) the argument. Calls to + ** GET_LCLPTR() from the current thread should + ** from now on return this value. + ** If a previous local pointer was set, free + ** it first. + ** Return an errno error code on failure, or 0. + ** + ** int CLEAR_THREAD_LCLPTR(void) + ** - Clear the thread-specific local timezone + ** object to the argument. Calls to + ** GET_LCLPTR() from the current thread should + ** from now on return the global pointer. + ** If a previous local pointer was set, free + ** it first. + ** Return an errno error code on failure, or 0. + */ + + /* + ** "Dummy" definitions of the TZ thread-safety operations. For use in + ** a non-threaded environment. + */ + + /* + ** There are actually two dummy TZ implementations -- one for ALL_STATE + ** (structures allocated as-needed) and one for static. + */ + + #ifdef ALL_STATE + extern struct tzinfo * _tz_lclptr; + extern struct tzinfo * _tz_gmtptr; + + #define GET_LCLPTR(_process_wide) \ + (*(_process_wide) = 1, \ + (_tz_lclptr != NULL ? _tz_lclptr : _tz_alloc_lclptr())) + #define GET_GMTPTR() \ + (_tz_gmtptr != NULL ? _tz_gmtptr : _tz_alloc_gmtptr()) + + extern struct tzinfo * _tz_alloc_lclptr P((void)); + extern struct tzinfo * _tz_alloc_gmtptr P((void)); + + #else /* !defined ALL_STATE */ + + extern struct tzinfo _tz_lclmem; + extern struct tzinfo _tz_gmtmem; + #define GET_LCLPTR(_process_wide) (*(_process_wide) = 1, &_tz_lclmem) + #define GET_GMTPTR() (&_tz_gmtmem) + + #endif /* !defined ALL_STATE */ + + /* + ** These dummy implementations apply regardless of ALL_STATE, since we're + ** non-threaded. + */ + + #define LOCK_LCLPTR() do { } while(0) + #define LOCK_GMTPTR() do { } while(0) + + #define UNLOCK_LCLPTR() do { } while(0) + #define UNLOCK_GMTPTR() do { } while(0) + + extern struct tm _tz_tm; + + #define GET_TM_BUF() (&_tz_tm) + + extern char _tz_asctime_buf[ASCTIME_BUF_SIZE]; + + #define GET_ASCTIME_BUF() (_tz_asctime_buf) + + #define SET_THREAD_LCLPTR(x) (ENOSYS) + #define CLEAR_THREAD_LCLPTR() (ENOSYS) + + #endif /* !defined TZTHREAD_DUMMY_H */ + + diff -crN -x *~ ../tzcode2001c/tzthread-posix.c thread-safe-2/tzthread-posix.c *** ../tzcode2001c/tzthread-posix.c Wed Dec 31 19:00:00 1969 --- thread-safe-2/tzthread-posix.c Mon Jun 18 16:15:47 2001 *************** *** 0 **** --- 1,282 ---- + /* + ** This file is in the public domain. Contributed by Jonathan Lennox + ** + */ + + #include "private.h" + #include "tzthread-posix.h" + #include "struct_tzinfo.h" + + #include + + /* + ** POSIX Thread versions of the TZ thread-safety operations. + */ + + static pthread_mutex_t _tz_lcl_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t _tz_gmt_mutex = PTHREAD_MUTEX_INITIALIZER; + + static int get_lclptr_key P((pthread_key_t *)); + + #ifdef ALL_STATE + static struct tzinfo * _tz_lclptr; + static struct tzinfo * _tz_gmtptr; + + struct tzinfo* + _tz_get_lclptr(process_wide) + int * process_wide; + { + pthread_key_t lclptr_key; + struct tzinfo *ret; + + if (get_lclptr_key(&lclptr_key) != 0) { + return NULL; + } + if ((ret = pthread_getspecific(lclptr_key)) != NULL) { + *process_wide = 0; + return ret; + } + + *process_wide = 1; + + if (_tz_lclptr == NULL) { + _tz_lclptr = (struct tzinfo *) malloc(sizeof *_tz_lclptr); + } + return _tz_lclptr; + } + + + struct tzinfo* + _tz_get_gmtptr P((void)) + { + /* + ** Fast-path the common case. Nothing sets or alters gmtptr + ** once it's set. + */ + if (_tz_gmtptr != NULL) { + return _tz_gmtptr; + } + + _tz_lock_gmtptr(); + /* + ** Check the pointer again, in case another thread just + ** allocated it. + */ + if (_tz_gmtptr != NULL) { + _tz_unlock_gmtptr(); + return _tz_gmtptr; + } + + _tz_gmtptr = (struct tzinfo *) malloc(sizeof *_tz_gmtptr); + _tz_unlock_gmtptr(); + + return _tz_gmtptr; + } + + #else /* !defined ALL_STATE */ + + static struct tzinfo _tz_lclmem; + static struct tzinfo _tz_gmtmem; + + struct tzinfo * + _tz_get_lclptr(process_wide) + int * process_wide; + { + pthread_key_t lclptr_key; + struct tzinfo *ret; + + if (get_lclptr_key(&lclptr_key) != 0) { + return NULL; + } + if ((ret = pthread_getspecific(lclptr_key)) != NULL) { + *process_wide = 0; + return ret; + } + + *process_wide = 1; + + return &_tz_lclmem; + } + + + struct tzinfo * + _tz_get_gmtptr P((void)) + { + return &_tz_gmtmem; + } + + #endif /* defined ALL_STATE */ + + void _tz_lock_lclptr P((void)) + { + pthread_mutex_lock(&_tz_lcl_mutex); + } + + + void _tz_lock_gmtptr P((void)) + { + pthread_mutex_lock(&_tz_gmt_mutex); + } + + + extern void _tz_unlock_lclptr P((void)) + { + pthread_mutex_unlock(&_tz_lcl_mutex); + } + + + extern void _tz_unlock_gmtptr P((void)) + { + pthread_mutex_unlock(&_tz_gmt_mutex); + } + + + + struct tm* + _tz_get_tm_buf P((void)) + { + static pthread_mutex_t tmbuf_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t tmbuf_key; + static int tmbuf_initialized = 0; + struct tm *p_tm; + int err; + + if (!tmbuf_initialized) { + pthread_mutex_lock(&tmbuf_mutex); + if (!tmbuf_initialized) { + if ((err = pthread_key_create(&tmbuf_key, free)) + != 0) { + errno = err; + pthread_mutex_unlock(&tmbuf_mutex); + return NULL; + } + tmbuf_initialized = 1; + } + pthread_mutex_unlock(&tmbuf_mutex); + } + + p_tm = pthread_getspecific(tmbuf_key); + if (p_tm == NULL) { + if ((p_tm = (struct tm *) malloc(sizeof(struct tm))) == NULL) { + return NULL; + } + if ((err = pthread_setspecific(tmbuf_key, p_tm)) != 0) { + errno = err; + free(p_tm); + return NULL; + } + } + return p_tm; + } + + + char* _tz_get_asctime_buf P((void)) + { + static pthread_mutex_t asctime_buf_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t asctime_buf_key; + static int asctime_buf_initialized = 0; + char *asctime_buf; + int err; + + if (!asctime_buf_initialized) { + pthread_mutex_lock(&asctime_buf_mutex); + if (!asctime_buf_initialized) { + if ((err = pthread_key_create(&asctime_buf_key, free)) + != 0) { + errno = err; + pthread_mutex_unlock(&asctime_buf_mutex); + return NULL; + } + asctime_buf_initialized = 1; + } + pthread_mutex_unlock(&asctime_buf_mutex); + } + + asctime_buf = pthread_getspecific(asctime_buf_key); + if (asctime_buf == NULL) { + if ((asctime_buf = (char *) malloc(ASCTIME_BUF_SIZE)) + == NULL) { + return NULL; + } + if ((err = pthread_setspecific(asctime_buf_key, asctime_buf)) + != 0) { + errno = err; + free(asctime_buf); + return NULL; + } + } + return asctime_buf; + } + + + int _tz_set_thread_lclptr(tz) + const struct tzinfo * tz; + { + pthread_key_t lclptr_key; + int err; + struct tzinfo *old, *new; + + if ((err = get_lclptr_key(&lclptr_key)) != 0) { + return err; + } + if ((old = pthread_getspecific(lclptr_key)) != NULL) { + free(old); + } + + new = (struct tzinfo *) malloc(sizeof(struct tzinfo)); + if (new == NULL) { + return ENOMEM; + } + + *new = *tz; + + if ((err = pthread_setspecific(lclptr_key, new)) != 0) { + free(new); + return err; + } + return 0; + } + + + int _tz_clear_thread_lclptr P((void)) + { + pthread_key_t lclptr_key; + int err; + struct tzinfo *old; + + if ((err = get_lclptr_key(&lclptr_key)) != 0) { + return err; + } + if ((old = pthread_getspecific(lclptr_key)) != NULL) { + free(old); + } + + return pthread_setspecific(lclptr_key, NULL); + } + + + static int get_lclptr_key(lclptr_key_p) + pthread_key_t * lclptr_key_p; + { + static pthread_mutex_t lclptr_key_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_key_t lclptr_key; + static int lclptr_key_initialized = 0; + + int err; + + if (!lclptr_key_initialized) { + pthread_mutex_lock(&lclptr_key_mutex); + if (!lclptr_key_initialized) { + if ((err = pthread_key_create(&lclptr_key, free)) + != 0) { + pthread_mutex_unlock(&lclptr_key_mutex); + return err; + } + lclptr_key_initialized = 1; + } + pthread_mutex_unlock(&lclptr_key_mutex); + } + + *lclptr_key_p = lclptr_key; + return 0; + } diff -crN -x *~ ../tzcode2001c/tzthread-posix.h thread-safe-2/tzthread-posix.h *** ../tzcode2001c/tzthread-posix.h Wed Dec 31 19:00:00 1969 --- thread-safe-2/tzthread-posix.h Mon Jun 18 16:20:38 2001 *************** *** 0 **** --- 1,109 ---- + #ifndef TZTHREAD_POSIX_H + #define TZTHREAD_POSIX_H + + /* + ** This file is in the public domain. Contributed by Jonathan Lennox + ** + */ + + /* + ** Thread primitives for tzcode. TZcode requires the following primitive + ** functions to be defined (probably as macros): + ** void LOCK_LCLPTR(void) - serialize references to the process-wide or + ** thread-specific local timezone object. + ** void LOCK_GMTPTR(void) - serialize references to write to the global + ** UTC timezone object. + ** void UNLOCK_LCLPTR(void) - Unlock the local timezone object. + ** void UNLOCK_GMTPTR(void) - Unlock the UTC timezone object. + ** + ** struct tzinfo * GET_LCLPTR(int *process) + ** - Return the current local timezone object. + ** The argument 'process' is filled in with + ** a boolean value indicating whether the + ** returned object is process-wide (true) + ** or thread-specific (false). + ** This will only be called when the local + ** pointer is locked. + ** The thread primitive is not responsible for + ** filling in the value, only for assuring that + ** sizeof(struct tzinfo) bytes are available. + ** This function returns NULL on failure. + ** + ** struct tzinfo * GET_GMTPTR(void) + ** - Return the UTC timezone object. + ** This *can* be called when the GMT pointer + ** is not locked. This function is responsible + ** for any resulting serialization necessary. + ** Any attempts to write to the object *will* + ** lock the object first, however. + ** The thread primitive is not responsible for + ** filling in the value, only for assuring that + ** sizeof(struct tzinfo) bytes are available. + ** This function returns NULL on failure. + ** + ** struct tm *GET_TM_BUF(void) - Get a pointer to a struct tm, suitable for + ** use as a return value for the localtime() + ** family of functions. In a threaded + ** environment, this buffer should be thread- + ** local. + ** + ** int SET_THREAD_LCLPTR(struct tzinfo *) + ** - Set the thread-specific local timezone + ** object to the argument. Calls to + ** GET_LCLPTR() from the current thread should + ** from now on return this value. + ** If a previous local pointer was set, free + ** it first. + ** Return an errno error code on failure, or 0. + ** + ** int CLEAR_THREAD_LCLPTR(void) + ** - Clear the thread-specific local timezone + ** object to the argument. Calls to + ** GET_LCLPTR() from the current thread should + ** from now on return the global pointer. + ** If a previous local pointer was set, free + ** it first. + ** Return an errno error code on failure, or 0. + */ + + #include "private.h" + + /* + ** POSIX Thread versions of the TZ thread-safety operations. + */ + + extern struct tzinfo * _tz_get_lclptr P((int *)); + extern struct tzinfo * _tz_get_gmtptr P((void)); + + #define GET_LCLPTR _tz_get_lclptr + #define GET_GMTPTR _tz_get_gmtptr + + extern void _tz_lock_lclptr P((void)); + extern void _tz_lock_gmtptr P((void)); + + extern void _tz_unlock_lclptr P((void)); + extern void _tz_unlock_gmtptr P((void)); + + #define LOCK_LCLPTR _tz_lock_lclptr + #define LOCK_GMTPTR _tz_lock_gmtptr + + #define UNLOCK_LCLPTR _tz_unlock_lclptr + #define UNLOCK_GMTPTR _tz_unlock_gmtptr + + extern struct tm* _tz_get_tm_buf P((void)); + + #define GET_TM_BUF _tz_get_tm_buf + + extern char* _tz_get_asctime_buf P((void)); + + #define GET_ASCTIME_BUF _tz_get_asctime_buf + + extern int _tz_set_thread_lclptr P((const struct tzinfo *)); + extern int _tz_clear_thread_lclptr P((void)); + + #define SET_THREAD_LCLPTR _tz_set_thread_lclptr + #define CLEAR_THREAD_LCLPTR _tz_clear_thread_lclptr + + #endif /* !defined TZTHREAD_POSIX_H */ + + diff -crN -x *~ ../tzcode2001c/tztimeext.h thread-safe-2/tztimeext.h *** ../tzcode2001c/tztimeext.h Wed Dec 31 19:00:00 1969 --- thread-safe-2/tztimeext.h Mon Jun 18 15:46:07 2001 *************** *** 0 **** --- 1,75 ---- + #ifndef TZTIMEEXT_H + #define TZTIMEEXT_H + + /* + ** This file is in the public domain. Contributed by Jonathan Lennox + ** + */ + + /* + ** This is an extended version of which provides function definitions + ** for the public functions defined by tzcode. + */ + + #include + + #if __STDC_VERSION__ < 199901 + #undef restrict + #define restrict + #endif + + struct tzinfo; + + #if defined(__STDC__) + + extern void tzsetwall(void); + extern struct tm * offtime(const time_t *, const long); + extern time_t timelocal(struct tm * const); + extern time_t timegm(struct tm * const); + extern time_t timeoff(struct tm * const, const long); + + extern time_t time2posix(time_t); + extern time_t posix2time(time_t); + + extern int tz_prep(struct tzinfo**, const char *); + extern void tz_free(struct tzinfo*); + + extern int time_make(time_t *, struct tm *, + const struct tzinfo *); + extern int time_breakup(struct tm *, const time_t *, + const struct tzinfo *); + extern size_t strftime_z(char * restrict, size_t, + const char * restrict, + const struct tm * restrict, + const struct tzinfo * restrict); + + extern int pthread_settz(const struct tzinfo *); + + #else /* !defined(__STDC__) */ + + extern void tzsetwall(); + extern struct tm * offtime(); + extern time_t timelocal(); + extern time_t timegm(); + extern time_t timeoff(); + + extern time_t time2posix(); + extern time_t posix2time(); + + extern int tz_prep(); + extern void tz_free(); + + extern int time_make(); + extern int time_breakup(); + extern size_t strftime_z(); + + extern int pthread_settz(); + + #endif /* defined(__STDC__) */ + + + #if __STDC_VERSION__ < 199901 + #undef restrict + #endif + + #endif /* TZTIMEEXT_H */