diff -r d0b0ff0594db Include/sysmodule.h --- a/Include/sysmodule.h Wed Oct 13 19:14:16 2010 +0200 +++ b/Include/sysmodule.h Wed Oct 13 20:58:52 2010 +0200 @@ -27,6 +27,9 @@ PyAPI_FUNC(void) PySys_AddWarnOption(con PyAPI_FUNC(void) PySys_AddWarnOptionUnicode(PyObject *); PyAPI_FUNC(int) PySys_HasWarnOptions(void); +PyAPI_FUNC(void) PySys_AddXOption(const wchar_t *); +PyAPI_FUNC(PyObject *) PySys_GetXOptions(void); + #ifdef __cplusplus } #endif diff -r d0b0ff0594db Lib/test/test_cmd_line.py --- a/Lib/test/test_cmd_line.py Wed Oct 13 19:14:16 2010 +0200 +++ b/Lib/test/test_cmd_line.py Wed Oct 13 20:58:52 2010 +0200 @@ -67,6 +67,16 @@ class CmdLineTest(unittest.TestCase): rc, out, err = assert_python_ok('-vv') self.assertNotIn(b'stack overflow', err) + def test_xoptions(self): + rc, out, err = assert_python_ok('-c', 'import sys; print(sys.xoptions)') + opts = eval(out.splitlines()[0]) + self.assertEqual(opts, {}) + rc, out, err = assert_python_ok( + '-Xa,b=c,d', '-Xe,f=g=h', '-c', 'import sys; print(sys.xoptions)') + opts = eval(out.splitlines()[0]) + self.assertEqual(opts, + {'a': True, 'b': 'c', 'd': True, 'e': True, 'f': 'g=h' }) + def test_run_module(self): # Test expected operation of the '-m' switch # Switch needs an argument diff -r d0b0ff0594db Modules/main.c --- a/Modules/main.c Wed Oct 13 19:14:16 2010 +0200 +++ b/Modules/main.c Wed Oct 13 20:58:52 2010 +0200 @@ -47,7 +47,7 @@ static wchar_t **orig_argv; static int orig_argc; /* command line options */ -#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX?" +#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX:?" #define PROGRAM_OPTS BASE_OPTS @@ -84,6 +84,7 @@ static char *usage_3 = "\ -W arg : warning control; arg is action:message:category:module:lineno\n\ also PYTHONWARNINGS=arg\n\ -x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\ +-X opt : set implementation-specific option\n\ "; static char *usage_4 = "\ file : program read from script file\n\ @@ -410,8 +411,6 @@ Py_Main(int argc, wchar_t **argv) skipfirstline = 1; break; - /* case 'X': reserved for implementation-specific arguments */ - case 'h': case '?': help++; @@ -425,6 +424,10 @@ Py_Main(int argc, wchar_t **argv) PySys_AddWarnOption(_PyOS_optarg); break; + case 'X': + PySys_AddXOption(_PyOS_optarg); + break; + /* This space reserved for other options */ default: diff -r d0b0ff0594db Python/getopt.c --- a/Python/getopt.c Wed Oct 13 19:14:16 2010 +0200 +++ b/Python/getopt.c Wed Oct 13 20:58:52 2010 +0200 @@ -89,12 +89,6 @@ int _PyOS_GetOpt(int argc, wchar_t **arg return '_'; } - if (option == 'X') { - fprintf(stderr, - "-X is reserved for implementation-specific arguments\n"); - return '_'; - } - if ((ptr = wcschr(optstring, option)) == NULL) { if (_PyOS_opterr) fprintf(stderr, "Unknown option: -%c\n", (char)option); diff -r d0b0ff0594db Python/sysmodule.c --- a/Python/sysmodule.c Wed Oct 13 19:14:16 2010 +0200 +++ b/Python/sysmodule.c Wed Oct 13 20:58:52 2010 +0200 @@ -1086,6 +1086,76 @@ PySys_HasWarnOptions(void) return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0; } +static PyObject *xoptions = NULL; + +static PyObject * +get_xoptions(void) +{ + if (xoptions == NULL || !PyDict_Check(xoptions)) { + Py_XDECREF(xoptions); + xoptions = PyDict_New(); + } + return xoptions; +} + +void +PySys_AddXOption(const wchar_t *s) +{ + PyObject *opts; + PyObject *name = NULL, *value = NULL; + const wchar_t *name_end, *opt_end; + int r; + + opts = get_xoptions(); + if (opts == NULL) + goto error; + + for (;;) { + opt_end = wcschr(s, L','); + name_end = wcschr(s, L'='); + if (!name_end || (opt_end && name_end > opt_end)) { + name_end = opt_end; + value = Py_True; + Py_INCREF(value); + } + else { + if (opt_end) + value = PyUnicode_FromWideChar(name_end + 1, opt_end - (name_end + 1)); + else + value = PyUnicode_FromWideChar(name_end + 1, -1); + if (value == NULL) + goto error; + } + if (name_end) + name = PyUnicode_FromWideChar(s, name_end - s); + else + name = PyUnicode_FromWideChar(s, -1); + if (name == NULL) + goto error; + r = PyDict_SetItem(opts, name, value); + Py_DECREF(name); + Py_DECREF(value); + if (!opt_end) + break; + s = opt_end + 1; + } + + return; + +error: + Py_XDECREF(name); + Py_XDECREF(value); + /* No return value, therefore clear error state if possible */ + if (_Py_atomic_load_relaxed(&_PyThreadState_Current)) + PyErr_Clear(); +} + +PyObject * +PySys_GetXOptions(void) +{ + return get_xoptions(); +} + /* XXX This doc string is too long to be a single string literal in VC++ 5.0. Two literals concatenated works just fine. If you have a K&R compiler or other abomination that however *does* understand longer strings, @@ -1531,6 +1601,11 @@ _PySys_Init(void) PyDict_SetItemString(sysdict, "warnoptions", warnoptions); } + v = get_xoptions(); + if (v != NULL) { + PyDict_SetItemString(sysdict, "xoptions", v); + } + /* version_info */ if (VersionInfoType.tp_name == 0) PyStructSequence_InitType(&VersionInfoType, &version_info_desc);