1 /* Python interpreter main program */
2 
3 #include "Python.h"
4 #include "osdefs.h"
5 #include "code.h" /* For CO_FUTURE_DIVISION */
6 #include "import.h"
7 
8 #ifdef __VMS
9 #include <unixlib.h>
10 #endif
11 
12 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
13 #ifdef HAVE_IO_H
14 #include <io.h>
15 #endif
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif
19 #endif
20 
21 #if (defined(PYOS_OS2) && !defined(PYCC_GCC)) || defined(MS_WINDOWS)
22 #define PYTHONHOMEHELP "<prefix>\\lib"
23 #else
24 #if defined(PYOS_OS2) && defined(PYCC_GCC)
25 #define PYTHONHOMEHELP "<prefix>/Lib"
26 #else
27 #define PYTHONHOMEHELP "<prefix>/pythonX.X"
28 #endif
29 #endif
30 
31 #include "pygetopt.h"
32 
33 #define COPYRIGHT \
34     "Type \"help\", \"copyright\", \"credits\" or \"license\" " \
35     "for more information."
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
41 /* For Py_GetArgcArgv(); set by main() */
42 static char **orig_argv;
43 static int  orig_argc;
44 
45 /* command line options */
46 #define BASE_OPTS "3bBc:dEhiJm:OQ:RsStuUvVW:xX?"
47 
48 #ifndef RISCOS
49 #define PROGRAM_OPTS BASE_OPTS
50 #else /*RISCOS*/
51 /* extra option saying that we are running under a special task window
52    frontend; especially my_readline will behave different */
53 #define PROGRAM_OPTS BASE_OPTS "w"
54 /* corresponding flag */
55 extern int Py_RISCOSWimpFlag;
56 #endif /*RISCOS*/
57 
58 /* Short usage message (with %s for argv0) */
59 static char *usage_line =
60 "usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...\n";
61 
62 /* Long usage message, split into parts < 512 bytes */
63 static char *usage_1 = "\
64 Options and arguments (and corresponding environment variables):\n\
65 -b     : issue warnings about comparing bytearray with unicode\n\
66          (-bb: issue errors)\n\
67 -B     : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x\n\
68 -c cmd : program passed in as string (terminates option list)\n\
69 -d     : debug output from parser; also PYTHONDEBUG=x\n\
70 -E     : ignore PYTHON* environment variables (such as PYTHONPATH)\n\
71 -h     : print this help message and exit (also --help)\n\
72 -i     : inspect interactively after running script; forces a prompt even\n\
73 ";
74 static char *usage_2 = "\
75          if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n\
76 -m mod : run library module as a script (terminates option list)\n\
77 -O     : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n\
78 -OO    : remove doc-strings in addition to the -O optimizations\n\
79 -R     : use a pseudo-random salt to make hash() values of various types be\n\
80          unpredictable between separate invocations of the interpreter, as\n\
81          a defense against denial-of-service attacks\n\
82 -Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n\
83 -s     : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\
84 -S     : don't imply 'import site' on initialization\n\
85 -t     : issue warnings about inconsistent tab usage (-tt: issue errors)\n\
86 ";
87 static char *usage_3 = "\
88 -u     : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x\n\
89          see man page for details on internal buffering relating to '-u'\n\
90 -v     : verbose (trace import statements); also PYTHONVERBOSE=x\n\
91          can be supplied multiple times to increase verbosity\n\
92 -V     : print the Python version number and exit (also --version)\n\
93 -W arg : warning control; arg is action:message:category:module:lineno\n\
94          also PYTHONWARNINGS=arg\n\
95 -x     : skip first line of source, allowing use of non-Unix forms of #!cmd\n\
96 ";
97 static char *usage_4 = "\
98 -3     : warn about Python 3.x incompatibilities that 2to3 cannot trivially fix\n\
99 file   : program read from script file\n\
100 -      : program read from stdin (default; interactive mode if a tty)\n\
101 arg ...: arguments passed to program in sys.argv[1:]\n\n\
102 Other environment variables:\n\
103 PYTHONSTARTUP: file executed on interactive startup (no default)\n\
104 PYTHONPATH   : '%c'-separated list of directories prefixed to the\n\
105                default module search path.  The result is sys.path.\n\
106 ";
107 static char *usage_5 = "\
108 PYTHONHOME   : alternate <prefix> directory (or <prefix>%c<exec_prefix>).\n\
109                The default module search path uses %s.\n\
110 PYTHONCASEOK : ignore case in 'import' statements (Windows).\n\
111 PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr.\n\
112 ";
113 static char *usage_6 = "\
114 PYTHONHASHSEED: if this variable is set to 'random', the effect is the same\n\
115    as specifying the -R option: a random value is used to seed the hashes of\n\
116    str, bytes and datetime objects.  It can also be set to an integer\n\
117    in the range [0,4294967295] to get hash values with a predictable seed.\n\
118 ";
119 
120 
121 static int
usage(int exitcode,char * program)122 usage(int exitcode, char* program)
123 {
124     FILE *f = exitcode ? stderr : stdout;
125 
126     fprintf(f, usage_line, program);
127     if (exitcode)
128         fprintf(f, "Try `python -h' for more information.\n");
129     else {
130         fputs(usage_1, f);
131         fputs(usage_2, f);
132         fputs(usage_3, f);
133         fprintf(f, usage_4, DELIM);
134         fprintf(f, usage_5, DELIM, PYTHONHOMEHELP);
135         fputs(usage_6, f);
136     }
137 #if defined(__VMS)
138     if (exitcode == 0) {
139         /* suppress 'error' message */
140         return 1;
141     }
142     else {
143         /* STS$M_INHIB_MSG + SS$_ABORT */
144         return 0x1000002c;
145     }
146 #else
147     return exitcode;
148 #endif
149     /*NOTREACHED*/
150 }
151 
152 // TODO(b/141583221): stop leaks
__asan_default_options()153 const char *__asan_default_options() {
154     return "detect_leaks=0";
155 }
156 
RunStartupFile(PyCompilerFlags * cf)157 static void RunStartupFile(PyCompilerFlags *cf)
158 {
159     char *startup = Py_GETENV("PYTHONSTARTUP");
160     if (startup != NULL && startup[0] != '\0') {
161         FILE *fp = fopen(startup, "r");
162         if (fp != NULL) {
163             (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf);
164             PyErr_Clear();
165             fclose(fp);
166         } else {
167             int save_errno;
168             save_errno = errno;
169             PySys_WriteStderr("Could not open PYTHONSTARTUP\n");
170             errno = save_errno;
171             PyErr_SetFromErrnoWithFilename(PyExc_IOError,
172                                            startup);
173             PyErr_Print();
174             PyErr_Clear();
175         }
176     }
177 }
178 
179 
RunModule(char * module,int set_argv0)180 static int RunModule(char *module, int set_argv0)
181 {
182     PyObject *runpy, *runmodule, *runargs, *result;
183     runpy = PyImport_ImportModule("runpy");
184     if (runpy == NULL) {
185         fprintf(stderr, "Could not import runpy module\n");
186         return -1;
187     }
188     runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main");
189     if (runmodule == NULL) {
190         fprintf(stderr, "Could not access runpy._run_module_as_main\n");
191         Py_DECREF(runpy);
192         return -1;
193     }
194     runargs = Py_BuildValue("(si)", module, set_argv0);
195     if (runargs == NULL) {
196         fprintf(stderr,
197             "Could not create arguments for runpy._run_module_as_main\n");
198         Py_DECREF(runpy);
199         Py_DECREF(runmodule);
200         return -1;
201     }
202     result = PyObject_Call(runmodule, runargs, NULL);
203     if (result == NULL) {
204         PyErr_Print();
205     }
206     Py_DECREF(runpy);
207     Py_DECREF(runmodule);
208     Py_DECREF(runargs);
209     if (result == NULL) {
210         return -1;
211     }
212     Py_DECREF(result);
213     return 0;
214 }
215 
RunMainFromImporter(char * filename)216 static int RunMainFromImporter(char *filename)
217 {
218     PyObject *argv0 = NULL, *importer = NULL;
219 
220     if ((argv0 = PyString_FromString(filename)) &&
221         (importer = PyImport_GetImporter(argv0)) &&
222         (importer->ob_type != &PyNullImporter_Type))
223     {
224              /* argv0 is usable as an import source, so
225                     put it in sys.path[0] and import __main__ */
226         PyObject *sys_path = NULL;
227         if ((sys_path = PySys_GetObject("path")) &&
228             !PyList_SetItem(sys_path, 0, argv0))
229         {
230             Py_INCREF(argv0);
231             Py_DECREF(importer);
232             sys_path = NULL;
233             return RunModule("__main__", 0) != 0;
234         }
235     }
236     Py_XDECREF(argv0);
237     Py_XDECREF(importer);
238     if (PyErr_Occurred()) {
239         PyErr_Print();
240         return 1;
241     }
242     return -1;
243 }
244 
245 
246 /* Main program */
247 
248 int
Py_Main(int argc,char ** argv)249 Py_Main(int argc, char **argv)
250 {
251     int c;
252     int sts;
253     char *command = NULL;
254     char *filename = NULL;
255     char *module = NULL;
256     FILE *fp = stdin;
257     char *p;
258     int unbuffered = 0;
259     int skipfirstline = 0;
260     int stdin_is_interactive = 0;
261     int help = 0;
262     int version = 0;
263     int saw_unbuffered_flag = 0;
264     PyCompilerFlags cf;
265 
266     cf.cf_flags = 0;
267 
268     orig_argc = argc;           /* For Py_GetArgcArgv() */
269     orig_argv = argv;
270 
271 #ifdef RISCOS
272     Py_RISCOSWimpFlag = 0;
273 #endif
274 
275     /* Hash randomization needed early for all string operations
276        (including -W and -X options). */
277     _PyOS_opterr = 0;  /* prevent printing the error in 1st pass */
278     while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
279         if (c == 'm' || c == 'c') {
280             /* -c / -m is the last option: following arguments are
281                not interpreter options. */
282             break;
283         }
284         switch (c) {
285         case 'E':
286             Py_IgnoreEnvironmentFlag++;
287             break;
288         case 'R':
289             Py_HashRandomizationFlag++;
290             break;
291         }
292     }
293     /* The variable is only tested for existence here; _PyRandom_Init will
294        check its value further. */
295     if (!Py_HashRandomizationFlag &&
296         (p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0')
297         Py_HashRandomizationFlag = 1;
298 
299     _PyRandom_Init();
300 
301     PySys_ResetWarnOptions();
302     _PyOS_ResetGetOpt();
303 
304     while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
305         if (c == 'c') {
306             /* -c is the last option; following arguments
307                that look like options are left for the
308                command to interpret. */
309             command = (char *)malloc(strlen(_PyOS_optarg) + 2);
310             if (command == NULL)
311                 Py_FatalError(
312                    "not enough memory to copy -c argument");
313             strcpy(command, _PyOS_optarg);
314             strcat(command, "\n");
315             break;
316         }
317 
318         if (c == 'm') {
319             /* -m is the last option; following arguments
320                that look like options are left for the
321                module to interpret. */
322             module = (char *)malloc(strlen(_PyOS_optarg) + 2);
323             if (module == NULL)
324                 Py_FatalError(
325                    "not enough memory to copy -m argument");
326             strcpy(module, _PyOS_optarg);
327             break;
328         }
329 
330         switch (c) {
331         case 'b':
332             Py_BytesWarningFlag++;
333             break;
334 
335         case 'd':
336             Py_DebugFlag++;
337             break;
338 
339         case '3':
340             Py_Py3kWarningFlag++;
341             if (!Py_DivisionWarningFlag)
342                 Py_DivisionWarningFlag = 1;
343             break;
344 
345         case 'Q':
346             if (strcmp(_PyOS_optarg, "old") == 0) {
347                 Py_DivisionWarningFlag = 0;
348                 break;
349             }
350             if (strcmp(_PyOS_optarg, "warn") == 0) {
351                 Py_DivisionWarningFlag = 1;
352                 break;
353             }
354             if (strcmp(_PyOS_optarg, "warnall") == 0) {
355                 Py_DivisionWarningFlag = 2;
356                 break;
357             }
358             if (strcmp(_PyOS_optarg, "new") == 0) {
359                 /* This only affects __main__ */
360                 cf.cf_flags |= CO_FUTURE_DIVISION;
361                 /* And this tells the eval loop to treat
362                    BINARY_DIVIDE as BINARY_TRUE_DIVIDE */
363                 _Py_QnewFlag = 1;
364                 break;
365             }
366             fprintf(stderr,
367                 "-Q option should be `-Qold', "
368                 "`-Qwarn', `-Qwarnall', or `-Qnew' only\n");
369             return usage(2, argv[0]);
370             /* NOTREACHED */
371 
372         case 'i':
373             Py_InspectFlag++;
374             Py_InteractiveFlag++;
375             break;
376 
377         /* case 'J': reserved for Jython */
378 
379         case 'O':
380             Py_OptimizeFlag++;
381             break;
382 
383         case 'B':
384             Py_DontWriteBytecodeFlag++;
385             break;
386 
387         case 's':
388             Py_NoUserSiteDirectory++;
389             break;
390 
391         case 'S':
392             Py_NoSiteFlag++;
393             break;
394 
395         case 'E':
396             /* Already handled above */
397             break;
398 
399         case 't':
400             Py_TabcheckFlag++;
401             break;
402 
403         case 'u':
404             unbuffered++;
405             saw_unbuffered_flag = 1;
406             break;
407 
408         case 'v':
409             Py_VerboseFlag++;
410             break;
411 
412 #ifdef RISCOS
413         case 'w':
414             Py_RISCOSWimpFlag = 1;
415             break;
416 #endif
417 
418         case 'x':
419             skipfirstline = 1;
420             break;
421 
422         /* case 'X': reserved for implementation-specific arguments */
423 
424         case 'U':
425             Py_UnicodeFlag++;
426             break;
427         case 'h':
428         case '?':
429             help++;
430             break;
431         case 'V':
432             version++;
433             break;
434 
435         case 'W':
436             PySys_AddWarnOption(_PyOS_optarg);
437             break;
438 
439         case 'R':
440             /* Already handled above */
441             break;
442 
443         /* This space reserved for other options */
444 
445         default:
446             return usage(2, argv[0]);
447             /*NOTREACHED*/
448 
449         }
450     }
451 
452     if (help)
453         return usage(0, argv[0]);
454 
455     if (version) {
456         fprintf(stderr, "Python %s\n", PY_VERSION);
457         return 0;
458     }
459 
460     if (Py_Py3kWarningFlag && !Py_TabcheckFlag)
461         /* -3 implies -t (but not -tt) */
462         Py_TabcheckFlag = 1;
463 
464     if (!Py_InspectFlag &&
465         (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
466         Py_InspectFlag = 1;
467     if (!saw_unbuffered_flag &&
468         (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
469         unbuffered = 1;
470 
471     if (!Py_NoUserSiteDirectory &&
472         (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
473         Py_NoUserSiteDirectory = 1;
474 
475     if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') {
476         char *buf, *warning;
477 
478         buf = (char *)malloc(strlen(p) + 1);
479         if (buf == NULL)
480             Py_FatalError(
481                "not enough memory to copy PYTHONWARNINGS");
482         strcpy(buf, p);
483         for (warning = strtok(buf, ",");
484              warning != NULL;
485              warning = strtok(NULL, ","))
486             PySys_AddWarnOption(warning);
487         free(buf);
488     }
489 
490     if (command == NULL && module == NULL && _PyOS_optind < argc &&
491         strcmp(argv[_PyOS_optind], "-") != 0)
492     {
493 #ifdef __VMS
494         filename = decc$translate_vms(argv[_PyOS_optind]);
495         if (filename == (char *)0 || filename == (char *)-1)
496             filename = argv[_PyOS_optind];
497 
498 #else
499         filename = argv[_PyOS_optind];
500 #endif
501     }
502 
503     stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0);
504 
505     if (unbuffered) {
506 #if defined(MS_WINDOWS) || defined(__CYGWIN__)
507         _setmode(fileno(stdin), O_BINARY);
508         _setmode(fileno(stdout), O_BINARY);
509 #endif
510 #ifdef HAVE_SETVBUF
511         setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
512         setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
513         setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
514 #else /* !HAVE_SETVBUF */
515         setbuf(stdin,  (char *)NULL);
516         setbuf(stdout, (char *)NULL);
517         setbuf(stderr, (char *)NULL);
518 #endif /* !HAVE_SETVBUF */
519     }
520     else if (Py_InteractiveFlag) {
521 #ifdef MS_WINDOWS
522         /* Doesn't have to have line-buffered -- use unbuffered */
523         /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
524         setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
525 #else /* !MS_WINDOWS */
526 #ifdef HAVE_SETVBUF
527         setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
528         setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
529 #endif /* HAVE_SETVBUF */
530 #endif /* !MS_WINDOWS */
531         /* Leave stderr alone - it should be unbuffered anyway. */
532     }
533 #ifdef __VMS
534     else {
535         setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ);
536     }
537 #endif /* __VMS */
538 
539 #ifdef __APPLE__
540     /* On MacOS X, when the Python interpreter is embedded in an
541        application bundle, it gets executed by a bootstrapping script
542        that does os.execve() with an argv[0] that's different from the
543        actual Python executable. This is needed to keep the Finder happy,
544        or rather, to work around Apple's overly strict requirements of
545        the process name. However, we still need a usable sys.executable,
546        so the actual executable path is passed in an environment variable.
547        See Lib/plat-mac/bundlebuiler.py for details about the bootstrap
548        script. */
549     if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0')
550         Py_SetProgramName(p);
551     else
552         Py_SetProgramName(argv[0]);
553 #else
554     Py_SetProgramName(argv[0]);
555 #endif
556     Py_Initialize();
557 
558     if (Py_VerboseFlag ||
559         (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) {
560         fprintf(stderr, "Python %s on %s\n",
561             Py_GetVersion(), Py_GetPlatform());
562         if (!Py_NoSiteFlag)
563             fprintf(stderr, "%s\n", COPYRIGHT);
564     }
565 
566     if (command != NULL) {
567         /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
568         _PyOS_optind--;
569         argv[_PyOS_optind] = "-c";
570     }
571 
572     if (module != NULL) {
573         /* Backup _PyOS_optind and force sys.argv[0] = '-c'
574            so that PySys_SetArgv correctly sets sys.path[0] to ''
575            rather than looking for a file called "-m". See
576            tracker issue #8202 for details. */
577         _PyOS_optind--;
578         argv[_PyOS_optind] = "-c";
579     }
580 
581     PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
582 
583     if ((Py_InspectFlag || (command == NULL && filename == NULL && module == NULL)) &&
584         isatty(fileno(stdin))) {
585         PyObject *v;
586         v = PyImport_ImportModule("readline");
587         if (v == NULL)
588             PyErr_Clear();
589         else
590             Py_DECREF(v);
591     }
592 
593     if (command) {
594         sts = PyRun_SimpleStringFlags(command, &cf) != 0;
595         free(command);
596     } else if (module) {
597         sts = (RunModule(module, 1) != 0);
598         free(module);
599     }
600     else {
601 
602         if (filename == NULL && stdin_is_interactive) {
603             Py_InspectFlag = 0; /* do exit on SystemExit */
604             RunStartupFile(&cf);
605         }
606         /* XXX */
607 
608         sts = -1;               /* keep track of whether we've already run __main__ */
609 
610         if (filename != NULL) {
611             sts = RunMainFromImporter(filename);
612         }
613 
614         if (sts==-1 && filename!=NULL) {
615             if ((fp = fopen(filename, "r")) == NULL) {
616                 fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n",
617                     argv[0], filename, errno, strerror(errno));
618 
619                 return 2;
620             }
621             else if (skipfirstline) {
622                 int ch;
623                 /* Push back first newline so line numbers
624                    remain the same */
625                 while ((ch = getc(fp)) != EOF) {
626                     if (ch == '\n') {
627                         (void)ungetc(ch, fp);
628                         break;
629                     }
630                 }
631             }
632             {
633                 /* XXX: does this work on Win/Win64? (see posix_fstat) */
634                 struct stat sb;
635                 if (fstat(fileno(fp), &sb) == 0 &&
636                     S_ISDIR(sb.st_mode)) {
637                     fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename);
638                     fclose(fp);
639                     return 1;
640                 }
641             }
642         }
643 
644         if (sts==-1) {
645             /* call pending calls like signal handlers (SIGINT) */
646             if (Py_MakePendingCalls() == -1) {
647                 PyErr_Print();
648                 sts = 1;
649             } else {
650                 sts = PyRun_AnyFileExFlags(
651                     fp,
652                     filename == NULL ? "<stdin>" : filename,
653                     filename != NULL, &cf) != 0;
654             }
655         }
656 
657     }
658 
659     /* Check this environment variable at the end, to give programs the
660      * opportunity to set it from Python.
661      */
662     if (!Py_InspectFlag &&
663         (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
664     {
665         Py_InspectFlag = 1;
666     }
667 
668     if (Py_InspectFlag && stdin_is_interactive &&
669         (filename != NULL || command != NULL || module != NULL)) {
670         Py_InspectFlag = 0;
671         /* XXX */
672         sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
673     }
674 
675     Py_Finalize();
676 #ifdef RISCOS
677     if (Py_RISCOSWimpFlag)
678         fprintf(stderr, "\x0cq\x0c"); /* make frontend quit */
679 #endif
680 
681 #ifdef __INSURE__
682     /* Insure++ is a memory analysis tool that aids in discovering
683      * memory leaks and other memory problems.  On Python exit, the
684      * interned string dictionary is flagged as being in use at exit
685      * (which it is).  Under normal circumstances, this is fine because
686      * the memory will be automatically reclaimed by the system.  Under
687      * memory debugging, it's a huge source of useless noise, so we
688      * trade off slower shutdown for less distraction in the memory
689      * reports.  -baw
690      */
691     _Py_ReleaseInternedStrings();
692 #endif /* __INSURE__ */
693 
694     return sts;
695 }
696 
697 /* this is gonna seem *real weird*, but if you put some other code between
698    Py_Main() and Py_GetArgcArgv() you will need to adjust the test in the
699    while statement in Misc/gdbinit:ppystack */
700 
701 /* Make the *original* argc/argv available to other modules.
702    This is rare, but it is needed by the secureware extension. */
703 
704 void
Py_GetArgcArgv(int * argc,char *** argv)705 Py_GetArgcArgv(int *argc, char ***argv)
706 {
707     *argc = orig_argc;
708     *argv = orig_argv;
709 }
710 
711 #ifdef __cplusplus
712 }
713 #endif
714 
715