blob: 18243ec6875088783e5aa8773309437ca0676472 [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;
189 WindowPtr win;
190 EventRecord ev;
191 int maysleep;
192
193 if (PyMac_ConsoleIsDead) return 0;
194#if 0
195 if (inForeground)
196 SpinCursor(msg == SP_AUTO_SPIN ? short(arg) : 1);
197#endif
198
199 if (interrupted) return -1;
200
201 if ( msg == SP_AUTO_SPIN || ((msg==SP_SLEEP||msg==SP_SELECT) && arg <= yield_fg))
202 maysleep = 0;
203 else
204 maysleep = 0;
205
206 PyMac_DoYield(maysleep);
207
208 return 0;
209}
210
211void
212PyMac_SetGUSISpin() {
213 GUSISetHook(GUSI_SpinHook, (GUSIHook)PyMac_GUSISpin);
214}
215
Jack Jansen378815c1996-03-06 16:21:34 +0000216#endif
217
Jack Jansen819f1771995-08-14 12:35:10 +0000218
Jack Jansen5f653091995-01-18 13:53:49 +0000219/* Convert C to Pascal string. Returns pointer to static buffer. */
220unsigned char *
221Pstring(char *str)
222{
223 static Str255 buf;
224 int len;
225
226 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000227 if (len > 255)
228 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000229 buf[0] = (unsigned char)len;
230 strncpy((char *)buf+1, str, len);
231 return buf;
232}
233
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000234/* Like strerror() but for Mac OS error numbers */
235char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000236{
237 static char buf[256];
238 Handle h;
239 char *str;
240
241 h = GetResource('Estr', err);
242 if ( h ) {
243 HLock(h);
244 str = (char *)*h;
245 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000246 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000247 HUnlock(h);
248 ReleaseResource(h);
249 } else {
250 sprintf(buf, "Mac OS error code %d", err);
251 }
252 return buf;
253}
254
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000255/* Exception object shared by all Mac specific modules for Mac OS errors */
256PyObject *PyMac_OSErrException;
257
258/* Initialize and return PyMac_OSErrException */
259PyObject *
260PyMac_GetOSErrException()
261{
262 if (PyMac_OSErrException == NULL)
263 PyMac_OSErrException = PyString_FromString("Mac OS Error");
264 return PyMac_OSErrException;
265}
266
Jack Jansenf93c72a1994-12-14 14:07:50 +0000267/* Set a MAC-specific error from errno, and return NULL; return None if no error */
268PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000269PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000270{
271 char *msg;
272 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000273
Guido van Rossum8f691791995-01-18 23:57:26 +0000274 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000275 Py_INCREF(Py_None);
276 return Py_None;
277 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000278 if (err == -1 && PyErr_Occurred())
279 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000280 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000281 v = Py_BuildValue("(is)", err, msg);
282 PyErr_SetObject(eobj, v);
283 Py_DECREF(v);
284 return NULL;
285}
286
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000287/* Call PyErr_Mac with PyMac_OSErrException */
288PyObject *
289PyMac_Error(OSErr err)
290{
291 return PyErr_Mac(PyMac_GetOSErrException(), err);
292}
293
Jack Jansen1ed95291996-07-22 15:25:10 +0000294#ifdef USE_STACKCHECK
295/* Check for stack overflow */
296int
297PyOS_CheckStack()
298{
299 long left;
300
301 left = StackSpace();
Jack Jansend1f06311996-08-01 15:23:54 +0000302 if ( left < MINIMUM_STACK_SIZE )
Jack Jansen1ed95291996-07-22 15:25:10 +0000303 return -1;
304 return 0;
305}
306#endif /* USE_STACKCHECK */
307
Jack Jansenee23d6e1995-01-27 14:43:25 +0000308/* The catcher routine (which may not be used for all compilers) */
309static RETSIGTYPE
310intcatcher(sig)
311 int sig;
312{
313 interrupted = 1;
314 signal(SIGINT, intcatcher);
315}
316
317void
318PyOS_InitInterrupts()
319{
320 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
321 signal(SIGINT, intcatcher);
322}
323
324/*
325** This routine scans the event queue looking for cmd-.
326** This is the only way to get an interrupt under THINK (since it
327** doesn't do SIGINT handling), but is also used under MW, when
328** the full-fledged event loop is disabled. This way, we can at least
329** interrupt a runaway python program.
330*/
331static void
332scan_event_queue(flush)
333 int flush;
334{
335 register EvQElPtr q;
336
Jack Jansencfadbd41996-08-19 11:36:25 +0000337 q = (EvQElPtr) GetEventQueue()->qHead;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000338
339 for (; q; q = (EvQElPtr)q->qLink) {
340 if (q->evtQWhat == keyDown &&
341 (char)q->evtQMessage == '.' &&
342 (q->evtQModifiers & cmdKey) != 0) {
343 if ( flush )
344 FlushEvents(keyDownMask, 0);
345 interrupted = 1;
346 break;
347 }
348 }
349}
350
351int
352PyOS_InterruptOccurred()
353{
Guido van Rossume7134aa1995-02-26 10:20:53 +0000354 if (PyMac_DoYieldEnabled < 0)
355 return 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000356#ifdef THINK_C
357 scan_event_queue(1);
358#endif
359 PyMac_Yield();
360 if (interrupted) {
361 interrupted = 0;
362 return 1;
363 }
364 return 0;
365}
366
367/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
368** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
369** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
370** thereafter.
371*/
372static int
373intrpeek()
374{
375#ifdef THINK_C
376 scan_event_queue(0);
377#endif
378 return interrupted;
379}
380
381/* Check whether we are in the foreground */
382int
383PyMac_InForeground()
384{
385 static ProcessSerialNumber ours;
386 static inited;
387 ProcessSerialNumber curfg;
388 Boolean eq;
389
390 if ( inited == 0 )
391 (void)GetCurrentProcess(&ours);
392 inited = 1;
393 if ( GetFrontProcess(&curfg) < 0 )
394 eq = 1;
395 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
396 eq = 1;
397 return (int)eq;
398
399}
400
Jack Jansenf93c72a1994-12-14 14:07:50 +0000401/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000402** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000403*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000404void
405PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
406{
407 interval_fg = fgi;
408 yield_fg = fgy;
409 interval_bg = bgi;
410 yield_bg = bgy;
411}
412
413/*
Jack Jansena76382a1995-02-02 14:25:56 +0000414** Handle an event, either one found in the mainloop eventhandler or
415** one passed back from the python program.
416*/
417void
418PyMac_HandleEvent(evp)
419 EventRecord *evp;
420{
Jack Jansena76382a1995-02-02 14:25:56 +0000421
422#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000423 {
424 int siouxdidit;
425
426 /* If SIOUX wants it we're done */
427 siouxdidit = SIOUXHandleOneEvent(evp);
428 if ( siouxdidit )
429 return;
430 }
Jack Jansena76382a1995-02-02 14:25:56 +0000431#else
432 /* Other compilers are just unlucky: we only weed out clicks in other applications */
433 if ( evp->what == mouseDown ) {
Jack Jansen847e89e1995-08-31 13:57:40 +0000434 WindowPtr wp;
435
Jack Jansen38e97661995-11-10 14:53:00 +0000436 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
Jack Jansena76382a1995-02-02 14:25:56 +0000437 SystemClick(evp, wp);
Jack Jansen38e97661995-11-10 14:53:00 +0000438 return;
439 }
Jack Jansena76382a1995-02-02 14:25:56 +0000440 }
441#endif /* !__MWERKS__ */
442}
443
444/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000445** Yield the CPU to other tasks.
446*/
Jack Jansencfadbd41996-08-19 11:36:25 +0000447static void
Jack Jansenf6865f71996-09-04 15:24:59 +0000448PyMac_DoYield(int maysleep)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000449{
450 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000451 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000452 static int no_waitnextevent = -1;
453 int gotone;
454
455 if ( no_waitnextevent < 0 ) {
456 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
457 NGetTrapAddress(_Unimplemented, ToolTrap));
458 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000459
Jack Jansenf6865f71996-09-04 15:24:59 +0000460 lastyield = TickCount();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000461#ifndef THINK_C
Jack Jansenf6865f71996-09-04 15:24:59 +0000462 /* Under think this has been done before in intrcheck() or intrpeek() */
463 if (PyMac_DoYieldEnabled >= 0)
Jack Jansenee23d6e1995-01-27 14:43:25 +0000464 scan_event_queue(0);
465#endif
Jack Jansenf6865f71996-09-04 15:24:59 +0000466 if (PyMac_DoYieldEnabled == 0)
Jack Jansene8e8ae01995-01-26 16:36:45 +0000467 return;
468
Jack Jansenee23d6e1995-01-27 14:43:25 +0000469 in_foreground = PyMac_InForeground();
Jack Jansenf6865f71996-09-04 15:24:59 +0000470 if ( maysleep ) {
471 if ( in_foreground )
472 yield = yield_fg;
473 else
474 yield = yield_bg;
475 } else {
476 yield = 0;
477 }
478
Jack Jansene8e8ae01995-01-26 16:36:45 +0000479 while ( 1 ) {
480 if ( no_waitnextevent ) {
481 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000482 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000483 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000484 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000485 }
486 /* Get out quickly if nothing interesting is happening */
487 if ( !gotone || ev.what == nullEvent )
488 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000489 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000490 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000491}
492
493/*
494** Yield the CPU to other tasks if opportune
495*/
496void
497PyMac_Yield() {
498 long iv;
499
Jack Jansenee23d6e1995-01-27 14:43:25 +0000500 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000501 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000502 else
503 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000504 if ( TickCount() > lastyield + iv )
Jack Jansenf6865f71996-09-04 15:24:59 +0000505 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000506}
507
Jack Jansenf6865f71996-09-04 15:24:59 +0000508#ifdef USE_MACTCP
Jack Jansene8e8ae01995-01-26 16:36:45 +0000509/*
510** Idle routine for busy-wait loops.
511** Gives up CPU, handles events and returns true if an interrupt is pending
512** (but not actually handled yet).
513*/
514int
515PyMac_Idle()
516{
Jack Jansenf6865f71996-09-04 15:24:59 +0000517 PyMac_DoYield(1);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000518 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000519}
Jack Jansenf6865f71996-09-04 15:24:59 +0000520#endif
521
Jack Jansen74162f31995-02-15 22:58:33 +0000522/*
523** Returns true if the argument has a resource fork, and it contains
524** a 'PYC ' resource of the correct name
525*/
526int
527PyMac_FindResourceModule(module, filename)
528char *module;
529char *filename;
530{
531 FSSpec fss;
532 FInfo finfo;
533 short oldrh, filerh;
534 int ok;
535 Handle h;
536
537 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
538 return 0; /* It doesn't exist */
539 if ( FSpGetFInfo(&fss, &finfo) != noErr )
540 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000541 oldrh = CurResFile();
542 filerh = FSpOpenResFile(&fss, fsRdPerm);
543 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000544 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000545 UseResFile(filerh);
546 SetResLoad(0);
547 h = Get1NamedResource('PYC ', Pstring(module));
548 SetResLoad(1);
549 ok = (h != NULL);
550 CloseResFile(filerh);
551 UseResFile(oldrh);
552 return ok;
553}
554
555/*
556** Load the specified module from a resource
557*/
558PyObject *
559PyMac_LoadResourceModule(module, filename)
560char *module;
561char *filename;
562{
563 FSSpec fss;
564 FInfo finfo;
565 short oldrh, filerh;
Jack Jansen74162f31995-02-15 22:58:33 +0000566 Handle h;
567 OSErr err;
568 PyObject *m, *co;
569 long num, size;
570
571 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
572 goto error;
573 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
574 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000575 oldrh = CurResFile();
576 filerh = FSpOpenResFile(&fss, fsRdPerm);
577 if ( filerh == -1 ) {
578 err = ResError();
579 goto error;
580 }
581 UseResFile(filerh);
582 h = Get1NamedResource('PYC ', Pstring(module));
583 if ( h == NULL ) {
584 err = ResError();
585 goto error;
586 }
587 HLock(h);
588 /*
589 ** XXXX The next few lines are intimately tied to the format of pyc
590 ** files. I'm not sure whether this code should be here or in import.c -- Jack
591 */
592 size = GetHandleSize(h);
593 if ( size < 8 ) {
594 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000595 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000596 } else {
597 num = (*h)[0] & 0xff;
598 num = num | (((*h)[1] & 0xff) << 8);
599 num = num | (((*h)[2] & 0xff) << 16);
600 num = num | (((*h)[3] & 0xff) << 24);
601 if ( num != PyImport_GetMagicNumber() ) {
602 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
603 co = NULL;
604 } else {
605 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
606 }
607 }
608 HUnlock(h);
609 CloseResFile(filerh);
610 UseResFile(oldrh);
611 if ( co ) {
612 m = PyImport_ExecCodeModule(module, co);
613 Py_DECREF(co);
614 } else {
615 m = NULL;
616 }
617 return m;
618error:
619 {
620 char buf[512];
621
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000622 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000623 PyErr_SetString(PyExc_ImportError, buf);
624 return NULL;
625 }
626}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000627
Jack Jansen3ec804a1995-02-20 15:56:10 +0000628/*
629** Helper routine for GetDirectory
630*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000631static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000632myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000633{
Jack Jansen819f1771995-08-14 12:35:10 +0000634 if ( item == sfHookFirstCall && dataptr->prompt) {
635 Handle prompth;
636 short type;
637 Rect rect;
638
639 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
640 if ( prompth )
641 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
642 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000643 if ( item == SELECTCUR_ITEM ) {
644 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000645 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000646 }
647 return item;
648}
649
650/*
651** Ask the user for a directory. I still can't understand
652** why Apple doesn't provide a standard solution for this...
653*/
654int
Jack Jansen819f1771995-08-14 12:35:10 +0000655PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000656 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000657 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000658{
659 static SFTypeList list = {'fldr', 0, 0, 0};
660 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000661 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000662 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000663
664 if ( !upp_inited ) {
665 myhook_upp = NewDlgHookYDProc(myhook_proc);
666 upp_inited = 1;
667 }
Jack Jansen819f1771995-08-14 12:35:10 +0000668 if ( prompt && *prompt )
669 hook_args.prompt = (char *)Pstring(prompt);
670 else
671 hook_args.prompt = NULL;
672 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000673 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000674 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000675
676 reply.sfFile.name[0] = 0;
677 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
678 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000679 return hook_args.selectcur_hit;
680}
681
682/*
683** Slightly extended StandardGetFile: accepts a prompt */
684void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
685 StandardFileReply *reply, char *prompt)
686{
687 static Point where = {-1, -1};
688 struct hook_args hook_args;
689
690 if ( !upp_inited ) {
691 myhook_upp = NewDlgHookYDProc(myhook_proc);
692 upp_inited = 1;
693 }
694 if ( prompt && *prompt )
695 hook_args.prompt = (char *)Pstring(prompt);
696 else
697 hook_args.prompt = NULL;
698 hook_args.selectcur_hit = 0;
699 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
700 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000701}
Jack Jansen5f653091995-01-18 13:53:49 +0000702
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000703/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000704int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000705PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000706{
707 if (!PyString_Check(v) || PyString_Size(v) != 4) {
708 PyErr_SetString(PyExc_TypeError,
709 "OSType arg must be string of 4 chars");
710 return 0;
711 }
712 memcpy((char *)pr, PyString_AsString(v), 4);
713 return 1;
714}
715
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000716/* Convert an OSType value to a 4-char string object */
717PyObject *
718PyMac_BuildOSType(OSType t)
719{
720 return PyString_FromStringAndSize((char *)&t, 4);
721}
722
Jack Jansend1f06311996-08-01 15:23:54 +0000723/* Convert an NumVersion value to a 4-element tuple */
724PyObject *
725PyMac_BuildNumVersion(NumVersion t)
726{
727 return Py_BuildValue("(hhhh)", t.majorRev, t.minorAndBugRev, t.stage, t.nonRelRev);
728}
729
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000730
731/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000732int
Guido van Rossum8f691791995-01-18 23:57:26 +0000733PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000734{
735 int len;
736 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
737 PyErr_SetString(PyExc_TypeError,
738 "Str255 arg must be string of at most 255 chars");
739 return 0;
740 }
741 pbuf[0] = len;
742 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
743 return 1;
744}
745
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000746/* Convert a Str255 to a Python string object */
747PyObject *
748PyMac_BuildStr255(Str255 s)
749{
750 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
751}
752
753
Jack Jansen5f653091995-01-18 13:53:49 +0000754/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000755** Convert a Python object to an FSSpec.
756** The object may either be a full pathname or a triple
757** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000758** NOTE: This routine will fail on pre-sys7 machines.
759** The caller is responsible for not calling this routine
760** in those cases (which is fine, since everyone calling
761** this is probably sys7 dependent anyway).
762*/
763int
Guido van Rossum8f691791995-01-18 23:57:26 +0000764PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000765{
766 Str255 path;
767 short refnum;
768 long parid;
769 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000770 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000771
Jack Jansene8e8ae01995-01-26 16:36:45 +0000772 /* first check whether it already is an FSSpec */
773 fs2 = mfs_GetFSSpecFSSpec(v);
774 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000775 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000776 return 1;
777 }
Jack Jansen5f653091995-01-18 13:53:49 +0000778 if ( PyString_Check(v) ) {
779 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000780 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000781 return 0;
Jack Jansen378815c1996-03-06 16:21:34 +0000782 refnum = 0; /* XXXX Should get CurWD here?? */
Jack Jansen5f653091995-01-18 13:53:49 +0000783 parid = 0;
784 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000785 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
786 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000787 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000788 }
Jack Jansen5f653091995-01-18 13:53:49 +0000789 }
790 err = FSMakeFSSpec(refnum, parid, path, fs);
791 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000792 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000793 return 0;
794 }
795 return 1;
796}
797
Guido van Rossum8f691791995-01-18 23:57:26 +0000798
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000799/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000800 The object must be a (left, top, right, bottom) tuple.
801 (This differs from the order in the struct but is consistent with
802 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000803int
804PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000805{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000806 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000807}
Guido van Rossumb3404661995-01-22 18:36:13 +0000808
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000809/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000810PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000811PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000812{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000813 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000814}
815
816
817/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000818 The object must be a (h, v) tuple.
819 (This differs from the order in the struct but is consistent with
820 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000821int
822PyMac_GetPoint(PyObject *v, Point *p)
823{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000824 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000825}
826
827/* Convert a Point to a Python object */
828PyObject *
829PyMac_BuildPoint(Point p)
830{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000831 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000832}
833
834
835/* Convert a Python object to an EventRecord.
836 The object must be a (what, message, when, (v, h), modifiers) tuple. */
837int
838PyMac_GetEventRecord(PyObject *v, EventRecord *e)
839{
840 return PyArg_Parse(v, "(hll(hh)h)",
841 &e->what,
842 &e->message,
843 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000844 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000845 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000846 &e->modifiers);
847}
848
849/* Convert a Rect to an EventRecord object */
850PyObject *
851PyMac_BuildEventRecord(EventRecord *e)
852{
853 return Py_BuildValue("(hll(hh)h)",
854 e->what,
855 e->message,
856 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000857 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000858 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000859 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000860}
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000861
862/* Convert Python object to Fixed */
863int
864PyMac_GetFixed(PyObject *v, Fixed *f)
865{
866 double d;
867
868 if( !PyArg_Parse(v, "d", &d))
869 return 0;
870 *f = (Fixed)(d * 0x10000);
Jack Jansen31dd5c01996-05-31 13:01:39 +0000871 return 1;
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000872}
873
874/* Convert a Point to a Python object */
875PyObject *
876PyMac_BuildFixed(Fixed f)
877{
878 double d;
879
880 d = f;
881 d = d / 0x10000;
882 return Py_BuildValue("d", d);
883}
884