Added 'list_only' option (and modified 'run()' to respect it).
[python/dscho.git] / Mac / Python / macimport.c
blobe079d2e5ee478e2d8775acf2107ed1f0ed764b5a
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 ******************************************************************/
26 #include "Python.h"
28 #include "macglue.h"
29 #include "marshal.h"
30 #include "import.h"
31 #include "importdl.h"
33 #include "pythonresources.h"
35 #include <Types.h>
36 #include <Files.h>
37 #include <Resources.h>
38 #if 0
39 #include <OSUtils.h> /* for Set(Current)A5 */
40 #include <StandardFile.h>
41 #include <Memory.h>
42 #include <Windows.h>
43 #include <Traps.h>
44 #include <Processes.h>
45 #include <Fonts.h>
46 #include <Menus.h>
47 #include <TextUtils.h>
48 #endif
49 #include <CodeFragments.h>
51 #ifdef USE_GUSI
52 #include "TFileSpec.h" /* for Path2FSSpec() */
53 #endif
55 typedef void (*dl_funcptr)();
56 #define FUNCNAME_PATTERN "init%.200s"
59 ** findnamedresource - Common code for the various *ResourceModule functions.
60 ** Check whether a file contains a resource of the correct name and type, and
61 ** optionally return the value in it.
63 static int
64 findnamedresource(
65 PyStringObject *obj,
66 char *module,
67 char *filename,
68 OSType restype,
69 StringPtr dataptr)
71 FSSpec fss;
72 FInfo finfo;
73 short oldrh, filerh;
74 int ok;
75 Handle h;
77 #ifdef INTERN_STRINGS
79 ** If we have interning find_module takes care of interning all
80 ** sys.path components. We then keep a record of all sys.path
81 ** components for which GetFInfo has failed (usually because the
82 ** component in question is a folder), and we don't try opening these
83 ** as resource files again.
85 #define MAXPATHCOMPONENTS 32
86 static PyStringObject *not_a_file[MAXPATHCOMPONENTS];
87 static int max_not_a_file = 0;
88 int i;
90 if (obj && obj->ob_sinterned ) {
91 for( i=0; i< max_not_a_file; i++ )
92 if ( obj == not_a_file[i] )
93 return 0;
95 #endif /* INTERN_STRINGS */
97 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
99 ** Special case: the application itself. Use a shortcut to
100 ** forestall opening and closing the application numerous times
101 ** (which is dead slow when running from CDROM)
103 oldrh = CurResFile();
104 UseResFile(PyMac_AppRefNum);
105 filerh = -1;
106 } else {
107 #ifdef USE_GUSI
108 if ( Path2FSSpec(filename, &fss) != noErr ||
109 #else
110 if ( FSMakeFSSpec(0, 0, Pstring(filename), &fss) != noErr ||
111 #endif
112 FSpGetFInfo(&fss, &finfo) != noErr ) {
113 #ifdef INTERN_STRINGS
114 if ( obj && max_not_a_file < MAXPATHCOMPONENTS && obj->ob_sinterned )
115 not_a_file[max_not_a_file++] = obj;
116 #endif /* INTERN_STRINGS */
117 /* doesn't exist or is folder */
118 return 0;
120 oldrh = CurResFile();
121 filerh = FSpOpenResFile(&fss, fsRdPerm);
122 if ( filerh == -1 )
123 return 0;
124 UseResFile(filerh);
126 if ( dataptr == NULL )
127 SetResLoad(0);
128 h = Get1NamedResource(restype, Pstring(module));
129 SetResLoad(1);
130 ok = (h != NULL);
131 if ( ok && dataptr != NULL ) {
132 HLock(h);
133 /* XXXX Unsafe if resource not correctly formatted! */
134 #ifdef __CFM68K__
135 /* for cfm68k we take the second pstring */
136 *dataptr = *((*h)+(**h)+1);
137 memcpy(dataptr+1, (*h)+(**h)+2, (int)*dataptr);
138 #else
139 /* for ppc we take the first pstring */
140 *dataptr = **h;
141 memcpy(dataptr+1, (*h)+1, (int)*dataptr);
142 #endif
143 HUnlock(h);
145 if ( filerh != -1 )
146 CloseResFile(filerh);
147 UseResFile(oldrh);
148 return ok;
152 ** Returns true if the argument has a resource fork, and it contains
153 ** a 'PYC ' resource of the correct name
156 PyMac_FindResourceModule(obj, module, filename)
157 PyStringObject *obj;
158 char *module;
159 char *filename;
161 int ok;
163 ok = findnamedresource(obj, module, filename, 'PYC ', (StringPtr)0);
164 return ok;
168 ** Returns true if the argument has a resource fork, and it contains
169 ** a 'PYD ' resource of the correct name
172 PyMac_FindCodeResourceModule(obj, module, filename)
173 PyStringObject *obj;
174 char *module;
175 char *filename;
177 int ok;
179 ok = findnamedresource(obj, module, filename, 'PYD ', (StringPtr)0);
180 return ok;
185 ** Load the specified module from a code resource
187 PyObject *
188 PyMac_LoadCodeResourceModule(name, pathname)
189 char *name;
190 char *pathname;
192 PyObject *m, *d, *s;
193 char funcname[258];
194 char *lastdot, *shortname, *packagecontext;
195 dl_funcptr p = NULL;
196 Str255 fragmentname;
197 CFragConnectionID connID;
198 Ptr mainAddr;
199 Str255 errMessage;
200 OSErr err;
201 char buf[512];
202 Ptr symAddr;
203 CFragSymbolClass class;
205 if ((m = _PyImport_FindExtension(name, name)) != NULL) {
206 Py_INCREF(m);
207 return m;
209 lastdot = strrchr(name, '.');
210 if (lastdot == NULL) {
211 packagecontext = NULL;
212 shortname = name;
214 else {
215 packagecontext = name;
216 shortname = lastdot+1;
218 sprintf(funcname, FUNCNAME_PATTERN, shortname);
219 if( !findnamedresource((PyStringObject *)0, shortname, pathname, 'PYD ', fragmentname)) {
220 PyErr_SetString(PyExc_ImportError, "PYD resource not found");
221 return NULL;
224 /* Load the fragment
225 (or return the connID if it is already loaded */
226 err = GetSharedLibrary(fragmentname, kCompiledCFragArch,
227 kLoadCFrag, &connID, &mainAddr,
228 errMessage);
229 if ( err ) {
230 sprintf(buf, "%.*s: %.200s",
231 errMessage[0], errMessage+1,
232 PyMac_StrError(err));
233 PyErr_SetString(PyExc_ImportError, buf);
234 return NULL;
236 /* Locate the address of the correct init function */
237 err = FindSymbol(connID, Pstring(funcname), &symAddr, &class);
238 if ( err ) {
239 sprintf(buf, "%s: %.200s",
240 funcname, PyMac_StrError(err));
241 PyErr_SetString(PyExc_ImportError, buf);
242 return NULL;
244 p = (dl_funcptr)symAddr;
245 if (p == NULL) {
246 PyErr_Format(PyExc_ImportError,
247 "dynamic module does not define init function (%.200s)",
248 funcname);
249 return NULL;
251 _Py_PackageContext = packagecontext;
252 (*p)();
253 _Py_PackageContext = NULL;
254 if (PyErr_Occurred())
255 return NULL;
256 if (_PyImport_FixupExtension(name, name) == NULL)
257 return NULL;
259 m = PyDict_GetItemString(PyImport_GetModuleDict(), name);
260 if (m == NULL) {
261 PyErr_SetString(PyExc_SystemError,
262 "dynamic module not initialized properly");
263 return NULL;
265 #if 1
266 /* Remember the filename as the __file__ attribute */
267 d = PyModule_GetDict(m);
268 s = PyString_FromString(pathname);
269 if (s == NULL || PyDict_SetItemString(d, "__file__", s) != 0)
270 PyErr_Clear(); /* Not important enough to report */
271 Py_XDECREF(s);
272 #endif
273 if (Py_VerboseFlag)
274 PySys_WriteStderr("import %s # pyd fragment %#s loaded from %s\n",
275 name, fragmentname, pathname);
276 Py_INCREF(m);
277 return m;
281 ** Load the specified module from a resource
283 PyObject *
284 PyMac_LoadResourceModule(module, filename)
285 char *module;
286 char *filename;
288 FSSpec fss;
289 FInfo finfo;
290 short oldrh, filerh;
291 Handle h;
292 OSErr err;
293 PyObject *m, *co;
294 long num, size;
296 if ( strcmp(filename, PyMac_ApplicationPath) == 0 ) {
298 ** Special case: the application itself. Use a shortcut to
299 ** forestall opening and closing the application numerous times
300 ** (which is dead slow when running from CDROM)
302 oldrh = CurResFile();
303 UseResFile(PyMac_AppRefNum);
304 filerh = -1;
305 } else {
306 #ifdef USE_GUSI
307 if ( (err=Path2FSSpec(filename, &fss)) != noErr ||
308 FSpGetFInfo(&fss, &finfo) != noErr )
309 #else
310 if ( (err=FSMakeFSSpec(0, 0, Pstring(filename), &fss)) != noErr )
311 #endif
312 goto error;
313 if ( (err=FSpGetFInfo(&fss, &finfo)) != noErr )
314 goto error;
315 oldrh = CurResFile();
316 filerh = FSpOpenResFile(&fss, fsRdPerm);
317 if ( filerh == -1 ) {
318 err = ResError();
319 goto error;
321 UseResFile(filerh);
323 h = Get1NamedResource('PYC ', Pstring(module));
324 if ( h == NULL ) {
325 err = ResError();
326 goto error;
328 HLock(h);
330 ** XXXX The next few lines are intimately tied to the format of pyc
331 ** files. I'm not sure whether this code should be here or in import.c -- Jack
333 size = GetHandleSize(h);
334 if ( size < 8 ) {
335 PyErr_SetString(PyExc_ImportError, "Resource too small");
336 co = NULL;
337 } else {
338 num = (*h)[0] & 0xff;
339 num = num | (((*h)[1] & 0xff) << 8);
340 num = num | (((*h)[2] & 0xff) << 16);
341 num = num | (((*h)[3] & 0xff) << 24);
342 if ( num != PyImport_GetMagicNumber() ) {
343 PyErr_SetString(PyExc_ImportError, "Bad MAGIC in resource");
344 co = NULL;
345 } else {
346 co = PyMarshal_ReadObjectFromString((*h)+8, size-8);
348 ** Normally, byte 4-7 are the time stamp, but that is not used
349 ** for 'PYC ' resources. We abuse byte 4 as a flag to indicate
350 ** that it is a package rather than an ordinary module.
351 ** See also py_resource.py. (jvr)
353 if ((*h)[4] & 0xff) {
354 /* it's a package */
355 /* Set __path__ to the package name */
356 PyObject *d, *s;
357 int err;
359 m = PyImport_AddModule(module);
360 if (m == NULL) {
361 co = NULL;
362 goto packageerror;
364 d = PyModule_GetDict(m);
365 s = PyString_InternFromString(module);
366 if (s == NULL) {
367 co = NULL;
368 goto packageerror;
370 err = PyDict_SetItemString(d, "__path__", s);
371 Py_DECREF(s);
372 if (err != 0) {
373 co = NULL;
374 goto packageerror;
379 packageerror:
380 HUnlock(h);
381 if ( filerh != -1 )
382 CloseResFile(filerh);
383 UseResFile(oldrh);
384 if ( co ) {
385 m = PyImport_ExecCodeModuleEx(module, co, "<pyc resource>");
386 Py_DECREF(co);
387 } else {
388 m = NULL;
390 if (Py_VerboseFlag)
391 PySys_WriteStderr("import %s # pyc resource from %s\n",
392 module, filename);
393 return m;
394 error:
396 char buf[512];
398 sprintf(buf, "%s: %s", filename, PyMac_StrError(err));
399 PyErr_SetString(PyExc_ImportError, buf);
400 return NULL;
405 ** Look for a module in a single folder. Upon entry buf and len
406 ** point to the folder to search, upon exit they refer to the full
407 ** pathname of the module found (if any).
409 struct filedescr *
410 PyMac_FindModuleExtension(char *buf, int *lenp, char *module)
412 struct filedescr *fdp;
413 unsigned char fnbuf[64];
414 int modnamelen = strlen(module);
415 FSSpec fss;
416 FInfo finfo;
417 short refnum;
418 long dirid;
421 ** Copy the module name to the buffer (already :-terminated)
422 ** We also copy the first suffix, if this matches immedeately we're
423 ** lucky and return immedeately.
425 if ( !_PyImport_Filetab[0].suffix )
426 return 0;
428 #if 0
429 /* Pre 1.5a4 */
430 strcpy(buf+*lenp, module);
431 strcpy(buf+*lenp+modnamelen, _PyImport_Filetab[0].suffix);
432 #else
433 strcpy(buf+*lenp, _PyImport_Filetab[0].suffix);
434 #endif
435 #ifdef USE_GUSI
436 if ( Path2FSSpec(buf, &fss) == noErr &&
437 FSpGetFInfo(&fss, &finfo) == noErr)
438 return _PyImport_Filetab;
439 #else
440 if ( FSMakeFSSpec(0, 0, Pstring(buf), &fss) == noErr )
441 return _PyImport_Filetab;
442 #endif
444 ** We cannot check for fnfErr (unfortunately), it can mean either that
445 ** the file doesn't exist (fine, we try others) or the path leading to it.
447 refnum = fss.vRefNum;
448 dirid = fss.parID;
449 if ( refnum == 0 || dirid == 0 ) /* Fail on nonexistent dir */
450 return 0;
452 ** We now have the folder parameters. Setup the field for the filename
454 if ( modnamelen > 54 ) return 0; /* Leave room for extension */
455 strcpy((char *)fnbuf+1, module);
457 for( fdp = _PyImport_Filetab+1; fdp->suffix; fdp++ ) {
458 strcpy((char *)fnbuf+1+modnamelen, fdp->suffix);
459 fnbuf[0] = strlen((char *)fnbuf+1);
460 if (Py_VerboseFlag > 1)
461 PySys_WriteStderr("# trying %s%s\n", buf, fdp->suffix);
462 if ( FSMakeFSSpec(refnum, dirid, fnbuf, &fss) == noErr ) {
463 /* Found it. */
464 #if 0
465 strcpy(buf+*lenp+modnamelen, fdp->suffix);
466 #else
467 strcpy(buf+*lenp, fdp->suffix);
468 #endif
469 *lenp = strlen(buf);
470 return fdp;
473 return 0;