diff Mac/Python/macimport.c @ 8665:f594778a56af legacy-trunk

All import-related code has moved to macimport.c. There's also new support for importing code fragments: if a file on sys.path contains a PYD resource with resourcename equal to the name of the module to be imported this PYD resource should contain a (pascal) string with the name of a code fragment to load. This allows freezing Python programs without access to source or a development environment.
author Jack Jansen <jack.jansen@cwi.nl>
date Mon, 13 Jul 1998 13:37:12 +0000
parents
children d32dbc202613
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Mac/Python/macimport.c	Mon Jul 13 13:37:12 1998 +0000
@@ -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;
+}