#!/usr/bin/env python
#
# Copyright (C) 2009 ABINIT Group (Yann Pouillon)
# All rights reserved.
#
# This file is part of the ABINIT software package. For license information,
# please see the COPYING file in the top-level directory of the ABINIT source
# distribution.
#

from time import gmtime,strftime

import commands
import os
import re
import sys

# ---------------------------------------------------------------------------- #

#
# Subroutines
#

# Macro header
def macro_header(name,stamp):

 return """# Generated by %s on %s

#
# ABINIT plug-in support for the "configure" script
#

#
# IMPORTANT NOTE
#
# This file has been automatically generated by the %s
# script. If you try to edit it, your changes will systematically be
# overwritten.
#
""" % (name,stamp,name)



# Autotools info macro
def macro_info(m4_version,ac_version,am_version,lt_version):

 return """


# ABI_INFO_AUTOTOOLS()
# --------------------
#
# Make information about the Autotools available.
#
AC_DEFUN([ABI_INFO_AUTOTOOLS],
[dnl Store version numbers
 abi_m4_version="%6.6d"
 abi_ac_version="%6.6d"
 abi_am_version="%6.6d"
 abi_lt_version="%6.6d"

 dnl Display version information
 AC_MSG_NOTICE([M4 ${abi_m4_version} - Autoconf ${abi_ac_version} - Automake ${abi_am_version} - Libtool ${abi_lt_version}])

 dnl Substitute variables
 AC_SUBST(abi_m4_version)
 AC_SUBST(abi_ac_version)
 AC_SUBST(abi_am_version)
 AC_SUBST(abi_lt_version)
]) # ABI_INFO_AUTOTOOLS
""" % (m4_version,ac_version,am_version,lt_version)



# Init macro for source and build dirs
def macro_init_dirs(ac_version):

 if ( ac_version > 25900 ):
  ac_macro = "_AC_SRCDIRS"
 else:
  ac_macro = "_AC_SRCPATHS"

 ret = """


# ABI_INIT_DIRS()
# ---------------
#
# Set paths to source and build directories.
#
AC_DEFUN([ABI_INIT_DIRS],
[dnl Set paths (needed by other ABINIT macros)
 %s(["."])
 abinit_srcdir=${ac_abs_top_srcdir}
 abinit_builddir=${ac_abs_top_builddir}

 AC_SUBST(abinit_srcdir)
 AC_SUBST(abinit_builddir)
]) # ABI_INIT_DIRS
""" % (ac_macro)

 return ret



# Missing macros in Autoconf < 2.60
def macros_autoconf():

 return """


# ---------------------------------------------------------------------------- #

#
# Missing Autoconf macros
#



# _AC_FEATURE_CHECK_LENGTH(PROGPATH, CACHE-VAR, CHECK-CMD, [MATCH-STRING])
# ------------------------------------------------------------------------
# For use as the FEATURE-TEST argument to _AC_PATH_PROG_FEATURE_TEST.
# On each iteration run CHECK-CMD on an input file, storing the value
# of PROGPATH in CACHE-VAR if the CHECK-CMD succeeds.  The input file
# is always one line, starting with only 10 characters, and doubling
# in length at each iteration until approx 10000 characters or the
# feature check succeeds.  The feature check is called at each
# iteration by appending (optionally, MATCH-STRING and) a newline
# to the file, and using the result as input to CHECK-CMD.
m4_define([_AC_FEATURE_CHECK_LENGTH],
[# Check for GNU $1 and select it if it is found.
  _AC_PATH_PROG_FLAVOR_GNU([$$1],
    [$2="$$1" $1_found=:],
  [ac_count=0
  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
  while :
  do
    cat "conftest.in" "conftest.in" >"conftest.tmp"
    mv "conftest.tmp" "conftest.in"
    cp "conftest.in" "conftest.nl"
    echo '$4' >> "conftest.nl"
    $3 < "conftest.nl" >"conftest.out" 2>/dev/null || break
    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
    ac_count=`expr $ac_count + 1`
    if test $ac_count -gt ${$1_max-0}; then
      # Best one so far, save it but keep looking for a better one
      $2="$$1"
dnl   # Using $1_max so that each tool feature checked gets its
dnl   # own variable.  Don't reset it otherwise the implied search
dnl   # for best performing tool in a list breaks down.
      $1_max=$ac_count
    fi
    # 10*(2^10) chars as input seems more than enough
    test $ac_count -gt 10 && break
  done
  rm -f conftest.in conftest.tmp conftest.nl conftest.out])
])



# _AC_PATH_PROG_FEATURE_CHECK(VARIABLE, PROGNAME-LIST, FEATURE-TEST, [PATH])
# --------------------------------------------------------------------------
# FEATURE-TEST is called repeatedly with $ac_path_VARIABLE set to the
# name of a program in PROGNAME-LIST found in PATH.  FEATURE-TEST must set
# $ac_cv_path_VARIABLE to the path of an acceptable program, or else
# _AC_PATH_PROG_FEATURE_CHECK will report that no acceptable program
# was found, and abort.  If a suitable $ac_path_VARIABLE is found in the
# FEATURE-TEST macro, it can set $ac_path_VARIABLE_found=':' to accept
# that value without any further checks.
m4_define([_AC_PATH_PROG_FEATURE_CHECK],
[# Extract the first word of "$2" to use in msg output
if test -z "$$1"; then
set dummy $2; ac_prog_name=$[2]
AC_CACHE_VAL([ac_cv_path_$1],
[ac_path_$1_found=false
# Loop through the user's path and test for each of PROGNAME-LIST
_AS_PATH_WALK([$4],
[for ac_prog in $2; do
  for ac_exec_ext in '' $ac_executable_extensions; do
    ac_path_$1="$as_dir/$ac_prog$ac_exec_ext"
    AS_EXECUTABLE_P(["$ac_path_$1"]) || continue
    $3
    $ac_path_$1_found && break 3
  done
done
])
])
$1="$ac_cv_path_$1"
if test -z "$$1"; then
  AC_MSG_ERROR([no acceptable $ac_prog_name could be found in dnl
m4_default([$4], [\$PATH])])
fi
AC_SUBST([$1])
else
  ac_cv_path_$1=$$1
fi
])



# _AC_PATH_PROG_FLAVOR_GNU(PROGRAM-PATH, IF-SUCCESS, [IF-FAILURE])
# ----------------------------------------------------------------
m4_define([_AC_PATH_PROG_FLAVOR_GNU],
[# Check for GNU $1
case `"$1" --version 2>&1` in
*GNU*)
  $2;;
m4_ifval([$3],
[*)
  $3;;
])esac
])# _AC_PATH_PROG_FLAVOR_GNU



# _AC_PROG_GREP(VARIABLE, PROGNAME-LIST, PROG-ARGUMENTS)
# ------------------------------------------------------
# Solaris 9 /usr/xpg4/bin/*grep is suitable, but /usr/bin/*grep lacks -e.
# AIX silently truncates long lines before matching.
# NeXT understands only one -e and truncates long lines.
m4_define([_AC_PROG_GREP],
[_AC_PATH_PROG_FEATURE_CHECK([$1], [$2],
	[_AC_FEATURE_CHECK_LENGTH([ac_path_$1], [ac_cv_path_$1],
		["$ac_path_$1" $3], [$1])], [$PATH$PATH_SEPARATOR/usr/xpg4/bin])
])



# AC_PROG_GREP
# ------------
# Check for a fully functional grep program that handles
# the longest lines possible and which respects multiple -e options.
# Prefer GNU grep if found.
AC_DEFUN([AC_PROG_GREP],
[AC_CACHE_CHECK([for grep that handles long lines and -e], ac_cv_path_GREP,
   [_$0(GREP, [grep ggrep], [-e 'GREP$' -e '-(cannot match)-'])])
 GREP="$ac_cv_path_GREP"
 AC_SUBST([GREP])
])



# AC_PROG_MKDIR_P
# ---------------
# Check whether `mkdir -p' is known to be thread-safe, and fall back to
# install-sh -d otherwise.
#
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
# created by `make install' are always world readable, even if the
# installer happens to have an overly restrictive umask (e.g. 077).
# This was a mistake.  There are at least two reasons why we must not
# use `-m 0755':
#   - it causes special bits like SGID to be ignored,
#   - it may be too restrictive (some setups expect 775 directories).
#
# Do not use -m 0755 and let people choose whatever they expect by
# setting umask.
#
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
# Some implementations (such as Solaris 8's) are vulnerable to race conditions:
# if a parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
# concurrently, both version can detect that a/ is missing, but only
# one can create it and the other will error out.  Consequently we
# restrict ourselves to known race-free implementations.
#
# Automake used to define mkdir_p as `mkdir -p .', in order to
# allow $(mkdir_p) to be used without argument.  As in
#   $(mkdir_p) $(somedir)
# where $(somedir) is conditionally defined.  However we don't do
# that for MKDIR_P.
#  1. before we restricted the check to GNU mkdir, `mkdir -p .' was
#     reported to fail in read-only directories.  The system where this
#     happened has been forgotten.
#  2. in practice we call $(MKDIR_P) on directories such as
#       $(MKDIR_P) "$(DESTDIR)$(somedir)"
#     and we don't want to create $(DESTDIR) if $(somedir) is empty.
#     To support the latter case, we have to write
#       test -z "$(somedir)" || $(MKDIR_P) "$(DESTDIR)$(somedir)"
#     so $(MKDIR_P) always has an argument.
#     We will have better chances of detecting a missing test if
#     $(MKDIR_P) complains about missing arguments.
#  3. $(MKDIR_P) is named after `mkdir -p' and we don't expect this
#     to accept no argument.
#  4. having something like `mkdir .' in the output is unsightly.
#
# On NextStep and OpenStep, the `mkdir' command does not
# recognize any option.  It will interpret all options as
# directories to create.
AN_MAKEVAR([MKDIR_P], [AC_PROG_MKDIR_P])
AC_DEFUN([AC_PROG_MKDIR_P],
[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
AC_REQUIRE_AUX_FILE([install-sh])dnl
AC_MSG_CHECKING([for a thread-safe mkdir -p])
if test -z "$MKDIR_P"; then
  AC_CACHE_VAL([ac_cv_path_mkdir],
    [_AS_PATH_WALK([$PATH$PATH_SEPARATOR/opt/sfw/bin],
      [for ac_prog in mkdir gmkdir; do
	 for ac_exec_ext in '' $ac_executable_extensions; do
	   AS_EXECUTABLE_P(["$as_dir/$ac_prog$ac_exec_ext"]) || continue
	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
	     'mkdir (GNU coreutils) '* | \
	     'mkdir (coreutils) '* | \
	     'mkdir (fileutils) '4.1*)
	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
	       break 3;;
	   esac
	 done
       done])])
  if test "${ac_cv_path_mkdir+set}" = set; then
    MKDIR_P="$ac_cv_path_mkdir -p"
  else
    # As a last resort, use the slow shell script.  Don't cache a
    # value for MKDIR_P within a source directory, because that will
    # break other packages using the cache if that directory is
    # removed, or if the value is a relative name.
    test -d ./--version && rmdir ./--version
    MKDIR_P="$ac_install_sh -d"
  fi
fi
dnl Do special magic for MKDIR_P instead of AC_SUBST, to get
dnl relative names right.
AC_MSG_RESULT([$MKDIR_P])
dnl Fix added by YP for ABINIT: do AC_SUBST!
AC_SUBST(MKDIR_P)
])# AC_PROG_MKDIR_P



# AC_PROG_SED
# -----------
# Check for a fully functional sed program that truncates
# as few characters as possible.  Prefer GNU sed if found.
AC_DEFUN([AC_PROG_SED],
[AC_CACHE_CHECK([for a sed that does not truncate output], ac_cv_path_SED,
    [dnl ac_script should not contain more than 99 commands (for HP-UX sed),
     dnl but more than about 7000 bytes, to catch a limit in Solaris 8 /usr/ucb/sed.
     ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
     for ac_i in 1 2 3 4 5 6 7; do
       ac_script="$ac_script$as_nl$ac_script"
     done
     echo "$ac_script" | sed 99q >conftest.sed
     $as_unset ac_script || ac_script=
     _AC_PATH_PROG_FEATURE_CHECK(SED, [sed gsed],
	[_AC_FEATURE_CHECK_LENGTH([ac_path_SED], [ac_cv_path_SED],
		["$ac_path_SED" -f conftest.sed])])])
 SED="$ac_cv_path_SED"
 AC_SUBST([SED])dnl
 rm -f conftest.sed
])# AC_PROG_SED



# AC_REQUIRE_AUX_FILE(FILE)
# -------------------------
# This macro does nothing, it's a hook to be read with `autoconf --trace'.
# It announces FILE is required in the auxdir.
m4_define([AC_REQUIRE_AUX_FILE],
[AS_LITERAL_IF([$1], [],
	       [AC_FATAL([$0: requires a literal argument])])])
"""



def translate_version(version_string):

 # Init
 ret = version_string
 ret = ret.split(".")

 # Force x.y.z version numbers
 while ( len(ret) < 3 ):
  ret.append("0")
 if ( len(ret) > 3 ):
  ret = ret[0:3]

 # Force 2 digits
 for i in range(len(ret)):
  try:
   if ( int(ret[i]) < 10 ):
    ret[i] = "0"+ret[i]
   elif ( int(ret[i]) > 99 ):
    sys.stderr.write("%s: Error: cannot handle 3-digit version numbers\n" % (my_name))
    sys.exit(1)
  except ValueError:
   sys.stderr.write("%s: WARNING: invalid version number %s set to 0\n" % (my_name,ret[i]))
   ret[i] = "00"

 # Finish
 ret = int("".join(ret))

 return ret



# ---------------------------------------------------------------------------- #

#
# Main program
#

# Initial setup
my_name    = "make-macros-autotools"
my_output  = "config/m4/do-not-edit-autotools.m4"

# Check if we are in the top of the ABINIT source tree
if ( not os.path.exists("configure.ac") or
     not os.path.exists("src/main/abinit.F90") ):
 print "%s: You must be in the top of an ABINIT source tree." % my_name
 print "%s: Aborting now." % my_name
 sys.exit(1)

# What time is it?
now = strftime("%Y/%m/%d %H:%M:%S +0000",gmtime())

# Get Autotools versions
(m4_ret,m4_version) = commands.getstatusoutput("m4 --version")
(ac_ret,ac_version) = commands.getstatusoutput("autoconf --version")
(am_ret,am_version) = commands.getstatusoutput("automake --version")
(lt_ret,lt_version) = commands.getstatusoutput("libtool  --version")

# Extract and process version numbers
if ( m4_ret == 0 ):
 m4_version = m4_version.split("\n")[0]
 m4_version = re.sub(r"^(GNU [Mm]4|m4 \(GNU M4\)) ","",m4_version)
 m4_version = re.sub(" .*","",m4_version)
 m4_version = translate_version(m4_version)
else:
 m4_version = 0

if ( ac_ret == 0 ):
 ac_version = ac_version.split("\n")[0]
 ac_version = re.sub(".*\(GNU Autoconf\) ","",ac_version)
 ac_version = re.sub(" .*","",ac_version)
 ac_version = translate_version(ac_version)
else:
 ac_version = 0

if ( am_ret == 0 ):
 am_version = am_version.split("\n")[0]
 am_version = re.sub(".*\(GNU automake\) ","",am_version)
 am_version = re.sub(" .*","",am_version)
 am_version = translate_version(am_version)
else:
 am_version = 0

if ( lt_ret == 0 ):
 lt_version = lt_version.split("\n")[0]
 lt_version = re.sub(".*\(GNU libtool\) ","",lt_version)
 lt_version = re.sub(" .*","",lt_version)
 lt_version = translate_version(lt_version)
else:
 lt_version = 0

if ( m4_version < 10400 ):
 sys.stderr.write("%s: Error: M4 is too old - " % (my_name) \
  + "please install v1.4 or above\n%s: Aborting now\n" % (my_name))
 sys.exit(10)

if ( ac_version < 25900 ):
 sys.stderr.write("%s: Error: Autoconf is too old - " % (my_name) \
  + "please install v2.59 or above\n%s: Aborting now\n" % (my_name))
 sys.exit(20)

if ( am_version < 10900 ):
 sys.stderr.write("%s: Error: Automake is too old - " % (my_name) \
  + "please install v1.9 or above\n%s: Aborting now\n" % (my_name))
 sys.exit(30)

# Write macros
m4 = file(my_output,"w")
m4.write(macro_header(my_name,now))
m4.write(macro_info(m4_version,ac_version,am_version,lt_version))
m4.write(macro_init_dirs(ac_version))
if ( ac_version < 26000 ):
 m4.write(macros_autoconf())
m4.close()

# Make version information available to makemake
ai = file("config/local/autotools.sh","w")
ai.write("""# Autotools version information
abi_m4_version="%6.6d"
abi_ac_version="%6.6d"
abi_am_version="%6.6d"
abi_lt_version="%6.6d"
""" % (m4_version,ac_version,am_version,lt_version))
ai.close()

tmp = commands.getoutput("./config/scripts/add-header-typed Autoconf %s" % (my_output))
if ( tmp != "" ):
 print tmp
