[PATCH 10/10] timegm: add portable implementation (Solaris support)
Blake Jones
blakej at foo.net
Sat Nov 3 20:16:02 PDT 2012
The timegm(3) function is a non-standard extension to libc which is
available in GNU libc and on some BSDs. Although SunOS had this
function in its libc, Solaris (unfortunately) removed it. This patch
implements a very simple version of timegm() which is good enough for
parse-time-string.c.
Although notmuch's idiom for portability is to test for native
availability and put alternate versions in compat/, that approach led to
a compilation problem in this case. libnotmuch.a includes a call to
parse_time_string() from parse-time-vrp.o, and parse_time_string() in
libparse-time-string.a needs to call timegm(). An attempt to create
compat/timegm.c caused the link to fail, because libparse-time-string.a
acquired a dependency on the new timegm.o in libnotmuch.a, and the
linker only does a single pass on each ".a" looking for dependencies.
This seems to be the case both for the GNU linker and the Solaris
linker. A different possible workaround would have been to include
libnotmuch.a multiple times on the link line, but that seemed like a
brittle way to track this dependency.
---
parse-time-string/parse-time-string.c | 37 ++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/parse-time-string/parse-time-string.c b/parse-time-string/parse-time-string.c
index 584067d..28901af 100644
--- a/parse-time-string/parse-time-string.c
+++ b/parse-time-string/parse-time-string.c
@@ -1315,6 +1315,41 @@ fixup_ampm (struct state *state)
return 0;
}
+static int
+leapyear (int year)
+{
+ return ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0));
+}
+
+/*
+ * This is a simple implementation of timegm() which does what is needed
+ * by create_output() -- just turns the "struct tm" into a GMT time_t.
+ * It does not normalize any of the fields of the "struct tm", nor does
+ * it set tm_wday or tm_yday.
+ */
+static time_t
+local_timegm (struct tm *tm)
+{
+ int monthlen[2][12] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ };
+ int year, month, days;
+
+ days = 365 * (tm->tm_year - 70);
+ for (year = 70; year < tm->tm_year; year++) {
+ if (leapyear(1900 + year)) {
+ days++;
+ }
+ }
+ for (month = 0; month < tm->tm_mon; month++) {
+ days += monthlen[leapyear(1900 + year)][month];
+ }
+ days += tm->tm_mday - 1;
+
+ return ((((days * 24) + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec);
+}
+
/* Combine absolute and relative fields, and round. */
static int
create_output (struct state *state, time_t *t_out, const time_t *ref,
@@ -1465,7 +1500,7 @@ create_output (struct state *state, time_t *t_out, const time_t *ref,
if (is_field_set (state, TM_TZ)) {
/* tm is in specified TZ, convert to UTC for timegm(3). */
tm.tm_min -= get_field (state, TM_TZ);
- t = timegm (&tm);
+ t = local_timegm (&tm);
} else {
/* tm is in local time. */
t = mktime (&tm);
--
1.7.9.2
More information about the notmuch
mailing list