blob: e0cbd1a9358d70e429e8805062a5deed967e9478 [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
Jack Jansen819f1771995-08-14 12:35:10 +000031#include "pythonresources.h"
32
Jack Jansenf93c72a1994-12-14 14:07:50 +000033#include <OSUtils.h> /* for Set(Current)A5 */
Jack Jansene8e8ae01995-01-26 16:36:45 +000034#include <Files.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>
Jack Jansen08305501995-06-18 20:03:40 +000045#include <TextUtils.h>
Guido van Rossumcc0d8791995-01-30 08:57:13 +000046#ifdef THINK_C
47#include <OSEvents.h> /* For EvQElPtr */
48#endif
Jack Jansen16df2aa1995-02-27 16:17:28 +000049#ifdef __MWERKS__
50#include <SIOUX.h>
51#endif
Jack Jansen911ad6b1996-03-05 16:56:24 +000052#ifdef USE_GUSI
53#include <TFileSpec.h> /* For Path2FSSpec */
Jack Jansen378815c1996-03-06 16:21:34 +000054#include <LowMem.h> /* For SetSFCurDir, etc */
Jack Jansen911ad6b1996-03-05 16:56:24 +000055#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +000056
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000057#ifndef HAVE_UNIVERSAL_HEADERS
58#define GetResourceSizeOnDisk(x) SizeResource(x)
Guido van Rossum24a45e31995-02-20 23:45:53 +000059typedef DlgHookYDProcPtr DlgHookYDUPP;
60#define NewDlgHookYDProc(userRoutine) ((DlgHookYDUPP) (userRoutine))
61typedef FileFilterYDProcPtr FileFilterYDUPP;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +000062#endif
63
Jack Jansenee23d6e1995-01-27 14:43:25 +000064#include <signal.h>
Jack Jansen74162f31995-02-15 22:58:33 +000065#include <stdio.h>
Jack Jansene8e8ae01995-01-26 16:36:45 +000066
Jack Jansenee23d6e1995-01-27 14:43:25 +000067/*
Jack Jansen16df2aa1995-02-27 16:17:28 +000068** We have to be careful, since we can't handle
Jack Jansenee23d6e1995-01-27 14:43:25 +000069** things like updates (and they'll keep coming back if we don't
Jack Jansen16df2aa1995-02-27 16:17:28 +000070** handle them). Note that we don't know who has windows open, so
71** even handing updates off to SIOUX under MW isn't going to work.
Jack Jansenee23d6e1995-01-27 14:43:25 +000072*/
73#define MAINLOOP_EVENTMASK (mDownMask|keyDownMask|osMask)
Jack Jansene8e8ae01995-01-26 16:36:45 +000074
75#include <signal.h>
Jack Jansenf93c72a1994-12-14 14:07:50 +000076
Guido van Rossumb3404661995-01-22 18:36:13 +000077/* XXX We should include Errors.h here, but it has a name conflict
Jack Jansen5f653091995-01-18 13:53:49 +000078** with the python errors.h. */
79#define fnfErr -43
80
Jack Jansene8e8ae01995-01-26 16:36:45 +000081/* Declared in macfsmodule.c: */
82extern FSSpec *mfs_GetFSSpecFSSpec();
83
Jack Jansenee23d6e1995-01-27 14:43:25 +000084/* Interrupt code variables: */
85static int interrupted; /* Set to true when cmd-. seen */
86static RETSIGTYPE intcatcher Py_PROTO((int));
87
Jack Jansene8e8ae01995-01-26 16:36:45 +000088/*
89** We attempt to be a good citizen by giving up the CPU periodically.
90** When in the foreground we do this less often and for shorter periods
91** than when in the background. At this time we also check for events and
Jack Jansenee23d6e1995-01-27 14:43:25 +000092** pass them off to SIOUX, if compiling with mwerks.
Jack Jansene8e8ae01995-01-26 16:36:45 +000093** The counts here are in ticks of 1/60th second.
94** XXXX The initial values here are not based on anything.
95** FG-python gives up the cpu for 1/60th 5 times per second,
96** BG-python for .2 second 10 times per second.
97*/
98static long interval_fg = 12;
99static long interval_bg = 6;
100static long yield_fg = 1;
101static long yield_bg = 12;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000102static long lastyield;
103static int in_foreground;
104
Guido van Rossume7134aa1995-02-26 10:20:53 +0000105/*
106** When > 0, do full scanning for events (program is not event aware)
107** when == 0, only scan for Command-period
108** when < 0, don't do any event scanning
109*/
110int PyMac_DoYieldEnabled = 1;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000111
Jack Jansen819f1771995-08-14 12:35:10 +0000112/*
113** Some stuff for our GetDirectory and PromptGetFile routines
114*/
115struct hook_args {
116 int selectcur_hit; /* Set to true when "select current" selected */
117 char *prompt; /* The prompt */
118};
119static DlgHookYDUPP myhook_upp;
120static int upp_inited = 0;
121
Jack Jansen378815c1996-03-06 16:21:34 +0000122#ifdef USE_GUSI
123/*
124** GUSI (1.6.0 and earlier, at the least) do not set the MacOS idea of
125** the working directory. Hence, we call this routine after each call
126** to chdir() to rectify things.
127*/
128void
129PyMac_FixGUSIcd()
130{
131 WDPBRec pb;
132 FSSpec curdirfss;
133
134 if ( Path2FSSpec(":x", &curdirfss) != noErr )
135 return;
136
137 /* Set MacOS "working directory" */
138 pb.ioNamePtr= "\p";
139 pb.ioVRefNum= curdirfss.vRefNum;
140 pb.ioWDDirID= curdirfss.parID;
141 if (PBHSetVol(&pb, 0) != noErr)
142 return;
143
Jack Jansen975aa221996-03-25 15:46:25 +0000144#if 0
Jack Jansen378815c1996-03-06 16:21:34 +0000145 /* Set standard-file working directory */
146 LMSetSFSaveDisk(-curdirfss.vRefNum);
147 LMSetCurDirStore(curdirfss.parID);
Jack Jansen975aa221996-03-25 15:46:25 +0000148#endif
Jack Jansen378815c1996-03-06 16:21:34 +0000149}
150#endif
151
Jack Jansen819f1771995-08-14 12:35:10 +0000152
Jack Jansen5f653091995-01-18 13:53:49 +0000153/* Convert C to Pascal string. Returns pointer to static buffer. */
154unsigned char *
155Pstring(char *str)
156{
157 static Str255 buf;
158 int len;
159
160 len = strlen(str);
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000161 if (len > 255)
162 len = 255;
Jack Jansen5f653091995-01-18 13:53:49 +0000163 buf[0] = (unsigned char)len;
164 strncpy((char *)buf+1, str, len);
165 return buf;
166}
167
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000168/* Like strerror() but for Mac OS error numbers */
169char *PyMac_StrError(int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000170{
171 static char buf[256];
172 Handle h;
173 char *str;
174
175 h = GetResource('Estr', err);
176 if ( h ) {
177 HLock(h);
178 str = (char *)*h;
179 memcpy(buf, str+1, (unsigned char)str[0]);
Guido van Rossumcc9bc8f1995-02-13 16:17:03 +0000180 buf[(unsigned char)str[0]] = '\0';
Jack Jansenf93c72a1994-12-14 14:07:50 +0000181 HUnlock(h);
182 ReleaseResource(h);
183 } else {
184 sprintf(buf, "Mac OS error code %d", err);
185 }
186 return buf;
187}
188
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000189/* Exception object shared by all Mac specific modules for Mac OS errors */
190PyObject *PyMac_OSErrException;
191
192/* Initialize and return PyMac_OSErrException */
193PyObject *
194PyMac_GetOSErrException()
195{
196 if (PyMac_OSErrException == NULL)
197 PyMac_OSErrException = PyString_FromString("Mac OS Error");
198 return PyMac_OSErrException;
199}
200
Jack Jansenf93c72a1994-12-14 14:07:50 +0000201/* Set a MAC-specific error from errno, and return NULL; return None if no error */
202PyObject *
Guido van Rossumfffb8bb1995-01-12 12:37:24 +0000203PyErr_Mac(PyObject *eobj, int err)
Jack Jansenf93c72a1994-12-14 14:07:50 +0000204{
205 char *msg;
206 PyObject *v;
Jack Jansenf93c72a1994-12-14 14:07:50 +0000207
Guido van Rossum8f691791995-01-18 23:57:26 +0000208 if (err == 0 && !PyErr_Occurred()) {
Jack Jansenf93c72a1994-12-14 14:07:50 +0000209 Py_INCREF(Py_None);
210 return Py_None;
211 }
Guido van Rossum8f691791995-01-18 23:57:26 +0000212 if (err == -1 && PyErr_Occurred())
213 return NULL;
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000214 msg = PyMac_StrError(err);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000215 v = Py_BuildValue("(is)", err, msg);
216 PyErr_SetObject(eobj, v);
217 Py_DECREF(v);
218 return NULL;
219}
220
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000221/* Call PyErr_Mac with PyMac_OSErrException */
222PyObject *
223PyMac_Error(OSErr err)
224{
225 return PyErr_Mac(PyMac_GetOSErrException(), err);
226}
227
Jack Jansen1ed95291996-07-22 15:25:10 +0000228#ifdef USE_STACKCHECK
229/* Check for stack overflow */
230int
231PyOS_CheckStack()
232{
233 long left;
234
235 left = StackSpace();
236 if ( left < 4000 )
237 return -1;
238 return 0;
239}
240#endif /* USE_STACKCHECK */
241
Jack Jansenee23d6e1995-01-27 14:43:25 +0000242/* The catcher routine (which may not be used for all compilers) */
243static RETSIGTYPE
244intcatcher(sig)
245 int sig;
246{
247 interrupted = 1;
248 signal(SIGINT, intcatcher);
249}
250
251void
252PyOS_InitInterrupts()
253{
254 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
255 signal(SIGINT, intcatcher);
256}
257
258/*
259** This routine scans the event queue looking for cmd-.
260** This is the only way to get an interrupt under THINK (since it
261** doesn't do SIGINT handling), but is also used under MW, when
262** the full-fledged event loop is disabled. This way, we can at least
263** interrupt a runaway python program.
264*/
265static void
266scan_event_queue(flush)
267 int flush;
268{
Jack Jansenf74f63a1995-06-27 13:18:14 +0000269#if defined(__MWERKS__) && defined(__CFM68K__)
270 return; /* No GetEvQHdr yet */
271#else
Jack Jansenee23d6e1995-01-27 14:43:25 +0000272 register EvQElPtr q;
273
274 q = (EvQElPtr) GetEvQHdr()->qHead;
275
276 for (; q; q = (EvQElPtr)q->qLink) {
277 if (q->evtQWhat == keyDown &&
278 (char)q->evtQMessage == '.' &&
279 (q->evtQModifiers & cmdKey) != 0) {
280 if ( flush )
281 FlushEvents(keyDownMask, 0);
282 interrupted = 1;
283 break;
284 }
285 }
Jack Jansenf74f63a1995-06-27 13:18:14 +0000286#endif
Jack Jansenee23d6e1995-01-27 14:43:25 +0000287}
288
289int
290PyOS_InterruptOccurred()
291{
Guido van Rossume7134aa1995-02-26 10:20:53 +0000292 if (PyMac_DoYieldEnabled < 0)
293 return 0;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000294#ifdef THINK_C
295 scan_event_queue(1);
296#endif
297 PyMac_Yield();
298 if (interrupted) {
299 interrupted = 0;
300 return 1;
301 }
302 return 0;
303}
304
305/* intrpeek() is like intrcheck(), but it doesn't flush the events. The
306** idea is that you call intrpeek() somewhere in a busy-wait loop, and return
307** None as soon as it returns 1. The mainloop will then pick up the cmd-. soon
308** thereafter.
309*/
310static int
311intrpeek()
312{
313#ifdef THINK_C
314 scan_event_queue(0);
315#endif
316 return interrupted;
317}
318
319/* Check whether we are in the foreground */
320int
321PyMac_InForeground()
322{
323 static ProcessSerialNumber ours;
324 static inited;
325 ProcessSerialNumber curfg;
326 Boolean eq;
327
328 if ( inited == 0 )
329 (void)GetCurrentProcess(&ours);
330 inited = 1;
331 if ( GetFrontProcess(&curfg) < 0 )
332 eq = 1;
333 else if ( SameProcess(&ours, &curfg, &eq) < 0 )
334 eq = 1;
335 return (int)eq;
336
337}
338
Jack Jansenf93c72a1994-12-14 14:07:50 +0000339/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000340** Set yield timeouts
Jack Jansenf93c72a1994-12-14 14:07:50 +0000341*/
Jack Jansene8e8ae01995-01-26 16:36:45 +0000342void
343PyMac_SetYield(long fgi, long fgy, long bgi, long bgy)
344{
345 interval_fg = fgi;
346 yield_fg = fgy;
347 interval_bg = bgi;
348 yield_bg = bgy;
349}
350
351/*
Jack Jansena76382a1995-02-02 14:25:56 +0000352** Handle an event, either one found in the mainloop eventhandler or
353** one passed back from the python program.
354*/
355void
356PyMac_HandleEvent(evp)
357 EventRecord *evp;
358{
Jack Jansena76382a1995-02-02 14:25:56 +0000359
360#ifdef __MWERKS__
Jack Jansen38e97661995-11-10 14:53:00 +0000361 {
362 int siouxdidit;
363
364 /* If SIOUX wants it we're done */
365 siouxdidit = SIOUXHandleOneEvent(evp);
366 if ( siouxdidit )
367 return;
368 }
Jack Jansena76382a1995-02-02 14:25:56 +0000369#else
370 /* Other compilers are just unlucky: we only weed out clicks in other applications */
371 if ( evp->what == mouseDown ) {
Jack Jansen847e89e1995-08-31 13:57:40 +0000372 WindowPtr wp;
373
Jack Jansen38e97661995-11-10 14:53:00 +0000374 if ( FindWindow(evp->where, &wp) == inSysWindow ) {
Jack Jansena76382a1995-02-02 14:25:56 +0000375 SystemClick(evp, wp);
Jack Jansen38e97661995-11-10 14:53:00 +0000376 return;
377 }
Jack Jansena76382a1995-02-02 14:25:56 +0000378 }
379#endif /* !__MWERKS__ */
380}
381
382/*
Jack Jansene8e8ae01995-01-26 16:36:45 +0000383** Yield the CPU to other tasks.
384*/
385static
386PyMac_DoYield()
Jack Jansenf93c72a1994-12-14 14:07:50 +0000387{
388 EventRecord ev;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000389 long yield;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000390 static int no_waitnextevent = -1;
391 int gotone;
392
393 if ( no_waitnextevent < 0 ) {
394 no_waitnextevent = (NGetTrapAddress(_WaitNextEvent, ToolTrap) ==
395 NGetTrapAddress(_Unimplemented, ToolTrap));
396 }
Jack Jansenf93c72a1994-12-14 14:07:50 +0000397
Jack Jansenee23d6e1995-01-27 14:43:25 +0000398 if ( !PyMac_DoYieldEnabled ) {
399#ifndef THINK_C
400 /* Under think this has been done before in intrcheck() or intrpeek() */
401 scan_event_queue(0);
402#endif
Jack Jansene8e8ae01995-01-26 16:36:45 +0000403 return;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000404 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000405
Jack Jansenee23d6e1995-01-27 14:43:25 +0000406 in_foreground = PyMac_InForeground();
407 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000408 yield = yield_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000409 else
410 yield = yield_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000411 while ( 1 ) {
412 if ( no_waitnextevent ) {
413 SystemTask();
Jack Jansenee23d6e1995-01-27 14:43:25 +0000414 gotone = GetNextEvent(MAINLOOP_EVENTMASK, &ev);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000415 } else {
Jack Jansenee23d6e1995-01-27 14:43:25 +0000416 gotone = WaitNextEvent(MAINLOOP_EVENTMASK, &ev, yield, NULL);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000417 }
418 /* Get out quickly if nothing interesting is happening */
419 if ( !gotone || ev.what == nullEvent )
420 break;
Jack Jansena76382a1995-02-02 14:25:56 +0000421 PyMac_HandleEvent(&ev);
Jack Jansenf93c72a1994-12-14 14:07:50 +0000422 }
Jack Jansene8e8ae01995-01-26 16:36:45 +0000423 lastyield = TickCount();
424}
425
426/*
427** Yield the CPU to other tasks if opportune
428*/
429void
430PyMac_Yield() {
431 long iv;
432
Jack Jansenee23d6e1995-01-27 14:43:25 +0000433 if ( in_foreground )
Jack Jansene8e8ae01995-01-26 16:36:45 +0000434 iv = interval_fg;
Jack Jansenee23d6e1995-01-27 14:43:25 +0000435 else
436 iv = interval_bg;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000437 if ( TickCount() > lastyield + iv )
438 PyMac_DoYield();
439}
440
441/*
442** Idle routine for busy-wait loops.
443** Gives up CPU, handles events and returns true if an interrupt is pending
444** (but not actually handled yet).
445*/
446int
447PyMac_Idle()
448{
449 PyMac_DoYield();
450 return intrpeek();
Jack Jansenf93c72a1994-12-14 14:07:50 +0000451}
Jack Jansen74162f31995-02-15 22:58:33 +0000452/*
453** Returns true if the argument has a resource fork, and it contains
454** a 'PYC ' resource of the correct name
455*/
456int
457PyMac_FindResourceModule(module, filename)
458char *module;
459char *filename;
460{
461 FSSpec fss;
462 FInfo finfo;
463 short oldrh, filerh;
464 int ok;
465 Handle h;
466
467 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr )
468 return 0; /* It doesn't exist */
469 if ( FSpGetFInfo(&fss, &finfo) != noErr )
470 return 0; /* shouldn't happen, I guess */
Jack Jansen74162f31995-02-15 22:58:33 +0000471 oldrh = CurResFile();
472 filerh = FSpOpenResFile(&fss, fsRdPerm);
473 if ( filerh == -1 )
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000474 return 0;
Jack Jansen74162f31995-02-15 22:58:33 +0000475 UseResFile(filerh);
476 SetResLoad(0);
477 h = Get1NamedResource('PYC ', Pstring(module));
478 SetResLoad(1);
479 ok = (h != NULL);
480 CloseResFile(filerh);
481 UseResFile(oldrh);
482 return ok;
483}
484
485/*
486** Load the specified module from a resource
487*/
488PyObject *
489PyMac_LoadResourceModule(module, filename)
490char *module;
491char *filename;
492{
493 FSSpec fss;
494 FInfo finfo;
495 short oldrh, filerh;
Jack Jansen74162f31995-02-15 22:58:33 +0000496 Handle h;
497 OSErr err;
498 PyObject *m, *co;
499 long num, size;
500
501 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
502 goto error;
503 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
504 goto error;
Jack Jansen74162f31995-02-15 22:58:33 +0000505 oldrh = CurResFile();
506 filerh = FSpOpenResFile(&fss, fsRdPerm);
507 if ( filerh == -1 ) {
508 err = ResError();
509 goto error;
510 }
511 UseResFile(filerh);
512 h = Get1NamedResource('PYC ', Pstring(module));
513 if ( h == NULL ) {
514 err = ResError();
515 goto error;
516 }
517 HLock(h);
518 /*
519 ** XXXX The next few lines are intimately tied to the format of pyc
520 ** files. I'm not sure whether this code should be here or in import.c -- Jack
521 */
522 size = GetHandleSize(h);
523 if ( size < 8 ) {
524 PyErr_SetString(PyExc_ImportError, "Resource too small");
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000525 co = NULL;
Jack Jansen74162f31995-02-15 22:58:33 +0000526 } else {
527 num = (*h)[0] & 0xff;
528 num = num | (((*h)[1] & 0xff) << 8);
529 num = num | (((*h)[2] & 0xff) << 16);
530 num = num | (((*h)[3] & 0xff) << 24);
531 if ( num != PyImport_GetMagicNumber() ) {
532 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
533 co = NULL;
534 } else {
535 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
536 }
537 }
538 HUnlock(h);
539 CloseResFile(filerh);
540 UseResFile(oldrh);
541 if ( co ) {
542 m = PyImport_ExecCodeModule(module, co);
543 Py_DECREF(co);
544 } else {
545 m = NULL;
546 }
547 return m;
548error:
549 {
550 char buf[512];
551
Guido van Rossumc3d1c8e1995-02-18 15:01:31 +0000552 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
Jack Jansen74162f31995-02-15 22:58:33 +0000553 PyErr_SetString(PyExc_ImportError, buf);
554 return NULL;
555 }
556}
Guido van Rossum24a45e31995-02-20 23:45:53 +0000557
Jack Jansen3ec804a1995-02-20 15:56:10 +0000558/*
559** Helper routine for GetDirectory
560*/
Guido van Rossum24a45e31995-02-20 23:45:53 +0000561static pascal short
Jack Jansen819f1771995-08-14 12:35:10 +0000562myhook_proc(short item, DialogPtr theDialog, struct hook_args *dataptr)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000563{
Jack Jansen819f1771995-08-14 12:35:10 +0000564 if ( item == sfHookFirstCall && dataptr->prompt) {
565 Handle prompth;
566 short type;
567 Rect rect;
568
569 GetDialogItem(theDialog, PROMPT_ITEM, &type, &prompth, &rect);
570 if ( prompth )
571 SetDialogItemText(prompth, (unsigned char *)dataptr->prompt);
572 } else
Jack Jansen3ec804a1995-02-20 15:56:10 +0000573 if ( item == SELECTCUR_ITEM ) {
574 item = sfItemCancelButton;
Jack Jansen819f1771995-08-14 12:35:10 +0000575 dataptr->selectcur_hit = 1;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000576 }
577 return item;
578}
579
580/*
581** Ask the user for a directory. I still can't understand
582** why Apple doesn't provide a standard solution for this...
583*/
584int
Jack Jansen819f1771995-08-14 12:35:10 +0000585PyMac_GetDirectory(dirfss, prompt)
Jack Jansen3ec804a1995-02-20 15:56:10 +0000586 FSSpec *dirfss;
Jack Jansen819f1771995-08-14 12:35:10 +0000587 char *prompt;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000588{
589 static SFTypeList list = {'fldr', 0, 0, 0};
590 static Point where = {-1, -1};
Jack Jansen3ec804a1995-02-20 15:56:10 +0000591 StandardFileReply reply;
Jack Jansen819f1771995-08-14 12:35:10 +0000592 struct hook_args hook_args;
Jack Jansen3ec804a1995-02-20 15:56:10 +0000593
594 if ( !upp_inited ) {
595 myhook_upp = NewDlgHookYDProc(myhook_proc);
596 upp_inited = 1;
597 }
Jack Jansen819f1771995-08-14 12:35:10 +0000598 if ( prompt && *prompt )
599 hook_args.prompt = (char *)Pstring(prompt);
600 else
601 hook_args.prompt = NULL;
602 hook_args.selectcur_hit = 0;
Guido van Rossum24a45e31995-02-20 23:45:53 +0000603 CustomGetFile((FileFilterYDUPP)0, 1, list, &reply, GETDIR_ID, where, myhook_upp,
Jack Jansen819f1771995-08-14 12:35:10 +0000604 NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000605
606 reply.sfFile.name[0] = 0;
607 if( FSMakeFSSpec(reply.sfFile.vRefNum, reply.sfFile.parID, reply.sfFile.name, dirfss) )
608 return 0;
Jack Jansen819f1771995-08-14 12:35:10 +0000609 return hook_args.selectcur_hit;
610}
611
612/*
613** Slightly extended StandardGetFile: accepts a prompt */
614void PyMac_PromptGetFile(short numTypes, ConstSFTypeListPtr typeList,
615 StandardFileReply *reply, char *prompt)
616{
617 static Point where = {-1, -1};
618 struct hook_args hook_args;
619
620 if ( !upp_inited ) {
621 myhook_upp = NewDlgHookYDProc(myhook_proc);
622 upp_inited = 1;
623 }
624 if ( prompt && *prompt )
625 hook_args.prompt = (char *)Pstring(prompt);
626 else
627 hook_args.prompt = NULL;
628 hook_args.selectcur_hit = 0;
629 CustomGetFile((FileFilterYDUPP)0, numTypes, typeList, reply, GETFILEPROMPT_ID, where,
630 myhook_upp, NULL, NULL, NULL, (void *)&hook_args);
Jack Jansen3ec804a1995-02-20 15:56:10 +0000631}
Jack Jansen5f653091995-01-18 13:53:49 +0000632
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000633/* Convert a 4-char string object argument to an OSType value */
Jack Jansen5f653091995-01-18 13:53:49 +0000634int
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000635PyMac_GetOSType(PyObject *v, OSType *pr)
Jack Jansen5f653091995-01-18 13:53:49 +0000636{
637 if (!PyString_Check(v) || PyString_Size(v) != 4) {
638 PyErr_SetString(PyExc_TypeError,
639 "OSType arg must be string of 4 chars");
640 return 0;
641 }
642 memcpy((char *)pr, PyString_AsString(v), 4);
643 return 1;
644}
645
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000646/* Convert an OSType value to a 4-char string object */
647PyObject *
648PyMac_BuildOSType(OSType t)
649{
650 return PyString_FromStringAndSize((char *)&t, 4);
651}
652
653
654/* Convert a Python string object to a Str255 */
Jack Jansen5f653091995-01-18 13:53:49 +0000655int
Guido van Rossum8f691791995-01-18 23:57:26 +0000656PyMac_GetStr255(PyObject *v, Str255 pbuf)
Jack Jansen5f653091995-01-18 13:53:49 +0000657{
658 int len;
659 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
660 PyErr_SetString(PyExc_TypeError,
661 "Str255 arg must be string of at most 255 chars");
662 return 0;
663 }
664 pbuf[0] = len;
665 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
666 return 1;
667}
668
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000669/* Convert a Str255 to a Python string object */
670PyObject *
671PyMac_BuildStr255(Str255 s)
672{
673 return PyString_FromStringAndSize((char *)&s[1], (int)s[0]);
674}
675
676
Jack Jansen5f653091995-01-18 13:53:49 +0000677/*
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000678** Convert a Python object to an FSSpec.
679** The object may either be a full pathname or a triple
680** (vrefnum, dirid, path).
Jack Jansen5f653091995-01-18 13:53:49 +0000681** NOTE: This routine will fail on pre-sys7 machines.
682** The caller is responsible for not calling this routine
683** in those cases (which is fine, since everyone calling
684** this is probably sys7 dependent anyway).
685*/
686int
Guido van Rossum8f691791995-01-18 23:57:26 +0000687PyMac_GetFSSpec(PyObject *v, FSSpec *fs)
Jack Jansen5f653091995-01-18 13:53:49 +0000688{
689 Str255 path;
690 short refnum;
691 long parid;
692 OSErr err;
Jack Jansene8e8ae01995-01-26 16:36:45 +0000693 FSSpec *fs2;
Jack Jansen5f653091995-01-18 13:53:49 +0000694
Jack Jansene8e8ae01995-01-26 16:36:45 +0000695 /* first check whether it already is an FSSpec */
696 fs2 = mfs_GetFSSpecFSSpec(v);
697 if ( fs2 ) {
Jack Jansen3ec804a1995-02-20 15:56:10 +0000698 (void)FSMakeFSSpec(fs2->vRefNum, fs2->parID, fs2->name, fs);
Jack Jansene8e8ae01995-01-26 16:36:45 +0000699 return 1;
700 }
Jack Jansen5f653091995-01-18 13:53:49 +0000701 if ( PyString_Check(v) ) {
702 /* It's a pathname */
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000703 if( !PyArg_Parse(v, "O&", PyMac_GetStr255, &path) )
Jack Jansen5f653091995-01-18 13:53:49 +0000704 return 0;
Jack Jansen378815c1996-03-06 16:21:34 +0000705 refnum = 0; /* XXXX Should get CurWD here?? */
Jack Jansen5f653091995-01-18 13:53:49 +0000706 parid = 0;
707 } else {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000708 if( !PyArg_Parse(v, "(hlO&); FSSpec should be fullpath or (vrefnum,dirid,path)",
709 &refnum, &parid, PyMac_GetStr255, &path)) {
Jack Jansen5f653091995-01-18 13:53:49 +0000710 return 0;
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000711 }
Jack Jansen5f653091995-01-18 13:53:49 +0000712 }
713 err = FSMakeFSSpec(refnum, parid, path, fs);
714 if ( err && err != fnfErr ) {
Guido van Rossum9aa3d131995-01-21 13:46:04 +0000715 PyErr_Mac(PyExc_ValueError, err);
Jack Jansen5f653091995-01-18 13:53:49 +0000716 return 0;
717 }
718 return 1;
719}
720
Guido van Rossum8f691791995-01-18 23:57:26 +0000721
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000722/* Convert a Python object to a Rect.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000723 The object must be a (left, top, right, bottom) tuple.
724 (This differs from the order in the struct but is consistent with
725 the arguments to SetRect(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000726int
727PyMac_GetRect(PyObject *v, Rect *r)
Guido van Rossum8f691791995-01-18 23:57:26 +0000728{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000729 return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom);
Guido van Rossum8f691791995-01-18 23:57:26 +0000730}
Guido van Rossumb3404661995-01-22 18:36:13 +0000731
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000732/* Convert a Rect to a Python object */
Guido van Rossumb3404661995-01-22 18:36:13 +0000733PyObject *
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000734PyMac_BuildRect(Rect *r)
Guido van Rossumb3404661995-01-22 18:36:13 +0000735{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000736 return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000737}
738
739
740/* Convert a Python object to a Point.
Guido van Rossum5279ec61995-01-26 22:56:59 +0000741 The object must be a (h, v) tuple.
742 (This differs from the order in the struct but is consistent with
743 the arguments to SetPoint(), and also with STDWIN). */
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000744int
745PyMac_GetPoint(PyObject *v, Point *p)
746{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000747 return PyArg_Parse(v, "(hh)", &p->h, &p->v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000748}
749
750/* Convert a Point to a Python object */
751PyObject *
752PyMac_BuildPoint(Point p)
753{
Guido van Rossum5279ec61995-01-26 22:56:59 +0000754 return Py_BuildValue("(hh)", p.h, p.v);
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000755}
756
757
758/* Convert a Python object to an EventRecord.
759 The object must be a (what, message, when, (v, h), modifiers) tuple. */
760int
761PyMac_GetEventRecord(PyObject *v, EventRecord *e)
762{
763 return PyArg_Parse(v, "(hll(hh)h)",
764 &e->what,
765 &e->message,
766 &e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000767 &e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000768 &e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000769 &e->modifiers);
770}
771
772/* Convert a Rect to an EventRecord object */
773PyObject *
774PyMac_BuildEventRecord(EventRecord *e)
775{
776 return Py_BuildValue("(hll(hh)h)",
777 e->what,
778 e->message,
779 e->when,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000780 e->where.h,
Guido van Rossum5279ec61995-01-26 22:56:59 +0000781 e->where.v,
Guido van Rossumcf27c2d1995-01-25 23:06:44 +0000782 e->modifiers);
Guido van Rossumb3404661995-01-22 18:36:13 +0000783}
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000784
785/* Convert Python object to Fixed */
786int
787PyMac_GetFixed(PyObject *v, Fixed *f)
788{
789 double d;
790
791 if( !PyArg_Parse(v, "d", &d))
792 return 0;
793 *f = (Fixed)(d * 0x10000);
Jack Jansen31dd5c01996-05-31 13:01:39 +0000794 return 1;
Jack Jansenfa4d5d01995-11-15 15:19:29 +0000795}
796
797/* Convert a Point to a Python object */
798PyObject *
799PyMac_BuildFixed(Fixed f)
800{
801 double d;
802
803 d = f;
804 d = d / 0x10000;
805 return Py_BuildValue("d", d);
806}
807