diff options
Diffstat (limited to 'Mac/Python/macimport.c')
-rw-r--r-- | Mac/Python/macimport.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/Mac/Python/macimport.c b/Mac/Python/macimport.c new file mode 100644 index 0000000..ce6b49e --- /dev/null +++ b/Mac/Python/macimport.c @@ -0,0 +1,416 @@ +/*********************************************************** +Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + + +#include "Python.h" + +#include "macglue.h" +#include "marshal.h" +#include "import.h" +#include "importdl.h" + +#include "pythonresources.h" + +#include <Types.h> +#include <Files.h> +#include <Resources.h> +#if 0 +#include <OSUtils.h> /* for Set(Current)A5 */ +#include <StandardFile.h> +#include <Memory.h> +#include <Windows.h> +#include <Traps.h> +#include <Processes.h> +#include <Fonts.h> +#include <Menus.h> +#include <TextUtils.h> +#endif +#include <CodeFragments.h> + +typedef void (*dl_funcptr)(); +#define FUNCNAME_PATTERN "init%.200s" + +/* +** findnamedresource - Common code for the various *ResourceModule functions. +** Check whether a file contains a resource of the correct name and type, and +** optionally return the value in it. +*/ +static int +findnamedresource( + PyStringObject *obj, + char *module, + char *filename, + OSType restype, + StringPtr dataptr) +{ + FSSpec fss; + FInfo finfo; + short oldrh, filerh; + int ok; + Handle h; + +#ifdef INTERN_STRINGS + /* + ** If we have interning find_module takes care of interning all + ** sys.path components. We then keep a record of all sys.path + ** components for which GetFInfo has failed (usually because the + ** component in question is a folder), and we don't try opening these + ** as resource files again. + */ +#define MAXPATHCOMPONENTS 32 + static PyStringObject *not_a_file[MAXPATHCOMPONENTS]; + static int max_not_a_file = 0; + int i; + + if (obj && obj->ob_sinterned ) { + for( i=0; i< max_not_a_file; i++ ) + if ( obj == not_a_file[i] ) + return 0; + } +#endif /* INTERN_STRINGS */ + + if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) { + /* + ** Special case: the application itself. Use a shortcut to + ** forestall opening and closing the application numerous times + ** (which is dead slow when running from CDROM) + */ + oldrh = CurResFile(); + UseResFile(PyMac_AppRefNum); + filerh = -1; + } else { + if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr || + FSpGetFInfo(&fss, &finfo) != noErr ) { +#ifdef INTERN_STRINGS + if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned ) + not_a_file[max_not_a_file++] = obj; +#endif /* INTERN_STRINGS */ + /* doesn't exist or is folder */ + return 0; + } + oldrh = CurResFile(); + filerh = FSpOpenResFile(&fss, fsRdPerm); + if ( filerh == -1 ) + return 0; + UseResFile(filerh); + } + if ( dataptr == NULL ) + SetResLoad(0); + h = Get1NamedResource(restype, Pstring(module)); + SetResLoad(1); + ok = (h != NULL); + if ( ok && dataptr != NULL ) { + HLock(h); + *dataptr = **h; + memcpy(dataptr+1, (*h)+1, (int)*dataptr); + HUnlock(h); + } + if ( filerh != -1 ) + CloseResFile(filerh); + UseResFile(oldrh); + return ok; +} + +/* +** Returns true if the argument has a resource fork, and it contains +** a 'PYC ' resource of the correct name +*/ +int +PyMac_FindResourceModule(obj, module, filename) +PyStringObject *obj; +char *module; +char *filename; +{ + int ok; + + ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0); + return ok; +} + +/* +** Returns true if the argument has a resource fork, and it contains +** a 'PYD ' resource of the correct name +*/ +int +PyMac_FindCodeResourceModule(obj, module, filename) +PyStringObject *obj; +char *module; +char *filename; +{ + int ok; + + ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0); + return ok; +} + + +/* +** Load the specified module from a code resource +*/ +PyObject * +PyMac_LoadCodeResourceModule(name, pathname) + char *name; + char *pathname; +{ + PyObject *m; + char funcname[258]; + char *lastdot, *shortname, *packagecontext; + dl_funcptr p = NULL; + Str255 fragmentname; + CFragConnectionID connID; + Ptr mainAddr; + Str255 errMessage; + OSErr err; + char buf[512]; + Ptr symAddr; + CFragSymbolClass class; + + if ((m = _PyImport_FindExtension(name, name)) != NULL) { + Py_INCREF(m); + return m; + } + lastdot = strrchr(name, '.'); + if (lastdot == NULL) { + packagecontext = NULL; + shortname = name; + } + else { + packagecontext = name; + shortname = lastdot+1; + } + sprintf(funcname, FUNCNAME_PATTERN, shortname); + if( !findnamedresource((PyStringObject *)0, shortname, pathname, 'PYD ', fragmentname)) { + PyErr_SetString(PyExc_ImportError, "PYD resource not found"); + return NULL; + } + + /* Load the fragment + (or return the connID if it is already loaded */ + err = GetSharedLibrary(fragmentname, kCompiledCFragArch, + kLoadCFrag, &connID, &mainAddr, + errMessage); + if ( err ) { + sprintf(buf, "%.*s: %.200s", + errMessage[0], errMessage+1, + PyMac_StrError(err)); + PyErr_SetString(PyExc_ImportError, buf); + return NULL; + } + /* Locate the address of the correct init function */ + err = FindSymbol(connID, Pstring(funcname), &symAddr, &class); + if ( err ) { + sprintf(buf, "%s: %.200s", + funcname, PyMac_StrError(err)); + PyErr_SetString(PyExc_ImportError, buf); + return NULL; + } + p = (dl_funcptr)symAddr; + if (p == NULL) { + PyErr_Format(PyExc_ImportError, + "dynamic module does not define init function (%.200s)", + funcname); + return NULL; + } + _Py_PackageContext = packagecontext; + (*p)(); + _Py_PackageContext = NULL; + if (PyErr_Occurred()) + return NULL; + if (_PyImport_FixupExtension(name, name) == NULL) + return NULL; + + m = PyDict_GetItemString(PyImport_GetModuleDict(), name); + if (m == NULL) { + PyErr_SetString(PyExc_SystemError, + "dynamic module not initialized properly"); + return NULL; + } +#if 0 + /* Remember the filename as the __file__ attribute */ + d = PyModule_GetDict(m); + s = PyString_FromString(pathname); + if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0) + PyErr_Clear(); /* Not important enough to report */ + Py_XDECREF(s); +#endif + if (Py_VerboseFlag) + fprintf(stderr, + "import %s # pyd fragment %#s loaded from %s\n", + name, fragmentname, pathname); + Py_INCREF(m); + return m; +} + +/* +** Load the specified module from a resource +*/ +PyObject * +PyMac_LoadResourceModule(module, filename) +char *module; +char *filename; +{ + FSSpec fss; + FInfo finfo; + short oldrh, filerh; + Handle h; + OSErr err; + PyObject *m, *co; + long num, size; + + if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) { + /* + ** Special case: the application itself. Use a shortcut to + ** forestall opening and closing the application numerous times + ** (which is dead slow when running from CDROM) + */ + oldrh = CurResFile(); + UseResFile(PyMac_AppRefNum); + filerh = -1; + } else { + if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr ) + goto error; + if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr ) + goto error; + oldrh = CurResFile(); + filerh = FSpOpenResFile(&fss, fsRdPerm); + if ( filerh == -1 ) { + err = ResError(); + goto error; + } + UseResFile(filerh); + } + h = Get1NamedResource('PYC ', Pstring(module)); + if ( h == NULL ) { + err = ResError(); + goto error; + } + HLock(h); + /* + ** XXXX The next few lines are intimately tied to the format of pyc + ** files. I'm not sure whether this code should be here or in import.c -- Jack + */ + size = GetHandleSize(h); + if ( size < 8 ) { + PyErr_SetString(PyExc_ImportError, "Resource too small"); + co = NULL; + } else { + num = (*h)[0] & 0xff; + num = num | (((*h)[1] & 0xff) << 8); + num = num | (((*h)[2] & 0xff) << 16); + num = num | (((*h)[3] & 0xff) << 24); + if ( num != PyImport_GetMagicNumber() ) { + PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource"); + co = NULL; + } else { + co = PyMarshal_ReadObjectFromString((*h)+8, size-8); + } + } + HUnlock(h); + if ( filerh != -1 ) + CloseResFile(filerh); + UseResFile(oldrh); + if ( co ) { + m = PyImport_ExecCodeModule(module, co); + Py_DECREF(co); + } else { + m = NULL; + } + if (Py_VerboseFlag) + fprintf(stderr, "import %s # pyc resource from %s\n", + module, filename); + return m; +error: + { + char buf[512]; + + sprintf(buf, "%s: %s", filename, PyMac_StrError(err)); + PyErr_SetString(PyExc_ImportError, buf); + return NULL; + } +} + +/* +** Look for a module in a single folder. Upon entry buf and len +** point to the folder to search, upon exit they refer to the full +** pathname of the module found (if any). +*/ +struct filedescr * +PyMac_FindModuleExtension(char *buf, int *lenp, char *module) +{ + struct filedescr *fdp; + unsigned char fnbuf[64]; + int modnamelen = strlen(module); + FSSpec fss; + short refnum; + long dirid; + + /* + ** Copy the module name to the buffer (already :-terminated) + ** We also copy the first suffix, if this matches immedeately we're + ** lucky and return immedeately. + */ + if ( !_PyImport_Filetab[0].suffix ) + return 0; + +#if 0 + /* Pre 1.5a4 */ + strcpy(buf+*lenp, module); + strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix); +#else + strcpy(buf+*lenp, _PyImport_Filetab[0].suffix); +#endif + if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr ) + return _PyImport_Filetab; + /* + ** We cannot check for fnfErr (unfortunately), it can mean either that + ** the file doesn't exist (fine, we try others) or the path leading to it. + */ + refnum = fss.vRefNum; + dirid = fss.parID; + if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */ + return 0; + /* + ** We now have the folder parameters. Setup the field for the filename + */ + if ( modnamelen > 54 ) return 0; /* Leave room for extension */ + strcpy((char *)fnbuf+1, module); + + for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) { + strcpy((char *)fnbuf+1+modnamelen, fdp->suffix); + fnbuf[0] = strlen((char *)fnbuf+1); + if (Py_VerboseFlag > 1) + fprintf(stderr, "# trying %s%s\n", buf, fdp->suffix); + if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) { + /* Found it. */ +#if 0 + strcpy(buf+*lenp+modnamelen, fdp->suffix); +#else + strcpy(buf+*lenp, fdp->suffix); +#endif + *lenp = strlen(buf); + return fdp; + } + } + return 0; +} |