#!/bin/sh
#
# Copyright 2009-2014
# Kaz Kylheku <kaz@kylheku.com>
# Vancouver, Canada
# All rights reserved.
#
# BSD License:
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#   1. Redistributions of source code must retain the above copyright
#      notice, this list of conditions and the following disclaimer.
#   2. Redistributions in binary form must reproduce the above copyright
#      notice, this list of conditions and the following disclaimer in
#      the documentation and/or other materials provided with the
#      distribution.
#   3. The name of the author may not be used to endorse or promote
#      products derived from this software without specific prior
#      written permission.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#
# Save command line in a way that can be re-run.
# This takes care of spaces, but if there are shell-meta characters
# in the arguments, oops.
#

if test x$txr_shell = x ; then
  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -x $shell ; then
       txr_shell=$shell
       break
    fi
  done
  if test x$txr_shell = x ; then
    echo "No known POSIX shell found: falling back on /bin/sh, which may not work"
    txr_shell=/bin/sh
  fi
  export txr_shell
  exec $txr_shell $0 ${@+"$@"}
fi

set -u

cmdline=
for arg in "$0" ${@+"$@"} ; do
  [ -n "$cmdline" ] && cmdline="$cmdline "
  case $arg in
  *" "* | " "* | *" " )
    cmdline=$cmdline$(printf "\"%s\"" "$arg")
    ;;
  * )
    cmdline=$cmdline$arg
    ;;
  esac
done

#
# Establish default values for any variables that are not specified
# on the command line. The default derivations from prefix are in
# Make syntax. They go verbatim into the generated config.make.
# This way they can be overridden more flexibly at make time.
#

#
# non-config
#
help=

#
# config
#
prefix='/usr/local'
install_prefix=
bindir='bin'
datadir='share/txr'
mandir='share/man'
make=
cross=
compiler_prefix=
ccname=gcc
cc='$(cross)$(compiler_prefix)$(ccname)'
intptr=
exe=
tool_prefix=
lex='$(cross)$(tool_prefix)flex'
lexlib=-lfl
yaccname_given=
yaccname=
yacc='$(cross)$(tool_prefix)$(yaccname)'
yacc_given=
nm='$(cross)$(tool_prefix)nm'
opt_flags=-O2
lang_flags='-ansi -D_XOPEN_SOURCE=600'
diag_flags='-Wall -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=strict-prototypes'
debug_flags=-g
inline=
platform_flags=
remove_flags=
lex_dbg_flags=
txr_dbg_opts=--gc-debug
valgrind=
lit_align=
extra_debugging=
debug_support=y
gen_gc=y
mpi_version=1.8.6
have_quilt=
have_patch=
have_unistd=
have_timegm=
have_syslog=
have_windows_h=
have_posix_sigs=
need_darwin_c_source=

#
# Parse configuration variables
#
while [ $# -gt 0 ] ; do
  case $1 in
  --no-* | --no_* )
    var=${1#--no?}
    val=
    ;;
  --*=* )
    var=${1%%=*}
    var=${var#--}
    val=${1#*=}
    ;;
  --*= )
    var=${1%%=*}
    var=${var#--}
    val=
    ;; --* )
    var=${1#--}
    val=y
    ;;
  *=* )
    var=${1%%=*}
    val=${1#*=}
    ;;
  *= )
    var=${1%%=*}
    val=
    ;;
  * )
    printf "$0: '$1' doesn't look like a configuration variable assignment\n"
    printf "$0: use --help to get help\n"
    exit 1
  esac

  var=$(echo "$var" | tr - _)

  if ! echo $var | grep -q -E '^[A-Za-z_][A-Za-z0-9_]*$' ; then
    printf "$0: '$var' isn't a proper configuration variable name\n"
    exit 1
  fi

  eval "var_exists=\${$var+y}"

  if [ "$var_exists" != y ] ; then
    printf "$0: nonexistent option: '%s'\n" "$1"
    exit 1
  fi

  eval "$var='$val'"

  eval "var_given_exists=\${${var}_given+y}"

  if [ "$var_given_exists" = y ] ; then
    eval "${var}_given=y"
  fi

  shift
done

#
# If --help was given (or --help=<nonempty> or help=<nonempty>) then
# print help and exit. The termination status is failed, to indicate
# that configuration was not done.
#

if [ -n "$help" ] ; then
cat <<!

usage: $0 { variable=value }*

The configure script prepares txr program for compilation and installation.
To configure a program means to establish the values of make variables
which influence how the software is built, where it is installed.
These variables can also influence what features are present in the
software, and can determine various defaults for those behaviors which are
dynamically configurable when the software is run.

Configuration variables are recorded in a file called config.make. This is a
GNU makefile, and consequently uses the GNU make syntax. It is included in the
main Makefile by an include statement.

The configure script is flexible. It allows variables to be entered in any
of these forms:

Canonical:

   variable=value      Defines the given variable as having the given value.
   variable=           Defines the variable as having an empty value.
                       An empty value serves as boolean false.

Long-option style:

   --variable=value    Same as 'variable=value', but resembles a GNU-style
                       long option.
   --variable          Same as 'variable=y'.
   --no-variable       Same as 'variable='.

No variables are required. The configure script establishes default values
for any variables which are needed by the build, but which are not specified
on the command line.

After running $0, check that the config.make contents are sane.

The following variables are supported.  Note that make variable syntax may
be used in paths. Default values are shown in [square brackets].

Variables are case-sensitive, but underscores and dashes are interchangeable.

prefix [$prefix]

  Specifies root directory where the software will ultimately be installed and
  run from.

install-prefix [$install_prefix]

  Specifies an extra path prefix that will be prepended to all paths during
  installation, which allows the software to be installed in a temporary
  directory for packaging. This variable becomes the \$(DESTDIR)
  variable in the config.make makefile.

bindir [$bindir]

  Specifies where the program executable will be installed, as a relative
  path from the prefix.

datadir [$datadir]

  Specifies where read-only program data is to be stored, as a relative
  path from the prefix.

mandir [$mandir]

  Specifies the directory where to install man pages, as a relative
  path from the prefix.

cross [$cross]

  Specifies the root of a cross-compiling toolchain.
  This becomes the \$(cross) variable in the config.make makefile, and by
  default will be added as a prefix to all of the toolchain commands.
  It should include the trailing slash, unless the \$compiler_prefix
  and \$tool_prefix variables take care of this by providing a leading slash.

compiler-prefix [$compiler_prefix]

  Specifies a prefix to be added to the compiler command.
  This is added to the \$(cross) prefix. This can include some path name
  components, and a name fragment. For instance, if
  \$cross is "/cross/toolchain/" and \$compiler_prefix is
  "bin/mips-linux-" then the compiler command, unless otherwise
  specified, will be "/cross/toolchain/bin/mips-linux-gcc".

ccname [$ccname]

  Specifies just the name of the compiler front-end program, without the path.
  The following variable, cc, specifies the full name.

cc [$cc]

  Specifies the name of the toolchain front-end driver command to use for
  compiling C sources to object files, and for linking object files to
  executables. This becomes the CC variable in config.make.

intptr [$intptr]

  Specifies the name of the C integer type wide enough such that a pointer
  value can be converted to it. If this is blank, the configure script
  will try to auto detect it.

lit-align [$lit_align]

  Specifies alignment for wide string literals.  This is guessed
  from the size of the wchar_t type. If your wchar_t type is two byte wide, but
  wide literals are aligned to four bytes, then you should specify this.  This
  will eliminate some kludges in the program. There is no easy way to check
  for this withut generating and running a C program, which is unfriendly
  for cross-compiling!

inline [$inline]

  Specifies the syntax for defining an inline function, in such
  a way that the function definition can be included into multiple
  translation units without clashes.

  If blank, an attempt is made to auto-detect this which
  falls back on "static".

tool-prefix [$tool_prefix]

  Specifies a prefix to be added to tool commands other than the
  compiler, like lex and yacc, in addition to \$cross.

lex [$lex]

  Specifies the program to use for compiling lex scanners to C.
  This must be compatible with GNU flex, since flex extensions are used.

lexlib [$lexlib]

  Specifies the linker flag to use for linking the lex library.

yaccname [$yaccname]

  Specifies just the name of the yacc program without the path.
  The following variable, yacc, specifies the full name.
  If blank, the choice yacc program will be auto-detected.

yacc [$yacc]

  Specifies the program to use for compiling yacc scanners to C.

nm [$nm]

  Specifies the nm program for dumping symbols from an object file.

opt-flags [$opt_flags]

  Specifies optimization flags to use for compiling and linking
  C sources.

lang-flags [$lang_flags]

  Specifies compiler flags which control the C language dialect and standard
  conformance in the language and header files. The txr program is written
  in C90, and requires POSIX and possibly other extensions.

diag-flags [$diag_flags]

  Specifies compiler flags for obtaining extra diagnostics.

debug-flags [$debug_flags]

  Specifies flags for requesting that debugging information be
  retained in the compile and link.

platform-flags [$platform_flags]

  Specify additional compiler flags for anything else, such as CPU tuning,
  target ABI selection, code generation options, et cetera.

remove-flags [$remove_flags]

  This is a negative otpion. Any flags mentioned in this variable
  will be removed from any of the other compiler flags options above.
  The flags may contain GNU Make patterns.

lex-dbg-flags [$lex_dbg_flags]

  Specifies debug flags to be passed to lex, perhaps to generate a debugging
  scanner.

txr-dbg-opts [$txr_dbg_opts]

  Specifies debug flags to pass to the txr program during the execution
  of "make tests".

valgrind [$valgrind]

  Use --valgrind to to build txr with valgrind integration.
  Valgrind integration means that when the program is running under valgrind,
  it advises valgrind about stack memory locations accessed by the garbage
  collector, to suppress diagnostics about uninitialized accesses.

extra-debugging [$extra_debugging]

  Use --extra_debugging to configure some additional debugging features,
  which incur a run-time penalty.

gen-gc [$gen_gc]

  Use --no-gen-gc to disable the generational garbage collector which
  is now enabled by default.

  When disabled, the garbage collector performs a full object traversal and
  sweep on each garbage collection.

!
  exit 1
fi

#
# Variables are read, --help wasn't given, so let's configure!
#


txr_ver=93

#
# The all important banner.
#

if [ $txr_ver ] ; then
  banner_text=$(printf " Configuring txr %s " "$txr_ver")
else
  banner_text=" Configuring txr (unknown version) "
fi
banner_box=$(printf "%.${#banner_text}s\n" \
             "-------------------------------------------")
printf "+%s+\n|%s|\n+%s+\n" $banner_box "$banner_text" $banner_box

#
# From here on in, we bail if any command fails.
#

set -e

printf "We are using this shell: %s\n" $txr_shell

#
# Check for GNU make
#

printf "Checking for GNU Make ... "

if [ -z "$make" ] ; then
  for make in make gmake ; do
    output=$($make --version 2> /dev/null) || true
    set -- $output

    if [ $# -lt 2 ] || [ $1 != "GNU" -o $2 != "Make" ] ; then
      continue
    fi
    break
  done
fi

if [ -z "$make" ] ; then
  printf "missing\n"
  exit 1
fi

make_version=$3

save_ifs=$IFS ; IFS=. ; set -- $make_version ; IFS=$save_ifs

if [ $1 -lt 3 -o \( $1 -eq 3 -a $2 -lt 80 \) ] ; then
  printf "too old (%s found, 3.80 or newer needed)\n" $make_version
  exit 1
else
  printf "yes (%s found)\n" $make_version
fi

#
# Verify sanity of --prefix and other directories.
#

printf "Checking installation paths:\n"

for name in bindir datadir mandir; do
  eval path="\$install_prefix\$prefix/\${$name}"
  printf "\$(install_prefix)\$(prefix)/\$%s=%s ... " $name "$path"
  test_access=y
  case "$path" in
  " "* | *" "* | *" " )
    printf "incorrect (contains spaces)\n"
    exit 1
    ;;
  -* )
    printf "incorrect (resembles a command option)\n"
    exit 1
    ;;
  *'$('* )
    # It's a make expression; can't test it
    test_access=
    ;;
  /* )
    ;;
  * )
    printf "incorrect (must be absolute path)\n"
    exit 1
    ;;
  esac

  if [ $test_access ] ; then
    test_prefix=$path

    while true ; do
      if [ -e $test_prefix ] ; then
      if [ ! -d $test_prefix ] ; then
        printf "incorrect ('%s' is not a directory)!\n" $test_prefix
        exit 1
      fi
      if [ ! -w $test_prefix ] ; then
        printf "okay\n  (but no write access to '%s'\n" $test_prefix

        printf "   so '$make install' will require root privileges)\n"
      else
        printf "okay\n"
      fi
      break
      fi
      test_prefix=$(dirname $test_prefix)
    done
  else
    printf "okay\n  (make variable derivation)\n"
  fi
done

#
# First, we have to figure out whether we are configured straight
# in the source directory, or whether we are in a separate build directory.
# In the latter case, we set up a symbolic link to the Makefile.
#
source_dir="$(dirname $0)"

#
# Compute an absolute path to the source directory.
#
top_srcdir="$(cd "$source_dir" ; pwd -P)"

printf "Checking source directory %s ..." "$top_srcdir"

case "$top_srcdir" in
" "* | *" "* | *" " )
  printf " bad (contains spaces)\n"
  exit 1
  ;;
* )
  printf " okay\n"
  ;;
esac

if [ "$source_dir" != "." ] ; then
  printf "Symlinking Makefile -> $source_dir/Makefile\n"
  ln -sf "$source_dir/Makefile" .
else
  printf "Warning: its recommended to build in a separate directory\n"
fi

gen_config_make()
{
  cat > config.make <<!
#
# Make include file automatically generated by $0.
# Changes to this file are lost when the above is re-run.
#

# Shell used by make for running recipes; this
# is the as the shell we chose for the configure script,
# derived from the txr_shell variable.
SHELL := $txr_shell

txr_ver := $txr_ver

# absolute path to source code directory
top_srcdir := $top_srcdir

# ultimate installation prefix, where the
# application will be run.
prefix := $prefix

# packaging installation prefix, where the
# application may be temporarily installed
# for creating pre-compiled packages,
# e.g. for an operating system distro.
DESTDIR := $install_prefix

# relative path from prefix to datadir
bindir_rel := $bindir

# executable directory
bindir = \$(prefix)/\$(bindir_rel)

# read-only data directory
datadir = \$(prefix)/$datadir

# man page directory
mandir = \$(prefix)/$mandir

# cross compiler toolchain root directory
cross := $cross

# compiler name
ccname = $ccname

# name of yacc program
yaccname = $yaccname

# prefix for compiler command
compiler_prefix := $compiler_prefix

# prefix for non-compiler toolchain commands
tool_prefix := $tool_prefix

# do we compile in syslog support?
have_syslog := $have_syslog

# do we modern posix signal handling?
have_posix_sigs := $have_posix_sigs

# do we compile in debug support?
debug_support := $debug_support

# MPI version
mpi_version := $mpi_version

# EXE suffix
EXE := $exe

CC := $cc
LEX := $lex
LEXLIB := $lexlib
YACC := $yacc
NM := $nm

OPT_FLAGS := $opt_flags
LANG_FLAGS := $lang_flags
DIAG_FLAGS := $diag_flags
DBG_FLAGS := $debug_flags
PLATFORM_FLAGS := $platform_flags
REMOVE_FLAGS := $remove_flags
LEX_DBG_FLAGS := $lex_dbg_flags
TXR_DBG_OPTS := $txr_dbg_opts
!
}

#
# Before doing some other tests, we need a config.make
#

printf "Generating config.make ... "
gen_config_make
printf "\n"

#
# Start config.h header
#

cat <<! > config.h
/*
 * Header file automatically generated by $0.
 * Tweaking this file may seem like a good temporary workaround
 * to some problem but you probably should fix the script
 * to do the job. In any case, be aware that you will lose your
 * changes if you re-run $0.
 */
!

#
# Perform a configure test.
# Arguments are passed through to make
#
conftest()
{
  rm -f ${exe-"conftest conftest.exe"} ${exe+"conftest$exe"}
  $make conftest ${@+"$@"} > conftest.err 2>&1 && [ -x conftest ] 
}

#
# Like conftest but make only .o
#
conftest_o()
{
  rm -f conftest.o
  $make conftest.o ${@+"$@"} > conftest.err 2>&1
}

#
# Like conftest but make conftest.syms
#
conftest_syms()
{
  rm -f conftest.o conftest.syms
  $make conftest.syms ${@+"$@"} > conftest.err 2>&1
}


#
# Check C compiler sanity
#
printf "Checking whether your C compiler can make a simple executable ... "

cat > conftest.c <<!
#include <stdio.h>
int main(void)
{
  printf("Hello, world!\n");
  return 0;
}
!

if ! conftest ; then
  printf "failed\n"
  printf "Checking whether the failure is due to a requirement to use C99 ... "
  if conftest EXTRA_FLAGS=-std=c99 ; then
    printf "yes\n"
    lang_flags="$(echo "$lang_flags" | sed -e 's/-ansi/-std=c99/')"
  else
    printf "no\n\n"
    conftest && true
    printf "Errors from compilation: \n\n"
    cat conftest.err
    exit 1
  fi
else
  printf "okay\n"
fi

printf "Checking whether executables have that idiotic .exe suffix ... "

if ls conftest.exe > /dev/null 2>&1 ; then
  echo "yes"
  exe=.exe
else
  echo "no"
fi

rm -f conftest$exe

#
# Check for annoying clashes from non-conforming BSD-derived systems that don't
# honor Unix/POSIX feature selection macros!
#

printf "Checking for name clashes caused by nonconforming toolchains ... "

for ident in trunc floorf random longlong_t ; do
  cat > conftest.c <<!
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <wchar.h>
#include <wctype.h>

struct txr_foo { int txr; } $ident;

int $ident(void);

int main(void) { return 0; }
!
  if ! conftest ; then
    printf "#define %s txr_%s\n" $ident $ident >> config.h
    have_unistd=y
  fi
done

printf "done\n"

#
# Check for idiotic behavior: extensions in C header files controlled
# by __STRICT_ANSI__ rather than things like __POSIX_SOURCE.
#

printf "Checking for proper support for feature-test macros ... "

cat > conftest.c <<!
#include <stdio.h>

int main(void)
{
   return fileno(stdin);
}
!
if conftest EXTRA_FLAGS=-Werror ; then
  printf "yes\n"
else
  printf "no\n"
  lang_flags="$lang_flags -U__STRICT_ANSI__"
  printf "Regenerating config.make ..."
  gen_config_make
  printf "done\n"
fi

#
# Detect Apple environment. We need _DARWIN_C_SOURCE.
#

case "$ccname" in
  *gcc )
     printf "Checking for Apple environment ... "
     if echo | gcc -dM -E - | grep -s __APPLE__ > /dev/null 2>&1 ; then
       printf "yes\n"
       need_darwin_c_source=y
       lang_flags="$lang_flags -D_DARWIN_C_SOURCE"
       printf "Regenerating config.make ..."
       gen_config_make
       printf "done\n"
     else
       printf "no\n"
     fi
     ;;
esac

#
# Detect stupid FreeBSD problem: no defined way to reveal
# traditional BSD functions if Unix compliance is selected with
# _XOPEN_SOURCE. Heaven help these troglodytes.
#

printf "Detecting what symbol reveals BSD functions ... "

cat > conftest.c <<!
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
  int (*pdaemon)(int, int) = &daemon;
}
!

if conftest ; then
  printf "none needed\n"
else
  for flag in _BSD_SOURCE __BSD_VISIBLE _GNU_SOURCE _X_OOPS; do
    if [ $flag = _X_OOPS ] ; then
      printf "failed\n"
      break
    fi
    
    if conftest EXTRA_FLAGS=-D$flag ; then
      printf "%s\n" $flag 
      lang_flags="$lang_flags -D$flag"
      gen_config_make
      break
    fi
  done
fi

#
# Check for annoying warnings from ctype.h macros
#

printf "Checking for annoying warnings from <ctype.h> macros ... "

cat > conftest.c <<!
#include <ctype.h>

int main(void)
{
  char x = '3';
  return isdigit(x);
}
!
if conftest EXTRA_FLAGS=-Werror ; then
  printf "absent\n"
else
  printf "present\n"
  cat >> config.h <<!
$(for x in isalpha isupper islower isdigit isxdigit isalnum isspace \
           ispunct isprint isgraph iscntrl isblank ; do \
    printf "#undef %s\n" $x ; done)
!
fi

#
# Check what kind of C type we have for integers wider than long,
# if any.
#
printf "Checking what C type we have for integers wider than \"long\" ... "

longlong=

for try_type in int64 __int64 "long long" ; do
  cat > conftest.c <<!
$try_type value;
!
  if conftest_o ; then
    longlong=$try_type
    break
  fi
done

if [ -n "$longlong" ] ; then
  printf '"%s"\n' "$longlong"
  printf "#define HAVE_LONGLONG_T 1\n" >> config.h
  printf "typedef $longlong longlong_t;\n" >> config.h
else
  printf "none\n"
fi

printf "Checking what C type we have for unsigned integers wider than \"long\" ... "

ulonglong=

for try_type in uint64 __uint64 "unsigned long long" ; do
  cat > conftest.c <<!
$try_type value;
!
  if conftest_o; then
    ulonglong=$try_type
    break
  fi
done

if [ -n "$ulonglong" ] ; then
  printf '"%s"\n' "$ulonglong"
  printf "#define HAVE_ULONGLONG_T 1\n" >> config.h
  printf "typedef $ulonglong ulonglong_t;\n" >> config.h
else
  printf "none\n"
fi

printf "Checking what C type we have for integers wider than \"long long\" ... "

broken128=
output=$($make conftest.ccver)
set -- $output
if [ "$1" = "gcc" ] ; then
  gcc_version=$3
  save_ifs=$IFS ; IFS=. ; set -- $gcc_version ; IFS=$save_ifs
  if [ $1 -lt 4 ] || [ $1 -eq 4 -a $2 -le 3 ] ; then
    broken128=y
  fi
fi

superlong=

if [ -z "$broken128" ] ; then
  for try_type in int128 int128_t __int128 __int128_t ; do
    cat > conftest.c <<!
#include "config.h"
int main(void)
{
   extern longlong_t a, b;
   $try_type value = ($try_type) a * ($try_type) b;
   return 0;
}
longlong_t a, b;
!
    if conftest_o ; then
      superlong=$try_type
      break
    fi
  done
fi

if [ -n "$superlong" ] ; then
  printf '"%s"\n' "$superlong"
  printf "#define HAVE_SUPERLONG_T 1\n" >> config.h
  printf "typedef $superlong superlong_t;\n" >> config.h
else
  printf "none\n"
fi

printf "Checking what C type we have for u. integers wider than \"long long\" ... "

usuperlong=

if [ -z "$broken128" ] ; then
  for try_type in uint128 uint128_t __uint128 __uint128_t ; do
    cat > conftest.c <<!
#include "config.h"
int main(void)
{
   extern longlong_t a, b;
   $try_type value = ($try_type) a * ($try_type) b;
   return 0;
}
longlong_t a, b;
!
    if conftest_o ; then
      usuperlong=$try_type
      break
    fi
  done
fi

if [ -n "$usuperlong" ] ; then
  printf '"%s"\n' "$usuperlong"
  printf "#define HAVE_USUPERLONG_T 1\n" >> config.h
  printf "typedef $usuperlong usuperlong_t;\n" >> config.h
else
  printf "none\n"
fi

printf "Checking what C integer type can hold a pointer ... "

read_syms()
{
  print_into_config=${1-} 
  deferred_offset=

  while read symbol type offset size ; do
    size=$(( 0$size + 0 ))
    offset=$(( 0$offset + 0 ))
    symbol=${symbol#_}
    case "$type" in
    C )
      size=$(( offset + 0 ))
      ;;
    S )
      if [ -n "$deferred_offset" ] ; then
      size=$(( offset - deferred_offset ))
      case "$deferred_sym" in
      SIZEOF* )
        eval $(printf "%s=%d\n" "$deferred_sym" "$size")
          if [ -n "$print_into_config" ] ; then
          printf "#define %s %s\n" "$deferred_sym" "$size" >> config.h
          fi
        ;;
      esac
      fi
      deferred_sym=$symbol
      deferred_offset=$offset
      continue
      ;;
    esac
    case "$symbol" in
    SIZEOF* )
      eval $(printf "%s=%d\n" "$symbol" "$size")
      if [ -n "$print_into_config" ] ; then
        printf "#define %s %s\n" "$symbol" "$size" >> config.h
      fi
      ;;
    esac
  done < conftest.syms
}

if [ -z "$intptr" ] ; then
  cat > conftest.c <<!
#include "config.h"
#ifdef HAVE_SUPERLONG_T
char SIZEOF_SUPERLONG_T[sizeof (superlong_t)];
#endif
#ifdef HAVE_LONGLONG_T
char SIZEOF_LONGLONG_T[sizeof (longlong_t)];
#endif
char SIZEOF_PTR[sizeof (char *)];
char SIZEOF_LONG[sizeof (long)];
char SIZEOF_INT[sizeof (int)];
char SIZEOF_SHORT[sizeof (short)];
char DUMMY;
!
  if ! conftest_syms ; then
    printf "failed\n\n"

    printf "Errors from compilation: \n\n"
    cat conftest.err
    exit 1
  fi

  SIZEOF_PTR=0
  SIZEOF_SHORT=0
  SIZEOF_INT=0
  SIZEOF_LONG=0
  SIZEOF_LONGLONG_T=0
  SIZEOF_SUPERLONG_T=0

  read_syms y

  if [ $SIZEOF_PTR -eq 0 ] ; then
    printf "failed\n"
    exit 1
  fi

  if [ $SIZEOF_PTR -eq $SIZEOF_SHORT ] ; then
    intptr="short"
    uintptr=y
  elif [ $SIZEOF_PTR -eq $SIZEOF_INT ] ; then
    intptr="int"
    uintptr=y
  elif [ $SIZEOF_PTR -eq $SIZEOF_LONG ] ; then
    intptr="long"
    uintptr=y
  elif [ $SIZEOF_PTR -eq $SIZEOF_LONG_LONG_T ] ; then
    intptr="longlong_t"
    uintptr=$ulonglong
  fi

  if [ -z "$intptr" ] ; then
    printf "failed\n"
    exit 1
  fi
fi

printf '"%s"\n' "$intptr"
printf "typedef $intptr int_ptr_t;\n" >> config.h
if [ -n "$uintptr" ] ; then
  printf "#define HAVE_UINTPTR_T 1\n" >> config.h
  printf "typedef unsigned $intptr uint_ptr_t;\n" >> config.h
fi
intptr_max_expr="((((($intptr) 1 << $((SIZEOF_PTR * 8 - 2))) - 1) << 1) + 1)"
printf "#define INT_PTR_MAX %s\n" "$intptr_max_expr" >> config.h
printf "#define INT_PTR_MIN (-INT_PTR_MAX)\n" >> config.h

if [ -n "$longlong" ] && [ $SIZEOF_LONGLONG_T -eq $(( 2 * $SIZEOF_PTR )) ] 
then
  printf "#define HAVE_DOUBLE_INTPTR_T 1\n" >> config.h
  printf "typedef longlong_t double_intptr_t;\n" >> config.h
elif [ -n "$superlong" ] && [ $SIZEOF_SUPERLONG_T -eq $(( 2 * $SIZEOF_PTR )) ]
then
  printf "#define HAVE_DOUBLE_INTPTR_T 1\n" >> config.h
  printf "typedef superlong_t double_intptr_t;\n" >> config.h
fi

#if HAVE_LONGLONG_T && 

#
# Alignment of wchar_t
#
# What we really want to know is the alignment of wide string literals
# like L"wide literal".
#
# We make pessimistic assumption that the size of the wchar_t type is this
# alignment.
#
# There is no easy way to get the information without running a compiled
# program.
#

printf "Conservatively guessing the alignment of wide literals ... "

if [ -z "$lit_align" ] ; then
  cat > conftest.c <<!
#include <wchar.h>
char SIZEOF_WCHAR_T[sizeof (wchar_t)];
char DUMMY;
!
  if ! conftest_syms ; then
    printf "failed\n\n"

    printf "Errors from compilation: \n\n"
    cat conftest.err
    exit 1
  fi

  SIZEOF_WCHAR_T=0
  deferred_offset=

  read_syms

  if [ $SIZEOF_WCHAR_T -eq 0 ] ; then
    printf "failed\n"
    exit 1
  fi

  lit_align=$SIZEOF_WCHAR_T
fi

printf "%d\n" "$lit_align"
printf "#define LIT_ALIGN %d\n" "$lit_align" >> config.h

#
# Inline functions
# 

printf "Checking how to declare inline functions ... "

if [ -z "$inline" ] ; then
  for inline in \
    "inline" "static inline" "extern inline" \
    "__inline__" "static __inline__" "extern __inline__" \
    "static"
  do
    cat > conftest1.c <<!
$inline int func(void)
{
  return 0;
}

int main(void)
{
  return func();
}
!
    cat > conftest2.c <<!
$inline int func(void)
{
  return 0;
}
!
    rm -f conftest2$exe
    if ! $make conftest2 > conftest.err 2>&1 || ! [ -x conftest2 ] ; then
      continue
    fi
    break
  done
fi

printf '"%s"\n' "$inline"
printf "#define INLINE $inline\n" >> config.h

#
# Valgrind
#

if [ -n "$valgrind" ] ; then
  printf "Checking valgrind API availability ... "

  cat > conftest.c <<!
#include <valgrind/memcheck.h>

#ifdef VALGRIND_DO_CLIENT_REQUEST

int main(void)
{
  return 0;
}

#else
syntax error
#endif
!
  if ! conftest ; then
    printf "failed\n\n"
    printf "Errors from compilation: \n\n"
    cat conftest.err
    exit 1
  fi

  printf "okay\n"
  printf "#define HAVE_VALGRIND 1\n" >> config.h
fi

#
# Yacc tests
#

printf "Checking for yacc program ... "

if [ -z "$yacc_given" -a -z "$yaccname_given" ] ; then
  rm -f conftest.yacc
  for yaccname in "yacc" "byacc" "bison -y" "" ; do
    yaccpath=$($make yaccname="$yaccname" conftest.yacc)
    if command -v $yaccpath > /dev/null ; then
      break;
    fi
  done

  if [ -z "$yaccname" ] ; then
    printf "not found\n"
    exit 1
  fi

  printf '"%s"\n' "$yaccpath"
else
  yaccpath=$($make conftest.yacc)
  case $yaccpath in
  *bison )
    printf "error\n\n"
    printf "GNU Bison needs -y to behave like yacc\n\n"
    printf "This needs to be specified in the --yaccname or --yacc option\n\n"
    exit 1
    ;;
  * )
    if ! command -v $yaccpath > /dev/null ; then
      printf "not found\n\n"
      exit 1
    fi
    printf "given\n"
    ;;
  esac
fi

#
# sys/wait.h
#

printf "Checking whether we have <sys/wait.h> ... "

cat > conftest.c <<!
#include <sys/wait.h>

int main(void)
{
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_SYS_WAIT 1\n" >> config.h
else
  printf "no\n"
fi

#
# sys/stat.h
#

printf "Checking whether we have <sys/stat.h> ... "

cat > conftest.c <<!
#include <sys/stat.h>

struct stat s;

int main(void)
{
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_SYS_STAT 1\n" >> config.h
else
  printf "no\n"
fi


#
# environ
#

printf "Checking whether we have environ ... "

cat > conftest.c <<!
#include <stdio.h>

int main(void)
{
  extern char **environ;
  puts(environ[0]);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_ENVIRON 1\n" >> config.h
else
  printf "no\n"
fi

#
# GetEnvironmentStrings
#

printf "Checking whether we have GetEnvironmentStrings ... "

cat > conftest.c <<!
#include <windows.h>

int main(void)
{
  WCHAR *ptr = GetEnvironmentStringsW();
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_GETENVIRONMENTSTRINGS 1\n" >> config.h
  have_windows_h=y
else
  printf "no\n"
fi

#
# fork, pipe, exec, waitpid.
#

printf "Checking for POSIX fork/pipe/exec/waitpid ... "

cat > conftest.c <<!
#include "config.h"
#ifdef HAVE_SYS_WAIT
#include <sys/wait.h>
#endif
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  int status, fd[2];
  pid_t p = fork();
  int res = pipe(fd);
  (void) execvp(argv[0], argv);
  (void) waitpid(p, &status, 0);
  (void) res;
  return 0;
}
!

if conftest ; then
  printf "yes\n"
  printf "#define HAVE_FORK_STUFF 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

#
# fcntl
#

printf "Checking for POSIX fcntl ... "

cat > conftest.c <<!
#include "config.h"
#include <fcntl.h>

int main(int argc, char **argv)
{
  int err = fcntl(0, F_SETFD, FD_CLOEXEC);
  return 0;
}
!

if conftest ; then
  printf "yes\n"
  printf "#define HAVE_FCNTL_H 1\n" >> config.h
else
  printf "no\n"
fi

#
# Check for fields inside struct tm
#

printf "Printf detecting timezone fields in struct tm ... "

tm_gmtoff=
tm_tmzone=

for try_field in tm_gmtoff __tm_gmtoff ; do
  cat > conftest.c <<!
#include <time.h>
int x = sizeof ((struct tm *) 0)->$try_field;
!
  if conftest_o ; then
    printf "#define HAVE_TM_GMTOFF 1\n" >> config.h
    printf "#define TM_GMTOFF %s\n" $try_field >> config.h
    break
  fi
done

for try_field in tm_zone __tm_zone ; do
  cat > conftest.c <<!
#include <time.h>
int x = sizeof ((struct tm *) 0)->$try_field;
!
  if conftest_o ; then
    printf "#define HAVE_TM_ZONE 1\n" >> config.h
    printf "#define TM_ZONE %s\n" $try_field >> config.h
    break
  fi
done

printf "done\n"

printf "Checking for timegm function ... "

cat > conftest.c <<!
#include <time.h>

int main(void)
{
  time_t (*ptgm)(struct tm *) = &timegm;
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_TIMEGM 1\n" >> config.h
  have_timegm=y
else
  printf "no\n"
fi

printf "Checking for setenv and unsetenv functions ... "

cat > conftest.c <<!
#include <stdlib.h>

int main(void)
{
  setenv("TERM", "foo", 1);
  unsetenv("TERM");
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_SETENV 1\n" >> config.h
else
  printf "no\n"
fi
printf "Checking for tzset function ... "

cat > conftest.c <<!
#include <time.h>

int main(void)
{
  tzset();
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_TZSET 1\n" >> config.h
else
  printf "no\n"
fi

printf "Checking for localtime_r and gmtime_r functions ... "

cat > conftest.c <<!
#include <time.h>

int main(int argc, char **argv)
{
  struct tm stm;
  time_t t;

  localtime_r(&t, &stm);
  gmtime_r(&t, &stm);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_GMTIME_R 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi


printf "Checking for POSIX sleep function ... "

cat > conftest.c <<!
#include <unistd.h>

int main(int argc, char **argv)
{
  sleep(42);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_POSIX_SLEEP 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for POSIX usleep function ... "

cat > conftest.c <<!
#include <unistd.h>

int main(int argc, char **argv)
{
  usleep(42);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_POSIX_USLEEP 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for POSIX nanosleep function ... "

cat > conftest.c <<!
#include <time.h>

int main(int argc, char **argv)
{
  struct timespec ts;
  nanosleep(&ts, &ts);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_POSIX_NANOSLEEP 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for BSD daemon function ... "

cat > conftest.c <<!
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
  int (*pdaemon)(int, int) = &daemon;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_DAEMON 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for isatty function ... "

cat > conftest.c <<!
#include <unistd.h>

int main(void)
{
  isatty(0);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_ISATTY 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for syslog ... "

cat > conftest.c <<!
#include <syslog.h>

int main(void)
{
  openlog("foo", LOG_CONS, LOG_DAEMON);
  syslog(LOG_EMERG, "bar %d\n", 3);
  setlogmask(0);
  closelog();
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_SYSLOG 1\n" >> config.h
  have_syslog=y
else
  printf "no\n"
fi

printf "Checking for reasonably modern POSIX signal handling ... "

cat > conftest.c <<!
#include <signal.h>
#include <setjmp.h>

int main(void)
{
  sigjmp_buf jb;
  static struct sigaction olda, newa;
  static sigset_t olds, news;
  sigaction(0, &newa, &olda);
  sigprocmask(SIG_BLOCK, &news, &olds);
  if (!sigsetjmp(jb, 1)) 
    siglongjmp(jb, 1);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_POSIX_SIGS 1\n" >> config.h
  have_posix_sigs=y
else
  printf "no\n"
fi

printf "Checking for sigaltstack ... "

cat > conftest.c <<!
#include <signal.h>
#include <stdlib.h>

int main(void)
{
  stack_t ss;
  ss.ss_sp = malloc(SIGSTKSZ);
  ss.ss_size = SIGSTKSZ;
  ss.ss_flags = 0;
  return sigaltstack(&ss, 0);
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_SIGALTSTACK 1\n" >> config.h
else
  printf "no\n"
fi

printf "Checking for makedev ... "

cat > conftest.c <<!
#include <sys/types.h>

int main(void)
{
  int d = makedev(1, 2);
  int j = major(d);
  int n = minor(d);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_MAKEDEV 1\n" >> config.h
else
  printf "no\n"
fi

printf "Checking for link, symlink and readlink ... "

cat > conftest.c <<!
#include <unistd.h>

int main(void)
{
  int e1 = symlink("a", "b");
  int e2 = link("c", "d");
  char buf[256];
  ssize_t foo = readlink("e", buf, sizeof buf);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_SYMLINK 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for POSIX mkdir ... "

cat > conftest.c <<!
#include "config.h"
#include <sys/stat.h>
#if HAVE_WINDOWS_H
#include <windows.h>
#endif

int main(void)
{
  int e = mkdir("a", 0);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_MKDIR 1\n" >> config.h
else
  printf "no\n"
fi

printf "Checking for mknod ... "

cat > conftest.c <<!
#include "config.h"
#include <unistd.h>
#if HAVE_SYS_STAT
#include <sys/stat.h>
#endif

int main(void)
{
  int e = mknod("a", 0, 0);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_MKNOD 1\n" >> config.h
  have_unistd=y
else
  printf "no\n"
fi

printf "Checking for _wspawnlp ... "

cat > conftest.c <<!
#include "config.h"
#include <process.h>
#include <wchar.h>

int main(int argc, char **argv)
{
  wchar_t *wargv[] = { L"foo", L"bar", 0 };
  int r = _wspawnlp(_P_WAIT, L"foo", wargv);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_WSPAWN 1\n" >> config.h
else
  printf "no\n"
fi

printf "Checking for log2 ... "

cat > conftest.c <<!
#include <math.h>

int main(void)
{
  double x = log2(42.0);
  return 0;
}
!
if conftest ; then
  printf "yes\n"
  printf "#define HAVE_LOG2 1\n" >> config.h
else
  printf "no\n"
fi

#
# Dependent variables
#

if [ -n "$have_unistd" ] ; then
  printf "#define HAVE_UNISTD_H 1\n" >> config.h
fi

if [ -n "$have_windows_h" ] ; then
  printf "#define HAVE_WINDOWS_H 1\n" >> config.h
fi

#
# Extra debugging.
#

if [ -n "$extra_debugging" ] ; then
  printf "Configuring extra debugging, as requested ...\n"
  printf "#define EXTRA_DEBUGGING 1\n" >> config.h
fi

#
# Clean up
#

$make conftest.clean

#
# What do we have for patch management.
#

printf "Checking for quilt ... "

if ! quilt --version > /dev/null 2>&1 ; then
  printf "not found\n"
else
  printf "found\n"
  have_quilt=y
fi

printf "Checking for patch ... "

if ! patch --version > /dev/null 2>&1 ; then
  printf "not found\n"
  printf "\npatch tool required!\n\n"
  exit 1
else
  printf "found\n"
  have_patch=y
fi

#
# Function to apply patches.
#
apply_patches()
{
  if ! [ -e patches/series ] ; then
    echo "no patches"
    return 0
  fi

  while read patch patchlevel ; do
    case patch in
    '#' ) continue ;;
    * ) patch ${patchlevel:--p1} < patches/$patch ;;
    esac
  done < patches/series
}

#
# Try to extract MPI if not already.
#

printf "Extracting MPI ... "

if [ -e mpi-${mpi_version} ] ; then
  printf "already extracted\n"
else
  tar -xzf $top_srcdir/mpi-${mpi_version}.tar.gz
  printf "\n"
  printf "Symlinking MPI patches ...\n"
  ln -sf $top_srcdir/mpi-patches mpi-${mpi_version}/patches
  printf "Applying MPI patches ...\n"
  if [ -n "$have_quilt" ] ; then
    ( cd mpi-${mpi_version}/patches ;
      if [ -e series ] ; then quilt push -a ; else echo "no patches" ; fi )
  else
    ( cd mpi-${mpi_version} ;
      apply_patches )
  fi
fi

#
# Some final blurbs into config.h
#

[ -n "$debug_support" ] && printf "#define CONFIG_DEBUG_SUPPORT 1\n" >> config.h
[ -n "$gen_gc" ] && printf "#define CONFIG_GEN_GC 1\n" >> config.h

#
# Regenerate config.make
#

printf "Regenerating config.make ... "
gen_config_make
printf "done\n"

#
# Save configuration in config.log
#
cat > config.log <<!

Configured on $(date) using

   $cmdline

!
#
# Parting message
#
cat <<!

The configuration seems to have been successful. That doesn't mean it's
correct!  Please check the above output for any problems, and verify that the
contents of the generated files config.make and config.h are sane for the
target platform.

The next step is to build the program with $make.

If that is successful, please follow the INSTALL guide.

Usually, most users just need to "$make tests" and "$make install",
possibly switching to superuser for "$make install" if the prefix
points to a privileged location like /usr/local/.

!