# Backported macros from autoconf git master + a few custom patches

# This file is part of Autoconf.			-*- Autoconf -*-
# Programming languages support.
# Copyright (C) 2001-2017, 2020-2023 Free Software Foundation, Inc.

# This file is part of Autoconf.  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.
#
# Under Section 7 of GPL version 3, you are granted additional
# permissions described in the Autoconf Configure Script Exception,
# version 3.0, as published by the Free Software Foundation.
#
# You should have received a copy of the GNU General Public License
# and a copy of the Autoconf Configure Script Exception along with
# this program; see the files COPYINGv3 and COPYING.EXCEPTION
# respectively.  If not, see <https://www.gnu.org/licenses/>.

# Written by David MacKenzie, with help from
# Akim Demaille, Paul Eggert,
# François Pinard, Karl Berry, Richard Pixley, Ian Lance Taylor,
# Roland McGrath, Noah Friedman, david d zuhn, and many others.

# ---- Backported macros only ----

AC_DEFUN([_AC_C_C89_TEST_GLOBALS],
[m4_divert_text([INIT_PREPARE],
[[# Test code for whether the C compiler supports C89 (global declarations)
ac_c_conftest_c89_globals='
/* Does the compiler advertise C89 conformance?
   Do not test the value of __STDC__, because some compilers set it to 0
   while being otherwise adequately conformant. */
#if !defined __STDC__
# error "Compiler does not advertise C89 conformance"
#endif

#include <stddef.h>
#include <stdarg.h>
struct stat;
/* Most of the following tests are stolen from RCS 5.7 src/conf.sh.  */
struct buf { int x; };
struct buf * (*rcsopen) (struct buf *, struct stat *, int);
static char *e (char **p, int i)
{
  return p[i];
}
static char *f (char * (*g) (char **, int), char **p, ...)
{
  char *s;
  va_list v;
  va_start (v,p);
  s = g (p, va_arg (v,int));
  va_end (v);
  return s;
}

/* C89 style stringification. */
#define noexpand_stringify(a) #a
const char *stringified = noexpand_stringify(arbitrary+token=sequence);

/* C89 style token pasting.  Exercises some of the corner cases that
   e.g. old MSVC gets wrong, but not very hard. */
#define noexpand_concat(a,b) a##b
#define expand_concat(a,b) noexpand_concat(a,b)
extern int vA;
extern int vbee;
#define aye A
#define bee B
int *pvA = &expand_concat(v,aye);
int *pvbee = &noexpand_concat(v,bee);

/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
   function prototypes and stuff, but not \xHH hex character constants.
   These do not provoke an error unfortunately, instead are silently treated
   as an "x".  The following induces an error, until -std is added to get
   proper ANSI mode.  Curiously \x00 != x always comes out true, for an
   array size at least.  It is necessary to write \x00 == 0 to get something
   that is true only with -std.  */
int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1];

/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
   inside strings and character constants.  */
#define FOO(x) '\''x'\''
int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1];

int test (int i, double x);
struct s1 {int (*f) (int a);};
struct s2 {int (*f) (double a);};
int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int),
               int, int);'
]])])


AC_DEFUN([_AC_C_C99_TEST_GLOBALS],
[m4_divert_text([INIT_PREPARE],
[[# Test code for whether the C compiler supports C99 (global declarations)
ac_c_conftest_c99_globals='
// Does the compiler advertise C99 conformance?
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
# error "Compiler does not advertise C99 conformance"
#endif

#include <stdbool.h>
extern int puts (const char *);
extern int printf (const char *, ...);
extern int dprintf (int, const char *, ...);
extern void *malloc (size_t);
extern void free (void *);

// Check varargs macros.  These examples are taken from C99 6.10.3.5.
// dprintf is used instead of fprintf to avoid needing to declare
// FILE and stderr.
#define debug(...) dprintf (2, __VA_ARGS__)
#define showlist(...) puts (#__VA_ARGS__)
#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
static void
test_varargs_macros (void)
{
  int x = 1234;
  int y = 5678;
  debug ("Flag");
  debug ("X = %d\n", x);
  showlist (The first, second, and third items.);
  report (x>y, "x is %d but y is %d", x, y);
}

// Check long long types.
#define BIG64 18446744073709551615ull
#define BIG32 4294967295ul
#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
#if !BIG_OK
  #error "your preprocessor is broken"
#endif
#if BIG_OK
#else
  #error "your preprocessor is broken"
#endif
static long long int bignum = -9223372036854775807LL;
static unsigned long long int ubignum = BIG64;

struct incomplete_array
{
  int datasize;
  double data[];
};

struct named_init {
  int number;
  const wchar_t *name;
  double average;
};

typedef const char *ccp;

static inline int
test_restrict (ccp restrict text)
{
  // See if C++-style comments work.
  // Iterate through items via the restricted pointer.
  // Also check for declarations in for loops.
  for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i)
    continue;
  return 0;
}

// Check varargs and va_copy.
static bool
test_varargs (const char *format, ...)
{
  va_list args;
  va_start (args, format);
  va_list args_copy;
  va_copy (args_copy, args);

  const char *str = "";
  int number = 0;
  float fnumber = 0;

  while (*format)
    {
      switch (*format++)
	{
	case '\''s'\'': // string
	  str = va_arg (args_copy, const char *);
	  break;
	case '\''d'\'': // int
	  number = va_arg (args_copy, int);
	  break;
	case '\''f'\'': // float
	  fnumber = va_arg (args_copy, double);
	  break;
	default:
	  break;
	}
    }
  va_end (args_copy);
  va_end (args);

  return *str && number && fnumber;
}
'
]])])


AC_DEFUN([_AC_C_C11_TEST_GLOBALS],
[m4_divert_text([INIT_PREPARE],
[[# Test code for whether the C compiler supports C11 (global declarations)
ac_c_conftest_c11_globals='
// Does the compiler advertise C11 conformance?
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L
# error "Compiler does not advertise C11 conformance"
#endif

// Check _Alignas.
char _Alignas (double) aligned_as_double;
char _Alignas (0) no_special_alignment;
extern char aligned_as_int;
char _Alignas (0) _Alignas (int) aligned_as_int;

// Check _Alignof.
enum
{
  int_alignment = _Alignof (int),
  int_array_alignment = _Alignof (int[100]),
  char_alignment = _Alignof (char)
};
_Static_assert (0 < -_Alignof (int), "_Alignof is signed");

// Check _Noreturn.
_Noreturn int does_not_return (void) { for (;;) continue; }

// Check _Static_assert.
struct test_static_assert
{
  int x;
  _Static_assert (sizeof (int) <= sizeof (long int),
                  "_Static_assert does not work in struct");
  long int y;
};

// Check UTF-8 literals.
#define u8 syntax error!
char const utf8_literal[] = u8"happens to be ASCII" "another string";

// Check duplicate typedefs.
typedef long *long_ptr;
typedef long int *long_ptr;
typedef long_ptr long_ptr;

// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
struct anonymous
{
  union {
    struct { int i; int j; };
    struct { int k; long int l; } w;
  };
  int m;
} v1;
'
]])])


# AC_LANG_CALL(C)(PROLOGUE, FUNCTION)
# -----------------------------------
# Avoid conflicting decl of main.
m4_define([AC_LANG_CALL(C)],
[AC_LANG_PROGRAM([$1
m4_if([$2], [main], ,
[/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.
   The 'extern "C"' is for builds by C++ compilers;
   although this is not generally supported in C code supporting it here
   has little cost and some practical benefit (sr 110532).  */
#ifdef __cplusplus
extern "C"
#endif
char $2 (void);])], [return $2 ();])])


# AC_LANG_FUNC_LINK_TRY(C)(FUNCTION)
# ----------------------------------
# Don't include <ctype.h> because on OSF/1 3.0 it includes
# <sys/types.h> which includes <sys/select.h> which contains a
# prototype for select.  Similarly for bzero.
#
# This test used to merely assign f=$1 in main(), but that was
# optimized away by HP unbundled cc A.05.36 for ia64 under +O3,
# presumably on the basis that there's no need to do that store if the
# program is about to exit.  Conversely, the AIX linker optimizes an
# unused external declaration that initializes f=$1.  So this test
# program has both an external initialization of f, and a use of f in
# main that affects the exit status.
#
m4_define([AC_LANG_FUNC_LINK_TRY(C)],
[AC_LANG_PROGRAM(
[/* Define $1 to an innocuous variant, in case <limits.h> declares $1.
   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
#define $1 innocuous_$1

/* System header to define __stub macros and hopefully few prototypes,
   which can conflict with char $1 (void); below.  */

#include <limits.h>
#undef $1

/* Override any GCC internal prototype to avoid an error.
   Use char because int might match the return type of a GCC
   builtin and then its argument prototype would still apply.  */
#ifdef __cplusplus
extern "C"
#endif
char $1 (void);
/* The GNU C library defines this for functions which it implements
    to always fail with ENOSYS.  Some functions are actually named
    something starting with __ and the normal name is an alias.  */
#if defined __stub_$1 || defined __stub___$1
choke me
#endif
], [return $1 ();])])


# AC_C_BIGENDIAN ([ACTION-IF-TRUE], [ACTION-IF-FALSE], [ACTION-IF-UNKNOWN],
#                 [ACTION-IF-UNIVERSAL])
# -------------------------------------------------------------------------
AC_DEFUN([AC_C_BIGENDIAN],
[AH_VERBATIM([WORDS_BIGENDIAN],
[/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
   significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
# if defined __BIG_ENDIAN__
#  define WORDS_BIGENDIAN 1
# endif
#else
# ifndef WORDS_BIGENDIAN
#  undef WORDS_BIGENDIAN
# endif
#endif])dnl
 AC_CACHE_CHECK([whether byte ordering is bigendian], [ac_cv_c_bigendian],
   [ac_cv_c_bigendian=unknown
    # See if we're dealing with a universal compiler.
    AC_COMPILE_IFELSE(
	 [AC_LANG_SOURCE(
	    [[#ifndef __APPLE_CC__
	       not a universal capable compiler
	     #endif
	     typedef int dummy;
	    ]])],
	 [
	# Check for potential -arch flags.  It is not universal unless
	# there are at least two -arch flags with different values.
	ac_arch=
	ac_prev=
	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
	 if test -n "$ac_prev"; then
	   case $ac_word in
	     i?86 | x86_64 | ppc | ppc64)
	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
		 ac_arch=$ac_word
	       else
		 ac_cv_c_bigendian=universal
		 break
	       fi
	       ;;
	   esac
	   ac_prev=
	 elif test "x$ac_word" = "x-arch"; then
	   ac_prev=arch
	 fi
       done])
    if test $ac_cv_c_bigendian = unknown; then
      # See if sys/param.h defines the BYTE_ORDER macro.
      AC_COMPILE_IFELSE(
	[AC_LANG_PROGRAM(
	   [[#include <sys/types.h>
	     #include <sys/param.h>
	   ]],
	   [[#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \\
		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \\
		     && LITTLE_ENDIAN)
	      bogus endian macros
	     #endif
	   ]])],
	[# It does; now see whether it defined to BIG_ENDIAN or not.
	 AC_COMPILE_IFELSE(
	   [AC_LANG_PROGRAM(
	      [[#include <sys/types.h>
		#include <sys/param.h>
	      ]],
	      [[#if BYTE_ORDER != BIG_ENDIAN
		 not big endian
		#endif
	      ]])],
	   [ac_cv_c_bigendian=yes],
	   [ac_cv_c_bigendian=no])])
    fi
    if test $ac_cv_c_bigendian = unknown; then
      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
      AC_COMPILE_IFELSE(
	[AC_LANG_PROGRAM(
	   [[#include <limits.h>
	   ]],
	   [[#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
	      bogus endian macros
	     #endif
	   ]])],
	[# It does; now see whether it defined to _BIG_ENDIAN or not.
	 AC_COMPILE_IFELSE(
	   [AC_LANG_PROGRAM(
	      [[#include <limits.h>
	      ]],
	      [[#ifndef _BIG_ENDIAN
		 not big endian
		#endif
	      ]])],
	   [ac_cv_c_bigendian=yes],
	   [ac_cv_c_bigendian=no])])
    fi
    if test $ac_cv_c_bigendian = unknown; then
      # Compile a test program.
      AC_RUN_IFELSE(
	[AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
	   [[
	     /* Are we little or big endian?  From Harbison&Steele.  */
	     union
	     {
	       long int l;
	       char c[sizeof (long int)];
	     } u;
	     u.l = 1;
	     return u.c[sizeof (long int) - 1] == 1;
	   ]])],
	[ac_cv_c_bigendian=no],
	[ac_cv_c_bigendian=yes],
	[# Try to guess by grepping values from an object file.
	 AC_LINK_IFELSE(
	   [AC_LANG_SOURCE(
	      [[unsigned short int ascii_mm[] =
		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
		unsigned short int ascii_ii[] =
		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
		int use_ascii (int i) {
		  return ascii_mm[i] + ascii_ii[i];
		}
		unsigned short int ebcdic_ii[] =
		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
		unsigned short int ebcdic_mm[] =
		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
		int use_ebcdic (int i) {
		  return ebcdic_mm[i] + ebcdic_ii[i];
		}
		int
		main (int argc, char **argv)
		{
		  /* Intimidate the compiler so that it does not
		     optimize the arrays away.  */
		  char *p = argv[0];
		  ascii_mm[1] = *p++; ebcdic_mm[1] = *p++;
		  ascii_ii[1] = *p++; ebcdic_ii[1] = *p++;
		  return use_ascii (argc) == use_ebcdic (*p);
		}]])],
	   [if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then
	      ac_cv_c_bigendian=yes
	    fi
	    if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then
	      if test "$ac_cv_c_bigendian" = unknown; then
		ac_cv_c_bigendian=no
	      else
		# finding both strings is unlikely to happen, but who knows?
		ac_cv_c_bigendian=unknown
	      fi
	    fi])])
    fi])
 case $ac_cv_c_bigendian in #(
   yes)
     m4_default([$1],
       [AC_DEFINE([WORDS_BIGENDIAN], 1)]);; #(
   no)
     $2 ;; #(
   universal)
dnl Note that AC_APPLE_UNIVERSAL_BUILD sorts less than WORDS_BIGENDIAN;
dnl this is a necessity for proper config header operation.  Warn if
dnl the user did not specify a config header but is relying on the
dnl default behavior for universal builds.
     m4_default([$4],
       [AC_CONFIG_COMMANDS_PRE([m4_ifset([AH_HEADER], [],
	 [m4_warn([obsolete],
	   [AC_C_BIGENDIAN should be used with AC_CONFIG_HEADERS])])])dnl
	AC_DEFINE([AC_APPLE_UNIVERSAL_BUILD],1,
	  [Define if building universal (internal helper macro)])])
     ;; #(
   *)
     m4_default([$3],
       [AC_MSG_ERROR([unknown endianness
 presetting ac_cv_c_bigendian=no (or yes) will help])]) ;;
 esac
])# AC_C_BIGENDIAN


# AC_C_VARARRAYS
# --------------
# Check whether the C compiler supports variable-length arrays.
AC_DEFUN([AC_C_VARARRAYS],
[
  AC_CACHE_CHECK([for variable-length arrays],
    ac_cv_c_vararrays,
    [AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[[	#ifndef __STDC_NO_VLA__
	#error __STDC_NO_VLA__ not defined
	choke me now
	#endif
]])],
       [ac_cv_c_vararrays='no: __STDC_NO_VLA__ is defined'],
       [AC_COMPILE_IFELSE(
	  [AC_LANG_PROGRAM(
	     [[/* Test for VLA support.  This test is partly inspired
		  from examples in the C standard.  Use at least two VLA
		  functions to detect the GCC 3.4.3 bug described in:
		  https://lists.gnu.org/archive/html/bug-gnulib/2014-08/msg00014.html
		  */
	       #ifdef __STDC_NO_VLA__
		syntax error;
	       #else
		 extern int n;
		 static int B[100];
		 int fvla (int m, int C[m][m]);

		 static int
		 simple (int count, int all[static count])
		 {
		   return all[count - 1];
		 }

		 int
		 fvla (int m, int C[m][m])
		 {
		   typedef int VLA[m][m];
		   VLA x;
		   int D[m];
		   static int (*q)[m] = &B;
		   int (*s)[n] = q;
		   (void) simple;
		   return C && &x[0][0] == &D[0] && &D[0] == s[0];
		 }
	       #endif
	       ]])],
	  [ac_cv_c_vararrays=yes],
	  [ac_cv_c_vararrays=no])])])
  if test "$ac_cv_c_vararrays" = yes; then
    dnl This is for compatibility with Autoconf 2.61-2.69.
    AC_DEFINE([HAVE_C_VARARRAYS], 1,
      [Define to 1 if C supports variable-length arrays.])
  elif test "$ac_cv_c_vararrays" = no; then
    AC_DEFINE([__STDC_NO_VLA__], 1,
      [Define to 1 if C does not support variable-length arrays, and
       if the compiler does not already define this.])
  fi
])

