blob: dc4d32b07fdfd04555051e40dc1571d1234d4ed3 [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 Jansen16df2aa1995-02-27 16:17:28 +000048#ifdef __MWERKS__
49#include <SIOUX.h>
50#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000051
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000052#ifndef HAVE_UNIVERSAL_HEADERS
53#define GetResourceSizeOnDisk(x) SizeResource(x)
Guido van Rossum24a45e31995-02-20 23:45:53 +000054typedef DlgHookYDProcPtr DlgHookYDUPP;
55#define NewDlgHookYDProc(userRoutine) ((DlgHookYDUPP) (userRoutine))
56typedef FileFilterYDProcPtr FileFilterYDUPP;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000057#endif
58
Jack Jansenee23d6e1995-01-27 14:43:25 +000059#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000060#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000061
Jack Jansen3ec804a1995-02-20 15:56:10 +000062/* The alert for "No Python directory, where is it?" */
Jack Jansen8cd2b721995-02-13 11:33:28 +000063#define NOPYTHON_ALERT 128
64#define YES_ITEM 1
65#define NO_ITEM 2
66#define CURWD_ITEM 3
67
Jack Jansen3ec804a1995-02-20 15:56:10 +000068/* The alert for "this is an applet template" */
69#define NOPYC_ALERT 129
70
71/* The dialog for our GetDirectory call */
72#define GETDIR_ID 130 /* Resource ID for our "get directory" */
73#define SELECTCUR_ITEM 10 /* "Select current directory" button */
74
Jack Jansenee23d6e1995-01-27 14:43:25 +000075/*
Jack Jansen16df2aa1995-02-27 16:17:28 +000076** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +000077** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +000078** handle them). Note that we don't know who has windows open, so
79** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +000080*/
81#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +000082
83#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000084
Guido van Rossumb3404661995-01-22 18:36:13 +000085/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +000086** with the python errors.h. */
87#define fnfErr -43
88
Jack Jansene8e8ae01995-01-26 16:36:45 +000089/* Declared in macfsmodule.c: */
90extern FSSpec *mfs_GetFSSpecFSSpec();
91
Jack Jansenee23d6e1995-01-27 14:43:25 +000092/* Interrupt code variables: */
93static int interrupted; /* Set to true when cmd-. seen */
94static RETSIGTYPE intcatcher Py_PROTO((int));
95
Jack Jansene8e8ae01995-01-26 16:36:45 +000096/*
97** We attempt to be a good citizen by giving up the CPU periodically.
98** When in the foreground we do this less often and for shorter periods
99** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +0000100** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000101** The counts here are in ticks of 1/60th second.
102** XXXX The initial values here are not based on anything.
103** FG-python gives up the cpu for 1/60th 5 times per second,
104** BG-python for .2 second 10 times per second.
105*/
106static long interval_fg = 12;
107static long interval_bg = 6;
108static long yield_fg = 1;
109static long yield_bg = 12;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000110static long lastyield;
111static int in_foreground;
112
Guido van Rossume7134aa1995-02-26 10:20:53 +0000113/*
114** When > 0, do full scanning for events (program is not event aware)
115** when == 0, only scan for Command-period
116** when < 0, don't do any event scanning
117*/
118int PyMac_DoYieldEnabled = 1;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000119
Jack Jansen5f653091995-01-18 13:53:49 +0000120/* Convert C to Pascal string. Returns pointer to static buffer. */
121unsigned char *
122Pstring(char *str)
123{
124 static Str255 buf;
125 int len;
126
127 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000128 if (len > 255)
129 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000130 buf[0] = (unsigned char)len;
131 strncpy((char *)buf+1, str, len);
132 return buf;
133}
134
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000135/* Like strerror() but for Mac OS error numbers */
136char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000137{
138 static char buf[256];
139 Handle h;
140 char *str;
141
142 h = GetResource('Estr', err);
143 if ( h ) {
144 HLock(h);
145 str = (char *)*h;
146 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000147 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000148 HUnlock(h);
149 ReleaseResource(h);
150 } else {
151 sprintf(buf, "Mac OS error code %d", err);
152 }
153 return buf;
154}
155
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000156/* Exception object shared by all Mac specific modules for Mac OS errors */
157PyObject *PyMac_OSErrException;
158
159/* Initialize and return PyMac_OSErrException */
160PyObject *
161PyMac_GetOSErrException()
162{
163 if (PyMac_OSErrException == NULL)
164 PyMac_OSErrException = PyString_FromString("Mac OS Error");
165 return PyMac_OSErrException;
166}
167
Jack Jansenf93c72a1994-12-14 14:07:50 +0000168/* Set a MAC-specific error from errno, and return NULL; return None if no error */
169PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000170PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000171{
172 char *msg;
173 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000174
Guido van Rossum8f691791995-01-18 23:57:26 +0000175 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000176 Py_INCREF(Py_None);
177 return Py_None;
178 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000179 if (err == -1 && PyErr_Occurred())
180 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000181 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000182 v = Py_BuildValue("(is)", err, msg);
183 PyErr_SetObject(eobj, v);
184 Py_DECREF(v);
185 return NULL;
186}
187
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000188/* Call PyErr_Mac with PyMac_OSErrException */
189PyObject *
190PyMac_Error(OSErr err)
191{
192 return PyErr_Mac(PyMac_GetOSErrException(), err);
193}
194
Jack Jansenee23d6e1995-01-27 14:43:25 +0000195/* The catcher routine (which may not be used for all compilers) */
196static RETSIGTYPE
197intcatcher(sig)
198 int sig;
199{
200 interrupted = 1;
201 signal(SIGINT, intcatcher);
202}
203
204void
205PyOS_InitInterrupts()
206{
207 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
208 signal(SIGINT, intcatcher);
209}
210
211/*
212** This routine scans the event queue looking for cmd-.
213** This is the only way to get an interrupt under THINK (since it
214** doesn't do SIGINT handling), but is also used under MW, when
215** the full-fledged event loop is disabled. This way, we can at least
216** interrupt a runaway python program.
217*/
218static void
219scan_event_queue(flush)
220 int flush;
221{
222 register EvQElPtr q;
223
224 q = (EvQElPtr) GetEvQHdr()->qHead;
225
226 for (; q; q = (EvQElPtr)q->qLink) {
227 if (q->evtQWhat == keyDown &&
228 (char)q->evtQMessage == '.' &&
229 (q->evtQModifiers & cmdKey) != 0) {
230 if ( flush )
231 FlushEvents(keyDownMask, 0);
232 interrupted = 1;
233 break;
234 }
235 }
236}
237
238int
239PyOS_InterruptOccurred()
240{
Guido van Rossume7134aa1995-02-26 10:20:53 +0000241 if (PyMac_DoYieldEnabled < 0)
242 return 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000243#ifdef THINK_C
244 scan_event_queue(1);
245#endif
246 PyMac_Yield();
247 if (interrupted) {
248 interrupted = 0;
249 return 1;
250 }
251 return 0;
252}
253
254/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
255** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
256** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
257** thereafter.
258*/
259static int
260intrpeek()
261{
262#ifdef THINK_C
263 scan_event_queue(0);
264#endif
265 return interrupted;
266}
267
268/* Check whether we are in the foreground */
269int
270PyMac_InForeground()
271{
272 static ProcessSerialNumber ours;
273 static inited;
274 ProcessSerialNumber curfg;
275 Boolean eq;
276
277 if ( inited == 0 )
278 (void)GetCurrentProcess(&ours);
279 inited = 1;
280 if ( GetFrontProcess(&curfg) < 0 )
281 eq = 1;
282 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
283 eq = 1;
284 return (int)eq;
285
286}
287
Jack Jansenf93c72a1994-12-14 14:07:50 +0000288/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000289** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000290*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000291void
292PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
293{
294 interval_fg = fgi;
295 yield_fg = fgy;
296 interval_bg = bgi;
297 yield_bg = bgy;
298}
299
300/*
Jack Jansena76382a1995-02-02 14:25:56 +0000301** Handle an event, either one found in the mainloop eventhandler or
302** one passed back from the python program.
303*/
304void
305PyMac_HandleEvent(evp)
306 EventRecord *evp;
307{
308 WindowPtr wp;
309
310#ifdef __MWERKS__
311 /* If SIOUX wants it we're done */
312 (void)SIOUXHandleOneEvent(evp);
313#else
314 /* Other compilers are just unlucky: we only weed out clicks in other applications */
315 if ( evp->what == mouseDown ) {
316 if ( FindWindow(evp->where, &wp) == inSysWindow )
317 SystemClick(evp, wp);
318 }
319#endif /* !__MWERKS__ */
320}
321
322/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000323** Yield the CPU to other tasks.
324*/
325static
326PyMac_DoYield()
Jack Jansenf93c72a1994-12-14 14:07:50 +0000327{
328 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000329 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000330 static int no_waitnextevent = -1;
331 int gotone;
332
333 if ( no_waitnextevent < 0 ) {
334 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
335 NGetTrapAddress(_Unimplemented, ToolTrap));
336 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000337
Jack Jansenee23d6e1995-01-27 14:43:25 +0000338 if ( !PyMac_DoYieldEnabled ) {
339#ifndef THINK_C
340 /* Under think this has been done before in intrcheck() or intrpeek() */
341 scan_event_queue(0);
342#endif
Jack Jansene8e8ae01995-01-26 16:36:45 +0000343 return;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000344 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000345
Jack Jansenee23d6e1995-01-27 14:43:25 +0000346 in_foreground = PyMac_InForeground();
347 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000348 yield = yield_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000349 else
350 yield = yield_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000351 while ( 1 ) {
352 if ( no_waitnextevent ) {
353 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000354 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000355 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000356 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000357 }
358 /* Get out quickly if nothing interesting is happening */
359 if ( !gotone || ev.what == nullEvent )
360 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000361 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000362 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000363 lastyield = TickCount();
364}
365
366/*
367** Yield the CPU to other tasks if opportune
368*/
369void
370PyMac_Yield() {
371 long iv;
372
Jack Jansenee23d6e1995-01-27 14:43:25 +0000373 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000374 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000375 else
376 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000377 if ( TickCount() > lastyield + iv )
378 PyMac_DoYield();
379}
380
381/*
382** Idle routine for busy-wait loops.
383** Gives up CPU, handles events and returns true if an interrupt is pending
384** (but not actually handled yet).
385*/
386int
387PyMac_Idle()
388{
389 PyMac_DoYield();
390 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000391}
392
Jack Jansen8cd2b721995-02-13 11:33:28 +0000393/*
394** Return the name of the Python directory
395*/
396char *
397PyMac_GetPythonDir()
398{
399 int item;
400 static char name[256];
401 AliasHandle handle;
402 FSSpec dirspec;
Jack Jansen45ff77f1995-04-24 12:41:41 +0000403 int ok = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000404 Boolean modified = 0, cannotmodify = 0;
Jack Jansen6cfab231995-02-13 22:46:00 +0000405 short oldrh, prefrh;
406 short prefdirRefNum;
407 long prefdirDirID;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000408
Jack Jansen6cfab231995-02-13 22:46:00 +0000409 /*
410 ** Remember old resource file and try to open preferences file
411 ** in the preferences folder. If it doesn't exist we try to create
412 ** it. If anything fails here we limp on, but set cannotmodify so
413 ** we don't try to store things later on.
414 */
415 oldrh = CurResFile();
416 if ( FindFolder(kOnSystemDisk, 'pref', kDontCreateFolder, &prefdirRefNum,
417 &prefdirDirID) != noErr ) {
418 /* Something wrong with preferences folder */
419 cannotmodify = 1;
420 } else {
421 (void)FSMakeFSSpec(prefdirRefNum, prefdirDirID, "\pPython Preferences", &dirspec);
422 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
423 if ( prefrh == -1 ) {
424 /* It doesn't exist. Try to create it */
Guido van Rossumbecdbec1995-02-14 01:27:24 +0000425 FSpCreateResFile(&dirspec, 'PYTH', 'pref', 0);
Jack Jansen6cfab231995-02-13 22:46:00 +0000426 prefrh = FSpOpenResFile(&dirspec, fsRdWrShPerm);
427 if ( prefrh == -1 ) {
Jack Jansen45ff77f1995-04-24 12:41:41 +0000428 /* This is strange, what should we do now? */
Jack Jansen6cfab231995-02-13 22:46:00 +0000429 cannotmodify = 1;
430 } else {
431 UseResFile(prefrh);
432 }
433 }
434 }
435 /* So, we've opened our preferences file, we hope. Look for the alias */
436 handle = (AliasHandle)Get1Resource('alis', 128);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000437 if ( handle ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000438 /* It exists. Resolve it (possibly updating it) */
Jack Jansen45ff77f1995-04-24 12:41:41 +0000439 if ( ResolveAlias(NULL, handle, &dirspec, &modified) == noErr ) {
Jack Jansen8cd2b721995-02-13 11:33:28 +0000440 ok = 1;
Jack Jansen45ff77f1995-04-24 12:41:41 +0000441 }
Jack Jansen8cd2b721995-02-13 11:33:28 +0000442 }
443 if ( !ok ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000444 /* No luck, so far. ask the user for help */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000445 item = Alert(NOPYTHON_ALERT, NULL);
446 if ( item == YES_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000447 /* The user wants to point us to a directory. Let her do so */
Jack Jansen3ec804a1995-02-20 15:56:10 +0000448 ok = PyMac_GetDirectory(&dirspec);
449 if ( ok )
450 modified = 1;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000451 } else if ( item == CURWD_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000452 /* The user told us the current directory is fine. Build an FSSpec for it */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000453 if ( getwd(name) ) {
454 if ( FSMakeFSSpec(0, 0, Pstring(name), &dirspec) == 0 ) {
455 ok = 1;
456 modified = 1;
457 }
458 }
459 }
Jack Jansen45ff77f1995-04-24 12:41:41 +0000460 if ( handle ) {
461 /* Set the (old, invalid) alias record to the new data */
462 UpdateAlias(NULL, &dirspec, handle, &modified);
463 }
Jack Jansen8cd2b721995-02-13 11:33:28 +0000464 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000465 if ( ok && modified && !cannotmodify) {
466 /* We have a new, valid fsspec and we can update the preferences file. Do so. */
Jack Jansen45ff77f1995-04-24 12:41:41 +0000467 if ( !handle ) {
Jack Jansen8cd2b721995-02-13 11:33:28 +0000468 if (NewAlias(NULL, &dirspec, &handle) == 0 )
469 AddResource((Handle)handle, 'alis', 128, "\p");
470 } else {
471 ChangedResource((Handle)handle);
472 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000473 UpdateResFile(prefrh);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000474 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000475 if ( !cannotmodify ) {
476 /* This means we have the resfile open. Close it. */
477 CloseResFile(prefrh);
478 }
479 /* Back to the old resource file */
480 UseResFile(oldrh);
481 /* Now turn the fsspec into a path to give back to our caller */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000482 if ( ok ) {
483 ok = (nfullpath(&dirspec, name) == 0);
484 if ( ok ) strcat(name, ":");
485 }
486 if ( !ok ) {
487 /* If all fails, we return the current directory */
488 name[0] = 0;
489 (void)getwd(name);
490 }
491 return name;
492}
493
Jack Jansen74162f31995-02-15 22:58:33 +0000494/*
495** Returns true if the argument has a resource fork, and it contains
496** a 'PYC ' resource of the correct name
497*/
498int
499PyMac_FindResourceModule(module, filename)
500char *module;
501char *filename;
502{
503 FSSpec fss;
504 FInfo finfo;
505 short oldrh, filerh;
506 int ok;
507 Handle h;
508
509 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
510 return 0; /* It doesn't exist */
511 if ( FSpGetFInfo(&fss, &finfo) != noErr )
512 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000513 oldrh = CurResFile();
514 filerh = FSpOpenResFile(&fss, fsRdPerm);
515 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000516 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000517 UseResFile(filerh);
518 SetResLoad(0);
519 h = Get1NamedResource('PYC ', Pstring(module));
520 SetResLoad(1);
521 ok = (h != NULL);
522 CloseResFile(filerh);
523 UseResFile(oldrh);
524 return ok;
525}
526
527/*
528** Load the specified module from a resource
529*/
530PyObject *
531PyMac_LoadResourceModule(module, filename)
532char *module;
533char *filename;
534{
535 FSSpec fss;
536 FInfo finfo;
537 short oldrh, filerh;
538 int ok;
539 Handle h;
540 OSErr err;
541 PyObject *m, *co;
542 long num, size;
543
544 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
545 goto error;
546 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
547 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000548 oldrh = CurResFile();
549 filerh = FSpOpenResFile(&fss, fsRdPerm);
550 if ( filerh == -1 ) {
551 err = ResError();
552 goto error;
553 }
554 UseResFile(filerh);
555 h = Get1NamedResource('PYC ', Pstring(module));
556 if ( h == NULL ) {
557 err = ResError();
558 goto error;
559 }
560 HLock(h);
561 /*
562 ** XXXX The next few lines are intimately tied to the format of pyc
563 ** files. I'm not sure whether this code should be here or in import.c -- Jack
564 */
565 size = GetHandleSize(h);
566 if ( size < 8 ) {
567 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000568 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000569 } else {
570 num = (*h)[0] & 0xff;
571 num = num | (((*h)[1] & 0xff) << 8);
572 num = num | (((*h)[2] & 0xff) << 16);
573 num = num | (((*h)[3] & 0xff) << 24);
574 if ( num != PyImport_GetMagicNumber() ) {
575 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
576 co = NULL;
577 } else {
578 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
579 }
580 }
581 HUnlock(h);
582 CloseResFile(filerh);
583 UseResFile(oldrh);
584 if ( co ) {
585 m = PyImport_ExecCodeModule(module, co);
586 Py_DECREF(co);
587 } else {
588 m = NULL;
589 }
590 return m;
591error:
592 {
593 char buf[512];
594
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000595 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000596 PyErr_SetString(PyExc_ImportError, buf);
597 return NULL;
598 }
599}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000600
Jack Jansen3ec804a1995-02-20 15:56:10 +0000601/*
602** Helper routine for GetDirectory
603*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000604static pascal short
605myhook_proc(short item, DialogPtr theDialog, void *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000606{
607 if ( item == SELECTCUR_ITEM ) {
608 item = sfItemCancelButton;
609 * (int *)dataptr = 1;
610 }
611 return item;
612}
613
614/*
615** Ask the user for a directory. I still can't understand
616** why Apple doesn't provide a standard solution for this...
617*/
618int
619PyMac_GetDirectory(dirfss)
620 FSSpec *dirfss;
621{
622 static SFTypeList list = {'fldr', 0, 0, 0};
623 static Point where = {-1, -1};
624 static DlgHookYDUPP myhook_upp;
625 static int upp_inited = 0;
626 StandardFileReply reply;
627 int select_clicked = 0;
628
629 if ( !upp_inited ) {
630 myhook_upp = NewDlgHookYDProc(myhook_proc);
631 upp_inited = 1;
632 }
Guido van Rossum24a45e31995-02-20 23:45:53 +0000633 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen3ec804a1995-02-20 15:56:10 +0000634 NULL, NULL, NULL, (void *)&select_clicked);
635
636 reply.sfFile.name[0] = 0;
637 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
638 return 0;
639 return select_clicked;
640}
Jack Jansen5f653091995-01-18 13:53:49 +0000641
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000642/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000643int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000644PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000645{
646 if (!PyString_Check(v) || PyString_Size(v) != 4) {
647 PyErr_SetString(PyExc_TypeError,
648 "OSType arg must be string of 4 chars");
649 return 0;
650 }
651 memcpy((char *)pr, PyString_AsString(v), 4);
652 return 1;
653}
654
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000655/* Convert an OSType value to a 4-char string object */
656PyObject *
657PyMac_BuildOSType(OSType t)
658{
659 return PyString_FromStringAndSize((char *)&t, 4);
660}
661
662
663/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000664int
Guido van Rossum8f691791995-01-18 23:57:26 +0000665PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000666{
667 int len;
668 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
669 PyErr_SetString(PyExc_TypeError,
670 "Str255 arg must be string of at most 255 chars");
671 return 0;
672 }
673 pbuf[0] = len;
674 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
675 return 1;
676}
677
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000678/* Convert a Str255 to a Python string object */
679PyObject *
680PyMac_BuildStr255(Str255 s)
681{
682 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
683}
684
685
Jack Jansen5f653091995-01-18 13:53:49 +0000686/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000687** Convert a Python object to an FSSpec.
688** The object may either be a full pathname or a triple
689** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000690** NOTE: This routine will fail on pre-sys7 machines.
691** The caller is responsible for not calling this routine
692** in those cases (which is fine, since everyone calling
693** this is probably sys7 dependent anyway).
694*/
695int
Guido van Rossum8f691791995-01-18 23:57:26 +0000696PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000697{
698 Str255 path;
699 short refnum;
700 long parid;
701 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000702 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000703
Jack Jansene8e8ae01995-01-26 16:36:45 +0000704 /* first check whether it already is an FSSpec */
705 fs2 = mfs_GetFSSpecFSSpec(v);
706 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000707 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000708 return 1;
709 }
Jack Jansen5f653091995-01-18 13:53:49 +0000710 if ( PyString_Check(v) ) {
711 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000712 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000713 return 0;
714 refnum = 0; /* XXXX Should get CurWD here... */
715 parid = 0;
716 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000717 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
718 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000719 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000720 }
Jack Jansen5f653091995-01-18 13:53:49 +0000721 }
722 err = FSMakeFSSpec(refnum, parid, path, fs);
723 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000724 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000725 return 0;
726 }
727 return 1;
728}
729
Guido van Rossum8f691791995-01-18 23:57:26 +0000730
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000731
732/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000733 The object must be a (left, top, right, bottom) tuple.
734 (This differs from the order in the struct but is consistent with
735 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000736int
737PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000738{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000739 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000740}
Guido van Rossumb3404661995-01-22 18:36:13 +0000741
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000742/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000743PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000744PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000745{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000746 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000747}
748
749
750/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000751 The object must be a (h, v) tuple.
752 (This differs from the order in the struct but is consistent with
753 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000754int
755PyMac_GetPoint(PyObject *v, Point *p)
756{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000757 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000758}
759
760/* Convert a Point to a Python object */
761PyObject *
762PyMac_BuildPoint(Point p)
763{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000764 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000765}
766
767
768/* Convert a Python object to an EventRecord.
769 The object must be a (what, message, when, (v, h), modifiers) tuple. */
770int
771PyMac_GetEventRecord(PyObject *v, EventRecord *e)
772{
773 return PyArg_Parse(v, "(hll(hh)h)",
774 &e->what,
775 &e->message,
776 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000777 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000778 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000779 &e->modifiers);
780}
781
782/* Convert a Rect to an EventRecord object */
783PyObject *
784PyMac_BuildEventRecord(EventRecord *e)
785{
786 return Py_BuildValue("(hll(hh)h)",
787 e->what,
788 e->message,
789 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000790 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000791 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000792 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000793}
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000794
795
Jack Jansen76efd8e1995-02-24 22:53:16 +0000796#ifdef USE_MAC_APPLET_SUPPORT
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000797/* Applet support */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000798
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000799/* Run a compiled Python Python script from 'PYC ' resource __main__ */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000800static int
801run_main_resource()
802{
803 Handle h;
804 long size;
805 PyObject *code;
806 PyObject *result;
807
808 h = GetNamedResource('PYC ', "\p__main__");
809 if (h == NULL) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000810 Alert(NOPYC_ALERT, NULL);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000811 return 1;
812 }
813 size = GetResourceSizeOnDisk(h);
814 HLock(h);
815 code = PyMarshal_ReadObjectFromString(*h + 8, (int)(size - 8));
816 HUnlock(h);
817 ReleaseResource(h);
818 if (code == NULL) {
819 PyErr_Print();
820 return 1;
821 }
822 result = PyImport_ExecCodeModule("__main__", code);
823 Py_DECREF(code);
824 if (result == NULL) {
825 PyErr_Print();
826 return 1;
827 }
828 Py_DECREF(result);
829 return 0;
830}
831
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000832/* Initialization sequence for applets */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000833void
834PyMac_InitApplet()
835{
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000836 int argc;
837 char **argv;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000838 int err;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000839
Jack Jansen3ec804a1995-02-20 15:56:10 +0000840 PyMac_AddLibResources();
Jack Jansen3ec804a1995-02-20 15:56:10 +0000841#ifdef __MWERKS__
842 SIOUXSettings.asktosaveonclose = 0;
843 SIOUXSettings.showstatusline = 0;
844 SIOUXSettings.tabspaces = 4;
845#endif
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000846 argc = PyMac_GetArgv(&argv);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000847 Py_Initialize();
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000848 PySys_SetArgv(argc, argv);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000849 err = run_main_resource();
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000850 fflush(stderr);
851 fflush(stdout);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000852#ifdef __MWERKS__
853 if (!err)
854 SIOUXSettings.autocloseonquit = 1;
855 else
856 SIOUXSettings.showstatusline = 1;
857#endif
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000858 /* XXX Should we bother to Py_Exit(sts)? */
859}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000860
Jack Jansen76efd8e1995-02-24 22:53:16 +0000861#endif /* USE_MAC_APPLET_SUPPORT */
862
863/* For normal application */
864void
865PyMac_InitApplication()
866{
867 int argc;
868 char **argv;
869
870#ifdef USE_MAC_SHARED_LIBRARY
871 PyMac_AddLibResources();
872#endif
873#ifdef __MWERKS__
874 SIOUXSettings.asktosaveonclose = 0;
875 SIOUXSettings.showstatusline = 0;
876 SIOUXSettings.tabspaces = 4;
877#endif
878 argc = PyMac_GetArgv(&argv);
879 if ( argc > 1 ) {
880 /* We're running a script. Attempt to change current directory */
881 char curwd[256], *endp;
882
883 strcpy(curwd, argv[1]);
884 endp = strrchr(curwd, ':');
885 if ( endp && endp > curwd ) {
886 *endp = '\0';
Jack Jansen45ff77f1995-04-24 12:41:41 +0000887
Jack Jansen76efd8e1995-02-24 22:53:16 +0000888 chdir(curwd);
889 }
890 }
891 Py_Main(argc, argv);
892}