diff options
Diffstat (limited to 'buildtools')
-rw-r--r-- | buildtools/Makefile | 12 | ||||
-rwxr-xr-x | buildtools/configure.pl | 115 | ||||
-rw-r--r-- | buildtools/debian/README | 17 | ||||
-rwxr-xr-x | buildtools/debian/mkdeb | 17 | ||||
-rw-r--r-- | buildtools/genfontc.c | 199 | ||||
-rwxr-xr-x | buildtools/installnetpbm.pl | 533 | ||||
-rw-r--r-- | buildtools/libopt.c | 10 | ||||
-rwxr-xr-x | buildtools/makeman | 67 | ||||
-rw-r--r-- | buildtools/manpage.mk | 607 | ||||
-rwxr-xr-x | buildtools/stamp-date | 19 |
10 files changed, 877 insertions, 719 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 42a986eb..684ca0fb 100755 --- a/buildtools/debian/mkdeb +++ b/buildtools/debian/mkdeb @@ -10,6 +10,10 @@ # package (what Debian contains is derived from Sourceforge Netpbm ca. # 2002). # +# The dependencies this package declares are those that can be satisfied by +# Debian 8 (Jessie) and Debian 9 (Stretch). Netpbm works fine on other +# versions of Debian, but you may have to change the dependencies in this +# program or ignore dependencies at install time. ############################################################################### use strict; @@ -111,8 +115,8 @@ sub control($$) { # 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 8. -# This makes the Netpbm package less useful. +# 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; @@ -134,9 +138,8 @@ sub control($$) { $control{'Depends'} = 'libc6, ' . 'libjpeg62, ' . - 'libpng12-0, ' . - 'libsvga1, ' . - 'libtiff4, ' . + 'libpng12-0 | libpng16-16, ' . + 'libtiff5, ' . 'libx11-6, ' . 'libxml2, ' . 'zlib1g, ' . @@ -425,7 +428,9 @@ sub buildDpkgBuildTree($$$$$) { makePkgConfig("$dpkgDirName/usr/lib/pkgconfig/netpbm.pc", $templateSubsR, $netpbmPkgDir); - makeManweb($dpkgDirName, $netpbmPkgDir); + # Beginning in Netpbm 10.78 (March 2017_, 'make package' doesn't package + # the manweb stuff, so we no longer put it in the Debian package. + #makeManweb($dpkgDirName, $netpbmPkgDir); } 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 — − +# 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(""", "'") indoc = indoc.replace(" ", "\\ ") + indoc = indoc.replace("−", "-") + indoc = indoc.replace("—", "-") + indoc = indoc.replace("μ", "mu") + indoc = indoc.replace("σ", "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..902c82e4 100755 --- a/buildtools/stamp-date +++ b/buildtools/stamp-date @@ -8,16 +8,25 @@ # 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} + +BUILD_DATETIME=$(date +%s) + 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\"" |