/*
 * This file is part of the openHiTLS project.
 *
 * openHiTLS is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

/*
 * stub_utils.h - Cross-Platform Stub Framework
 *
 * This framework provides a real-by-default stubbing mechanism:
 *   - Unix/Linux/macOS: Calls real implementations via dlsym(RTLD_NEXT)
 *   - Windows: Placeholder for future GetProcAddress-based implementation
 *   - Allows runtime stubbing for test control
 *
 * Usage:
 *   #include "stub_utils.h"
 *
 *   STUB_DEFINE_RET2(int, Add, int, int);
 *
 *   // By default: Calls real Add from library (Unix) or returns default (Windows placeholder)
 *   int result = Add(10, 20);
 *
 *   // Can stub for testing:
 *   STUB_REPLACE(Add, my_custom_stub);
 *   result = Add(10, 20);  // Uses my_custom_stub
 *
 *   // Restore to real implementation:
 *   STUB_RESTORE(Add);
 */

#ifndef STUB_UTILS_H
#define STUB_UTILS_H

#if defined(__linux__) || defined(__gnu_linux__)
    #ifndef _GNU_SOURCE
        #define _GNU_SOURCE
    #endif
#endif

#include <string.h>
#include <stddef.h>

/* ============================================================================
 * Platform Detection and Includes
 * ============================================================================ */

#if defined(__unix__) || defined(__unix) || defined(__APPLE__) || defined(__MACH__)
    /* Unix-like platforms: Linux, macOS, BSD, etc. */
    #define STUB_PLATFORM_UNIX
    #include <dlfcn.h>

    #ifndef RTLD_NEXT
        #error "RTLD_NEXT not supported on this Unix platform. Please ensure _GNU_SOURCE is defined on Linux."
    #endif

#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
    /* Windows platforms */
    #define STUB_PLATFORM_WINDOWS
    #include <windows.h>

    /* Windows implementation is placeholder - real symbol lookup not yet implemented */
    #ifndef STUB_WINDOWS_WARN_ONCE
        #define STUB_WINDOWS_WARN_ONCE
        #pragma message("Warning: Windows real function call support is not yet implemented.")
    #endif

#else
    #error "Unsupported platform. This framework requires Unix-like OS or Windows."
#endif

/* ============================================================================
 * Common Macros
 * ============================================================================ */

#define STUB_COMMON_FIELDS                                                     \
    const char* stub_target_symbol

/* ============================================================================
 * Control Macros (Platform-Independent)
 * ============================================================================ */

#define STUB_REPLACE(FUNCNAME, STUB_FUNC)                                      \
    do { FUNCNAME##_stub.stub_impl = STUB_FUNC; } while(0)

#define STUB_RESTORE(FUNCNAME)                                                 \
    do { FUNCNAME##_stub.stub_impl = NULL; } while(0)

#define WITH_STUB_SCOPED(FUNCNAME, STUB_FUNC)                                  \
    for(int _stub_once = (FUNCNAME##_stub.stub_impl = STUB_FUNC, 1);           \
        _stub_once;                                                            \
        _stub_once = 0, FUNCNAME##_stub.stub_impl = NULL)

/* ============================================================================
 * Platform-Specific: Real Implementation Lookup
 * ============================================================================ */

#ifdef STUB_PLATFORM_UNIX

/* Unix/Linux/macOS: Use dlsym with RTLD_NEXT */
#define STUB_GET_REAL_IMPL(FUNCNAME, FUNC_TYPE)                                 \
    static FUNC_TYPE get_real_##FUNCNAME(void) {                                \
        if (FUNCNAME##_stub.real_impl == NULL) {                                \
            FUNCNAME##_stub.real_impl = (FUNC_TYPE)dlsym(RTLD_NEXT, #FUNCNAME); \
        }                                                                       \
        return FUNCNAME##_stub.real_impl;                                       \
    }

#define STUB_REAL_IMPL_FIELD(FUNC_TYPE) FUNC_TYPE real_impl;

#elif defined(STUB_PLATFORM_WINDOWS)

/* Windows: Placeholder - GetProcAddress-based lookup not yet implemented */
#define STUB_GET_REAL_IMPL(FUNCNAME, FUNC_TYPE)                                 \
    static FUNC_TYPE get_real_##FUNCNAME(void) {                                \
        /* TODO: Implement GetProcAddress-based lookup */                       \
        /* Strategy: Use GetModuleHandle + GetProcAddress to find real impl */  \
        /* For now, always return NULL to fall back to default behavior */      \
        return NULL;                                                            \
    }

/* Windows doesn't cache real_impl since lookup is not implemented */
#define STUB_REAL_IMPL_FIELD(FUNC_TYPE) /* No real_impl field on Windows */

#endif

/* ============================================================================
 * VOID Function Stubs (0-10 arguments)
 * ============================================================================ */

#define STUB_DEFINE_VOID0(FUNCNAME)                                            \
    typedef void (*real_##FUNCNAME##_func_t)(void);                            \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(void);                                               \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(void) {                                                      \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl();                                       \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func();                                                       \
        }                                                                      \
    }

#define STUB_DEFINE_VOID1(FUNCNAME, T0)                                        \
    typedef void (*real_##FUNCNAME##_func_t)(T0);                              \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0);                                                 \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0) {                                                   \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0);                                   \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0);                                                   \
        }                                                                      \
    }

#define STUB_DEFINE_VOID2(FUNCNAME, T0, T1)                                    \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1);                          \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0, T1);                                             \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0, T1 arg1) {                                          \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0, arg1);                             \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0, arg1);                                             \
        }                                                                      \
    }

#define STUB_DEFINE_VOID3(FUNCNAME, T0, T1, T2)                                \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2);                      \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0, T1, T2);                                         \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2) {                                 \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2);                       \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0, arg1, arg2);                                       \
        }                                                                      \
    }

#define STUB_DEFINE_VOID4(FUNCNAME, T0, T1, T2, T3)                            \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3);                  \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0, T1, T2, T3);                                     \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3) {                        \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3);                 \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0, arg1, arg2, arg3);                                 \
        }                                                                      \
    }

#define STUB_DEFINE_VOID5(FUNCNAME, T0, T1, T2, T3, T4)                        \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4);              \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0, T1, T2, T3, T4);                                 \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {               \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4);           \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0, arg1, arg2, arg3, arg4);                           \
        }                                                                      \
    }

#define STUB_DEFINE_VOID6(FUNCNAME, T0, T1, T2, T3, T4, T5)                    \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5);          \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0, T1, T2, T3, T4, T5);                             \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) {      \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5);     \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0, arg1, arg2, arg3, arg4, arg5);                     \
        }                                                                      \
    }

#define STUB_DEFINE_VOID7(FUNCNAME, T0, T1, T2, T3, T4, T5, T6)                \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6);      \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        void (*stub_impl)(T0, T1, T2, T3, T4, T5, T6);                         \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) { \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6); \
            return;                                                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6);               \
        }                                                                      \
    }

#define STUB_DEFINE_VOID8(FUNCNAME, T0, T1, T2, T3, T4, T5, T6, T7)                         \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6, T7);               \
    typedef struct FUNCNAME##_Stub {                                                        \
        STUB_COMMON_FIELDS;                                                                 \
        void (*stub_impl)(T0, T1, T2, T3, T4, T5, T6, T7);                                  \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                      \
    } FUNCNAME##_Stub;                                                                      \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                     \
        .stub_target_symbol = #FUNCNAME,                                                    \
        .stub_impl = NULL,                                                                  \
    };                                                                                      \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                                  \
    void FUNCNAME##_restore(void) {                                                         \
        FUNCNAME##_stub.stub_impl = NULL;                                                   \
    }                                                                                       \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) { \
        if (FUNCNAME##_stub.stub_impl) {                                                    \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);      \
            return;                                                                         \
        }                                                                                   \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                         \
        if (real_func) {                                                                    \
            real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);                      \
        }                                                                                   \
    }

#define STUB_DEFINE_VOID9(FUNCNAME, T0, T1, T2, T3, T4, T5, T6, T7, T8)                              \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6, T7, T8);                    \
    typedef struct FUNCNAME##_Stub {                                                                 \
        STUB_COMMON_FIELDS;                                                                          \
        void (*stub_impl)(T0, T1, T2, T3, T4, T5, T6, T7, T8);                                       \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                               \
    } FUNCNAME##_Stub;                                                                               \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                              \
        .stub_target_symbol = #FUNCNAME,                                                             \
        .stub_impl = NULL,                                                                           \
    };                                                                                               \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                                           \
    void FUNCNAME##_restore(void) {                                                                  \
        FUNCNAME##_stub.stub_impl = NULL;                                                            \
    }                                                                                                \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { \
        if (FUNCNAME##_stub.stub_impl) {                                                             \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);         \
            return;                                                                                  \
        }                                                                                            \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                                  \
        if (real_func) {                                                                             \
            real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);                         \
        }                                                                                            \
    }

#define STUB_DEFINE_VOID10(FUNCNAME, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)                                  \
    typedef void (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);                         \
    typedef struct FUNCNAME##_Stub {                                                                          \
        STUB_COMMON_FIELDS;                                                                                   \
        void (*stub_impl)(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);                                            \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                                        \
    } FUNCNAME##_Stub;                                                                                        \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                                       \
        .stub_target_symbol = #FUNCNAME,                                                                      \
        .stub_impl = NULL,                                                                                    \
    };                                                                                                        \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                                                    \
    void FUNCNAME##_restore(void) {                                                                           \
        FUNCNAME##_stub.stub_impl = NULL;                                                                     \
    }                                                                                                         \
    void FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { \
        if (FUNCNAME##_stub.stub_impl) {                                                                      \
            FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);            \
            return;                                                                                           \
        }                                                                                                     \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                                           \
        if (real_func) {                                                                                      \
            real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);                            \
        }                                                                                                     \
    }

/* ============================================================================
 * Return Value Function Stubs (0-10 arguments)
 * ============================================================================ */

#define STUB_DEFINE_RET0(RTYPE, FUNCNAME)                                      \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(void);                           \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        RTYPE (*stub_impl)(void);                                              \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    RTYPE FUNCNAME(void) {                                                     \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            return FUNCNAME##_stub.stub_impl();                                \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            return real_func();                                                \
        }                                                                      \
        RTYPE default_ret = {0};                                               \
        return default_ret;                                                    \
    }

#define STUB_DEFINE_RET1(RTYPE, FUNCNAME, T0)                                  \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0);                             \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        RTYPE (*stub_impl)(T0);                                                \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    RTYPE FUNCNAME(T0 arg0) {                                                  \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            return FUNCNAME##_stub.stub_impl(arg0);                            \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            return real_func(arg0);                                            \
        }                                                                      \
        RTYPE default_ret = {0};                                               \
        return default_ret;                                                    \
    }

#define STUB_DEFINE_RET2(RTYPE, FUNCNAME, T0, T1)                              \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1);                         \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        RTYPE (*stub_impl)(T0, T1);                                            \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    RTYPE FUNCNAME(T0 arg0, T1 arg1) {                                         \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            return FUNCNAME##_stub.stub_impl(arg0, arg1);                      \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            return real_func(arg0, arg1);                                      \
        }                                                                      \
        RTYPE default_ret = {0};                                               \
        return default_ret;                                                    \
    }

#define STUB_DEFINE_RET3(RTYPE, FUNCNAME, T0, T1, T2)                          \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2);                     \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        RTYPE (*stub_impl)(T0, T1, T2);                                        \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2) {                                \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2);                \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            return real_func(arg0, arg1, arg2);                                \
        }                                                                      \
        RTYPE default_ret = {0};                                               \
        return default_ret;                                                    \
    }

#define STUB_DEFINE_RET4(RTYPE, FUNCNAME, T0, T1, T2, T3)                      \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3);                 \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        RTYPE (*stub_impl)(T0, T1, T2, T3);                                    \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3) {                       \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3);          \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            return real_func(arg0, arg1, arg2, arg3);                          \
        }                                                                      \
        RTYPE default_ret = {0};                                               \
        return default_ret;                                                    \
    }

#define STUB_DEFINE_RET5(RTYPE, FUNCNAME, T0, T1, T2, T3, T4)                  \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4);             \
    typedef struct FUNCNAME##_Stub {                                           \
        STUB_COMMON_FIELDS;                                                    \
        RTYPE (*stub_impl)(T0, T1, T2, T3, T4);                                \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                         \
    } FUNCNAME##_Stub;                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                        \
        .stub_target_symbol = #FUNCNAME,                                       \
        .stub_impl = NULL,                                                     \
    };                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                     \
    void FUNCNAME##_restore(void) {                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                      \
    }                                                                          \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4) {              \
        if (FUNCNAME##_stub.stub_impl) {                                       \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4);    \
        }                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();            \
        if (real_func) {                                                       \
            return real_func(arg0, arg1, arg2, arg3, arg4);                    \
        }                                                                      \
        RTYPE default_ret = {0};                                               \
        return default_ret;                                                    \
    }

#define STUB_DEFINE_RET6(RTYPE, FUNCNAME, T0, T1, T2, T3, T4, T5)                 \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5);            \
    typedef struct FUNCNAME##_Stub {                                              \
        STUB_COMMON_FIELDS;                                                       \
        RTYPE (*stub_impl)(T0, T1, T2, T3, T4, T5);                               \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                            \
    } FUNCNAME##_Stub;                                                            \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                           \
        .stub_target_symbol = #FUNCNAME,                                          \
        .stub_impl = NULL,                                                        \
    };                                                                            \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                        \
    void FUNCNAME##_restore(void) {                                               \
        FUNCNAME##_stub.stub_impl = NULL;                                         \
    }                                                                             \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5) {        \
        if (FUNCNAME##_stub.stub_impl) {                                          \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5); \
        }                                                                         \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();               \
        if (real_func) {                                                          \
            return real_func(arg0, arg1, arg2, arg3, arg4, arg5);                 \
        }                                                                         \
        RTYPE default_ret = {0};                                                  \
        return default_ret;                                                       \
    }

#define STUB_DEFINE_RET7(RTYPE, FUNCNAME, T0, T1, T2, T3, T4, T5, T6)                   \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6);              \
    typedef struct FUNCNAME##_Stub {                                                    \
        STUB_COMMON_FIELDS;                                                             \
        RTYPE (*stub_impl)(T0, T1, T2, T3, T4, T5, T6);                                 \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                  \
    } FUNCNAME##_Stub;                                                                  \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                 \
        .stub_target_symbol = #FUNCNAME,                                                \
        .stub_impl = NULL,                                                              \
    };                                                                                  \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                              \
    void FUNCNAME##_restore(void) {                                                     \
        FUNCNAME##_stub.stub_impl = NULL;                                               \
    }                                                                                   \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6) {     \
        if (FUNCNAME##_stub.stub_impl) {                                                \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6); \
        }                                                                               \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                     \
        if (real_func) {                                                                \
            return real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6);                 \
        }                                                                               \
        RTYPE default_ret = {0};                                                        \
        return default_ret;                                                             \
    }

#define STUB_DEFINE_RET8(RTYPE, FUNCNAME, T0, T1, T2, T3, T4, T5, T6, T7)                     \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6, T7);                \
    typedef struct FUNCNAME##_Stub {                                                          \
        STUB_COMMON_FIELDS;                                                                   \
        RTYPE (*stub_impl)(T0, T1, T2, T3, T4, T5, T6, T7);                                   \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                        \
    } FUNCNAME##_Stub;                                                                        \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                       \
        .stub_target_symbol = #FUNCNAME,                                                      \
        .stub_impl = NULL,                                                                    \
    };                                                                                        \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                                    \
    void FUNCNAME##_restore(void) {                                                           \
        FUNCNAME##_stub.stub_impl = NULL;                                                     \
    }                                                                                         \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7) {  \
        if (FUNCNAME##_stub.stub_impl) {                                                      \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); \
        }                                                                                     \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                           \
        if (real_func) {                                                                      \
            return real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);                 \
        }                                                                                     \
        RTYPE default_ret = {0};                                                              \
        return default_ret;                                                                   \
    }

#define STUB_DEFINE_RET9(RTYPE, FUNCNAME, T0, T1, T2, T3, T4, T5, T6, T7, T8)                         \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6, T7, T8);                    \
    typedef struct FUNCNAME##_Stub {                                                                  \
        STUB_COMMON_FIELDS;                                                                           \
        RTYPE (*stub_impl)(T0, T1, T2, T3, T4, T5, T6, T7, T8);                                       \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                                \
    } FUNCNAME##_Stub;                                                                                \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                               \
        .stub_target_symbol = #FUNCNAME,                                                              \
        .stub_impl = NULL,                                                                            \
    };                                                                                                \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                                            \
    void FUNCNAME##_restore(void) {                                                                   \
        FUNCNAME##_stub.stub_impl = NULL;                                                             \
    }                                                                                                 \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8) { \
        if (FUNCNAME##_stub.stub_impl) {                                                              \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);   \
        }                                                                                             \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                                   \
        if (real_func) {                                                                              \
            return real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);                   \
        }                                                                                             \
        RTYPE default_ret = {0};                                                                      \
        return default_ret;                                                                           \
    }

#define STUB_DEFINE_RET10(RTYPE, FUNCNAME, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)                             \
    typedef RTYPE (*real_##FUNCNAME##_func_t)(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);                         \
    typedef struct FUNCNAME##_Stub {                                                                           \
        STUB_COMMON_FIELDS;                                                                                    \
        RTYPE (*stub_impl)(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);                                            \
        STUB_REAL_IMPL_FIELD(real_##FUNCNAME##_func_t)                                                         \
    } FUNCNAME##_Stub;                                                                                         \
    FUNCNAME##_Stub FUNCNAME##_stub = {                                                                        \
        .stub_target_symbol = #FUNCNAME,                                                                       \
        .stub_impl = NULL,                                                                                     \
    };                                                                                                         \
    STUB_GET_REAL_IMPL(FUNCNAME, real_##FUNCNAME##_func_t)                                                     \
    void FUNCNAME##_restore(void) {                                                                            \
        FUNCNAME##_stub.stub_impl = NULL;                                                                      \
    }                                                                                                          \
    RTYPE FUNCNAME(T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9) { \
        if (FUNCNAME##_stub.stub_impl) {                                                                       \
            return FUNCNAME##_stub.stub_impl(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);      \
        }                                                                                                      \
        real_##FUNCNAME##_func_t real_func = get_real_##FUNCNAME();                                            \
        if (real_func) {                                                                                       \
            return real_func(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);                      \
        }                                                                                                      \
        RTYPE default_ret = {0};                                                                               \
        return default_ret;                                                                                    \
    }

#endif /* STUB_UTILS_H */