Re: [PATCH 10/10] timegm: add portable implementation (Solaris support)

Subject: Re: [PATCH 10/10] timegm: add portable implementation (Solaris support)

Date: Sun, 4 Nov 2012 12:21:01 +0200

To: Blake Jones

Cc: notmuch@notmuchmail.org

From: Jani Nikula


On Nov 4, 2012 11:30 AM, "Blake Jones" <blakej@foo.net> wrote:
>
> 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.

I'd prefer to use timegm() where available, and the suggested alternative
[1] elsewhere. I'll look into the compat build issues when I have a moment.

Jani.

[1] http://www.kernel.org/doc/man-pages/online/pages/man3/timegm.3.html

> ---
>  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
>
> _______________________________________________
> notmuch mailing list
> notmuch@notmuchmail.org
> http://notmuchmail.org/mailman/listinfo/notmuch

Thread: