changeset 13152:4bb701a8736f

[gaim-migrate @ 15515] gaim_utf8_strftime() will now provide %z itself if your C library doesn't have it. I'm going to use this shortly. committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Tue, 07 Feb 2006 07:25:45 +0000
parents 1646cd4f00ad
children caee920323e2
files config.h.mingw configure.ac src/util.c src/util.h
diffstat 4 files changed, 149 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/config.h.mingw	Tue Feb 07 07:17:09 2006 +0000
+++ b/config.h.mingw	Tue Feb 07 07:25:45 2006 +0000
@@ -373,6 +373,9 @@
 /* Define to 1 if you have the `strftime' function. */
 #define HAVE_STRFTIME 1
 
+/* Define to 1 if you have a strftime() that supports the %z format string. */
+/* #undef HAVE_STRFTIME_Z_FORMAT */
+
 /* Define to 1 if you have the <strings.h> header file. */
 #define HAVE_STRINGS_H 1
 
--- a/configure.ac	Tue Feb 07 07:17:09 2006 +0000
+++ b/configure.ac	Tue Feb 07 07:25:45 2006 +0000
@@ -108,6 +108,41 @@
 dnl FreeBSD doesn't have libdl, dlopen is provided by libc
 AC_CHECK_FUNC(dlopen, LIBDL="", [AC_CHECK_LIB(dl, dlopen, LIBDL="-ldl")])
 
+AC_MSG_CHECKING(for the %z format string in strftime())
+AC_TRY_RUN([
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <time.h>
+#include <stdio.h>
+
+int main()
+{
+	char buf[6];
+	time_t t = time(NULL);
+	
+	if (strftime(buf, sizeof(buf), "%z", localtime(&t)) != 5)
+		return 1;
+	
+	fprintf(stderr, "strftime(\"%%z\") yields: \"%s\"\n", buf);
+	
+	return !((buf[0] == '-' || buf[0] == '+') &&
+	         (buf[1] >= '0' && buf[1] <= '9') &&
+	         (buf[2] >= '0' && buf[2] <= '9') &&
+	         (buf[3] >= '0' && buf[3] <= '9') &&
+	         (buf[4] >= '0' && buf[4] <= '9')
+	        );
+}
+],
+[
+	AC_MSG_RESULT(yes)
+	AC_DEFINE([HAVE_STRFTIME_Z_FORMAT], [1],
+                                      [Define to 1 if you have a strftime() that supports the %z format string.])
+],
+[
+	AC_MSG_RESULT(no)
+]
+)
 
 
 dnl #######################################################################
--- a/src/util.c	Tue Feb 07 07:17:09 2006 +0000
+++ b/src/util.c	Tue Feb 07 07:25:45 2006 +0000
@@ -484,6 +484,109 @@
 /**************************************************************************
  * Date/Time Functions
  **************************************************************************/
+
+#ifndef HAVE_STRFTIME_Z_FORMAT
+static const char *get_tmoff(const struct tm *tm)
+{
+	static char buf[6];
+	long off;
+	gint8 min;
+	gint8 hrs;
+	struct tm new_tm = *tm;
+
+	mktime(&new_tm);
+
+	if (new_tm.tm_isdst < 0)
+		g_return_val_if_reached("");
+
+#ifdef _WIN32
+	TIME_ZONE_INFORMATION tzi;
+	DWORD ret;
+	if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID)
+	{
+			off = tzi.Bias * 60;
+			if (ret == TIME_ZONE_ID_DAYLIGHT)
+					off -= tzi.DaylightBias * 60;
+	}
+	else
+			return "";
+#else
+# ifdef HAVE_TM_GMTOFF
+	off = new_tm.tm_gmtoff;
+# else
+#  ifdef HAVE_TIMEZONE
+	tzset();
+	off = -timezone;
+#  endif /* HAVE_TIMEZONE */
+# endif /* !HAVE_TM_GMTOFF */
+#endif /* _WIN32 */
+
+	min = (off / 60) % 60;
+	hrs = ((off / 60) - min) / 60;
+
+	if (g_snprintf(buf, sizeof(buf), "%+03d%02d", hrs, ABS(min)) > 5)
+		g_return_val_if_reached("");
+
+	return buf;
+}
+
+static size_t gaim_internal_strftime(char *s, size_t max, const char *format, const struct tm *tm)
+{
+	const char *start;
+	const char *c;
+	char *fmt = NULL;
+
+	/* Yes, this is checked in gaim_utf8_strftime(),
+	 * but better safe than sorry. -- rlaager */
+	g_return_val_if_fail(format != NULL, 0);
+
+	/* This is fairly efficient, and it only gets
+	 * executed if the underlying system doesn't
+	 * support the %z format string for strftime(),
+	 * so I think it's good enough. -- rlaager */
+	for (c = start = format; *c ; c++)
+	{
+		if (*c != '%')
+			continue;
+
+		c++;
+
+		if (*c == 'z')
+		{
+			char *tmp = g_strdup_printf("%s%.*s%s",
+			                            fmt ? fmt : "",
+			                            c - start - 1,
+			                            start,
+			                            get_tmoff(tm));
+			g_free(fmt);
+			fmt = tmp;
+			start = c + 1;
+		}
+	}
+
+	if (fmt != NULL)
+	{
+		size_t ret;
+
+		if (*start)
+		{
+			char *tmp = g_strconcat(fmt, start, NULL);
+			g_free(fmt);
+			fmt = tmp;
+		}
+
+		ret = strftime(s, max, fmt, tm);
+		g_free(fmt);
+
+		return ret;
+	}
+
+	return strftime(s, max, format, tm);
+}
+#else /* !HAVE_STRFTIME_Z_FORMAT */
+#define gaim_internal_strftime strftime
+#endif
+
 const char *
 gaim_utf8_strftime(const char *format, const struct tm *tm)
 {
@@ -502,7 +605,7 @@
 	 * which case, the contents of the buffer are
 	 * undefined) or the empty string (in which
 	 * case, no harm is done here). */
-	if (strftime(buf, sizeof(buf), format, tm) == 0)
+	if (gaim_internal_strftime(buf, sizeof(buf), format, tm) == 0)
 	{
 		buf[0] = '\0';
 		return buf;
--- a/src/util.h	Tue Feb 07 07:17:09 2006 +0000
+++ b/src/util.h	Tue Feb 07 07:25:45 2006 +0000
@@ -216,6 +216,13 @@
  * This is essentially strftime(), but it has a static buffer
  * and handles the UTF-8 conversion for the caller.
  *
+ * This function also provides the GNU %z formatter if the underlying C
+ * library doesn't.  However, the format string parser is very naive, which
+ * means that conversions specifiers to %z cannot be guaranteed.  The GNU
+ * strftime(3) man page describes %z as: 'The time-zone as hour offset from
+ * GMT.  Required to emit RFC822-conformant dates
+ * (using "%a, %d %b %Y %H:%M:%S %z"). (GNU)'
+ *
  * @param format The format string
  * @param tm     The time to format, or @c NULL to use the current local time
  *