blob: 00d6d2c5aedba2e1c3564b7c1acc46a0472e3410 [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
Jack Jansenbf05d4c1996-08-19 15:11:45 +000025#ifdef __CFM68K__
26/* cfm68k InterfaceLib exports GetEventQueue, but Events.h doesn't know this
27** and defines it as GetEvQHdr (which is correct for PPC). This fix is for
28** CW9, check that the workaround is still needed for the next release.
29*/
30#define GetEvQHdr GetEventQueue
31#endif /* __CFM68K__ */
32
33#include <Events.h>
34
35#ifdef __CFM68K__
36#undef GetEventQueue
37#endif /* __CFM68K__ */
38
Jack Jansenf93c72a1994-12-14 14:07:50 +000039#include "Python.h"
Guido van Rossumbecdbec1995-02-14 01:27:24 +000040
Jack Jansenf93c72a1994-12-14 14:07:50 +000041#include "macglue.h"
Jack Jansen74162f31995-02-15 22:58:33 +000042#include "marshal.h"
43#include "import.h"
Jack Jansenf93c72a1994-12-14 14:07:50 +000044
Jack Jansen819f1771995-08-14 12:35:10 +000045#include "pythonresources.h"
46
Jack Jansenf93c72a1994-12-14 14:07:50 +000047#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000048#include <Files.h>
Jack Jansen8cd2b721995-02-13 11:33:28 +000049#include <StandardFile.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000050#include <Resources.h>
51#include <Memory.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000052#include <Windows.h>
53#include <Desk.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000054#include <Traps.h>
Jack Jansenee23d6e1995-01-27 14:43:25 +000055#include <Processes.h>
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000056#include <Fonts.h>
57#include <Menus.h>
Jack Jansen08305501995-06-18 20:03:40 +000058#include <TextUtils.h>
Guido van Rossumcc0d8791995-01-30 08:57:13 +000059#ifdef THINK_C
60#include <OSEvents.h> /* For EvQElPtr */
61#endif
Jack Jansen16df2aa1995-02-27 16:17:28 +000062#ifdef __MWERKS__
63#include <SIOUX.h>
64#endif
Jack Jansen911ad6b1996-03-05 16:56:24 +000065#ifdef USE_GUSI
66#include <TFileSpec.h> /* For Path2FSSpec */
Jack Jansen378815c1996-03-06 16:21:34 +000067#include <LowMem.h> /* For SetSFCurDir, etc */
Jack Jansenf6865f71996-09-04 15:24:59 +000068#include <GUSI.h>
Jack Jansen911ad6b1996-03-05 16:56:24 +000069#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000070
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000071#ifndef HAVE_UNIVERSAL_HEADERS
72#define GetResourceSizeOnDisk(x) SizeResource(x)
Guido van Rossum24a45e31995-02-20 23:45:53 +000073typedef DlgHookYDProcPtr DlgHookYDUPP;
74#define NewDlgHookYDProc(userRoutine) ((DlgHookYDUPP) (userRoutine))
75typedef FileFilterYDProcPtr FileFilterYDUPP;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000076#endif
77
Jack Jansenee23d6e1995-01-27 14:43:25 +000078#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000079#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000080
Jack Jansenee23d6e1995-01-27 14:43:25 +000081/*
Jack Jansend1f06311996-08-01 15:23:54 +000082** When less than this amount of stackspace is left we
83** raise a MemoryError.
84*/
85#ifndef MINIMUM_STACK_SIZE
86#ifdef __powerc
87#define MINIMUM_STACK_SIZE 8192
88#else
89#define MINIMUM_STACK_SIZE 4096
90#endif
91#endif
92
93/*
Jack Jansen16df2aa1995-02-27 16:17:28 +000094** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +000095** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +000096** handle them). Note that we don't know who has windows open, so
97** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +000098*/
99#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000100
101#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +0000102
Guido van Rossumb3404661995-01-22 18:36:13 +0000103/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +0000104** with the python errors.h. */
105#define fnfErr -43
106
Jack Jansene8e8ae01995-01-26 16:36:45 +0000107/* Declared in macfsmodule.c: */
108extern FSSpec *mfs_GetFSSpecFSSpec();
109
Jack Jansenee23d6e1995-01-27 14:43:25 +0000110/* Interrupt code variables: */
111static int interrupted; /* Set to true when cmd-. seen */
112static RETSIGTYPE intcatcher Py_PROTO((int));
113
Jack Jansenf6865f71996-09-04 15:24:59 +0000114static void PyMac_DoYield Py_PROTO((int));
115
Jack Jansene8e8ae01995-01-26 16:36:45 +0000116/*
117** We attempt to be a good citizen by giving up the CPU periodically.
118** When in the foreground we do this less often and for shorter periods
119** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +0000120** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +0000121** The counts here are in ticks of 1/60th second.
122** XXXX The initial values here are not based on anything.
123** FG-python gives up the cpu for 1/60th 5 times per second,
124** BG-python for .2 second 10 times per second.
125*/
126static long interval_fg = 12;
127static long interval_bg = 6;
128static long yield_fg = 1;
129static long yield_bg = 12;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000130static long lastyield;
131static int in_foreground;
132
Guido van Rossume7134aa1995-02-26 10:20:53 +0000133/*
134** When > 0, do full scanning for events (program is not event aware)
135** when == 0, only scan for Command-period
136** when < 0, don't do any event scanning
137*/
138int PyMac_DoYieldEnabled = 1;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000139
Jack Jansen819f1771995-08-14 12:35:10 +0000140/*
Jack Jansenf6865f71996-09-04 15:24:59 +0000141** Workaround for sioux/gusi combo: set when we are exiting
142*/
143int PyMac_ConsoleIsDead;
144
145/*
Jack Jansen819f1771995-08-14 12:35:10 +0000146** Some stuff for our GetDirectory and PromptGetFile routines
147*/
148struct hook_args {
149 int selectcur_hit; /* Set to true when "select current" selected */
150 char *prompt; /* The prompt */
151};
152static DlgHookYDUPP myhook_upp;
153static int upp_inited = 0;
154
Jack Jansen378815c1996-03-06 16:21:34 +0000155#ifdef USE_GUSI
156/*
157** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
158** the working directory. Hence, we call this routine after each call
159** to chdir() to rectify things.
160*/
161void
162PyMac_FixGUSIcd()
163{
164 WDPBRec pb;
165 FSSpec curdirfss;
166
167 if ( Path2FSSpec(":x", &curdirfss) != noErr )
168 return;
169
170 /* Set MacOS "working directory" */
171 pb.ioNamePtr= "\p";
172 pb.ioVRefNum= curdirfss.vRefNum;
173 pb.ioWDDirID= curdirfss.parID;
174 if (PBHSetVol(&pb, 0) != noErr)
175 return;
Jack Jansen378815c1996-03-06 16:21:34 +0000176}
Jack Jansen7ac70af1996-08-19 11:01:05 +0000177
178#ifdef __CFM68K__
Jack Jansencfadbd41996-08-19 11:36:25 +0000179void SpinCursor(short x) { /* Dummy */ }
180#endif /* __CFM68K */
181
Jack Jansenf6865f71996-09-04 15:24:59 +0000182/*
183** Replacement GUSI Spin function
184*/
185static int
186PyMac_GUSISpin(spin_msg msg, long arg)
187{
188 static Boolean inForeground = true;
Jack Jansenf6865f71996-09-04 15:24:59 +0000189 int maysleep;
190
191 if (PyMac_ConsoleIsDead) return 0;
192#if 0
193 if (inForeground)
194 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
195#endif
196
197 if (interrupted) return -1;
198
199 if ( msg == SP_AUTO_SPIN || ((msg==SP_SLEEP||msg==SP_SELECT) && arg <= yield_fg))
200 maysleep = 0;
201 else
202 maysleep = 0;
203
204 PyMac_DoYield(maysleep);
205
206 return 0;
207}
208
209void
210PyMac_SetGUSISpin() {
211 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
212}
213
Jack Jansen378815c1996-03-06 16:21:34 +0000214#endif
215
Jack Jansen819f1771995-08-14 12:35:10 +0000216
Jack Jansen5f653091995-01-18 13:53:49 +0000217/* Convert C to Pascal string. Returns pointer to static buffer. */
218unsigned char *
219Pstring(char *str)
220{
221 static Str255 buf;
222 int len;
223
224 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000225 if (len > 255)
226 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000227 buf[0] = (unsigned char)len;
228 strncpy((char *)buf+1, str, len);
229 return buf;
230}
231
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000232/* Like strerror() but for Mac OS error numbers */
233char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000234{
235 static char buf[256];
236 Handle h;
237 char *str;
238
239 h = GetResource('Estr', err);
240 if ( h ) {
241 HLock(h);
242 str = (char *)*h;
243 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000244 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000245 HUnlock(h);
246 ReleaseResource(h);
247 } else {
248 sprintf(buf, "Mac OS error code %d", err);
249 }
250 return buf;
251}
252
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000253/* Exception object shared by all Mac specific modules for Mac OS errors */
254PyObject *PyMac_OSErrException;
255
256/* Initialize and return PyMac_OSErrException */
257PyObject *
258PyMac_GetOSErrException()
259{
260 if (PyMac_OSErrException == NULL)
261 PyMac_OSErrException = PyString_FromString("Mac OS Error");
262 return PyMac_OSErrException;
263}
264
Jack Jansenf93c72a1994-12-14 14:07:50 +0000265/* Set a MAC-specific error from errno, and return NULL; return None if no error */
266PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000267PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000268{
269 char *msg;
270 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000271
Guido van Rossum8f691791995-01-18 23:57:26 +0000272 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000273 Py_INCREF(Py_None);
274 return Py_None;
275 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000276 if (err == -1 && PyErr_Occurred())
277 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000278 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000279 v = Py_BuildValue("(is)", err, msg);
280 PyErr_SetObject(eobj, v);
281 Py_DECREF(v);
282 return NULL;
283}
284
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000285/* Call PyErr_Mac with PyMac_OSErrException */
286PyObject *
287PyMac_Error(OSErr err)
288{
289 return PyErr_Mac(PyMac_GetOSErrException(), err);
290}
291
Jack Jansen1ed95291996-07-22 15:25:10 +0000292#ifdef USE_STACKCHECK
293/* Check for stack overflow */
294int
295PyOS_CheckStack()
296{
297 long left;
298
299 left = StackSpace();
Jack Jansend1f06311996-08-01 15:23:54 +0000300 if ( left < MINIMUM_STACK_SIZE )
Jack Jansen1ed95291996-07-22 15:25:10 +0000301 return -1;
302 return 0;
303}
304#endif /* USE_STACKCHECK */
305
Jack Jansenee23d6e1995-01-27 14:43:25 +0000306/* The catcher routine (which may not be used for all compilers) */
307static RETSIGTYPE
308intcatcher(sig)
309 int sig;
310{
311 interrupted = 1;
312 signal(SIGINT, intcatcher);
313}
314
315void
316PyOS_InitInterrupts()
317{
318 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
319 signal(SIGINT, intcatcher);
320}
321
322/*
323** This routine scans the event queue looking for cmd-.
324** This is the only way to get an interrupt under THINK (since it
325** doesn't do SIGINT handling), but is also used under MW, when
326** the full-fledged event loop is disabled. This way, we can at least
327** interrupt a runaway python program.
328*/
329static void
330scan_event_queue(flush)
331 int flush;
332{
333 register EvQElPtr q;
334
Jack Jansencfadbd41996-08-19 11:36:25 +0000335 q = (EvQElPtr) GetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000336
337 for (; q; q = (EvQElPtr)q->qLink) {
338 if (q->evtQWhat == keyDown &&
339 (char)q->evtQMessage == '.' &&
340 (q->evtQModifiers & cmdKey) != 0) {
341 if ( flush )
342 FlushEvents(keyDownMask, 0);
343 interrupted = 1;
344 break;
345 }
346 }
347}
348
349int
350PyOS_InterruptOccurred()
351{
Guido van Rossume7134aa1995-02-26 10:20:53 +0000352 if (PyMac_DoYieldEnabled < 0)
353 return 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000354#ifdef THINK_C
355 scan_event_queue(1);
356#endif
357 PyMac_Yield();
358 if (interrupted) {
359 interrupted = 0;
360 return 1;
361 }
362 return 0;
363}
364
365/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
366** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
367** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
368** thereafter.
369*/
370static int
371intrpeek()
372{
373#ifdef THINK_C
374 scan_event_queue(0);
375#endif
376 return interrupted;
377}
378
379/* Check whether we are in the foreground */
380int
381PyMac_InForeground()
382{
383 static ProcessSerialNumber ours;
384 static inited;
385 ProcessSerialNumber curfg;
386 Boolean eq;
387
388 if ( inited == 0 )
389 (void)GetCurrentProcess(&ours);
390 inited = 1;
391 if ( GetFrontProcess(&curfg) < 0 )
392 eq = 1;
393 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
394 eq = 1;
395 return (int)eq;
396
397}
398
Jack Jansenf93c72a1994-12-14 14:07:50 +0000399/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000400** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000401*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000402void
403PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
404{
405 interval_fg = fgi;
406 yield_fg = fgy;
407 interval_bg = bgi;
408 yield_bg = bgy;
409}
410
411/*
Jack Jansena76382a1995-02-02 14:25:56 +0000412** Handle an event, either one found in the mainloop eventhandler or
413** one passed back from the python program.
414*/
415void
416PyMac_HandleEvent(evp)
417 EventRecord *evp;
418{
Jack Jansena76382a1995-02-02 14:25:56 +0000419
420#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000421 {
422 int siouxdidit;
423
424 /* If SIOUX wants it we're done */
425 siouxdidit = SIOUXHandleOneEvent(evp);
426 if ( siouxdidit )
427 return;
428 }
Jack Jansena76382a1995-02-02 14:25:56 +0000429#else
430 /* Other compilers are just unlucky: we only weed out clicks in other applications */
431 if ( evp->what == mouseDown ) {
Jack Jansen847e89e1995-08-31 13:57:40 +0000432 WindowPtr wp;
433
Jack Jansen38e97661995-11-10 14:53:00 +0000434 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
Jack Jansena76382a1995-02-02 14:25:56 +0000435 SystemClick(evp, wp);
Jack Jansen38e97661995-11-10 14:53:00 +0000436 return;
437 }
Jack Jansena76382a1995-02-02 14:25:56 +0000438 }
439#endif /* !__MWERKS__ */
440}
441
442/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000443** Yield the CPU to other tasks.
444*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000445static void
Jack Jansenf6865f71996-09-04 15:24:59 +0000446PyMac_DoYield(int maysleep)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000447{
448 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000449 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000450 static int no_waitnextevent = -1;
451 int gotone;
452
453 if ( no_waitnextevent < 0 ) {
454 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
455 NGetTrapAddress(_Unimplemented, ToolTrap));
456 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000457
Jack Jansenf6865f71996-09-04 15:24:59 +0000458 lastyield = TickCount();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000459#ifndef THINK_C
Jack Jansenf6865f71996-09-04 15:24:59 +0000460 /* Under think this has been done before in intrcheck() or intrpeek() */
461 if (PyMac_DoYieldEnabled >= 0)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000462 scan_event_queue(0);
463#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000464 if (PyMac_DoYieldEnabled == 0)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000465 return;
466
Jack Jansenee23d6e1995-01-27 14:43:25 +0000467 in_foreground = PyMac_InForeground();
Jack Jansenf6865f71996-09-04 15:24:59 +0000468 if ( maysleep ) {
469 if ( in_foreground )
470 yield = yield_fg;
471 else
472 yield = yield_bg;
473 } else {
474 yield = 0;
475 }
476
Jack Jansene8e8ae01995-01-26 16:36:45 +0000477 while ( 1 ) {
478 if ( no_waitnextevent ) {
479 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000480 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000481 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000482 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000483 }
484 /* Get out quickly if nothing interesting is happening */
485 if ( !gotone || ev.what == nullEvent )
486 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000487 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000488 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000489}
490
491/*
492** Yield the CPU to other tasks if opportune
493*/
494void
495PyMac_Yield() {
496 long iv;
497
Jack Jansenee23d6e1995-01-27 14:43:25 +0000498 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000499 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000500 else
501 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000502 if ( TickCount() > lastyield + iv )
Jack Jansenf6865f71996-09-04 15:24:59 +0000503 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000504}
505
Jack Jansenf6865f71996-09-04 15:24:59 +0000506#ifdef USE_MACTCP
Jack Jansene8e8ae01995-01-26 16:36:45 +0000507/*
508** Idle routine for busy-wait loops.
509** Gives up CPU, handles events and returns true if an interrupt is pending
510** (but not actually handled yet).
511*/
512int
513PyMac_Idle()
514{
Jack Jansenf6865f71996-09-04 15:24:59 +0000515 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000516 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000517}
Jack Jansenf6865f71996-09-04 15:24:59 +0000518#endif
519
Jack Jansen74162f31995-02-15 22:58:33 +0000520/*
521** Returns true if the argument has a resource fork, and it contains
522** a 'PYC ' resource of the correct name
523*/
524int
525PyMac_FindResourceModule(module, filename)
526char *module;
527char *filename;
528{
529 FSSpec fss;
530 FInfo finfo;
531 short oldrh, filerh;
532 int ok;
533 Handle h;
534
535 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
536 return 0; /* It doesn't exist */
537 if ( FSpGetFInfo(&fss, &finfo) != noErr )
538 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000539 oldrh = CurResFile();
540 filerh = FSpOpenResFile(&fss, fsRdPerm);
541 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000542 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000543 UseResFile(filerh);
544 SetResLoad(0);
545 h = Get1NamedResource('PYC ', Pstring(module));
546 SetResLoad(1);
547 ok = (h != NULL);
548 CloseResFile(filerh);
549 UseResFile(oldrh);
550 return ok;
551}
552
553/*
554** Load the specified module from a resource
555*/
556PyObject *
557PyMac_LoadResourceModule(module, filename)
558char *module;
559char *filename;
560{
561 FSSpec fss;
562 FInfo finfo;
563 short oldrh, filerh;
Jack Jansen74162f31995-02-15 22:58:33 +0000564 Handle h;
565 OSErr err;
566 PyObject *m, *co;
567 long num, size;
568
569 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
570 goto error;
571 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
572 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000573 oldrh = CurResFile();
574 filerh = FSpOpenResFile(&fss, fsRdPerm);
575 if ( filerh == -1 ) {
576 err = ResError();
577 goto error;
578 }
579 UseResFile(filerh);
580 h = Get1NamedResource('PYC ', Pstring(module));
581 if ( h == NULL ) {
582 err = ResError();
583 goto error;
584 }
585 HLock(h);
586 /*
587 ** XXXX The next few lines are intimately tied to the format of pyc
588 ** files. I'm not sure whether this code should be here or in import.c -- Jack
589 */
590 size = GetHandleSize(h);
591 if ( size < 8 ) {
592 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000593 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000594 } else {
595 num = (*h)[0] & 0xff;
596 num = num | (((*h)[1] & 0xff) << 8);
597 num = num | (((*h)[2] & 0xff) << 16);
598 num = num | (((*h)[3] & 0xff) << 24);
599 if ( num != PyImport_GetMagicNumber() ) {
600 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
601 co = NULL;
602 } else {
603 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
604 }
605 }
606 HUnlock(h);
607 CloseResFile(filerh);
608 UseResFile(oldrh);
609 if ( co ) {
610 m = PyImport_ExecCodeModule(module, co);
611 Py_DECREF(co);
612 } else {
613 m = NULL;
614 }
615 return m;
616error:
617 {
618 char buf[512];
619
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000620 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000621 PyErr_SetString(PyExc_ImportError, buf);
622 return NULL;
623 }
624}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000625
Jack Jansen3ec804a1995-02-20 15:56:10 +0000626/*
627** Helper routine for GetDirectory
628*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000629static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000630myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000631{
Jack Jansen819f1771995-08-14 12:35:10 +0000632 if ( item == sfHookFirstCall && dataptr->prompt) {
633 Handle prompth;
634 short type;
635 Rect rect;
636
637 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
638 if ( prompth )
639 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
640 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000641 if ( item == SELECTCUR_ITEM ) {
642 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000643 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000644 }
645 return item;
646}
647
648/*
649** Ask the user for a directory. I still can't understand
650** why Apple doesn't provide a standard solution for this...
651*/
652int
Jack Jansen819f1771995-08-14 12:35:10 +0000653PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000654 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000655 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000656{
657 static SFTypeList list = {'fldr', 0, 0, 0};
658 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000659 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000660 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000661
662 if ( !upp_inited ) {
663 myhook_upp = NewDlgHookYDProc(myhook_proc);
664 upp_inited = 1;
665 }
Jack Jansen819f1771995-08-14 12:35:10 +0000666 if ( prompt && *prompt )
667 hook_args.prompt = (char *)Pstring(prompt);
668 else
669 hook_args.prompt = NULL;
670 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000671 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000672 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000673
674 reply.sfFile.name[0] = 0;
675 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
676 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000677 return hook_args.selectcur_hit;
678}
679
680/*
681** Slightly extended StandardGetFile: accepts a prompt */
682void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
683 StandardFileReply *reply, char *prompt)
684{
685 static Point where = {-1, -1};
686 struct hook_args hook_args;
687
688 if ( !upp_inited ) {
689 myhook_upp = NewDlgHookYDProc(myhook_proc);
690 upp_inited = 1;
691 }
692 if ( prompt && *prompt )
693 hook_args.prompt = (char *)Pstring(prompt);
694 else
695 hook_args.prompt = NULL;
696 hook_args.selectcur_hit = 0;
697 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
698 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000699}
Jack Jansen5f653091995-01-18 13:53:49 +0000700
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000701/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000702int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000703PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000704{
705 if (!PyString_Check(v) || PyString_Size(v) != 4) {
706 PyErr_SetString(PyExc_TypeError,
707 "OSType arg must be string of 4 chars");
708 return 0;
709 }
710 memcpy((char *)pr, PyString_AsString(v), 4);
711 return 1;
712}
713
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000714/* Convert an OSType value to a 4-char string object */
715PyObject *
716PyMac_BuildOSType(OSType t)
717{
718 return PyString_FromStringAndSize((char *)&t, 4);
719}
720
Jack Jansend1f06311996-08-01 15:23:54 +0000721/* Convert an NumVersion value to a 4-element tuple */
722PyObject *
723PyMac_BuildNumVersion(NumVersion t)
724{
725 return Py_BuildValue("(hhhh)", t.majorRev, t.minorAndBugRev, t.stage, t.nonRelRev);
726}
727
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000728
729/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000730int
Guido van Rossum8f691791995-01-18 23:57:26 +0000731PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000732{
733 int len;
734 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
735 PyErr_SetString(PyExc_TypeError,
736 "Str255 arg must be string of at most 255 chars");
737 return 0;
738 }
739 pbuf[0] = len;
740 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
741 return 1;
742}
743
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000744/* Convert a Str255 to a Python string object */
745PyObject *
746PyMac_BuildStr255(Str255 s)
747{
748 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
749}
750
751
Jack Jansen5f653091995-01-18 13:53:49 +0000752/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000753** Convert a Python object to an FSSpec.
754** The object may either be a full pathname or a triple
755** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000756** NOTE: This routine will fail on pre-sys7 machines.
757** The caller is responsible for not calling this routine
758** in those cases (which is fine, since everyone calling
759** this is probably sys7 dependent anyway).
760*/
761int
Guido van Rossum8f691791995-01-18 23:57:26 +0000762PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000763{
764 Str255 path;
765 short refnum;
766 long parid;
767 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000768 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000769
Jack Jansene8e8ae01995-01-26 16:36:45 +0000770 /* first check whether it already is an FSSpec */
771 fs2 = mfs_GetFSSpecFSSpec(v);
772 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000773 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000774 return 1;
775 }
Jack Jansen5f653091995-01-18 13:53:49 +0000776 if ( PyString_Check(v) ) {
777 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000778 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000779 return 0;
Jack Jansen378815c1996-03-06 16:21:34 +0000780 refnum = 0; /* XXXX Should get CurWD here?? */
Jack Jansen5f653091995-01-18 13:53:49 +0000781 parid = 0;
782 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000783 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
784 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000785 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000786 }
Jack Jansen5f653091995-01-18 13:53:49 +0000787 }
788 err = FSMakeFSSpec(refnum, parid, path, fs);
789 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000790 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000791 return 0;
792 }
793 return 1;
794}
795
Guido van Rossum8f691791995-01-18 23:57:26 +0000796
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000797/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000798 The object must be a (left, top, right, bottom) tuple.
799 (This differs from the order in the struct but is consistent with
800 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000801int
802PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000803{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000804 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000805}
Guido van Rossumb3404661995-01-22 18:36:13 +0000806
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000807/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000808PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000809PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000810{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000811 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000812}
813
814
815/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000816 The object must be a (h, v) tuple.
817 (This differs from the order in the struct but is consistent with
818 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000819int
820PyMac_GetPoint(PyObject *v, Point *p)
821{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000822 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000823}
824
825/* Convert a Point to a Python object */
826PyObject *
827PyMac_BuildPoint(Point p)
828{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000829 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000830}
831
832
833/* Convert a Python object to an EventRecord.
834 The object must be a (what, message, when, (v, h), modifiers) tuple. */
835int
836PyMac_GetEventRecord(PyObject *v, EventRecord *e)
837{
838 return PyArg_Parse(v, "(hll(hh)h)",
839 &e->what,
840 &e->message,
841 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000842 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000843 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000844 &e->modifiers);
845}
846
847/* Convert a Rect to an EventRecord object */
848PyObject *
849PyMac_BuildEventRecord(EventRecord *e)
850{
851 return Py_BuildValue("(hll(hh)h)",
852 e->what,
853 e->message,
854 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000855 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000856 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000857 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000858}
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000859
860/* Convert Python object to Fixed */
861int
862PyMac_GetFixed(PyObject *v, Fixed *f)
863{
864 double d;
865
866 if( !PyArg_Parse(v, "d", &d))
867 return 0;
868 *f = (Fixed)(d * 0x10000);
Jack Jansen31dd5c01996-05-31 13:01:39 +0000869 return 1;
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000870}
871
872/* Convert a Point to a Python object */
873PyObject *
874PyMac_BuildFixed(Fixed f)
875{
876 double d;
877
878 d = f;
879 d = d / 0x10000;
880 return Py_BuildValue("d", d);
881}
882