Proposed changes to asctime.c, zdump.c, and localtime.c
Below find proposed changes, all (I hope) noncontroversial: 1. The addition of a comment to asctime.c warning against relying completely on strftime. 2. Changes to zdump.c to improve the output when gmtime() returns NULL and time_t is a strange type. 3. A fix to the declaration of wildabbr in localtime.c 4. Changes to some localtime.c internal functions from returning voids to returning struct tm *s. The last above is in preparation for doing a better job of handling the situation where a time_t value is fed to localtime or gmtime but the year associated with the time_t value won't fit in an int (as can happen if, for example, time_t is double). --ado ------- asctime.c ------- *** /tmp/geta3717 Mon Dec 27 09:18:15 2004 --- /tmp/getb3717 Mon Dec 27 09:18:15 2004 *************** *** 3,11 **** ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)asctime.c 7.29"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 3,17 ---- ** 1996-06-05 by Arthur David Olson (arthur_david_olson@nih.gov). */ + /* + ** Avoid the temptation to punt entirely to strftime; + ** the output of strftime is supposed to be locale specific + ** whereas the output of asctime is supposed to be constant. + */ + #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)asctime.c 7.30"; #endif /* !defined NOID */ #endif /* !defined lint */ ------- zdump.c ------- *** /tmp/geta3736 Mon Dec 27 09:18:15 2004 --- /tmp/getb3736 Mon Dec 27 09:18:15 2004 *************** *** 1,4 **** ! static char elsieid[] = "@(#)zdump.c 7.57"; /* ** This code has been made independent of the rest of the time --- 1,4 ---- ! static char elsieid[] = "@(#)zdump.c 7.58"; /* ** This code has been made independent of the rest of the time *************** *** 151,156 **** --- 151,157 ---- static time_t hunt P((char * name, time_t lot, time_t hit)); static void setabsolutes(); static void show P((char * zone, time_t t, int v)); + static char * tformat P((void)); static time_t yeartot P((long y)); int *************** *** 469,475 **** if (v) { tmp = gmtime(&t); if (tmp == NULL) { ! (void) printf("%g", (double) t); } else { dumptime(tmp); (void) printf(" UTC"); --- 470,476 ---- if (v) { tmp = gmtime(&t); if (tmp == NULL) { ! (void) printf(tformat(), t); } else { dumptime(tmp); (void) printf(" UTC"); *************** *** 504,509 **** --- 505,529 ---- return (result == NULL) ? &nada : result; } + static char * + tformat() + { + if (0.5 == (time_t) 0.5) /* floating */ + return "%g"; + if (0 > (time_t) -1) { /* signed */ + if (sizeof (time_t) > sizeof (long)) + return "%lld"; + if (sizeof (time_t) == sizeof (long)) + return "%ld"; + return "%d"; + } + if (sizeof (time_t) > sizeof (unsigned long)) + return "%llu"; + if (sizeof (time_t) == sizeof (unsigned long)) + return "%lu"; + return "%u"; + } + static void dumptime(timeptr) register const struct tm * timeptr; ------- localtime.c ------- *** /tmp/geta3754 Mon Dec 27 09:18:15 2004 --- /tmp/getb3754 Mon Dec 27 09:18:15 2004 *************** *** 2,7 **** --- 2,8 ---- ** XXX--do the right thing if time_t is double and ** the value fed to gmtime or localtime is very very negative or ** very very positive (which causes problems with the days-and-rem logic). + ** Also: do the right thing in mktime if time_t is double. */ /* *************** *** 11,17 **** #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.83"; #endif /* !defined NOID */ #endif /* !defined lint */ --- 12,18 ---- #ifndef lint #ifndef NOID ! static char elsieid[] = "@(#)localtime.c 7.85"; #endif /* !defined NOID */ #endif /* !defined lint */ *************** *** 61,67 **** #define WILDABBR " " #endif /* !defined WILDABBR */ ! static char wildabbr[] = "WILDABBR"; static const char gmt[] = "GMT"; --- 62,68 ---- #define WILDABBR " " #endif /* !defined WILDABBR */ ! static char wildabbr[] = WILDABBR; static const char gmt[] = "GMT"; *************** *** 135,143 **** 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 long_increment_overflow P((long * number, int delta)); --- 136,144 ---- 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 struct tm * gmtsub P((const time_t * timep, long offset, struct tm * tmp)); ! static struct tm * localsub P((const time_t * timep, long offset, struct tm * tmp)); static int increment_overflow P((int * number, int delta)); static int long_increment_overflow P((long * number, int delta)); *************** *** 147,164 **** 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)); --- 148,165 ---- int base)); static void settzname P((void)); static time_t time1 P((struct tm * tmp, ! struct tm * (*funcp) P((const time_t *, long, struct tm *)), long offset)); static time_t time2 P((struct tm *tmp, ! struct tm * (*funcp) P((const time_t *, long, struct tm*)), long offset, int * okayp)); static time_t time2sub P((struct tm *tmp, ! struct tm * (*funcp) P((const time_t *, long, struct tm*)), long offset, int * okayp, int do_norm_secs)); ! static struct tm * 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)); *************** *** 1033,1039 **** */ /*ARGSUSED*/ ! static void localsub(timep, offset, tmp) const time_t * const timep; const long offset; --- 1034,1040 ---- */ /*ARGSUSED*/ ! static struct tm * localsub(timep, offset, tmp) const time_t * const timep; const long offset; *************** *** 1042,1055 **** 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; --- 1043,1055 ---- register struct state * sp; register const struct ttinfo * ttisp; register int i; + register struct tm * result; const time_t t = *timep; sp = lclptr; #ifdef ALL_STATE ! if (sp == NULL) ! return gmtsub(timep, offset, tmp); #endif /* defined ALL_STATE */ if (sp->timecnt == 0 || t < sp->ats[0]) { i = 0; *************** *** 1071,1082 **** ** 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 */ } struct tm * --- 1071,1083 ---- ** t += ttisp->tt_gmtoff; ** timesub(&t, 0L, sp, tmp); */ ! result = 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 */ + return result; } struct tm * *************** *** 1084,1091 **** const time_t * const timep; { tzset(); ! localsub(timep, 0L, &tm); ! return &tm; } /* --- 1085,1091 ---- const time_t * const timep; { tzset(); ! return localsub(timep, 0L, &tm); } /* *************** *** 1097,1104 **** const time_t * const timep; struct tm * tm; { ! localsub(timep, 0L, tm); ! return tm; } /* --- 1097,1103 ---- const time_t * const timep; struct tm * tm; { ! return localsub(timep, 0L, tm); } /* *************** *** 1105,1116 **** ** 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 --- 1104,1117 ---- ** gmtsub is to gmtime as localsub is to localtime. */ ! static struct tm * gmtsub(timep, offset, tmp) const time_t * const timep; const long offset; struct tm * const tmp; { + register struct tm * result; + if (!gmt_is_set) { gmt_is_set = TRUE; #ifdef ALL_STATE *************** *** 1119,1125 **** #endif /* defined ALL_STATE */ gmtload(gmtptr); } ! timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as --- 1120,1126 ---- #endif /* defined ALL_STATE */ gmtload(gmtptr); } ! result = timesub(timep, offset, gmtptr, tmp); #ifdef TM_ZONE /* ** Could get fancy here and deliver something such as *************** *** 1139,1144 **** --- 1140,1146 ---- #endif /* State Farm */ } #endif /* defined TM_ZONE */ + return result; } struct tm * *************** *** 1145,1152 **** gmtime(timep) const time_t * const timep; { ! gmtsub(timep, 0L, &tm); ! return &tm; } /* --- 1147,1153 ---- gmtime(timep) const time_t * const timep; { ! return gmtsub(timep, 0L, &tm); } /* *************** *** 1158,1165 **** const time_t * const timep; struct tm * tm; { ! gmtsub(timep, 0L, tm); ! return tm; } #ifdef STD_INSPIRED --- 1159,1165 ---- const time_t * const timep; struct tm * tm; { ! return gmtsub(timep, 0L, tm); } #ifdef STD_INSPIRED *************** *** 1169,1181 **** const time_t * const timep; const long offset; { ! gmtsub(timep, offset, &tm); ! return &tm; } #endif /* defined STD_INSPIRED */ ! static void timesub(timep, offset, sp, tmp) const time_t * const timep; const long offset; --- 1169,1180 ---- const time_t * const timep; const long offset; { ! return gmtsub(timep, offset, &tm); } #endif /* defined STD_INSPIRED */ ! static struct tm * timesub(timep, offset, sp, tmp) const time_t * const timep; const long offset; *************** *** 1275,1280 **** --- 1274,1280 ---- #ifdef TM_GMTOFF tmp->TM_GMTOFF = offset; #endif /* defined TM_GMTOFF */ + return tmp; } char * *************** *** 1391,1397 **** 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; --- 1391,1397 ---- static time_t time2sub(tmp, funcp, offset, okayp, do_norm_secs) struct tm * const tmp; ! struct tm * (* const funcp) P((const time_t*, long, struct tm*)); const long offset; int * const okayp; const int do_norm_secs; *************** *** 1486,1492 **** */ t = TYPE_SIGNED(time_t) ? 0 : (((unsigned long) 1) << bits); for ( ; ; ) { ! (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (bits-- < 0) --- 1486,1492 ---- */ t = TYPE_SIGNED(time_t) ? 0 : (((unsigned long) 1) << bits); for ( ; ; ) { ! /* XXX */ (void) (*funcp)(&t, offset, &mytm); dir = tmcomp(&mytm, &yourtm); if (dir != 0) { if (bits-- < 0) *************** *** 1524,1530 **** 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) --- 1524,1530 ---- continue; newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; ! /* XXX */ (void) (*funcp)(&newt, offset, &mytm); if (tmcomp(&mytm, &yourtm) != 0) continue; if (mytm.tm_isdst != yourtm.tm_isdst) *************** *** 1543,1550 **** if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; ! (*funcp)(&t, offset, tmp); ! *okayp = TRUE; return t; } --- 1543,1550 ---- if ((newt < t) != (saved_seconds < 0)) return WRONG; t = newt; ! if ((*funcp)(&t, offset, tmp)) ! *okayp = TRUE; return t; } *************** *** 1551,1557 **** 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; { --- 1551,1557 ---- static time_t time2(tmp, funcp, offset, okayp) struct tm * const tmp; ! struct tm * (* const funcp) P((const time_t*, long, struct tm*)); const long offset; int * const okayp; { *************** *** 1569,1575 **** 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; --- 1569,1575 ---- static time_t time1(tmp, funcp, offset) struct tm * const tmp; ! struct tm * (* const funcp) P((const time_t *, long, struct tm *)); const long offset; { register time_t t;
"Olson, Arthur David (NIH/NCI)" <olsona@dc37a.nci.nih.gov> writes:
+ static char * + tformat() + { + if (0.5 == (time_t) 0.5) /* floating */ + return "%g";
This mishandles the case where time_t is long double; in that case, presumably you'd use the format "%Lg". Also (and this is a problem with the int code of tformat as well), there's no guarantee that long double has a size greater than double. You might want to put in a comment here, that says the code assumes three things: (1) that arithmetic types with larger size are no narrower than types with smaller size, (2) if two types s and t are the same width, then it's OK to use s's format on a value of type t (a common case is int and long int both being 32 bits wide), and (3) that time_t must be either narrower than int, or the same width as either int, long int, or long long int. C99 does not guarantee any of these assumptions. If you want to remove these assumptions, then we could go down that road, but the basic idea will be to implement that part of C99 that's needed (e.g., intmax_t, uintmax_t).
+ if (sizeof (time_t) == sizeof (long)) + return "%ld";
This should be "if (sizeof (time_t) > sizeof (int))", for consistency with the other tests (and also to avoid storing the unnecessary "l" :-). Similarly for the unsigned code.
participants (3)
-
Ken Pizzini -
Olson, Arthur David (NIH/NCI) -
Paul Eggert