blob: 24667e65d50d6bf3d19551d55e1333a9d374b3ee [file] [log] [blame]
Guido van Rossumb3404661995-01-22 18:36:13 +00001/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
Jack Jansenf93c72a1994-12-14 14:07:50 +000024
25#include "Python.h"
Guido van Rossumbecdbec1995-02-14 01:27:24 +000026
Jack Jansenf93c72a1994-12-14 14:07:50 +000027#include "macglue.h"
Jack Jansen74162f31995-02-15 22:58:33 +000028#include "marshal.h"
29#include "import.h"
Jack Jansenf93c72a1994-12-14 14:07:50 +000030
31#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000032#include <Files.h>
Jack Jansen8cd2b721995-02-13 11:33:28 +000033#include <Aliases.h>
Jack Jansen6cfab231995-02-13 22:46:00 +000034#include <Folders.h>
Jack Jansen8cd2b721995-02-13 11:33:28 +000035#include <StandardFile.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000036#include <Resources.h>
37#include <Memory.h>
38#include <Events.h>
39#include <Windows.h>
40#include <Desk.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000041#include <Traps.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000042#include <Processes.h>
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000043#include <Fonts.h>
44#include <Menus.h>
Jack Jansen08305501995-06-18 20:03:40 +000045#include <TextUtils.h>
Guido van Rossumcc0d8791995-01-30 08:57:13 +000046#ifdef THINK_C
47#include <OSEvents.h> /* For EvQElPtr */
48#endif
Jack Jansen16df2aa1995-02-27 16:17:28 +000049#ifdef __MWERKS__
50#include <SIOUX.h>
51#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000052
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000053#ifndef HAVE_UNIVERSAL_HEADERS
54#define GetResourceSizeOnDisk(x) SizeResource(x)
Guido van Rossum24a45e31995-02-20 23:45:53 +000055typedef DlgHookYDProcPtr DlgHookYDUPP;
56#define NewDlgHookYDProc(userRoutine) ((DlgHookYDUPP) (userRoutine))
57typedef FileFilterYDProcPtr FileFilterYDUPP;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000058#endif
59
Jack Jansenee23d6e1995-01-27 14:43:25 +000060#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000061#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000062
Jack Jansen3ec804a1995-02-20 15:56:10 +000063/* The alert for "No Python directory, where is it?" */
Jack Jansen8cd2b721995-02-13 11:33:28 +000064#define NOPYTHON_ALERT 128
65#define YES_ITEM 1
66#define NO_ITEM 2
67#define CURWD_ITEM 3
68
Jack Jansen3ec804a1995-02-20 15:56:10 +000069/* The alert for "this is an applet template" */
70#define NOPYC_ALERT 129
71
72/* The dialog for our GetDirectory call */
73#define GETDIR_ID 130 /* Resource ID for our "get directory" */
74#define SELECTCUR_ITEM 10 /* "Select current directory" button */
75
Jack Jansen08305501995-06-18 20:03:40 +000076/* The STR# resource for sys.path initialization */
77#define PYTHONPATH_ID 128
78
Jack Jansenee23d6e1995-01-27 14:43:25 +000079/*
Jack Jansen16df2aa1995-02-27 16:17:28 +000080** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +000081** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +000082** handle them). Note that we don't know who has windows open, so
83** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +000084*/
85#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +000086
87#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000088
Guido van Rossumb3404661995-01-22 18:36:13 +000089/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +000090** with the python errors.h. */
91#define fnfErr -43
92
Jack Jansene8e8ae01995-01-26 16:36:45 +000093/* Declared in macfsmodule.c: */
94extern FSSpec *mfs_GetFSSpecFSSpec();
95
Jack Jansenee23d6e1995-01-27 14:43:25 +000096/* Interrupt code variables: */
97static int interrupted; /* Set to true when cmd-. seen */
98static RETSIGTYPE intcatcher Py_PROTO((int));
99
Jack Jansene8e8ae01995-01-26 16:36:45 +0000100/*
101** We attempt to be a good citizen by giving up the CPU periodically.
102** When in the foreground we do this less often and for shorter periods
103** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +0000104** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000105** The counts here are in ticks of 1/60th second.
106** XXXX The initial values here are not based on anything.
107** FG-python gives up the cpu for 1/60th 5 times per second,
108** BG-python for .2 second 10 times per second.
109*/
110static long interval_fg = 12;
111static long interval_bg = 6;
112static long yield_fg = 1;
113static long yield_bg = 12;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000114static long lastyield;
115static int in_foreground;
116
Guido van Rossume7134aa1995-02-26 10:20:53 +0000117/*
118** When > 0, do full scanning for events (program is not event aware)
119** when == 0, only scan for Command-period
120** when < 0, don't do any event scanning
121*/
122int PyMac_DoYieldEnabled = 1;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000123
Jack Jansen5f653091995-01-18 13:53:49 +0000124/* Convert C to Pascal string. Returns pointer to static buffer. */
125unsigned char *
126Pstring(char *str)
127{
128 static Str255 buf;
129 int len;
130
131 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000132 if (len > 255)
133 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000134 buf[0] = (unsigned char)len;
135 strncpy((char *)buf+1, str, len);
136 return buf;
137}
138
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000139/* Like strerror() but for Mac OS error numbers */
140char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000141{
142 static char buf[256];
143 Handle h;
144 char *str;
145
146 h = GetResource('Estr', err);
147 if ( h ) {
148 HLock(h);
149 str = (char *)*h;
150 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000151 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000152 HUnlock(h);
153 ReleaseResource(h);
154 } else {
155 sprintf(buf, "Mac OS error code %d", err);
156 }
157 return buf;
158}
159
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000160/* Exception object shared by all Mac specific modules for Mac OS errors */
161PyObject *PyMac_OSErrException;
162
163/* Initialize and return PyMac_OSErrException */
164PyObject *
165PyMac_GetOSErrException()
166{
167 if (PyMac_OSErrException == NULL)
168 PyMac_OSErrException = PyString_FromString("Mac OS Error");
169 return PyMac_OSErrException;
170}
171
Jack Jansenf93c72a1994-12-14 14:07:50 +0000172/* Set a MAC-specific error from errno, and return NULL; return None if no error */
173PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000174PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000175{
176 char *msg;
177 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000178
Guido van Rossum8f691791995-01-18 23:57:26 +0000179 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000180 Py_INCREF(Py_None);
181 return Py_None;
182 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000183 if (err == -1 && PyErr_Occurred())
184 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000185 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000186 v = Py_BuildValue("(is)", err, msg);
187 PyErr_SetObject(eobj, v);
188 Py_DECREF(v);
189 return NULL;
190}
191
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000192/* Call PyErr_Mac with PyMac_OSErrException */
193PyObject *
194PyMac_Error(OSErr err)
195{
196 return PyErr_Mac(PyMac_GetOSErrException(), err);
197}
198
Jack Jansenee23d6e1995-01-27 14:43:25 +0000199/* The catcher routine (which may not be used for all compilers) */
200static RETSIGTYPE
201intcatcher(sig)
202 int sig;
203{
204 interrupted = 1;
205 signal(SIGINT, intcatcher);
206}
207
208void
209PyOS_InitInterrupts()
210{
211 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
212 signal(SIGINT, intcatcher);
213}
214
215/*
216** This routine scans the event queue looking for cmd-.
217** This is the only way to get an interrupt under THINK (since it
218** doesn't do SIGINT handling), but is also used under MW, when
219** the full-fledged event loop is disabled. This way, we can at least
220** interrupt a runaway python program.
221*/
222static void
223scan_event_queue(flush)
224 int flush;
225{
Jack Jansenf74f63a1995-06-27 13:18:14 +0000226#if defined(__MWERKS__) && defined(__CFM68K__)
227 return; /* No GetEvQHdr yet */
228#else
Jack Jansenee23d6e1995-01-27 14:43:25 +0000229 register EvQElPtr q;
230
231 q = (EvQElPtr) GetEvQHdr()->qHead;
232
233 for (; q; q = (EvQElPtr)q->qLink) {
234 if (q->evtQWhat == keyDown &&
235 (char)q->evtQMessage == '.' &&
236 (q->evtQModifiers & cmdKey) != 0) {
237 if ( flush )
238 FlushEvents(keyDownMask, 0);
239 interrupted = 1;
240 break;
241 }
242 }
Jack Jansenf74f63a1995-06-27 13:18:14 +0000243#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000244}
245
246int
247PyOS_InterruptOccurred()
248{
Guido van Rossume7134aa1995-02-26 10:20:53 +0000249 if (PyMac_DoYieldEnabled < 0)
250 return 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000251#ifdef THINK_C
252 scan_event_queue(1);
253#endif
254 PyMac_Yield();
255 if (interrupted) {
256 interrupted = 0;
257 return 1;
258 }
259 return 0;
260}
261
262/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
263** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
264** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
265** thereafter.
266*/
267static int
268intrpeek()
269{
270#ifdef THINK_C
271 scan_event_queue(0);
272#endif
273 return interrupted;
274}
275
276/* Check whether we are in the foreground */
277int
278PyMac_InForeground()
279{
280 static ProcessSerialNumber ours;
281 static inited;
282 ProcessSerialNumber curfg;
283 Boolean eq;
284
285 if ( inited == 0 )
286 (void)GetCurrentProcess(&ours);
287 inited = 1;
288 if ( GetFrontProcess(&curfg) < 0 )
289 eq = 1;
290 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
291 eq = 1;
292 return (int)eq;
293
294}
295
Jack Jansenf93c72a1994-12-14 14:07:50 +0000296/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000297** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000298*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000299void
300PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
301{
302 interval_fg = fgi;
303 yield_fg = fgy;
304 interval_bg = bgi;
305 yield_bg = bgy;
306}
307
308/*
Jack Jansena76382a1995-02-02 14:25:56 +0000309** Handle an event, either one found in the mainloop eventhandler or
310** one passed back from the python program.
311*/
312void
313PyMac_HandleEvent(evp)
314 EventRecord *evp;
315{
316 WindowPtr wp;
317
318#ifdef __MWERKS__
319 /* If SIOUX wants it we're done */
320 (void)SIOUXHandleOneEvent(evp);
321#else
322 /* Other compilers are just unlucky: we only weed out clicks in other applications */
323 if ( evp->what == mouseDown ) {
324 if ( FindWindow(evp->where, &wp) == inSysWindow )
325 SystemClick(evp, wp);
326 }
327#endif /* !__MWERKS__ */
328}
329
330/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000331** Yield the CPU to other tasks.
332*/
333static
334PyMac_DoYield()
Jack Jansenf93c72a1994-12-14 14:07:50 +0000335{
336 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000337 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000338 static int no_waitnextevent = -1;
339 int gotone;
340
341 if ( no_waitnextevent < 0 ) {
342 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
343 NGetTrapAddress(_Unimplemented, ToolTrap));
344 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000345
Jack Jansenee23d6e1995-01-27 14:43:25 +0000346 if ( !PyMac_DoYieldEnabled ) {
347#ifndef THINK_C
348 /* Under think this has been done before in intrcheck() or intrpeek() */
349 scan_event_queue(0);
350#endif
Jack Jansene8e8ae01995-01-26 16:36:45 +0000351 return;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000352 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000353
Jack Jansenee23d6e1995-01-27 14:43:25 +0000354 in_foreground = PyMac_InForeground();
355 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000356 yield = yield_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000357 else
358 yield = yield_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000359 while ( 1 ) {
360 if ( no_waitnextevent ) {
361 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000362 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000363 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000364 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000365 }
366 /* Get out quickly if nothing interesting is happening */
367 if ( !gotone || ev.what == nullEvent )
368 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000369 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000370 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000371 lastyield = TickCount();
372}
373
374/*
375** Yield the CPU to other tasks if opportune
376*/
377void
378PyMac_Yield() {
379 long iv;
380
Jack Jansenee23d6e1995-01-27 14:43:25 +0000381 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000382 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000383 else
384 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000385 if ( TickCount() > lastyield + iv )
386 PyMac_DoYield();
387}
388
389/*
390** Idle routine for busy-wait loops.
391** Gives up CPU, handles events and returns true if an interrupt is pending
392** (but not actually handled yet).
393*/
394int
395PyMac_Idle()
396{
397 PyMac_DoYield();
398 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000399}
400
Jack Jansen8cd2b721995-02-13 11:33:28 +0000401/*
402** Return the name of the Python directory
403*/
404char *
405PyMac_GetPythonDir()
406{
407 int item;
408 static char name[256];
409 AliasHandle handle;
410 FSSpec dirspec;
Jack Jansen45ff77f1995-04-24 12:41:41 +0000411 int ok = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000412 Boolean modified = 0, cannotmodify = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000413 short oldrh, prefrh;
414 short prefdirRefNum;
415 long prefdirDirID;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000416
Jack Jansen6cfab231995-02-13 22:46:00 +0000417 /*
418 ** Remember old resource file and try to open preferences file
419 ** in the preferences folder. If it doesn't exist we try to create
420 ** it. If anything fails here we limp on, but set cannotmodify so
421 ** we don't try to store things later on.
422 */
423 oldrh = CurResFile();
424 if ( FindFolder(kOnSystemDisk, 'pref', kDontCreateFolder, &prefdirRefNum,
425 &prefdirDirID) != noErr ) {
426 /* Something wrong with preferences folder */
427 cannotmodify = 1;
428 } else {
429 (void)FSMakeFSSpec(prefdirRefNum, prefdirDirID, "\pPython Preferences", &dirspec);
430 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
431 if ( prefrh == -1 ) {
Jack Jansen08305501995-06-18 20:03:40 +0000432#ifdef USE_MAC_MODPREFS
Jack Jansen6cfab231995-02-13 22:46:00 +0000433 /* It doesn't exist. Try to create it */
Guido van Rossumbecdbec1995-02-14 01:27:24 +0000434 FSpCreateResFile(&dirspec, 'PYTH', 'pref', 0);
Jack Jansen6cfab231995-02-13 22:46:00 +0000435 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
436 if ( prefrh == -1 ) {
Jack Jansen45ff77f1995-04-24 12:41:41 +0000437 /* This is strange, what should we do now? */
Jack Jansen6cfab231995-02-13 22:46:00 +0000438 cannotmodify = 1;
439 } else {
440 UseResFile(prefrh);
441 }
Jack Jansen08305501995-06-18 20:03:40 +0000442#else
443 printf("Error: no Preferences file. Attempting to limp on...\n");
444 name[0] = 0;
445 getwd(name);
446 return name;
447#endif
Jack Jansen6cfab231995-02-13 22:46:00 +0000448 }
449 }
450 /* So, we've opened our preferences file, we hope. Look for the alias */
451 handle = (AliasHandle)Get1Resource('alis', 128);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000452 if ( handle ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000453 /* It exists. Resolve it (possibly updating it) */
Jack Jansen45ff77f1995-04-24 12:41:41 +0000454 if ( ResolveAlias(NULL, handle, &dirspec, &modified) == noErr ) {
Jack Jansen8cd2b721995-02-13 11:33:28 +0000455 ok = 1;
Jack Jansen45ff77f1995-04-24 12:41:41 +0000456 }
Jack Jansen8cd2b721995-02-13 11:33:28 +0000457 }
458 if ( !ok ) {
Jack Jansen08305501995-06-18 20:03:40 +0000459#ifdef USE_MAC_MODPREFS
Jack Jansen6cfab231995-02-13 22:46:00 +0000460 /* No luck, so far. ask the user for help */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000461 item = Alert(NOPYTHON_ALERT, NULL);
462 if ( item == YES_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000463 /* The user wants to point us to a directory. Let her do so */
Jack Jansen3ec804a1995-02-20 15:56:10 +0000464 ok = PyMac_GetDirectory(&dirspec);
465 if ( ok )
466 modified = 1;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000467 } else if ( item == CURWD_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000468 /* The user told us the current directory is fine. Build an FSSpec for it */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000469 if ( getwd(name) ) {
470 if ( FSMakeFSSpec(0, 0, Pstring(name), &dirspec) == 0 ) {
471 ok = 1;
472 modified = 1;
473 }
474 }
475 }
Jack Jansen45ff77f1995-04-24 12:41:41 +0000476 if ( handle ) {
477 /* Set the (old, invalid) alias record to the new data */
478 UpdateAlias(NULL, &dirspec, handle, &modified);
479 }
Jack Jansen08305501995-06-18 20:03:40 +0000480#else
481 printf("Error: no Preferences file. Attempting to limp on...\n");
482 name[0] = 0;
483 getwd(name);
484 return name;
485#endif
Jack Jansen8cd2b721995-02-13 11:33:28 +0000486 }
Jack Jansen08305501995-06-18 20:03:40 +0000487#ifdef USE_MAC_MODPREFS
Jack Jansen6cfab231995-02-13 22:46:00 +0000488 if ( ok && modified && !cannotmodify) {
489 /* We have a new, valid fsspec and we can update the preferences file. Do so. */
Jack Jansen45ff77f1995-04-24 12:41:41 +0000490 if ( !handle ) {
Jack Jansen8cd2b721995-02-13 11:33:28 +0000491 if (NewAlias(NULL, &dirspec, &handle) == 0 )
492 AddResource((Handle)handle, 'alis', 128, "\p");
493 } else {
494 ChangedResource((Handle)handle);
495 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000496 UpdateResFile(prefrh);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000497 }
Jack Jansen08305501995-06-18 20:03:40 +0000498#endif
Jack Jansen6cfab231995-02-13 22:46:00 +0000499 if ( !cannotmodify ) {
500 /* This means we have the resfile open. Close it. */
501 CloseResFile(prefrh);
502 }
503 /* Back to the old resource file */
504 UseResFile(oldrh);
505 /* Now turn the fsspec into a path to give back to our caller */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000506 if ( ok ) {
507 ok = (nfullpath(&dirspec, name) == 0);
508 if ( ok ) strcat(name, ":");
509 }
510 if ( !ok ) {
511 /* If all fails, we return the current directory */
512 name[0] = 0;
513 (void)getwd(name);
514 }
515 return name;
516}
517
Jack Jansen08305501995-06-18 20:03:40 +0000518#ifndef USE_BUILTIN_PATH
519char *
520PyMac_GetPythonPath(dir)
521char *dir;
522{
523 FSSpec dirspec;
524 short oldrh, prefrh = -1;
525 short prefdirRefNum;
526 long prefdirDirID;
527 char *rv;
528 int i, newlen;
529 Str255 pathitem;
530
531 /*
532 ** Remember old resource file and try to open preferences file
533 ** in the preferences folder.
534 */
535 oldrh = CurResFile();
536 if ( FindFolder(kOnSystemDisk, 'pref', kDontCreateFolder, &prefdirRefNum,
537 &prefdirDirID) == noErr ) {
538 (void)FSMakeFSSpec(prefdirRefNum, prefdirDirID, "\pPython Preferences", &dirspec);
539 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
540 }
541 /* At this point, we may or may not have the preferences file open, and it
542 ** may or may not contain a sys.path STR# resource. We don't care, if it doesn't
543 ** exist we use the one from the application (the default).
544 ** We put an initial '\n' in front of the path that we don't return to the caller
545 */
546 if( (rv = malloc(2)) == NULL )
547 goto out;
548 strcpy(rv, "\n");
549 for(i=1; ; i++) {
550 GetIndString(pathitem, PYTHONPATH_ID, i);
551 if( pathitem[0] == 0 )
552 break;
553 if ( pathitem[0] >= 9 && strncmp((char *)pathitem+1, "$(PYTHON)", 9) == 0 ) {
554 /* We have to put the directory in place */
555 newlen = strlen(rv) + strlen(dir) + (pathitem[0]-9) + 2;
556 if( (rv=realloc(rv, newlen)) == NULL)
557 goto out;
558 strcat(rv, dir);
559 /* Skip a colon at the beginning of the item */
560 if ( pathitem[0] > 9 && pathitem[1+9] == ':' ) {
561 memcpy(rv+strlen(rv), pathitem+1+10, pathitem[0]-10);
562 newlen--;
563 } else {
564 memcpy(rv+strlen(rv), pathitem+1+9, pathitem[0]-9);
565 }
566 rv[newlen-2] = '\n';
567 rv[newlen-1] = 0;
568 } else {
569 /* Use as-is */
570 newlen = strlen(rv) + (pathitem[0]) + 2;
571 if( (rv=realloc(rv, newlen)) == NULL)
572 goto out;
573 memcpy(rv+strlen(rv), pathitem+1, pathitem[0]);
574 rv[newlen-2] = '\n';
575 rv[newlen-1] = 0;
576 }
577 }
578 if( strlen(rv) == 1) {
579 free(rv);
580 rv = NULL;
581 }
582 if ( rv ) {
583 rv[strlen(rv)-1] = 0;
584 rv++;
585 }
586out:
587 if ( prefrh ) {
588 CloseResFile(prefrh);
589 UseResFile(oldrh);
590 }
591 return rv;
592}
593#endif /* !USE_BUILTIN_PATH */
594
Jack Jansen74162f31995-02-15 22:58:33 +0000595/*
596** Returns true if the argument has a resource fork, and it contains
597** a 'PYC ' resource of the correct name
598*/
599int
600PyMac_FindResourceModule(module, filename)
601char *module;
602char *filename;
603{
604 FSSpec fss;
605 FInfo finfo;
606 short oldrh, filerh;
607 int ok;
608 Handle h;
609
610 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
611 return 0; /* It doesn't exist */
612 if ( FSpGetFInfo(&fss, &finfo) != noErr )
613 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000614 oldrh = CurResFile();
615 filerh = FSpOpenResFile(&fss, fsRdPerm);
616 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000617 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000618 UseResFile(filerh);
619 SetResLoad(0);
620 h = Get1NamedResource('PYC ', Pstring(module));
621 SetResLoad(1);
622 ok = (h != NULL);
623 CloseResFile(filerh);
624 UseResFile(oldrh);
625 return ok;
626}
627
628/*
629** Load the specified module from a resource
630*/
631PyObject *
632PyMac_LoadResourceModule(module, filename)
633char *module;
634char *filename;
635{
636 FSSpec fss;
637 FInfo finfo;
638 short oldrh, filerh;
639 int ok;
640 Handle h;
641 OSErr err;
642 PyObject *m, *co;
643 long num, size;
644
645 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
646 goto error;
647 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
648 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000649 oldrh = CurResFile();
650 filerh = FSpOpenResFile(&fss, fsRdPerm);
651 if ( filerh == -1 ) {
652 err = ResError();
653 goto error;
654 }
655 UseResFile(filerh);
656 h = Get1NamedResource('PYC ', Pstring(module));
657 if ( h == NULL ) {
658 err = ResError();
659 goto error;
660 }
661 HLock(h);
662 /*
663 ** XXXX The next few lines are intimately tied to the format of pyc
664 ** files. I'm not sure whether this code should be here or in import.c -- Jack
665 */
666 size = GetHandleSize(h);
667 if ( size < 8 ) {
668 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000669 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000670 } else {
671 num = (*h)[0] & 0xff;
672 num = num | (((*h)[1] & 0xff) << 8);
673 num = num | (((*h)[2] & 0xff) << 16);
674 num = num | (((*h)[3] & 0xff) << 24);
675 if ( num != PyImport_GetMagicNumber() ) {
676 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
677 co = NULL;
678 } else {
679 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
680 }
681 }
682 HUnlock(h);
683 CloseResFile(filerh);
684 UseResFile(oldrh);
685 if ( co ) {
686 m = PyImport_ExecCodeModule(module, co);
687 Py_DECREF(co);
688 } else {
689 m = NULL;
690 }
691 return m;
692error:
693 {
694 char buf[512];
695
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000696 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000697 PyErr_SetString(PyExc_ImportError, buf);
698 return NULL;
699 }
700}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000701
Jack Jansen3ec804a1995-02-20 15:56:10 +0000702/*
703** Helper routine for GetDirectory
704*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000705static pascal short
706myhook_proc(short item, DialogPtr theDialog, void *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000707{
708 if ( item == SELECTCUR_ITEM ) {
709 item = sfItemCancelButton;
710 * (int *)dataptr = 1;
711 }
712 return item;
713}
714
715/*
716** Ask the user for a directory. I still can't understand
717** why Apple doesn't provide a standard solution for this...
718*/
719int
720PyMac_GetDirectory(dirfss)
721 FSSpec *dirfss;
722{
723 static SFTypeList list = {'fldr', 0, 0, 0};
724 static Point where = {-1, -1};
725 static DlgHookYDUPP myhook_upp;
726 static int upp_inited = 0;
727 StandardFileReply reply;
728 int select_clicked = 0;
729
730 if ( !upp_inited ) {
731 myhook_upp = NewDlgHookYDProc(myhook_proc);
732 upp_inited = 1;
733 }
Guido van Rossum24a45e31995-02-20 23:45:53 +0000734 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen3ec804a1995-02-20 15:56:10 +0000735 NULL, NULL, NULL, (void *)&select_clicked);
736
737 reply.sfFile.name[0] = 0;
738 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
739 return 0;
740 return select_clicked;
741}
Jack Jansen5f653091995-01-18 13:53:49 +0000742
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000743/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000744int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000745PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000746{
747 if (!PyString_Check(v) || PyString_Size(v) != 4) {
748 PyErr_SetString(PyExc_TypeError,
749 "OSType arg must be string of 4 chars");
750 return 0;
751 }
752 memcpy((char *)pr, PyString_AsString(v), 4);
753 return 1;
754}
755
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000756/* Convert an OSType value to a 4-char string object */
757PyObject *
758PyMac_BuildOSType(OSType t)
759{
760 return PyString_FromStringAndSize((char *)&t, 4);
761}
762
763
764/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000765int
Guido van Rossum8f691791995-01-18 23:57:26 +0000766PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000767{
768 int len;
769 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
770 PyErr_SetString(PyExc_TypeError,
771 "Str255 arg must be string of at most 255 chars");
772 return 0;
773 }
774 pbuf[0] = len;
775 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
776 return 1;
777}
778
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000779/* Convert a Str255 to a Python string object */
780PyObject *
781PyMac_BuildStr255(Str255 s)
782{
783 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
784}
785
786
Jack Jansen5f653091995-01-18 13:53:49 +0000787/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000788** Convert a Python object to an FSSpec.
789** The object may either be a full pathname or a triple
790** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000791** NOTE: This routine will fail on pre-sys7 machines.
792** The caller is responsible for not calling this routine
793** in those cases (which is fine, since everyone calling
794** this is probably sys7 dependent anyway).
795*/
796int
Guido van Rossum8f691791995-01-18 23:57:26 +0000797PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000798{
799 Str255 path;
800 short refnum;
801 long parid;
802 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000803 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000804
Jack Jansene8e8ae01995-01-26 16:36:45 +0000805 /* first check whether it already is an FSSpec */
806 fs2 = mfs_GetFSSpecFSSpec(v);
807 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000808 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000809 return 1;
810 }
Jack Jansen5f653091995-01-18 13:53:49 +0000811 if ( PyString_Check(v) ) {
812 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000813 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000814 return 0;
815 refnum = 0; /* XXXX Should get CurWD here... */
816 parid = 0;
817 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000818 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
819 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000820 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000821 }
Jack Jansen5f653091995-01-18 13:53:49 +0000822 }
823 err = FSMakeFSSpec(refnum, parid, path, fs);
824 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000825 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000826 return 0;
827 }
828 return 1;
829}
830
Guido van Rossum8f691791995-01-18 23:57:26 +0000831
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000832
833/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000834 The object must be a (left, top, right, bottom) tuple.
835 (This differs from the order in the struct but is consistent with
836 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000837int
838PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000839{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000840 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000841}
Guido van Rossumb3404661995-01-22 18:36:13 +0000842
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000843/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000844PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000845PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000846{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000847 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000848}
849
850
851/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000852 The object must be a (h, v) tuple.
853 (This differs from the order in the struct but is consistent with
854 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000855int
856PyMac_GetPoint(PyObject *v, Point *p)
857{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000858 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000859}
860
861/* Convert a Point to a Python object */
862PyObject *
863PyMac_BuildPoint(Point p)
864{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000865 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000866}
867
868
869/* Convert a Python object to an EventRecord.
870 The object must be a (what, message, when, (v, h), modifiers) tuple. */
871int
872PyMac_GetEventRecord(PyObject *v, EventRecord *e)
873{
874 return PyArg_Parse(v, "(hll(hh)h)",
875 &e->what,
876 &e->message,
877 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000878 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000879 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000880 &e->modifiers);
881}
882
883/* Convert a Rect to an EventRecord object */
884PyObject *
885PyMac_BuildEventRecord(EventRecord *e)
886{
887 return Py_BuildValue("(hll(hh)h)",
888 e->what,
889 e->message,
890 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000891 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000892 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000893 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000894}
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000895
896
Jack Jansen76efd8e1995-02-24 22:53:16 +0000897#ifdef USE_MAC_APPLET_SUPPORT
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000898/* Applet support */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000899
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000900/* Run a compiled Python Python script from 'PYC ' resource __main__ */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000901static int
902run_main_resource()
903{
904 Handle h;
905 long size;
906 PyObject *code;
907 PyObject *result;
908
909 h = GetNamedResource('PYC ', "\p__main__");
910 if (h == NULL) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000911 Alert(NOPYC_ALERT, NULL);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000912 return 1;
913 }
914 size = GetResourceSizeOnDisk(h);
915 HLock(h);
916 code = PyMarshal_ReadObjectFromString(*h + 8, (int)(size - 8));
917 HUnlock(h);
918 ReleaseResource(h);
919 if (code == NULL) {
920 PyErr_Print();
921 return 1;
922 }
923 result = PyImport_ExecCodeModule("__main__", code);
924 Py_DECREF(code);
925 if (result == NULL) {
926 PyErr_Print();
927 return 1;
928 }
929 Py_DECREF(result);
930 return 0;
931}
932
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000933/* Initialization sequence for applets */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000934void
935PyMac_InitApplet()
936{
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000937 int argc;
938 char **argv;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000939 int err;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000940
Jack Jansen3ec804a1995-02-20 15:56:10 +0000941 PyMac_AddLibResources();
Jack Jansen3ec804a1995-02-20 15:56:10 +0000942#ifdef __MWERKS__
943 SIOUXSettings.asktosaveonclose = 0;
944 SIOUXSettings.showstatusline = 0;
945 SIOUXSettings.tabspaces = 4;
946#endif
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000947 argc = PyMac_GetArgv(&argv);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000948 Py_Initialize();
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000949 PySys_SetArgv(argc, argv);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000950 err = run_main_resource();
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000951 fflush(stderr);
952 fflush(stdout);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000953#ifdef __MWERKS__
954 if (!err)
955 SIOUXSettings.autocloseonquit = 1;
956 else
957 SIOUXSettings.showstatusline = 1;
958#endif
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000959 /* XXX Should we bother to Py_Exit(sts)? */
960}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000961
Jack Jansen76efd8e1995-02-24 22:53:16 +0000962#endif /* USE_MAC_APPLET_SUPPORT */
963
964/* For normal application */
965void
966PyMac_InitApplication()
967{
968 int argc;
969 char **argv;
970
971#ifdef USE_MAC_SHARED_LIBRARY
972 PyMac_AddLibResources();
973#endif
974#ifdef __MWERKS__
975 SIOUXSettings.asktosaveonclose = 0;
976 SIOUXSettings.showstatusline = 0;
977 SIOUXSettings.tabspaces = 4;
978#endif
979 argc = PyMac_GetArgv(&argv);
980 if ( argc > 1 ) {
981 /* We're running a script. Attempt to change current directory */
982 char curwd[256], *endp;
983
984 strcpy(curwd, argv[1]);
985 endp = strrchr(curwd, ':');
986 if ( endp && endp > curwd ) {
987 *endp = '\0';
Jack Jansen45ff77f1995-04-24 12:41:41 +0000988
Jack Jansen76efd8e1995-02-24 22:53:16 +0000989 chdir(curwd);
990 }
991 }
992 Py_Main(argc, argv);
993}