@@ -19,6 +19,7 @@ extern "C" {
1919#endif
2020
2121#include < Python.h>
22+ #include < stddef.h> // offsetof()
2223
2324// Python 3.11.0b4 added PyFrame_Back() to Python.h
2425#if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION)
@@ -1974,6 +1975,235 @@ int Py_fclose(FILE *file)
19741975#endif
19751976
19761977
1978+ #if 0x03090000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION)
1979+ static inline PyObject*
1980+ PyConfig_Get (const char *name)
1981+ {
1982+ typedef enum {
1983+ _PyConfig_MEMBER_INT,
1984+ _PyConfig_MEMBER_UINT,
1985+ _PyConfig_MEMBER_ULONG,
1986+ _PyConfig_MEMBER_BOOL,
1987+ _PyConfig_MEMBER_WSTR,
1988+ _PyConfig_MEMBER_WSTR_OPT,
1989+ _PyConfig_MEMBER_WSTR_LIST,
1990+ } PyConfigMemberType;
1991+
1992+ typedef struct {
1993+ const char *name;
1994+ size_t offset;
1995+ PyConfigMemberType type;
1996+ const char *sys_attr;
1997+ } PyConfigSpec;
1998+
1999+ #define PYTHONCAPI_COMPAT_SPEC (MEMBER, TYPE, sys_attr ) \
2000+ {#MEMBER, offsetof (PyConfig, MEMBER), \
2001+ _PyConfig_MEMBER_##TYPE, sys_attr}
2002+
2003+ static const PyConfigSpec config_spec[] = {
2004+ PYTHONCAPI_COMPAT_SPEC (argv, WSTR_LIST, " argv" ),
2005+ PYTHONCAPI_COMPAT_SPEC (base_exec_prefix, WSTR_OPT, " base_exec_prefix" ),
2006+ PYTHONCAPI_COMPAT_SPEC (base_executable, WSTR_OPT, " _base_executable" ),
2007+ PYTHONCAPI_COMPAT_SPEC (base_prefix, WSTR_OPT, " base_prefix" ),
2008+ PYTHONCAPI_COMPAT_SPEC (bytes_warning, UINT, _Py_NULL),
2009+ PYTHONCAPI_COMPAT_SPEC (exec_prefix, WSTR_OPT, " exec_prefix" ),
2010+ PYTHONCAPI_COMPAT_SPEC (executable, WSTR_OPT, " executable" ),
2011+ PYTHONCAPI_COMPAT_SPEC (inspect, BOOL, _Py_NULL),
2012+ #if 0x030C0000 <= PY_VERSION_HEX
2013+ PYTHONCAPI_COMPAT_SPEC (int_max_str_digits, UINT, _Py_NULL),
2014+ #endif
2015+ PYTHONCAPI_COMPAT_SPEC (interactive, BOOL, _Py_NULL),
2016+ PYTHONCAPI_COMPAT_SPEC (module_search_paths, WSTR_LIST, " path" ),
2017+ PYTHONCAPI_COMPAT_SPEC (optimization_level, UINT, _Py_NULL),
2018+ PYTHONCAPI_COMPAT_SPEC (parser_debug, BOOL, _Py_NULL),
2019+ PYTHONCAPI_COMPAT_SPEC (platlibdir, WSTR, " platlibdir" ),
2020+ PYTHONCAPI_COMPAT_SPEC (prefix, WSTR_OPT, " prefix" ),
2021+ PYTHONCAPI_COMPAT_SPEC (pycache_prefix, WSTR_OPT, " pycache_prefix" ),
2022+ PYTHONCAPI_COMPAT_SPEC (quiet, BOOL, _Py_NULL),
2023+ #if 0x030B0000 <= PY_VERSION_HEX
2024+ PYTHONCAPI_COMPAT_SPEC (stdlib_dir, WSTR_OPT, " _stdlib_dir" ),
2025+ #endif
2026+ PYTHONCAPI_COMPAT_SPEC (use_environment, BOOL, _Py_NULL),
2027+ PYTHONCAPI_COMPAT_SPEC (verbose, UINT, _Py_NULL),
2028+ PYTHONCAPI_COMPAT_SPEC (warnoptions, WSTR_LIST, " warnoptions" ),
2029+ PYTHONCAPI_COMPAT_SPEC (write_bytecode, BOOL, _Py_NULL),
2030+ PYTHONCAPI_COMPAT_SPEC (xoptions, WSTR_LIST, " _xoptions" ),
2031+ #ifdef Py_STATS
2032+ PYTHONCAPI_COMPAT_SPEC (_pystats, BOOL, _Py_NULL),
2033+ #endif
2034+ PYTHONCAPI_COMPAT_SPEC (buffered_stdio, BOOL, _Py_NULL),
2035+ PYTHONCAPI_COMPAT_SPEC (check_hash_pycs_mode, WSTR, _Py_NULL),
2036+ #if 0x030B0000 <= PY_VERSION_HEX
2037+ PYTHONCAPI_COMPAT_SPEC (code_debug_ranges, BOOL, _Py_NULL),
2038+ #endif
2039+ PYTHONCAPI_COMPAT_SPEC (configure_c_stdio, BOOL, _Py_NULL),
2040+ #if 0x030D0000 <= PY_VERSION_HEX
2041+ PYTHONCAPI_COMPAT_SPEC (cpu_count, INT, _Py_NULL),
2042+ #endif
2043+ PYTHONCAPI_COMPAT_SPEC (dev_mode, BOOL, _Py_NULL),
2044+ PYTHONCAPI_COMPAT_SPEC (dump_refs, BOOL, _Py_NULL),
2045+ #if 0x030B0000 <= PY_VERSION_HEX
2046+ PYTHONCAPI_COMPAT_SPEC (dump_refs_file, WSTR_OPT, _Py_NULL),
2047+ #endif
2048+ #ifdef Py_GIL_DISABLED
2049+ PYTHONCAPI_COMPAT_SPEC (enable_gil, INT, _Py_NULL),
2050+ #endif
2051+ PYTHONCAPI_COMPAT_SPEC (faulthandler, BOOL, _Py_NULL),
2052+ PYTHONCAPI_COMPAT_SPEC (filesystem_encoding, WSTR, _Py_NULL),
2053+ PYTHONCAPI_COMPAT_SPEC (filesystem_errors, WSTR, _Py_NULL),
2054+ PYTHONCAPI_COMPAT_SPEC (hash_seed, ULONG, _Py_NULL),
2055+ PYTHONCAPI_COMPAT_SPEC (home, WSTR_OPT, _Py_NULL),
2056+ PYTHONCAPI_COMPAT_SPEC (import_time, BOOL, _Py_NULL),
2057+ PYTHONCAPI_COMPAT_SPEC (install_signal_handlers, BOOL, _Py_NULL),
2058+ PYTHONCAPI_COMPAT_SPEC (isolated, BOOL, _Py_NULL),
2059+ #ifdef MS_WINDOWS
2060+ PYTHONCAPI_COMPAT_SPEC (legacy_windows_stdio, BOOL, _Py_NULL),
2061+ #endif
2062+ PYTHONCAPI_COMPAT_SPEC (malloc_stats, BOOL, _Py_NULL),
2063+ #if 0x030A0000 <= PY_VERSION_HEX
2064+ PYTHONCAPI_COMPAT_SPEC (orig_argv, WSTR_LIST, " orig_argv" ),
2065+ #endif
2066+ PYTHONCAPI_COMPAT_SPEC (parse_argv, BOOL, _Py_NULL),
2067+ PYTHONCAPI_COMPAT_SPEC (pathconfig_warnings, BOOL, _Py_NULL),
2068+ #if 0x030C0000 <= PY_VERSION_HEX
2069+ PYTHONCAPI_COMPAT_SPEC (perf_profiling, UINT, _Py_NULL),
2070+ #endif
2071+ PYTHONCAPI_COMPAT_SPEC (program_name, WSTR, _Py_NULL),
2072+ PYTHONCAPI_COMPAT_SPEC (run_command, WSTR_OPT, _Py_NULL),
2073+ PYTHONCAPI_COMPAT_SPEC (run_filename, WSTR_OPT, _Py_NULL),
2074+ PYTHONCAPI_COMPAT_SPEC (run_module, WSTR_OPT, _Py_NULL),
2075+ #ifdef Py_DEBUG
2076+ PYTHONCAPI_COMPAT_SPEC (run_presite, WSTR_OPT, _Py_NULL),
2077+ #endif
2078+ #if 0x030B0000 <= PY_VERSION_HEX
2079+ PYTHONCAPI_COMPAT_SPEC (safe_path, BOOL, _Py_NULL),
2080+ #endif
2081+ PYTHONCAPI_COMPAT_SPEC (show_ref_count, BOOL, _Py_NULL),
2082+ PYTHONCAPI_COMPAT_SPEC (site_import, BOOL, _Py_NULL),
2083+ PYTHONCAPI_COMPAT_SPEC (skip_source_first_line, BOOL, _Py_NULL),
2084+ PYTHONCAPI_COMPAT_SPEC (stdio_encoding, WSTR, _Py_NULL),
2085+ PYTHONCAPI_COMPAT_SPEC (stdio_errors, WSTR, _Py_NULL),
2086+ PYTHONCAPI_COMPAT_SPEC (tracemalloc, UINT, _Py_NULL),
2087+ #if 0x030B0000 <= PY_VERSION_HEX
2088+ PYTHONCAPI_COMPAT_SPEC (use_frozen_modules, BOOL, _Py_NULL),
2089+ #endif
2090+ PYTHONCAPI_COMPAT_SPEC (use_hash_seed, BOOL, _Py_NULL),
2091+ #ifdef __APPLE__
2092+ PYTHONCAPI_COMPAT_SPEC (use_system_logger, BOOL, _Py_NULL),
2093+ #endif
2094+ PYTHONCAPI_COMPAT_SPEC (user_site_directory, BOOL, _Py_NULL),
2095+ #if 0x030A0000 <= PY_VERSION_HEX
2096+ PYTHONCAPI_COMPAT_SPEC (warn_default_encoding, BOOL, _Py_NULL),
2097+ #endif
2098+ };
2099+
2100+ #undef PYTHONCAPI_COMPAT_SPEC
2101+
2102+ const PyConfigSpec *spec;
2103+ int found = 0 ;
2104+ for (size_t i=0 ; i < Py_ARRAY_LENGTH (config_spec); i++) {
2105+ spec = &config_spec[i];
2106+ if (strcmp (spec->name , name) == 0 ) {
2107+ found = 1 ;
2108+ break ;
2109+ }
2110+ }
2111+ if (found) {
2112+ if (spec->sys_attr != NULL ) {
2113+ PyObject *value = PySys_GetObject (spec->sys_attr );
2114+ if (value == NULL ) {
2115+ PyErr_Format (PyExc_RuntimeError, " lost sys.%s" , spec->sys_attr );
2116+ return NULL ;
2117+ }
2118+ return Py_NewRef (value);
2119+ }
2120+
2121+ extern const PyConfig* _Py_GetConfig (void );
2122+ const PyConfig *config = _Py_GetConfig ();
2123+ void *member = (char *)config + spec->offset ;
2124+ switch (spec->type ) {
2125+ case _PyConfig_MEMBER_INT:
2126+ case _PyConfig_MEMBER_UINT:
2127+ {
2128+ int value = *(int *)member;
2129+ return PyLong_FromLong (value);
2130+ }
2131+ case _PyConfig_MEMBER_BOOL:
2132+ {
2133+ int value = *(int *)member;
2134+ return PyBool_FromLong (value != 0 );
2135+ }
2136+ case _PyConfig_MEMBER_ULONG:
2137+ {
2138+ unsigned long value = *(unsigned long *)member;
2139+ return PyLong_FromUnsignedLong (value);
2140+ }
2141+ case _PyConfig_MEMBER_WSTR:
2142+ case _PyConfig_MEMBER_WSTR_OPT:
2143+ {
2144+ wchar_t *wstr = *(wchar_t **)member;
2145+ if (wstr != NULL ) {
2146+ return PyUnicode_FromWideChar (wstr, -1 );
2147+ }
2148+ else {
2149+ return Py_NewRef (Py_None);
2150+ }
2151+ }
2152+ case _PyConfig_MEMBER_WSTR_LIST:
2153+ {
2154+ const PyWideStringList *list = (const PyWideStringList *)member;
2155+ PyObject *tuple = PyTuple_New (list->length );
2156+ if (tuple == NULL ) {
2157+ return NULL ;
2158+ }
2159+
2160+ for (Py_ssize_t i = 0 ; i < list->length ; i++) {
2161+ PyObject *item = PyUnicode_FromWideChar (list->items [i], -1 );
2162+ if (item == NULL ) {
2163+ Py_DECREF (tuple);
2164+ return NULL ;
2165+ }
2166+ PyTuple_SET_ITEM (tuple, i, item);
2167+ }
2168+ return tuple;
2169+ }
2170+ default :
2171+ Py_UNREACHABLE ();
2172+ }
2173+ }
2174+
2175+ PyErr_Format (PyExc_ValueError, " unknown config option name: %s" , name);
2176+ return NULL ;
2177+ }
2178+
2179+ static inline int
2180+ PyConfig_GetInt (const char *name, int *value)
2181+ {
2182+ PyObject *obj = PyConfig_Get (name);
2183+ if (obj == NULL ) {
2184+ return -1 ;
2185+ }
2186+
2187+ if (!PyLong_Check (obj)) {
2188+ Py_DECREF (obj);
2189+ PyErr_Format (PyExc_TypeError, " config option %s is not an int" , name);
2190+ return -1 ;
2191+ }
2192+
2193+ int as_int = PyLong_AsInt (obj);
2194+ Py_DECREF (obj);
2195+ if (as_int == -1 && PyErr_Occurred ()) {
2196+ PyErr_Format (PyExc_OverflowError,
2197+ " config option %s value does not fit into a C int" , name);
2198+ return -1 ;
2199+ }
2200+
2201+ *value = as_int;
2202+ return 0 ;
2203+ }
2204+ #endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION)
2205+
2206+
19772207#ifdef __cplusplus
19782208}
19792209#endif
0 commit comments