about summary refs log tree commit diff
path: root/buildtools
diff options
context:
space:
mode:
Diffstat (limited to 'buildtools')
-rw-r--r--buildtools/Makefile12
-rwxr-xr-xbuildtools/configure.pl115
-rw-r--r--buildtools/debian/README17
-rwxr-xr-xbuildtools/debian/mkdeb32
-rw-r--r--buildtools/genfontc.c199
-rwxr-xr-xbuildtools/installnetpbm.pl533
-rw-r--r--buildtools/libopt.c10
-rwxr-xr-xbuildtools/makeman67
-rw-r--r--buildtools/manpage.mk607
-rwxr-xr-xbuildtools/stamp-date26
10 files changed, 880 insertions, 738 deletions
diff --git a/buildtools/Makefile b/buildtools/Makefile
index 8671c066..0490865b 100644
--- a/buildtools/Makefile
+++ b/buildtools/Makefile
@@ -33,10 +33,20 @@ libopt.o: libopt.c
 typegen.o endiangen.o:%.o:%.c
 	$(CC_FOR_BUILD) -c -o $@ $(CFLAGS_FOR_BUILD) $<
 
+# genfontc is strange because it isn't really a build tool; it's a development
+# tool.  And it uses Netpbm.  So we don't even build it by default and the
+# developer who builds it explicitly may have to be careful.
+genfontc.o:%.o:%.c importinc
+	$(CC_FOR_BUILD) -c -o $@ $(CFLAGS_FOR_BUILD) \
+	  $(NETPBM_INCLUDES) \
+	  $<
+genfontc:%:%.o $(NETPBMLIB)
+	$(LD_FOR_BUILD) -o $@ $(LDFLAGS_FOR_BUILD)  $< $(NETPBMLIB)
+
 $(BUILDPROGS):%:%.o
 	$(LD_FOR_BUILD) -o $@ $(LDFLAGS_FOR_BUILD) $<
 
 distclean clean: cleanlocal
 .PHONY: cleanlocal
 cleanlocal:
-	rm -f $(BUILDPROGS)
+	rm -f $(BUILDPROGS) genfontc
diff --git a/buildtools/configure.pl b/buildtools/configure.pl
index 9cafd019..4e6ff21a 100755
--- a/buildtools/configure.pl
+++ b/buildtools/configure.pl
@@ -442,6 +442,18 @@ sub askAboutDjgpp() {
 
 
 
+sub askAboutMingw() {
+
+    print("Are you building for the MinGW environment?\n");
+    print("\n");
+    
+    my $retval = promptYesNo("n");
+
+    return $retval;
+}
+
+
+
 sub computePlatformDefault($) {
 
     my ($defaultP) = @_;
@@ -556,6 +568,29 @@ sub getPlatform() {
 
 
 
+sub warnMingwXopenSource($) {
+    my ($subplatform) = @_;
+
+    if ($subplatform ne 'cygwin' && $subplatform ne 'djgpp') {
+        my $mingw = askAboutMingw();
+
+        if ($mingw) {
+            print << 'EOF';
+
+MinGW does not implement enough of the standard on which Netpbm relies to
+build out-of-the-box, but there is a trivial way to add the needed capability
+to MinGW.  See file doc/INSTALL for details.
+
+Press ENTER to continue.
+
+EOF
+            <STDIN>;
+        }
+    }
+}
+
+
+
 sub getGccChoiceFromUser($) {
     my ($platform) = @_;
 
@@ -1164,10 +1199,20 @@ sub getPngLibrary($@) {
 
     my ($pnglib, $pnghdr_dir);
 
-    if (commandExists('libpng-config')) {
-        # We don't need to ask where Libpng is; there's a 'libpng-config'
-        # That tells exactly how to access it, and the make files will use
-        # that.
+    if (system('pkg-config libpng --exists') == 0) {
+        # We don't need to ask where Libpng is; the Pkg-config database knows
+        # and the make files will use that.
+        #
+        # To limit the confusion when someone tries to use our result in
+        # spite of the fact that 'libpng-config' exists, we assign suggestive
+        # dummy values (just for use in human debugging).
+        $pnglib     = 'USE_PKG_CONFIG.a';
+        $pnghdr_dir = 'USE_PKG_CONFIG.a';
+    } elsif (commandExists('libpng-config')) {
+        # As with Pkg-config above, we can find out how to access the
+        # library by invoking a 'libpng-config' command.
+        $pnglib     = 'USE_LIBPNG-CONFIG.a';
+        $pnghdr_dir = 'USE_LIBPNG-CONFIG.a';
     } else {
         {
             my $default = "libpng" . libSuffix($platform);
@@ -1252,6 +1297,12 @@ sub getX11Library($@) {
     if (system('pkg-config x11 --exists') == 0) {
         # We don't need to ask where X libraries are; pkg-config knows and the
         # make files will use that.
+        #
+        # To limit the confusion when someone tries to use our result in
+        # spite of the fact that 'libpng-config' exists, we assign suggestive
+        # dummy values (just for use in human debugging).
+        $x11lib     = 'USE_PKGCONFIG.a';
+        $x11hdr_dir = 'USE_PKGCONFIG.a';
     } else {
         {
             my $default;
@@ -1456,14 +1507,52 @@ sub gnuOptimizeOpt($) {
 
 
 
+sub wnostrictoverflowWorks($) {
+    my ($gccCommandName) = @_;
+
+    my ($cFile, $cFileName) = tempFile(".c");
+
+    print $cFile "int x;";
+    
+    my $compileCommand =
+        "$gccCommandName -c -o /dev/null -Wno-strict-overflow $cFileName";
+    print("Doing test compile to see if -Wno-strict-overflow works: "
+          . "$compileCommand\n");
+    my $rc = system($compileCommand);
+    
+    unlink($cFileName);
+    close($cFile);
+
+    return ($rc == 0);
+}
+
+
+
 sub gnuCflags($) {
     my ($gccCommandName) = @_;
 
-    return("CFLAGS = " . gnuOptimizeOpt($gccCommandName) . " -ffast-math " .
-           " -pedantic -fno-common " . 
-           "-Wall -Wno-uninitialized -Wmissing-declarations -Wimplicit " .
-           "-Wwrite-strings -Wmissing-prototypes -Wundef " .
-           "-Wno-unknown-pragmas\n");
+    my $flags;
+
+    $flags = gnuOptimizeOpt($gccCommandName) . " -ffast-math " .
+        " -pedantic -fno-common " . 
+        "-Wall -Wno-uninitialized -Wmissing-declarations -Wimplicit " .
+        "-Wwrite-strings -Wmissing-prototypes -Wundef " .
+        "-Wno-unknown-pragmas ";
+
+    if (wnostrictoverflowWorks($gccCommandName)) {
+        # The compiler generates some optimizations based on the assumption
+        # that you wouldn't code something that can arithmetically overflow,
+        # so adding a positive value to something can only make it bigger.
+        # E.g. if (x + y > x), where y is unsigned, is a no-op.  The compiler
+        # optionally warns when it makes that assumption.  Sometimes, the
+        # compiler is able to do that optimization because of inlining, so the
+        # code per se is not ridiculous, it just becomes superfluous in
+        # context.  That means you can't code around the warning.  Ergo, we
+        # must disable the warning.
+
+        $flags .= '-Wno-strict-overflow';
+    }
+    return("CFLAGS = $flags\n");
 }
 
 
@@ -2030,6 +2119,10 @@ if ($platform eq "NONE") {
     exit;
 }
 
+if ($platform eq 'WINDOWS') {
+    warnMingwXopenSource($subplatform);
+}
+
 getCompiler($platform, $subplatform, \my $compiler);
 
 getLinker($platform, $compiler, \my $baseLinker, \my $linkViaCompiler);
@@ -2142,8 +2235,8 @@ my ($linuxsvgalib, $linuxsvgahdr_dir) = getLinuxsvgaLibrary($platform);
 
 print("\n");
 
-# We should add the JBIG and URT libraries here too.  They're a little
-# more complicated because there are versions shipped with Netpbm.
+# We should add the URT, JBIG, and Jasper libraries here too.  They're a
+# little more complicated because there are versions shipped with Netpbm.
 
 
 #******************************************************************************
diff --git a/buildtools/debian/README b/buildtools/debian/README
index 02fae4b5..7cefb249 100644
--- a/buildtools/debian/README
+++ b/buildtools/debian/README
@@ -37,11 +37,11 @@ To install Netpbm as a Debian package:
 PREREQUSISITES
 --------------
 
-The following information was taken from the Wheezy version (Version 7) of
-Debian, in January 2014.
+The following information was taken from the Jessie version (Version 8) of
+Debian, in March 2017.
 
 You don't actually need the current version of any of these.  For example,
-while we list package libjpeg8-dev, the package libjpeg62-dev works fine.
+while we list package libjpeg62-dev, the package libjpeg8-dev works fine.
 
 
 Building
@@ -54,12 +54,11 @@ indicate you don't have them, and the build will simply omit some parts.
 For example, if you don't install libx11-dev, the Netpbm build process
 will not build the 'pamx' program.
 
-  libjpeg8-dev
-  libpng12-0-dev
-  libsvga1-dev
+  libjpeg-dev
+  libpng-dev
   libtiff5-dev
   libx11-dev
-  libxml2a-dev
+  libxml2-dev
   zlib1g-dev
 
 
@@ -80,9 +79,9 @@ The following Debian packages are the known prerequisites for running Netpbm
 (and the package created by 'mkdeb' knows this).
 
     libc6
-    libjpeg8
+    libjpeg62 or libjpeg8
     libpng12-0
-    libsvga1
+    libsvga1 (available only on older systems)
     libtiff5
     libx11-6
     zlib1g
diff --git a/buildtools/debian/mkdeb b/buildtools/debian/mkdeb
index 8ca0f738..51d77cdb 100755
--- a/buildtools/debian/mkdeb
+++ b/buildtools/debian/mkdeb
@@ -3,7 +3,7 @@
 #                                mkdeb
 ###############################################################################
 #
-#  This generates a Debian package file (.deb) to install Sourceforge
+#  This generates a Debian packge file (.deb) to install Sourceforge
 #  Netpbm on a Debian system.
 #
 #  This is especially useful because Debian does not have a good Debian
@@ -112,30 +112,12 @@ sub netpbmVersion($) {
 
 sub control($$) {
     my ($release, $architecture) = @_;
-#-----------------------------------------------------------------------------
-#  The contents for the package control file, as a hash reference.  In the
-#  referenced hash, there is one key for each line of the control file.  The
-#  key and value in the hash are the key and value for the line of the control
-#  file.
-#-----------------------------------------------------------------------------
 
-    # Because developers of some of the dependent libraries frequently switch
-    # to distributing versions not backward compatible with what they
-    # previously distributed, and Debian always packages the currently
-    # distributed version, it is virtually impossible to produce a Netpbm
-    # package that works in multiple Debian versions.  This program is coded
-    # to create a package that works on the Debian system the Netpbm
-    # maintainer currently uses to build the Debian packages he distributes.
-    # If you are building for any other version of Debian, you'll have to
-    # modify this code.
-
-    # Note that the backward incompatibility is usually only at a binary
-    # level, not source level.  And sometimes the only incompatibility for
-    # Netpbm purposes is that the soname has changed so that Linux will refuse
-    # to run a Netpbm program built for Debian N on Debian N-1.
-
-    # The following is for Debian 9.
-    
+# The Debian packaging system doesn't provide a way to express Netpbm's actual
+# prerequisites.  For example, Netpbm needs Version 6.2 or better of Libjpeg,
+# but there is no way to state that here.  Instead, we state Libjpeg 6.2
+# exactly.  This makes the Netpbm package less useful.
+
     my %control;
 
     my $debianNativeNetpbm = 
@@ -156,7 +138,7 @@ sub control($$) {
     $control{'Depends'} =
         'libc6, ' .
         'libjpeg62, ' .
-        'libpng16-16, ' .
+        'libpng12-0 | libpng16-16, ' .
         'libtiff5, ' .
         'libx11-6, ' .
         'libxml2, ' .
diff --git a/buildtools/genfontc.c b/buildtools/genfontc.c
new file mode 100644
index 00000000..ce6b8c9c
--- /dev/null
+++ b/buildtools/genfontc.c
@@ -0,0 +1,199 @@
+#include "pm_c_util.h"
+#include "mallocvar.h"
+#include "shhopt.h"
+#include "pm.h"
+#include "pbmfont.h"
+
+
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char * font;    
+    const char * builtin; 
+    const char * header; 
+    const char * varname; 
+    unsigned int verbose;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to OptParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int fontSpec, builtinSpec, headerSpec, varnameSpec;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "font",      OPT_STRING, &cmdlineP->font, &fontSpec,        0);
+    OPTENT3(0, "builtin",   OPT_STRING, &cmdlineP->builtin, &builtinSpec,  0);
+    OPTENT3(0, "header",    OPT_STRING, &cmdlineP->header, &headerSpec,    0);
+    OPTENT3(0, "varname",   OPT_STRING, &cmdlineP->varname, &varnameSpec,  0);
+    OPTENT3(0, "verbose",   OPT_FLAG,   NULL, &cmdlineP->verbose,          0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!fontSpec)
+        cmdlineP->font = NULL;
+
+    if (!builtinSpec)
+        cmdlineP->builtin = NULL;
+
+    if (!headerSpec)
+        cmdlineP->header = NULL;
+
+    if (!varnameSpec)
+        cmdlineP->varname = NULL;
+}
+
+
+
+static void
+reportFont(struct font * const fontP) {
+
+    unsigned int n;
+    unsigned int c;
+
+    pm_message("FONT:");
+    pm_message("  character dimensions: %uw x %uh",
+               fontP->maxwidth, fontP->maxheight);
+    pm_message("  Additional vert white space: %d pixels", fontP->y);
+
+    for (c = 0, n = 0; c < ARRAY_SIZE(fontP->glyph); ++c) {
+        if (fontP->glyph[c])
+            ++n;
+    }
+
+    pm_message("  # characters: %u", n);
+}
+
+
+
+static void
+computeFont(const char *   const fontName,
+            const char *   const builtinName,
+            struct font ** const fontPP) {
+
+    struct font * fontP;
+
+    if (fontName)
+        fontP = pbm_loadfont(fontName);
+    else {
+        if (builtinName)
+            fontP = pbm_defaultfont(builtinName);
+        else
+            fontP = pbm_defaultfont("bdf");
+    }
+
+    *fontPP = fontP;
+}
+
+
+
+
+static void
+dumpfont(struct font * const fontP,
+         const char *  const header,
+         const char *  const varname,
+         FILE *        const ofP) {
+/*----------------------------------------------------------------------------
+  Dump out font as C source code.
+-----------------------------------------------------------------------------*/
+    unsigned int i;
+    unsigned int ng;
+
+    for (i = 0, ng = 0; i < 256; ++i) {
+        if (fontP->glyph[i])
+            ++ng;
+    }
+
+    if (header != NULL)
+        printf("#include \"%s\"\n\n", header);    
+
+    printf("static struct glyph _g[%d] = {\n", ng);
+
+    for (i = 0; i < 256; ++i) {
+        struct glyph * const glyphP = fontP->glyph[i];
+
+        if (glyphP) {
+            unsigned int j;
+
+            printf(" { %d, %d, %d, %d, %d, \"",
+                   glyphP->width, glyphP->height,
+                   glyphP->x, glyphP->y, glyphP->xadd);
+            
+            for (j = 0; j < glyphP->width * glyphP->height; ++j) {
+                if (glyphP->bmap[j])
+                    printf("\\1");
+                else
+                    printf("\\0");
+            }    
+            --ng;
+            printf("\" }%s\n", ng ? "," : "");
+        }
+    }
+    printf("};\n");
+
+    printf("struct font %s = { %d, %d, %d, %d, {\n",
+           (varname == NULL) ? "XXX_font" : varname,
+           fontP->maxwidth, fontP->maxheight, fontP->x, fontP->y);
+
+    {
+        unsigned int i;
+
+        for (i = 0; i < 256; ++i) {
+            if (fontP->glyph[i])
+                printf(" _g + %d", ng++);
+            else
+                printf(" NULL");
+        
+            if (i != 255)
+                printf(",");
+
+            printf("\n");
+        }
+    }
+
+    printf(" }\n};\n");
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+
+    struct CmdlineInfo cmdline;
+    struct font * fontP;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+    
+    computeFont(cmdline.font, cmdline.builtin, &fontP);
+
+    if (cmdline.verbose)
+        reportFont(fontP);
+
+    dumpfont(fontP, cmdline.header, cmdline.varname, stdout);
+}
+
+
+
diff --git a/buildtools/installnetpbm.pl b/buildtools/installnetpbm.pl
index 61900335..d29fda1a 100755
--- a/buildtools/installnetpbm.pl
+++ b/buildtools/installnetpbm.pl
@@ -8,6 +8,7 @@ use strict;
 use English;
 use Fcntl;
 use File::Basename;
+use Cwd qw(getcwd);
 
 my ($TRUE, $FALSE) = (1,0);
 
@@ -46,6 +47,37 @@ sub prompt($$) {
 
 
 
+sub fsObjPrompt($$) {
+    my ($prompt, $default) = @_;
+#-----------------------------------------------------------------------------
+#  Prompt for a filesystem object name and accept glob pattern such as
+#  ~/mydir and /usr/lib/net* .
+#
+#  If there are zero or multiple filesystem object names that match the
+#  pattern the user gave, ask again.  If there is only one possible name
+#  consistent with the user's response, return that even if no filesystem
+#  object by that name exists.
+#-----------------------------------------------------------------------------
+    my $globbedResponse;
+
+    while (!$globbedResponse) {
+        my $response = prompt($prompt, $default);
+
+        my @matchList = glob($response);
+
+        if (@matchList == 0) {
+            print("No filesystem object matches that pattern\n");
+        } elsif (@matchList > 1) {
+            print("Multiple filesystem objects match that pattern\n");
+        } else {
+            $globbedResponse = $matchList[0];
+        }
+    }
+    return $globbedResponse;
+}
+
+
+
 sub getPkgdir() {
 #-----------------------------------------------------------------------------
 #  Find out from the user where the Netpbm package is (i.e. where
@@ -53,6 +85,17 @@ sub getPkgdir() {
 #-----------------------------------------------------------------------------
     my $pkgdir;
 
+    # We allow the user to respond with a shell filename pattern.  This seems
+    # like a lot of complexity for a barely useful feature, but we actually
+    # saw a problem where a user typed ~/mypackage without realizing that ~ is
+    # a globbing thing and was stumped when we said no such file exists, while
+    # shell commands said it does.
+
+    # Note that glob() of something that has no wildcard/substitution
+    # characters just returns its argument, whether a filesystem object by
+    # that name exists or not.  But for a wildcard pattern that doesn't match
+    # any existing files, glob() returns an empty list.
+
     while (!$pkgdir) {
     
         print("Where is the install package you created with " .
@@ -61,13 +104,32 @@ sub getPkgdir() {
         
         my $response = prompt("package directory", $default);
 
-        if (!-f("$response/pkginfo")) {
-            print("This does not appear to be a Netpbm install package. \n");
-            print("A file named $response/pkginfo does not exist.\n");
-            print("\n");
+        my @matchList = glob($response);
+
+        if (@matchList == 0) {
+            print("No filesystem object matches that pattern\n");
+        } elsif (@matchList > 1) {
+            print("Multiple filesystem objects match that pattern\n");
         } else {
-            $pkgdir = $response;
+            my $fsObjNm = $matchList[0];
+            
+            if (!-e($fsObjNm)) {
+                print("No filesystem object named '$fsObjNm' exists.\n");
+            } else {
+                if (!-d($fsObjNm)) {
+                    print("'$fsObjNm' is not a directory\n");
+                } else {
+                    if (!-f("$fsObjNm/pkginfo")) {
+                        print("Directory '$fsObjNm' does not appear to be " .
+                              "a Netpbm install package. \n");
+                        print("It does not contain a file named 'pkginfo'.\n");
+                    } else {
+                        $pkgdir = $fsObjNm;
+                    }
+                }
+            }
         }
+        print("\n");
     }
     print("\n");
     return $pkgdir;
@@ -80,8 +142,8 @@ sub makePrefixDirectory($) {
     my ($prefixDir) = @_;
 
     if ($prefixDir ne "" and !-d($prefixDir)) {
-        print("No directory named '$prefixDir' exists.  Do you want " .
-              "to create it?\n");
+        print("No directory named '$prefixDir' exists.  " .
+              "Do you want to create it?\n");
 
         my $done;
         while (!$done) {
@@ -97,6 +159,7 @@ sub makePrefixDirectory($) {
                 $done = $TRUE;
             } 
         }
+        print("\n");
     }
 }
 
@@ -123,7 +186,7 @@ sub getPrefix() {
         $default = "/usr/local/netpbm";
     }
 
-    my $response = prompt("install prefix", $default);
+    my $response = fsObjPrompt("install prefix", $default);
 
     my $prefix;
 
@@ -185,7 +248,7 @@ sub getBinDir($) {
     while (!$binDir) {
         my $default = "$prefix/bin";
 
-        my $response = prompt("program directory", $default);
+        my $response = fsObjPrompt("program directory", $default);
         
         if (-d($response)) {
             $binDir = $response;
@@ -243,7 +306,7 @@ sub getLibDir($) {
     while (!$libDir) {
         my $default = "$prefix/lib";
 
-        my $response = prompt("shared library directory", $default);
+        my $response = fsObjPrompt("shared library directory", $default);
         
         if (-d($response)) {
             $libDir = $response;
@@ -559,9 +622,194 @@ sub installSharedLib($$$) {
 
 
 
-sub getLinkDir($) {
+sub getSharedLinkDir($) {
+#-----------------------------------------------------------------------------
+#  Find out from the user where he wants the shared library stubs installed
+#  and return that.
+#-----------------------------------------------------------------------------
+    my ($prefix) = @_;
+
+    print("Where do you want the shared library stub (used to link-edit\n" .
+          "programs to use the shared lirary) installed?\n");
+    print("\n");
+
+    my $linkDir;
+
+    while (!$linkDir) {
+        my $default = "$prefix/lib";
+
+        my $response = fsObjPrompt("shared library stub directory", $default);
+        
+        if (-d($response)) {
+            $linkDir = $response;
+        } else {
+            my $succeeded = mkdir($response, 0777);
+            
+            if (!$succeeded) {
+                print("Unable to create directory '$response'.  " .
+                      "Error=$ERRNO\n");
+            } else {
+                $linkDir = $response;
+            }
+        }
+    }
+    print("\n");
+
+    return $linkDir;
+}
+
+
+
+sub removeDotDirs($) {
+
+    my ($readDirResultR) = @_;
+
+    my @dirContents;
+
+    foreach (@{$readDirResultR}) {
+        if ($_ ne '.' && $_ ne '..') {
+            push(@dirContents, $_);
+        }
+    }
+
+    return \@dirContents;
+}
+
+
+
+sub readDirContents($$$) {
+    my ($dirName, $contentsRR, $errorR) = @_;
+#-----------------------------------------------------------------------------
+#  Return the contents of the directory named $dirName, excluding the
+#  fake . and .. entries.
+#-----------------------------------------------------------------------------
+    my $dirContentsR;
+    my $error;
+
+    my $success = opendir(DIR, $dirName);
+
+    if (!$success) {
+        $error = "Unable to open directory '$dirName' with opendir()";
+    } else {
+        my @readDirResult = readdir(DIR);
+
+        $dirContentsR = removeDotDirs(\@readDirResult);
+
+        closedir(DIR);
+    }
+
+    $$contentsRR = $dirContentsR;
+
+    if ($errorR) {
+        $$errorR = $error;
+    }
+}
+
+
+
+sub dirContents($) {
+    my ($dirName) = @_;
+#-----------------------------------------------------------------------------
+#  Return the contents of the directory named $dirName, excluding the
+#  fake . and .. entries.
+#-----------------------------------------------------------------------------
+
+    readDirContents($dirName, \my $contentsR, \my $error);
+
+    if ($error) {
+        die($error);
+    }
+    return @{$contentsR};
+}
+
+
+
+sub fixSharedStubSymlink($$) {
+#-----------------------------------------------------------------------------
+#  This is a hack to install a shared library link on a GNU system.
+#
+# On systems that use the GNU dynamic linker, the shared library stub (the
+# file one uses at link-edit time to tell the linker what it needs to know
+# about the shared library that the code will use at run time) is just a
+# symbolic link to a copy of the actual shared library.  In the Netpbm
+# package, this is a relative symbolic link to the shared library in the
+# package.
+
+# Assuming Caller just copied the contents of the 'sharedlink' directory
+# straight from the package to the install target system, that symbolic link
+# isn't necessarily correct, and even if it is, it's probably messy.  (In the
+# normal case, the link value is ../lib/libnetpbm.so.<MAJ>).
+
+# So what we do is just detect and patch up that case.  If the stub is a
+# symbolic link to something in the shared library directory of the package,
+# we replace it with a symbolic link to the same thing in the shared library
+# directory of the install target system.
+# -----------------------------------------------------------------------------
+    my ($linkDir, $shlibDir) = @_;
+
+    my $oldCwd = getcwd();
+    chdir($linkDir);
+
+    foreach my $fsObjNm (dirContents('.')) {
+        if (-l("$fsObjNm")) {
+            if (readlink($fsObjNm) =~ m{^\.\./lib/(.*)$}) {
+                my $shlibNm = $1;
+
+                unlink($fsObjNm) or
+                    die("Failed to delete symlink copied from package " .
+                        "in order to replace it with a proper symlink " .
+                        "for this installation");
+
+                if ($linkDir eq $shlibDir) {
+                    symlink($shlibNm, $fsObjNm) or
+                        die("Failed to create symlink as shared library stub");
+                } else {
+                    symlink("$shlibDir/$shlibNm", $fsObjNm) or
+                        die("Failed to create symlink as shared library stub");
+                }
+                    
+                print("Linked $shlibDir/$shlibNm from $linkDir/$fsObjNm");
+            }
+        }
+    }
+    chdir($oldCwd);
+}
+
+
+
+sub installSharedStub($$$$) {
+
+    my ($pkgdir, $prefix, $shlibDir, $linkdirR) = @_;
+
+    if (-d("$pkgdir/sharedlink")) {
+        my $linkDir = getSharedLinkDir($prefix);
+
+        print("Installing shared library stubs.\n");
+
+        my $rc = system("$cpCommand $pkgdir/sharedlink/* $linkDir/");
+
+        if ($rc != 0) {
+            print("Copy of files from $pkgdir/sharedlink " .
+                  "to $linkDir failed.\n");
+            print("cp return code is $rc\n");
+        } else {
+            fixSharedStubSymlink($linkDir, $shlibDir);
+
+            print("done.\n");
+        }
+        $$linkdirR = $linkDir;
+    } else {
+        print("You did not build a shared library, so I will not " .
+              "install a stub \n");
+        $$linkdirR = undef;
+    }
+}
+
+
+
+sub getStaticLinkDir($) {
 #-----------------------------------------------------------------------------
-#  Find out from the user where he wants the link-edit libraries installed and
+#  Find out from the user where he wants the static  libraries installed and
 #  return that.
 #-----------------------------------------------------------------------------
     my ($prefix) = @_;
@@ -574,7 +822,7 @@ sub getLinkDir($) {
     while (!$linkDir) {
         my $default = "$prefix/lib";
 
-        my $response = prompt("static library directory", $default);
+        my $response = fsObjPrompt("static library directory", $default);
         
         if (-d($response)) {
             $linkDir = $response;
@@ -600,15 +848,16 @@ sub installStaticLib($$$) {
 
     my ($pkgdir, $prefix, $linkdirR) = @_;
 
-    if (-d("$pkgdir/link")) {
-        my $linkDir = getLinkDir($prefix);
+    if (-d("$pkgdir/staticlink")) {
+        my $linkDir = getStaticLinkDir($prefix);
 
-        print("Installing link libraries.\n");
+        print("Installing static link libraries.\n");
 
-        my $rc = system("$cpCommand $pkgdir/link/* $linkDir/");
+        my $rc = system("$cpCommand $pkgdir/staticlink/* $linkDir/");
 
         if ($rc != 0) {
-            print("Copy of files from $pkgdir/link to $linkDir failed.\n");
+            print("Copy of files from $pkgdir/staticlink " .
+                  "to $linkDir failed.\n");
             print("cp return code is $rc\n");
         } else {
             print("done.\n");
@@ -617,6 +866,7 @@ sub installStaticLib($$$) {
     } else {
         print("You did not build a static library, so I will not " .
               "install one \n");
+        $$linkdirR = undef;
     }
 }
 
@@ -637,7 +887,7 @@ sub getDataDir($) {
     while (!$dataDir) {
         my $default = "$prefix/lib";
 
-        my $response = prompt("data file directory", $default);
+        my $response = fsObjPrompt("data file directory", $default);
         
         if (-d($response)) {
             $dataDir = $response;
@@ -674,7 +924,7 @@ sub getHdrDir($) {
     while (!$hdrDir) {
         my $default = "$prefix/include";
 
-        my $response = prompt("header directory", $default);
+        my $response = fsObjPrompt("header directory", $default);
         
         if (-d($response)) {
             $hdrDir = $response;
@@ -752,228 +1002,6 @@ sub installHeader($$$) {
 
 
 
-sub getManDir($) {
-#-----------------------------------------------------------------------------
-#  Find out from the user where he wants the pointer man pages
-#  installed and return that.
-#-----------------------------------------------------------------------------
-    my ($prefix) = @_;
-
-    print("Where do you want the man pages installed?\n");
-
-    print("\n");
-
-    my $manDir;
-
-    while (!$manDir) {
-        my $default = "$prefix/man";
-
-        my $response = prompt("man page directory", $default);
-
-        if (-d($response)) {
-            $manDir = $response;
-        } else {
-            my $succeeded = mkdir($response, 0777);
-            
-            if (!$succeeded) {
-                print("Unable to create directory '$response'.  " .
-                      "Error=$ERRNO\n");
-            } else {
-                $manDir = $response;
-            }
-        }
-    }
-    print("\n");
-
-    return $manDir;
-}
-
-
-
-sub removeObsoleteManPage($) {
-
-    my ($mandir) = @_;
-
-    unlink("$mandir/man1/pgmoil");
-    unlink("$mandir/man1/pgmnorm");
-    unlink("$mandir/man1/ppmtojpeg");
-    unlink("$mandir/man1/bmptoppm");
-    unlink("$mandir/man1/ppmtonorm");
-    unlink("$mandir/man1/ppmtouil");
-    unlink("$mandir/man1/pnmnoraw");
-    unlink("$mandir/man1/gemtopbm");
-    unlink("$mandir/man1/pnminterp");
-}
-
-
-
-sub tryToCreateManwebConf($) {
-
-    my ($manweb_conf_filename) = $@;
-
-    print("You don't have a /etc/manweb.conf, which is the " .
-          "configuration\n");
-    print("file for the 'manweb' program, which is a quick way to " .
-          "get to Netpbm\n");
-    print("documentation.  Would you like to create one now?\n");
-        
-    my $done;
-    
-    while (!$done) {
-        my $response = prompt("create /etc/manweb.conf", "Y");
-        
-        if (uc($response) eq "Y") {
-            my $successful = open(MANWEB_CONF, ">/etc/manweb.conf");
-            if (!$successful) {
-                print("Unable to create file /etc/manweb.conf.  " .
-                          "error = $ERRNO\n");
-            } else {
-                print(MANWEB_CONF "#Configuration file for Manweb\n");
-                print(MANWEB_CONF "webdir=/usr/man/web\n");
-                close(MANWEB_CONF);
-                $done = $TRUE;
-            }
-        } else {
-            $done = $TRUE;
-        }
-    }
-}
-
-
-
-sub getWebdir($) {
-    my ($manweb_conf_filename) = @_;
-#-----------------------------------------------------------------------------
-#  Return the value of the Manweb "web directory," as indicated by the
-#  Manweb configuration file $manweb_conf_filename.
-#
-#  If that file doesn't exist, or doesn't have a 'webdir' value, or
-#  the 'webdir' value is a chain of directories instead of just one,
-#  we return an undefined value.
-#-----------------------------------------------------------------------------
-    my $webdir;
-
-    my $success = open(MANWEB_CONF, "<$manweb_conf_filename");
-    if (!$success) {
-        print("Unable to open file '$manweb_conf_filename' for reading.  " .
-              "error is $ERRNO\n");
-    } else {
-        while (<MANWEB_CONF>) {
-            chomp();
-            if (/^\s*#/) {
-                #It's comment - ignore
-            } elsif (/^\s*$/) {
-                #It's a blank line - ignore
-            } elsif (/\s*(\S+)\s*=\s*(\S+)/) {
-                #It looks like "keyword=value"
-                my ($keyword, $value) = ($1, $2);
-                if ($keyword eq "webdir") {
-                    # We can't handle a multi-directory path; we're looking
-                    # only for a webdir statement naming a sole directory.
-                    if ($value !~ m{:}) {
-                        $webdir = $value;
-                    }
-                }
-            }
-        }
-        close(MANWEB_CONF);
-    }              
-
-    return $webdir
-}
-
-
-
-sub userWantsManwebSymlink($$) {
-
-    my ($webdir, $netpbmWebdir) = @_;
-
-    print("Your manweb.conf file says top level documentation " .
-          "is in $webdir, \n");
-    print("but you installed netpbm.url in $netpbmWebdir.\n");
-    print("Do you want to create a symlink in $webdir now?\n");
-
-    my $wants;
-    my $done;
-    
-    while (!$done) {
-        my $response = prompt("create symlink (Y/N)", "Y");
-        
-        if (uc($response) eq "Y") {
-            $wants = $TRUE;
-            $done = $TRUE;
-        } elsif (uc($response) eq "N") {
-            $wants = $FALSE;
-            $done = $TRUE;
-        }
-    }
-    return $wants;
-}
-
-
-
-sub makeInManwebPath($) {
-
-    my ($netpbmWebdir) = @_;
-
-    # Now we need /etc/manweb.conf to point to the directory in which we
-    # just installed netpbm.url.
-
-    if (!-f("/etc/manweb.conf")) {
-        tryToCreateManwebConf("/etc/manweb.conf");
-    }
-    if (-f("/etc/manweb.conf")) {
-        my $webdir = getWebdir("/etc/manweb.conf");
-        if (defined($webdir)) {
-            if ($webdir ne $netpbmWebdir) {
-                if (userWantsManwebSymlink($webdir, $netpbmWebdir)) {
-                    my $old = "$netpbmWebdir/netpbm.url";
-                    my $new = "$webdir/netpbm.url";
-                    mkdir($webdir, 0777);
-                    my $success = symlink($old, $new);
-                    if (!$success) {
-                        print("Failed to create symbolic link from $new to " .
-                              "$old.  Error is $ERRNO\n");
-                    }
-                }
-            }
-        }
-    }
-}
-
-
-
-sub installManPage($$$) {
-
-
-# Note: This installs the pointer man pages and the netpbm.url file for Manweb.
-
-    my ($pkgdir, $prefix, $mandirR) = @_;
-
-    my $manDir = getManDir($prefix);
-
-    print("Installing man pages...\n");
-
-    my $rc = system("$cpCommand $pkgdir/man/* $manDir/");
-
-    if ($rc != 0) {
-        print("copy of man pages from $pkgdir/man to $manDir failed.\n");
-        print("cp exit code is $rc\n");
-    } else {
-        print("done.\n");
-    }
-
-    print("\n");
-
-    removeObsoleteManPage($manDir);
-
-    makeInManwebPath("$manDir/web");
-    
-    $$mandirR = $manDir;
-}
-
-
-
 sub netpbmVersion($) {
     my ($pkgdir) = @_;
 
@@ -1030,9 +1058,6 @@ processTemplate($$$) {
             if (defined($infoR->{INCLUDEDIR})) {
                 s/\@INCLUDEDIR@/$infoR->{INCLUDEDIR}/;
             }
-            if (defined($infoR->{MANDIR})) {
-                s/\@MANDIR@/$infoR->{MANDIR}/;
-            }
             push(@output, $_);
         }
     }
@@ -1102,7 +1127,7 @@ sub getPkgconfigDir($) {
     while (!$pkgconfigDir) {
         my $default = "$prefix/lib/pkgconfig";
 
-        my $response = prompt("Pkg-config directory", $default);
+        my $response = fsObjPrompt("Pkg-config directory", $default);
         
         if (-d($response)) {
             $pkgconfigDir = $response;
@@ -1184,8 +1209,14 @@ print("\n");
 
 my $pkgdir = getPkgdir();
 
+print("Installing from package directory '$pkgdir'\n");
+print("\n");
+
 my $prefix = getPrefix();
 
+print("Using prefix '$prefix'\n");
+print("\n");
+
 $cpCommand = getCpCommand();
 
 installProgram($pkgdir, $prefix, \my $bindir);
@@ -1194,7 +1225,10 @@ print("\n");
 installSharedLib($pkgdir, $prefix, \my $libdir);
 print("\n");
 
-installStaticLib($pkgdir, $prefix, \my $linkdir);
+installSharedStub($pkgdir, $prefix, $libdir, \my $sharedlinkdir);
+print("\n");
+
+installStaticLib($pkgdir, $prefix, \my $staticlinkdir);
 print("\n");
 
 installDataFile($pkgdir, $prefix, \my $datadir);
@@ -1203,8 +1237,7 @@ print("\n");
 installHeader($pkgdir, $prefix, \my $includedir);
 print("\n");
 
-installManPage($pkgdir, $prefix, \my $mandir);
-print("\n");
+my $linkdir = defined($sharedlinkdir) ? $sharedlinkdir : $staticlinkdir;
 
 my $templateSubsR =
     {VERSION    => netpbmVersion($pkgdir),
@@ -1213,7 +1246,7 @@ my $templateSubsR =
      LINKDIR    => $linkdir,
      DATADIR    => $datadir,
      INCLUDEDIR => $includedir,
-     MANDIR     => $mandir};
+    };
 
 installConfig($bindir, $templateSubsR);
 
diff --git a/buildtools/libopt.c b/buildtools/libopt.c
index a0bf1cda..f62194e5 100644
--- a/buildtools/libopt.c
+++ b/buildtools/libopt.c
@@ -65,6 +65,7 @@
   handle explicit file names.
 
 -----------------------------------------------------------------------------*/
+#define _DEFAULT_SOURCE 1  /* New name for SVID & BSD source defines */
 #define _BSD_SOURCE 1      /* Make sure strdup() is in stdio.h */
 #define _XOPEN_SOURCE 500  /* Make sure strdup() is in string.h */
 
@@ -497,21 +498,20 @@ main(int argc, char **argv) {
 
     bool error;
     bool runtime;  /* -runtime option has been seen */
-    bool quiet;    /* -quiet option has been seen */
     int retval;
     unsigned int arg;  /* Index into argv[] of argument we're processing */
     char outputLine[1024];
 
     strcpy(outputLine, "");  /* initial value */
     runtime = FALSE;  /* initial value */
-    quiet = FALSE;   /* initial value */
     error = FALSE;  /* no error yet */
+
     for (arg = 1; arg < argc && !error; arg++) {
         if (strcmp(argv[arg], "-runtime") == 0)
             runtime = TRUE;
-        else if (strcmp(argv[arg], "-quiet") == 0)
-            quiet = TRUE;
-        else {
+        else if (strcmp(argv[arg], "-quiet") == 0) {
+            /* Doesn't do anything today */
+        } else {
             const char * options;
             processOneLibrary(argv[arg], runtime, explicit, 
                               &options, &error);
diff --git a/buildtools/makeman b/buildtools/makeman
index 94ee2172..dc8e45ce 100755
--- a/buildtools/makeman
+++ b/buildtools/makeman
@@ -24,8 +24,15 @@
 #
 # By Eric S. Raymond <esr@thyrsus.com>
 # Version 1.0, July 26 2004
+#
+# Modified by Akira F. Urushibata <afu@wta.att.ne.jp>
+# Version 1.1, February 11 2016
+#
+#   Added ability to process &mdash; &minus;
+#   Added footer message to clarify original source. 
+#
 
-import os, sys, exceptions, re
+import os, sys, re
 
 source = "netpbm documentation"
 section = 1
@@ -37,7 +44,13 @@ warning = r'''\
 .\" against that, and send it to the Netpbm maintainer.
 '''
 
-class LiftException(exceptions.Exception):
+footerprefix = '''.SH DOCUMENT SOURCE
+This manual page was generated by the Netpbm tool 'makeman' from HTML
+source.  The master documentation is at
+.IP
+.B http://netpbm.sourceforge.net/doc/'''
+
+class LiftException(Exception):
     def __init__(self, message, retval=1):
         self.message = message
         self.retval = retval
@@ -56,6 +69,7 @@ def makeman(name, file, indoc):
     indoc = indoc.replace('<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"/>', "")
     indoc = indoc.replace('<?xml version="1.1" encoding="iso-8859-1" ?>\n',"")
     indoc = indoc.replace('<html xmlns="http://www.w3.org/1999/xhtml">', "")
+    indoc = indoc.replace('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">', "")
     indoc = indoc.replace("<HEAD>", "").replace("</HEAD>", "")
     indoc = indoc.replace("<head>", "").replace("</head>", "")
     indoc = re.sub('(?i)<A HREF="#index">Table Of Contents</A>', "", indoc)
@@ -92,6 +106,7 @@ def makeman(name, file, indoc):
         title = None
     indoc = titlematch.sub("", indoc)
     indoc = re.sub("(?i)\n*<BR>\n+", "\n", indoc)
+    indoc = re.sub("(?i)<BR>", "\n", indoc)
     indoc = ('.TH "%s" %d "%s" "%s"\n' % (title,section,date,source)) + indoc
     # Literal layout
     indoc = re.sub("(?i)\n *<PRE>", "\n.nf", indoc)
@@ -145,7 +160,7 @@ def makeman(name, file, indoc):
         if xrefsection == 0:
             return "\n.I " + xrefto
         else:
-            return "\n.BR %s (%d)\n" % (xrefto, xrefsection)
+            return '\n.BR "%s" (%d)\\c\n\\&' % (xrefto, xrefsection)
     indoc = re.sub(r'(?i)\n* *(?:\\fB)?<A[ \n]+HREF="?([^>]+.html)"?>([^<]+)</A>(?:\\fP)?',
                    xrefmatch, indoc)
     # Format URLs
@@ -203,31 +218,39 @@ def makeman(name, file, indoc):
     indoc = re.sub(r"<\?makeman (.*) \?>", r'\1', indoc)
     # Comments
     indoc = re.sub("<!--([^\n])*-->", r'.\"\1', indoc)
+    # Acronyms
+    indoc = re.sub('<acronym [a-zA-Z0-9:= \n"]*>', "", indoc)
+    indoc = re.sub("</acronym>", "", indoc)
     # Image tags
     indoc = re.sub(' *<img src="([^"]*)" alt="([^"]*)"( *[a-z]*="?[0-9]*"?)*>', ".B \\2\n.IMG -C \\1", indoc)
     # Special characters
     indoc = indoc.replace("&quot;", "'")
     indoc = indoc.replace("&nbsp;", "\\ ")
+    indoc = indoc.replace("&minus;", "-")
+    indoc = indoc.replace("&mdash;", "-")
+    indoc = indoc.replace("&mu;", "mu")
+    indoc = indoc.replace("&sigma;", "sigma")
     # Tables
-    indoc = re.sub(' *<table[^>]*>.*', ".TS", indoc)
-    indoc = re.sub(" *</table>.*", ".TE", indoc)
+    # This will not handle rowspan
+    indoc = re.sub('(?i) *<table[^>]*>.*', ".TS", indoc)
+    indoc = re.sub("(?i) *</table>.*", ".TE", indoc)
     # First the single-line case
-    indoc = re.sub("</td> *<td>", "\t", indoc)
-    indoc = re.sub("<tr> *<td>", "", indoc)
-    indoc = re.sub("</td> *</tr>", "", indoc)
+    indoc = re.sub("(?i)</td> *<td>", "\t", indoc)
+    indoc = re.sub("(?i)<tr> *<td>", "", indoc)
+    indoc = re.sub("(?i)</td> *</tr>", "", indoc)
     # Then the multiline case
-    indoc = re.sub(r'\s*<t[hd][^>]*>([^<\n]*)</t[dh]>\s*', '\t\\1', indoc)
-    indoc = re.sub(r'\s*<t[hd][^>]*>([^<]*)</t[dh]>\s*', '\tT{\n\\1T}', indoc)
+    indoc = re.sub(r'(?i)\s*<t[hd][^>]*>([^<\n]*)</t[dh]>\s*', '\t\\1', indoc)
+    indoc = re.sub(r'(?i)\s*<t[hd][^>]*>([^<]*)</t[dh]>\s*', '\tT{\n\\1T}', indoc)
     indoc = indoc.replace("\n\\&T}", "\nT}")
-    indoc = re.sub(" *</tr>", "", indoc)
-    indoc = re.sub(" *<tr[^>]*>\t*", "", indoc)
-    indoc = re.sub(r"\.TS\s+<caption>([^<]*)</caption>\s*", ".B \\1\n.TS\n", indoc)
+    indoc = re.sub("(?i) *</tr>", "", indoc)
+    indoc = re.sub("(?i) *<tr[^>]*>\t*", "", indoc)
+    indoc = re.sub(r"\.TS\s+<[Cc][Aa][Pp][Tt][Ii][Oo][Nn]>([^<]*)</[Cc][Aa][Pp][Tt][Ii][Oo][Nn]>\s*", ".B \\1\n.TS\n", indoc)
     # Debugging
     #sys.stderr.write("Name: %s, Title: %s, Date: %s\n" % (name, title, date))
     # Time for error checking now
     badlines = []
     for line in indoc.split("\n"):
-        if "<" in line or ">" in line.replace(" >", "") or re.search("&.*;", line):
+        if "<" in line or ">" in line.replace(" >", "") or re.search(r'(?<!^\\)&.*;', line):
             badlines.append(line)
     if badlines:
         sys.stderr.write(("Bad lines from %s:\n-----------------\n" % file) + "\n".join(badlines) + "\n-----------------\n")
@@ -241,6 +264,7 @@ def makeman(name, file, indoc):
     indoc = indoc.replace("\n@%@%@", "\n\\&.")
     # Mark these generated pages so people won't hand-hack them.
     indoc = warning + indoc
+    indoc = indoc + footerprefix + os.path.basename(file) +"\n.PP"
     return indoc
 
 def main(args, mainout=sys.stdout, mainerr=sys.stderr):
@@ -308,9 +332,7 @@ def main(args, mainout=sys.stdout, mainerr=sys.stderr):
                 outdoc = makeman(name, file, indoc)
             except:
                 os.remove(tempfile)
-                # Pass the exception upwards
-                (exc_type, exc_value, exc_traceback) = sys.exc_info()
-                raise exc_type, exc_value, exc_traceback
+                raise
             if outdoc == indoc:
                 os.remove(tempfile)
             if outdoc is None:
@@ -319,11 +341,11 @@ def main(args, mainout=sys.stdout, mainerr=sys.stderr):
                 outfp.write(outdoc)
                 outfp.close()	# under Windows you can't rename an open file
                 stem = file[:file.find(".")]
-                os.rename(tempfile, stem + "." + `sectmap[file]`)
-    except LiftException, e:
+                os.rename(tempfile, stem + "." + repr(sectmap[file]))
+    except LiftException as e:
         mainerr.write("makeman: " + e.message + "\n")
         return e.retval
-    except IOError, e:
+    except IOError as e:
         mainerr.write("makeman: file I/O error: %s\n" % e)
         return 3
     except KeyboardInterrupt:
@@ -331,15 +353,14 @@ def main(args, mainout=sys.stdout, mainerr=sys.stderr):
         return 4
     except:
         if verbosity:
-            (exc_type, exc_value, exc_traceback) = sys.exc_info()
-            raise exc_type, exc_value, exc_traceback
+            raise
         else:
             mainerr.write("makeman: internal error!\n")
             return 5
 
 if __name__ == "__main__":
     # Run the main sequence
-    raise SystemExit, main(sys.argv[1:])
+    raise SystemExit(main(sys.argv[1:]))
 
 # The following sets edit modes for GNU EMACS
 # Local Variables:
diff --git a/buildtools/manpage.mk b/buildtools/manpage.mk
index 76116ffe..ef1a1039 100644
--- a/buildtools/manpage.mk
+++ b/buildtools/manpage.mk
@@ -1,414 +1,203 @@
 # Make Unix man pages from Netpbm HTML user manual
-
-MAKEMAN = makeman
-
-MANDIR = /usr/share/man/
-
-# These can convert to man pages cleanly
-MAN1 = \
-	411toppm.1 \
-	anytopnm.1 \
-	asciitopgm.1 \
-	atktopbm.1 \
-	bioradtopgm.1 \
-	bmptopnm.1 \
-	bmptoppm.1 \
-	brushtopbm.1 \
-	cameratopam.1 \
-	cmuwmtopbm.1 \
-	ddbugtopbm.1 \
-	escp2topbm.1 \
-	eyuvtoppm.1 \
-	fiascotopnm.1 \
-	fitstopnm.1 \
-	fstopgm.1 \
-	g3topbm.1 \
-	gemtopbm.1 \
-	gemtopnm.1 \
-	giftopnm.1 \
-	gouldtoppm.1 \
-	hdifftopam.1 \
-	hipstopgm.1 \
-	hpcdtoppm.1 \
-	icontopbm.1 \
-	ilbmtoppm.1 \
-	imgtoppm.1 \
-	infotopam.1 \
-	jbigtopnm.1 \
-	jpeg2ktopam.1 \
-	jpegtopnm.1 \
-	leaftoppm.1 \
-	lispmtopgm.1 \
-	macptopbm.1 \
-	manweb.1 \
-	mdatopbm.1 \
-	mgrtopbm.1 \
-	mrf.1 \
-	mrftopbm.1 \
-	mtvtoppm.1 \
-	neotoppm.1 \
-	palmtopnm.1 \
-	pamaddnoise.1 \
-	pamarith.1 \
-	pambackground.1 \
-	pambayer.1 \
-	pamchannel.1 \
-	pamcomp.1 \
-	pamcut.1 \
-	pamdeinterlace.1 \
-	pamdepth.1 \
-	pamdice.1 \
-	pamditherbw.1 \
-	pamedge.1 \
-	pamendian.1 \
-	pamenlarge.1 \
-	pamfile.1 \
-	pamfixtrunc.1 \
-	pamflip.1 \
-	pamfunc.1 \
-	pamgauss.1 \
-	pamgradient.1 \
-	pamlookup.1 \
-	pammasksharpen.1 \
-	pammixinterlace.1 \
-	pamoil.1 \
-	pamperspective.1 \
-	pampick.1 \
-	pampop9.1 \
-	pamrgbatopng.1 \
-	pamscale.1 \
-	pamseq.1 \
-	pamsharpmap.1 \
-	pamsharpness.1 \
-	pamslice.1 \
-	pamsplit.1 \
-	pamstack.1 \
-	pamstereogram.1 \
-	pamstretch-gen.1 \
-	pamstretch.1 \
-	pamsumm.1 \
-	pamsummcol.1 \
-	pamthreshold.1 \
-	pamtilt.1 \
-	pamtodjvurle.1 \
-	pamtofits.1 \
-	pamtogif.1 \
-	pamtohdiff.1 \
-	pamtohtmltbl.1 \
-	pamtojpeg2k.1 \
-	pamtopfm.1 \
-	pamtopnm.1 \
-	pamtosvg.1 \
-	pamtotga.1 \
-	pamtotiff.1 \
-	pamtouil.1 \
-	pamtoxvmini.1 \
-	pamx.1 \
-	pbmclean.1 \
-	pbmlife.1 \
-	pbmmake.1 \
-	pbmmask.1 \
-	pbmpage.1 \
-	pbmpscale.1 \
-	pbmreduce.1 \
-	pbmtext.1 \
-	pbmtextps.1 \
-	pbmto10x.1 \
-	pbmto4425.1 \
-	pbmtoascii.1 \
-	pbmtoatk.1 \
-	pbmtobbnbg.1 \
-	pbmtocmuwm.1 \
-	pbmtodjvurle.1 \
-	pbmtoepsi.1 \
-	pbmtoepson.1 \
-	pbmtoescp2.1 \
-	pbmtog3.1 \
-	pbmtogem.1 \
-	pbmtogo.1 \
-	pbmtoibm23xx.1 \
-	pbmtoicon.1 \
-	pbmtolj.1 \
-	pbmtoln03.1 \
-	pbmtolps.1 \
-	pbmtomacp.1 \
-	pbmtomatrixorbital.1 \
-	pbmtomda.1 \
-	pbmtomgr.1 \
-	pbmtomrf.1 \
-	pbmtonokia.1 \
-	pbmtopgm.1 \
-	pbmtopi3.1 \
-	pbmtopk.1 \
-	pbmtoplot.1 \
-	pbmtoppa.1 \
-	pbmtopsg3.1 \
-	pbmtoptx.1 \
-	pbmtowbmp.1 \
-	pbmtox10bm.1 \
-	pbmtoxbm.1 \
-	pbmtoybm.1 \
-	pbmtozinc.1 \
-	pbmupc.1 \
-	pc1toppm.1 \
-	pcdovtoppm.1 \
-	pcxtoppm.1 \
-	pfmtopam.1 \
-	pgmabel.1 \
-	pgmbentley.1 \
-	pgmcrater.1 \
-	pgmdeshadow.1 \
-	pgmedge.1 \
-	pgmenhance.1 \
-	pgmhist.1 \
-	pgmkernel.1 \
-	pgmmake.1 \
-	pgmmedian.1 \
-	pgmminkowski.1 \
-	pgmmorphconv.1 \
-	pgmnoise.1 \
-	pgmnorm.1 \
-	pgmoil.1 \
-	pgmramp.1 \
-	pgmslice.1 \
-	pgmtexture.1 \
-	pgmtofs.1 \
-	pgmtolispm.1 \
-	pgmtopbm.1 \
-	pgmtopgm.1 \
-	pgmtoppm.1 \
-	pi1toppm.1 \
-	pi3topbm.1 \
-	picttoppm.1 \
-	pjtoppm.1 \
-	pktopbm.1 \
-	pngtopnm.1 \
-	pnmalias.1 \
-	pnmarith.1 \
-	pnmcat.1 \
-	pnmcolormap.1 \
-	pnmcomp.1 \
-	pnmconvol.1 \
-	pnmcrop.1 \
-	pnmcut.1 \
-	pnmdepth.1 \
-	pnmenlarge.1 \
-	pnmfile.1 \
-	pnmgamma.1 \
-	pnmhisteq.1 \
-	pnmhistmap.1 \
-	pnmindex.1 \
-	pnminterp.1 \
-	pnminvert.1 \
-	pnmmargin.1 \
-	pnmmontage.1 \
-	pnmnlfilt.1 \
-	pnmnoraw.1 \
-	pnmnorm.1 \
-	pnmpad.1 \
-	pnmpaste.1 \
-	pnmpsnr.1 \
-	pnmquant.1 \
-	pnmremap.1 \
-	pnmrotate.1 \
-	pnmscale.1 \
-	pnmscalefixed.1 \
-	pnmshear.1 \
-	pnmsmooth.1 \
-	pnmsplit.1 \
-	pnmstitch.1 \
-	pnmtile.1 \
-	pnmtoddif.1 \
-	pnmtofiasco.1 \
-	pnmtofits.1 \
-	pnmtojbig.1 \
-	pnmtojpeg.1 \
-	pnmtopalm.1 \
-	pnmtopclxl.1 \
-	pnmtoplainpnm.1 \
-	pnmtopng.1 \
-	pnmtopnm.1 \
-	pnmtops.1 \
-	pnmtorast.1 \
-	pnmtorle.1 \
-	pnmtosgi.1 \
-	pnmtosir.1 \
-	pnmtotiff.1 \
-	pnmtotiffcmyk.1 \
-	pnmtoxwd.1 \
-	ppm3d.1 \
-	ppmbrighten.1 \
-	ppmchange.1 \
-	ppmcie.1 \
-	ppmcolormask.1 \
-	ppmdcfont.1 \
-	ppmddumpfont.1 \
-	ppmdim.1 \
-	ppmdist.1 \
-	ppmdither.1 \
-	ppmdmkfont.1 \
-	ppmdraw.1 \
-	ppmfade.1 \
-	ppmflash.1 \
-	ppmforge.1 \
-	ppmglobe.1 \
-	ppmhist.1 \
-	ppmlabel.1 \
-	ppmmake.1 \
-	ppmmix.1 \
-	ppmnorm.1 \
-	ppmntsc.1 \
-	ppmpat.1 \
-	ppmquant.1 \
-	ppmquantall.1 \
-	ppmrainbow.1 \
-	ppmrelief.1 \
-	ppmrough.1 \
-	ppmshadow.1 \
-	ppmshift.1 \
-	ppmspread.1 \
-	ppmsvgalib.1 \
-	ppmtoacad.1 \
-	ppmtoarbtxt.1 \
-	ppmtobmp.1 \
-	ppmtoeyuv.1 \
-	ppmtoicr.1 \
-	ppmtoilbm.1 \
-	ppmtojpeg.1 \
-	ppmtoleaf.1 \
-	ppmtolj.1 \
-	ppmtomap.1 \
-	ppmtomitsu.1 \
-	ppmtompeg.1 \
-	ppmtoneo.1 \
-	ppmtopcx.1 \
-	ppmtopgm.1 \
-	ppmtopi1.1 \
-	ppmtopict.1 \
-	ppmtopj.1 \
-	ppmtopjxl.1 \
-	ppmtoppm.1 \
-	ppmtopuzz.1 \
-	ppmtorgb3.1 \
-	ppmtosixel.1 \
-	ppmtoterm.1 \
-	ppmtotga.1 \
-	ppmtouil.1 \
-	ppmtowinicon.1 \
-	ppmtoxpm.1 \
-	ppmtoyuv.1 \
-	ppmtoyuvsplit.1 \
-	ppmtv.1 \
-	ppmwheel.1 \
-	psidtopgm.1 \
-	pstopnm.1 \
-	qrttoppm.1 \
-	rasttopnm.1 \
-	rawtopgm.1 \
-	rawtoppm.1 \
-	rgb3toppm.1 \
-	rlatopam.1 \
-	rletopnm.1 \
-	sbigtopgm.1 \
-	sgitopnm.1 \
-	sirtopnm.1 \
-	sldtoppm.1 \
-	spctoppm.1 \
-	spottopgm.1 \
-	sputoppm.1 \
-	tgatoppm.1 \
-	thinkjettopbm.1 \
-	tifftopnm.1 \
-	vidtoppm.1 \
-	wbmptopbm.1 \
-	winicontoppm.1 \
-	xbmtopbm.1 \
-	ximtoppm.1 \
-	xpmtoppm.1 \
-	xvminitoppm.1 \
-	xwdtopnm.1 \
-	ybmtopbm.1 \
-	yuvsplittoppm.1 \
-	yuvtoppm.1 \
-	zeisstopnm.1 \
-
-MAN3 = \
-	libnetpbm_image.3 \
-	libnetpbm_ug.3 \
-	libnetpbm.3 \
-	libpbm.3 \
-	libpgm.3 \
-	libpm.3 \
-	libpnm.3 \
-	libppm.3 \
-	libsystem.3 \
-	libtmpfile.3 \
-
-MAN5 = \
-	extendedopacity.5 \
-	pam.5 \
-	pbm.5 \
-	pfm.5 \
-	pgm.5 \
-	pnm.5 \
-	ppm.5 \
-
-# These things do get converted to man pages and installed.
-MANPAGES = netpbm.1 $(MAN1) $(MAN3) $(MAN5)
-HTMLMANUALS = $(MAN1:.1=.html) $(MAN3:.3=.html) $(MAN5:.5=.html)
-
-# These things don't get converted to manual pages.
-EXCEPTIONS = directory.html libnetpbm_dir.html libnetpbm_draw.html error.html
-STUBS = pcdindex.1 ppmcolors.1 pnmflip.1 ppmtogif.1
-
-# This works if you've done a full SVN checkout.
-USERGUIDE= ../../userguide
-
-XML = $(HTMLMANUALS:.html=.xml) netpbm.xml
-
-# List everything in the userguide directory that is not categorized above.
-# Use this to check that 'make manpages' converts as much as possible
-# of the HTML documentation.
-uncategorized:
-	@echo $(HTMLMANUALS) $(EXCEPTIONS) $(STUBS) | tr " " "\n" | sort >LIST1
-	@(cd $(USERGUIDE); ls | sort) >LIST2
-	@comm -3 LIST1 LIST2
-	@rm LIST1 LIST2
-
-# Make man pages -- reports bad lines to standard error.
-manpages:
-	@python $(MAKEMAN) -d $(USERGUIDE) index.html $(HTMLMANUALS) 
+# GNU make version 3.81 or newer recommended.
+# Tested with GNU make version 3.80.
+
+# CAVEAT: USERGUIDE must be a valid directory: even for "make clean"!
+
+# MAKEFILE_DIR is the directory with this file: manpage.mk.
+# Should be buildtools.
+# Use $(realpath) and $(lastword) if available.
+# (both appear in GNU make v. 3.81)
+
+ifeq ($(realpath $(CURDIR)/.),$(CURDIR))
+  MAKEFILE_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
+else
+  MAKEFILE_DIR := $(dir $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)))
+endif
+
+# Program 'makeman' should be in the same directory.
+MAKEMAN ?= $(MAKEFILE_DIR)makeman
+
+# Install location of manpages.
+# Subdirectories man{1,3,5} must exist.
+MANDIR ?= /usr/share/man/
+
+# Directory with the HTML input files.  It must be explicitly set and
+# must be a valid directory.
+
+ifeq ($(USERGUIDE),)
+  $(error error: Variable USERGUIDE must be explicitly set)
+else
+  ifeq ($(wildcard $(USERGUIDE)/*html),)
+    $(error error: No HTML files found in $(USERGUIDE))
+  endif
+endif
+
+# In the past, the following default value was used.  It works if you've done
+# a Subversion checkout for source code and userguide in the same directory,
+# and you are working in a subdirectory of netpbm, say ./buildtools .
+# USERGUIDE = ../../userguide
+
+# The files that don't get converted to manual pages.
+# Override at the command line if necessary.
+
+# error.html: appears when problem occurs when fetching HTML files with wget.
+# directory.html: list of Netpbm programs.
+# libnetpbm_dir.html: directory to pages describing libnetpbm functions
+# hpcdtoppm:  Not distributed via Sourceforge for copyright restrictions.
+# ppmsvgalib: Not used in systems with X Window System.
+# vidtoppm:   Does not compile due to missing header files.
+
+EXCEPTIONS = \
+	directory.html \
+	error.html \
+	hpcdtoppm.html \
+	liberror.html \
+	libnetpbm_dir.html \
+	ppmsvgalib.html \
+	vidtoppm.html
+
+# File lists
+
+# We do not provide a list of troff manpages to be generated.
+# Instead the list is generated afresh from HTML file names.  Reasons:
+# 1. Any list would have to be updated every time an HTML file is added.
+# 2. The suffix (man section) depends on content (a "META" tag) of the
+#    HTML file.  (The makeman script is clever.)
+# 3. In one instance the file stem name changes: index.html => netpbm.1
+
+# HTML files in USERGUIDE
+HTML_ALL := $(sort $(notdir $(wildcard $(USERGUIDE)/*.html)))
+HTMLMANUALS := $(filter-out $(EXCEPTIONS),$(HTML_ALL))
+HTML_REJECT := $(filter $(EXCEPTIONS),$(HTML_ALL))
+
+# Subsets of HTMLMANUALS, by target man section
+HTML3 := $(shell cd $(USERGUIDE) && \
+                fgrep -l -i '<META NAME="manual_section" CONTENT="3">' \
+                      $(HTMLMANUALS))
+HTML5 := $(shell cd $(USERGUIDE) && \
+                fgrep -l -i '<META NAME="manual_section" CONTENT="5">' \
+                      $(HTMLMANUALS))
+HTML1 := $(filter-out $(HTML3) $(HTML5),$(HTMLMANUALS))
+
+# Troff man pages, by section
+MAN1 := $(patsubst index.1,netpbm.1,$(HTML1:.html=.1))
+MAN3 := $(HTML3:.html=.3)
+MAN5 := $(HTML5:.html=.5)
+MANPAGES := $(MAN1) $(MAN3) $(MAN5)
+
+# XML
+XML1 := $(MAN1:.1=.xml)
+XML3 := $(MAN3:.3=.xml)
+XML5 := $(MAN5:.5=.xml)
+XMLPAGES = $(XML1) $(XML3) $(XML5)
+
+.PHONY : report
+report: htmlcount manpagecount
+
+.PHONY : manpagecount
+manpagecount:
+	@echo Number of actual / expected troff man pages in current directory:
+	@echo Section 1: $(words $(wildcard $(MAN1))) / $(words $(MAN1)) 
+	@echo Section 3: $(words $(wildcard $(MAN3))) / $(words $(MAN3)) 
+	@echo Section 5: $(words $(wildcard $(MAN5))) / $(words $(MAN5)) 
+	@echo total: $(words $(wildcard $(MANPAGES))) / $(words $(MANPAGES))
+	@echo
+
+.PHONY : htmlcount
+htmlcount:
+	@echo HTML files in USERGUIDE directory: $(USERGUIDE)
+	@echo Total HTML files: $(words $(HTML_ALL))
+	@echo Rejected HTML files: $(HTML_REJECT) : $(words $(HTML_REJECT))
+	@echo Valid HTML files: $(words $(HTMLMANUALS))
+	@echo
+
+.PHONY : reportvalid
+reportvalid:
+	@echo Source HTML files in USERGUIDE directory: $(USERGUIDE)
+	@echo $(HTMLMANUALS)
+
+# Note that this may give different results from "ls ."
+.PHONY : reportman
+reportman:
+	@echo $(MANPAGES)
+
+# Static rules for converting HTML to troff man -- reports bad lines
+# to standard error.
+%.1 %.3 %.5: $(USERGUIDE)/%.html
+	@echo Converting $< to $@
+	@python $(MAKEMAN) -d $(USERGUIDE) $(<F) 
+
+netpbm.1: $(USERGUIDE)/index.html
+	@echo Converting $< to $@
+	@python $(MAKEMAN) -d $(USERGUIDE) index.html
 	@mv index.1 netpbm.1
 
-# Make XML pages, and validate them.
-xmlpages:
-	@for x in $(MANPAGES); do doclifter -v $$x; done
-	@for x in $(MANPAGES); do xmllint -xinclude --postvalid $$x.xml >/dev/null; done
-
-# This will install the generated man pages
-installman:
+# Generate man pages
+.PHONY : manpages
+manpages: $(MANPAGES)
+
+# Static rules for converting troff man to XML.
+$(XML1): %.xml: %.1
+	doclifter -v $<
+	mv $<.xml $@
+
+$(XML3): %.xml: %.3
+	doclifter -v $<
+	mv $<.xml $@
+
+$(XML5): %.xml: %.5
+	doclifter -v $<
+	mv $<.xml $@
+
+# Generate XML pages.
+# TODO: Does not work completely.  Some pages have glitches.
+.PHONY : xmlpages
+xmlpages: manpages $(XMLPAGES)
+
+# Validate XML pages.
+# TODO: Not working.
+.PHONY : xmlvalidate
+xmlvalidate: xmlpages
+	xmllint -xinclude --postvalid $< >> /dev/null
+
+# This will install the generated man pages.
+# Note that lists MAN1 MAN3 MAN5 depend upon the names of HTML files
+# in the USERGUIDE directory, even after man page generation.
+# If the current directory has "pbm.1" but USERGUIDE does not have
+# "pbm.html", the document will not be installed.
+# If the USERGUIDE directory is empty, no documents will be installed.
+
+.PHONY : installman
+installman: report
 	set -x
-	for f in netpbm.1 $(MAN1); do if [ -f $$f ]; then gzip <$$f >$(MANDIR)/man1/$$f.gz; fi; done
-	for f in $(MAN3); do if [ -f $$f ]; then gzip <$$f >$(MANDIR)/man3/$$f.gz; fi; done
-	for f in $(MAN5); do if [ -f $$f ]; then gzip <$$f >$(MANDIR)/man5/$$f.gz; fi; done
-
-# This will uninstall them
-uninstallman:
-	for f in netpbm.1 $(MAN1); do rm -f $(MANDIR)/man1/$$f.gz; fi; done
-	for f in $(MAN3); do rm -f $(MANDIR)/man3/$$f.gz; fi; done
-	for f in $(MAN5); do rm -f $(MANDIR)/man5/$$f.gz; fi; done
-
-oldclean:
-	# Clean up old locations on Fedora Core 2
-	rm -f $(MANDIR)/man1/extendedopacity.1.gz 
-	rm -f $(MANDIR)/man3/directory.3.gz
-	rm -f $(MANDIR)/man3/libnetpbm_dir.3.gz
-	# remove pointer man pages (that say, "The man page isn't here")
-	# which might have been installed previously
-	for f in $(MAN1); do rm -f $(MANDIR)/man1/$$f; done
-	for f in $(MAN3); do rm -f $(MANDIR)/man3/$$f; done
-	for f in $(MAN5); do rm -f $(MANDIR)/man5/$$f; done
-
+	for f in $(wildcard $(MAN1)); do if [ -f $$f ]; then gzip <$$f >$(MANDIR)/man1/$$f.gz; fi; done
+	for f in $(wildcard $(MAN3)); do if [ -f $$f ]; then gzip <$$f >$(MANDIR)/man3/$$f.gz; fi; done
+	for f in $(wildcard $(MAN5)); do if [ -f $$f ]; then gzip <$$f >$(MANDIR)/man5/$$f.gz; fi; done
+
+
+# This will uninstall the man pages.
+# Only pages with corresponding files in USERGUIDE are deleted.
+.PHONY : uninstallman
+uninstallman: report
+	for f in $(MAN1); do if [ -f $(MANDIR)/man1/$$f.gz ]; then rm -f $(MANDIR)/man1/$$f.gz; fi; done
+	for f in $(MAN3); do if [ -f $(MANDIR)/man3/$$f.gz ]; then rm -f $(MANDIR)/man3/$$f.gz; fi; done
+	for f in $(MAN5); do if [ -f $(MANDIR)/man5/$$f.gz ]; then rm -f $(MANDIR)/man5/$$f.gz; fi; done
+
+
+# Legacy uninstall target.
+#oldclean:
+#	# Clean up old locations on Fedora Core 2
+#	rm -f $(MANDIR)/man1/extendedopacity.1.gz 
+#	rm -f $(MANDIR)/man3/directory.3.gz
+#	rm -f $(MANDIR)/man3/libnetpbm_dir.3.gz
+#	# remove pointer man pages (that say, "The man page isn't here")
+#	# which might have been installed previously
+#	for f in $(MAN1); do rm -f $(MANDIR)/man1/$$f; done
+#	for f in $(MAN3); do rm -f $(MANDIR)/man3/$$f; done
+#	for f in $(MAN5); do rm -f $(MANDIR)/man5/$$f; done
+
+
+.PHONY: clean
 clean:
-	@rm -f *.[135] $(XML)
-
+	  @rm -f *.[135] $(XML)
diff --git a/buildtools/stamp-date b/buildtools/stamp-date
index 32839e94..f867416d 100755
--- a/buildtools/stamp-date
+++ b/buildtools/stamp-date
@@ -8,16 +8,32 @@
 # copyright notice and this permission notice appear in supporting
 # documentation.  This software is provided "as is" without express or
 # implied warranty.
-#
-DATE=$(date)
+
+# SOURCE_DATE_EPOCH is an environment variable as described here:
+# https://reproducible-builds.org/specs/source-date-epoch/ on 2017.03.16.
+
+SOURCE_DATE_OR_NONE=${SOURCE_DATE_EPOCH:-NONE}
+
+NOW_FROM_DATE_PGM=$(date +%s)
+if [ "$NOW_FROM_DATE_PGM" = "%s" ]; then
+    # This system's 'date' doesn't know %s.  (Solaris 10 for example).
+    # Try Perl
+    BUILD_DATETIME=$(perl -e 'print time()')
+else
+    BUILD_DATETIME=$NOW_FROM_DATE_PGM
+fi
+
 LOGNAME_OR_UNKNOWN=${LOGNAME:-UNKNOWN}
 USER=${USER:-$LOGNAME_OR_UNKNOWN}
 if [ "$USER" = "UNKNOWN" ]; then
-    USER=`whoami`
+    USER=$(whoami)
 fi
 
-echo "/* This file tells the package when it was compiled */"
+echo "/* This file tells some facts about the building of the package */"
 echo "/* DO NOT EDIT - THIS FILE IS MAINTAINED AUTOMATICALLY */"
 echo "/* Created by the program 'stamp-date'  */"
-echo "#define COMPILE_TIME \"$DATE\""
+if [ "$SOURCE_DATE_OR_NONE" != "NONE" ]; then
+  echo "#define SOURCE_DATETIME $SOURCE_DATE_OR_NONE"
+fi
+echo "#define BUILD_DATETIME $BUILD_DATETIME"
 echo "#define COMPILED_BY \"$USER\""