py-cvs-rel2_1 (Rev 1.2) merge
[python/dscho.git] / Mac / Python / macmain.c
blob10c5a5ff74804897e5a56232124f9ed70dd84067
1 /***********************************************************
2 Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* Python interpreter main program */
27 #include "Python.h"
28 #include "pythonresources.h"
29 #include "import.h"
30 #include "marshal.h"
31 #include "macglue.h"
33 #include <Memory.h>
34 #include <Resources.h>
35 #include <stdio.h>
36 #include <Events.h>
37 #include <Windows.h>
38 #include <Fonts.h>
39 #include <Balloons.h>
40 #ifdef USE_APPEARANCE
41 #include <Gestalt.h>
42 #include <Appearance.h>
43 #endif /* USE_APPEARANCE */
44 #ifdef __MWERKS__
45 #include <SIOUX.h>
46 #define USE_SIOUX
47 extern int ccommand(char ***);
48 #if __profile__ == 1
49 #include <profiler.h>
50 #endif
51 #endif
52 #include <unistd.h>
53 #ifdef USE_MAC_SHARED_LIBRARY
54 extern PyMac_AddLibResources(void);
55 #endif
56 //#ifdef USE_GUSI
57 //#include "GUSISIOUX.h"
58 //#endif
60 #define STARTUP "PythonStartup"
62 #define COPYRIGHT \
63 "Type \"copyright\", \"credits\" or \"license\" for more information."
66 extern int Py_DebugFlag; /* For parser.c, declared in pythonrun.c */
67 extern int Py_VerboseFlag; /* For import.c, declared in pythonrun.c */
68 short PyMac_AppRefNum; /* RefNum of application resource fork */
70 /* For Py_GetArgcArgv(); set by main() */
71 static char **orig_argv;
72 static int orig_argc;
74 /* A flag which remembers whether the user has acknowledged all the console
75 ** output (by typing something)
77 #define STATE_UNKNOWN 0
78 #define STATE_LASTREAD 1
79 #define STATE_LASTWRITE 2
80 int console_output_state = STATE_UNKNOWN;
82 PyMac_PrefRecord PyMac_options;
84 static void Py_Main(int, char **); /* Forward */
85 void PyMac_Exit(int); /* Forward */
87 static void init_appearance()
89 #ifdef USE_APPEARANCE
90 OSErr err;
91 SInt32 response;
93 err = Gestalt(gestaltAppearanceAttr,&response);
94 if ( err ) goto no_appearance;
95 if ( !(response&(1<<gestaltAppearanceExists)) ) goto no_appearance;
96 /* XXXX Should we check the version? Compat-mode? */
97 PyMac_AppearanceCompliant = 1;
98 no_appearance:
99 return;
100 #endif /* USE_APPEARANCE */
102 /* Initialize the Mac toolbox world */
104 static void
105 init_mac_world()
107 #if !TARGET_API_MAC_CARBON
108 /* These aren't needed for carbon */
109 MaxApplZone();
110 InitGraf(&qd.thePort);
111 InitFonts();
112 InitWindows();
113 TEInit();
114 InitDialogs((long)0);
115 InitMenus();
116 #endif
117 InitCursor();
118 init_appearance();
122 ** PyMac_InteractiveOptions - Allow user to set options if option key is pressed
124 static void
125 PyMac_InteractiveOptions(PyMac_PrefRecord *p, int *argcp, char ***argvp)
127 KeyMap rmap;
128 unsigned char *map;
129 short item, type;
130 ControlHandle handle;
131 DialogPtr dialog;
132 Rect rect;
133 int old_argc = *argcp;
134 int i;
137 ** If the preferences disallows interactive options we return,
138 ** similarly of <option> isn't pressed.
140 if (p->nointopt) return;
142 GetKeys(rmap);
143 map = (unsigned char *)rmap;
144 if ( ( map[0x3a>>3] & (1<<(0x3a&7)) ) == 0 ) /* option key is 3a */
145 return;
147 dialog = GetNewDialog(OPT_DIALOG, NULL, (WindowPtr)-1);
148 if ( dialog == NULL ) {
149 printf("Option dialog not found - cannot set options\n");
150 return;
152 SetDialogDefaultItem(dialog, OPT_OK);
153 SetDialogCancelItem(dialog, OPT_CANCEL);
155 /* Set default values */
156 #define SET_OPT_ITEM(num, var) \
157 GetDialogItem(dialog, (num), &type, (Handle *)&handle, &rect); \
158 SetControlValue(handle, (short)p->var);
160 SET_OPT_ITEM(OPT_INSPECT, inspect);
161 SET_OPT_ITEM(OPT_VERBOSE, verbose);
162 SET_OPT_ITEM(OPT_OPTIMIZE, optimize);
163 SET_OPT_ITEM(OPT_UNBUFFERED, unbuffered);
164 SET_OPT_ITEM(OPT_DEBUGGING, debugging);
165 GetDialogItem(dialog, OPT_KEEPALWAYS, &type, (Handle *)&handle, &rect);
166 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_ALWAYS));
167 GetDialogItem(dialog, OPT_KEEPOUTPUT, &type, (Handle *)&handle, &rect);
168 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_OUTPUT));
169 GetDialogItem(dialog, OPT_KEEPERROR, &type, (Handle *)&handle, &rect);
170 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_ERROR));
171 GetDialogItem(dialog, OPT_KEEPNEVER, &type, (Handle *)&handle, &rect);
172 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_NEVER));
173 /* SET_OPT_ITEM(OPT_KEEPCONSOLE, keep_console); */
174 SET_OPT_ITEM(OPT_TABWARN, tabwarn);
175 SET_OPT_ITEM(OPT_NOSITE, nosite);
176 SET_OPT_ITEM(OPT_NONAVSERV, nonavservice);
177 /* The rest are not settable interactively */
179 #undef SET_OPT_ITEM
181 while (1) {
182 handle = NULL;
183 ModalDialog(NULL, &item);
184 if ( item == OPT_OK )
185 break;
186 if ( item == OPT_CANCEL ) {
187 DisposeDialog(dialog);
188 exit(0);
190 #if !TARGET_API_MAC_CARBON
191 if ( item == OPT_HELP ) {
192 HMSetBalloons(!HMGetBalloons());
194 #endif
195 if ( item == OPT_CMDLINE ) {
196 int new_argc, newer_argc;
197 char **new_argv, **newer_argv;
199 new_argc = ccommand(&new_argv);
200 newer_argc = (new_argc-1) + old_argc;
201 newer_argv = malloc((newer_argc+1)*sizeof(char *));
202 if( !newer_argv )
203 Py_FatalError("Cannot malloc argv\n");
204 for(i=0; i<old_argc; i++)
205 newer_argv[i] = (*argvp)[i];
206 for(i=old_argc; i<=newer_argc; i++) /* Copy the NULL too */
207 newer_argv[i] = new_argv[i-old_argc+1];
208 *argvp = newer_argv;
209 *argcp = newer_argc;
211 /* XXXX Is it not safe to use free() here, apparently */
213 #define OPT_ITEM(num, var) \
214 if ( item == (num) ) { \
215 p->var = !p->var; \
216 GetDialogItem(dialog, (num), &type, (Handle *)&handle, &rect); \
217 SetControlValue(handle, (short)p->var); \
220 OPT_ITEM(OPT_INSPECT, inspect);
221 OPT_ITEM(OPT_VERBOSE, verbose);
222 OPT_ITEM(OPT_OPTIMIZE, optimize);
223 OPT_ITEM(OPT_UNBUFFERED, unbuffered);
224 OPT_ITEM(OPT_DEBUGGING, debugging);
225 if ( item == OPT_KEEPALWAYS ) p->keep_console = POPT_KEEPCONSOLE_ALWAYS;
226 if ( item == OPT_KEEPOUTPUT ) p->keep_console = POPT_KEEPCONSOLE_OUTPUT;
227 if ( item == OPT_KEEPERROR ) p->keep_console = POPT_KEEPCONSOLE_ERROR;
228 if ( item == OPT_KEEPNEVER ) p->keep_console = POPT_KEEPCONSOLE_NEVER;
229 GetDialogItem(dialog, OPT_KEEPALWAYS, &type, (Handle *)&handle, &rect);
230 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_ALWAYS));
231 GetDialogItem(dialog, OPT_KEEPOUTPUT, &type, (Handle *)&handle, &rect);
232 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_OUTPUT));
233 GetDialogItem(dialog, OPT_KEEPERROR, &type, (Handle *)&handle, &rect);
234 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_ERROR));
235 GetDialogItem(dialog, OPT_KEEPNEVER, &type, (Handle *)&handle, &rect);
236 SetControlValue(handle, (short)(p->keep_console == POPT_KEEPCONSOLE_NEVER));
237 OPT_ITEM(OPT_TABWARN, tabwarn);
238 OPT_ITEM(OPT_NOSITE, nosite);
239 OPT_ITEM(OPT_NONAVSERV, nonavservice);
241 #undef OPT_ITEM
243 DisposeDialog(dialog);
247 ** Initialization code, shared by interpreter and applets
249 static void
250 init_common(int *argcp, char ***argvp, int embedded)
252 /* Remember resource fork refnum, for later */
253 PyMac_AppRefNum = CurResFile();
255 /* Initialize toolboxes */
256 init_mac_world();
258 #ifdef USE_MAC_SHARED_LIBRARY
259 /* Add the shared library to the stack of resource files */
260 (void)PyMac_init_process_location();
261 PyMac_AddLibResources();
262 #endif
264 #if defined(USE_GUSI1)
265 /* Setup GUSI */
266 GUSIDefaultSetup();
267 PyMac_SetGUSISpin();
268 PyMac_SetGUSIOptions();
269 #endif
270 #if defined(USE_GUSI)
271 atexit(PyMac_StopGUSISpin);
272 #endif
274 #ifdef USE_SIOUX
275 /* Set various SIOUX flags. Some are changed later based on options */
276 /* SIOUXSettings.standalone = 0; /* XXXX Attempting to keep sioux from eating events */
277 SIOUXSettings.asktosaveonclose = 0;
278 SIOUXSettings.showstatusline = 0;
279 SIOUXSettings.tabspaces = 4;
280 #endif
282 /* Get options from preference file (or from applet resource fork) */
283 PyMac_options.keep_console = POPT_KEEPCONSOLE_OUTPUT; /* default-default */
284 PyMac_PreferenceOptions(&PyMac_options);
286 if ( embedded ) {
287 static char *emb_argv[] = {"embedded-python", 0};
289 *argcp = 1;
290 *argvp = emb_argv;
291 } else {
292 /* Create argc/argv. Do it before we go into the options event loop. */
293 *argcp = PyMac_GetArgv(argvp, PyMac_options.noargs);
294 #ifndef NO_ARGV0_CHDIR
295 if (*argcp >= 1 && (*argvp)[0] && (*argvp)[0][0]) {
296 /* Workaround for MacOS X, which currently (DP4) doesn't set
297 ** the working folder correctly
299 char app_wd[256], *p;
301 strncpy(app_wd, (*argvp)[0], 256);
302 p = strrchr(app_wd, ':');
303 if ( p ) *p = 0;
304 chdir(app_wd);
306 #endif
307 /* Do interactive option setting, if allowed and <option> depressed */
308 PyMac_InteractiveOptions(&PyMac_options, argcp, argvp);
311 /* Copy selected options to where the machine-independent stuff wants it */
312 Py_VerboseFlag = PyMac_options.verbose;
313 /* Py_SuppressPrintingFlag = PyMac_options.suppress_print; */
314 Py_OptimizeFlag = PyMac_options.optimize;
315 Py_DebugFlag = PyMac_options.debugging;
316 Py_NoSiteFlag = PyMac_options.nosite;
317 Py_TabcheckFlag = PyMac_options.tabwarn;
318 if ( PyMac_options.noargs ) {
319 /* don't process events at all without the scripts permission */
320 PyMacSchedParams scp;
322 PyMac_GetSchedParams(&scp);
323 scp.process_events = 0;
324 /* Should we disable command-dot as well? */
325 PyMac_SetSchedParams(&scp);
327 /* XXXX dispatch oldexc and nosite */
329 /* Set buffering */
330 if (PyMac_options.unbuffered) {
331 #ifndef MPW
332 setbuf(stdout, (char *)NULL);
333 setbuf(stderr, (char *)NULL);
334 #else
335 /* On MPW (3.2) unbuffered seems to hang */
336 setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
337 setvbuf(stderr, (char *)NULL, _IOLBF, BUFSIZ);
338 #endif
340 #if __profile__ == 1
341 /* collectSummary or collectDetailed, timebase, #routines, max stack depth */
342 ProfilerInit(collectSummary, bestTimeBase, 8000, 250);
343 #endif
345 /* Tell the rest of python about our argc/argv */
346 orig_argc = *argcp; /* For Py_GetArgcArgv() */
347 orig_argv = *argvp;
348 Py_SetProgramName((*argvp)[0]);
352 ** Inspection mode after script/applet termination
354 static int
355 run_inspect()
357 int sts = 0;
359 if (PyMac_options.inspect && isatty((int)fileno(stdin)))
360 sts = PyRun_AnyFile(stdin, "<stdin>") != 0;
361 return sts;
365 ** Import the macfsn module, which will override the Standard File
366 ** calls in the macfs builtin module by Navigation Services versions,
367 ** if available on this machine.
369 static void
370 PyMac_InstallNavServicesForSF()
372 if ( !PyMac_options.nonavservice ) {
373 PyObject *m = PyImport_ImportModule("macfsn");
375 if ( m == NULL ) {
376 PySys_WriteStderr("'import macfsn' failed; ");
377 if (Py_VerboseFlag) {
378 PySys_WriteStderr("traceback:\n");
379 PyErr_Print();
381 else {
382 PySys_WriteStderr("use -v for traceback\n");
388 #ifdef USE_MAC_APPLET_SUPPORT
389 /* Applet support */
391 /* Run a compiled Python Python script from 'PYC ' resource __main__ */
392 static int
393 run_main_resource()
395 Handle h;
396 long size;
397 PyObject *code;
398 PyObject *result;
400 h = GetNamedResource('PYC ', "\p__main__");
401 if (h == NULL) {
402 Alert(NOPYC_ALERT, NULL);
403 return 1;
405 size = GetResourceSizeOnDisk(h);
406 HLock(h);
407 code = PyMarshal_ReadObjectFromString(*h + 8, (int)(size - 8));
408 HUnlock(h);
409 ReleaseResource(h);
410 if (code == NULL) {
411 PyErr_Print();
412 return 1;
414 result = PyImport_ExecCodeModule("__main__", code);
415 Py_DECREF(code);
416 if (result == NULL) {
417 PyErr_Print();
418 return 1;
420 Py_DECREF(result);
421 return 0;
424 /* Initialization sequence for applets */
425 void
426 PyMac_InitApplet()
428 int argc;
429 char **argv;
430 int err;
432 init_common(&argc, &argv, 0);
434 Py_Initialize();
435 PyMac_InstallNavServicesForSF();
436 PySys_SetArgv(argc, argv);
438 err = run_main_resource();
440 err = (run_inspect() || err);
442 fflush(stderr);
443 fflush(stdout);
444 PyMac_Exit(err);
445 /* XXX Should we bother to Py_Exit(sts)? */
449 ** Hook for embedding python.
451 void
452 PyMac_Initialize()
454 int argc;
455 char **argv;
457 init_common(&argc, &argv, 1);
458 Py_Initialize();
459 PyMac_InstallNavServicesForSF();
460 PySys_SetArgv(argc, argv);
463 #endif /* USE_MAC_APPLET_SUPPORT */
465 /* For normal application */
466 void
467 PyMac_InitApplication()
469 int argc;
470 char **argv;
472 init_common(&argc, &argv, 0);
474 if ( argc > 1 ) {
475 /* We're running a script. Attempt to change current directory */
476 char curwd[256], *endp;
478 strcpy(curwd, argv[1]);
479 endp = strrchr(curwd, ':');
480 if ( endp && endp > curwd ) {
481 *endp = '\0';
483 chdir(curwd);
484 #ifdef USE_GUSI1
485 /* Change MacOS's idea of wd too */
486 PyMac_FixGUSIcd();
487 #endif
490 Py_Main(argc, argv);
493 /* Main program */
495 static void
496 Py_Main(argc, argv)
497 int argc;
498 char **argv;
500 int sts;
501 char *command = NULL;
502 char *filename = NULL;
503 FILE *fp = stdin;
505 filename = argv[1];
507 if (Py_VerboseFlag ||
508 command == NULL && filename == NULL && isatty((int)fileno(fp)))
509 fprintf(stderr, "Python %s on %s\n%s\n",
510 Py_GetVersion(), Py_GetPlatform(), COPYRIGHT);
512 if (filename != NULL) {
513 if ((fp = fopen(filename, "r")) == NULL) {
514 fprintf(stderr, "%s: can't open file '%s'\n",
515 argv[0], filename);
516 PyMac_Exit(2);
520 /* We initialize the menubar here, hoping SIOUX is initialized by now */
521 PyMac_InitMenuBar();
523 Py_Initialize();
525 PyUnicode_SetDefaultEncoding(PyMac_getscript());
527 PyMac_InstallNavServicesForSF();
529 PySys_SetArgv(argc-1, argv+1);
531 if (filename == NULL && isatty((int)fileno(fp))) {
532 FILE *fp = fopen(STARTUP, "r");
533 if (fp != NULL) {
534 (void) PyRun_SimpleFile(fp, STARTUP);
535 PyErr_Clear();
536 fclose(fp);
539 sts = PyRun_AnyFile(
540 fp, filename == NULL ? "<stdin>" : filename) != 0;
541 if (filename != NULL)
542 fclose(fp);
544 if ( filename != NULL || command != NULL )
545 sts = (run_inspect() || sts);
547 Py_Exit(sts);
548 /*NOTREACHED*/
552 ** Reset the "unseen output" flag
554 void
555 PyMac_OutputSeen()
557 if ( console_output_state == STATE_UNKNOWN )
558 PyMac_InitMenuBar();
559 console_output_state = STATE_LASTREAD;
563 ** Set the "unseen output" flag
565 void
566 PyMac_OutputNotSeen()
568 if ( console_output_state == STATE_UNKNOWN )
569 PyMac_InitMenuBar();
570 console_output_state = STATE_LASTWRITE;
574 ** Override abort() - The default one is not what we want.
576 void
577 abort()
579 console_output_state = STATE_LASTWRITE;
580 PyMac_Exit(1);
584 ** Terminate application
586 void
587 PyMac_Exit(status)
588 int status;
590 int keep = 0;
592 #if __profile__ == 1
593 ProfilerDump("\pPython Profiler Results");
594 ProfilerTerm();
595 #endif
597 #ifdef USE_SIOUX
598 switch (PyMac_options.keep_console) {
599 case POPT_KEEPCONSOLE_NEVER:
600 keep = 0;
601 break;
602 case POPT_KEEPCONSOLE_OUTPUT:
603 if (console_output_state == STATE_LASTWRITE ||
604 console_output_state == STATE_UNKNOWN )
605 keep = 1;
606 else
607 keep = 0;
608 break;
609 case POPT_KEEPCONSOLE_ERROR:
610 keep = (status != 0);
611 break;
612 default:
613 keep = 1;
615 if (keep) {
616 SIOUXSettings.standalone = 1;
617 SIOUXSettings.autocloseonquit = 0;
618 SIOUXSetTitle("\p\307terminated\310");
619 PyMac_RaiseConsoleWindow();
620 PyMac_RestoreMenuBar();
621 #ifdef USE_MSL
623 ** Temporary workaround: autocloseonquit clearing does not
624 ** currently work for the MSL/GUSI combo.
626 while(getchar() > 0);
627 #endif
629 else
630 SIOUXSettings.autocloseonquit = 1;
631 #endif /* USE_SIOUX */
633 exit(status);
636 /* Return the program name -- some code out there needs this. */
637 char *
638 Py_GetProgramFullPath()
640 return orig_argv[0];
644 /* Make the *original* argc/argv available to other modules.
645 This is rare, but it is needed by the secureware extension. */
647 void
648 Py_GetArgcArgv(int *argc,char ***argv)
650 *argc = orig_argc;
651 *argv = orig_argv;
654 /* More cruft that shouldn't really be here, used in sysmodule.c */
656 char *
657 Py_GetPrefix()
659 return PyMac_GetPythonDir();
662 char *
663 Py_GetExecPrefix()
665 return PyMac_GetPythonDir();
669 PyMac_GetDelayConsoleFlag()
671 return (int)PyMac_options.delayconsole;