2487 lines · 62.3 KB · C
RawDownload
	char* p;	/* temp */	char buf[MAXBUFSIZE];	PyObject* v;	/* the string object result */	char* pvfree;	/* address of next free slot */	char* pvend;    /* address one beyond last free slot */	size_t nfree;	/* # of free buffer slots; pvend-pvfree */	size_t total_v_size;  /* total # of slots in buffer */	size_t increment;	/* amount to increment the buffer */	size_t prev_v_size; 	/* Optimize for normal case:  avoid _PyString_Resize if at all	 * possible via first reading into stack buffer "buf".	 */	total_v_size = INITBUFSIZE;	/* start small and pray */	pvfree = buf;	for (;;) {		Py_BEGIN_ALLOW_THREADS		pvend = buf + total_v_size;		nfree = pvend - pvfree;		memset(pvfree, '\n', nfree);		assert(nfree < INT_MAX); /* Should be atmost MAXBUFSIZE */		p = fgets(pvfree, (int)nfree, fp);		Py_END_ALLOW_THREADS 		if (p == NULL) {			clearerr(fp);			if (PyErr_CheckSignals())				return NULL;			v = PyString_FromStringAndSize(buf, pvfree - buf);			return v;		}		/* fgets read *something* */		p = memchr(pvfree, '\n', nfree);		if (p != NULL) {			/* Did the \n come from fgets or from us?			 * Since fgets stops at the first \n, and then writes			 * \0, if it's from fgets a \0 must be next.  But if			 * that's so, it could not have come from us, since			 * the \n's we filled the buffer with have only more			 * \n's to the right.			 */			if (p+1 < pvend && *(p+1) == '\0') {				/* It's from fgets:  we win!  In particular,				 * we haven't done any mallocs yet, and can				 * build the final result on the first try.				 */				++p;	/* include \n from fgets */			}			else {				/* Must be from us:  fgets didn't fill the				 * buffer and didn't find a newline, so it				 * must be the last and newline-free line of				 * the file.				 */				assert(p > pvfree && *(p-1) == '\0');				--p;	/* don't include \0 from fgets */			}			v = PyString_FromStringAndSize(buf, p - buf);			return v;		}		/* yuck:  fgets overwrote all the newlines, i.e. the entire		 * buffer.  So this line isn't over yet, or maybe it is but		 * we're exactly at EOF.  If we haven't already, try using the		 * rest of the stack buffer.		 */		assert(*(pvend-1) == '\0');		if (pvfree == buf) {			pvfree = pvend - 1;	/* overwrite trailing null */			total_v_size = MAXBUFSIZE;		}		else			break;	} 	/* The stack buffer isn't big enough; malloc a string object and read	 * into its buffer.	 */	total_v_size = MAXBUFSIZE << 1;	v = PyString_FromStringAndSize((char*)NULL, (int)total_v_size);	if (v == NULL)		return v;	/* copy over everything except the last null byte */	memcpy(BUF(v), buf, MAXBUFSIZE-1);	pvfree = BUF(v) + MAXBUFSIZE - 1; 	/* Keep reading stuff into v; if it ever ends successfully, break	 * after setting p one beyond the end of the line.  The code here is	 * very much like the code above, except reads into v's buffer; see	 * the code above for detailed comments about the logic.	 */	for (;;) {		Py_BEGIN_ALLOW_THREADS		pvend = BUF(v) + total_v_size;		nfree = pvend - pvfree;		memset(pvfree, '\n', nfree);		assert(nfree < INT_MAX);		p = fgets(pvfree, (int)nfree, fp);		Py_END_ALLOW_THREADS 		if (p == NULL) {			clearerr(fp);			if (PyErr_CheckSignals()) {				Py_DECREF(v);				return NULL;			}			p = pvfree;			break;		}		p = memchr(pvfree, '\n', nfree);		if (p != NULL) {			if (p+1 < pvend && *(p+1) == '\0') {				/* \n came from fgets */				++p;				break;			}			/* \n came from us; last line of file, no newline */			assert(p > pvfree && *(p-1) == '\0');			--p;			break;		}		/* expand buffer and try again */		assert(*(pvend-1) == '\0');		increment = total_v_size >> 2;	/* mild exponential growth */		prev_v_size = total_v_size;		total_v_size += increment;		/* check for overflow */		if (total_v_size <= prev_v_size ||		    total_v_size > PY_SSIZE_T_MAX) {			PyErr_SetString(PyExc_OverflowError,			    "line is longer than a Python string can hold");			Py_DECREF(v);			return NULL;		}		if (_PyString_Resize(&v, (int)total_v_size) < 0)			return NULL;		/* overwrite the trailing null byte */		pvfree = BUF(v) + (prev_v_size - 1);	}	if (BUF(v) + total_v_size != p)		_PyString_Resize(&v, p - BUF(v));	return v;#undef INITBUFSIZE#undef MAXBUFSIZE}#endif	/* ifdef USE_FGETS_IN_GETLINE */ /* Internal routine to get a line.   Size argument interpretation:   > 0: max length;   <= 0: read arbitrary line*/ static PyObject *get_line(PyFileObject *f, int n){	FILE *fp = f->f_fp;	int c;	char *buf, *end;	size_t total_v_size;	/* total # of slots in buffer */	size_t used_v_size;	/* # used slots in buffer */	size_t increment;       /* amount to increment the buffer */	PyObject *v;	int newlinetypes = f->f_newlinetypes;	int skipnextlf = f->f_skipnextlf;	int univ_newline = f->f_univ_newline; #if defined(USE_FGETS_IN_GETLINE)	if (n <= 0 && !univ_newline )		return getline_via_fgets(fp);#endif	total_v_size = n > 0 ? n : 100;	v = PyString_FromStringAndSize((char *)NULL, total_v_size);	if (v == NULL)		return NULL;	buf = BUF(v);	end = buf + total_v_size; 	for (;;) {		Py_BEGIN_ALLOW_THREADS		FLOCKFILE(fp);		if (univ_newline) {			c = 'x'; /* Shut up gcc warning */			while ( buf != end && (c = GETC(fp)) != EOF ) {				if (skipnextlf ) {					skipnextlf = 0;					if (c == '\n') {						/* Seeing a \n here with						 * skipnextlf true means we						 * saw a \r before.						 */						newlinetypes |= NEWLINE_CRLF;						c = GETC(fp);						if (c == EOF) break;					} else {						newlinetypes |= NEWLINE_CR;					}				}				if (c == '\r') {					skipnextlf = 1;					c = '\n';				} else if ( c == '\n')					newlinetypes |= NEWLINE_LF;				*buf++ = c;				if (c == '\n') break;			}			if ( c == EOF && skipnextlf )				newlinetypes |= NEWLINE_CR;		} else /* If not universal newlines use the normal loop */		while ((c = GETC(fp)) != EOF &&		       (*buf++ = c) != '\n' &&			buf != end)			;		FUNLOCKFILE(fp);		Py_END_ALLOW_THREADS		f->f_newlinetypes = newlinetypes;		f->f_skipnextlf = skipnextlf;		if (c == '\n')			break;		if (c == EOF) {			if (ferror(fp)) {				PyErr_SetFromErrno(PyExc_IOError);				clearerr(fp);				Py_DECREF(v);				return NULL;			}			clearerr(fp);			if (PyErr_CheckSignals()) {				Py_DECREF(v);				return NULL;			}			break;		}		/* Must be because buf == end */		if (n > 0)			break;		used_v_size = total_v_size;		increment = total_v_size >> 2; /* mild exponential growth */		total_v_size += increment;		if (total_v_size > PY_SSIZE_T_MAX) {			PyErr_SetString(PyExc_OverflowError,			    "line is longer than a Python string can hold");			Py_DECREF(v);			return NULL;		}		if (_PyString_Resize(&v, total_v_size) < 0)			return NULL;		buf = BUF(v) + used_v_size;		end = BUF(v) + total_v_size;	} 	used_v_size = buf - BUF(v);	if (used_v_size != total_v_size)		_PyString_Resize(&v, used_v_size);	return v;} /* External C interface */ PyObject *PyFile_GetLine(PyObject *f, int n){	PyObject *result; 	if (f == NULL) {		PyErr_BadInternalCall();		return NULL;	} 	if (PyFile_Check(f)) {		PyFileObject *fo = (PyFileObject *)f;		if (fo->f_fp == NULL)			return err_closed();		/* refuse to mix with f.next() */		if (fo->f_buf != NULL &&		    (fo->f_bufend - fo->f_bufptr) > 0 &&		    fo->f_buf[0] != '\0')			return err_iterbuffered();		result = get_line(fo, n);	}	else {		PyObject *reader;		PyObject *args; 		reader = PyObject_GetAttrString(f, "readline");		if (reader == NULL)			return NULL;		if (n <= 0)			args = PyTuple_New(0);		else			args = Py_BuildValue("(i)", n);		if (args == NULL) {			Py_DECREF(reader);			return NULL;		}		result = PyEval_CallObject(reader, args);		Py_DECREF(reader);		Py_DECREF(args);		if (result != NULL && !PyString_Check(result) &&		    !PyUnicode_Check(result)) {			Py_DECREF(result);			result = NULL;			PyErr_SetString(PyExc_TypeError,				   "object.readline() returned non-string");		}	} 	if (n < 0 && result != NULL && PyString_Check(result)) {		char *s = PyString_AS_STRING(result);		Py_ssize_t len = PyString_GET_SIZE(result);		if (len == 0) {			Py_DECREF(result);			result = NULL;			PyErr_SetString(PyExc_EOFError,					"EOF when reading a line");		}		else if (s[len-1] == '\n') {			if (result->ob_refcnt == 1)				_PyString_Resize(&result, len-1);			else {				PyObject *v;				v = PyString_FromStringAndSize(s, len-1);				Py_DECREF(result);				result = v;			}		}	}#ifdef Py_USING_UNICODE	if (n < 0 && result != NULL && PyUnicode_Check(result)) {		Py_UNICODE *s = PyUnicode_AS_UNICODE(result);		Py_ssize_t len = PyUnicode_GET_SIZE(result);		if (len == 0) {			Py_DECREF(result);			result = NULL;			PyErr_SetString(PyExc_EOFError,					"EOF when reading a line");		}		else if (s[len-1] == '\n') {			if (result->ob_refcnt == 1)				PyUnicode_Resize(&result, len-1);			else {				PyObject *v;				v = PyUnicode_FromUnicode(s, len-1);				Py_DECREF(result);				result = v;			}		}	}#endif	return result;} /* Python method */ static PyObject *file_readline(PyFileObject *f, PyObject *args){	int n = -1; 	if (f->f_fp == NULL)		return err_closed();	/* refuse to mix with f.next() */	if (f->f_buf != NULL &&	    (f->f_bufend - f->f_bufptr) > 0 &&	    f->f_buf[0] != '\0')		return err_iterbuffered();	if (!PyArg_ParseTuple(args, "|i:readline", &n))		return NULL;	if (n == 0)		return PyString_FromString("");	if (n < 0)		n = 0;	return get_line(f, n);} static PyObject *file_readlines(PyFileObject *f, PyObject *args){	long sizehint = 0;	PyObject *list;	PyObject *line;	char small_buffer[SMALLCHUNK];	char *buffer = small_buffer;	size_t buffersize = SMALLCHUNK;	PyObject *big_buffer = NULL;	size_t nfilled = 0;	size_t nread;	size_t totalread = 0;	char *p, *q, *end;	int err;	int shortread = 0; 	if (f->f_fp == NULL)		return err_closed();	/* refuse to mix with f.next() */	if (f->f_buf != NULL &&	    (f->f_bufend - f->f_bufptr) > 0 &&	    f->f_buf[0] != '\0')		return err_iterbuffered();	if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint))		return NULL;	if ((list = PyList_New(0)) == NULL)		return NULL;	for (;;) {		if (shortread)			nread = 0;		else {			Py_BEGIN_ALLOW_THREADS			errno = 0;			nread = Py_UniversalNewlineFread(buffer+nfilled,				buffersize-nfilled, f->f_fp, (PyObject *)f);			Py_END_ALLOW_THREADS			shortread = (nread < buffersize-nfilled);		}		if (nread == 0) {			sizehint = 0;			if (!ferror(f->f_fp))				break;			PyErr_SetFromErrno(PyExc_IOError);			clearerr(f->f_fp);		  error:			Py_DECREF(list);			list = NULL;			goto cleanup;		}		totalread += nread;		p = (char *)memchr(buffer+nfilled, '\n', nread);		if (p == NULL) {			/* Need a larger buffer to fit this line */			nfilled += nread;			buffersize *= 2;			if (buffersize > PY_SSIZE_T_MAX) {				PyErr_SetString(PyExc_OverflowError,			    "line is longer than a Python string can hold");				goto error;			}			if (big_buffer == NULL) {				/* Create the big buffer */				big_buffer = PyString_FromStringAndSize(					NULL, buffersize);				if (big_buffer == NULL)					goto error;				buffer = PyString_AS_STRING(big_buffer);				memcpy(buffer, small_buffer, nfilled);			}			else {				/* Grow the big buffer */				if ( _PyString_Resize(&big_buffer, buffersize) < 0 )					goto error;				buffer = PyString_AS_STRING(big_buffer);			}			continue;		}		end = buffer+nfilled+nread;		q = buffer;		do {			/* Process complete lines */			p++;			line = PyString_FromStringAndSize(q, p-q);			if (line == NULL)				goto error;			err = PyList_Append(list, line);			Py_DECREF(line);			if (err != 0)				goto error;			q = p;			p = (char *)memchr(q, '\n', end-q);		} while (p != NULL);		/* Move the remaining incomplete line to the start */		nfilled = end-q;		memmove(buffer, q, nfilled);		if (sizehint > 0)			if (totalread >= (size_t)sizehint)				break;	}	if (nfilled != 0) {		/* Partial last line */		line = PyString_FromStringAndSize(buffer, nfilled);		if (line == NULL)			goto error;		if (sizehint > 0) {			/* Need to complete the last line */			PyObject *rest = get_line(f, 0);			if (rest == NULL) {				Py_DECREF(line);				goto error;			}			PyString_Concat(&line, rest);			Py_DECREF(rest);			if (line == NULL)				goto error;		}		err = PyList_Append(list, line);		Py_DECREF(line);		if (err != 0)			goto error;	}  cleanup:	Py_XDECREF(big_buffer);	return list;}

Lines 1001–1500 of 2487. Previous lines