summaryrefslogtreecommitdiffstats
path: root/debian/patches/source-date-epoch-utc.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/source-date-epoch-utc.patch')
-rw-r--r--debian/patches/source-date-epoch-utc.patch468
1 files changed, 468 insertions, 0 deletions
diff --git a/debian/patches/source-date-epoch-utc.patch b/debian/patches/source-date-epoch-utc.patch
new file mode 100644
index 0000000..b9e5b76
--- /dev/null
+++ b/debian/patches/source-date-epoch-utc.patch
@@ -0,0 +1,468 @@
+From 56d2f35b18a8e6502c6aa842c07b3d27fe9f6f7f Mon Sep 17 00:00:00 2001
+From: Colin Watson <cjwatson@debian.org>
+Date: Sun, 9 Jul 2023 13:23:21 +0100
+Subject: Display time from SOURCE_DATE_EPOCH in UTC.
+
+The semantics imposed in 1.23.0 are unsuitable for use with
+reproducible-builds harnesses, since those specifically want to vary the
+TZ environment variable to shake out other problems in build systems.
+However, my patch that Debian has been carrying for a while is
+unsuitable for general use, since most people expect the time displayed
+in output to use local time.
+
+A viable compromise seems to be to force UTC _only_ when
+SOURCE_DATE_EPOCH is set. That will keep reproducible-builds harnesses
+working with no extra effort, while also preserving the expected
+behaviour for typical users of groff that don't go out of their way to
+set that environment variable.
+
+As a bonus, this corrects the behaviour of gropdf when the local offset
+from UTC is not a whole number of hours.
+
+* src/include/curtime.h (current_time): Return a `struct tm *`.
+ Document behaviour.
+* src/libs/libgroff/curtime.cpp (current_time): If SOURCE_DATE_EPOCH is
+ set, return the overridden time after passing it through `gmtime`.
+ Otherwise, pass the current time through `localtime`.
+
+* src/devices/grohtml/post-html.cpp (html_printer::do_file_components,
+ html_printer::~html_printer):
+* src/devices/grops/ps.cpp (ps_printer::~ps_printer):
+* src/roff/troff/input.cpp (init_registers): Adjust to new
+ `current_time` signature.
+
+* src/devices/gropdf/gropdf.pl: If SOURCE_DATE_EPOCH is set, return the
+ overridden time after passing it through `gmtime`. Otherwise, pass
+ the current time through `localtime`.
+ (PDFDate): Fix output in the case where the local offset from UTC is
+ not a whole number of hours. (Previously, the minutes offset field
+ was always set to zero.)
+
+* doc/groff.texi (Environment):
+* src/devices/grohtml/grohtml.1.man (Environment):
+* src/devices/gropdf/gropdf.1.man (Environment):
+* src/devices/grops/grops.1.man (Environment):
+* src/roff/groff/groff.1.man (Environment):
+* src/roff/troff/troff.1.man (Environment): Update.
+
+Origin: upstream, https://git.savannah.gnu.org/cgit/groff.git/commit/?id=d7bbfb04ea25a82a8597cdef6ebb391cb78ab47c
+Last-Update: 2023-07-11
+
+Patch-Name: source-date-epoch-utc.patch
+---
+ doc/groff.texi | 13 +++++++------
+ src/devices/grohtml/grohtml.1.man | 12 +++++++-----
+ src/devices/grohtml/post-html.cpp | 16 ++++------------
+ src/devices/gropdf/gropdf.1.man | 10 +++++-----
+ src/devices/gropdf/gropdf.pl | 16 ++++++++++++++--
+ src/devices/grops/grops.1.man | 12 +++++++-----
+ src/devices/grops/ps.cpp | 9 ++-------
+ src/include/curtime.h | 19 +++++++++++--------
+ src/libs/libgroff/curtime.cpp | 23 +++++++++++++----------
+ src/roff/groff/groff.1.man | 12 +++++++-----
+ src/roff/troff/input.cpp | 24 +++++++++---------------
+ src/roff/troff/troff.1.man | 12 +++++++-----
+ 12 files changed, 93 insertions(+), 85 deletions(-)
+
+diff --git a/doc/groff.texi b/doc/groff.texi
+index 2a6635e9d..bcea4f3e7 100644
+--- a/doc/groff.texi
++++ b/doc/groff.texi
+@@ -1389,15 +1389,16 @@ overrides @env{GROFF_TYPESETTER}.
+ @tindex SOURCE_DATE_EPOCH@r{, environment variable}
+ A timestamp (expressed as seconds since the Unix epoch) to use as the
+ output creation timestamp in place of the current time. The time is
+-converted to human-readable form using @cite{localtime@r{(3)}} when the
+-formatter starts up and stored in registers usable by documents and
+-macro packages (@pxref{Built-in Registers}).
++converted to human-readable form using @cite{gmtime@r{(3)}} and
++@cite{asctime@r{(3)}} when the formatter starts up and stored in
++registers usable by documents and macro packages (@pxref{Built-in
++Registers}).
+
+ @item TZ
+ @tindex TZ@r{, environment variable}
+-The time zone to use when converting the current time (or value of
+-@env{SOURCE_DATE_EPOCH}) to human-readable form; see
+-@cite{tzset@r{(3)}}.
++The time zone to use when converting the current time to human-readable
++form; see @cite{tzset@r{(3)}}. If @env{SOURCE_DATE_EPOCH} is used, it
++is always converted to human-readable form using UTC.
+ @end table
+
+ MS-DOS and MS-Windows ports of @code{groff} use semicolons, rather than
+diff --git a/src/devices/grohtml/grohtml.1.man b/src/devices/grohtml/grohtml.1.man
+index 2243b474c..8a55c93dd 100644
+--- a/src/devices/grohtml/grohtml.1.man
++++ b/src/devices/grohtml/grohtml.1.man
+@@ -616,18 +616,20 @@ A timestamp
+ to use as the output creation timestamp in place of the current time.
+ .
+ The time is converted to human-readable form using
+-.MR ctime 3
++.MR gmtime 3
++and
++.MR asctime 3 ,
+ and recorded in an HTML comment.
+ .
+ .
+ .TP
+ .I TZ
+-The time zone to use when converting the current time
+-(or value of
+-.IR SOURCE_DATE_EPOCH )
+-to human-readable form;
++The time zone to use when converting the current time to human-readable form;
+ see
+ .MR tzset 3 .
++If
++.I SOURCE_DATE_EPOCH
++is used, it is always converted to human-readable form using UTC.
+ .
+ .
+ .\" ====================================================================
+diff --git a/src/devices/grohtml/post-html.cpp b/src/devices/grohtml/post-html.cpp
+index 4e02b5cfa..b42720da1 100644
+--- a/src/devices/grohtml/post-html.cpp
++++ b/src/devices/grohtml/post-html.cpp
+@@ -5081,11 +5081,7 @@ void html_printer::do_file_components (void)
+ fclose(file_list.get_file());
+ file_list.move_next();
+ if (file_list.is_new_output_file()) {
+-#ifdef LONG_FOR_TIME_T
+- long t;
+-#else
+- time_t t;
+-#endif
++ struct tm *t;
+
+ if (fragment_no > 1)
+ write_navigation(top, prev, next, current);
+@@ -5115,7 +5111,7 @@ void html_printer::do_file_components (void)
+ if (do_write_date_comment) {
+ t = current_time();
+ html.begin_comment("CreationDate: ")
+- .put_string(ctime(&t), strlen(ctime(&t))-1)
++ .put_string(asctime(t), strlen(asctime(t))-1)
+ .end_comment();
+ }
+
+@@ -5215,11 +5211,7 @@ void html_printer::writeHeadMetaStyle (void)
+
+ html_printer::~html_printer()
+ {
+-#ifdef LONG_FOR_TIME_T
+- long t;
+-#else
+- time_t t;
+-#endif
++ struct tm *t;
+
+ if (current_paragraph)
+ current_paragraph->flush_text();
+@@ -5240,7 +5232,7 @@ html_printer::~html_printer()
+ if (do_write_date_comment) {
+ t = current_time();
+ html.begin_comment("CreationDate: ")
+- .put_string(ctime(&t), strlen(ctime(&t))-1)
++ .put_string(asctime(t), strlen(asctime(t))-1)
+ .end_comment();
+ }
+
+diff --git a/src/devices/gropdf/gropdf.1.man b/src/devices/gropdf/gropdf.1.man
+index d1d39bbe0..20a957e68 100644
+--- a/src/devices/gropdf/gropdf.1.man
++++ b/src/devices/gropdf/gropdf.1.man
+@@ -1673,18 +1673,18 @@ A timestamp
+ to use as the output creation timestamp in place of the current time.
+ .
+ The time is converted to human-readable form using Perl's
+-.I \%localtime()
++.I \%gmtime()
+ function and recorded in a PDF comment.
+ .
+ .
+ .TP
+ .I TZ
+-The time zone to use when converting the current time
+-(or value of
+-.IR SOURCE_DATE_EPOCH )
+-to human-readable form;
++The time zone to use when converting the current time to human-readable form;
+ see
+ .MR tzset 3 .
++If
++.I SOURCE_DATE_EPOCH
++is used, it is always converted to human-readable form using UTC.
+ .
+ .
+ .\" ====================================================================
+diff --git a/src/devices/gropdf/gropdf.pl b/src/devices/gropdf/gropdf.pl
+index c65a1051f..0e1b612a5 100644
+--- a/src/devices/gropdf/gropdf.pl
++++ b/src/devices/gropdf/gropdf.pl
+@@ -23,6 +23,7 @@
+ use strict;
+ use warnings;
+ use Getopt::Long qw(:config bundling);
++use POSIX qw(mktime);
+
+ use constant
+ {
+@@ -343,7 +344,12 @@ for $papersz ( split(" ", lc($possiblesizes).' #duff#') )
+ # If we get here, $papersz was invalid, so try the next one.
+ }
+
+-my (@dt)=localtime($ENV{SOURCE_DATE_EPOCH} || time);
++my @dt;
++if ($ENV{SOURCE_DATE_EPOCH}) {
++ @dt=gmtime($ENV{SOURCE_DATE_EPOCH});
++} else {
++ @dt=localtime;
++}
+ my $dt=PDFDate(\@dt);
+
+ my %info=('Creator' => "(groff version $cfg{GROFF_VERSION})",
+@@ -628,7 +634,13 @@ sub GetObj
+ sub PDFDate
+ {
+ my $dt=shift;
+- return(sprintf("D:%04d%02d%02d%02d%02d%02d%+03d'00'",$dt->[5]+1900,$dt->[4]+1,$dt->[3],$dt->[2],$dt->[1],$dt->[0],( localtime time() + 3600*( 12 - (gmtime)[2] ) )[2] - 12));
++ my $offset;
++ if ($ENV{SOURCE_DATE_EPOCH}) {
++ $offset=0;
++ } else {
++ $offset=mktime((localtime $dt)[0..5]) - mktime((gmtime $dt)[0..5]);
++ }
++ return(sprintf("D:%04d%02d%02d%02d%02d%02d%+03d'%+03d'",$dt->[5]+1900,$dt->[4]+1,$dt->[3],$dt->[2],$dt->[1],$dt->[0],int($offset/3600),int(($offset%3600)/60)));
+ }
+
+ sub ToPoints
+diff --git a/src/devices/grops/grops.1.man b/src/devices/grops/grops.1.man
+index d0ec21d0b..53014ee1b 100644
+--- a/src/devices/grops/grops.1.man
++++ b/src/devices/grops/grops.1.man
+@@ -1696,18 +1696,20 @@ A timestamp
+ to use as the output creation timestamp in place of the current time.
+ .
+ The time is converted to human-readable form using
+-.MR ctime 3
++.MR gmtime 3
++and
++.MR asctime 3 ,
+ and recorded in a PostScript comment.
+ .
+ .
+ .TP
+ .I TZ
+-The time zone to use when converting the current time
+-(or value of
+-.IR SOURCE_DATE_EPOCH )
+-to human-readable form;
++The time zone to use when converting the current time to human-readable form;
+ see
+ .MR tzset 3 .
++If
++.I SOURCE_DATE_EPOCH
++is used, it is always converted to human-readable form using UTC.
+ .
+ .
+ .\" ====================================================================
+diff --git a/src/devices/grops/ps.cpp b/src/devices/grops/ps.cpp
+index 807945f97..59e6e253d 100644
+--- a/src/devices/grops/ps.cpp
++++ b/src/devices/grops/ps.cpp
+@@ -1390,13 +1390,8 @@ ps_printer::~ps_printer()
+ .end_comment();
+ {
+ fputs("%%CreationDate: ", out.get_file());
+-#ifdef LONG_FOR_TIME_T
+- long
+-#else
+- time_t
+-#endif
+- t = current_time();
+- fputs(ctime(&t), out.get_file());
++ struct tm *t = current_time();
++ fputs(asctime(t), out.get_file());
+ }
+ for (font_pointer_list *f = font_list; f; f = f->next) {
+ ps_font *psf = (ps_font *)(f->p);
+diff --git a/src/include/curtime.h b/src/include/curtime.h
+index 5d3a24a7b..ebd2efb80 100644
+--- a/src/include/curtime.h
++++ b/src/include/curtime.h
+@@ -15,13 +15,16 @@ for more details.
+ The GNU General Public License version 2 (GPL2) is available in the
+ internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */
+
+-#ifndef LONG_FOR_TIME_T
+ #include <time.h>
+-#endif
+
+-#ifdef LONG_FOR_TIME_T
+-long
+-#else
+-time_t
+-#endif
+-current_time();
++// Get the current time in broken-down time representation. If the
++// SOURCE_DATE_EPOCH environment variable is set, then it is used instead of
++// the real time from the system clock; in this case, the user is clearly
++// trying to arrange for some kind of reproducible build, so express the
++// time in UTC. Otherwise, use the real time from the system clock, and
++// express it relative to the user's time zone.
++//
++// In either case, as with gmtime() and localtime(), the return value points
++// to a statically-allocated struct which might be overwritten by later
++// calls.
++struct tm *current_time();
+diff --git a/src/libs/libgroff/curtime.cpp b/src/libs/libgroff/curtime.cpp
+index 34dbc5ca9..277755cab 100644
+--- a/src/libs/libgroff/curtime.cpp
++++ b/src/libs/libgroff/curtime.cpp
+@@ -15,9 +15,7 @@ for more details.
+ The GNU General Public License version 2 (GPL2) is available in the
+ internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */
+
+-#ifdef HAVE_CONFIG_H
+-#include <config.h>
+-#endif
++#include "lib.h"
+
+ #include <errno.h>
+ #include <limits.h>
+@@ -25,16 +23,18 @@ internet at <http://www.gnu.org/licenses/gpl-2.0.txt>. */
+ #include <string.h>
+ #include <time.h>
+
++#include "curtime.h"
+ #include "errarg.h"
+ #include "error.h"
+
++struct tm *current_time()
++{
+ #ifdef LONG_FOR_TIME_T
+-long
++ long
+ #else
+-time_t
++ time_t
+ #endif
+-current_time()
+-{
++ t;
+ char *source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+
+ if (source_date_epoch) {
+@@ -49,7 +49,10 @@ current_time()
+ fatal("$SOURCE_DATE_EPOCH: no digits found: '%1'", endptr);
+ if (*endptr != '\0')
+ fatal("$SOURCE_DATE_EPOCH: trailing garbage: '%1'", endptr);
+- return epoch;
+- } else
+- return time(0);
++ t = epoch;
++ return gmtime(&t);
++ } else {
++ t = time(0);
++ return localtime(&t);
++ }
+ }
+diff --git a/src/roff/groff/groff.1.man b/src/roff/groff/groff.1.man
+index 75687440e..348036cdf 100644
+--- a/src/roff/groff/groff.1.man
++++ b/src/roff/groff/groff.1.man
+@@ -1879,19 +1879,21 @@ A time stamp
+ to use as the output creation time stamp in place of the current time.
+ .
+ The time is converted to human-readable form using
+-.MR localtime 3
++.MR gmtime 3
++and
++.MR asctime 3
+ when the formatter starts up and stored in registers usable by documents
+ and macro packages.
+ .
+ .
+ .TP
+ .I TZ
+-The time zone to use when converting the current time
+-(or value of
+-.IR SOURCE_DATE_EPOCH )
+-to human-readable form;
++The time zone to use when converting the current time to human-readable form;
+ see
+ .MR tzset 3 .
++If
++.I SOURCE_DATE_EPOCH
++is used, it is always converted to human-readable form using UTC.
+ .
+ .
+ .\" ====================================================================
+diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
+index 292ee7389..f03338335 100644
+--- a/src/roff/troff/input.cpp
++++ b/src/roff/troff/input.cpp
+@@ -8297,21 +8297,15 @@ void warn_request()
+
+ static void init_registers()
+ {
+-#ifdef LONG_FOR_TIME_T
+- long
+-#else /* not LONG_FOR_TIME_T */
+- time_t
+-#endif /* not LONG_FOR_TIME_T */
+- t = current_time();
+- struct tm *tt = localtime(&t);
+- set_number_reg("seconds", int(tt->tm_sec));
+- set_number_reg("minutes", int(tt->tm_min));
+- set_number_reg("hours", int(tt->tm_hour));
+- set_number_reg("dw", int(tt->tm_wday + 1));
+- set_number_reg("dy", int(tt->tm_mday));
+- set_number_reg("mo", int(tt->tm_mon + 1));
+- set_number_reg("year", int(1900 + tt->tm_year));
+- set_number_reg("yr", int(tt->tm_year));
++ struct tm *t = current_time();
++ set_number_reg("seconds", int(t->tm_sec));
++ set_number_reg("minutes", int(t->tm_min));
++ set_number_reg("hours", int(t->tm_hour));
++ set_number_reg("dw", int(t->tm_wday + 1));
++ set_number_reg("dy", int(t->tm_mday));
++ set_number_reg("mo", int(t->tm_mon + 1));
++ set_number_reg("year", int(1900 + t->tm_year));
++ set_number_reg("yr", int(t->tm_year));
+ set_number_reg("$$", getpid());
+ register_dictionary.define(".A",
+ new readonly_text_register(ascii_output_flag
+diff --git a/src/roff/troff/troff.1.man b/src/roff/troff/troff.1.man
+index 01b46616c..4fbb962b1 100644
+--- a/src/roff/troff/troff.1.man
++++ b/src/roff/troff/troff.1.man
+@@ -868,19 +868,21 @@ A timestamp
+ to use as the output creation timestamp in place of the current time.
+ .
+ The time is converted to human-readable form using
+-.MR localtime 3
++.MR gmtime 3
++and
++.MR asctime 3
+ when the formatter starts up and stored in registers usable by documents
+ and macro packages.
+ .
+ .
+ .TP
+ .I TZ
+-The timezone to use when converting the current time
+-(or value of
+-.IR SOURCE_DATE_EPOCH )
+-to human-readable form;
++The time zone to use when converting the current time to human-readable form;
+ see
+ .MR tzset 3 .
++If
++.I SOURCE_DATE_EPOCH
++is used, it is always converted to human-readable form using UTC.
+ .
+ .
+ .\" ====================================================================