blob: 60d6930945bee837c11d069aa9732b615dd724d0 [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>
Guido van Rossumcc0d8791995-01-30 08:57:13 +000045#ifdef THINK_C
46#include <OSEvents.h> /* For EvQElPtr */
47#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000048
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000049#ifndef HAVE_UNIVERSAL_HEADERS
50#define GetResourceSizeOnDisk(x) SizeResource(x)
51#endif
52
Jack Jansenee23d6e1995-01-27 14:43:25 +000053#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000054#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000055
Jack Jansen3ec804a1995-02-20 15:56:10 +000056/* The alert for "No Python directory, where is it?" */
Jack Jansen8cd2b721995-02-13 11:33:28 +000057#define NOPYTHON_ALERT 128
58#define YES_ITEM 1
59#define NO_ITEM 2
60#define CURWD_ITEM 3
61
Jack Jansen3ec804a1995-02-20 15:56:10 +000062/* The alert for "this is an applet template" */
63#define NOPYC_ALERT 129
64
65/* The dialog for our GetDirectory call */
66#define GETDIR_ID 130 /* Resource ID for our "get directory" */
67#define SELECTCUR_ITEM 10 /* "Select current directory" button */
68
Jack Jansene8e8ae01995-01-26 16:36:45 +000069#ifdef __MWERKS__
Jack Jansenee23d6e1995-01-27 14:43:25 +000070/*
71** With MW we can pass the event off to the console window, so
72** we might as well handle all events.
73*/
Jack Jansene8e8ae01995-01-26 16:36:45 +000074#include <SIOUX.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000075#define MAINLOOP_EVENTMASK everyEvent
76#else
77/*
78** For other compilers we're more careful, since we can't handle
79** things like updates (and they'll keep coming back if we don't
80** handle them)
81*/
82#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +000083#endif /* __MWERKS__ */
84
85#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000086
Guido van Rossumb3404661995-01-22 18:36:13 +000087/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +000088** with the python errors.h. */
89#define fnfErr -43
90
Jack Jansene8e8ae01995-01-26 16:36:45 +000091/* Declared in macfsmodule.c: */
92extern FSSpec *mfs_GetFSSpecFSSpec();
93
Jack Jansenee23d6e1995-01-27 14:43:25 +000094/* Interrupt code variables: */
95static int interrupted; /* Set to true when cmd-. seen */
96static RETSIGTYPE intcatcher Py_PROTO((int));
97
Jack Jansene8e8ae01995-01-26 16:36:45 +000098/*
99** We attempt to be a good citizen by giving up the CPU periodically.
100** When in the foreground we do this less often and for shorter periods
101** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +0000102** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000103** The counts here are in ticks of 1/60th second.
104** XXXX The initial values here are not based on anything.
105** FG-python gives up the cpu for 1/60th 5 times per second,
106** BG-python for .2 second 10 times per second.
107*/
108static long interval_fg = 12;
109static long interval_bg = 6;
110static long yield_fg = 1;
111static long yield_bg = 12;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000112static long lastyield;
113static int in_foreground;
114
115int PyMac_DoYieldEnabled = 1; /* Don't do eventloop when false */
116
Jack Jansene8e8ae01995-01-26 16:36:45 +0000117
Jack Jansen5f653091995-01-18 13:53:49 +0000118/* Convert C to Pascal string. Returns pointer to static buffer. */
119unsigned char *
120Pstring(char *str)
121{
122 static Str255 buf;
123 int len;
124
125 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000126 if (len > 255)
127 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000128 buf[0] = (unsigned char)len;
129 strncpy((char *)buf+1, str, len);
130 return buf;
131}
132
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000133/* Like strerror() but for Mac OS error numbers */
134char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000135{
136 static char buf[256];
137 Handle h;
138 char *str;
139
140 h = GetResource('Estr', err);
141 if ( h ) {
142 HLock(h);
143 str = (char *)*h;
144 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000145 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000146 HUnlock(h);
147 ReleaseResource(h);
148 } else {
149 sprintf(buf, "Mac OS error code %d", err);
150 }
151 return buf;
152}
153
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000154/* Exception object shared by all Mac specific modules for Mac OS errors */
155PyObject *PyMac_OSErrException;
156
157/* Initialize and return PyMac_OSErrException */
158PyObject *
159PyMac_GetOSErrException()
160{
161 if (PyMac_OSErrException == NULL)
162 PyMac_OSErrException = PyString_FromString("Mac OS Error");
163 return PyMac_OSErrException;
164}
165
Jack Jansenf93c72a1994-12-14 14:07:50 +0000166/* Set a MAC-specific error from errno, and return NULL; return None if no error */
167PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000168PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000169{
170 char *msg;
171 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000172
Guido van Rossum8f691791995-01-18 23:57:26 +0000173 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000174 Py_INCREF(Py_None);
175 return Py_None;
176 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000177 if (err == -1 && PyErr_Occurred())
178 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000179 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000180 v = Py_BuildValue("(is)", err, msg);
181 PyErr_SetObject(eobj, v);
182 Py_DECREF(v);
183 return NULL;
184}
185
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000186/* Call PyErr_Mac with PyMac_OSErrException */
187PyObject *
188PyMac_Error(OSErr err)
189{
190 return PyErr_Mac(PyMac_GetOSErrException(), err);
191}
192
Jack Jansenee23d6e1995-01-27 14:43:25 +0000193/* The catcher routine (which may not be used for all compilers) */
194static RETSIGTYPE
195intcatcher(sig)
196 int sig;
197{
198 interrupted = 1;
199 signal(SIGINT, intcatcher);
200}
201
202void
203PyOS_InitInterrupts()
204{
205 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
206 signal(SIGINT, intcatcher);
207}
208
209/*
210** This routine scans the event queue looking for cmd-.
211** This is the only way to get an interrupt under THINK (since it
212** doesn't do SIGINT handling), but is also used under MW, when
213** the full-fledged event loop is disabled. This way, we can at least
214** interrupt a runaway python program.
215*/
216static void
217scan_event_queue(flush)
218 int flush;
219{
220 register EvQElPtr q;
221
222 q = (EvQElPtr) GetEvQHdr()->qHead;
223
224 for (; q; q = (EvQElPtr)q->qLink) {
225 if (q->evtQWhat == keyDown &&
226 (char)q->evtQMessage == '.' &&
227 (q->evtQModifiers & cmdKey) != 0) {
228 if ( flush )
229 FlushEvents(keyDownMask, 0);
230 interrupted = 1;
231 break;
232 }
233 }
234}
235
236int
237PyOS_InterruptOccurred()
238{
239#ifdef THINK_C
240 scan_event_queue(1);
241#endif
242 PyMac_Yield();
243 if (interrupted) {
244 interrupted = 0;
245 return 1;
246 }
247 return 0;
248}
249
250/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
251** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
252** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
253** thereafter.
254*/
255static int
256intrpeek()
257{
258#ifdef THINK_C
259 scan_event_queue(0);
260#endif
261 return interrupted;
262}
263
264/* Check whether we are in the foreground */
265int
266PyMac_InForeground()
267{
268 static ProcessSerialNumber ours;
269 static inited;
270 ProcessSerialNumber curfg;
271 Boolean eq;
272
273 if ( inited == 0 )
274 (void)GetCurrentProcess(&ours);
275 inited = 1;
276 if ( GetFrontProcess(&curfg) < 0 )
277 eq = 1;
278 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
279 eq = 1;
280 return (int)eq;
281
282}
283
Jack Jansenf93c72a1994-12-14 14:07:50 +0000284/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000285** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000286*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000287void
288PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
289{
290 interval_fg = fgi;
291 yield_fg = fgy;
292 interval_bg = bgi;
293 yield_bg = bgy;
294}
295
296/*
Jack Jansena76382a1995-02-02 14:25:56 +0000297** Handle an event, either one found in the mainloop eventhandler or
298** one passed back from the python program.
299*/
300void
301PyMac_HandleEvent(evp)
302 EventRecord *evp;
303{
304 WindowPtr wp;
305
306#ifdef __MWERKS__
307 /* If SIOUX wants it we're done */
308 (void)SIOUXHandleOneEvent(evp);
309#else
310 /* Other compilers are just unlucky: we only weed out clicks in other applications */
311 if ( evp->what == mouseDown ) {
312 if ( FindWindow(evp->where, &wp) == inSysWindow )
313 SystemClick(evp, wp);
314 }
315#endif /* !__MWERKS__ */
316}
317
318/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000319** Yield the CPU to other tasks.
320*/
321static
322PyMac_DoYield()
Jack Jansenf93c72a1994-12-14 14:07:50 +0000323{
324 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000325 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000326 static int no_waitnextevent = -1;
327 int gotone;
328
329 if ( no_waitnextevent < 0 ) {
330 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
331 NGetTrapAddress(_Unimplemented, ToolTrap));
332 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000333
Jack Jansenee23d6e1995-01-27 14:43:25 +0000334 if ( !PyMac_DoYieldEnabled ) {
335#ifndef THINK_C
336 /* Under think this has been done before in intrcheck() or intrpeek() */
337 scan_event_queue(0);
338#endif
Jack Jansene8e8ae01995-01-26 16:36:45 +0000339 return;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000340 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000341
Jack Jansenee23d6e1995-01-27 14:43:25 +0000342 in_foreground = PyMac_InForeground();
343 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000344 yield = yield_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000345 else
346 yield = yield_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000347 while ( 1 ) {
348 if ( no_waitnextevent ) {
349 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000350 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000351 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000352 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000353 }
354 /* Get out quickly if nothing interesting is happening */
355 if ( !gotone || ev.what == nullEvent )
356 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000357 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000358 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000359 lastyield = TickCount();
360}
361
362/*
363** Yield the CPU to other tasks if opportune
364*/
365void
366PyMac_Yield() {
367 long iv;
368
Jack Jansenee23d6e1995-01-27 14:43:25 +0000369 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000370 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000371 else
372 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000373 if ( TickCount() > lastyield + iv )
374 PyMac_DoYield();
375}
376
377/*
378** Idle routine for busy-wait loops.
379** Gives up CPU, handles events and returns true if an interrupt is pending
380** (but not actually handled yet).
381*/
382int
383PyMac_Idle()
384{
385 PyMac_DoYield();
386 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000387}
388
Jack Jansen8cd2b721995-02-13 11:33:28 +0000389/*
390** Return the name of the Python directory
391*/
392char *
393PyMac_GetPythonDir()
394{
395 int item;
396 static char name[256];
397 AliasHandle handle;
398 FSSpec dirspec;
399 int ok = 0, exists = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000400 Boolean modified = 0, cannotmodify = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000401 short oldrh, prefrh;
402 short prefdirRefNum;
403 long prefdirDirID;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000404
Jack Jansen6cfab231995-02-13 22:46:00 +0000405 /*
406 ** Remember old resource file and try to open preferences file
407 ** in the preferences folder. If it doesn't exist we try to create
408 ** it. If anything fails here we limp on, but set cannotmodify so
409 ** we don't try to store things later on.
410 */
411 oldrh = CurResFile();
412 if ( FindFolder(kOnSystemDisk, 'pref', kDontCreateFolder, &prefdirRefNum,
413 &prefdirDirID) != noErr ) {
414 /* Something wrong with preferences folder */
415 cannotmodify = 1;
416 } else {
417 (void)FSMakeFSSpec(prefdirRefNum, prefdirDirID, "\pPython Preferences", &dirspec);
418 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
419 if ( prefrh == -1 ) {
420 /* It doesn't exist. Try to create it */
Guido van Rossumbecdbec1995-02-14 01:27:24 +0000421 FSpCreateResFile(&dirspec, 'PYTH', 'pref', 0);
Jack Jansen6cfab231995-02-13 22:46:00 +0000422 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
423 if ( prefrh == -1 ) {
424 cannotmodify = 1;
425 } else {
426 UseResFile(prefrh);
427 }
428 }
429 }
430 /* So, we've opened our preferences file, we hope. Look for the alias */
431 handle = (AliasHandle)Get1Resource('alis', 128);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000432 if ( handle ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000433 /* It exists. Resolve it (possibly updating it) */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000434 if ( ResolveAlias(NULL, handle, &dirspec, &modified) == noErr )
435 ok = 1;
436 exists = 1;
437 }
438 if ( !ok ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000439 /* No luck, so far. ask the user for help */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000440 item = Alert(NOPYTHON_ALERT, NULL);
441 if ( item == YES_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000442 /* The user wants to point us to a directory. Let her do so */
Jack Jansen3ec804a1995-02-20 15:56:10 +0000443 ok = PyMac_GetDirectory(&dirspec);
444 if ( ok )
445 modified = 1;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000446 } else if ( item == CURWD_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000447 /* The user told us the current directory is fine. Build an FSSpec for it */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000448 if ( getwd(name) ) {
449 if ( FSMakeFSSpec(0, 0, Pstring(name), &dirspec) == 0 ) {
450 ok = 1;
451 modified = 1;
452 }
453 }
454 }
455 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000456 if ( ok && modified && !cannotmodify) {
457 /* We have a new, valid fsspec and we can update the preferences file. Do so. */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000458 if ( !exists ) {
459 if (NewAlias(NULL, &dirspec, &handle) == 0 )
460 AddResource((Handle)handle, 'alis', 128, "\p");
461 } else {
462 ChangedResource((Handle)handle);
463 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000464 UpdateResFile(prefrh);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000465 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000466 if ( !cannotmodify ) {
467 /* This means we have the resfile open. Close it. */
468 CloseResFile(prefrh);
469 }
470 /* Back to the old resource file */
471 UseResFile(oldrh);
472 /* Now turn the fsspec into a path to give back to our caller */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000473 if ( ok ) {
474 ok = (nfullpath(&dirspec, name) == 0);
475 if ( ok ) strcat(name, ":");
476 }
477 if ( !ok ) {
478 /* If all fails, we return the current directory */
479 name[0] = 0;
480 (void)getwd(name);
481 }
482 return name;
483}
484
Jack Jansen74162f31995-02-15 22:58:33 +0000485/*
486** Returns true if the argument has a resource fork, and it contains
487** a 'PYC ' resource of the correct name
488*/
489int
490PyMac_FindResourceModule(module, filename)
491char *module;
492char *filename;
493{
494 FSSpec fss;
495 FInfo finfo;
496 short oldrh, filerh;
497 int ok;
498 Handle h;
499
500 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
501 return 0; /* It doesn't exist */
502 if ( FSpGetFInfo(&fss, &finfo) != noErr )
503 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000504 oldrh = CurResFile();
505 filerh = FSpOpenResFile(&fss, fsRdPerm);
506 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000507 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000508 UseResFile(filerh);
509 SetResLoad(0);
510 h = Get1NamedResource('PYC ', Pstring(module));
511 SetResLoad(1);
512 ok = (h != NULL);
513 CloseResFile(filerh);
514 UseResFile(oldrh);
515 return ok;
516}
517
518/*
519** Load the specified module from a resource
520*/
521PyObject *
522PyMac_LoadResourceModule(module, filename)
523char *module;
524char *filename;
525{
526 FSSpec fss;
527 FInfo finfo;
528 short oldrh, filerh;
529 int ok;
530 Handle h;
531 OSErr err;
532 PyObject *m, *co;
533 long num, size;
534
535 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
536 goto error;
537 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
538 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000539 oldrh = CurResFile();
540 filerh = FSpOpenResFile(&fss, fsRdPerm);
541 if ( filerh == -1 ) {
542 err = ResError();
543 goto error;
544 }
545 UseResFile(filerh);
546 h = Get1NamedResource('PYC ', Pstring(module));
547 if ( h == NULL ) {
548 err = ResError();
549 goto error;
550 }
551 HLock(h);
552 /*
553 ** XXXX The next few lines are intimately tied to the format of pyc
554 ** files. I'm not sure whether this code should be here or in import.c -- Jack
555 */
556 size = GetHandleSize(h);
557 if ( size < 8 ) {
558 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000559 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000560 } else {
561 num = (*h)[0] & 0xff;
562 num = num | (((*h)[1] & 0xff) << 8);
563 num = num | (((*h)[2] & 0xff) << 16);
564 num = num | (((*h)[3] & 0xff) << 24);
565 if ( num != PyImport_GetMagicNumber() ) {
566 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
567 co = NULL;
568 } else {
569 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
570 }
571 }
572 HUnlock(h);
573 CloseResFile(filerh);
574 UseResFile(oldrh);
575 if ( co ) {
576 m = PyImport_ExecCodeModule(module, co);
577 Py_DECREF(co);
578 } else {
579 m = NULL;
580 }
581 return m;
582error:
583 {
584 char buf[512];
585
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000586 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000587 PyErr_SetString(PyExc_ImportError, buf);
588 return NULL;
589 }
590}
Jack Jansen3ec804a1995-02-20 15:56:10 +0000591/*
592** Helper routine for GetDirectory
593*/
594static int
595myhook_proc(item, theDialog, dataptr)
596 short item;
597 DialogPtr theDialog;
598 void *dataptr;
599{
600 if ( item == SELECTCUR_ITEM ) {
601 item = sfItemCancelButton;
602 * (int *)dataptr = 1;
603 }
604 return item;
605}
606
607/*
608** Ask the user for a directory. I still can't understand
609** why Apple doesn't provide a standard solution for this...
610*/
611int
612PyMac_GetDirectory(dirfss)
613 FSSpec *dirfss;
614{
615 static SFTypeList list = {'fldr', 0, 0, 0};
616 static Point where = {-1, -1};
617 static DlgHookYDUPP myhook_upp;
618 static int upp_inited = 0;
619 StandardFileReply reply;
620 int select_clicked = 0;
621
622 if ( !upp_inited ) {
623 myhook_upp = NewDlgHookYDProc(myhook_proc);
624 upp_inited = 1;
625 }
626 CustomGetFile((FileFilterUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
627 NULL, NULL, NULL, (void *)&select_clicked);
628
629 reply.sfFile.name[0] = 0;
630 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
631 return 0;
632 return select_clicked;
633}
Jack Jansen5f653091995-01-18 13:53:49 +0000634
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000635/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000636int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000637PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000638{
639 if (!PyString_Check(v) || PyString_Size(v) != 4) {
640 PyErr_SetString(PyExc_TypeError,
641 "OSType arg must be string of 4 chars");
642 return 0;
643 }
644 memcpy((char *)pr, PyString_AsString(v), 4);
645 return 1;
646}
647
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000648/* Convert an OSType value to a 4-char string object */
649PyObject *
650PyMac_BuildOSType(OSType t)
651{
652 return PyString_FromStringAndSize((char *)&t, 4);
653}
654
655
656/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000657int
Guido van Rossum8f691791995-01-18 23:57:26 +0000658PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000659{
660 int len;
661 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
662 PyErr_SetString(PyExc_TypeError,
663 "Str255 arg must be string of at most 255 chars");
664 return 0;
665 }
666 pbuf[0] = len;
667 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
668 return 1;
669}
670
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000671/* Convert a Str255 to a Python string object */
672PyObject *
673PyMac_BuildStr255(Str255 s)
674{
675 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
676}
677
678
Jack Jansen5f653091995-01-18 13:53:49 +0000679/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000680** Convert a Python object to an FSSpec.
681** The object may either be a full pathname or a triple
682** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000683** NOTE: This routine will fail on pre-sys7 machines.
684** The caller is responsible for not calling this routine
685** in those cases (which is fine, since everyone calling
686** this is probably sys7 dependent anyway).
687*/
688int
Guido van Rossum8f691791995-01-18 23:57:26 +0000689PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000690{
691 Str255 path;
692 short refnum;
693 long parid;
694 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000695 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000696
Jack Jansene8e8ae01995-01-26 16:36:45 +0000697 /* first check whether it already is an FSSpec */
698 fs2 = mfs_GetFSSpecFSSpec(v);
699 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000700 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000701 return 1;
702 }
Jack Jansen5f653091995-01-18 13:53:49 +0000703 if ( PyString_Check(v) ) {
704 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000705 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000706 return 0;
707 refnum = 0; /* XXXX Should get CurWD here... */
708 parid = 0;
709 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000710 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
711 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000712 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000713 }
Jack Jansen5f653091995-01-18 13:53:49 +0000714 }
715 err = FSMakeFSSpec(refnum, parid, path, fs);
716 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000717 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000718 return 0;
719 }
720 return 1;
721}
722
Guido van Rossum8f691791995-01-18 23:57:26 +0000723
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000724
725/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000726 The object must be a (left, top, right, bottom) tuple.
727 (This differs from the order in the struct but is consistent with
728 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000729int
730PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000731{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000732 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000733}
Guido van Rossumb3404661995-01-22 18:36:13 +0000734
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000735/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000736PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000737PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000738{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000739 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000740}
741
742
743/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000744 The object must be a (h, v) tuple.
745 (This differs from the order in the struct but is consistent with
746 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000747int
748PyMac_GetPoint(PyObject *v, Point *p)
749{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000750 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000751}
752
753/* Convert a Point to a Python object */
754PyObject *
755PyMac_BuildPoint(Point p)
756{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000757 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000758}
759
760
761/* Convert a Python object to an EventRecord.
762 The object must be a (what, message, when, (v, h), modifiers) tuple. */
763int
764PyMac_GetEventRecord(PyObject *v, EventRecord *e)
765{
766 return PyArg_Parse(v, "(hll(hh)h)",
767 &e->what,
768 &e->message,
769 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000770 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000771 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000772 &e->modifiers);
773}
774
775/* Convert a Rect to an EventRecord object */
776PyObject *
777PyMac_BuildEventRecord(EventRecord *e)
778{
779 return Py_BuildValue("(hll(hh)h)",
780 e->what,
781 e->message,
782 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000783 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000784 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000785 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000786}
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000787
788
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000789/* ---------- */
790/* Applet support */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000791
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000792/* Run a compiled Python Python script from 'PYC ' resource __main__ */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000793static int
794run_main_resource()
795{
796 Handle h;
797 long size;
798 PyObject *code;
799 PyObject *result;
800
801 h = GetNamedResource('PYC ', "\p__main__");
802 if (h == NULL) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000803 Alert(NOPYC_ALERT, NULL);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000804 return 1;
805 }
806 size = GetResourceSizeOnDisk(h);
807 HLock(h);
808 code = PyMarshal_ReadObjectFromString(*h + 8, (int)(size - 8));
809 HUnlock(h);
810 ReleaseResource(h);
811 if (code == NULL) {
812 PyErr_Print();
813 return 1;
814 }
815 result = PyImport_ExecCodeModule("__main__", code);
816 Py_DECREF(code);
817 if (result == NULL) {
818 PyErr_Print();
819 return 1;
820 }
821 Py_DECREF(result);
822 return 0;
823}
824
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000825/* Initialization sequence for applets */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000826void
827PyMac_InitApplet()
828{
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000829 int argc;
830 char **argv;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000831
832#ifdef __MWERKS__
833 /*
834 ** Guido: you should fix this. You should arrange to have the
835 ** __sinit routine from macshlglue.c called so you can stuff
836 ** resources into the lib file.
837 */
838 PyMac_AddLibResources();
839#else
840 KABOO! KABOO!
841#endif
842#ifdef __MWERKS__
843 SIOUXSettings.asktosaveonclose = 0;
844 SIOUXSettings.showstatusline = 0;
845 SIOUXSettings.tabspaces = 4;
846#endif
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000847 argc = PyMac_GetArgv(&argv);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000848 Py_Initialize();
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000849 PySys_SetArgv(argc, argv);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000850 err = run_main_resource();
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000851 fflush(stderr);
852 fflush(stdout);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000853#ifdef __MWERKS__
854 if (!err)
855 SIOUXSettings.autocloseonquit = 1;
856 else
857 SIOUXSettings.showstatusline = 1;
858#endif
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000859 /* XXX Should we bother to Py_Exit(sts)? */
860}