blob: 38f654fb80956c3760855b6822ed52a6ed5dc40b [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{
226 register EvQElPtr q;
227
228 q = (EvQElPtr) GetEvQHdr()->qHead;
229
230 for (; q; q = (EvQElPtr)q->qLink) {
231 if (q->evtQWhat == keyDown &&
232 (char)q->evtQMessage == '.' &&
233 (q->evtQModifiers & cmdKey) != 0) {
234 if ( flush )
235 FlushEvents(keyDownMask, 0);
236 interrupted = 1;
237 break;
238 }
239 }
240}
241
242int
243PyOS_InterruptOccurred()
244{
Guido van Rossume7134aa1995-02-26 10:20:53 +0000245 if (PyMac_DoYieldEnabled < 0)
246 return 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000247#ifdef THINK_C
248 scan_event_queue(1);
249#endif
250 PyMac_Yield();
251 if (interrupted) {
252 interrupted = 0;
253 return 1;
254 }
255 return 0;
256}
257
258/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
259** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
260** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
261** thereafter.
262*/
263static int
264intrpeek()
265{
266#ifdef THINK_C
267 scan_event_queue(0);
268#endif
269 return interrupted;
270}
271
272/* Check whether we are in the foreground */
273int
274PyMac_InForeground()
275{
276 static ProcessSerialNumber ours;
277 static inited;
278 ProcessSerialNumber curfg;
279 Boolean eq;
280
281 if ( inited == 0 )
282 (void)GetCurrentProcess(&ours);
283 inited = 1;
284 if ( GetFrontProcess(&curfg) < 0 )
285 eq = 1;
286 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
287 eq = 1;
288 return (int)eq;
289
290}
291
Jack Jansenf93c72a1994-12-14 14:07:50 +0000292/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000293** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000294*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000295void
296PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
297{
298 interval_fg = fgi;
299 yield_fg = fgy;
300 interval_bg = bgi;
301 yield_bg = bgy;
302}
303
304/*
Jack Jansena76382a1995-02-02 14:25:56 +0000305** Handle an event, either one found in the mainloop eventhandler or
306** one passed back from the python program.
307*/
308void
309PyMac_HandleEvent(evp)
310 EventRecord *evp;
311{
312 WindowPtr wp;
313
314#ifdef __MWERKS__
315 /* If SIOUX wants it we're done */
316 (void)SIOUXHandleOneEvent(evp);
317#else
318 /* Other compilers are just unlucky: we only weed out clicks in other applications */
319 if ( evp->what == mouseDown ) {
320 if ( FindWindow(evp->where, &wp) == inSysWindow )
321 SystemClick(evp, wp);
322 }
323#endif /* !__MWERKS__ */
324}
325
326/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000327** Yield the CPU to other tasks.
328*/
329static
330PyMac_DoYield()
Jack Jansenf93c72a1994-12-14 14:07:50 +0000331{
332 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000333 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000334 static int no_waitnextevent = -1;
335 int gotone;
336
337 if ( no_waitnextevent < 0 ) {
338 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
339 NGetTrapAddress(_Unimplemented, ToolTrap));
340 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000341
Jack Jansenee23d6e1995-01-27 14:43:25 +0000342 if ( !PyMac_DoYieldEnabled ) {
343#ifndef THINK_C
344 /* Under think this has been done before in intrcheck() or intrpeek() */
345 scan_event_queue(0);
346#endif
Jack Jansene8e8ae01995-01-26 16:36:45 +0000347 return;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000348 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000349
Jack Jansenee23d6e1995-01-27 14:43:25 +0000350 in_foreground = PyMac_InForeground();
351 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000352 yield = yield_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000353 else
354 yield = yield_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000355 while ( 1 ) {
356 if ( no_waitnextevent ) {
357 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000358 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000359 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000360 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000361 }
362 /* Get out quickly if nothing interesting is happening */
363 if ( !gotone || ev.what == nullEvent )
364 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000365 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000366 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000367 lastyield = TickCount();
368}
369
370/*
371** Yield the CPU to other tasks if opportune
372*/
373void
374PyMac_Yield() {
375 long iv;
376
Jack Jansenee23d6e1995-01-27 14:43:25 +0000377 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000378 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000379 else
380 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000381 if ( TickCount() > lastyield + iv )
382 PyMac_DoYield();
383}
384
385/*
386** Idle routine for busy-wait loops.
387** Gives up CPU, handles events and returns true if an interrupt is pending
388** (but not actually handled yet).
389*/
390int
391PyMac_Idle()
392{
393 PyMac_DoYield();
394 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000395}
396
Jack Jansen8cd2b721995-02-13 11:33:28 +0000397/*
398** Return the name of the Python directory
399*/
400char *
401PyMac_GetPythonDir()
402{
403 int item;
404 static char name[256];
405 AliasHandle handle;
406 FSSpec dirspec;
Jack Jansen45ff77f1995-04-24 12:41:41 +0000407 int ok = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000408 Boolean modified = 0, cannotmodify = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000409 short oldrh, prefrh;
410 short prefdirRefNum;
411 long prefdirDirID;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000412
Jack Jansen6cfab231995-02-13 22:46:00 +0000413 /*
414 ** Remember old resource file and try to open preferences file
415 ** in the preferences folder. If it doesn't exist we try to create
416 ** it. If anything fails here we limp on, but set cannotmodify so
417 ** we don't try to store things later on.
418 */
419 oldrh = CurResFile();
420 if ( FindFolder(kOnSystemDisk, 'pref', kDontCreateFolder, &prefdirRefNum,
421 &prefdirDirID) != noErr ) {
422 /* Something wrong with preferences folder */
423 cannotmodify = 1;
424 } else {
425 (void)FSMakeFSSpec(prefdirRefNum, prefdirDirID, "\pPython Preferences", &dirspec);
426 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
427 if ( prefrh == -1 ) {
Jack Jansen08305501995-06-18 20:03:40 +0000428#ifdef USE_MAC_MODPREFS
Jack Jansen6cfab231995-02-13 22:46:00 +0000429 /* It doesn't exist. Try to create it */
Guido van Rossumbecdbec1995-02-14 01:27:24 +0000430 FSpCreateResFile(&dirspec, 'PYTH', 'pref', 0);
Jack Jansen6cfab231995-02-13 22:46:00 +0000431 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
432 if ( prefrh == -1 ) {
Jack Jansen45ff77f1995-04-24 12:41:41 +0000433 /* This is strange, what should we do now? */
Jack Jansen6cfab231995-02-13 22:46:00 +0000434 cannotmodify = 1;
435 } else {
436 UseResFile(prefrh);
437 }
Jack Jansen08305501995-06-18 20:03:40 +0000438#else
439 printf("Error: no Preferences file. Attempting to limp on...\n");
440 name[0] = 0;
441 getwd(name);
442 return name;
443#endif
Jack Jansen6cfab231995-02-13 22:46:00 +0000444 }
445 }
446 /* So, we've opened our preferences file, we hope. Look for the alias */
447 handle = (AliasHandle)Get1Resource('alis', 128);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000448 if ( handle ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000449 /* It exists. Resolve it (possibly updating it) */
Jack Jansen45ff77f1995-04-24 12:41:41 +0000450 if ( ResolveAlias(NULL, handle, &dirspec, &modified) == noErr ) {
Jack Jansen8cd2b721995-02-13 11:33:28 +0000451 ok = 1;
Jack Jansen45ff77f1995-04-24 12:41:41 +0000452 }
Jack Jansen8cd2b721995-02-13 11:33:28 +0000453 }
454 if ( !ok ) {
Jack Jansen08305501995-06-18 20:03:40 +0000455#ifdef USE_MAC_MODPREFS
Jack Jansen6cfab231995-02-13 22:46:00 +0000456 /* No luck, so far. ask the user for help */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000457 item = Alert(NOPYTHON_ALERT, NULL);
458 if ( item == YES_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000459 /* The user wants to point us to a directory. Let her do so */
Jack Jansen3ec804a1995-02-20 15:56:10 +0000460 ok = PyMac_GetDirectory(&dirspec);
461 if ( ok )
462 modified = 1;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000463 } else if ( item == CURWD_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000464 /* The user told us the current directory is fine. Build an FSSpec for it */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000465 if ( getwd(name) ) {
466 if ( FSMakeFSSpec(0, 0, Pstring(name), &dirspec) == 0 ) {
467 ok = 1;
468 modified = 1;
469 }
470 }
471 }
Jack Jansen45ff77f1995-04-24 12:41:41 +0000472 if ( handle ) {
473 /* Set the (old, invalid) alias record to the new data */
474 UpdateAlias(NULL, &dirspec, handle, &modified);
475 }
Jack Jansen08305501995-06-18 20:03:40 +0000476#else
477 printf("Error: no Preferences file. Attempting to limp on...\n");
478 name[0] = 0;
479 getwd(name);
480 return name;
481#endif
Jack Jansen8cd2b721995-02-13 11:33:28 +0000482 }
Jack Jansen08305501995-06-18 20:03:40 +0000483#ifdef USE_MAC_MODPREFS
Jack Jansen6cfab231995-02-13 22:46:00 +0000484 if ( ok && modified && !cannotmodify) {
485 /* We have a new, valid fsspec and we can update the preferences file. Do so. */
Jack Jansen45ff77f1995-04-24 12:41:41 +0000486 if ( !handle ) {
Jack Jansen8cd2b721995-02-13 11:33:28 +0000487 if (NewAlias(NULL, &dirspec, &handle) == 0 )
488 AddResource((Handle)handle, 'alis', 128, "\p");
489 } else {
490 ChangedResource((Handle)handle);
491 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000492 UpdateResFile(prefrh);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000493 }
Jack Jansen08305501995-06-18 20:03:40 +0000494#endif
Jack Jansen6cfab231995-02-13 22:46:00 +0000495 if ( !cannotmodify ) {
496 /* This means we have the resfile open. Close it. */
497 CloseResFile(prefrh);
498 }
499 /* Back to the old resource file */
500 UseResFile(oldrh);
501 /* Now turn the fsspec into a path to give back to our caller */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000502 if ( ok ) {
503 ok = (nfullpath(&dirspec, name) == 0);
504 if ( ok ) strcat(name, ":");
505 }
506 if ( !ok ) {
507 /* If all fails, we return the current directory */
508 name[0] = 0;
509 (void)getwd(name);
510 }
511 return name;
512}
513
Jack Jansen08305501995-06-18 20:03:40 +0000514#ifndef USE_BUILTIN_PATH
515char *
516PyMac_GetPythonPath(dir)
517char *dir;
518{
519 FSSpec dirspec;
520 short oldrh, prefrh = -1;
521 short prefdirRefNum;
522 long prefdirDirID;
523 char *rv;
524 int i, newlen;
525 Str255 pathitem;
526
527 /*
528 ** Remember old resource file and try to open preferences file
529 ** in the preferences folder.
530 */
531 oldrh = CurResFile();
532 if ( FindFolder(kOnSystemDisk, 'pref', kDontCreateFolder, &prefdirRefNum,
533 &prefdirDirID) == noErr ) {
534 (void)FSMakeFSSpec(prefdirRefNum, prefdirDirID, "\pPython Preferences", &dirspec);
535 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
536 }
537 /* At this point, we may or may not have the preferences file open, and it
538 ** may or may not contain a sys.path STR# resource. We don't care, if it doesn't
539 ** exist we use the one from the application (the default).
540 ** We put an initial '\n' in front of the path that we don't return to the caller
541 */
542 if( (rv = malloc(2)) == NULL )
543 goto out;
544 strcpy(rv, "\n");
545 for(i=1; ; i++) {
546 GetIndString(pathitem, PYTHONPATH_ID, i);
547 if( pathitem[0] == 0 )
548 break;
549 if ( pathitem[0] >= 9 && strncmp((char *)pathitem+1, "$(PYTHON)", 9) == 0 ) {
550 /* We have to put the directory in place */
551 newlen = strlen(rv) + strlen(dir) + (pathitem[0]-9) + 2;
552 if( (rv=realloc(rv, newlen)) == NULL)
553 goto out;
554 strcat(rv, dir);
555 /* Skip a colon at the beginning of the item */
556 if ( pathitem[0] > 9 && pathitem[1+9] == ':' ) {
557 memcpy(rv+strlen(rv), pathitem+1+10, pathitem[0]-10);
558 newlen--;
559 } else {
560 memcpy(rv+strlen(rv), pathitem+1+9, pathitem[0]-9);
561 }
562 rv[newlen-2] = '\n';
563 rv[newlen-1] = 0;
564 } else {
565 /* Use as-is */
566 newlen = strlen(rv) + (pathitem[0]) + 2;
567 if( (rv=realloc(rv, newlen)) == NULL)
568 goto out;
569 memcpy(rv+strlen(rv), pathitem+1, pathitem[0]);
570 rv[newlen-2] = '\n';
571 rv[newlen-1] = 0;
572 }
573 }
574 if( strlen(rv) == 1) {
575 free(rv);
576 rv = NULL;
577 }
578 if ( rv ) {
579 rv[strlen(rv)-1] = 0;
580 rv++;
581 }
582out:
583 if ( prefrh ) {
584 CloseResFile(prefrh);
585 UseResFile(oldrh);
586 }
587 return rv;
588}
589#endif /* !USE_BUILTIN_PATH */
590
Jack Jansen74162f31995-02-15 22:58:33 +0000591/*
592** Returns true if the argument has a resource fork, and it contains
593** a 'PYC ' resource of the correct name
594*/
595int
596PyMac_FindResourceModule(module, filename)
597char *module;
598char *filename;
599{
600 FSSpec fss;
601 FInfo finfo;
602 short oldrh, filerh;
603 int ok;
604 Handle h;
605
606 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
607 return 0; /* It doesn't exist */
608 if ( FSpGetFInfo(&fss, &finfo) != noErr )
609 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000610 oldrh = CurResFile();
611 filerh = FSpOpenResFile(&fss, fsRdPerm);
612 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000613 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000614 UseResFile(filerh);
615 SetResLoad(0);
616 h = Get1NamedResource('PYC ', Pstring(module));
617 SetResLoad(1);
618 ok = (h != NULL);
619 CloseResFile(filerh);
620 UseResFile(oldrh);
621 return ok;
622}
623
624/*
625** Load the specified module from a resource
626*/
627PyObject *
628PyMac_LoadResourceModule(module, filename)
629char *module;
630char *filename;
631{
632 FSSpec fss;
633 FInfo finfo;
634 short oldrh, filerh;
635 int ok;
636 Handle h;
637 OSErr err;
638 PyObject *m, *co;
639 long num, size;
640
641 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
642 goto error;
643 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
644 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000645 oldrh = CurResFile();
646 filerh = FSpOpenResFile(&fss, fsRdPerm);
647 if ( filerh == -1 ) {
648 err = ResError();
649 goto error;
650 }
651 UseResFile(filerh);
652 h = Get1NamedResource('PYC ', Pstring(module));
653 if ( h == NULL ) {
654 err = ResError();
655 goto error;
656 }
657 HLock(h);
658 /*
659 ** XXXX The next few lines are intimately tied to the format of pyc
660 ** files. I'm not sure whether this code should be here or in import.c -- Jack
661 */
662 size = GetHandleSize(h);
663 if ( size < 8 ) {
664 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000665 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000666 } else {
667 num = (*h)[0] & 0xff;
668 num = num | (((*h)[1] & 0xff) << 8);
669 num = num | (((*h)[2] & 0xff) << 16);
670 num = num | (((*h)[3] & 0xff) << 24);
671 if ( num != PyImport_GetMagicNumber() ) {
672 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
673 co = NULL;
674 } else {
675 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
676 }
677 }
678 HUnlock(h);
679 CloseResFile(filerh);
680 UseResFile(oldrh);
681 if ( co ) {
682 m = PyImport_ExecCodeModule(module, co);
683 Py_DECREF(co);
684 } else {
685 m = NULL;
686 }
687 return m;
688error:
689 {
690 char buf[512];
691
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000692 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000693 PyErr_SetString(PyExc_ImportError, buf);
694 return NULL;
695 }
696}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000697
Jack Jansen3ec804a1995-02-20 15:56:10 +0000698/*
699** Helper routine for GetDirectory
700*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000701static pascal short
702myhook_proc(short item, DialogPtr theDialog, void *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000703{
704 if ( item == SELECTCUR_ITEM ) {
705 item = sfItemCancelButton;
706 * (int *)dataptr = 1;
707 }
708 return item;
709}
710
711/*
712** Ask the user for a directory. I still can't understand
713** why Apple doesn't provide a standard solution for this...
714*/
715int
716PyMac_GetDirectory(dirfss)
717 FSSpec *dirfss;
718{
719 static SFTypeList list = {'fldr', 0, 0, 0};
720 static Point where = {-1, -1};
721 static DlgHookYDUPP myhook_upp;
722 static int upp_inited = 0;
723 StandardFileReply reply;
724 int select_clicked = 0;
725
726 if ( !upp_inited ) {
727 myhook_upp = NewDlgHookYDProc(myhook_proc);
728 upp_inited = 1;
729 }
Guido van Rossum24a45e31995-02-20 23:45:53 +0000730 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen3ec804a1995-02-20 15:56:10 +0000731 NULL, NULL, NULL, (void *)&select_clicked);
732
733 reply.sfFile.name[0] = 0;
734 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
735 return 0;
736 return select_clicked;
737}
Jack Jansen5f653091995-01-18 13:53:49 +0000738
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000739/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000740int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000741PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000742{
743 if (!PyString_Check(v) || PyString_Size(v) != 4) {
744 PyErr_SetString(PyExc_TypeError,
745 "OSType arg must be string of 4 chars");
746 return 0;
747 }
748 memcpy((char *)pr, PyString_AsString(v), 4);
749 return 1;
750}
751
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000752/* Convert an OSType value to a 4-char string object */
753PyObject *
754PyMac_BuildOSType(OSType t)
755{
756 return PyString_FromStringAndSize((char *)&t, 4);
757}
758
759
760/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000761int
Guido van Rossum8f691791995-01-18 23:57:26 +0000762PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000763{
764 int len;
765 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
766 PyErr_SetString(PyExc_TypeError,
767 "Str255 arg must be string of at most 255 chars");
768 return 0;
769 }
770 pbuf[0] = len;
771 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
772 return 1;
773}
774
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000775/* Convert a Str255 to a Python string object */
776PyObject *
777PyMac_BuildStr255(Str255 s)
778{
779 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
780}
781
782
Jack Jansen5f653091995-01-18 13:53:49 +0000783/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000784** Convert a Python object to an FSSpec.
785** The object may either be a full pathname or a triple
786** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000787** NOTE: This routine will fail on pre-sys7 machines.
788** The caller is responsible for not calling this routine
789** in those cases (which is fine, since everyone calling
790** this is probably sys7 dependent anyway).
791*/
792int
Guido van Rossum8f691791995-01-18 23:57:26 +0000793PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000794{
795 Str255 path;
796 short refnum;
797 long parid;
798 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000799 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000800
Jack Jansene8e8ae01995-01-26 16:36:45 +0000801 /* first check whether it already is an FSSpec */
802 fs2 = mfs_GetFSSpecFSSpec(v);
803 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000804 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000805 return 1;
806 }
Jack Jansen5f653091995-01-18 13:53:49 +0000807 if ( PyString_Check(v) ) {
808 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000809 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000810 return 0;
811 refnum = 0; /* XXXX Should get CurWD here... */
812 parid = 0;
813 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000814 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
815 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000816 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000817 }
Jack Jansen5f653091995-01-18 13:53:49 +0000818 }
819 err = FSMakeFSSpec(refnum, parid, path, fs);
820 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000821 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000822 return 0;
823 }
824 return 1;
825}
826
Guido van Rossum8f691791995-01-18 23:57:26 +0000827
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000828
829/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000830 The object must be a (left, top, right, bottom) tuple.
831 (This differs from the order in the struct but is consistent with
832 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000833int
834PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000835{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000836 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000837}
Guido van Rossumb3404661995-01-22 18:36:13 +0000838
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000839/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000840PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000841PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000842{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000843 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000844}
845
846
847/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000848 The object must be a (h, v) tuple.
849 (This differs from the order in the struct but is consistent with
850 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000851int
852PyMac_GetPoint(PyObject *v, Point *p)
853{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000854 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000855}
856
857/* Convert a Point to a Python object */
858PyObject *
859PyMac_BuildPoint(Point p)
860{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000861 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000862}
863
864
865/* Convert a Python object to an EventRecord.
866 The object must be a (what, message, when, (v, h), modifiers) tuple. */
867int
868PyMac_GetEventRecord(PyObject *v, EventRecord *e)
869{
870 return PyArg_Parse(v, "(hll(hh)h)",
871 &e->what,
872 &e->message,
873 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000874 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000875 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000876 &e->modifiers);
877}
878
879/* Convert a Rect to an EventRecord object */
880PyObject *
881PyMac_BuildEventRecord(EventRecord *e)
882{
883 return Py_BuildValue("(hll(hh)h)",
884 e->what,
885 e->message,
886 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000887 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000888 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000889 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000890}
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000891
892
Jack Jansen76efd8e1995-02-24 22:53:16 +0000893#ifdef USE_MAC_APPLET_SUPPORT
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000894/* Applet support */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000895
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000896/* Run a compiled Python Python script from 'PYC ' resource __main__ */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000897static int
898run_main_resource()
899{
900 Handle h;
901 long size;
902 PyObject *code;
903 PyObject *result;
904
905 h = GetNamedResource('PYC ', "\p__main__");
906 if (h == NULL) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000907 Alert(NOPYC_ALERT, NULL);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000908 return 1;
909 }
910 size = GetResourceSizeOnDisk(h);
911 HLock(h);
912 code = PyMarshal_ReadObjectFromString(*h + 8, (int)(size - 8));
913 HUnlock(h);
914 ReleaseResource(h);
915 if (code == NULL) {
916 PyErr_Print();
917 return 1;
918 }
919 result = PyImport_ExecCodeModule("__main__", code);
920 Py_DECREF(code);
921 if (result == NULL) {
922 PyErr_Print();
923 return 1;
924 }
925 Py_DECREF(result);
926 return 0;
927}
928
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000929/* Initialization sequence for applets */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000930void
931PyMac_InitApplet()
932{
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000933 int argc;
934 char **argv;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000935 int err;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000936
Jack Jansen3ec804a1995-02-20 15:56:10 +0000937 PyMac_AddLibResources();
Jack Jansen3ec804a1995-02-20 15:56:10 +0000938#ifdef __MWERKS__
939 SIOUXSettings.asktosaveonclose = 0;
940 SIOUXSettings.showstatusline = 0;
941 SIOUXSettings.tabspaces = 4;
942#endif
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000943 argc = PyMac_GetArgv(&argv);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000944 Py_Initialize();
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000945 PySys_SetArgv(argc, argv);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000946 err = run_main_resource();
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000947 fflush(stderr);
948 fflush(stdout);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000949#ifdef __MWERKS__
950 if (!err)
951 SIOUXSettings.autocloseonquit = 1;
952 else
953 SIOUXSettings.showstatusline = 1;
954#endif
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000955 /* XXX Should we bother to Py_Exit(sts)? */
956}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000957
Jack Jansen76efd8e1995-02-24 22:53:16 +0000958#endif /* USE_MAC_APPLET_SUPPORT */
959
960/* For normal application */
961void
962PyMac_InitApplication()
963{
964 int argc;
965 char **argv;
966
967#ifdef USE_MAC_SHARED_LIBRARY
968 PyMac_AddLibResources();
969#endif
970#ifdef __MWERKS__
971 SIOUXSettings.asktosaveonclose = 0;
972 SIOUXSettings.showstatusline = 0;
973 SIOUXSettings.tabspaces = 4;
974#endif
975 argc = PyMac_GetArgv(&argv);
976 if ( argc > 1 ) {
977 /* We're running a script. Attempt to change current directory */
978 char curwd[256], *endp;
979
980 strcpy(curwd, argv[1]);
981 endp = strrchr(curwd, ':');
982 if ( endp && endp > curwd ) {
983 *endp = '\0';
Jack Jansen45ff77f1995-04-24 12:41:41 +0000984
Jack Jansen76efd8e1995-02-24 22:53:16 +0000985 chdir(curwd);
986 }
987 }
988 Py_Main(argc, argv);
989}