Implement PEP 235: Import on Case-Insensitive Platforms.

http://python.sourceforge.net/peps/pep-0235.html

Renamed check_case to case_ok.  Substantial code rearrangement to get
this stuff in one place in the file.  Innermost loop of find_module()
now much simpler and #ifdef-free, and I want to keep it that way (it's
bad enough that the innermost loop is itself still in an #ifdef!).

Windows semantics tested and are fine.

Jason, Cygwin *should* be fine if and only if what you did before "worked"
for case_ok.

Jack, the semantics on your flavor of Mac have definitely changed (see
the PEP), and need to be tested.  The intent is that your flavor of Mac
now work the same as everything else in the "lower left" box, including
respecting PYTHONCASEOK.

Steven, sorry, you did the most work here so far but you got screwed the
worst.  Happy to work with you on repairing it, but I don't understand
anything about all your Mac variants.  We need to add another branch (or
two, three, ...?) inside case_ok.  But we should not need to change
anything else.
This commit is contained in:
Tim Peters 2001-02-28 05:34:27 +00:00
parent 6e7e485d5d
commit 50d8d37b3f
1 changed files with 86 additions and 137 deletions

View File

@ -830,13 +830,10 @@ extern FILE *PyWin_FindRegisteredModule(const char *, struct filedescr **,
char *, int);
#endif
#ifdef CHECK_IMPORT_CASE
static int check_case(char *, int, int, char *);
#endif
static int case_ok(char *, int, int, char *);
static int find_init_module(char *); /* Forward */
#ifdef HAVE_DIRENT_H
#if 0 /* XXX was #ifdef HAVE_DIRENT_H; resolve whether we really need this */
static int MatchFilename(char *pathname, char *filename);
@ -974,18 +971,17 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen,
buf[len++] = SEP;
strcpy(buf+len, name);
len += namelen;
/* Check for package import (buf holds a directory name,
and there's an __init__ module in that directory */
#ifdef HAVE_STAT
if (stat(buf, &statbuf) == 0) {
if (S_ISDIR(statbuf.st_mode)) {
if (find_init_module(buf)) {
#ifdef CHECK_IMPORT_CASE
if (!check_case(buf, len, namelen,
name))
return NULL;
#endif
return &fd_package;
}
}
if (stat(buf, &statbuf) == 0 &&
S_ISDIR(statbuf.st_mode) &&
find_init_module(buf)) {
if (case_ok(buf, len, namelen, name))
return &fd_package;
else
return NULL;
}
#else
/* XXX How are you going to test for directories? */
@ -1000,27 +996,14 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen,
if (Py_VerboseFlag > 1)
PySys_WriteStderr("# trying %s\n", buf);
fp = fopen(buf, fdp->mode);
#ifdef HAVE_DIRENT_H
if (fp != NULL) { /* check case */
char *curpath = PyString_AsString(v);
char *nstart = buf + strlen(curpath);
if (*nstart == SEP)
nstart++;
if (MatchFilename(curpath, nstart)) {
break; /* Found */
if (fp != NULL) {
if (case_ok(buf, len, namelen, name))
break;
else { /* continue search */
fclose(fp);
fp = NULL;
}
fclose(fp); /* No. Close & continue search */
fp = NULL;
if (Py_VerboseFlag > 1)
PySys_WriteStderr(
"# case mismatch for %s: %s\n",
name, buf);
}
#else /* !HAVE_DIRENT_H */
if (fp != NULL)
break;
#endif /* HAVE_DIRENT_H */
}
#endif /* !macintosh */
if (fp != NULL)
@ -1031,62 +1014,62 @@ find_module(char *realname, PyObject *path, char *buf, size_t buflen,
"No module named %.200s", name);
return NULL;
}
#ifdef CHECK_IMPORT_CASE
if (!check_case(buf, len, namelen, name)) {
fclose(fp);
return NULL;
}
#endif
*p_fp = fp;
return fdp;
}
#ifdef CHECK_IMPORT_CASE
/* case_ok(buf, len, namelen, name)
* We've already done a successful stat() or fopen() on buf (a path of length
* len; can not assume there's a trailing null). name is the last component
* of then path (a string of length namelen, exclusive of trailing null).
* case_ok() is to return 1 if there's a case-sensitive match for
* name, else 0. case_ok() is also to return 1 if envar PYTHONCASEOK
* exists.
* case_ok() is used to implement case-sensitive import semantics even
* on platforms with case-insensitive filesystems. It's trivial to implement
* for case-sensitive filesystems. It's pretty much a cross-platform
* nightmare for systems with case-insensitive filesystems.
*/
/* First we may need a pile of platform-specific header files; the sequence
* of #if's here should match the sequence in the body of case_ok().
*/
#if defined(MS_WIN32) || defined(__CYGWIN__)
#include <windows.h>
#include <ctype.h>
static int
allcaps8x3(char *s)
{
/* Return 1 if s is an 8.3 filename in ALLCAPS */
char c;
char *dot = strchr(s, '.');
char *end = strchr(s, '\0');
if (dot != NULL) {
if (dot-s > 8)
return 0; /* More than 8 before '.' */
if (end-dot > 4)
return 0; /* More than 3 after '.' */
end = strchr(dot+1, '.');
if (end != NULL)
return 0; /* More than one dot */
}
else if (end-s > 8)
return 0; /* More than 8 and no dot */
while ((c = *s++)) {
if (islower(c))
return 0;
}
return 1;
}
#ifdef __CYGWIN__
#include <sys/cygwin.h>
#endif
#elif defined(DJGPP)
#include <dir.h>
#elif defined(macintosh)
#include <TextUtils.h>
#ifdef USE_GUSI1
#include "TFileSpec.h" /* for Path2FSSpec() */
#endif
#endif
static int
check_case(char *buf, int len, int namelen, char *name)
case_ok(char *buf, int len, int namelen, char *name)
{
/* Pick a platform-specific implementation; the sequence of #if's here should
* match the sequence just above.
*/
/* MS_WIN32 || __CYGWIN__ */
#if defined(MS_WIN32) || defined(__CYGWIN__)
WIN32_FIND_DATA data;
HANDLE h;
#ifdef __CYGWIN__
char tempbuf[MAX_PATH];
#endif
if (getenv("PYTHONCASEOK") != NULL)
return 1;
#ifdef __CYGWIN__
cygwin32_conv_to_win32_path(buf, tempbuf);
h = FindFirstFile(tempbuf, &data);
@ -1100,35 +1083,33 @@ check_case(char *buf, int len, int namelen, char *name)
return 0;
}
FindClose(h);
if (allcaps8x3(data.cFileName)) {
/* Skip the test if the filename is ALL.CAPS. This can
happen in certain circumstances beyond our control,
e.g. when software is installed under NT on a FAT
filesystem and then the same FAT filesystem is used
under Windows 95. */
return strncmp(data.cFileName, name, namelen) == 0;
/* DJGPP */
#elif defined(DJGPP)
struct ffblk ffblk;
int done;
if (getenv("PYTHONCASEOK") != NULL)
return 1;
}
if (strncmp(data.cFileName, name, namelen) != 0) {
strcpy(buf+len-namelen, data.cFileName);
done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC);
if (done) {
PyErr_Format(PyExc_NameError,
"Case mismatch for module name %.100s\n(filename %.300s)",
"Can't find file for module %.100s\n(filename %.300s)",
name, buf);
return 0;
}
return 1;
}
#endif /* MS_WIN32 */
return strncmp(ffblk.ff_name, name, namelen) == 0;
#ifdef macintosh
#include <TextUtils.h>
#ifdef USE_GUSI1
#include "TFileSpec.h" /* for Path2FSSpec() */
#endif
static int
check_case(char *buf, int len, int namelen, char *name)
{
/* macintosh */
#elif defined(macintosh)
FSSpec fss;
OSErr err;
if (getenv("PYTHONCASEOK") != NULL)
return 1;
#ifndef USE_GUSI1
err = FSMakeFSSpec(0, 0, Pstring(buf), &fss);
#else
@ -1154,48 +1135,16 @@ check_case(char *buf, int len, int namelen, char *name)
name, buf);
return 0;
}
if (namelen > fss.name[0] ||
strncmp(name, (char *)fss.name+1, namelen) != 0) {
PyErr_Format(PyExc_NameError,
"Case mismatch for module name %.100s\n(filename %.300s)",
name, fss.name);
return 0;
}
return fss.name[0] >= namelen &&
strncmp(name, (char *)fss.name+1, namelen) == 0;
/* assuming it's a case-sensitive filesystem, so there's nothing to do! */
#else
return 1;
}
#endif /* macintosh */
#ifdef DJGPP
#include <dir.h>
static int
check_case(char *buf, int len, int namelen, char *name)
{
struct ffblk ffblk;
int done;
if (getenv("PYTHONCASEOK") != NULL)
return 1;
done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC);
if (done) {
PyErr_Format(PyExc_NameError,
"Can't find file for module %.100s\n(filename %.300s)",
name, buf);
return 0;
}
if (strncmp(ffblk.ff_name, name, namelen) != 0) {
strcpy(buf+len-namelen, ffblk.ff_name);
PyErr_Format(PyExc_NameError,
"Case mismatch for module name %.100s\n(filename %.300s)",
name, buf);
return 0;
}
return 1;
}
#endif
}
#endif /* CHECK_IMPORT_CASE */
#ifdef HAVE_STAT
/* Helper to look for __init__.py or __init__.py[co] in potential package */