# HG changeset patch # User Timo Sirainen # Date 1190495927 -10800 # Node ID 6d15946eccb506fd81a4ceb2fe3b1af5e7c1259d # Parent c02c7912fb15c4465803d59d4e372009e65f57a6 Rewrote utc_mktime() so it's now MIT licensed. This also fixes handling years older than 1970. diff -r c02c7912fb15 -r 6d15946eccb5 configure.in --- a/configure.in Sat Sep 22 23:14:30 2007 +0300 +++ b/configure.in Sun Sep 23 00:18:47 2007 +0300 @@ -927,9 +927,9 @@ int main() { FILE *f; int bits; - time_t t; - for (bits = 1, t = 1; t > 0; ++bits, t <<= 1) { + for (bits = 1; bits < 64; bits++) { + time_t t = ((time_t)1 << bits) - 1; if (gmtime(&t) == NULL) { bits--; break; @@ -960,6 +960,23 @@ ]) AC_DEFINE_UNQUOTED(TIME_T_MAX_BITS, $gmtime_max_time_t, max. time_t bits gmtime() can handle) +AC_CACHE_CHECK([whether time_t is signed],signed_time_t,[ + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + #include + int main() { + /* return 0 if we're signed */ + exit((time_t)(int)-1 <= 0 ? 0 : 1); + } + ]])],[ + signed_time_t=yes + ], [ + signed_time_t=no + ]) +]) +if test $signed_time_t = yes; then + AC_DEFINE(TIME_T_SIGNED,, Define if your time_t is signed) +fi + dnl * do we have struct iovec AC_MSG_CHECKING([for struct iovec]) AC_CACHE_VAL(i_cv_struct_iovec, diff -r c02c7912fb15 -r 6d15946eccb5 src/lib/utc-mktime.c --- a/src/lib/utc-mktime.c Sat Sep 22 23:14:30 2007 +0300 +++ b/src/lib/utc-mktime.c Sun Sep 23 00:18:47 2007 +0300 @@ -1,148 +1,61 @@ -/* - * Copyright (c) 1998-2000 Carnegie Mellon University. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The name "Carnegie Mellon University" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For permission or any other legal - * details, please contact - * Office of Technology Transfer - * Carnegie Mellon University - * 5000 Forbes Avenue - * Pittsburgh, PA 15213-3890 - * (412) 268-4387, fax: (412) 268-7395 - * tech-transfer@andrew.cmu.edu - * - * 4. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by Computing Services - * at Carnegie Mellon University (http://www.cmu.edu/computing/)." - * - * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO - * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE - * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * - */ -/* - * Copyright (c) 1987, 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Arthur David Olson of the National Cancer Institute. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* -** Adapted from code provided by Robert Elz, who writes: -** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. (mtxinu!kridle now). -** It does a binary search of the time_t space. Since time_t's are -** just 32 bits, its a max of 32 iterations (even at 64 bits it -** would still be very reasonable). -*/ +/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "utc-mktime.h" -static int tmcomp(register const struct tm * const atmp, - register const struct tm * const btmp) +static int tm_cmp(const struct tm *tm1, const struct tm *tm2) { - register int result; + int diff; - if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && - (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && - (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && - (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; + if ((diff = tm1->tm_year - tm2->tm_year) != 0) + return diff; + if ((diff = tm1->tm_mon - tm2->tm_mon) != 0) + return diff; + if ((diff = tm1->tm_mday - tm2->tm_mday) != 0) + return diff; + if ((diff = tm1->tm_hour - tm2->tm_hour) != 0) + return diff; + if ((diff = tm1->tm_min - tm2->tm_min) != 0) + return diff; + return tm1->tm_sec - tm2->tm_sec; } -time_t utc_mktime(struct tm *tm) +time_t utc_mktime(const struct tm *tm) { - register int dir; - register int bits; - register int saved_seconds; - time_t t; - struct tm yourtm, *mytm; + const struct tm *try_tm; + struct tm nosec_tm; + time_t t; + int bits, dir; - yourtm = *tm; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - /* - ** Calculate the number of magnitude bits in a time_t - ** (this works regardless of whether time_t is - ** signed or unsigned, though lint complains if unsigned). - ** - ** We check TIME_T_MAX_BITS beforehand since gmtime() may fail - ** with large 64bit values in some systems. - */ - for (bits = 0, t = 1; t > 0 && bits < TIME_T_MAX_BITS-1; bits++) - t <<= 1; + /* we'll do a binary search across the entire valid time_t range. + when gmtime()'s output matches the tm parameter, we've found the + correct time_t value. this also means that if tm contains invalid + values, -1 is returned. */ +#ifdef TIME_T_SIGNED + t = 0; + bits = TIME_T_MAX_BITS - 1; +#else + t = 1 << (TIME_T_MAX_BITS - 1); + bits = TIME_T_MAX_BITS - 2; +#endif - /* - ** If time_t is signed, then 0 is the median value, - ** if time_t is unsigned, then 1 << bits is median. - */ - t = (t < 0) ? 0 : ((time_t) 1 << bits); - for ( ; ; ) { - mytm = gmtime(&t); - dir = tmcomp(mytm, &yourtm); - if (dir != 0) { - if (bits-- < 0) - return (time_t)-1; - if (bits < 0) - --t; - else if (dir > 0) - t -= (time_t) 1 << bits; - else t += (time_t) 1 << bits; - continue; - } - break; + /* we can ignore seconds in checks and add them back when returning */ + nosec_tm = *tm; + nosec_tm.tm_sec = 0; + + for (;; bits--) { + try_tm = gmtime(&t); + dir = tm_cmp(&nosec_tm, try_tm); + if (dir == 0) + return t + tm->tm_sec; + if (bits < 0) + break; + + if (dir < 0) + t -= (time_t)1 << bits; + else + t += (time_t)1 << bits; } - t += saved_seconds; - return t; + + return (time_t)-1; } diff -r c02c7912fb15 -r 6d15946eccb5 src/lib/utc-mktime.h --- a/src/lib/utc-mktime.h Sat Sep 22 23:14:30 2007 +0300 +++ b/src/lib/utc-mktime.h Sun Sep 23 00:18:47 2007 +0300 @@ -5,6 +5,6 @@ /* Like mktime(), but assume that tm is in UTC. Unlike mktime(), values in tm fields must be in valid range. */ -time_t utc_mktime(struct tm *tm); +time_t utc_mktime(const struct tm *tm); #endif