@@ -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,229 @@ 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+ PYTHONCAPI_COMPAT_SPEC (buffered_stdio, BOOL, _Py_NULL),
2032+ PYTHONCAPI_COMPAT_SPEC (check_hash_pycs_mode, WSTR, _Py_NULL),
2033+ #if 0x030B0000 <= PY_VERSION_HEX
2034+ PYTHONCAPI_COMPAT_SPEC (code_debug_ranges, BOOL, _Py_NULL),
2035+ #endif
2036+ PYTHONCAPI_COMPAT_SPEC (configure_c_stdio, BOOL, _Py_NULL),
2037+ #if 0x030D0000 <= PY_VERSION_HEX
2038+ PYTHONCAPI_COMPAT_SPEC (cpu_count, INT, _Py_NULL),
2039+ #endif
2040+ PYTHONCAPI_COMPAT_SPEC (dev_mode, BOOL, _Py_NULL),
2041+ PYTHONCAPI_COMPAT_SPEC (dump_refs, BOOL, _Py_NULL),
2042+ #if 0x030B0000 <= PY_VERSION_HEX
2043+ PYTHONCAPI_COMPAT_SPEC (dump_refs_file, WSTR_OPT, _Py_NULL),
2044+ #endif
2045+ #ifdef Py_GIL_DISABLED
2046+ PYTHONCAPI_COMPAT_SPEC (enable_gil, INT, _Py_NULL),
2047+ #endif
2048+ PYTHONCAPI_COMPAT_SPEC (faulthandler, BOOL, _Py_NULL),
2049+ PYTHONCAPI_COMPAT_SPEC (filesystem_encoding, WSTR, _Py_NULL),
2050+ PYTHONCAPI_COMPAT_SPEC (filesystem_errors, WSTR, _Py_NULL),
2051+ PYTHONCAPI_COMPAT_SPEC (hash_seed, ULONG, _Py_NULL),
2052+ PYTHONCAPI_COMPAT_SPEC (home, WSTR_OPT, _Py_NULL),
2053+ PYTHONCAPI_COMPAT_SPEC (import_time, BOOL, _Py_NULL),
2054+ PYTHONCAPI_COMPAT_SPEC (install_signal_handlers, BOOL, _Py_NULL),
2055+ PYTHONCAPI_COMPAT_SPEC (isolated, BOOL, _Py_NULL),
2056+ #ifdef MS_WINDOWS
2057+ PYTHONCAPI_COMPAT_SPEC (legacy_windows_stdio, BOOL, _Py_NULL),
2058+ #endif
2059+ PYTHONCAPI_COMPAT_SPEC (malloc_stats, BOOL, _Py_NULL),
2060+ #if 0x030A0000 <= PY_VERSION_HEX
2061+ PYTHONCAPI_COMPAT_SPEC (orig_argv, WSTR_LIST, " orig_argv" ),
2062+ #endif
2063+ PYTHONCAPI_COMPAT_SPEC (parse_argv, BOOL, _Py_NULL),
2064+ PYTHONCAPI_COMPAT_SPEC (pathconfig_warnings, BOOL, _Py_NULL),
2065+ #if 0x030C0000 <= PY_VERSION_HEX
2066+ PYTHONCAPI_COMPAT_SPEC (perf_profiling, UINT, _Py_NULL),
2067+ #endif
2068+ PYTHONCAPI_COMPAT_SPEC (program_name, WSTR, _Py_NULL),
2069+ PYTHONCAPI_COMPAT_SPEC (run_command, WSTR_OPT, _Py_NULL),
2070+ PYTHONCAPI_COMPAT_SPEC (run_filename, WSTR_OPT, _Py_NULL),
2071+ PYTHONCAPI_COMPAT_SPEC (run_module, WSTR_OPT, _Py_NULL),
2072+ #if 0x030B0000 <= PY_VERSION_HEX
2073+ PYTHONCAPI_COMPAT_SPEC (safe_path, BOOL, _Py_NULL),
2074+ #endif
2075+ PYTHONCAPI_COMPAT_SPEC (show_ref_count, BOOL, _Py_NULL),
2076+ PYTHONCAPI_COMPAT_SPEC (site_import, BOOL, _Py_NULL),
2077+ PYTHONCAPI_COMPAT_SPEC (skip_source_first_line, BOOL, _Py_NULL),
2078+ PYTHONCAPI_COMPAT_SPEC (stdio_encoding, WSTR, _Py_NULL),
2079+ PYTHONCAPI_COMPAT_SPEC (stdio_errors, WSTR, _Py_NULL),
2080+ PYTHONCAPI_COMPAT_SPEC (tracemalloc, UINT, _Py_NULL),
2081+ #if 0x030B0000 <= PY_VERSION_HEX
2082+ PYTHONCAPI_COMPAT_SPEC (use_frozen_modules, BOOL, _Py_NULL),
2083+ #endif
2084+ PYTHONCAPI_COMPAT_SPEC (use_hash_seed, BOOL, _Py_NULL),
2085+ #if 0x030D0000 <= PY_VERSION_HEX && defined(__APPLE__)
2086+ PYTHONCAPI_COMPAT_SPEC (use_system_logger, BOOL, _Py_NULL),
2087+ #endif
2088+ PYTHONCAPI_COMPAT_SPEC (user_site_directory, BOOL, _Py_NULL),
2089+ #if 0x030A0000 <= PY_VERSION_HEX
2090+ PYTHONCAPI_COMPAT_SPEC (warn_default_encoding, BOOL, _Py_NULL),
2091+ #endif
2092+ };
2093+
2094+ #undef PYTHONCAPI_COMPAT_SPEC
2095+
2096+ const PyConfigSpec *spec;
2097+ int found = 0 ;
2098+ for (size_t i=0 ; i < Py_ARRAY_LENGTH (config_spec); i++) {
2099+ spec = &config_spec[i];
2100+ if (strcmp (spec->name , name) == 0 ) {
2101+ found = 1 ;
2102+ break ;
2103+ }
2104+ }
2105+ if (found) {
2106+ if (spec->sys_attr != NULL ) {
2107+ PyObject *value = PySys_GetObject (spec->sys_attr );
2108+ if (value == NULL ) {
2109+ PyErr_Format (PyExc_RuntimeError, " lost sys.%s" , spec->sys_attr );
2110+ return NULL ;
2111+ }
2112+ return Py_NewRef (value);
2113+ }
2114+
2115+ extern const PyConfig* _Py_GetConfig (void );
2116+ const PyConfig *config = _Py_GetConfig ();
2117+ void *member = (char *)config + spec->offset ;
2118+ switch (spec->type ) {
2119+ case _PyConfig_MEMBER_INT:
2120+ case _PyConfig_MEMBER_UINT:
2121+ {
2122+ int value = *(int *)member;
2123+ return PyLong_FromLong (value);
2124+ }
2125+ case _PyConfig_MEMBER_BOOL:
2126+ {
2127+ int value = *(int *)member;
2128+ return PyBool_FromLong (value != 0 );
2129+ }
2130+ case _PyConfig_MEMBER_ULONG:
2131+ {
2132+ unsigned long value = *(unsigned long *)member;
2133+ return PyLong_FromUnsignedLong (value);
2134+ }
2135+ case _PyConfig_MEMBER_WSTR:
2136+ case _PyConfig_MEMBER_WSTR_OPT:
2137+ {
2138+ wchar_t *wstr = *(wchar_t **)member;
2139+ if (wstr != NULL ) {
2140+ return PyUnicode_FromWideChar (wstr, -1 );
2141+ }
2142+ else {
2143+ return Py_NewRef (Py_None);
2144+ }
2145+ }
2146+ case _PyConfig_MEMBER_WSTR_LIST:
2147+ {
2148+ const PyWideStringList *list = (const PyWideStringList *)member;
2149+ PyObject *tuple = PyTuple_New (list->length );
2150+ if (tuple == NULL ) {
2151+ return NULL ;
2152+ }
2153+
2154+ for (Py_ssize_t i = 0 ; i < list->length ; i++) {
2155+ PyObject *item = PyUnicode_FromWideChar (list->items [i], -1 );
2156+ if (item == NULL ) {
2157+ Py_DECREF (tuple);
2158+ return NULL ;
2159+ }
2160+ PyTuple_SET_ITEM (tuple, i, item);
2161+ }
2162+ return tuple;
2163+ }
2164+ default :
2165+ Py_UNREACHABLE ();
2166+ }
2167+ }
2168+
2169+ PyErr_Format (PyExc_ValueError, " unknown config option name: %s" , name);
2170+ return NULL ;
2171+ }
2172+
2173+ static inline int
2174+ PyConfig_GetInt (const char *name, int *value)
2175+ {
2176+ PyObject *obj = PyConfig_Get (name);
2177+ if (obj == NULL ) {
2178+ return -1 ;
2179+ }
2180+
2181+ if (!PyLong_Check (obj)) {
2182+ Py_DECREF (obj);
2183+ PyErr_Format (PyExc_TypeError, " config option %s is not an int" , name);
2184+ return -1 ;
2185+ }
2186+
2187+ int as_int = PyLong_AsInt (obj);
2188+ Py_DECREF (obj);
2189+ if (as_int == -1 && PyErr_Occurred ()) {
2190+ PyErr_Format (PyExc_OverflowError,
2191+ " config option %s value does not fit into a C int" , name);
2192+ return -1 ;
2193+ }
2194+
2195+ *value = as_int;
2196+ return 0 ;
2197+ }
2198+ #endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION)
2199+
2200+
19772201#ifdef __cplusplus
19782202}
19792203#endif
0 commit comments