#!/usr/bin/perl -w

require 5.000;

use strict;
use English;
use File::Basename;
use Cwd 'abs_path';
use Fcntl;
use Config;
#use File::Temp "tempfile";   Not available before Perl 5.6.1
    

my ($TRUE, $FALSE) = (1,0);

# This program generates Makefile.config, which is included by all of the
# Netpbm makefiles.  You run this program as the first step in building 
# Netpbm.  (The second step is 'make').

# This program is only a convenience.  It is supported to create 
# Makefile.config any way you want.  In fact, an easy way is to copy
# Makefile.config.in and follow the instructions in the comments therein
# to uncomment certain lines and make other changes.

# Note that if you invoke 'make' without having first run 'configure',
# the make will call 'configure' itself when it finds
# 'Makefile.config' missing.  That might look a little messy to the
# user, but it isn't the normal build process.

# The argument to this program is the filepath of the Makefile.config.in
# file.  If unspecified, the default is 'Makefile.config.in' in the 
# Netpbm source directory.

# For explanations of the stuff we put in the make files, see the comments
# in Makefile.config.in.


# $testCc is the command we use to do test compiles.  Note that test
# compiles are never more than heuristics, because we may be configuring
# a build that will happen on a whole different system, which will build
# programs to run on a third system.

my $testCc;

##############################################################################
#
#  Implementation note:
#
#  At one time, we thought we had to add /usr/local/lib and /usr/local/include
#  to the path on some platforms because they needed it and didn't include
#  it in the default compiler search path.  But then we had reason to doubt
#  that was really required, so removed the function on 04.03.15 and never
#  had any complaint in the next 3 years.
##############################################################################


#******************************************************************************
#
#  SUBROUTINES
#
#*****************************************************************************

sub autoFlushStdout() {
    my $oldFh = select(STDOUT);
    $OUTPUT_AUTOFLUSH = $TRUE;
    select($oldFh);
}



sub prompt($$) {

    my ($prompt, $default) = @_;

    my $defaultPrompt = defined($default) ? $default : "?";

    print("$prompt [$defaultPrompt] ==> ");

    my $response = <STDIN>;

    if (defined($response)) {
        chomp($response);
        if ($response eq "" && defined($default)) {
            $response = $default;
        }
    } else {
        print("\n");
        die("End of file on Standard Input when expecting response to prompt");
    }

    return $response;
}



sub tmpdir() {
# This is our approximation of File::Spec->tmpdir(), which became part of
# basic Perl some time after Perl 5.005_03.

    my $retval;
    
    if ($ENV{"TMPDIR"}) {
        $retval = $ENV{"TMPDIR"};
    } else {
        if ($Config{'osvers'} eq "djgpp") {
            $retval = "/dev/env/DJDIR/tmp";
        } else {
            $retval =  "/tmp";
        }
    }
    return $retval;
}



sub tempFile($) {

# Here's what we'd do if we could expect Perl 5.6.1 or later, instead
# of calling this subroutine:
#    my ($cFile, $cFileName) = tempfile("netpbmXXXX", 
#                                       SUFFIX=>".c", 
#                                       DIR=>File::Spec->tmpdir(),
#                                       UNLINK=>0);
    my ($suffix) = @_;
    my $fileName;
    local *file;  # For some inexplicable reason, must be local, not my
    my $i;
    $i = 0;
    do {
        $fileName = tmpdir() . "/netpbm" . $i++ . $suffix;
    } until sysopen(*file, $fileName, O_RDWR|O_CREAT|O_EXCL);

    return(*file, $fileName);
}



sub commandExists($) {
    my ($command) = @_;
#-----------------------------------------------------------------------------
#  Return TRUE iff a shell command $command exists.
#-----------------------------------------------------------------------------

# Note that it's significant that the redirection on the following
# causes it to be executed in a shell.  That makes the return code
# from system() a lot different than if system() were to try to
# execute the program directly.

    return(system("$command 1</dev/null 1>/dev/null 2>/dev/null")/256 != 127); 
}



sub chooseTestCompiler($$) {

    my ($compiler, $testCcR) = @_;

    my $cc;

    if (!defined($compiler)) {
        if ($ENV{'CC'}) {
            $cc = $ENV{'CC'};
        } else {
            if (commandExists('cc')) {
                $cc = 'cc';
            } elsif (commandExists("gcc")) {
                $cc = 'gcc';
            }
        }
    } elsif ($compiler eq 'cc') {
        $cc = "cc";
    } elsif ($compiler eq 'gcc') {
        $cc = 'gcc';
    } else {
        die("Internal error: invalid value \"$compiler\" for \$compiler");
    }
    $$testCcR = $cc;
}



sub testCflags() {

    my $cflags;

    $cflags = "";  # initial value 
    
    if ($ENV{"CPPFLAGS"}) {
        $cflags = $ENV{"CPPFLAGS"};
    } else {
        $cflags = "";
    }
    
    if ($ENV{"CFLAGS"}) {
        $cflags .= " " . $ENV{"CFLAGS"};
    }
    
    return $cflags;
}    



sub testCompile($$$) {
    my ($cflags, $cSourceCodeR, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile of the program in @{$cSourceCodeR}.
#  
#  Return $$successR == $TRUE iff the compile succeeds (exit code 0).
#-----------------------------------------------------------------------------
    my ($cFile, $cFileName) = tempFile(".c");

    print $cFile @{$cSourceCodeR};
    
    my ($oFile, $oFileName) = tempFile(".o");
    # Note: we tried using /dev/null for the output file and got complaints
    # from the Sun compiler that it has the wrong suffix.  2002.08.09.
    
    my $compileCommand = "$testCc -c -o $oFileName $cflags $cFileName";
    print ("Doing test compile: $compileCommand\n");
    my $rc = system($compileCommand);
    
    unlink($oFileName);
    close($oFile);
    unlink($cFileName);
    close($cFile);

    $$successR = ($rc == 0);
}



sub testCompileLink($$$) {
    my ($flags, $cSourceCodeR, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile of the program in @{$cSourceCodeR}.
#  
#  Return $$successR == $TRUE iff the compile succeeds (exit code 0).
#-----------------------------------------------------------------------------
    my ($cFile, $cFileName) = tempFile('.c');

    print $cFile @{$cSourceCodeR};
    
    my ($oFile, $oFileName) = tempFile('');

    # Note that $flags may contain -l options, which where static linking
    # is involved have to go _after_ the base object file ($oFileName).
    
    my $compileCommand = "$testCc -o $oFileName $cFileName $flags";
    print ("Doing test compile/link: $compileCommand\n");
    my $rc = system($compileCommand);
    
    unlink($oFileName);
    close($oFile);
    unlink($cFileName);
    close($cFile);

    $$successR = ($rc == 0);
}



sub displayIntroduction() {
    print("This is the Netpbm configurator.  It is an interactive dialog " .
          "that\n");
    print("helps you build the file 'Makefile.config' and prepare to build ");
    print("Netpbm.\n");
    print("\n");

    print("Do not be put off by all the questions.  Configure gives you " .
          "the \n");
    print("opportunity to make a lot of choices, but you don't have to.  " .
          "If \n");
    print("you don't have reason to believe you're smarter than Configure,\n");
    print("just take the defaults (hit ENTER) and don't sweat it.\n");
    print("\n");

    print("If you are considering having a program feed answers to the " .
          "questions\n");
    print("below, please read doc/INSTALL, because that's probably the " .
          "wrong thing to do.\n");
    print("\n");

    print("Hit ENTER to begin.\n");
    my $response = <STDIN>;
}


sub askAboutCygwin() {

    print("Are you building in/for the Cygwin environment?\n");
    print("\n");
    
    my $default;
    if ($OSNAME eq "cygwin") {
        $default = "y";
    } else {
        $default = "n";
    }
    
    my $retval;

    while (!defined($retval)) {
        my $response = prompt("(y)es or (n)o", $default);
    
        if (uc($response) =~ /^(Y|YES)$/)  {
            $retval = $TRUE;
        } elsif (uc($response) =~ /^(N|NO)$/)  {
            $retval = $FALSE;
        } else {
            print("'$response' isn't one of the choices.  \n" .
                  "You must choose 'yes' or 'no' (or 'y' or 'n').\n");
        }
    }
    return $retval;
}



sub askAboutDjgpp() {

    print("Are you building in/for the DJGPP environment?\n");
    print("\n");
    
    my $default;
    if ($OSNAME eq "dos") {
        $default = "y";
    } else {
        $default = "n";
    }
    
    my $retval;

    while (!defined($retval)) {
        my $response = prompt("(y)es or (n)o", $default);
    
        if (uc($response) =~ /^(Y|YES)$/)  {
            $retval = $TRUE;
        } elsif (uc($response) =~ /^(N|NO)$/)  {
            $retval = $FALSE;
        } else {
            print("'$response' isn't one of the choices.  \n" .
                  "You must choose 'yes' or 'no' (or 'y' or 'n').\n");
        }
    }
}



sub computePlatformDefault($) {

    my ($defaultP) = @_;

    if ($OSNAME eq "linux") {
        $$defaultP = "gnu";
    } elsif ($OSNAME eq "cygwin") {
        $$defaultP = "win";
    } elsif ($OSNAME eq "dos") {
        # DJGPP says "dos"
        $$defaultP = "win";
    } elsif ($OSNAME eq "aix" || $OSNAME eq "freebsd" || $OSNAME eq "darwin" ||
             $OSNAME eq "amigaos") {
        $$defaultP = $OSNAME;
    } elsif ($OSNAME eq "solaris") {
        $$defaultP = "sun";
    } elsif ($OSNAME eq "dec_osf") {
        $$defaultP = "tru64";
    } else {
        print("Unrecognized OSNAME='$OSNAME'.  No default possible\n");
    }
    # OK - if you know what $OSNAME is on any other platform, send me a patch!
}



sub getPlatform() {

    my $platform;
    my $default;

    computePlatformDefault(\$default);

    print("Which of the following best describes your platform?\n");
 
    print("gnu      GNU/Linux\n");
    print("sun      Solaris or SunOS\n");
    print("hp       HP-UX\n");
    print("aix      AIX\n");
    print("win      Windows/DOS (Cygwin, DJGPP, Mingw32)\n");
    print("tru64    Tru64\n");
    print("irix     Irix\n");
    print("bsd      NetBSD, BSD/OS\n");
    print("openbsd  OpenBSD\n");
    print("freebsd  FreeBSD\n");
    print("darwin   Darwin or Mac OS X\n");
    print("amigaos  Amiga\n");
    print("unixware Unixware\n");
    print("sco      SCO OpenServer\n");
    print("beos     BeOS\n");
    print("none     none of these are even close\n");
    print("\n");

    my $response = prompt("Platform", $default);

    my %platform = ("gnu"      => "GNU",
                    "sun"      => "SOLARIS",
                    "hp"       => "HP-UX",
                    "aix"      => "AIX",
                    "tru64"    => "TRU64",
                    "irix"     => "IRIX",
                    "win"      => "WINDOWS",
                    "beos"     => "BEOS",
                    "bsd"      => "NETBSD",
                    "openbsd"  => "OPENBSD",
                    "freebsd"  => "FREEBSD",
                    "unixware" => "UNIXWARE",
                    "sco"      => "SCO",
                    "darwin"   => "DARWIN",
                    "amigaos"  => "AMIGA",
                    "none"     => "NONE"
                    );

    $platform = $platform{$response};
    if (!defined($platform)) {
        print("'$response' isn't one of the choices.\n");
        exit 8;
    }

    my $subplatform;

    if ($platform eq "WINDOWS") {
        my ($djgpp, $cygwin);

        if ($OSNAME eq "dos") {
            $djgpp = askAboutDjgpp();
            if ($djgpp) {
                $cygwin = $FALSE;
            } else {
                $cygwin = askAboutCygwin();
            }
        } else {
            $cygwin = askAboutCygwin();
            if ($cygwin) {
                $djgpp = $FALSE;
            } else {
                $djgpp = askAboutDjgpp();
            }
        }

        if ($cygwin) {
            $subplatform = "cygwin";
        } elsif ($djgpp) {
            $subplatform = "djgpp";
        } else {
            $subplatform = "other";
        }
    }

    return($platform, $subplatform);
}



sub getCompiler($$) {
    my ($platform, $compilerR) = @_;
#-----------------------------------------------------------------------------
#  Here are some of the issues surrounding choosing a compiler:
#
#  - It's not just the name of the program we need -- different compilers
#    need different options.
#
#  - There are basically two choices on any system:  native compiler or
#    GNU compiler.  That's all this program recognizes, anyway.
#
#  - A user may well have various compilers.  Different releases, using
#    different standard libraries, for different target machines, etc.
#
#  - The CC environment variable tells the default compiler.
#
#  - In the absence of a CC environment variable, 'cc' is the default
#    compiler.
#
#  - The user must be able to specify the compiler by overriding the CC
#    make variable (e.g. make CC=gcc2).
#
#  - Configure needs to do test compiles.  The test is best if it uses
#    the same compiler that the build eventually will use, but it's 
#    useful even if not.
#
# The value this subroutine returns is NOT the command name to invoke the
# compiler.  It is simply "cc" to mean native compiler or "gcc" to mean
# GNU compiler or undefined to express no preference.
#-----------------------------------------------------------------------------
    my %gccCapablePlatform = ("SOLARIS" => 1,
                              "TRU64"   => 1,
                              "SCO"     => 1,
                              "AIX"     => 1,
                              "HP"      => 1);

    if ($gccCapablePlatform{$platform}) {
        print("GNU compiler or native operating system compiler (cc)?\n");
        print("\n");

        my $default;

        if ($platform eq "SOLARIS" || $platform eq "SCO" ) {
            $default = "gcc";
        } else {
            $default = "cc";
        }

        my $response = prompt("gcc or cc", $default);

        if ($response eq "gcc") {
            $$compilerR = "gcc";
        } elsif ($response eq "cc") {
            $$compilerR = "cc";
        } else {
            print("'$response' isn't one of the choices.  \n" .
                  "You must choose 'gcc' or 'cc'.\n");
            exit 12;
        }

        if ($$compilerR eq 'gcc' && !commandExists('gcc')) {
            print("WARNING: You selected the GNU compiler, " .
                  "but do not appear to have a program " .
                  "named 'gcc' in your PATH.  This may " .
                  "cause trouble later.  You may need to " .
                  "set the CC environment variable or CC " .
                  "makefile variable or install 'gcc'\n");
        }
        print("\n");
    }
}



sub gccLinker() {
#-----------------------------------------------------------------------------
#  Determine what linker Gcc on this system appears to use.
#
#  Return either "gnu" or "sun"
#
#  For now, we assume it must be either a GNU linker or Sun linker and
#  that all Sun linkers are fungible.
#
#  If we can't tell, we assume it is the GNU linker.
#-----------------------------------------------------------------------------
    # First, we assume that the compiler calls 'collect2' as the linker
    # front end.  The specs file might specify some other program, but
    # it usually says 'collect2'.
    
    my $retval;

    my $collect2 = qx{gcc --print-prog-name=collect2};
    
    if (defined($collect2)) {
        chomp($collect2);
        my $linker = qx{$collect2 -v 2>&1};
        if (defined($linker) && $linker =~ m{GNU ld}) {
            $retval = "gnu";
        } else {
            $retval = "sun";
        }
    } else {
        $retval = "gnu";
    }
    return $retval;
}



sub getLinker($$$$) {

    my ($platform, $compiler, $baseLinkerR, $viaCompilerR) = @_;

    my $baseLinker;

    if ($platform eq "SOLARIS") {
        $$viaCompilerR = $TRUE;

        while (!defined($$baseLinkerR)) {
            print("GNU linker or SUN linker?\n");
            print("\n");

            my $default;
            
            if ($compiler eq "gcc") {
                $default = gccLinker();
            } else {
                $default = "sun";
            }
            my $response = prompt("sun or gnu", $default);
            
            if ($response eq "gnu") {
                $$baseLinkerR = "GNU";
            } elsif ($response eq "sun") {
                $$baseLinkerR = "SUN";
            } else {
                print("'$response' isn't one of the choices.  \n" .
                      "You must choose 'sun' or 'gnu'.\n");
            }
            print("\n");
        }
    } else {
        $$viaCompilerR = $TRUE;
        $$baseLinkerR = "?";
    }
}



sub libSuffix($) {
    my ($platform) = @_;
#-----------------------------------------------------------------------------
#  Return the traditional suffix for the link-time library on platform
#  type $platform.
#
#  Note that this information is used mainly for cosmetic purposes in this
#  this program and the Netpbm build, because the build typically removes
#  any suffix and uses link options such as "-ltiff" to link the library.
#  This leaves it up to the linker to supply the actual suffix.
#-----------------------------------------------------------------------------
    my $suffix;

    if ($platform eq 'WINDOWS') {
        $suffix = '.dll';
    } elsif ($platform eq 'AIX') {
        $suffix = '.a';
    } elsif ($platform eq 'DARWIN') {
        $suffix = '.dylib';
    } else {
        $suffix = '.so';
    }
}



sub getLibTypes($$$$$$$$) {
    my ($platform, $subplatform, $default_target,
        $netpbmlibtypeR, $netpbmlibsuffixR, $shlibprefixlistR,
        $willBuildSharedR, $staticlib_tooR) = @_;

    print("Do you want libnetpbm to be statically linked or shared?\n");
    print("\n");

    my $default = ($default_target eq "merge") ? "static" : "shared";

    my ($netpbmlibtype, $netpbmlibsuffix, $shlibprefixlist, 
        $willBuildShared, $staticlib_too);
    
    my $response = prompt("static or shared", $default);
    
    if ($response eq "shared") {
        $willBuildShared = $TRUE;
        if ($platform eq "WINDOWS") {
            $netpbmlibtype = "dll";
            $netpbmlibsuffix = "dll";
            if ($subplatform eq "cygwin") {
                $shlibprefixlist = "cyg lib";
            } 
        } elsif ($platform eq "DARWIN") {
            $netpbmlibtype = "dylib";
            $netpbmlibsuffix = "dylib";
        } else {
	    if ($platform eq "IRIX") {
		$netpbmlibtype = "irixshared";
	    } else {
		$netpbmlibtype = "unixshared";
	    }
            if ($platform eq "AIX") {
                $netpbmlibsuffix = "a";
            } elsif ($platform eq "HP-UX") {
                $netpbmlibsuffix = "sl";
            } else {
                $netpbmlibsuffix = "so";
            }
        }
    } elsif ($response eq "static") {
        $willBuildShared = $FALSE;
        $netpbmlibtype = "unixstatic";
        $netpbmlibsuffix = "a";
        # targets, but needed for building
        # libopt 
    } else {
        print("'$response' isn't one of the choices.  \n" .
              "You must choose 'static' or 'shared'.\n");
        exit 12;
    }

    print("\n");

    # Note that we can't do both a static and shared library for AIX, because
    # they both have the same name: libnetpbm.a.
    
    if (($netpbmlibtype eq "unixshared" or 
         $netpbmlibtype eq "irixshared" or 
         $netpbmlibtype eq "dll") and $netpbmlibsuffix ne "a") {
        print("Do you want to build static libraries too (for linking to \n");
        print("programs not in the Netpbm package?\n");
        print("\n");
        
        my $default = "y";
        
        my $response = prompt("(y)es or (n)o", $default);
        
        if (uc($response) =~ /^(Y|YES)$/)  {
            $staticlib_too = "y";
        } elsif (uc($response) =~ /^(N|NO)$/)  {
            $staticlib_too = "n";
        } else {
            print("'$response' isn't one of the choices.  \n" .
              "You must choose 'yes' or 'no' (or 'y' or 'n').\n");
            exit 12;
        }
    } else {
        $staticlib_too = "n";
    }
    print("\n");

    $$netpbmlibtypeR   = $netpbmlibtype;
    $$netpbmlibsuffixR = $netpbmlibsuffix;
    $$shlibprefixlistR = $shlibprefixlist;
    $$willBuildSharedR = $willBuildShared;
    $$staticlib_tooR   = $staticlib_too;
}



sub inttypesDefault() {

    my $retval;

    if (defined($testCc)) {

        print("(Doing test compiles to choose a default for you -- " .
              "ignore errors)\n");

        my $cflags = testCflags();

        my $works;

        # We saw a system (Irix 5.3 with native IDO, December 2005) on
        # which sys/types.h defines uint32_t, but not int32_t and other
        # similar types.  We saw a Mac OS X system (January 2006) on which
        # sys/types sometimes defines uint32_t, but sometimes doesn't.
        # So we make those last resorts.

        # int_fastXXX_t are the least likely of all the types to be
        # defined, so we look for that.

        # Solaris 8, for example, has a <sys/inttypes.h> that defines
        # int32_t and uint32_t, but nothing the defines int_fast32_t.

        my @candidateList = ("<inttypes.h>", "<sys/inttypes.h>",
                             "<types.h>", "<sys/types.h>");
        
        for (my $i = 0; $i < @candidateList && !$works; ++$i) {
            my $candidate = $candidateList[$i];
            my @cSourceCode = (
                               "#include $candidate\n",
                               "int_fast32_t testvar;\n"
                               );
            
            testCompile($cflags, \@cSourceCode, \my $success);
            
            if ($success) {
                $works = $candidate;
            }
        }
        if ($works) {
            $retval = $works;
        } else {
            testCompile($cflags, ["int_fast32_t testvar;"], \my $success);
            if ($success) {
                $retval = "NONE";
            } else {
                $retval = '"inttypes_netpbm.h"';
            }
        }
        print("\n");
    } else {
        $retval = '<inttypes.h>';
    }
    return $retval;
}



sub getInttypes($) {
    my ($inttypesHeaderFileR) = @_;

    my $gotit;

    print("What header file defines uint32_t, etc.?\n");
    print("\n");

    my $default = inttypesDefault();
    
    while (!$gotit) {
        my $response = prompt("'#include' argument or NONE", $default);

        if ($response eq "NONE") {
            $$inttypesHeaderFileR = '';
            $gotit = $TRUE;
        } else {
            if ($response !~ m{<.+>} &&
                $response !~ m{".+"}) {
                print("'$response' is not a legal argument of a C #include " .
                      "statement.  It must be something in <> or \"\".\n");
            } else {
                $gotit = $TRUE;
                $$inttypesHeaderFileR = $response;
            }
        }
    }
}


sub getInt64($$) {

    my ($inttypes_h, $haveInt64R) = @_;

    if (defined($testCc)) {

        print("(Doing test compiles to determine if you have int64 type -- " .
              "ignore errors)\n");

        my $cflags = testCflags();

        my $works;

        my @cSourceCode = (
                           "#include $inttypes_h\n",
                           "int64_t testvar;\n"
                           );
            
        testCompile($cflags, \@cSourceCode, \my $success);
            
        if ($success) {
            print("You do.\n");
            $$haveInt64R = 'Y';
        } else {
            print("You do not.  64-bit code won't be built.\n");
            $$haveInt64R = 'N';
        }
        print("\n");
    } else {
        $$haveInt64R = "N";
    }
}



# TODO: These should do test compiles to see if the headers are in the
# default search path, both to create a default to offer and to issue a
# warning after user has chosen.  Also test links to test the link library.

# It looks like these should all be in the default search paths and were there
# just to override defaults in Makefile.config.in.  Since Configure now
# creates a default of "standard search path," I'm guessing we don't need
# to set these anymore.

sub getTiffLibrary($@) {

    my ($platform, @suggestedHdrDir) = @_;

    my $tifflib;
    {
        my $default = "libtiff" . libSuffix($platform);

        print("What is your TIFF (graphics format) library?\n");
        
        my $response = prompt("library filename or 'none'", $default);
        
        if ($response ne "none") {
            $tifflib = $response;
        }
        if (defined($tifflib) and $tifflib =~ m{/} and !-f($tifflib)) {
            printf("WARNING: No regular file named '$tifflib' exists.\n");
        }
    }
    my $tiffhdr_dir;
    if (defined($tifflib)) {
        my $default;

        if (-d("/usr/include/tiff")) {
            $default = "/usr/include/tiff";
        } elsif (-d("/usr/include/libtiff")) {
            $default = "/usr/include/libtiff";
        } else {
            $default = "default";
        }
        print("Where are the interface headers for it?\n");
        
        my $response = prompt("TIFF header directory", $default);
        
        if ($response ne "default") {
            $tiffhdr_dir = $response;
        }
        if (defined($tiffhdr_dir) and !-d($tiffhdr_dir)) {
            printf("WARNING: No directory named '$tiffhdr_dir' exists.\n");
        }
    }
    return($tifflib, $tiffhdr_dir);
}



sub getJpegLibrary($@) {

    my ($platform, @suggestedHdrDir) = @_;

    my $jpeglib;
    {
        my $default = "libjpeg" . libSuffix($platform);

        print("What is your JPEG (graphics format) library?\n");
        
        my $response = prompt("library filename or 'none'", $default);
        
        if ($response ne "none") {
            $jpeglib = $response;
        }
    }
    my $jpeghdr_dir;
    if (defined($jpeglib)) {
        my $default;

        if (-d("/usr/include/jpeg")) {
            $default = "/usr/include/jpeg";
        } else {
            $default = "default";
        }
        print("Where are the interface headers for it?\n");
        
        my $response = prompt("JPEG header directory", $default);
        
        if ($response ne "default") {
            $jpeghdr_dir = $response;
        }
        if (defined($jpeghdr_dir) and !-d($jpeghdr_dir)) {
            printf("WARNING: No directory named '$jpeghdr_dir' exists.\n");
        }
    }
    return($jpeglib, $jpeghdr_dir);
}



sub getPngLibrary($@) {

    my ($platform, @suggestedHdrDir) = @_;

    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.
    } else {
        {
            my $default = "libpng" . libSuffix($platform);

            print("What is your PNG (graphics format) library?\n");
            
            my $response = prompt("library filename or 'none'", $default);
            
            if ($response ne "none") {
                $pnglib = $response;
            }
        }
        if (defined($pnglib)) {
            my $default;

            if (-d("/usr/include/png")) {
                $default = "/usr/include/libpng";
            } else {
                $default = "default";
            }
            
            print("Where are the interface headers for it?\n");
            
            my $response = prompt("PNG header directory", $default);

            if ($response ne "default") {
                $pnghdr_dir = $response;
            }
        }
    }
    return($pnglib, $pnghdr_dir);
}



sub getZLibrary($@) {

    my ($platform, @suggestedHdrDir) = @_;

    my ($zlib, $zhdr_dir);

    {
        my $default = "libz" . libSuffix($platform);

        print("What is your Z (compression) library?\n");
        
        my $response = prompt("library filename or 'none'", $default);
        
        if ($response ne "none") {
            $zlib = $response;
        }
    }
    if (defined($zlib)) {
        my $default;

        if (-d("/usr/include/zlib")) {
            $default = "/usr/include/zlib";
        } else {
            $default = "default";
        }
        
        print("Where are the interface headers for it?\n");
        
        my $response = prompt("Z header directory", $default);
        
        if ($response ne "default") {
            $zhdr_dir = $response;
        }
    }
    return($zlib, $zhdr_dir);
}



sub getX11Library($@) {

    my ($platform, @suggestedHdrDir) = @_;

    my $x11lib;
    {
        my $default;

        if (-d('/usr/link/X11')) {
            $default = '/usr/link/X11/libX11' . libSuffix($platform);
        } elsif (-d('/usr/X11R6')) {
            $default = '/usr/X11R6/lib/libX11' . libSuffix($platform);
        } else {
            $default = "libX11" . libSuffix($platform);
        }
        print("What is your X11 (X client) library?\n");
        
        my $response = prompt("library filename or 'none'", $default);
        
        if ($response ne "none") {
            $x11lib = $response;
        }
    }
    my $x11hdr_dir;
    if (defined($x11lib)) {
        my $default;

        $default = "default";

        print("Where are the interface headers for it?\n");
        
        my $response = prompt("X11 header directory", $default);
        
        if ($response ne "default") {
            $x11hdr_dir = $response;
        }
        if (defined($x11hdr_dir)) {
            if (!-d($x11hdr_dir)) {
                printf("WARNING: No directory named '$x11hdr_dir' exists.\n");
            } elsif (!-d("$x11hdr_dir/X11")) {
                printf("WARNING: Directory '$x11hdr_dir' does not contain " .
                       "the requisite 'X11' subdirectory\n");
            }
        }
    }
    return($x11lib, $x11hdr_dir);
}



sub getLinuxsvgaLibrary($@) {

    my ($platform, @suggestedHdrDir) = @_;

    my ($svgalib, $svgalibhdr_dir);

    if ($platform eq "GNU") {
        my $default;

        if (-d('/usr/link/svgalib')) {
            $default = '/usr/link/svgalib/libvga.so';
        } elsif (-d('/usr/lib/svgalib')) {
            $default = '/usr/lib/svgalib/libvga.so';
        } elsif (system('ldconfig -p | grep libvga &>/dev/null') == 0) {
            $default = 'libvga.so';
        } else {
            $default = 'none';
        }
            
        print("What is your Svgalib library?\n");
        
        my $response = prompt("library filename or 'none'", $default);
            
        if ($response ne 'none') {
            $svgalib = $response;
        }
    }
    if (defined($svgalib) && $svgalib ne 'none') {
        my $default;
        
        if (-d('/usr/include/svgalib')) {
            $default = '/usr/include/svgalib';
        } else {
            $default = "default";
        }
        print("Where are the interface headers for it?\n");
        
        my $response = prompt("Svgalib header directory", $default);
        
        if ($response ne "default") {
            $svgalibhdr_dir = $response;
        }
        if (defined($svgalibhdr_dir)) {
            if (!-d($svgalibhdr_dir)) {
                printf("WARNING: No directory named " .
                       "'$svgalibhdr_dir' exists.\n");
            }
        }
    }
    return($svgalib, $svgalibhdr_dir);
}



sub symlink_command() {

    my $retval;

    # Some Windows environments don't have symbolic links (or even a
    # simulation via a "ln" command, but have a "cp" command which works
    # in a pinch.  Some Windows environments have "ln", but it won't do
    # symbolic links.
    
    if (commandExists("ln")) {
        # We assume if Perl can do symbolic links, so can Ln, and vice
        # versa.

        my $symlink_exists = eval { symlink("",""); 1 };
        
        if ($symlink_exists) {
            $retval = "ln -s";
        } else {
            $retval = "ln";
        }
    } elsif (commandExists("cp")) {
        $retval = "cp";
    } else {
        # Well, maybe we just made a mistake.
        $retval = "ln -s";
    }
    return $retval;
}



sub help() {

    print("This is the Netpbm custom configuration program.  \n");
    print("It is not GNU Configure.\n");
    print("\n");
    print("There is one optional argument to this program:  The " .
          "name of the file to use as the basis for the Makefile.config " .
          "file.  Default is 'Makefile.config.in'\n");
    print("\n");
    print("Otherwise, the program is interactive.\n");
}



sub gnuOptimizeOpt($) {
    my ($gccCommandName) = @_;
#-----------------------------------------------------------------------------
#  Compute the -O compiler flag appropriate for a GNU system.  Ordinarily,
#  this is just -O3.  But many popular GNU systems have a broken compiler
#  that causes -O3 to generate incorrect code (symptom: pnmtojpeg --quality=95
#  generates a syntax error message from shhopt).
#-----------------------------------------------------------------------------
# I don't know what are exactly the cases that Gcc is broken.  I know 
# Red Hat 7.1 and 7.2 and Mandrake 8.2, running gcc 2.96.1, commonly have
# the problem.  But it may be limited to a certain subrelease level or
# CPU type or other environment.  People who have reported the problem have
# reported that Gcc 3.0 doesn't have it.  Gcc 2.95.3 doesn't have it.

# Note that automatic inlining happens at -O3 level, but there are some
# subroutines in Netpbm marked for explicit inlining, and we need to disable
# that inlining too, so we must go all the way down to -O0.

    my @gccVerboseResp = `$gccCommandName --verbose 2>&1`;

    my $brokenCompiler;
    
    if (@gccVerboseResp ==2) {
        if ($gccVerboseResp[1] =~ m{gcc version 2.96}) {
            $brokenCompiler = $TRUE;
        } else {
            $brokenCompiler = $FALSE;
        }
    } else {
        $brokenCompiler = $FALSE;
    }

    my $oOpt;

    if ($brokenCompiler) {
        print("You appear to have a broken compiler which would produce \n");
        print("incorrect code if requested to do inline optimization.\n");
        print("Therefore, I am configuring the build to not do inline \n");
        print("optimization.  This will make some Netpbm programs \n");
        print("noticeably slower.  If I am wrong about your compiler, just\n");
        print("edit Makefile.config and change -O0 to -O3 near the bottom.\n");
        print("\n");
        print("The problem is known to exist in the GNU Compiler \n");
        print("release 2.96.  If you upgrade, you will not have this \n");
        print("problem.\n");
        print("---------------------------------------------\n");
        print("\n");
        $oOpt = "-O0";
    } else {
        $oOpt = "-O3";
    }
    return $oOpt;
}



sub findProcessManagement($) {
    my ($dontHaveProcessMgmtR) = @_;
#-----------------------------------------------------------------------------
#  Return $TRUE iff the system does not have <sys/wait.h> in its default
#  search path.
#-----------------------------------------------------------------------------
    my $cflags = testCflags();

    my @cSourceCode = (
                       "#include <sys/wait.h>\n",
                       );
    
    testCompile($cflags, \@cSourceCode, \my $success);

    if (!$success) {
        print("Your system does not appear to have <sys/wait.h> in its " .
              "standard compiler include path.  Therefore, we will build " .
              "Netpbm with some function missing (e.g. the pm_system() " .
              "function in libnetpbm and most of 'pamlookup'\n");
        $$dontHaveProcessMgmtR = $TRUE;
    } else {
        $$dontHaveProcessMgmtR = $FALSE;
    }
}



sub validateLibraries(@) {
    my @libList = @_;
#-----------------------------------------------------------------------------
#  Check each library name in the list @libList for viability.
#-----------------------------------------------------------------------------
    foreach my $libname (@libList) {
        if (defined($libname)) {
            if ($libname =~ m{/} and !-f($libname)) {
                print("WARNING: No regular file named '$libname' exists.\n");
            } elsif (!($libname =~ m{ .* \. (so|a|sa|sl|dll|dylib) $ }x)) {
                print("WARNING: The library name '$libname' does not have " .
                      "a conventional suffix (.so, .a, .dll, etc.)\n");
            }
        }
    }
}



sub warnJpegTiffDependency($$) {
    my ($jpeglib, $tifflib) = @_;

    if (defined($tifflib) && !defined($jpeglib)) {
        print("WARNING: You say you have a Tiff library, " .
              "but no Jpeg library.\n");
        print("Sometimes the Tiff library prerequires the " .
              "Jpeg library.  If \n");
        print("that is the case on your system, you will " .
              "have some links fail with\n");
        print("missing 'jpeg...' symbols.  If so, rerun " .
              "Configure and say you\n");
        print("have no Tiff library either.\n");
        print("\n");
    }
}



sub testCompileJpeglibH($$) {
    my ($cflags, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile to see if we can see jpeglib.h.
#-----------------------------------------------------------------------------
    my @cSourceCode = (
                       "#include <ctype.h>\n",
                       "#include <stdio.h>\n",
                       "#include <jpeglib.h>\n",
                       );
    
    testCompile($cflags, \@cSourceCode, $successR);
}



sub testCompileJpegMarkerStruct($$) {
    my ($cflags, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile to see if struct jpeg_marker_struct is defined in 
#  jpeglib.h.  Assume it is already established that the compiler works
#  and can find jpeglib.h.
#-----------------------------------------------------------------------------
    my @cSourceCode = (
                       "#include <ctype.h>\n",
                       "#include <stdio.h>\n",
                       "#include <jpeglib.h>\n",
                       "struct jpeg_marker_struct test;\n",
                       );

    testCompile($cflags, \@cSourceCode, $successR);
}



sub printMissingHdrWarning($$) {

    my ($name, $hdr_dir) = @_;

    print("WARNING: You said the compile-time part of the $name library " .
          "(the header\n");
    print("files) is in ");

    if (defined($hdr_dir)) {
        print("directory '$hdr_dir', ");
    } else {
        print("the compiler's default search path, ");
    }
    print("but a test compile failed\n");
    print("to confirm that.  If your configuration is exotic, the test " .
          "compile might\n");
    print("just be wrong, but otherwise the Netpbm build will fail.\n");
    print("\n");
    print("To fix this, either install the $name library there \n");
    print("or re-run Configure and answer the question about the $name " .
          "library\n");
    print("differently.\n");
    print("\n");
}



sub printOldJpegWarning() {
    print("WARNING: Your JPEG library appears to be too old for Netpbm.\n");
    print("We base this conclusion on the fact that jpeglib.h apparently\n");
    print("does not define struct jpeg_marker_struct.\n");
    print("If the JPEG library is not Independent Jpeg Group's Version 6b\n");
    print("or better, the Netpbm build will fail when it attempts to build\n");
    print("the parts that use the JPEG library.\n");
    print("\n");
    print("If your configuration is exotic, this test may just be wrong.\n");
    print("Otherwise, either upgrade your JPEG library or re-run Configure\n");
    print("and say you don't have a JPEG library.\n");
    print("\n");
}



sub testJpegHdr($) {

    my ($jpeghdr_dir) = @_;

    if (defined($testCc)) {

        my $generalCflags = testCflags();

        my $jpegIOpt = $jpeghdr_dir ? "-I$jpeghdr_dir" : "";

        testCompileJpeglibH("$generalCflags $jpegIOpt", \my $success);

        if (!$success) {
            print("\n");
            printMissingHdrWarning("JPEG", $jpeghdr_dir);
        } else {
            # We can get to something named jpeglib.h, but maybe it's an old
            # version we can't use.  Check it out.
            testCompileJpegMarkerStruct("$generalCflags $jpegIOpt", 
                                        \my $success);
            if (!$success) {
                print("\n");
                printOldJpegWarning();
            }
        }
    }
}



sub testCompileZlibH($$) {
    my ($cflags, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile to see if we can see zlib.h.
#-----------------------------------------------------------------------------
    my @cSourceCode = (
                       "#include <zlib.h>\n",
                       );
    
    testCompile($cflags, \@cSourceCode, $successR);
}



sub testCompilePngH($$) {
    my ($cflags, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile to see if we can see png.h, assuming we can see
#  zlib.h, which png.h #includes.
#-----------------------------------------------------------------------------
    my @cSourceCode = (
                       "#include <png.h>\n",
                       );
    
    testCompile($cflags, \@cSourceCode, $successR);
}



sub testPngHdr($$) {
#-----------------------------------------------------------------------------
#  Issue a warning if the compiler can't find png.h.
#-----------------------------------------------------------------------------
    my ($pnghdr_dir, $zhdr_dir) = @_;

    if (defined($testCc)) {

        my $generalCflags = testCflags();

        my $zlibIOpt = $zhdr_dir ? "-I$zhdr_dir" : "";

        testCompileZlibH("$generalCflags $zlibIOpt", \my $success);
        if (!$success) {
            print("\n");
            printMissingHdrWarning("Zlib", $zhdr_dir);
        } else {
            my $pngIOpt = $pnghdr_dir ? "-I$pnghdr_dir" : "";

            testCompilePngH("$generalCflags $zlibIOpt $pngIOpt", 
                            \my $success);

            if (!$success) {
                print("\n");
                printMissingHdrWarning("PNG", $pnghdr_dir);
            }
        }
    }
}



sub printBadPngConfigLdflagsWarning($) {
    my ($pngLdFlags) = @_;

    print << 'EOF';
WARNING: 'libpng-config' in this environment (a program in your PATH)
gives instructions that don't work for linking with the PNG library.
Our test link failed.

This indicates Libpng is installed incorrectly on this system.  If so,
your Netpbm build, which uses 'libpng-config', will fail.  But it
might also just be our test that is broken.

EOF

}



sub printBadPngConfigCFlagsWarning($) {
    my ($pngCFlags) = @_;

    print << 'EOF';
WARNING: 'libpng-config' in this environment (a program in your PATH)
gives instructions that don't work for compiling for the PNG library.
Our test compile failed.

This indicates Libpng is installed incorrectly on this system.  If so,
your Netpbm build, which uses 'libpng-config', will fail.  But it
might also just be our test that is broken.

EOF

}



sub testLinkPnglib($$) {
    my ($generalCflags, $pngCflags) = @_;

    my @cSourceCode = (
                       "#include <png.h>\n",
                       "int main() {\n",
                       "png_create_write_struct(0, NULL, NULL, NULL);\n",
                       "}\n",
                       );

    testCompile("$generalCflags $pngCflags", \@cSourceCode, \my $success);
    if (!$success) {
        # Since it won't compile, we can't test the link
    } else {
        my $pngLdflags = qx{libpng-config --ldflags};
        chomp($pngLdflags);
        
        testCompileLink("$generalCflags $pngCflags $pngLdflags",
                        \@cSourceCode, \my $success);
        
        if (!$success) {
            printBadPngConfigLdflagsWarning($pngLdflags);
        }
    }
}



sub testLibpngConfig() {
#-----------------------------------------------------------------------------
#  Issue a warning if the instructions 'libpng-config' give for compiling
#  with Libpng don't work.
#-----------------------------------------------------------------------------
    my $generalCflags = testCflags();

    my $pngCflags = qx{libpng-config --cflags};
    chomp($pngCflags);

    testCompilePngH("$generalCflags $pngCflags", \my $success);

    if (!$success) {
        printBadPngConfigCflagsWarning($pngCflags);
    } else {
        testLinkPnglib($generalCflags, $pngCflags);
    }
}



sub testCompileXmlreaderH($$) {
    my ($cflags, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile to see if we can see xmlreader.h.
#-----------------------------------------------------------------------------
    my @cSourceCode = (
                       "#include <libxml/xmlreader.h>\n",
                       );
    
    testCompile($cflags, \@cSourceCode, $successR);
}



sub printBadXml2CFlagsWarning($) {
    my ($xml2CFlags) = @_;

    print << 'EOF';

WARNING: 'xml2-config' in this environment (a program in your PATH)
gives instructions that don't work for compiling for the Libxml2 library.
Our test compile failed.

This indicates Libxml2 is installed incorrectly on this system.  If so,
your Netpbm build, which uses 'xml2-config', will fail.  But it
might also just be our test that is broken.

EOF

}



sub testCompileXmlReaderTypes($$) {
    my ($cflags, $successR) = @_;
#-----------------------------------------------------------------------------
#  Do a test compile to see if xmlreader.h defines xmlReaderTypes,
#  assuming we can compile with xmlreader.h in general.
#-----------------------------------------------------------------------------
    my @cSourceCode = (
                       "#include <libxml/xmlreader.h>\n",
                       "xmlReaderTypes dummy;\n",
                       );
    
    testCompile($cflags, \@cSourceCode, $successR);
}



sub printBadXml2XmlReaderTypesWarning($) {

    print << 'EOF';

WARNING: Your libxml2 interface header file does not define the type
'xmlReaderTypes', which Netpbm needs.  In order to build Netpbm successfully,
you must install a more recent version of Libxml2.

EOF
}



sub printNoLibxml2Warning() {

    print << 'EOF';

WARNING: You appear not to have Libxml2 installed ('xml2-config' does not
exist in your program search PATH).  If this is the case at build time,
the build will skip building 'svtgtopam'.

EOF
}



sub testLibxml2Hdr() {
#-----------------------------------------------------------------------------
#  Issue a warning if the instructions 'xml2-config' give for compiling
#  with Libxml2 don't work.  In particular, note whether they get us a
#  modern enough Libxml2 to have the 'xmlReaderTypes' type.
#-----------------------------------------------------------------------------
    if (commandExists('xml2-config')) {
        my $generalCflags = testCflags();

        my $xml2Cflags = qx{xml2-config --cflags};
        chomp($xml2Cflags);

        testCompileXmlreaderH("$generalCflags $xml2Cflags", \my $success);

        if (!$success) {
            printBadXml2CflagsWarning($xml2Cflags);
        } else {
            testCompileXmlReaderTypes("$generalCflags $xml2Cflags",
                                      \my $success);

            if (!$success) {
                printMissingXmlReaderTypesWarning();
            }
        }
    } else {
        printNoLibxml2Warning();
    }
}



sub testConfiguration($$$$$$) {

    my ($jpeglib, $jpeghdr_dir,
        $pnglib, $pnghdr_dir, $zlib, $zhdr_dir) = @_;

    if (defined($jpeglib)) {
        testJpegHdr($jpeghdr_dir);
    }
    if (defined($pnglib) && defined($zlib)) {
        testPngHdr($pnghdr_dir, $zhdr_dir);
    } elsif (commandExists('libpng-config')) {
        testLibpngConfig();
    }
    testLibxml2Hdr();

    # TODO: We ought to validate other libraries too.  But it's not
    # that important, because in the vast majority of cases where the
    # user incorrectly identifies any library, it affects all the
    # libraries and if the user can get a handle on the JPEG library
    # problem, he will also solve problems with any other library.
}



#******************************************************************************
#
#  MAINLINE
#
#*****************************************************************************

autoFlushStdout();

my $configInPathArg;
if (@ARGV > 0) {
    if ($ARGV[0] =~ "^-") {
        if ($ARGV[0] eq "--help") {
            help();
            exit(0);
        } else {
            die("Unrecognized option: $ARGV[0]");
        }
    } 
    $configInPathArg = $ARGV[0];
}

if (stat("Makefile.config")) {
    print("Discard existing Makefile.config?\n");
    print("Y or N (N) ==> ");

    my $answer = <STDIN>;
    if (!defined($answer)) {
        die("\nEnd of file on Standard Input");
    }
    chomp($answer);
    if (uc($answer) ne "Y") {
        print("Aborting at user request.\n");
        exit(1);
    }
}

print("\n");

displayIntroduction();

my ($platform, $subplatform) = getPlatform();

print("\n");

if ($platform eq "NONE") {
    print("You will have to construct Makefile.config manually.  To do \n");
    print("this, copy Makefile.config.in as Makefile.config, and then \n");
    print("edit it.  Follow the instructions and examples in the file. \n");
    print("Please report your results to the Netpbm maintainer so he \n");
    print("can improve the configure program. \n");
    exit;
}

getCompiler($platform, \my $compiler);
getLinker($platform, $compiler, \my $baseLinker, \my $linkViaCompiler);

chooseTestCompiler($compiler, \$testCc);

my $netpbmlib_runtime_path;
    # Undefined if the default from Makefile.config.in is acceptable.

if ($platform eq "SOLARIS" or $platform eq "IRIX" or
    $platform eq "DARWIN" or $platform eq "NETBSD" or
    $platform eq "AMIGA") {
    print("Where will the Netpbm shared library reside once installed?\n");
    print("Enter 'default' if it will reside somewhere that the shared\n");
    print("library loader will find it automatically.  Otherwise, \n");
    print("this directory will get built into the Netpbm programs.\n");
    print("\n");

    my $default = "default";
    my $response = prompt("Netpbm shared library directory", $default);

    if ($response eq "default") {
        $netpbmlib_runtime_path = "";
    } else {
        $netpbmlib_runtime_path = $response;
    }
}

my $default_target;

print("Do you want a regular build or a merge build?\n");
print("If you don't know what this means, " .
      "take the default or see doc/INSTALL\n");
print("\n");

{
    my $default = "regular";
    my $response = prompt("regular or merge", $default);
    
    if ($response eq "regular") {
        $default_target = "nonmerge";
    } elsif ($response eq "merge") {
        $default_target = "merge";
    } else {
        print("'$response' isn't one of the choices.  \n" .
              "You must choose 'regular' or 'merge'.\n");
        exit 12;
    }
}

print("\n");

getLibTypes($platform, $subplatform, $default_target,
            \my $netpbmlibtype, \my $netpbmlibsuffix, \my $shlibprefixlist,
            \my $willBuildShared, \my $staticlib_too);


getInttypes(\my $inttypesHeaderFile);

getInt64($inttypesHeaderFile, \my $haveInt64);

findProcessManagement(\my $dontHaveProcessMgmt);

#******************************************************************************
#
#  FIND THE PREREQUISITE LIBRARIES
#
#*****************************************************************************

print("\n\n");
print("The following questions concern the subroutine libraries that are " .
      "Netpbm\n");
print("prerequisites.  Every library has a compile-time part (header " .
      "files)\n");
print("and a link-time part.  In the case of a shared library, these are " .
      "both\n");
print("part of the \"development\" component of the library, which may be " .
      "separately\n");
print("installable from the runtime shared library.  For each library, you " .
      "must\n");
print("give the filename of the link library.  If it is not in your " .
      "linker's\n");
print("default search path, give the absolute pathname of the file.  In " .
      "addition,\n");
print("you will be asked for the directory in which the library's interface " .
      "headers\n");
print("reside, and you can respond 'default' if they are in your compiler's " .
      "default\n");
print("search path.\n");
print("\n");
print("If you don't have the library on your system, you can enter 'none' " .
      "as the\n");
print("library filename and the builder will skip any part that requires " .
      "that ");
print("library.\n");
print("\n");

my ($jpeglib, $jpeghdr_dir) = getJpegLibrary($platform);
print("\n");
my ($tifflib, $tiffhdr_dir) = getTiffLibrary($platform, $jpeghdr_dir);
print("\n");
my ($pnglib, $pnghdr_dir)   = getPngLibrary($platform, 
                                            $tiffhdr_dir, $jpeghdr_dir);
print("\n");
my ($zlib, $zhdr_dir)       = getZLibrary($platform, 
                                          $pnghdr_dir,
                                          $tiffhdr_dir,
                                          $jpeghdr_dir);
print("\n");
my ($x11lib, $x11hdr_dir) = getX11Library($platform); 

print("\n");
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.


#******************************************************************************
#
#  CONFIGURE DOCUMENTATION
#
#*****************************************************************************

print("What URL will you use for the main Netpbm documentation page?\n");
print("This information does not get built into any programs or libraries.\n");
print("It does not make anything actually install that web page.\n");
print("It is just for including in legacy man pages.\n");
print("\n");

my $default = "http://netpbm.sourceforge.net/doc/";

my $netpbm_docurl = prompt("Documentation URL", $default);

print("\n");




#******************************************************************************
#
#  VALIDATE THE CONFIGURATION USER HAS SELECTED
#
#*****************************************************************************

validateLibraries($jpeglib, $tifflib, $pnglib, $zlib);

warnJpegTiffDependency($jpeglib, $tifflib);

testConfiguration($jpeglib, $jpeghdr_dir,
                  $pnglib, $pnghdr_dir,
                  $zlib, $zhdr_dir,
                  );

#******************************************************************************
#
#  FIND THE NETPBM SOURCE TREE AND INITIALIZE BUILD TREE
#
#*****************************************************************************

my $defaultConfigInPath;

if (-f("GNUmakefile")) {
    # He's apparently running us in the source tree or an already set up
    # build directory.
    $defaultConfigInPath = "Makefile.config.in";
} else {
    my $srcdir;
    my $done;

    $done = $FALSE;
    while (!$done) {
        print("Where is the Netpbm source code?\n");

        $srcdir = prompt("Netpbm source directory", 
                         abs_path(dirname($0) . "/.."));

        if (-f("$srcdir/GNUmakefile")) {
            $done = $TRUE;
        } else {
            print("That doesn't appear to contain Netpbm source code.\n");
            print("There is no file named 'GNUmakefile' in it.\n");
            print("\n");
        }    
    }
    unlink("GNUmakefile");
    symlink("$srcdir/GNUmakefile", "GNUmakefile");
    unlink("Makefile");
    symlink("$srcdir/Makefile", "Makefile");

    open(SRCDIR, ">Makefile.srcdir");
    print(SRCDIR "SRCDIR = $srcdir\n");
    close(SRCDIR);
    
    $defaultConfigInPath = "$srcdir/Makefile.config.in";
}

sub makeCompilerGcc($) {
    my ($Makefile_configR) = @_;
    my $compileCommand = 'gcc';
    push(@{$Makefile_configR}, "CC = $compileCommand\n");
    push(@{$Makefile_configR}, gnuCflags($compileCommand));
}


#******************************************************************************
#
#  BUILD Makefile.config
#
#*****************************************************************************

sub gnuCflags($) {
    my ($gccCommandName) = @_;

    return("CFLAGS = " . gnuOptimizeOpt($gccCommandName) . " -ffast-math " .
           " -pedantic -fno-common " . 
           "-Wall -Wno-uninitialized -Wmissing-declarations -Wimplicit " .
           "-Wwrite-strings -Wmissing-prototypes -Wundef\n");
}

my @Makefile_config;
    # This is the complete Makefile.config contents.  We construct it here
    # and ultimately write the whole thing out as Makefile.config.

# First, we just read the 'Makefile.config.in' in

my $configInPath;
if (defined($configInPathArg)) {
    $configInPath = $configInPathArg;
} else {
    $configInPath = $defaultConfigInPath;
}
open (CONFIG_IN,"<$configInPath") or
    die("Unable to open file '$configInPath' for input.");

@Makefile_config = <CONFIG_IN>;

unshift(@Makefile_config, 
        "####This file was automatically created by 'configure.'\n",
        "####Many variables are set twice -- a generic setting, then \n",
        "####a system-specific override at the bottom of the file.\n",
        "####\n");

close(CONFIG_IN);

# Now, add the variable settings that override the default settings that are
# done by the Makefile.config.in contents.

push(@Makefile_config, "\n\n\n\n");
push(@Makefile_config, "####Lines above were copied from Makefile.config.in " .
     "by 'configure'.\n");
push(@Makefile_config, "####Lines below were added by 'configure' based on " .
     "the $platform platform.\n");
if (defined($subplatform)) {
    push(@Makefile_config, "####subplatform '$subplatform'\n");
}

push(@Makefile_config, "DEFAULT_TARGET = $default_target\n");

push(@Makefile_config, "NETPBMLIBTYPE=$netpbmlibtype\n");
push(@Makefile_config, "NETPBMLIBSUFFIX=$netpbmlibsuffix\n");
if (defined($shlibprefixlist)) {
    push(@Makefile_config, "SHLIBPREFIXLIST=$shlibprefixlist\n");
}
push(@Makefile_config, "STATICLIB_TOO=$staticlib_too\n");

if (defined($netpbmlib_runtime_path)) {
    push(@Makefile_config, "NETPBMLIB_RUNTIME_PATH=$netpbmlib_runtime_path\n");
}

if ($platform eq "GNU") {
    my $compileCommand;
    if (!commandExists("cc") && commandExists("gcc")) {
        $compileCommand = "gcc";
        push(@Makefile_config, "CC = $compileCommand\n");
    } else {
        $compileCommand = "cc";
    }
    push(@Makefile_config, gnuCflags($compileCommand));
# The merged programs have a main_XXX subroutine instead of main(),
# which would cause a warning with -Wmissing-declarations or 
# -Wmissing-prototypes.
    push(@Makefile_config, "CFLAGS_MERGE = " .
         "-Wno-missing-declarations -Wno-missing-prototypes\n");
    push(@Makefile_config, "LDRELOC = ld --reloc\n");
    push(@Makefile_config, "LINKER_CAN_DO_EXPLICIT_LIBRARY=Y\n");
} elsif ($platform eq "SOLARIS") {
    push(@Makefile_config, 'LDSHLIB = -Wl,-Bdynamic,-G,-h,$(SONAME)', "\n");

    push(@Makefile_config, 'NEED_RUNTIME_PATH = Y', "\n");
    if ($compiler eq "cc") {
        push(@Makefile_config, "CFLAGS = -O\n");
        push(@Makefile_config, "CFLAGS_SHLIB = -Kpic\n");
    } else {
        makeCompilerGcc(\@Makefile_config);
    }
    # Before Netpbm 10.20 (January 2004), we set this to -R for 
    # $compiler == cc and -rpath otherwise.  But now we know that the GNU
    # compiler can also invoke a linker that needs -R, so we're more flexible.
    if ($baseLinker eq "GNU") {
        push(@Makefile_config, "RPATHOPTNAME = -rpath\n");
    } else {
        push(@Makefile_config, "RPATHOPTNAME = -R\n");
    }
    push(@Makefile_config, "NETWORKLD = -lsocket -lnsl\n");
} elsif ($platform eq "HP-UX") {
    if ($compiler eq "gcc") {
        makeCompilerGcc(\@Makefile_config);
        push(@Makefile_config, "CFLAGS += -fPIC\n");
        push(@Makefile_config, "LDSHLIB = -shared -fPIC\n");
        push(@Makefile_config, 'LDFLAGS += -Wl,+b,/usr/pubsw/lib', "\n");
    } else {
        # We don't know what to do here.  We used to (before 10.20) just
        # just assume the compiler was gcc.  We know that the gcc stuff
        # above does NOT work for HP native compiler.
    }
} elsif ($platform eq "AIX") {
    push(@Makefile_config, 'LDFLAGS = -L /usr/pubsw/lib', "\n");
    if ($compiler eq "cc") {
        # Yes, the -L option implies the runtime as well as linktime library
        # search path.  There's no way to specify runtime path independently.
        push(@Makefile_config, "RPATHOPTNAME = -L\n");
        push(@Makefile_config, "LDSHLIB = -qmkshrobj\n");
    } else {
        makeCompilerGcc(\@Makefile_config);
        push(@Makefile_config, "LDSHLIB = -shared\n");
    }
} elsif ($platform eq "TRU64") {
#    push(@Makefile_config, "INSTALL = installbsd\n");
    if ($compiler eq "cc") {
        push(@Makefile_config, 'CFLAGS = -O2 -std1', "\n");
        push(@Makefile_config, "LDFLAGS = -call_shared -oldstyle_liblookup " .
             "-L/usr/local/lib\n");
        push(@Makefile_config, "LDSHLIB = -shared -expect_unresolved \"*\"\n");
    } else {
        # We've never tested this.  This is just here to give a user a 
        # headstart on submitting to us the necessary information.  2002.07.04.
        push(@Makefile_config, "CC = gcc\n");
        push(@Makefile_config, 'CFLAGS = -O3', "\n");
        push(@Makefile_config, "LDSHLIB = -shared\n");
    }
    # Between May 2000 and July 2003, we had -DLONG_32 in these options.
    # We took it out because it generated bad code for a TRU64 user in
    # July 2003 whose system has 64 bit long and 32 bit int.  It affects
    # only Ppmtompeg and it isn't clear that using long instead of int is
    # ever right anyway.

    push(@Makefile_config, "OMIT_NETWORK = y\n");
    push(@Makefile_config, "LINKER_CAN_DO_EXPLICIT_LIBRARY=Y\n");
} elsif ($platform eq "IRIX") {
#    push(@Makefile_config, "INSTALL = install\n");
    push(@Makefile_config, "MANPAGE_FORMAT = cat\n");
    push(@Makefile_config, "RANLIB = true\n");
    push(@Makefile_config, "CFLAGS = -n32 -O3 -fullwarn\n");
    push(@Makefile_config, "LDFLAGS = -n32\n");
    push(@Makefile_config, "LDSHLIB = -shared -n32\n");
} elsif ($platform eq "WINDOWS") {
    if ($subplatform eq "cygwin") {
        makeCompilerGcc(\@Makefile_config);
    }
    push(@Makefile_config, "EXE = .exe\n");
    push(@Makefile_config, "OMIT_NETWORK = y\n");
#    # Though it may not have the link as "ginstall", "install" in a Windows
#    # Unix environment is usually GNU install.
#    my $ginstall_result = `ginstall --version 2>/dev/null`;
#    if (!$ginstall_result) {
#        # System doesn't have 'ginstall', so use 'install' instead.
#        push(@Makefile_config, "INSTALL = install\n");
#    }
    push(@Makefile_config, 'SYMLINK = ', symlink_command(), "\n");
    push(@Makefile_config, 'DLLVER=$(NETPBM_MAJOR_RELEASE)', "\n");
    push(@Makefile_config, "LDSHLIB = " . 
         '-shared -Wl,--image-base=0x10000000 -Wl,--enable-auto-import', "\n");
} elsif ($platform eq "BEOS") {
    push(@Makefile_config, "LDSHLIB = -nostart\n");
} elsif ($platform eq "NETBSD") {
    push(@Makefile_config, 'CFLAGS_SHLIB = -fpic', "\n");
} elsif ($platform eq "OPENBSD") {
    # vedge@vedge.com.ar says on 2001.04.29 that there are a ton of 
    # undefined symbols in the Fiasco stuff on OpenBSD.  So we'll just
    # cut it out of the build until someone feels like fixing it.
    push(@Makefile_config, "BUILD_FIASCO = N\n");
} elsif ($platform eq "FREEBSD") {
} elsif ($platform eq "AMIGA") {
    push(@Makefile_config, "CFLAGS = -m68020-60 -ffast-math -mstackextend\n");
} elsif ($platform eq "UNIXWARE") {
    # Nothing to do.
} elsif ($platform eq "SCO") {
    # Got this from "John H. DuBois III" <spcecdt@armory.com> 2002.09.27:
    push(@Makefile_config, "RANLIB = true\n");
    if ($compiler eq "cc") {
        push(@Makefile_config, "CFLAGS = -O\n");
        push(@Makefile_config, "CFLAGS_SHLIB = -O -K pic\n");
        push(@Makefile_config, "LD_SHLIB = -G\n");
        push(@Makefile_config, "SHLIB_CLIB =\n");
    } else {
        makeCompilerGcc(\@Makefile_config);
    }
    push(@Makefile_config, "CFLAGS_SHLIB = -fPIC\n");
    push(@Makefile_config, "LDSHLIB = -shared\n"); 
    push(@Makefile_config, "NETWORKLD = -lsocket -lresolve\n");
} elsif ($platform eq "DARWIN") {
    push(@Makefile_config, "CC = cc -no-cpp-precomp\n");
    push(@Makefile_config, 'CFLAGS_SHLIB = -fno-common', "\n");

    my $installNameOpt;
    if ($netpbmlib_runtime_path eq '') {
        $installNameOpt = '';
    } else {
        $installNameOpt  =
            '-install_name $(NETPBMLIB_RUNTIME_PATH)/libnetpbm.$(MAJ).dylib';
    }
    push(@Makefile_config, "LDSHLIB = -dynamiclib $installNameOpt\n");
#    push(@Makefile_config, "INSTALL = install\n");
} else {
    die ("Internal error: invalid value for \$platform: '$platform'\n");
}

if ($linkViaCompiler) {
    push(@Makefile_config, "LINKERISCOMPILER = Y\n");
}

my $flex_result = `flex --version`;
if (!$flex_result) {
    # System doesn't have 'flex'.  Maybe 'lex' will work.  See the
    # make rules for Thinkjettopbm for information on our experiences
    # with Lexes besides Flex.

    my $systemRc = system('lex </dev/null &>/dev/null');

    if ($systemRc >> 8 == 127) {
        print("\n");
        print("You do not appear to have the 'flex' or 'lex' pattern \n");
        print("matcher generator on your system, so we will not build \n");
        print("programs that need it (Thinkjettopbm)\n");
        
        print("\n");
        print("Press ENTER to continue.\n");
        my $key = <STDIN>;
        print("\n");

        push(@Makefile_config, "LEX=\n");
    } else {
        print("\n");
        print("Using 'lex' as the pattern matcher generator, " .
              "since we cannot\n");
        print("find 'flex' on your system.\n");
        print("\n");

        push(@Makefile_config, "LEX = lex\n"); 
    }
}

if (defined($tiffhdr_dir)) {
    push(@Makefile_config, "TIFFHDR_DIR = $tiffhdr_dir\n");
}
if (defined($tifflib)) {
    push(@Makefile_config, "TIFFLIB = $tifflib\n");
}

if (defined($jpeghdr_dir)) {
    push(@Makefile_config, "JPEGHDR_DIR = $jpeghdr_dir\n");
}
if (defined($jpeglib)) {
    push(@Makefile_config, "JPEGLIB = $jpeglib\n");
}

if (defined($pnghdr_dir)) {
    push(@Makefile_config, "PNGHDR_DIR = $pnghdr_dir\n");
}
if (defined($pnglib)) {
    push(@Makefile_config, "PNGLIB = $pnglib\n");
}

if (defined($zhdr_dir)) {
    push(@Makefile_config, "ZHDR_DIR = $zhdr_dir\n");
}
if (defined($zlib)) {
    push(@Makefile_config, "ZLIB = $zlib\n");
}

if (defined($x11hdr_dir)) {
    push(@Makefile_config, "X11HDR_DIR = $x11hdr_dir\n");
}
if (defined($x11lib)) {
    push(@Makefile_config, "X11LIB = $x11lib\n");
}

if (defined($linuxsvgahdr_dir)) {
    push(@Makefile_config, "LINUXSVGAHDR_DIR = $linuxsvgahdr_dir\n");
}
if (defined($linuxsvgalib)) {
    push(@Makefile_config, "LINUXSVGALIB = $linuxsvgalib\n");
}

if (defined($netpbm_docurl)) {
    push(@Makefile_config, "NETPBM_DOCURL = $netpbm_docurl\n");
}

if ($inttypesHeaderFile ne '<inttypes.h>') {
    push(@Makefile_config, "INTTYPES_H = $inttypesHeaderFile\n");
}

if ($haveInt64 ne 'Y') {
    push(@Makefile_config, "HAVE_INT64 = $haveInt64\n");
}

if ($dontHaveProcessMgmt) {
    push(@Makefile_config, "DONT_HAVE_PROCESS_MGMT = Y\n");
}

#******************************************************************************
#
#  WRITE OUT THE FILE
#
#*****************************************************************************

open(MAKEFILE_CONFIG, ">Makefile.config") or
    die("Unable to open Makefile.config for writing in the current " .
        "directory.");

print MAKEFILE_CONFIG @Makefile_config;

close(MAKEFILE_CONFIG) or
    die("Error:  Close of Makefile.config failed.\n");

print("\n");
print("We have created the file 'Makefile.config'.  You may want to look \n");
print("at it and edit it to your requirements and taste before doing the \n");
print("make.\n");
print("\n");

print("Now you may proceed with 'make'\n");
print("\n");


exit 0;          
