#!/bin/sh
# configure:
#    Makefile configuration script for Scid.
#
# This program tries to determine system-specific details needed
# for compiling Scid (such as the version of Tcl/Tk you have
# installed, and where to find the Tcl/Tk header and library 
# files), and creates the file "Makefile".


# Try to find the most recent version of Tcl/Tk 8.x that is installed,
# by searching the PATH directories for tclsh8.3, tclsh83, etc.  If no
# tclsh program with a version number in the file name is found, the
# default program to execute is just tclsh.
# The backslashes at the end of these lines are needed: \
tclsh=tclsh8.5;

# This shell script code did not work for me in Linux so it is
# commented out for now; the configure script will just run in
# tclsh even if there is a more recent version.
## for tclver in 80 8.0 81 8.1 82 8.2 83 8.3 84 8.4 85 8.5; do \
##   IFS=:; \
##  for dir in $PATH; do \
##    if [ -x $dir/tclsh$tclver ]; then tclsh=$dir/tclsh$tclver; fi; \
##  done; \
## done

# Now execute this script using the best tclsh version found:
# The backslash at the end of this line is needed: \
exec $tclsh "$0" ${1+"$@"}


# Default values for Makefile settings:
#
set var(BINDIR) /usr/local/bin
set var(COMPILE) g++
set var(CC) gcc
set var(DEBUG) #-DASSERTIONS
set var(LANGUAGES) [list \
  tcl/lang/catalan.tcl \
  tcl/lang/czech.tcl \
  tcl/lang/deutsch.tcl \
  tcl/lang/francais.tcl \
  tcl/lang/greek.tcl \
  tcl/lang/hungary.tcl \
  tcl/lang/italian.tcl \
  tcl/lang/nederlan.tcl \
  tcl/lang/norsk.tcl \
  tcl/lang/polish.tcl \
  tcl/lang/portbr.tcl \
  tcl/lang/russian.tcl \
  tcl/lang/serbian.tcl \
  tcl/lang/spanish.tcl \
  tcl/lang/suomi.tcl \
  tcl/lang/swedish.tcl \
  ]
set var(LINK) g++
set var(OBJS) {$(SCIDOBJS)}
#TODO: Write a more portable script to detect c++11 support
set var(OPTIMIZE) {-O3 -fno-rtti -fno-exceptions -std=c++0x -pthread}
if { [catch { exec echo "int main() {}" | g++ -std=c++0x -pthread -x c++ - }] } {
  set var(OPTIMIZE) {-O3 -fno-rtti -fno-exceptions}
}
set var(PROFILE) {}
set var(SCIDFLAGS) {}
set var(SHAREDIR) /usr/local/share/scid
set var(TB) {-DSCID_USE_TB -DT41_INCLUDE}
set var(TCL_VERSION) $tcl_version
set var(WARNINGS) -Wall
set var(ZLIB) -lz
set var(MAKEFILE) Makefile.conf

set defaultVar(TCL_INCLUDE) {-I/usr/include}
set defaultVar(TCL_LIBRARY) {-L/usr/lib -ltcl$(TCL_VERSION) -ldl}
set defaultVar(TK_LIBRARY) \
    {$(TCL_LIBRARY) -ltk$(TCL_VERSION) -L/usr/X11R6/lib -lX11}


# findDir:
#    Returns the first directory in the list "path" that contains a
#    readable file matching the wildcard pattern "f".
#    If exp is provided, the directory of the first such file that also
#    has a line containing the regular expression "exp" is returned. If
#    none of the found files contains the expression, the first file
#    found is returned.
#
proc findDir {f path {exp ""}} {
    set best ""
    foreach dir $path {
        set p [file join $dir $f]
        if {![catch {glob $p}]} {
          if {$best == ""} { set best $p }
            if {$exp != ""} {
              if {[catch {exec grep -c $exp $p}] == 0} { return $dir } else {
                # puts "$p skipped, not right version"
              }
            } else {
                return $dir 
            }
        }
    }
    return $best
}

# findTclTkPathsDarwin:
#    Set-up paths using frameworks. Since frameworks are quite
#    different, the UNIX search logic is not sharable:
proc findTclTkPathsAqua {} {
    global var
    set frameworkPaths "\
        [ file nativename ~/Library/Frameworks ] \
        /Library/Frameworks \
        /System/Library/Frameworks \
    "
    set fw_path ""
    # Find the path to the Tcl and Tk frameworks:
    foreach F $frameworkPaths {
        set both 1
        foreach fw {"Tcl" "Tk"} {
            # Both Tcl.framework and Tk.framework must be present:
            if {! [file exists "$F/$fw.framework/Versions/$var(TCL_VERSION)"]} {
                set both 0
                break
            }
        }
        if {$both == 1} {
            # $F has both frameworks, continue:
            set fw_path $F
            break
        }
    }
    if {$both == 0} {
        # Couldn't find Tcl and Tk frameworks, keep searching the "unix" way:
        return 0
    }
    if {! [info exists var(TCL_INCLUDE)]} {
        set var(TCL_INCLUDE) "-F$fw_path/Tcl.framework -F$fw_path/Tk.framework"
    }
    if {! [info exists var(TCL_LIBRARY)]} {
        set var(TCL_LIBRARY) {-framework Tcl -ldl}
    }
    if {! [info exists var(TK_LIBRARY)]} {
        set var(TK_LIBRARY) {$(TCL_LIBRARY) -framework Tk}
        #if {! [file exists "$fw_path/Tk.framework/Headers/X11"]} {
        #   append var(TK_LIBRARY) " -L/usr/X11R6/lib -lX11"
        #}
    }
    puts "    Location of Tcl/Tk frameworks: $fw_path"
    return 1
}

# findTclTkPaths:
#    Finds all details of the Tcl/Tk installation.
#    Returns 1 on success, 0 on failure.
#
proc findTclTkPaths {} {
    global tclv tclv_nodot var
    set success 1
    array set opt {}
    if {"$::tcl_platform(os)" == "Darwin" && [findTclTkPathsAqua]} {
        # Frameworks found, stop looking for paths:
        return 1
    }

    # headerPath: List of possible locations for tcl.h and tk.h
    set headerPath {
        /usr/include
        /usr/local/tcl/include
        /usr/local/include
        /usr/X11/include
        /usr/X11R6/include
        /usr/local/X11/include
        /opt/tcltk/include
        /usr/X11R/include
    }
    lappend headerPath "/usr/local/include/tcl${tclv}"
    lappend headerPath "/usr/local/include/tk${tclv}"
    lappend headerPath "/usr/local/include/tcl${tclv_nodot}"
    lappend headerPath "/usr/local/include/tk${tclv_nodot}"
    lappend headerPath "/usr/include/tcl${tclv}"
    lappend headerPath "/usr/include/tk${tclv}"
    lappend headerPath "/usr/include/tcl${tclv_nodot}"
    lappend headerPath "/usr/include/tk${tclv_nodot}"

    # libraryPath: List of possible locations of Tcl/Tk library.
    set libraryPath {
        /usr/lib
        /usr/lib64
        /usr/local/tcl/lib
        /usr/local/lib
        /usr/X11R6/lib
        /opt/tcltk/lib
    }
    lappend libraryPath "/usr/lib/tcl${tclv}"
    lappend libraryPath "/usr/lib/tk${tclv}"
    lappend libraryPath "/usr/lib/tcl${tclv_nodot}"
    lappend libraryPath "/usr/lib/tk${tclv_nodot}"

    # Try to add tcl_library and auto_path values to libraryPath,
    # in case the user has a non-standard Tcl/Tk library location:

    if {[info exists ::tcl_library]} {
        lappend headerPath \
            [file join [file dirname [file dirname $::tcl_library]] include]
        lappend libraryPath [file dirname $::tcl_library]
        lappend libraryPath $::tcl_library
    }
    if {[info exists ::auto_path]} {
        foreach name $::auto_path {
            lappend libraryPath $name
        }
    }

    # x11Path: List of common locations of the X11 library files.
    set x11Path {
        /usr/lib
        /usr/X11/lib
        /usr/X11R6/lib
        /usr/local/X11/lib
        /usr/local/X11R6/lib
        /usr/X/lib
        /usr/local/X/lib
        /usr/openwin/lib
        /usr/lib/x86_64-linux-gnu
    }

    if {! [info exists var(TCL_INCLUDE)]} {
        puts -nonewline {    Location of "tcl.h": }
        set opt(tcl_h) [findDir "tcl.h" $headerPath "TCL_VERSION.*$tclv"]
        if {$opt(tcl_h) == ""} {
            puts "not found"
            set success 0
        } else {
            puts $opt(tcl_h)
        }

        puts -nonewline {    Location of "tk.h": }
        set opt(tk_h) [findDir "tk.h" $headerPath "TK_VERSION.*$tclv"]
        if {$opt(tk_h) == ""} {
            puts "not found"
            set success 0
        } else {
            puts $opt(tk_h)
        }
    }

    set opt(tcl_lib) ""
    set opt(tk_lib) ""

    if {! [info exists var(TCL_LIBRARY)]} {
        puts -nonewline "    Location of Tcl $tclv library: "
        set opt(tcl_lib) [findDir "libtcl${tclv}.*" $libraryPath]
        if {$opt(tcl_lib) == ""} {
            set opt(tcl_lib) [findDir "libtcl${tclv_nodot}.*" $libraryPath]
            if {$opt(tcl_lib) == ""} {
                puts "not found"
                set success 0
            } else {
                set opt(tcl_lib_file) "tcl${tclv_nodot}"
                puts $opt(tcl_lib)
            }
        } else {
            set opt(tcl_lib_file) "tcl\$(TCL_VERSION)"
            puts $opt(tcl_lib)
        }
    }

    if {! [info exists var(TK_LIBRARY)]} {
        puts -nonewline "    Location of Tk $tclv library: "
        set opt(tk_lib) [findDir "libtk${tclv}.*" $libraryPath]
        if {$opt(tk_lib) == ""} {
            set opt(tk_lib) [findDir "libtk${tclv_nodot}.*" $libraryPath]
            if {$opt(tk_lib) == ""} {
                puts "not found"
                set success 0
            } else {
                set opt(tk_lib_file) "tk${tclv_nodot}"
                puts $opt(tk_lib)
            }
        } else {
            set opt(tk_lib_file) "tk\$(TCL_VERSION)"
            puts $opt(tk_lib)
        }

        puts -nonewline {    Location of X11 library: }
        set opt(x11_lib) [findDir "libX11*" $x11Path]
        if {$opt(x11_lib) == ""} {
            puts "not found"
            set success 0
        } else {
            puts $opt(x11_lib)
        }
    }

    # If all files were found, assemble the TCL_INCLUDE, TCL_LIBRARY
    # and TK_LIBRARY settings:

    if {$success} {
        if {! [info exists var(TCL_INCLUDE)]} {
            set var(TCL_INCLUDE) "-I$opt(tcl_h)"
            if {$opt(tcl_h) != $opt(tk_h)} {
                append var(TCL_INCLUDE) " -I$opt(tk_h)"
            }
        }
        if {! [info exists var(TCL_LIBRARY)]} {
            set var(TCL_LIBRARY) "-L$opt(tcl_lib) -l$opt(tcl_lib_file) -ldl"
        }
        if {! [info exists var(TK_LIBRARY)]} {
            set var(TK_LIBRARY) {$(TCL_LIBRARY)}
            if {$opt(tk_lib) != $opt(tcl_lib)} {
                append var(TK_LIBRARY) " -L$opt(tk_lib)"
            }
            append var(TK_LIBRARY) " -l$opt(tk_lib_file)"
            if {$opt(x11_lib) != $opt(tcl_lib) && $opt(x11_lib) != $opt(tk_lib)} {
                append var(TK_LIBRARY) " -L$opt(x11_lib)"
            }
            append var(TK_LIBRARY) " -lX11"
        }
    }
    return $success
}


# testzlib_sh:
#    Script used to test if the system has zlib installed.
#
set testzlib {#!/bin/sh
CC=gcc
cat <<EOF > testzlib.c
#include <zlib.h>
int main()
{
    z_streamp z;
    deflateInit(z, 0);
    return 0;
}
EOF

$CC -o testzlib testzlib.c -lz
if [ -f testzlib ]; then
    exit 0
else
    exit 1
fi
}

# systemHasZlib:
#    Determines if the system has zlib installed. If not, the Zlib
#    version that comes with Scid will be used.
#
proc systemHasZlib {} {
    set systemHasZlib 0
    flush stdout
    if {[catch {open testzlib.sh w} f]} { return 0 }
    puts $f $::testzlib
    close $f
    set result 0
    if {! [catch {exec sh testzlib.sh} err]} { set result 1 }
    catch {file delete -force testzlib.sh}
    catch {file delete -force testzlib.c}
    catch {file delete -force testzlib}
    return $result
}


# checkZlib:
#    Checks whether the system has the zlib compression library installed,
#    if necessary. 
#
proc checkZlib {} {
    global var
    if {[string first "DZLIB" $var(SCIDFLAGS)] >= 0} {
        set var(ZLIB) {}
        set var(OBJS) {$(SCIDOBJS) $(ZLIBOBJS)}
        return
    }
    puts -nonewline "    Checking if your system already has zlib installed: "
    flush stdout
    if {[systemHasZlib]} {
        puts "yes."
        set var(ZLIB) {-lz}
        set var(OBJS) {$(SCIDOBJS)}
    } else {
        puts "no."
        append var(SCIDFLAGS) " -DZLIB"
        set var(ZLIB) {}
        set var(OBJS) {$(SCIDOBJS) $(ZLIBOBJS)}
    }
}

# writeMakefile:
#    Creates the Makefile using Makefile.conf and the configured
#    settings.
#    Also creates tcl/config.tcl
#
proc writeMakefile {{type ""}} {
    global var defaultVar
    set default 0
    set success 0
    if {$type == "default"} {
        set default 1
        set var(CONFIG_RESULT) \
            {You have not run "./configure" yet.  The default settings are:}
    } else {
        set success [findTclTkPaths]
        set var(CONFIG_RESULT) \
            {Sorry, "./configure" was not successful. The default settings are:}
        if {$success} {
           set var(CONFIG_RESULT) \
               {The settings determined by "./configure" are:}
        }
    }

    foreach name {TCL_INCLUDE TCL_LIBRARY TK_LIBRARY} {
        if {! [info exists var($name)]} { set var($name) $defaultVar($name) }
    }

    checkZlib

    if {[catch {set from [open $var(MAKEFILE) r]}]} {
       puts "Error opening file for reading: $var(MAKEFILE)"
       exit 1
    }
    puts "    Using $var(MAKEFILE)."

    if {[catch {set to [open "Makefile" w]}]} {
       puts "Error opening file for writing: Makefile"
       exit 1
    }

    set line [gets $from]
    while {1} {
        set line [gets $from]
        if {[eof $from]} { break }
        foreach sub [array names var] {
            set first [string first "@$sub@" $line]
            if {$first >= 0} {
                set last [expr $first + [string length $sub] + 1]
                set pre [string range $line 0 [expr $first - 1]]
                set post [string range $line [expr $last + 1] end]
                set line $pre
                append line $var($sub)
                append line $post
            }
        }
        if {[string compare "!" [string index $line 0]]} {
            puts $to $line
        }
    }

    close $from
    close $to

    # Summary info

    if {$default} {
        puts {The default Makefile was written.}
    } elseif {$success} {
        puts {The Makefile configured for your system was written.}
        puts {Now just type "make" to compile Scid.}
    } else {
        puts {Not all settings could be determined!}
        puts {The default Makefile was written.}
        puts {You will need to edit it before you can compile Scid.}
    }
}


# usage:
#     Explains the usage of this script, then exits
#
proc usage {} {
    puts {Valid options are:}
    puts {  BINDIR       The location for scid executables for "make install".}
    puts {  COMPILE      Your C++ compiler. Default: "g++".}
    puts {  CC           Your C compiler. Default: "gcc".}
    puts {  DEBUG        Debugging flags. Use DEBUG="-DASSERTIONS" for assertions.}
    puts {  LANGUAGES    Multi-language support. Use LANGUAGES="" for English only.}
    puts {  LINK         Your C++ linker. Default: "g++".}
    puts {  OPTIMIZE     C++ optimizations. Default: "-O3 -fno-rtti -fno-exceptions".}
    puts {  PROFILE      Used for profiling the source code. Default: none.}
    puts {  SCIDFLAGS    Scid customization flags. Default: none.}
    puts {  SHAREDIR     Location of Scid data (ECO, spelling) files for "make install".}
    puts {  TB           Tablebase support. Use TB="" to exclude Tablebase code.}
    puts {  TCL_INCLUDE  Compiler directives for including Tcl.}
    puts {  TCL_LIBRARY  Compiler directives for linking Tcl.}
    puts {  TCL_VERSION  Your Tcl/Tk version. Example: TCL_VERSION="8.3".}
    puts {  TK_LIBRARY   Compiler directives for linking Tcl/Tk.}
    puts {  WARNINGS     C++ compiler warnings. Default: "-Wall".}
    puts {  MAKEFILE     Makefile configuration file. Default: "Makefile.conf".}
    puts {}
    puts {  This configure program should find the proper values for the options}
    puts {  starting with TCL_ and TK_ automatically, so you should only use those}
    puts {  options if it fails to find your Tcl/Tk installation.}
    puts {}
    puts {Example usage:}
    puts {  ./configure LANGUAGES="tcl/francais.tcl" BINDIR="/usr/local/bin"}
    puts {}
    exit 1
}

########################################

puts "configure: Makefile configuration program for Scid"

# Parse command-line arguments:
set default 0

foreach arg $argv {
    if {![string compare "default" $arg]} {
        set default 1
    } else {
        set temp_idx [string first "=" $arg]
        if {$temp_idx > 0} {
            set temp_var [string range $arg 0 [expr $temp_idx - 1]]
            set temp_value [string range $arg [expr $temp_idx + 1] end]
            set var($temp_var) $temp_value
        } else {
            puts "Invalid argument: $arg"
            usage
        }
    }
}

if {$default} {
    writeMakefile default
    exit 0
}

if {[file readable "Makefile"]} {
    puts {    Renaming "Makefile" to "Makefile.bak"}
    catch {file rename -force "Makefile" "Makefile.bak"}
}

set tclv $var(TCL_VERSION)
set tclv_nodot [expr round($tclv * 10)]

puts "    Tcl/Tk version: $tclv"
puts "    Your operating system is: $tcl_platform(os) $tcl_platform(osVersion)"

writeMakefile

### End of configure script ###
