Index: Python/getopt.c =================================================================== --- Python/getopt.c (Revision 45904) +++ Python/getopt.c (Arbeitskopie) @@ -1,31 +1,13 @@ -/*---------------------------------------------------------------------------* - * +/* Python getopt replacement library + * --------------------------------- * - * C++ Library + * Idea based on the previous getopt library used by Python, originally + * written by David Gottner . * - * Copyright 1992-1994, David Gottner - * - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and its - * documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice, this permission notice and - * the following disclaimer notice appear unmodified in all copies. - * - * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I - * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY - * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * Nevertheless, I would like to know about bugs in this library or - * suggestions for improvment. Send bug reports and feedback to - * davegottner@delphi.com. - *---------------------------------------------------------------------------*/ + * Written by Heiko Wundram, 2006. + */ #include -#include #ifdef __cplusplus extern "C" { @@ -38,49 +20,153 @@ int _PyOS_GetOpt(int argc, char **argv, char *optstring) { static char *opt_ptr = ""; - char *ptr; - int option; + char *opt_ptr_save, splitchr = '='; + int islongopt = 0, option = -1; - if (*opt_ptr == '\0') { - - if (_PyOS_optind >= argc || argv[_PyOS_optind][0] != '-' || - argv[_PyOS_optind][1] == '\0' /* lone dash */ ) + if (!*opt_ptr) { + if (_PyOS_optind == argc) return -1; +#ifdef MS_WINDOWS + else if (argv[_PyOS_optind][0] == '/') { + /* Should we error out here? '/' is an additional long + * option format on Windows, so actually, we got an + * empty long option, but let's be lenient for + * now... */ + if (!argv[_PyOS_optind][1]) + return -1; + splitchr = ':'; + islongopt = 1; + } +#endif + else if (argv[_PyOS_optind][0] != '-' || + !argv[_PyOS_optind][1]) + return -1; + else if (argv[_PyOS_optind][1] == '-' && + !argv[_PyOS_optind][2]) + return -1; + else + islongopt = ( argv[_PyOS_optind][1] == '-' ); - else if (strcmp(argv[_PyOS_optind], "--") == 0) { - ++_PyOS_optind; - return -1; + if (!islongopt) { + opt_ptr = argv[_PyOS_optind++]+1; + option = *(opt_ptr++); } - - opt_ptr = &argv[_PyOS_optind++][1]; + else { +#ifdef MS_WINDOWS + opt_ptr = argv[_PyOS_optind] + + ( argv[_PyOS_optind++][0] == '/' ? 1 : 2 ); +#else + opt_ptr = argv[_PyOS_optind++] + 2; +#endif + if (*opt_ptr == splitchr) { + /* Lets not be lenient here: specifying a long + * option which only is a parameter is a + * complete NO NO. */ + if (_PyOS_opterr) + fprintf(stderr, + "No option name, but argument: '%s'\n", + argv[_PyOS_optind-1]); + /* New return value for invalid value, -2, as + * '?' is used for an option on Windows. This + * is somewhat unlucky, but -1 is taken for + * EOF, and 0 would be meaningless... */ + return -2; + } + } } + else + option = *(opt_ptr++); - if ( (option = *opt_ptr++) == '\0') - return -1; - - if ((ptr = strchr(optstring, option)) == NULL) { - if (_PyOS_opterr) - fprintf(stderr, "Unknown option: -%c\n", option); + if (!islongopt) { + /* No long option. Just try to find the character in the option + * string; one pass is sufficient, so we can change the + * optstring variable and don't need an extra pointer. */ + while (*optstring) { + if (*optstring == ':') + ; + else if (*optstring == '(') + while (*(++optstring) != ')'); + else if (*optstring == option) + break; + optstring++; + } - return '?'; + if (!*optstring) { + if (_PyOS_opterr) + fprintf(stderr, + "Invalid option: -%c\n", option); + return -2; + } + + /* Skip over a possible long name for this option. */ + if (*(++optstring) == '(') + while (*(optstring++) != ')'); } + else { + /* Long option name. Try to find an exact equivalent to the + * passed option in long names. */ + opt_ptr_save = opt_ptr; + while (*optstring) { + if (*optstring == '(') { + option = *(optstring-1); + optstring++; + while (*opt_ptr && *opt_ptr != splitchr && + *optstring != ')' && + *optstring == *opt_ptr) { + optstring++; + opt_ptr++; + } - if (*(ptr + 1) == ':') { - if (*opt_ptr != '\0') { - _PyOS_optarg = opt_ptr; - opt_ptr = ""; + if (*optstring == ')' && + (!*opt_ptr || *opt_ptr == splitchr)) + break; + opt_ptr = opt_ptr_save; + } + optstring++; } - else { - if (_PyOS_optind >= argc) { + if (!*optstring ) { + if (_PyOS_opterr) + fprintf(stderr, + "Invalid option: '%s'\n", + argv[_PyOS_optind-1]); + return -2; + } + optstring++; + + if (*opt_ptr == splitchr) { + if (*optstring != ':') { if (_PyOS_opterr) fprintf(stderr, - "Argument expected for the -%c option\n", option); - return '?'; + "Option takes no argument: '%s'\n", + argv[_PyOS_optind-1]); + return -2; } + opt_ptr++; + } + } + /* Set argument corresponding to option state. */ + if (*optstring == ':') { + if (*opt_ptr || *(opt_ptr-1) == splitchr) { + _PyOS_optarg = opt_ptr; + opt_ptr = ""; + } + else if (_PyOS_optind == argc) { + if (_PyOS_opterr) { + if (!islongopt) + fprintf(stderr, + "Argument expected for option: -%c\n", + option); + else + fprintf(stderr, + "Argument expected for option: '%s'\n", + argv[_PyOS_optind-1]); + } + return -2; + } + else _PyOS_optarg = argv[_PyOS_optind++]; - } } return option; @@ -89,4 +175,3 @@ #ifdef __cplusplus } #endif - Index: Lib/test/test_cmd_line.py =================================================================== --- Lib/test/test_cmd_line.py (Revision 45904) +++ Lib/test/test_cmd_line.py (Arbeitskopie) @@ -48,10 +48,18 @@ def test_usage(self): self.assertTrue('usage' in self.start_python('-h')) + self.assertTrue('usage' in self.start_python('--help')) + if sys.platform == 'win32': + self.assertTrue('usage' in self.start_python('/help')) + self.assertTrue('usage' in self.start_python('-?')) + self.assertTrue('usage' in self.start_python('/?')) def test_version(self): version = 'Python %d.%d' % sys.version_info[:2] self.assertTrue(self.start_python('-V').startswith(version)) + self.assertTrue(self.start_python('--version').startswith(version)) + if sys.platform == 'win32': + self.assertTrue(self.start_python('/version').startswith(version)) def test_run_module(self): # Test expected operation of the '-m' switch Index: Modules/main.c =================================================================== --- Modules/main.c (Revision 45904) +++ Modules/main.c (Arbeitskopie) @@ -38,50 +38,88 @@ static int orig_argc; /* command line options */ -#define BASE_OPTS "c:dEhim:OQ:StuUvVW:xX" +#define BASE_OPTS "c:dEh(help)im:OQ:StuUvV(version)W:xX" -#ifndef RISCOS -#define PROGRAM_OPTS BASE_OPTS -#else /*RISCOS*/ +#ifdef RISCOS /* extra option saying that we are running under a special task window frontend; especially my_readline will behave different */ #define PROGRAM_OPTS BASE_OPTS "w" /* corresponding flag */ extern int Py_RISCOSWimpFlag; -#endif /*RISCOS*/ +#else +#ifdef MS_WINDOWS +/* Extra options for command line arguments -? and /?, the latter is taken + care of in Python/getopt.c if MS_WINDOWS is defined */ +#define PROGRAM_OPTS BASE_OPTS "?(?)" +#else +/* All other platforms. */ +#define PROGRAM_OPTS BASE_OPTS +#endif /* MS_WINDOWS */ +#endif /* RISCOS */ /* Short usage message (with %s for argv0) */ static char *usage_line = "usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"; /* Long usage message, split into parts < 512 bytes */ +#ifdef MS_WINDOWS static char *usage_1 = "\ Options and arguments (and corresponding environment variables):\n\ --c cmd : program passed in as string (terminates option list)\n\ --d : debug output from parser (also PYTHONDEBUG=x)\n\ --E : ignore environment variables (such as PYTHONPATH)\n\ --h : print this help message and exit\n\ --i : inspect interactively after running script, (also PYTHONINSPECT=x)\n\ - and force prompts, even if stdin does not appear to be a terminal\n\ +-c cmd : program passed in as string (terminates option list)\n\ +-d : debug output from parser (also PYTHONDEBUG=x)\n\ +-E : ignore environment variables (such as PYTHONPATH)\n\ +-h, --help, /help, -?, /?\n\ + : print this help message and exit\n\ +-i : inspect interactively after running script,\n\ + (also PYTHONINSPECT=x) and force prompts, even if stdin does\n\ + not appear to be a terminal\n\ "; +#else +static char *usage_1 = "\ +Options and arguments (and corresponding environment variables):\n\ +-c cmd : program passed in as string (terminates option list)\n\ +-d : debug output from parser (also PYTHONDEBUG=x)\n\ +-E : ignore environment variables (such as PYTHONPATH)\n\ +-h, --help : print this help message and exit\n\ +-i : inspect interactively after running script,\n\ + (also PYTHONINSPECT=x) and force prompts, even if stdin does\n\ + not appear to be a terminal\n\ +"; +#endif static char *usage_2 = "\ --m mod : run library module as a script (terminates option list)\n\ --O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\ --OO : remove doc-strings in addition to the -O optimizations\n\ --Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n\ --S : don't imply 'import site' on initialization\n\ --t : issue warnings about inconsistent tab usage (-tt: issue errors)\n\ --u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\ +-m mod : run library module as a script (terminates option list)\n\ +-O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\ +-OO : remove doc-strings in addition to the -O optimizations\n\ +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n\ +-S : don't imply 'import site' on initialization\n\ +-t : issue warnings about inconsistent tab usage (-tt: issue errors)\n\ +-u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\ "; +#ifdef MS_WINDOWS static char *usage_3 = "\ - see man page for details on internal buffering relating to '-u'\n\ --v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\ --V : print the Python version number and exit\n\ --W arg : warning control (arg is action:message:category:module:lineno)\n\ --x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\ -file : program read from script file\n\ -- : program read from stdin (default; interactive mode if a tty)\n\ + see man page for details on internal buffering relating to '-u'\n\ +-v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\ +-V, --version, /version\n\ + : print the Python version number and exit\n\ +-W arg : warning control (arg is action:message:category:module:lineno)\n\ +-x : skip first line of source, allowing use of non-Unix forms of\n\ + #!cmd\n\ +file : program read from script file\n\ +- : program read from stdin (default; interactive mode if a tty)\n\ "; +#else +static char *usage_3 = "\ + see man page for details on internal buffering relating to '-u'\n\ +-v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\ +-V, --version\n\ + : print the Python version number and exit\n\ +-W arg : warning control (arg is action:message:category:module:lineno)\n\ +-x : skip first line of source, allowing use of non-Unix forms of\n\ + #!cmd\n\ +file : program read from script file\n\ +- : program read from stdin (default; interactive mode if a tty)\n\ +"; +#endif static char *usage_4 = "\ arg ...: arguments passed to program in sys.argv[1:]\n\ Other environment variables:\n\ @@ -310,6 +348,9 @@ case 'U': Py_UnicodeFlag++; break; +#ifdef MS_WINDOWS + case '?': +#endif case 'h': help++; break;