#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
#
### Copyright (C) 2015-2020 Olaf Till <i7tiol@t-online.de>
###
### This program is free software; you can redistribute it and/or
### modify it under the terms of the GNU General Public License as
### published by the Free Software Foundation; either version 3 of the
### License, or (at your option) any later version.
###
### This program is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
### General Public License for more details.
###
### You should have received a copy of the GNU General Public License
### along with this program; if not, see
### <http://www.gnu.org/licenses/>.


AC_PREREQ(2.63)
AC_INIT(parallel, 4.0.0, i7tiol@t-online.de)
AC_CONFIG_SRCDIR([pconnect.cc])
AC_CONFIG_HEADERS([config.h])

# Avoid warnings for redefining AH-generated preprocessor symbols of
# Octave.
AH_TOP([#include "undef-ah-octave.h"])

AC_CONFIG_MACRO_DIRS([m4 gl/m4])

AM_INIT_AUTOMAKE

# Checks for programs.
AC_CHECK_PROG(MKOCTFILE, mkoctfile, mkoctfile)
if test -z "$MKOCTFILE"; then
AC_MSG_ERROR([mkoctfile not found], 1);
fi
AC_CHECK_PROG(OCTAVE_CONFIG, octave-config, octave-config)
if test -z "$OCTAVE_CONFIG"; then
AC_MSG_ERROR([octave-config not found], 1);
fi

AC_PROG_SED

# The same value of CXX as Octave was compiled with is supposed to be
# used.
CXX=${CXX:-`${MKOCTFILE} -p CXX`}
# The AC_PROG_CXX macro is locally defined to a recent version which
# checks for C++11. If necessary, a suitable option is appended to
# CXX.
AC_PROG_CXX
# Require C++11.
if test "x$ac_prog_cxx_stdcxx" != "xcxx11"; then
  AC_MSG_ERROR([could not enforce using C++11 features])
fi

AC_PROG_CXXCPP

AC_PROG_CC

gl_EARLY

gl_INIT

## The first AC_CHECK_HEADER should be called unconditionally, since
## this macro arranges some preconditions only the first time it is
## expanded.
AC_CHECK_HEADER([gnutls/gnutls.h])

# Checks for gnutls libraries.
if test "x$ac_cv_header_gnutls_gnutls_h" = "xyes"; then
  AC_CHECK_LIB([gnutls], [gnutls_global_init], [[echo -n ""]])
  if test "x$ac_cv_lib_gnutls_gnutls_global_init" = "xyes"; then
    LIBS="-lgnutls $LIBS"
    AC_CHECK_PROG(PKG_CONFIG, pkg-config, pkg-config)
    if test -z "$PKG_CONFIG"; then
      AC_SUBST([HAVE_GNUTLS], [no])
      AC_MSG_WARN([TLS disabled since pkg-config not found])
    else
      AC_LINK_IFELSE(
        [AC_LANG_PROGRAM([[#include <gnutls/gnutls.h>]
                          [#include <stdio.h>]],
                         [[printf ("%u", gnutls_srp_2048_group_prime.size);]])],
        [AC_DEFINE([HAVE_LIBGNUTLS], 1,
          [Define as 1 if gnutls library is present.])
         AC_SUBST([HAVE_GNUTLS], [yes])
         AC_COMPILE_IFELSE(
           [AC_LANG_PROGRAM([[#include <gnutls/gnutls.h>]],
                            [[const gnutls_datum_t *dat = NULL;]
                             [gnutls_datum_t *res = NULL;]
                             [gnutls_srp_base64_decode2 (dat, res);]])],
           [AC_DEFINE([HAVE_GNUTLS_SRP_BASE64_DECODE2], 1,
             [Define as 1 if libgnutls has gnutls_srp_base64_decode2])])],
        [AC_SUBST([HAVE_GNUTLS], [no])
         AC_MSG_WARN([TLS disabled since symbol gnutls_srp_2048_group_prime not found in gnutls library - built with --disable-srp-authentication?])])  
    fi
    AC_CHECK_LIB([gnutls-extra], [gnutls_global_init_extra], [[echo -n ""]])
    if test "x$ac_cv_lib_gnutls_extra_gnutls_global_init_extra" = "xyes"; then
      LIBS="-lgnutls-extra $LIBS"
      AC_DEFINE([HAVE_LIBGNUTLS_EXTRA], 1,
        [Define as 1 if gnutls extra library is present.])
      AC_SUBST([HAVE_GNUTLS_EXTRA], [yes])
    else
      AC_SUBST([HAVE_GNUTLS_EXTRA], [no])
    fi
  else
    AC_SUBST([HAVE_GNUTLS], [no])
    AC_MSG_WARN([TLS disabled since no gnutls library found])
  fi
else
  AC_SUBST([HAVE_GNUTLS], [no])
  AC_MSG_WARN([TLS disabled since gnutls/gnutls.h not found or not compilable])
fi

# Checks for header files.
AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h sys/malloc.h netdb.h netinet/in.h stdio_ext.h stdlib.h string.h sys/time.h termios.h unistd.h error.h])
if test "x$ac_cv_header_malloc_h" = "xno"; then
  if test "x$ac_cv_header_sys_malloc_h" = "xno"; then
    AC_MSG_ERROR([neither malloc.h nor sys/malloc.h found])
  fi
fi

# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_TYPE_INT32_T
AC_TYPE_MODE_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T
AC_TYPE_UINT32_T

# Checks for library functions.
AC_FUNC_ERROR_AT_LINE
AC_FUNC_FORK
AC_FUNC_FSEEKO
AC_FUNC_MALLOC
AC_TYPE_SIGNAL
AC_CHECK_FUNCS([memset mkdir modf strchr strdup], ,
  [AC_MSG_ERROR([required system functions not found])])
AC_CHECK_FUNC([getpass])
if test "x$ac_cv_func_getpass" = "xyes"; then
  AC_DEFINE([HAVE_GETPASS], 1,
    [Define as 1 if getpass function is present.])
  AC_SUBST([HAVE_GETPASS], [yes])
else
  AC_SUBST([HAVE_GETPASS], [no])
fi
AC_CHECK_FUNC([fexecve])
if test "x$ac_cv_func_fexecve" = "xyes"; then
  AC_DEFINE([HAVE_FEXECVE], 1,
    [Define as 1 if fexecve function is present.])
fi
AC_CHECK_FUNC([uname])

if test "x$ac_cv_func_fork_works" = "xyes" \
   && test "x$ac_cv_func_uname" = "xyes" \
   && test "x$ac_cv_header_error_h" = "xyes"; then
  AC_SUBST([REDUCED_BUILD], [no])
else
  AC_SUBST([REDUCED_BUILD], [yes])
  AC_MSG_WARN([No working fork(), no uname(), or no error.h found. On such platforms, notably Windows and macOS, the remote Octave server will not be built. The functions for accessing a remote Octave server are not affected by this and may still be built, as well as the functions for local parallel execution.])
fi

# Start of checks for Octave features, preparations for checks.
OCTLIBDIR=${OCTLIBDIR:-`$OCTAVE_CONFIG -p OCTLIBDIR`}
## We need Octaves include path both with and without '/octave'
## appended. The path without '/octave' is needed to selectively test
## for Octave headers, like octave/....h. The path with '/octave' is
## needed since some Octave headers contain include directives for
## other Octave headers with <> instead of "".
OCTINCLUDEDIR=${OCTINCLUDEDIR:-`$MKOCTFILE -p INCFLAGS`}
AC_LANG_PUSH([C++])
TCXXFLAGS=$CXXFLAGS
TLDFLAGS=$LDFLAGS
TLIBS=$LIBS
TCPPFLAGS=$CPPFLAGS
LDFLAGS="-L$OCTLIBDIR $LDFLAGS"
LIBS="-loctinterp $LIBS"
# CXXFLAGS=
CPPFLAGS="$OCTINCLUDEDIR $CPPFLAGS"

## Presence of 'error_state' -- does _not_ indicate no exceptions are
## used.
AC_LINK_IFELSE(
  [AC_LANG_PROGRAM([[#include <octave/oct.h>]
                    [#include <stdio.h>]],
                   [[printf ("%i", error_state);]])],
  [AC_DEFINE([HAVE_OCTAVE_ERROR_STATE], 1,
    [Define as 1 if liboctinterp is old enough to provide error_state.])])

## Presence of 'verror (octave_execution_exception&, const char *,
## va_list)'
AC_LINK_IFELSE(
  [AC_LANG_PROGRAM([[#include <octave/oct.h>]],
                   [[octave_execution_exception e;]
                    [va_list args;]
                    [verror (e, "test", args);]])],
  [AC_DEFINE([HAVE_OCTAVE_VERROR_ARG_EXC], 1,
    [Define as 1 if liboctinterp has
'verror (octave_execution_exception&, const char *, va_list)'.])])

## Presence of octave/interpreter.h. If present, we assume that
## octave/call-stack.h is also present. Code corresponding to both of
## them was formerly in octave/toplev.h, the latter being now
## deprecated. Setting CPPFLAGS is necessary for the tests in
## OF_OCTAVE_LIST_ALT_SYMS to work correctly without messing up the
## result of the current test.
AC_CHECK_HEADERS([octave/interpreter.h],
                 [CPPFLAGS="-include octave/interpreter.h -include octave/call-stack.h $CPPFLAGS"])

## Presence of octave/dirfns.h
AC_CHECK_HEADERS([octave/dirfns.h])

## Simple symbol alternatives of different Octave versions.
OF_OCTAVE_LIST_ALT_SYMS([
[dnl
  [octave_execution_exception],
  [octave::execution_exception],
  [[octave::execution_exception ();]],
  [OCTAVE__EXECUTION_EXCEPTION],
  [],
  []
],

[dnl
  [file_ops],
  [octave::sys::file_ops],
  [[octave::sys::file_ops::dir_sep_str ();]],
  [OCTAVE__SYS__FILE_OPS],
  [[#include <octave/file-ops.h>]],
  [[#include <octave/file-ops.h>]]
],

dnl  include directive for old version is conditionally given by a
dnl  separate test
[dnl
  [octave::application],
  [octave::interpreter],
  [[octave::interpreter::the_interpreter ();]],
  [OCTAVE__INTERPRETER],
  [],
  []
],

[dnl
  [symbol_table::assign],
  [octave::interpreter::the_interpreter () -> get_symbol_table ().assign],
  [[octave::interpreter::the_interpreter () -> get_symbol_table ();]],
  [OCTAVE__INTERPRETER__SYMBOL_TABLE__ASSIGN],
  [[#include <octave/symtab.h>]],
  []
],

[dnl
  [symbol_table::is_global],
  [octave::interpreter::the_interpreter () -> get_current_scope ().is_global],
  [[octave::interpreter::the_interpreter () -> get_current_scope ();]],
  [OCTAVE__INTERPRETER__CURRENT_SCOPE__IS_GLOBAL],
  [[#include <octave/symtab.h>]],
  []
],

[dnl
  [oct_mach_info],
  [octave::mach_info],
  [[int f = octave::mach_info::flt_fmt_unknown;]],
  [OCTAVE__MACH_INFO],
  [],
  []
],

[dnl
  [octave_stream_list::get_file_number],
  [octave::interpreter::the_interpreter () -> get_stream_list ().get_file_number],
  [[octave::interpreter::the_interpreter () -> get_stream_list ();]],
  [OCTAVE__INTERPRETER__STREAM_LIST__GET_FILE_NUMBER],
  [[#include <octave/oct-stream.h>]],
  [[#include <octave/oct-stream.h>]]
],

[dnl
  [octave_stream_list::lookup],
  [octave::interpreter::the_interpreter () -> get_stream_list ().lookup],
  [[octave::interpreter::the_interpreter () -> get_stream_list ();]],
  [OCTAVE__INTERPRETER__STREAM_LIST__LOOKUP],
  [[#include <octave/oct-stream.h>]],
  [[#include <octave/oct-stream.h>]]
],

[dnl
  [octave_child_list::],
  [octave::interpreter::the_interpreter () -> get_child_list ().],
  [[octave::interpreter::the_interpreter () -> get_child_list ();]],
  [OCTAVE_CHILD_LIST],
  [[#include <octave/sighandlers.h>]],
  [[#include <octave/sighandlers.h>]]
],

[dnl
  [octave_call_stack::goto_caller_frame],
  [octave::interpreter::the_interpreter () -> get_call_stack ().goto_caller_frame],
  [[octave::interpreter::the_interpreter () -> get_call_stack ();]],
  [OCTAVE__INTERPRETER__CALL_STACK__GOTO_CALLER_FRAME],
  [],
  []
],

[dnl
  [last_error_id],
  [octave::interpreter::the_interpreter ()->get_error_system ().last_error_id],
  [[octave::interpreter::the_interpreter ()->get_error_system ().last_error_id ();]],
  [OCTAVE__INTERPRETER__GET_ERROR_SYSTEM__LAST_ERROR_ID],
  [],
  []
],

[dnl
  [last_error_message],
  [octave::interpreter::the_interpreter ()->get_error_system ().last_error_message],
  [[octave::interpreter::the_interpreter ()->get_error_system ().last_error_message ();]],
  [OCTAVE__INTERPRETER__GET_ERROR_SYSTEM__LAST_ERROR_MESSAGE],
  [],
  []
],

[dnl
  [unwind_protect],
  [octave::unwind_protect],
  [[octave::unwind_protect frame;]],
  [OCTAVE__UNWIND_PROTECT],
  [],
  []
],

[dnl
  [is_empty],
  [isempty],
  [[octave_value ().isempty ();]],
  [OV_ISEMPTY],
  [],
  []
],

[dnl
  [is_integer_type],
  [isinteger],
  [[octave_value ().isinteger ();]],
  [OV_ISINTEGER],
  [],
  []
],

[dnl
  [is_cell],
  [iscell],
  [[octave_value ().iscell ();]],
  [OV_ISCELL],
  [],
  []
],

[dnl
  [is_real_type],
  [isreal],
  [[octave_value ().isreal ();]],
  [OV_ISREAL],
  [],
  []
],

[dnl
  [is_vector],
  [isvector],
  [[idx_vector ().isvector ();]],
  [IDXVECTOR_ISVECTOR],
  [],
  []
],

[dnl
  [octave_stream],
  [octave::stream],
  [[octave::stream ();]],
  [OCTAVE__STREAM],
  [[#include <octave/oct-stream.h>]],
  [[#include <octave/oct-stream.h>]]
],

[dnl
  [octave_refcount],
  [octave::refcount],
  [[octave::refcount<int> (0);]],
  [OCTAVE__REFCOUNT],
  [[#include <octave/oct-refcount.h>]],
  [[#include <octave/oct-refcount.h>]]
],

[dnl
  [feval],
  [octave::feval],
  [[octave::feval ("date");]],
  [[OCTAVE__FEVAL], [octave__feval]],
  [[#include <octave/parse.h>]],
  [[#include <octave/parse.h>]]
],

dnl test if feval accepts octave_value as first argument, otherwise
dnl define a macro to extract function_value() from octave_value
[dnl
  [ov.function_value ()],
  [ov],
  [[octave_value fcn;]
   [octave_value_list args, out_val;]
   [out_val = ${octave__feval} (fcn, args, 0);]],
  [MAYBE_FUNCTION_VALUE(ov)],
  [[#include <octave/parse.h>]],
  [[#include <octave/parse.h>]]
],

[dnl
  [file_stat],
  [octave::sys::file_stat],
  [[octave::sys::file_stat ();]],
  [OCTAVE__SYS__FILE_STAT],
  [],
  [[#include <octave/file-stat.h>]]
],

[dnl
  [add_fcn (octave_call_stack::pop)],
  [add_method (octave::interpreter::the_interpreter () -> get_call_stack (), &octave::call_stack::pop)],
  [[octave::interpreter::the_interpreter () -> get_call_stack ();]],
  [ADD_OCTAVE__INTERPRETER__CALL_STACK__POP],
  [],
  []
],

[dnl
  [octave_vformat],
  [octave::vformat],
  [[std::ostringstream obuf;]
   [va_list args;]
   [octave::vformat (obuf, "dummy", args);]],
  [OCTAVE__VFORMAT],
  [],
  []
],

[dnl
  [command_editor],
  [octave::command_editor],
  [[octave::command_editor::increment_current_command_number ();]],
  [OCTAVE__COMMAND_EDITOR],
  [[#include <octave/cmd-edit.h>]],
  [[#include <octave/cmd-edit.h>]]
],

[dnl
  [octave_env],
  [octave::sys::env],
  [[octave::sys::env::get_current_directory ();]],
  [OCTAVE__SYS__ENV],
  [[#include <octave/oct-env.h>]],
  [[#include <octave/oct-env.h>]]
],

[dnl
  [Vbin_dir],
  [octave::config::bin_dir ()],
  [[octave::config::bin_dir ();]],
  [OCTAVE__CONFIG__BIN_DIR],
  [[#include <octave/defaults.h>]],
  [[#include <octave/defaults.h>]]
],

[dnl
  [octave_syscalls],
  [octave::sys],
  [[octave::sys::getpid ();]],
  [OCTAVE__SYS],
  [[#include <octave/oct-syscalls.h>]],
  [[#include <octave/oct-syscalls.h>]]
]

],
   [oct-alt-includes.h])

AC_MSG_CHECKING([for octave::config::octave_home ()])
  AC_COMPILE_IFELSE(
    [AC_LANG_PROGRAM([[#include <octave/oct.h>]
                      [#include <octave/defaults.h>]],
                     [octave::config::octave_home ();])],
    [AC_DEFINE([HAVE_OCTAVE_CONFIG_FCNS], 1,
               [Define to 1 if you have octave::config::octave_home ()])
     AC_MSG_RESULT([yes])
     echo '#include <octave/defaults.h>' >> oct-alt-includes.h],
    [AC_MSG_RESULT([no])]
  )

AC_MSG_CHECKING([for eval_string])
  AC_COMPILE_IFELSE(
    [AC_LANG_PROGRAM([[#include <octave/oct.h>]],
                     [std::string cmd ("date"); int p_err; octave::interpreter::the_interpreter () -> eval_string (cmd, false, p_err, 0);])],
    [AC_DEFINE([OCTAVE__EVAL_STRING], [octave::interpreter::the_interpreter () -> eval_string],
               [macro for alternatives to octave::eval_string])
     AC_MSG_RESULT([octave::interpreter::eval_string])],
    [AC_COMPILE_IFELSE(
      [AC_LANG_PROGRAM([[#include <octave/oct.h>]
                        [#include <octave/parse.h>]],
                       [int p_err; octave::eval_string ("date", false, p_err, 0);])],
      [AC_DEFINE([OCTAVE__EVAL_STRING], [octave::eval_string],
                 [macro for alternatives to octave::eval_string])
       AC_MSG_RESULT([octave::eval_string])
       echo '#include <octave/parse.h>' >> oct-alt-includes.h],
      [AC_DEFINE([OCTAVE__EVAL_STRING], [eval_string],
                 [macro for alternatives to octave::eval_string])
       AC_MSG_RESULT([eval_string])
       echo '#include <octave/parse.h>' >> oct-alt-includes.h])]
)

AC_MSG_CHECKING([for recover_from_exception])
  AC_COMPILE_IFELSE(
    [AC_LANG_PROGRAM([[#include <octave/oct.h>]],
                     [octave::interpreter::the_interpreter ()->recover_from_exception ();])],
    [AC_DEFINE([OCTAVE__INTERPRETER__RECOVER_FROM_EXCEPTION], [octave::interpreter::the_interpreter ()->recover_from_exception ()],
               [macro for alternatives to octave::interpreter::the_interpreter ()->recover_from_exception ()])
     AC_MSG_RESULT([octave::interpreter::the_interpreter ()->recover_from_exception ()])],
    [AC_COMPILE_IFELSE(
      [AC_LANG_PROGRAM([[#include <octave/oct.h>]],
                       [recover_from_exception ();])],
      [AC_DEFINE([OCTAVE__INTERPRETER__RECOVER_FROM_EXCEPTION], [recover_from_exception ()],
                 [macro for alternatives to octave::interpreter::the_interpreter ()->recover_from_exception ()])
       AC_MSG_RESULT([recover_from_exception ()])],
      [AC_DEFINE([OCTAVE__INTERPRETER__RECOVER_FROM_EXCEPTION], [],
                 [macro for alternatives to octave::interpreter::the_interpreter ()->recover_from_exception ()])
       AC_MSG_RESULT([<empty>])])]
)

LIBS=$TLIBS
LDFLAGS=$TLDFLAGS
CXXFLAGS=$TCXXFLAGS
CPPFLAGS=$TCPPFLAGS
AC_LANG_POP([C++])
# End of checks for Octave features.

AC_CONFIG_FILES([Makefile gl/Makefile])
AC_OUTPUT

AH_BOTTOM([#ifndef EXTERNAL_BINARY
#include "custom.h"
#endif])
