dovecot: Rewrote utc_mktime() so it's now MIT licensed. This als...

dovecot at dovecot.org dovecot at dovecot.org
Sun Sep 23 00:18:51 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/6d15946eccb5
changeset: 6483:6d15946eccb5
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Sep 23 00:18:47 2007 +0300
description:
Rewrote utc_mktime() so it's now MIT licensed. This also fixes handling
years older than 1970.

diffstat:

3 files changed, 68 insertions(+), 138 deletions(-)
configure.in         |   21 +++++
src/lib/utc-mktime.c |  183 +++++++++++++-------------------------------------
src/lib/utc-mktime.h |    2 

diffs (250 lines):

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 @@ AC_CACHE_CHECK([how large time_t values 
     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;
@@ -959,6 +959,23 @@ AC_CACHE_CHECK([how large time_t values 
   ],[])
 ])
 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 <sys/types.h>
+    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])
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 at 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


More information about the dovecot-cvs mailing list