Issue 1267, continued.

Additional patch by Christian Heimes to deal more cleanly with the
FILE* vs file-descriptor issues.
I cleaned up his code a bit, and moved the lseek() call into import.c.
This commit is contained in:
Guido van Rossum 2007-10-22 00:09:51 +00:00
parent c2954e5273
commit 40d20bcf1f
12 changed files with 94 additions and 64 deletions

View file

@ -2410,31 +2410,23 @@ change in future releases of Python.
:ctype:`PyFileObject`. :ctype:`PyFileObject`.
.. cfunction:: PyObject* PyFile_FromString(char *filename, char *mode) .. cfunction:: PyFile_FromFd(int fd, char *name, char *mode, int buffering, char *encoding, char *newline)
.. index:: single: fopen() Create a new :ctype:`PyFileObject` from the file descriptor of an already
opened file *fd*. The arguments *name*, *encoding* and *newline* can be
*NULL* as well as buffering can be *-1* to use the defaults. Return *NULL* on
failure.
On success, return a new file object that is opened on the file given by .. warning::
*filename*, with a file mode given by *mode*, where *mode* has the same
semantics as the standard C routine :cfunc:`fopen`. On failure, return *NULL*. Take care when you are mixing streams and descriptors! For more
information, see `GNU C Library
<http://www.gnu.org/software/libc/manual/html_node/Stream_002fDescriptor-Precautions.html#Stream_002fDescriptor-Precautions>`_.
.. cfunction:: PyObject* PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE*)) .. cfunction:: int PyObject_AsFileDescriptor(PyObject *p)
Create a new :ctype:`PyFileObject` from the already-open standard C file Return the file descriptor associated with *p* as an :ctype:`int`.
pointer, *fp*. The function *close* will be called when the file should be
closed. Return *NULL* on failure.
.. cfunction:: PyFile_FromFileEx(FILE *fp, char *name, char *mode, int (*close)(FILE *), int buffering, char *encoding, char *newline)
Create a new :ctype:`PyFileObject` from the already-open standard C file
pointer, *fp*. The functions works similar to *PyFile_FromFile* but takes
optional arguments for *buffering*, *encoding* and *newline*. Use -1 resp.
*NULL* for default values.
.. cfunction:: FILE* PyFile_AsFile(PyObject *p)
Return the file object associated with *p* as a :ctype:`FILE\*`.
.. cfunction:: PyObject* PyFile_GetLine(PyObject *p, int n) .. cfunction:: PyObject* PyFile_GetLine(PyObject *p, int n)

View file

@ -60,7 +60,7 @@ Python for .NET
This implementation actually uses the CPython implementation, but is a managed This implementation actually uses the CPython implementation, but is a managed
.NET application and makes .NET libraries available. This was created by Brian .NET application and makes .NET libraries available. This was created by Brian
Lloyd. For more information, see the `Python for .NET home page Lloyd. For more information, see the `Python for .NET home page
<http://www.zope.org/Members/Brian/PythonNet>`_. <http://pythonnet.sourceforge.net>`_.
IronPython IronPython
An alternate Python for .NET. Unlike Python.NET, this is a complete Python An alternate Python for .NET. Unlike Python.NET, this is a complete Python

View file

@ -8,10 +8,7 @@ extern "C" {
#define PY_STDIOTEXTMODE "b" #define PY_STDIOTEXTMODE "b"
PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *, int (*)(FILE*)); PyAPI_FUNC(PyObject *) PyFile_FromFd(int, char *, char *, int, char *, char *);
PyAPI_FUNC(PyObject *) PyFile_FromFileEx(FILE *, char *, char *,
int (*)(FILE *), int, char *,
char *);
PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int); PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int);
PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int); PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *); PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *);

View file

@ -44,6 +44,23 @@ class ImportTests(unittest.TestCase):
fd = imp.find_module("heapq")[0] fd = imp.find_module("heapq")[0]
self.assertEqual(fd.encoding, "iso-8859-1") self.assertEqual(fd.encoding, "iso-8859-1")
def test_issue1267(self):
fp, filename, info = imp.find_module("pydoc")
self.assertNotEqual(fp, None)
self.assertEqual(fp.encoding, "iso-8859-1")
self.assertEqual(fp.tell(), 0)
self.assertEqual(fp.readline(), '#!/usr/bin/env python\n')
fp.close()
fp, filename, info = imp.find_module("tokenize")
self.assertNotEqual(fp, None)
self.assertEqual(fp.encoding, "utf-8")
self.assertEqual(fp.tell(), 0)
self.assertEqual(fp.readline(),
'"""Tokenization help for Python programs.\n')
fp.close()
def test_main(): def test_main():
test_support.run_unittest( test_support.run_unittest(
LockTests, LockTests,

View file

@ -8,6 +8,18 @@ What's New in Python 3.0a2?
*Unreleased* *Unreleased*
Core and Builtins
-----------------
- Replaced `PyFile_FromFile()` with `PyFile_FromFd(fd, name. mode, buffer,
encoding, newline)`
- Fixed `imp.find_module()` to obey the -*- coding: -*- header.
- Changed `__file__` and `co_filename` to unicode. The path names are decoded
with `Py_FileSystemDefaultEncoding` and a new API method
`PyUnicode_DecodeFSDefault(char*)` was added.
Extension Modules Extension Modules
----------------- -----------------

View file

@ -5386,11 +5386,18 @@ static PyObject *
posix_tmpfile(PyObject *self, PyObject *noargs) posix_tmpfile(PyObject *self, PyObject *noargs)
{ {
FILE *fp; FILE *fp;
int fd;
fp = tmpfile(); fp = tmpfile();
if (fp == NULL) if (fp == NULL)
return posix_error(); return posix_error();
return PyFile_FromFile(fp, "<tmpfile>", "w+b", fclose); fd = fileno(fp);
if (fd != -1)
fd = dup(fd);
fclose(fp);
if (fd == -1)
return posix_error();
return PyFile_FromFd(fd, "<tmpfile>", "w+b", -1, NULL, NULL);
} }
#endif #endif

View file

@ -1214,7 +1214,7 @@ _bytes_tailmatch(PyBytesObject *self, PyObject *substr, Py_ssize_t start,
Py_ssize_t len = PyBytes_GET_SIZE(self); Py_ssize_t len = PyBytes_GET_SIZE(self);
const char* str; const char* str;
Py_buffer vsubstr; Py_buffer vsubstr;
int rv; int rv = 0;
str = PyBytes_AS_STRING(self); str = PyBytes_AS_STRING(self);
@ -1226,13 +1226,11 @@ _bytes_tailmatch(PyBytesObject *self, PyObject *substr, Py_ssize_t start,
if (direction < 0) { if (direction < 0) {
/* startswith */ /* startswith */
if (start+vsubstr.len > len) { if (start+vsubstr.len > len) {
rv = 0;
goto done; goto done;
} }
} else { } else {
/* endswith */ /* endswith */
if (end-start < vsubstr.len || start > len) { if (end-start < vsubstr.len || start > len) {
rv = 0;
goto done; goto done;
} }

View file

@ -26,22 +26,16 @@ extern "C" {
/* External C interface */ /* External C interface */
PyObject * PyObject *
PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *)) PyFile_FromFd(int fd, char *name, char *mode, int buffering, char *encoding,
char *newline)
{ {
return PyFile_FromFileEx(fp, name, mode, close, -1, NULL, NULL); PyObject *io, *stream, *nameobj = NULL;
}
PyObject *
PyFile_FromFileEx(FILE *fp, char *name, char *mode, int (*close)(FILE *),
int buffering, char *encoding, char *newline)
{
PyObject *io, *stream, *nameobj=NULL;
io = PyImport_ImportModule("io"); io = PyImport_ImportModule("io");
if (io == NULL) if (io == NULL)
return NULL; return NULL;
stream = PyObject_CallMethod(io, "open", "isiss", fileno(fp), mode, stream = PyObject_CallMethod(io, "open", "isiss", fd, mode,
buffering, encoding, newline); buffering, encoding, newline);
Py_DECREF(io); Py_DECREF(io);
if (stream == NULL) if (stream == NULL)
return NULL; return NULL;

View file

@ -1602,40 +1602,44 @@ PyTokenizer_RestoreEncoding(struct tok_state* tok, int len, int *offset)
} }
#endif #endif
/* Get -*- encoding -*- from a Python file /* Get -*- encoding -*- from a Python file.
PyTokenizer_FindEncoding returns NULL when it can't find the encoding in PyTokenizer_FindEncoding returns NULL when it can't find the encoding in
the first or second line of the file (in which case the encoding the first or second line of the file (in which case the encoding
should be assumed to be PyUnicode_GetDefaultEncoding()). should be assumed to be PyUnicode_GetDefaultEncoding()).
The char * returned was malloc'ed from PyMem_MALLOC() and thus must be freed The char * returned is malloc'ed via PyMem_MALLOC() and thus must be freed
when no longer needed. by the caller.
*/ */
char * char *
PyTokenizer_FindEncoding(FILE *fp) { PyTokenizer_FindEncoding(int fd)
{
struct tok_state *tok; struct tok_state *tok;
char *p_start=NULL, *p_end=NULL, *encoding=NULL; FILE *fp;
char *p_start =NULL , *p_end =NULL , *encoding = NULL;
if ((tok = PyTokenizer_FromFile(fp, NULL, NULL, NULL)) == NULL) { fd = dup(fd);
/* lseek() usage is on purpose; see note later in code. */ if (fd < 0) {
lseek(fileno(fp), 0, 0);
return NULL; return NULL;
} }
while(((tok->lineno < 2) && (tok->done == E_OK))) { fp = fdopen(fd, "r");
if (fp == NULL) {
return NULL;
}
tok = PyTokenizer_FromFile(fp, NULL, NULL, NULL);
if (tok == NULL) {
fclose(fp);
return NULL;
}
while (tok->lineno < 2 && tok->done == E_OK) {
PyTokenizer_Get(tok, &p_start, &p_end); PyTokenizer_Get(tok, &p_start, &p_end);
} }
fclose(fp);
/* lseek() must be used instead of fseek()/rewind() as those fail on
OS X 10.4 to properly seek back to the beginning when reading from
the file descriptor instead of the file pointer. */
lseek(fileno(fp), 0, 0);
if (tok->encoding) { if (tok->encoding) {
encoding = (char *)PyMem_MALLOC(strlen(tok->encoding) + 1); encoding = (char *)PyMem_MALLOC(strlen(tok->encoding) + 1);
strcpy(encoding, tok->encoding); strcpy(encoding, tok->encoding);
} }
PyTokenizer_Free(tok); PyTokenizer_Free(tok);
return encoding; return encoding;
} }

View file

@ -67,7 +67,7 @@ extern void PyTokenizer_Free(struct tok_state *);
extern int PyTokenizer_Get(struct tok_state *, char **, char **); extern int PyTokenizer_Get(struct tok_state *, char **, char **);
extern char * PyTokenizer_RestoreEncoding(struct tok_state* tok, extern char * PyTokenizer_RestoreEncoding(struct tok_state* tok,
int len, int *offset); int len, int *offset);
extern char * PyTokenizer_FindEncoding(FILE *fp); extern char * PyTokenizer_FindEncoding(int);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -92,7 +92,7 @@ static PyObject *extensions = NULL;
extern struct _inittab _PyImport_Inittab[]; extern struct _inittab _PyImport_Inittab[];
/* Method from Parser/tokenizer.c */ /* Method from Parser/tokenizer.c */
extern char * PyTokenizer_FindEncoding(FILE *fp); extern char * PyTokenizer_FindEncoding(int);
struct _inittab *PyImport_Inittab = _PyImport_Inittab; struct _inittab *PyImport_Inittab = _PyImport_Inittab;
@ -2561,6 +2561,7 @@ call_find_module(char *name, PyObject *path)
struct filedescr *fdp; struct filedescr *fdp;
char pathname[MAXPATHLEN+1]; char pathname[MAXPATHLEN+1];
FILE *fp = NULL; FILE *fp = NULL;
int fd = -1;
char *found_encoding = NULL; char *found_encoding = NULL;
char *encoding = NULL; char *encoding = NULL;
@ -2571,17 +2572,25 @@ call_find_module(char *name, PyObject *path)
if (fdp == NULL) if (fdp == NULL)
return NULL; return NULL;
if (fp != NULL) { if (fp != NULL) {
fd = fileno(fp);
if (fd != -1)
fd = dup(fd);
fclose(fp);
fp = NULL;
}
if (fd != -1) {
if (strchr(fdp->mode, 'b') == NULL) { if (strchr(fdp->mode, 'b') == NULL) {
/* PyTokenizer_FindEncoding() returns PyMem_MALLOC'ed /* PyTokenizer_FindEncoding() returns PyMem_MALLOC'ed
memory. */ memory. */
found_encoding = PyTokenizer_FindEncoding(fp); found_encoding = PyTokenizer_FindEncoding(fd);
lseek(fd, 0, 0); /* Reset position */
encoding = (found_encoding != NULL) ? found_encoding : encoding = (found_encoding != NULL) ? found_encoding :
(char*)PyUnicode_GetDefaultEncoding(); (char*)PyUnicode_GetDefaultEncoding();
} }
fob = PyFile_FromFileEx(fp, pathname, fdp->mode, fclose, -1, fob = PyFile_FromFd(fd, pathname, fdp->mode, -1,
(char*)encoding, NULL); (char*)encoding, NULL);
if (fob == NULL) { if (fob == NULL) {
fclose(fp); close(fd);
PyMem_FREE(found_encoding); PyMem_FREE(found_encoding);
return NULL; return NULL;
} }

View file

@ -719,7 +719,7 @@ initstdio(void)
} }
/* Set sys.stdin */ /* Set sys.stdin */
if (!(std = PyFile_FromFileEx(stdin, "<stdin>", "r", fclose, -1, if (!(std = PyFile_FromFd(fileno(stdin), "<stdin>", "r", -1,
NULL, "\n"))) { NULL, "\n"))) {
goto error; goto error;
} }
@ -728,7 +728,7 @@ initstdio(void)
Py_DECREF(std); Py_DECREF(std);
/* Set sys.stdout */ /* Set sys.stdout */
if (!(std = PyFile_FromFileEx(stdout, "<stdout>", "w", fclose, -1, if (!(std = PyFile_FromFd(fileno(stdout), "<stdout>", "w", -1,
NULL, "\n"))) { NULL, "\n"))) {
goto error; goto error;
} }
@ -737,7 +737,7 @@ initstdio(void)
Py_DECREF(std); Py_DECREF(std);
/* Set sys.stderr */ /* Set sys.stderr */
if (!(std = PyFile_FromFileEx(stderr, "<stderr>", "w", fclose, -1, if (!(std = PyFile_FromFd(fileno(stderr), "<stderr>", "w", -1,
NULL, "\n"))) { NULL, "\n"))) {
goto error; goto error;
} }