Last-minute fix for Jim H: don't die after del sys.stdout
[python/dscho.git] / Mac / Modules / macosmodule.c
blob6fc3cf4e7034138140f1483f16f99366803c0ce5
1 /***********************************************************
2 Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* Macintosh OS-specific interface */
27 #include "Python.h"
28 #include "macglue.h"
30 #include <Windows.h>
31 #include <Files.h>
32 #include <LowMem.h>
34 static PyObject *MacOS_Error; /* Exception MacOS.Error */
36 #ifdef MPW
37 #define bufferIsSmall -607 /*error returns from Post and Accept */
38 #endif
40 static PyObject *ErrorObject;
42 /* ----------------------------------------------------- */
44 /* Declarations for objects of type Resource fork */
46 typedef struct {
47 PyObject_HEAD
48 short fRefNum;
49 int isclosed;
50 } rfobject;
52 staticforward PyTypeObject Rftype;
56 /* ---------------------------------------------------------------- */
58 static void
59 do_close(self)
60 rfobject *self;
62 if (self->isclosed ) return;
63 (void)FSClose(self->fRefNum);
64 self->isclosed = 1;
67 static char rf_read__doc__[] =
68 "Read data from resource fork"
71 static PyObject *
72 rf_read(self, args)
73 rfobject *self;
74 PyObject *args;
76 long n;
77 PyObject *v;
78 OSErr err;
80 if (self->isclosed) {
81 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
82 return NULL;
85 if (!PyArg_ParseTuple(args, "l", &n))
86 return NULL;
88 v = PyString_FromStringAndSize((char *)NULL, n);
89 if (v == NULL)
90 return NULL;
92 err = FSRead(self->fRefNum, &n, PyString_AsString(v));
93 if (err && err != eofErr) {
94 PyMac_Error(err);
95 Py_DECREF(v);
96 return NULL;
98 _PyString_Resize(&v, n);
99 return v;
103 static char rf_write__doc__[] =
104 "Write to resource fork"
107 static PyObject *
108 rf_write(self, args)
109 rfobject *self;
110 PyObject *args;
112 char *buffer;
113 long size;
114 OSErr err;
116 if (self->isclosed) {
117 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
118 return NULL;
120 if (!PyArg_ParseTuple(args, "s#", &buffer, &size))
121 return NULL;
122 err = FSWrite(self->fRefNum, &size, buffer);
123 if (err) {
124 PyMac_Error(err);
125 return NULL;
127 Py_INCREF(Py_None);
128 return Py_None;
132 static char rf_seek__doc__[] =
133 "Set file position"
136 static PyObject *
137 rf_seek(self, args)
138 rfobject *self;
139 PyObject *args;
141 long amount, pos;
142 int whence = SEEK_SET;
143 long eof;
144 OSErr err;
146 if (self->isclosed) {
147 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
148 return NULL;
150 if (!PyArg_ParseTuple(args, "l|i", &amount, &whence))
151 return NULL;
153 if ( err = GetEOF(self->fRefNum, &eof))
154 goto ioerr;
156 switch (whence) {
157 case SEEK_CUR:
158 if (err = GetFPos(self->fRefNum, &pos))
159 goto ioerr;
160 break;
161 case SEEK_END:
162 pos = eof;
163 break;
164 case SEEK_SET:
165 pos = 0;
166 break;
167 default:
168 PyErr_BadArgument();
169 return NULL;
172 pos += amount;
174 /* Don't bother implementing seek past EOF */
175 if (pos > eof || pos < 0) {
176 PyErr_BadArgument();
177 return NULL;
180 if ( err = SetFPos(self->fRefNum, fsFromStart, pos) ) {
181 ioerr:
182 PyMac_Error(err);
183 return NULL;
185 Py_INCREF(Py_None);
186 return Py_None;
190 static char rf_tell__doc__[] =
191 "Get file position"
194 static PyObject *
195 rf_tell(self, args)
196 rfobject *self;
197 PyObject *args;
199 long where;
200 OSErr err;
202 if (self->isclosed) {
203 PyErr_SetString(PyExc_ValueError, "Operation on closed file");
204 return NULL;
206 if (!PyArg_ParseTuple(args, ""))
207 return NULL;
208 if ( err = GetFPos(self->fRefNum, &where) ) {
209 PyMac_Error(err);
210 return NULL;
212 return PyInt_FromLong(where);
215 static char rf_close__doc__[] =
216 "Close resource fork"
219 static PyObject *
220 rf_close(self, args)
221 rfobject *self;
222 PyObject *args;
224 if (!PyArg_ParseTuple(args, ""))
225 return NULL;
226 do_close(self);
227 Py_INCREF(Py_None);
228 return Py_None;
232 static struct PyMethodDef rf_methods[] = {
233 {"read", rf_read, 1, rf_read__doc__},
234 {"write", rf_write, 1, rf_write__doc__},
235 {"seek", rf_seek, 1, rf_seek__doc__},
236 {"tell", rf_tell, 1, rf_tell__doc__},
237 {"close", rf_close, 1, rf_close__doc__},
239 {NULL, NULL} /* sentinel */
242 /* ---------- */
245 static rfobject *
246 newrfobject()
248 rfobject *self;
250 self = PyObject_NEW(rfobject, &Rftype);
251 if (self == NULL)
252 return NULL;
253 self->isclosed = 1;
254 return self;
258 static void
259 rf_dealloc(self)
260 rfobject *self;
262 do_close(self);
263 PyMem_DEL(self);
266 static PyObject *
267 rf_getattr(self, name)
268 rfobject *self;
269 char *name;
271 return Py_FindMethod(rf_methods, (PyObject *)self, name);
274 static char Rftype__doc__[] =
275 "Resource fork file object"
278 static PyTypeObject Rftype = {
279 PyObject_HEAD_INIT(&PyType_Type)
280 0, /*ob_size*/
281 "ResourceFork", /*tp_name*/
282 sizeof(rfobject), /*tp_basicsize*/
283 0, /*tp_itemsize*/
284 /* methods */
285 (destructor)rf_dealloc, /*tp_dealloc*/
286 (printfunc)0, /*tp_print*/
287 (getattrfunc)rf_getattr, /*tp_getattr*/
288 (setattrfunc)0, /*tp_setattr*/
289 (cmpfunc)0, /*tp_compare*/
290 (reprfunc)0, /*tp_repr*/
291 0, /*tp_as_number*/
292 0, /*tp_as_sequence*/
293 0, /*tp_as_mapping*/
294 (hashfunc)0, /*tp_hash*/
295 (ternaryfunc)0, /*tp_call*/
296 (reprfunc)0, /*tp_str*/
298 /* Space for future expansion */
299 0L,0L,0L,0L,
300 Rftype__doc__ /* Documentation string */
303 /* End of code for Resource fork objects */
304 /* -------------------------------------------------------- */
306 /*----------------------------------------------------------------------*/
307 /* Miscellaneous File System Operations */
309 static char getcrtp_doc[] = "Obsolete, use macfs module";
311 static PyObject *
312 MacOS_GetCreatorAndType(PyObject *self, PyObject *args)
314 Str255 name;
315 FInfo info;
316 PyObject *creator, *type, *res;
317 OSErr err;
319 if (!PyArg_ParseTuple(args, "O&", PyMac_GetStr255, &name))
320 return NULL;
321 if ((err = GetFInfo(name, 0, &info)) != noErr)
322 return PyErr_Mac(MacOS_Error, err);
323 creator = PyString_FromStringAndSize((char *)&info.fdCreator, 4);
324 type = PyString_FromStringAndSize((char *)&info.fdType, 4);
325 res = Py_BuildValue("OO", creator, type);
326 Py_DECREF(creator);
327 Py_DECREF(type);
328 return res;
331 static char setcrtp_doc[] = "Obsolete, use macfs module";
333 static PyObject *
334 MacOS_SetCreatorAndType(PyObject *self, PyObject *args)
336 Str255 name;
337 ResType creator, type;
338 FInfo info;
339 OSErr err;
341 if (!PyArg_ParseTuple(args, "O&O&O&",
342 PyMac_GetStr255, &name, PyMac_GetOSType, &creator, PyMac_GetOSType, &type))
343 return NULL;
344 if ((err = GetFInfo(name, 0, &info)) != noErr)
345 return PyErr_Mac(MacOS_Error, err);
346 info.fdCreator = creator;
347 info.fdType = type;
348 if ((err = SetFInfo(name, 0, &info)) != noErr)
349 return PyErr_Mac(MacOS_Error, err);
350 Py_INCREF(Py_None);
351 return Py_None;
354 /*----------------------------------------------------------------------*/
355 /* STDWIN High Level Event interface */
357 #include <EPPC.h>
358 #include <Events.h>
360 #ifdef USE_STDWIN
362 extern void (*_w_high_level_event_proc)(EventRecord *);
364 static PyObject *MacOS_HighLevelEventHandler = NULL;
366 static void
367 MacOS_HighLevelEventProc(EventRecord *e)
369 if (MacOS_HighLevelEventHandler != NULL) {
370 PyObject *args = PyMac_BuildEventRecord(e);
371 PyObject *res;
372 if (args == NULL)
373 res = NULL;
374 else {
375 res = PyEval_CallObject(MacOS_HighLevelEventHandler, args);
376 Py_DECREF(args);
378 if (res == NULL) {
379 fprintf(stderr, "Exception in MacOS_HighLevelEventProc:\n");
380 PyErr_Print();
382 else
383 Py_DECREF(res);
387 /* XXXX Need to come here from PyMac_DoYield too... */
389 static PyObject *
390 MacOS_SetHighLevelEventHandler(self, args)
391 PyObject *self;
392 PyObject *args;
394 PyObject *previous = MacOS_HighLevelEventHandler;
395 PyObject *next = NULL;
396 if (!PyArg_ParseTuple(args, "|O", &next))
397 return NULL;
398 if (next == Py_None)
399 next = NULL;
400 Py_INCREF(next);
401 MacOS_HighLevelEventHandler = next;
402 if (next == NULL)
403 _w_high_level_event_proc = NULL;
404 else
405 _w_high_level_event_proc = MacOS_HighLevelEventProc;
406 if (previous == NULL) {
407 Py_INCREF(Py_None);
408 previous = Py_None;
410 return previous;
413 #endif /* USE_STDWIN */
415 static char accepthle_doc[] = "Get arguments of pending high-level event";
417 static PyObject *
418 MacOS_AcceptHighLevelEvent(self, args)
419 PyObject *self;
420 PyObject *args;
422 TargetID sender;
423 unsigned long refcon;
424 Ptr buf;
425 unsigned long len;
426 OSErr err;
427 PyObject *res;
429 buf = NULL;
430 len = 0;
431 err = AcceptHighLevelEvent(&sender, &refcon, buf, &len);
432 if (err == bufferIsSmall) {
433 buf = malloc(len);
434 if (buf == NULL)
435 return PyErr_NoMemory();
436 err = AcceptHighLevelEvent(&sender, &refcon, buf, &len);
437 if (err != noErr) {
438 free(buf);
439 return PyErr_Mac(MacOS_Error, (int)err);
442 else if (err != noErr)
443 return PyErr_Mac(MacOS_Error, (int)err);
444 res = Py_BuildValue("s#ls#",
445 (char *)&sender, (int)(sizeof sender), refcon, (char *)buf, (int)len);
446 free(buf);
447 return res;
450 static char schedparams_doc[] = "Set/return mainloop interrupt check flag, etc";
453 ** Set scheduler parameters
455 static PyObject *
456 MacOS_SchedParams(PyObject *self, PyObject *args)
458 PyMacSchedParams old, new;
460 PyMac_GetSchedParams(&old);
461 new = old;
462 if (!PyArg_ParseTuple(args, "|iiidd", &new.check_interrupt, &new.process_events,
463 &new.besocial, &new.check_interval, &new.bg_yield))
464 return NULL;
465 PyMac_SetSchedParams(&new);
466 return Py_BuildValue("iiidd", old.check_interrupt, old.process_events,
467 old.besocial, old.check_interval, old.bg_yield);
470 static char appswitch_doc[] = "Obsolete, use SchedParams";
472 /* Obsolete, for backward compatability */
473 static PyObject *
474 MacOS_EnableAppswitch(PyObject *self, PyObject *args)
476 int new, old;
477 PyMacSchedParams schp;
479 if (!PyArg_ParseTuple(args, "i", &new))
480 return NULL;
481 PyMac_GetSchedParams(&schp);
482 if ( schp.process_events )
483 old = 1;
484 else if ( schp.check_interrupt )
485 old = 0;
486 else
487 old = -1;
488 if ( new > 0 ) {
489 schp.process_events = mDownMask|keyDownMask|osMask;
490 schp.check_interrupt = 1;
491 } else if ( new == 0 ) {
492 schp.process_events = 0;
493 schp.check_interrupt = 1;
494 } else {
495 schp.process_events = 0;
496 schp.check_interrupt = 0;
498 PyMac_SetSchedParams(&schp);
499 return Py_BuildValue("i", old);
502 static char setevh_doc[] = "Set python event handler to be called in mainloop";
504 static PyObject *
505 MacOS_SetEventHandler(self, args)
506 PyObject *self;
507 PyObject *args;
509 PyObject *evh = NULL;
511 if (!PyArg_ParseTuple(args, "|O", &evh))
512 return NULL;
513 if (evh == Py_None)
514 evh = NULL;
515 if ( evh && !PyCallable_Check(evh) ) {
516 PyErr_SetString(PyExc_ValueError, "SetEventHandler argument must be callable");
517 return NULL;
519 if ( !PyMac_SetEventHandler(evh) )
520 return NULL;
521 Py_INCREF(Py_None);
522 return Py_None;
525 static char handleev_doc[] = "Pass event to other interested parties like sioux";
527 static PyObject *
528 MacOS_HandleEvent(PyObject *self, PyObject *args)
530 EventRecord ev;
532 if (!PyArg_ParseTuple(args, "O&", PyMac_GetEventRecord, &ev))
533 return NULL;
534 PyMac_HandleEventIntern(&ev);
535 Py_INCREF(Py_None);
536 return Py_None;
539 static char geterr_doc[] = "Convert OSErr number to string";
541 static PyObject *
542 MacOS_GetErrorString(PyObject *self, PyObject *args)
544 int errn;
546 if (!PyArg_ParseTuple(args, "i", &errn))
547 return NULL;
548 return Py_BuildValue("s", PyMac_StrError(errn));
551 static char splash_doc[] = "Open a splash-screen dialog by resource-id (0=close)";
553 static PyObject *
554 MacOS_splash(PyObject *self, PyObject *args)
556 int resid = -1;
557 static DialogPtr curdialog = NULL;
558 DialogPtr olddialog;
559 WindowRef theWindow;
560 CGrafPtr thePort;
561 short xpos, ypos, width, height, swidth, sheight;
563 if (!PyArg_ParseTuple(args, "|i", &resid))
564 return NULL;
565 olddialog = curdialog;
567 if ( resid != -1 ) {
568 curdialog = GetNewDialog(resid, NULL, (WindowPtr)-1);
569 if ( curdialog ) {
570 theWindow = GetDialogWindow(curdialog);
571 thePort = GetWindowPort(theWindow);
572 width = thePort->portRect.right - thePort->portRect.left;
573 height = thePort->portRect.bottom - thePort->portRect.top;
574 swidth = qd.screenBits.bounds.right - qd.screenBits.bounds.left;
575 sheight = qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - LMGetMBarHeight();
576 xpos = (swidth-width)/2;
577 ypos = (sheight-height)/5 + LMGetMBarHeight();
578 MoveWindow(theWindow, xpos, ypos, 0);
579 ShowWindow(theWindow);
580 DrawDialog(curdialog);
583 if (olddialog)
584 DisposeDialog(olddialog);
585 Py_INCREF(Py_None);
586 return Py_None;
589 static char DebugStr_doc[] = "Switch to low-level debugger with a message";
591 static PyObject *
592 MacOS_DebugStr(PyObject *self, PyObject *args)
594 Str255 message;
595 PyObject *object = 0;
597 if (!PyArg_ParseTuple(args, "O&|O", PyMac_GetStr255, message, &object))
598 return NULL;
599 DebugStr(message);
600 Py_INCREF(Py_None);
601 return Py_None;
604 static char SysBeep_doc[] = "BEEEEEP!!!";
606 static PyObject *
607 MacOS_SysBeep(PyObject *self, PyObject *args)
609 int duration = 6;
611 if (!PyArg_ParseTuple(args, "|i", &duration))
612 return NULL;
613 SysBeep(duration);
614 Py_INCREF(Py_None);
615 return Py_None;
618 static char GetTicks_doc[] = "Return number of ticks since bootup";
620 static PyObject *
621 MacOS_GetTicks(PyObject *self, PyObject *args)
623 return Py_BuildValue("i", (int)LMGetTicks());
626 static char openrf_doc[] = "Open resource fork of a file";
628 static PyObject *
629 MacOS_openrf(PyObject *self, PyObject *args)
631 OSErr err;
632 char *mode = "r";
633 FSSpec fss;
634 SignedByte permission = 1;
635 rfobject *fp;
637 if (!PyArg_ParseTuple(args, "O&|s", PyMac_GetFSSpec, &fss, &mode))
638 return NULL;
639 while (*mode) {
640 switch (*mode++) {
641 case '*': break;
642 case 'r': permission = 1; break;
643 case 'w': permission = 2; break;
644 case 'b': break;
645 default:
646 PyErr_BadArgument();
647 return NULL;
651 if ( (fp = newrfobject()) == NULL )
652 return NULL;
654 err = HOpenRF(fss.vRefNum, fss.parID, fss.name, permission, &fp->fRefNum);
656 if ( err == fnfErr ) {
657 /* In stead of doing complicated things here to get creator/type
658 ** correct we let the standard i/o library handle it
660 FILE *tfp;
661 char pathname[257];
663 if ( err=PyMac_GetFullPath(&fss, pathname) ) {
664 PyMac_Error(err);
665 Py_DECREF(fp);
666 return NULL;
669 if ( (tfp = fopen(pathname, "w")) == NULL ) {
670 PyMac_Error(fnfErr); /* What else... */
671 Py_DECREF(fp);
672 return NULL;
674 fclose(tfp);
675 err = HOpenRF(fss.vRefNum, fss.parID, fss.name, permission, &fp->fRefNum);
677 if ( err ) {
678 Py_DECREF(fp);
679 PyMac_Error(err);
680 return NULL;
682 fp->isclosed = 0;
683 return (PyObject *)fp;
686 static PyMethodDef MacOS_Methods[] = {
687 {"AcceptHighLevelEvent", MacOS_AcceptHighLevelEvent, 1, accepthle_doc},
688 {"GetCreatorAndType", MacOS_GetCreatorAndType, 1, getcrtp_doc},
689 {"SetCreatorAndType", MacOS_SetCreatorAndType, 1, setcrtp_doc},
690 #ifdef USE_STDWIN
691 {"SetHighLevelEventHandler", MacOS_SetHighLevelEventHandler, 1},
692 #endif
693 {"SchedParams", MacOS_SchedParams, 1, schedparams_doc},
694 {"EnableAppswitch", MacOS_EnableAppswitch, 1, appswitch_doc},
695 {"SetEventHandler", MacOS_SetEventHandler, 1, setevh_doc},
696 {"HandleEvent", MacOS_HandleEvent, 1, handleev_doc},
697 {"GetErrorString", MacOS_GetErrorString, 1, geterr_doc},
698 {"openrf", MacOS_openrf, 1, openrf_doc},
699 {"splash", MacOS_splash, 1, splash_doc},
700 {"DebugStr", MacOS_DebugStr, 1, DebugStr_doc},
701 {"GetTicks", MacOS_GetTicks, 1, GetTicks_doc},
702 {"SysBeep", MacOS_SysBeep, 1, SysBeep_doc},
703 {NULL, NULL} /* Sentinel */
707 void
708 MacOS_Init()
710 PyObject *m, *d;
712 m = Py_InitModule("MacOS", MacOS_Methods);
713 d = PyModule_GetDict(m);
715 /* Initialize MacOS.Error exception */
716 MacOS_Error = PyMac_GetOSErrException();
717 if (MacOS_Error == NULL || PyDict_SetItemString(d, "Error", MacOS_Error) != 0)
718 Py_FatalError("can't define MacOS.Error");
719 Rftype.ob_type = &PyType_Type;
720 Py_INCREF(&Rftype);
721 if (PyDict_SetItemString(d, "ResourceForkType", (PyObject *)&Rftype) != 0)
722 Py_FatalError("can't define MacOS.ResourceForkType");
724 ** This is a hack: the following constant added to the id() of a string
725 ** object gives you the address of the data. Unfortunately, it is needed for
726 ** some of the image and sound processing interfaces on the mac:-(
729 PyStringObject *p = 0;
730 long off = (long)&(p->ob_sval[0]);
732 if( PyDict_SetItemString(d, "string_id_to_buffer", Py_BuildValue("i", off)) != 0)
733 Py_FatalError("Can't define MacOS.string_id_to_buffer");