#ifndef __PDCLIB_AUX_H
#define __PDCLIB_AUX_H __PDCLIB_AUX_H

/* Auxiliary PDCLib code <_PDCLIB_aux.h>

   This file is part of the Public Domain C Library (PDCLib).
   Permission is granted to use, modify, and / or redistribute at will.
*/

/* -------------------------------------------------------------------------- */
/* You should not have to edit anything in this file; if you DO have to, it   */
/* would be considered a bug / missing feature: notify the author(s).         */
/* -------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------- */
/* Standard Version                                                           */
/* -------------------------------------------------------------------------- */

/* Many a compiler gets this wrong, so you might have to hardcode it instead. */

#if __STDC__ != 1
#error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)!
#endif

#if defined(_PDCLIB_C_VERSION)
    /* Pass - conditional simplification case */
#elif !defined(__STDC_VERSION__)
    #define _PDCLIB_C_VERSION 1990
#elif __STDC_VERSION__ == 199409L
    #define _PDCLIB_C_VERSION 1995
#elif __STDC_VERSION__ == 199901L
    #define _PDCLIB_C_VERSION 1999
#elif __STDC_VERSION__ == 201112L
    #define _PDCLIB_C_VERSION 2011
#else
    #error Unsupported _ _STDC_VERSION_ _ (__STDC_VERSION__) (supported: ISO/IEC 9899:1990, 9899/AMD1:1995, 9899:1999, 9899:2011).
#endif

#if !defined(__cplusplus) || defined(_PDCLIB_CXX_VERSION)
   #define _PDCLIB_CXX_VERSION 0
#elif __cplusplus == 201103L
    #define _PDCLIB_CXX_VERSION 2011
    /* TODO: Do we want this? */
    #if _PDCLIB_C_VERSION < 2011
        #undef _PDCLIB_C_VERSION
        #define _PDCLIB_C_VERSION 2011
    #endif
#elif __cplusplus == 199711L
   #define _PDCLIB_CXX_VERSION 1997
#else
#if __cplusplus == 1 && __clang__ && __clang_major__ == 3 && __clang_minor__ == 1
    /* clang 3.1 does not state it is C++98 unless -std=c++98 is given
     * later versions do that by default.
     *
     * This of course breaks build of divine's models if you use clang 3.1
     * so we work-around this here
     *
     * We don't care about older clangs since we don't support them at all in divine.
     */
   #define _PDCLIB_CXX_VERSION 1997
#else
   #error Unsupported _ _cplusplus (__cplusplus) (supported: ISO/IEC 14882:1997, ISO/IEC 14882:2011).
#endif
#endif

#ifndef __STDC_HOSTED__
    #error Compiler does not define _ _STDC_HOSTED_ _ (not standard-compliant)!
#elif __STDC_HOSTED__ == 0
    #define _PDCLIB_HOSTED 0
#elif __STDC_HOSTED__ == 1
    #define _PDCLIB_HOSTED 1
#else
    #error Compiler does not define _ _STDC_HOSTED_ _ to 0 or 1 (not standard-compliant)!
#endif

#ifdef __cplusplus
    #define _PDCLIB_BEGIN_EXTERN_C extern "C" {
    #define _PDCLIB_END_EXTERN_C }
    typedef bool _PDCLIB_bool;
#else
    #define _PDCLIB_BEGIN_EXTERN_C
    #define _PDCLIB_END_EXTERN_C
    typedef _Bool _PDCLIB_bool;
#endif

/* Clang style feature detection macros
 * Note: It is common to #define __has_feature(0) if undefined so the presence
 * of this macro does not guarantee it to be working
 */

#ifdef __has_feature
   #define _PDCLIB_HAS_FEATURE(x) __has_feature(x)
#else
   #define _PDCLIB_HAS_FEATURE(x) (0)
#endif

#ifdef __has_extension
   #define _PDCLIB_HAS_EXTENSION(x) __has_extension(x)
#else
   // Older versions of Clang use __has_feature instead
   #define _PDCLIB_HAS_EXTENSION(x) _PDCLIB_HAS_FEATURE(x)
#endif

#ifdef __has_builtin
   #define _PDCLIB_HAS_BUILTIN(x) __has_builtin(x)
#else
   #define _PDCLIB_HAS_BUILTIN(x) (0)
#endif

#ifdef __has_attribute
   #define _PDCLIB_HAS_ATTRIBUTE(x) __has_builtin(x)
#else
   #define _PDCLIB_HAS_ATTRIBUTE(x) (0)
#endif

/* GCC feature detection macros */

#if defined(__GNUC__)
    #define _PDCLIB_GCC_MIN(maj, min) \
        ((__GNUC__ > maj) || (__GNUC__ == maj && __GNUC_MINOR__ >= min))
#else
    #define _PDCLIB_GCC_MIN(maj, min) (0)
#endif

/* Hybrid GCC/Clang feature detection macros */
#define _PDCLIB_GCC_FEATURE(x, gccmaj, gccmin) \
        (_PDCLIB_HAS_FEATURE(x) || _PDCLIB_GCC_MIN(gccmin, gccmaj))

#define _PDCLIB_GCC_EXTENSION(x, gccmaj, gccmin) \
        (_PDCLIB_HAS_EXTENSION(x) || _PDCLIB_GCC_MIN(gccmin, gccmaj))

#define _PDCLIB_GCC_BUILTIN(x, gccmaj, gccmin) \
        (_PDCLIB_HAS_BUILTIN(x) || _PDCLIB_GCC_MIN(gccmin, gccmaj))

#define _PDCLIB_GCC_ATTRIBUTE(x, gccmaj, gccmin) \
        (_PDCLIB_HAS_ATTRIBUTE(x) || _PDCLIB_GCC_MIN(gccmin, gccmaj))

/* Extension & Language feature detection */

#if _PDCLIB_C_VERSION >= 1999 || defined(__cplusplus)
    #ifndef __cplusplus
        #define _PDCLIB_restrict restrict
    #endif
    #define _PDCLIB_inline   inline
#endif

#if _PDCLIB_CXX_VERSION >= 2011
  #define _PDCLIB_nothrow     noexcept
  #define _PDCLIB_noexcept(x) noexcept(x)
#elif _PDCLIB_CXX_VERSION
  #define _PDCLIB_nothrow     throw()
  #define _PDCLIB_noexcept
#endif

#if _PDCLIB_CXX_VERSION >= 2011 && _PDCLIB_GCC_FEATURE(cxx_attributes, 4, 8)
    #define _PDCLIB_noreturn [[noreturn]]
#elif _PDCLIB_C_VERSION >= 2011 && _PDCLIB_GCC_FEATURE(c_noreturn, 4, 7)
    #define _PDCLIB_noreturn _Noreturn
#endif

#ifdef _WIN32
   #define _PDCLIB_EXPORT __declspec(dllexport)
   #define _PDCLIB_IMPORT __declspec(dllimport)
#endif

#if !defined(_PDCLIB_EXPORT) && _PDCLIB_GCC_ATTRIBUTE(__visibility__, 4, 0)
    #define _PDCLIB_EXPORT __attribute__((__visibility__("protected")))
#endif

#if !defined(_PDCLIB_HIDDEN) && _PDCLIB_GCC_ATTRIBUTE(__visibility__, 4, 0)
    #define _PDCLIB_HIDDEN __attribute__((__visibility__("hidden")))
#endif

#if !defined(_PDCLIB_nothrow) && _PDCLIB_GCC_ATTRIBUTE(__nothrow__, 4, 0)
    #define _PDCLIB_nothrow __attribute__((__nothrow__))
    #define _PDCLIB_noexcept
#endif

#if !defined(_PDCLIB_restrict) && _PDCLIB_GCC_MIN(3, 0)
    #define _PDCLIB_restrict __restrict
#endif

#if !defined(_PDCLIB_inline) && _PDCLIB_GCC_MIN(3, 0)
    #define _PDCLIB_inline __inline
#endif

#if !defined(_PDCLIB_noreturn) && _PDCLIB_GCC_ATTRIBUTE(__noreturn__, 3, 0)
    /* If you don't use __noreturn__, then stdnoreturn.h will break things! */
    #define _PDCLIB_noreturn __attribute__((__noreturn__))
#endif

#if !defined(_PDCLIB_DEPRECATED) && _PDCLIB_GCC_ATTRIBUTE(__deprecated__, 3, 0)
    #define _PDCLIB_DEPRECATED __attribute__ ((__deprecated__))
#endif

#if !defined(_PDCLIB_UNREACHABLE) && _PDCLIB_GCC_BUILTIN(__builtin_unreachable, 4, 0)
    #define _PDCLIB_UNREACHABLE __builtin_unreachable()
#endif

#if !defined(_PDCLIB_UNDEFINED) && defined(__GNUC__)
    #define _PDCLIB_UNDEFINED(_var) \
        do { __asm__("" : "=X"(_var)); } while(0)
#endif

/* No-op fallbacks */

#ifndef _PDCLIB_nothrow
  #define _PDCLIB_nothrow
  #define _PDCLIB_noexcept
#endif

#ifndef _PDCLIB_EXPORT
    #define _PDCLIB_EXPORT
#endif
#ifndef _PDCLIB_IMPORT
    #define _PDCLIB_IMPORT
#endif
#ifndef _PDCLIB_HIDDEN
    #define _PDCLIB_HIDDEN
#endif

#if defined(_PDCLIB_SHARED) 
    #if defined(_PDCLIB_BUILD)
        #define _PDCLIB_API _PDCLIB_EXPORT
    #else
        #define _PDCLIB_API _PDCLIB_IMPORT
    #endif
#else
    #define _PDCLIB_API
#endif

#ifndef _PDCLIB_restrict
      #define _PDCLIB_restrict
#endif

#ifndef _PDCLIB_inline
      #define _PDCLIB_inline
#endif

#ifndef _PDCLIB_noreturn
      #define _PDCLIB_noreturn
#endif

#ifndef _PDCLIB_DEPRECATED
    #define _PDCLIB_DEPRECATED
#endif

#ifndef _PDCLIB_UNREACHABLE
    #define _PDCLIB_UNREACHABLE do {} while(0)
#endif

#ifndef _PDCLIB_UNDEFINED
    #define _PDCLIB_UNDEFINED(_var) do {} while(0)
#endif

/*#if _PDCLIB_C_VERSION != 1999
#error PDCLib might not be fully conforming to either C89 or C95 prior to v2.x.
#endif*/

/* -------------------------------------------------------------------------- */
/* Helper macros:                                                             */
/* _PDCLIB_cc( x, y ) concatenates two preprocessor tokens without extending  */
/* _PDCLIB_concat( x, y ) concatenates two preprocessor tokens with extending */
/* -------------------------------------------------------------------------- */

#define _PDCLIB_cc( x, y )     x ## y
#define _PDCLIB_concat( x, y ) _PDCLIB_cc( x, y )
#define _PDCLIB_concat3( x, y, z ) _PDCLIB_concat( _PDCLIB_concat( x, y ), z )

#define _PDCLIB_symbol2value( x ) #x
#define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x )

/* Feature test macros
 *
 * All of the feature test macros come in the following forms
 *   _PDCLIB_*_MIN(min):            Available in versions >= min
 *   _PDCLIB_*_MINMAX(min, max):    Available in versions >= min <= max
 *   _PDCLIB_*_MAX(max):            Availabel in versions <= max
 *
 * The defined tests are:
 *   C:     C standard versions 
 *              1990, 1995, 1999, 2011
 *   CXX:   C++ standard versions 
 *              1997, 2011
 *   POSIX: POSIX extension versions.
 *              1 (POSIX.2), 2 (POSIX.2), 199309L (POSIX.1b), 
 *              199506L (POSIX.1c), 200112L (2001), 200809L (2008)
 *   XOPEN: X/Open System Interface (XSI)/Single Unix Specification
 *              0 (XPG4), 500 (SUSv2/UNIX98), 600 (SUSv3/UNIX03), 700 (SUSv4)
 *
 *   Additionally, the macros
 *     _BSD_SOURCE, _SVID_SOURCE and _GNU_SOURCE
 *   are adhered to. If _GNU_SOURCE is defined, _XOPEN_SOURCE and 
 *   _POSIX_C_SOURCE are defined to their most recent values to match glibc 
 *   behaviour
 *
 *   The intention of supporting these feature test macros is to ease 
 *   application portability from these systems to PDCLib systems; in addition,
 *   it eases support for these standards by systems supporting them which are 
 *   using PDCLib as their default C library.
 *
 *   Applications targetting purely PDClib/PDCLib based platforms may define 
 *   just _PDCLIB_EXTENSIONS, which will enable all supported extensions, plus
 *   all features from all supported versions of C and C++.
 *
 */
#define _PDCLIB_C_MIN(min)         _PDCLIB_C_MINMAX(min, 3000)
#define _PDCLIB_CXX_MIN(min)     _PDCLIB_CXX_MINMAX(min, 3000)
#define _PDCLIB_XOPEN_MIN(min) _PDCLIB_XOPEN_MINMAX(min, 30000000)
#define _PDCLIB_POSIX_MIN(min) _PDCLIB_POSIX_MINMAX(min, 30000000)
#define _PDCLIB_C_MAX(max)         _PDCLIB_C_MINMAX(0, max)
#define _PDCLIB_CXX_MAX(max)     _PDCLIB_CXX_MINMAX(0, max)
#define _PDCLIB_XOPEN_MAX(max) _PDCLIB_XOPEN_MINMAX(0, max)
#define _PDCLIB_POSIX_MAX(max) _PDCLIB_POSIX_MINMAX(0, max)
#if defined(_PDCLIB_EXTENSIONS) || defined(_PDCLIB_BUILD)
    #define _PDCLIB_C_MINMAX(min, max) 1
    #define _PDCLIB_CXX_MINMAX(min, max) 1
    #define _PDCLIB_POSIX_MINMAX(min, max) 1
    #define _PDCLIB_XOPEN_MINMAX(min, max) 1

    #undef _PDCLIB_EXTENSIONS
    #undef _PDCLIB_BSD_SOURCE 
    #undef _PDCLIB_SVID_SOURCE
    #undef _PDCLIB_GNU_SOURCE

    #define _PDCLIB_EXTENSIONS 1
    #define _PDCLIB_BSD_SOURCE 1
    #define _PDCLIB_SVID_SOURCE 1
    #define _PDCLIB_GNU_SOURCE 1
#else
    #define _PDCLIB_C_MINMAX(min, max) \
        (_PDCLIB_C_VERSION >= (min) && _PDCLIB_C_VERSION <= (max))
    #define _PDCLIB_CXX_MINMAX(min, max) \
        (_PDCLIB_CXX_VERSION >= (min) && _PDCLIB_CXX_VERSION <= (max))
    #define _PDCLIB_XOPEN_MINMAX(min, max) \
        (defined(_XOPEN_SOURCE) \
            && _XOPEN_SOURCE >= (min) && _XOPEN_SOURCE <= (max))
    #define _PDCLIB_POSIX_MINMAX(min, max) \
        (defined(_POSIX_C_SOURCE) \
            && _POSIX_C_SOURCE >= (min) && _POSIX_C_SOURCE <= (max))

    #if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE-1 == -1)
        /* If _XOPEN_SOURCE is defined as empty, redefine here as zero */
        #undef _XOPEN_SOURCE
        #define _XOPEN_SOURCE 0
    #endif

    #if defined(_GNU_SOURCE)
        #define _PDCLIB_GNU_SOURCE 1
        #define _PDCLIB_SVID_SOURCE 1
        #define _PDCLIB_BSD_SOURCE 1
        #undef _XOPEN_SOURCE
        #define _XOPEN_SOURCE 700
    #else
        #define _PDCLIB_GNU_SOURCE 0
    #endif

    #if defined(_PDCLIB_BSD_SOURCE)
        // pass
    #elif defined(_BSD_SOURCE)
        #define _PDCLIB_BSD_SOURCE 1
    #else
        #define _PDCLIB_BSD_SOURCE 0
    #endif

    #if defined(_PDCLIB_SVID_SOURCE)
        // pass
    #elif defined(_SVID_SOURCE)
        #define _PDCLIB_SVID_SOURCE 1
    #else
        #define _PDCLIB_SVID_SOURCE 0
    #endif

    #if _PDCLIB_XOPEN_MIN(700) && !_PDCLIB_POSIX_MIN(200809L)
        #undef _POSIX_C_SOURCE
        #define _POSIX_C_SOURCE 2008098L    
    #elif _PDCLIB_XOPEN_MIN(600) && !_PDCLIB_POSIX_MIN(200112L)
        #undef _POSIX_C_SOURCE
        #define _POSIX_C_SOURCE 200112L
    #elif _PDCLIB_XOPEN_MIN(0) && !_PDCLIB_POSIX_MIN(2)
        #undef _POSIX_C_SOURCE
        #define _POSIX_C_SOURCE 2
    #endif

    #if defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE)
        #define _POSIX_C_SOURCE 1
    #endif
#endif

#endif
