X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/68c45bf06516ed4650eb7f9f617742d84750600a..974aae61bbb8c05e0d0fc1a95b419fe596423fd8:/src/mktime.c diff --git a/src/mktime.c b/src/mktime.c index 3b3330eea0..c61f146356 100644 --- a/src/mktime.c +++ b/src/mktime.c @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Define this to have a standalone program to test this implementation of @@ -117,7 +117,9 @@ const unsigned short int __mon_yday[2][13] = localtime to localtime_r, since many localtime_r implementations are buggy. */ static struct tm * -my_mktime_localtime_r (const time_t *t, struct tm *tp) +my_mktime_localtime_r (t, tp) + const time_t *t; + struct tm *tp; { struct tm *l = localtime (t); if (! l) @@ -135,8 +137,9 @@ my_mktime_localtime_r (const time_t *t, struct tm *tp) If TP is null, return a nonzero value. If overflow occurs, yield the low order bits of the correct answer. */ static time_t -ydhms_tm_diff (int year, int yday, int hour, int min, int sec, - const struct tm *tp) +ydhms_tm_diff (year, yday, hour, min, sec, tp) + int year, yday, hour, min, sec; + const struct tm *tp; { if (!tp) return 1; @@ -167,8 +170,14 @@ ydhms_tm_diff (int year, int yday, int hour, int min, int sec, If *T is out of range for conversion, adjust it so that it is the nearest in-range value and then convert that. */ static struct tm * -ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), - time_t *t, struct tm *tp) +ranged_convert (convert, t, tp) +#ifdef PROTOTYPES + struct tm *(*convert) (const time_t *, struct tm *); +#else + struct tm *(*convert)(); +#endif + time_t *t; + struct tm *tp; { struct tm *r; @@ -215,9 +224,14 @@ ranged_convert (struct tm *(*convert) (const time_t *, struct tm *), compared to what the result would be for UTC without leap seconds. If *OFFSET's guess is correct, only one CONVERT call is needed. */ time_t -__mktime_internal (struct tm *tp, - struct tm *(*convert) (const time_t *, struct tm *), - time_t *offset) +__mktime_internal (tp, convert, offset) + struct tm *tp; +#ifdef PROTOTYPES + struct tm *(*convert) (const time_t *, struct tm *); +#else + struct tm *(*convert)(); +#endif + time_t *offset; { time_t t, dt, t0, t1, t2; struct tm tm; @@ -238,6 +252,9 @@ __mktime_internal (struct tm *tp, int year_requested = tp->tm_year; int isdst = tp->tm_isdst; + /* 1 if the previous probe was DST. */ + int dst2; + /* Ensure that mon is in range, and set year accordingly. */ int mon_remainder = mon % 12; int negative_mon_remainder = mon_remainder < 0; @@ -256,6 +273,13 @@ __mktime_internal (struct tm *tp, + mday - 1); int sec_requested = sec; + + /* Only years after 1970 are defined. + If year is 69, it might still be representable due to + timezone differences. */ + if (year < 69) + return -1; + #if LEAP_SECONDS_POSSIBLE /* Handle out-of-range seconds specially, since ydhms_tm_diff assumes every minute has 60 seconds. */ @@ -272,20 +296,24 @@ __mktime_internal (struct tm *tp, tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0; t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm); - for (t = t1 = t2 = t0 + *offset; + for (t = t1 = t2 = t0 + *offset, dst2 = 0; (dt = ydhms_tm_diff (year, yday, hour, min, sec, ranged_convert (convert, &t, &tm))); - t1 = t2, t2 = t, t += dt) + t1 = t2, t2 = t, t += dt, dst2 = tm.tm_isdst != 0) if (t == t1 && t != t2 - && (isdst < 0 || tm.tm_isdst < 0 - || (isdst != 0) != (tm.tm_isdst != 0))) + && (tm.tm_isdst < 0 + || (isdst < 0 + ? dst2 <= (tm.tm_isdst != 0) + : (isdst != 0) != (tm.tm_isdst != 0)))) /* We can't possibly find a match, as we are oscillating between two values. The requested time probably falls within a spring-forward gap of size DT. Follow the common practice in this case, which is to return a time that is DT away from the requested time, preferring a time whose - tm_isdst differs from the requested value. In practice, - this is more useful than returning -1. */ + tm_isdst differs from the requested value. (If no tm_isdst + was requested and only one of the two values has a nonzero + tm_isdst, prefer that value.) In practice, this is more + useful than returning -1. */ break; else if (--remaining_probes == 0) return -1; @@ -359,6 +387,14 @@ __mktime_internal (struct tm *tp, return -1; } + if (year == 69) + { + /* If year was 69, need to check whether the time was representable + or not. */ + if (t < 0 || t > 2 * 24 * 60 * 60) + return -1; + } + *tp = tm; return t; } @@ -528,3 +564,6 @@ Local Variables: compile-command: "gcc -DDEBUG -DHAVE_LIMITS_H -DSTDC_HEADERS -Wall -W -O -g mktime.c -o mktime" End: */ + +/* arch-tag: 9456752f-7ddd-47cb-8286-fa807b1355ae + (do not change this comment) */