# -*- autoconf -*-
#########################################
##
# Checks for library functions.
##
#########################################
#
# Portions of this file are copyrighted by:
# Copyright (c) 2016 VMware, Inc. All rights reserved.
# Use is subject to license terms specified in the COPYING file
# distributed with the Net-SNMP package.

##
#   Standard checks:
##
AC_FUNC_ALLOCA          #  alloca()
AC_PROG_GCC_TRADITIONAL

AC_TYPE_SIGNAL

##
#   Stand-alone function checks:
##
#  Core:
AC_CHECK_FUNCS([rand   random srand srandom lrand48 srand48])

#  Library:
AC_CHECK_FUNCS([asprintf        closedir        fgetc_unlocked   ] dnl
               [flockfile       funlockfile     getipnodebyname  ] dnl
               [gettimeofday    getlogin                         ] dnl
               [if_nametoindex  mkstemp                          ] dnl
               [opendir         readdir         regcomp          ] dnl
               [setenv          setitimer       setlocale        ] dnl
               [setsid          snprintf        strcasestr       ] dnl
               [strdup          strerror        strncasecmp      ] dnl
               [sysconf         times           vsnprintf        ] )

AC_MSG_CHECKING([for _NSGetArgv()])
AC_LINK_IFELSE(
  [AC_LANG_PROGRAM([#include <crt_externs.h>], [return _NSGetArgv])],
  [AC_DEFINE([HAVE__NSGETARGV], [1],
    [Define to 1 if you have the `_NSGetArgv' function.])
    AC_MSG_RESULT([yes])
  ],
  [AC_MSG_RESULT([no])]
)

AC_MSG_CHECKING([for _NSGetExecutablePath()])
AC_LINK_IFELSE(
  [AC_LANG_PROGRAM([#include <mach-o/dyld.h>], [return _NSGetExecutablePath])],
  [AC_DEFINE([HAVE__NSGETEXECUTABLEPATH], [1],
    [Define to 1 if you have the `_NSGetExecutablePath' function.])
    AC_MSG_RESULT([yes])
  ],
  [AC_MSG_RESULT([no])]
)

# IPv4/IPv6 function checks. AC_CHECK_FUNC() can't find these on MinGW
# since these functions have the __cdecl calling convention on MinGW.
case x$with_socklib in
  xwinsock2)
    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <winsock2.h>],
    [ closesocket(0); ])],
    [ ac_cv_func_closesocket=yes
      AS_ECHO "#define HAVE_CLOSESOCKET 1" >>confdefs.h
    ], [ ])

    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <ws2tcpip.h>],
    [ gai_strerror(0); ])],
    [ ac_cv_func_gai_strerror=yes
      AS_ECHO "#define HAVE_GAI_STRERROR 1" >>confdefs.h
    ], [ ])

    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <ws2tcpip.h>],
    [ getaddrinfo(NULL, NULL, NULL, NULL); ])],
    [ ac_cv_func_getaddrinfo=yes
      AS_ECHO "#define HAVE_GETADDRINFO 1" >>confdefs.h
    ], [ ])

    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <winsock2.h>],
    [ gethostbyname(NULL); ])],
    [ ac_cv_func_gethostbyname=yes
      AS_ECHO "#define HAVE_GETHOSTBYNAME 1" >>confdefs.h
    ], [ ])

    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <winsock2.h>],
    [ gethostbyaddr(NULL); ])],
    [ ac_cv_func_gethostbyaddr=yes
      AS_ECHO "#define HAVE_GETHOSTBYADDR 1" >>confdefs.h
    ], [ ])

    AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <winsock2.h>],
    [ gethostname(NULL, 0); ])],
    [ ac_cv_func_gethostname=yes
      AS_ECHO "#define HAVE_GETHOSTNAME 1" >>confdefs.h
    ], [ ])
    ;;

  *)
    # Do not use fork() nor any related function when using Windows sockets
    # because Windows sockets are not compatible with fork().
    AC_CHECK_FUNCS([execv fork signal sigset uname]dnl
                   [closesocket gai_strerror getaddrinfo gethostbyname]dnl
                   [gethostbyname2 gethostname gethostbyaddr]dnl
                   [inet_ntop inet_pton])
    ;;
esac

# Check for MSVC functions.
AC_MSG_CHECKING([for _beginthreadex()])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <stddef.h>
#include <process.h>
], [ _beginthreadex(NULL, 0, NULL, NULL, 0, NULL); ])],
[AC_MSG_RESULT([yes])
 AC_DEFINE([HAVE__BEGINTHREADEX], [1],
           [Define if _beginthreadex() is defined in <process.h>])],
[AC_MSG_RESULT([no])])

AC_MSG_CHECKING([for _cputs()])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <conio.h>],[ _cputs(0); ])],
[AC_MSG_RESULT([yes])
 AC_DEFINE([HAVE__CPUTS], [1],
           [Define if _cputs() is defined in <conio.h>])],
[AC_MSG_RESULT([no])])

AC_MSG_CHECKING([for _get_osfhandle()])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <io.h>],[ _get_osfhandle(0); ])],
[AC_MSG_RESULT([yes])
 AC_DEFINE([HAVE__GET_OSFHANDLE], [1],
           [Define if _get_osfhandle() is defined in <io.h>])],
[AC_MSG_RESULT([no])])

AC_MSG_CHECKING([for _getch()])
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <conio.h>],[ return _getch(); ])],
[AC_MSG_RESULT([yes])
 AC_DEFINE([HAVE__GETCH], [1],
           [Define if _getch() is defined in <conio.h>])],
[AC_MSG_RESULT([no])])

AC_MSG_CHECKING([for _open_osfhandle()])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <stddef.h>
#include <io.h>
], [ _open_osfhandle(NULL, 0); ])],
[AC_MSG_RESULT([yes])
 AC_DEFINE([HAVE__OPEN_OSFHANDLE], [1],
           [Define if _open_osfhandle() is defined in <io.h>])],
[AC_MSG_RESULT([no])])


AC_CONFIG_LIBOBJ_DIR([snmplib])

AC_REPLACE_FUNCS([getopt                                       ] dnl
                 [strlcat       strlcpy       strtok_r         ] dnl
                 [strtol        strtoul       strtoull         ] )

#  Agent:
AC_CHECK_FUNCS([cgetnext        chown          forkall         ] dnl
               [fsync           gai_strerror   getgrnam        ] dnl
               [gethostname     getloadavg                     ] dnl
               [getpid          getpwnam                       ] dnl
               [hasmntopt       initgroups                     ] dnl
               [if_nameindex    if_indextoname if_nametoindex  ] dnl
               [localtime_r     mkstemp        mktime          ] dnl
               [poll            regcomp                        ] dnl
               [setgid          setgroups                      ] dnl
               [setmntent       setuid                         ] dnl
               [sigaction       sigblock      sighold          ] dnl
               [sigprocmask                                    ] dnl
               [statfs          statvfs       stime            ] dnl
               [strncasecmp     system        usleep           ] )

#  Apps:
AC_CHECK_FUNCS([getdtablesize                                  ] dnl
               [getgrnam        getpid        getpwnam         ] dnl
               [setgid          setgroups     setuid           ] dnl
               [tcgetattr                                      ] )

#  Not-Used:
AC_CHECK_FUNCS([if_freenameindex              getpagesize      ] dnl
               [lseek64         pread64                        ] dnl
               [select          sigalrm       socket           ] )


##
#   More complex function checks:
#           (Agent)
##

#       rpmGetPath check needs clean LIBS environment   (Linux)
#
if test "x$with_rpm" != "xno"; then
    OLDLIBS=$LIBS
    LIBS=$LMIBLIBS
    AC_CHECK_FUNCS(rpmGetPath)
    LIBS=$OLDLIBS
fi

#       statfs( char *, struct fs_data* )               (Ultrix)
#
AC_MSG_CHECKING([[for two-argument statfs with struct fs_data (Ultrix)]])
AC_CACHE_VAL(
    fu_cv_sys_stat_fs_data,
    [AC_RUN_IFELSE([AC_LANG_SOURCE([[
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#include <sys/types.h>
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_FS_TYPES_H
#include <sys/fs_types.h>
#endif
main ()
{
struct fs_data fsd;
/* Ultrix's statfs returns 1 for success,
   0 for not mounted, -1 for failure.  */
exit (statfs (".", &fsd) != 1);
}]])],
    [fu_cv_sys_stat_fs_data=yes],
    [fu_cv_sys_stat_fs_data=no],
    [fu_cv_sys_stat_fs_data=no])])
AC_MSG_RESULT($fu_cv_sys_stat_fs_data)
if test $fu_cv_sys_stat_fs_data = yes; then
    AC_DEFINE(STAT_STATFS_FS_DATA, 1,
        [Define if statfs takes 2 args and the second argument has
         type struct fs_data. @<:@Ultrix@:>@])
fi


##
#   Other function-related checks:
#           (general build)
##

#       How to get the name of the current function
#
AC_CACHE_CHECK([how to get the name of the current function],
               [netsnmp_cv__func__name],[
    netsnmp_cv__func__name=no
    AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(,[[const char* cp = __func__;]])],
        [netsnmp_cv__func__name=__func__])
    if test "$netsnmp_cv__func__name" = no ; then
      AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM(,[[const char* cp = __FUNCTION__;]])],
        [netsnmp_cv__func__name=__FUNCTION__])
    fi])
if test "$netsnmp_cv__func__name" != no; then
    AC_DEFINE_UNQUOTED([NETSNMP_FUNCTION],[$netsnmp_cv__func__name],
        [Should evaluate to the name of the current function if defined])
fi


#       Whether static inline functions are broken      (SCO Unixware)
#
AC_CACHE_CHECK([[whether static inline functions are broken (Unixware)]],
                [netsnmp_cv_broken_inline],
    AC_COMPILE_IFELSE([AC_LANG_SOURCE([
static inline int nested_inline_function(void) {
  return 0;
}
inline int main_inline_function( void ) {
  return nested_inline_function();
}
    ])], [[
#       Yes -  static inline functions are broken       (Solaris 2.x)
#
case "$target_os" in
    solaris*)
        netsnmp_cv_broken_inline=yes
        ;;
    *)
        netsnmp_cv_broken_inline=no
        ;;
esac]], [
    netsnmp_cv_broken_inline=yes]
))

if test "$netsnmp_cv_broken_inline" = yes ; then
  AC_DEFINE(NETSNMP_BROKEN_INLINE, 1,
        [Define if static inline functions are unsupported])
fi


##
#   Mis-placed (non-function) checks:
##

AC_CACHE_CHECK([for SIOCGIFADDR in sys/ioctl.h],
               netsnmp_cv_sys_ioctl_h_has_SIOCGIFADDR,
    AC_COMPILE_IFELSE(
        [AC_LANG_PROGRAM([[
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifndef SIOCGIFADDR
No SIOCGIFADDR found here.
#endif
        ]])],
    [netsnmp_cv_sys_ioctl_h_has_SIOCGIFADDR=yes],
    [netsnmp_cv_sys_ioctl_h_has_SIOCGIFADDR=no]))
if test $netsnmp_cv_sys_ioctl_h_has_SIOCGIFADDR = yes; then
  AC_DEFINE(SYS_IOCTL_H_HAS_SIOCGIFADDR, 1,
   [define if SIOCGIFADDR exists in sys/ioctl.h])
fi

##
#   Check how to print a size_t variable
##

case x${host_cpu}-${host_vendor}-${host_os} in
  x*mingw*)
    # MinGW or MinGW-w64.
    AC_CACHE_CHECK(
      [the underlying type of size_t],
      [netsnmp_cv_size_t_type],
      [for TYPE in int long "long long" short char; do
        AC_COMPILE_IFELSE(
          [AC_LANG_PROGRAM([
            AC_INCLUDES_DEFAULT()
            extern unsigned $TYPE variable;
            extern size_t variable;
          ], [])],
          [netsnmp_cv_size_t_type="$TYPE"])
        if test "x$netsnmp_cv_size_t_type" != x; then break; fi
      done])

    AC_MSG_CHECKING([how to printf a size_t])
    case "$netsnmp_cv_size_t_type" in
      char|short|int)
        netsnmp_PRIz="";;
      long)
        netsnmp_PRIz="l";;
      "long long")
        netsnmp_PRIz="I64";;
      *)
        AC_MSG_ERROR([underlying type of size_t not known]);;
    esac
    AC_MSG_RESULT([$netsnmp_PRIz]);;
  *)
    # Unix or Cygwin.
    netsnmp_PRIz="z";;
esac
AC_DEFINE_UNQUOTED([NETSNMP_PRIz], ["$netsnmp_PRIz"],
                   [Size prefix to use to printf a size_t or ssize_t])

# check to see if the openssl is good enough for DTLS
# (BIO_dgram_get_peer is a macro, not a true function)
if echo " $transport_result_list " | $GREP "DTLS" > /dev/null; then
    AC_CACHE_VAL(
       netsnmp_cv_bio_dgram_get_peer,
       AC_MSG_CHECKING([[for BIO_dgram_get_peer]])
       [
        oldLIBS="$LIBS"
        LIBS="$LIBS -lcrypto"
        AC_LINK_IFELSE(
          [AC_LANG_PROGRAM(
            [[#include <openssl/bio.h>]],
            [[BIO_dgram_get_peer(NULL, NULL);]])], [],
          [AC_MSG_ERROR(DTLS support requires a newer version of OpenSSL)])

        LIBS="$oldLIBS"
       ]
       AC_MSG_RESULT(yes)
    )
fi

