blob: 5c255fbc3806de6dd74c050e4d05980efe9e7685 [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;
403 int ok = 0, exists = 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 ) {
428 cannotmodify = 1;
429 } else {
430 UseResFile(prefrh);
431 }
432 }
433 }
434 /* So, we've opened our preferences file, we hope. Look for the alias */
435 handle = (AliasHandle)Get1Resource('alis', 128);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000436 if ( handle ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000437 /* It exists. Resolve it (possibly updating it) */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000438 if ( ResolveAlias(NULL, handle, &dirspec, &modified) == noErr )
439 ok = 1;
440 exists = 1;
441 }
442 if ( !ok ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000443 /* No luck, so far. ask the user for help */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000444 item = Alert(NOPYTHON_ALERT, NULL);
445 if ( item == YES_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000446 /* The user wants to point us to a directory. Let her do so */
Jack Jansen3ec804a1995-02-20 15:56:10 +0000447 ok = PyMac_GetDirectory(&dirspec);
448 if ( ok )
449 modified = 1;
Jack Jansen8cd2b721995-02-13 11:33:28 +0000450 } else if ( item == CURWD_ITEM ) {
Jack Jansen6cfab231995-02-13 22:46:00 +0000451 /* The user told us the current directory is fine. Build an FSSpec for it */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000452 if ( getwd(name) ) {
453 if ( FSMakeFSSpec(0, 0, Pstring(name), &dirspec) == 0 ) {
454 ok = 1;
455 modified = 1;
456 }
457 }
458 }
459 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000460 if ( ok && modified && !cannotmodify) {
461 /* We have a new, valid fsspec and we can update the preferences file. Do so. */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000462 if ( !exists ) {
463 if (NewAlias(NULL, &dirspec, &handle) == 0 )
464 AddResource((Handle)handle, 'alis', 128, "\p");
465 } else {
466 ChangedResource((Handle)handle);
467 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000468 UpdateResFile(prefrh);
Jack Jansen8cd2b721995-02-13 11:33:28 +0000469 }
Jack Jansen6cfab231995-02-13 22:46:00 +0000470 if ( !cannotmodify ) {
471 /* This means we have the resfile open. Close it. */
472 CloseResFile(prefrh);
473 }
474 /* Back to the old resource file */
475 UseResFile(oldrh);
476 /* Now turn the fsspec into a path to give back to our caller */
Jack Jansen8cd2b721995-02-13 11:33:28 +0000477 if ( ok ) {
478 ok = (nfullpath(&dirspec, name) == 0);
479 if ( ok ) strcat(name, ":");
480 }
481 if ( !ok ) {
482 /* If all fails, we return the current directory */
483 name[0] = 0;
484 (void)getwd(name);
485 }
486 return name;
487}
488
Jack Jansen74162f31995-02-15 22:58:33 +0000489/*
490** Returns true if the argument has a resource fork, and it contains
491** a 'PYC ' resource of the correct name
492*/
493int
494PyMac_FindResourceModule(module, filename)
495char *module;
496char *filename;
497{
498 FSSpec fss;
499 FInfo finfo;
500 short oldrh, filerh;
501 int ok;
502 Handle h;
503
504 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
505 return 0; /* It doesn't exist */
506 if ( FSpGetFInfo(&fss, &finfo) != noErr )
507 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000508 oldrh = CurResFile();
509 filerh = FSpOpenResFile(&fss, fsRdPerm);
510 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000511 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000512 UseResFile(filerh);
513 SetResLoad(0);
514 h = Get1NamedResource('PYC ', Pstring(module));
515 SetResLoad(1);
516 ok = (h != NULL);
517 CloseResFile(filerh);
518 UseResFile(oldrh);
519 return ok;
520}
521
522/*
523** Load the specified module from a resource
524*/
525PyObject *
526PyMac_LoadResourceModule(module, filename)
527char *module;
528char *filename;
529{
530 FSSpec fss;
531 FInfo finfo;
532 short oldrh, filerh;
533 int ok;
534 Handle h;
535 OSErr err;
536 PyObject *m, *co;
537 long num, size;
538
539 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
540 goto error;
541 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
542 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000543 oldrh = CurResFile();
544 filerh = FSpOpenResFile(&fss, fsRdPerm);
545 if ( filerh == -1 ) {
546 err = ResError();
547 goto error;
548 }
549 UseResFile(filerh);
550 h = Get1NamedResource('PYC ', Pstring(module));
551 if ( h == NULL ) {
552 err = ResError();
553 goto error;
554 }
555 HLock(h);
556 /*
557 ** XXXX The next few lines are intimately tied to the format of pyc
558 ** files. I'm not sure whether this code should be here or in import.c -- Jack
559 */
560 size = GetHandleSize(h);
561 if ( size < 8 ) {
562 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000563 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000564 } else {
565 num = (*h)[0] & 0xff;
566 num = num | (((*h)[1] & 0xff) << 8);
567 num = num | (((*h)[2] & 0xff) << 16);
568 num = num | (((*h)[3] & 0xff) << 24);
569 if ( num != PyImport_GetMagicNumber() ) {
570 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
571 co = NULL;
572 } else {
573 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
574 }
575 }
576 HUnlock(h);
577 CloseResFile(filerh);
578 UseResFile(oldrh);
579 if ( co ) {
580 m = PyImport_ExecCodeModule(module, co);
581 Py_DECREF(co);
582 } else {
583 m = NULL;
584 }
585 return m;
586error:
587 {
588 char buf[512];
589
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000590 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000591 PyErr_SetString(PyExc_ImportError, buf);
592 return NULL;
593 }
594}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000595
Jack Jansen3ec804a1995-02-20 15:56:10 +0000596/*
597** Helper routine for GetDirectory
598*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000599static pascal short
600myhook_proc(short item, DialogPtr theDialog, void *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000601{
602 if ( item == SELECTCUR_ITEM ) {
603 item = sfItemCancelButton;
604 * (int *)dataptr = 1;
605 }
606 return item;
607}
608
609/*
610** Ask the user for a directory. I still can't understand
611** why Apple doesn't provide a standard solution for this...
612*/
613int
614PyMac_GetDirectory(dirfss)
615 FSSpec *dirfss;
616{
617 static SFTypeList list = {'fldr', 0, 0, 0};
618 static Point where = {-1, -1};
619 static DlgHookYDUPP myhook_upp;
620 static int upp_inited = 0;
621 StandardFileReply reply;
622 int select_clicked = 0;
623
624 if ( !upp_inited ) {
625 myhook_upp = NewDlgHookYDProc(myhook_proc);
626 upp_inited = 1;
627 }
Guido van Rossum24a45e31995-02-20 23:45:53 +0000628 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen3ec804a1995-02-20 15:56:10 +0000629 NULL, NULL, NULL, (void *)&select_clicked);
630
631 reply.sfFile.name[0] = 0;
632 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
633 return 0;
634 return select_clicked;
635}
Jack Jansen5f653091995-01-18 13:53:49 +0000636
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000637/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000638int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000639PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000640{
641 if (!PyString_Check(v) || PyString_Size(v) != 4) {
642 PyErr_SetString(PyExc_TypeError,
643 "OSType arg must be string of 4 chars");
644 return 0;
645 }
646 memcpy((char *)pr, PyString_AsString(v), 4);
647 return 1;
648}
649
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000650/* Convert an OSType value to a 4-char string object */
651PyObject *
652PyMac_BuildOSType(OSType t)
653{
654 return PyString_FromStringAndSize((char *)&t, 4);
655}
656
657
658/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000659int
Guido van Rossum8f691791995-01-18 23:57:26 +0000660PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000661{
662 int len;
663 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
664 PyErr_SetString(PyExc_TypeError,
665 "Str255 arg must be string of at most 255 chars");
666 return 0;
667 }
668 pbuf[0] = len;
669 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
670 return 1;
671}
672
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000673/* Convert a Str255 to a Python string object */
674PyObject *
675PyMac_BuildStr255(Str255 s)
676{
677 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
678}
679
680
Jack Jansen5f653091995-01-18 13:53:49 +0000681/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000682** Convert a Python object to an FSSpec.
683** The object may either be a full pathname or a triple
684** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000685** NOTE: This routine will fail on pre-sys7 machines.
686** The caller is responsible for not calling this routine
687** in those cases (which is fine, since everyone calling
688** this is probably sys7 dependent anyway).
689*/
690int
Guido van Rossum8f691791995-01-18 23:57:26 +0000691PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000692{
693 Str255 path;
694 short refnum;
695 long parid;
696 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000697 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000698
Jack Jansene8e8ae01995-01-26 16:36:45 +0000699 /* first check whether it already is an FSSpec */
700 fs2 = mfs_GetFSSpecFSSpec(v);
701 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000702 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000703 return 1;
704 }
Jack Jansen5f653091995-01-18 13:53:49 +0000705 if ( PyString_Check(v) ) {
706 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000707 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000708 return 0;
709 refnum = 0; /* XXXX Should get CurWD here... */
710 parid = 0;
711 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000712 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
713 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000714 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000715 }
Jack Jansen5f653091995-01-18 13:53:49 +0000716 }
717 err = FSMakeFSSpec(refnum, parid, path, fs);
718 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000719 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000720 return 0;
721 }
722 return 1;
723}
724
Guido van Rossum8f691791995-01-18 23:57:26 +0000725
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000726
727/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000728 The object must be a (left, top, right, bottom) tuple.
729 (This differs from the order in the struct but is consistent with
730 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000731int
732PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000733{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000734 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000735}
Guido van Rossumb3404661995-01-22 18:36:13 +0000736
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000737/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000738PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000739PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000740{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000741 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000742}
743
744
745/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000746 The object must be a (h, v) tuple.
747 (This differs from the order in the struct but is consistent with
748 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000749int
750PyMac_GetPoint(PyObject *v, Point *p)
751{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000752 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000753}
754
755/* Convert a Point to a Python object */
756PyObject *
757PyMac_BuildPoint(Point p)
758{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000759 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000760}
761
762
763/* Convert a Python object to an EventRecord.
764 The object must be a (what, message, when, (v, h), modifiers) tuple. */
765int
766PyMac_GetEventRecord(PyObject *v, EventRecord *e)
767{
768 return PyArg_Parse(v, "(hll(hh)h)",
769 &e->what,
770 &e->message,
771 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000772 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000773 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000774 &e->modifiers);
775}
776
777/* Convert a Rect to an EventRecord object */
778PyObject *
779PyMac_BuildEventRecord(EventRecord *e)
780{
781 return Py_BuildValue("(hll(hh)h)",
782 e->what,
783 e->message,
784 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000785 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000786 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000787 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000788}
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000789
790
Jack Jansen76efd8e1995-02-24 22:53:16 +0000791#ifdef USE_MAC_APPLET_SUPPORT
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000792/* Applet support */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000793
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000794/* Run a compiled Python Python script from 'PYC ' resource __main__ */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000795static int
796run_main_resource()
797{
798 Handle h;
799 long size;
800 PyObject *code;
801 PyObject *result;
802
803 h = GetNamedResource('PYC ', "\p__main__");
804 if (h == NULL) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000805 Alert(NOPYC_ALERT, NULL);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000806 return 1;
807 }
808 size = GetResourceSizeOnDisk(h);
809 HLock(h);
810 code = PyMarshal_ReadObjectFromString(*h + 8, (int)(size - 8));
811 HUnlock(h);
812 ReleaseResource(h);
813 if (code == NULL) {
814 PyErr_Print();
815 return 1;
816 }
817 result = PyImport_ExecCodeModule("__main__", code);
818 Py_DECREF(code);
819 if (result == NULL) {
820 PyErr_Print();
821 return 1;
822 }
823 Py_DECREF(result);
824 return 0;
825}
826
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000827/* Initialization sequence for applets */
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000828void
829PyMac_InitApplet()
830{
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000831 int argc;
832 char **argv;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000833 int err;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000834
Jack Jansen3ec804a1995-02-20 15:56:10 +0000835 PyMac_AddLibResources();
Jack Jansen3ec804a1995-02-20 15:56:10 +0000836#ifdef __MWERKS__
837 SIOUXSettings.asktosaveonclose = 0;
838 SIOUXSettings.showstatusline = 0;
839 SIOUXSettings.tabspaces = 4;
840#endif
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000841 argc = PyMac_GetArgv(&argv);
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000842 Py_Initialize();
Guido van Rossum8c89a6f1995-02-19 15:52:17 +0000843 PySys_SetArgv(argc, argv);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000844 err = run_main_resource();
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000845 fflush(stderr);
846 fflush(stdout);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000847#ifdef __MWERKS__
848 if (!err)
849 SIOUXSettings.autocloseonquit = 1;
850 else
851 SIOUXSettings.showstatusline = 1;
852#endif
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000853 /* XXX Should we bother to Py_Exit(sts)? */
854}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000855
Jack Jansen76efd8e1995-02-24 22:53:16 +0000856#endif /* USE_MAC_APPLET_SUPPORT */
857
858/* For normal application */
859void
860PyMac_InitApplication()
861{
862 int argc;
863 char **argv;
864
865#ifdef USE_MAC_SHARED_LIBRARY
866 PyMac_AddLibResources();
867#endif
868#ifdef __MWERKS__
869 SIOUXSettings.asktosaveonclose = 0;
870 SIOUXSettings.showstatusline = 0;
871 SIOUXSettings.tabspaces = 4;
872#endif
873 argc = PyMac_GetArgv(&argv);
874 if ( argc > 1 ) {
875 /* We're running a script. Attempt to change current directory */
876 char curwd[256], *endp;
877
878 strcpy(curwd, argv[1]);
879 endp = strrchr(curwd, ':');
880 if ( endp && endp > curwd ) {
881 *endp = '\0';
882 chdir(curwd);
883 }
884 }
885 Py_Main(argc, argv);
886}
Guido van Rossume7134aa1995-02-26 10:20:53 +0000887