if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:file", kwlist, &po, &mode, &bufsize)) { wideargument = 1; if (fill_file_fields(foself, NULL, po, mode, fclose) == NULL) goto Error; } else { /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); } }#endif if (!wideargument) { PyObject *o_name; if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:file", kwlist, Py_FileSystemDefaultEncoding, &name, &mode, &bufsize)) return -1; /* We parse again to get the name as a PyObject */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:file", kwlist, &o_name, &mode, &bufsize)) goto Error; if (fill_file_fields(foself, NULL, o_name, mode, fclose) == NULL) goto Error; } if (open_the_file(foself, name, mode) == NULL) goto Error; foself->f_setbuf = NULL; PyFile_SetBufSize(self, bufsize); goto Done; Error: ret = -1; /* fall through */Done: PyMem_Free(name); /* free the encoded string */ return ret;} PyDoc_VAR(file_doc) =PyDoc_STR("file(name[, mode[, buffering]]) -> file object\n""\n""Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n""writing or appending. The file will be created if it doesn't exist\n""when opened for writing or appending; it will be truncated when\n""opened for writing. Add a 'b' to the mode for binary files.\n""Add a '+' to the mode to allow simultaneous reading and writing.\n""If the buffering argument is given, 0 means unbuffered, 1 means line\n""buffered, and larger numbers specify the buffer size.\n")PyDoc_STR("Add a 'U' to mode to open the file for input with universal newline\n""support. Any line ending in the input file will be seen as a '\\n'\n""in Python. Also, a file so opened gains the attribute 'newlines';\n""the value for this attribute is one of None (no newline read yet),\n""'\\r', '\\n', '\\r\\n' or a tuple containing all the newline types seen.\n""\n""'U' cannot be combined with 'w' or '+' mode.\n"); PyTypeObject PyFile_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "file", sizeof(PyFileObject), 0, (destructor)file_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)file_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ /* softspace is writable: we must supply tp_setattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ file_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PyFileObject, weakreflist), /* tp_weaklistoffset */ (getiterfunc)file_self, /* tp_iter */ (iternextfunc)file_iternext, /* tp_iternext */ file_methods, /* tp_methods */ file_memberlist, /* tp_members */ file_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ file_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ file_new, /* tp_new */ PyObject_Del, /* tp_free */}; /* Interface for the 'soft space' between print items. */ intPyFile_SoftSpace(PyObject *f, int newflag){ long oldflag = 0; if (f == NULL) { /* Do nothing */ } else if (PyFile_Check(f)) { oldflag = ((PyFileObject *)f)->f_softspace; ((PyFileObject *)f)->f_softspace = newflag; } else { PyObject *v; v = PyObject_GetAttrString(f, "softspace"); if (v == NULL) PyErr_Clear(); else { if (PyInt_Check(v)) oldflag = PyInt_AsLong(v); assert(oldflag < INT_MAX); Py_DECREF(v); } v = PyInt_FromLong((long)newflag); if (v == NULL) PyErr_Clear(); else { if (PyObject_SetAttrString(f, "softspace", v) != 0) PyErr_Clear(); Py_DECREF(v); } } return (int)oldflag;} /* Interfaces to write objects/strings to file-like objects */ intPyFile_WriteObject(PyObject *v, PyObject *f, int flags){ PyObject *writer, *value, *args, *result; if (f == NULL) { PyErr_SetString(PyExc_TypeError, "writeobject with NULL file"); return -1; } else if (PyFile_Check(f)) { FILE *fp = PyFile_AsFile(f);#ifdef Py_USING_UNICODE PyObject *enc = ((PyFileObject*)f)->f_encoding; int result;#endif if (fp == NULL) { err_closed(); return -1; }#ifdef Py_USING_UNICODE if ((flags & Py_PRINT_RAW) && PyUnicode_Check(v) && enc != Py_None) { char *cenc = PyString_AS_STRING(enc); value = PyUnicode_AsEncodedString(v, cenc, "strict"); if (value == NULL) return -1; } else { value = v; Py_INCREF(value); } result = PyObject_Print(value, fp, flags); Py_DECREF(value); return result;#else return PyObject_Print(v, fp, flags);#endif } writer = PyObject_GetAttrString(f, "write"); if (writer == NULL) return -1; if (flags & Py_PRINT_RAW) { if (PyUnicode_Check(v)) { value = v; Py_INCREF(value); } else value = PyObject_Str(v); } else value = PyObject_Repr(v); if (value == NULL) { Py_DECREF(writer); return -1; } args = PyTuple_Pack(1, value); if (args == NULL) { Py_DECREF(value); Py_DECREF(writer); return -1; } result = PyEval_CallObject(writer, args); Py_DECREF(args); Py_DECREF(value); Py_DECREF(writer); if (result == NULL) return -1; Py_DECREF(result); return 0;} intPyFile_WriteString(const char *s, PyObject *f){ if (f == NULL) { /* Should be caused by a pre-existing error */ if (!PyErr_Occurred()) PyErr_SetString(PyExc_SystemError, "null file for PyFile_WriteString"); return -1; } else if (PyFile_Check(f)) { FILE *fp = PyFile_AsFile(f); if (fp == NULL) { err_closed(); return -1; } fputs(s, fp); return 0; } else if (!PyErr_Occurred()) { PyObject *v = PyString_FromString(s); int err; if (v == NULL) return -1; err = PyFile_WriteObject(v, f, Py_PRINT_RAW); Py_DECREF(v); return err; } else return -1;} /* Try to get a file-descriptor from a Python object. If the object is an integer or long integer, its value is returned. If not, the object's fileno() method is called if it exists; the method must return an integer or long integer, which is returned as the file descriptor value. -1 is returned on failure.*/ int PyObject_AsFileDescriptor(PyObject *o){ int fd; PyObject *meth; if (PyInt_Check(o)) { fd = PyInt_AsLong(o); } else if (PyLong_Check(o)) { fd = PyLong_AsLong(o); } else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) { PyObject *fno = PyEval_CallObject(meth, NULL); Py_DECREF(meth); if (fno == NULL) return -1; if (PyInt_Check(fno)) { fd = PyInt_AsLong(fno); Py_DECREF(fno); } else if (PyLong_Check(fno)) { fd = PyLong_AsLong(fno); Py_DECREF(fno); } else { PyErr_SetString(PyExc_TypeError, "fileno() returned a non-integer"); Py_DECREF(fno); return -1; } } else { PyErr_SetString(PyExc_TypeError, "argument must be an int, or have a fileno() method."); return -1; } if (fd < 0) { PyErr_Format(PyExc_ValueError, "file descriptor cannot be a negative integer (%i)", fd); return -1; } return fd;} /* From here on we need access to the real fgets and fread */#undef fgets#undef fread /*** Py_UniversalNewlineFgets is an fgets variation that understands** all of \r, \n and \r\n conventions.** The stream should be opened in binary mode.** If fobj is NULL the routine always does newline conversion, and** it may peek one char ahead to gobble the second char in \r\n.** If fobj is non-NULL it must be a PyFileObject. In this case there** is no readahead but in stead a flag is used to skip a following** \n on the next read. Also, if the file is open in binary mode** the whole conversion is skipped. Finally, the routine keeps track of** the different types of newlines seen.** Note that we need no error handling: fgets() treats error and eof** identically.*/char *Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj){ char *p = buf; int c; int newlinetypes = 0; int skipnextlf = 0; int univ_newline = 1; if (fobj) { if (!PyFile_Check(fobj)) { errno = ENXIO; /* What can you do... */ return NULL; } univ_newline = ((PyFileObject *)fobj)->f_univ_newline; if ( !univ_newline ) return fgets(buf, n, stream); newlinetypes = ((PyFileObject *)fobj)->f_newlinetypes; skipnextlf = ((PyFileObject *)fobj)->f_skipnextlf; } FLOCKFILE(stream); c = 'x'; /* Shut up gcc warning */ while (--n > 0 && (c = GETC(stream)) != 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(stream); if (c == EOF) break; } else { /* ** Note that c == EOF also brings us here, ** so we're okay if the last char in the file ** is a CR. */ newlinetypes |= NEWLINE_CR; } } if (c == '\r') { /* A \r is translated into a \n, and we skip ** an adjacent \n, if any. We don't set the ** newlinetypes flag until we've seen the next char. */ skipnextlf = 1; c = '\n'; } else if ( c == '\n') { newlinetypes |= NEWLINE_LF; } *p++ = c; if (c == '\n') break; } if ( c == EOF && skipnextlf ) newlinetypes |= NEWLINE_CR; FUNLOCKFILE(stream); *p = '\0'; if (fobj) { ((PyFileObject *)fobj)->f_newlinetypes = newlinetypes; ((PyFileObject *)fobj)->f_skipnextlf = skipnextlf; } else if ( skipnextlf ) { /* If we have no file object we cannot save the ** skipnextlf flag. We have to readahead, which ** will cause a pause if we're reading from an ** interactive stream, but that is very unlikely ** unless we're doing something silly like ** execfile("/dev/tty"). */ c = GETC(stream); if ( c != '\n' ) ungetc(c, stream); } if (p == buf) return NULL; return buf;} /*** Py_UniversalNewlineFread is an fread variation that understands** all of \r, \n and \r\n conventions.** The stream should be opened in binary mode.** fobj must be a PyFileObject. In this case there** is no readahead but in stead a flag is used to skip a following** \n on the next read. Also, if the file is open in binary mode** the whole conversion is skipped. Finally, the routine keeps track of** the different types of newlines seen.*/size_tPy_UniversalNewlineFread(char *buf, size_t n, FILE *stream, PyObject *fobj){ char *dst = buf; PyFileObject *f = (PyFileObject *)fobj; int newlinetypes, skipnextlf; assert(buf != NULL); assert(stream != NULL); if (!fobj || !PyFile_Check(fobj)) { errno = ENXIO; /* What can you do... */ return 0; } if (!f->f_univ_newline) return fread(buf, 1, n, stream); newlinetypes = f->f_newlinetypes; skipnextlf = f->f_skipnextlf; /* Invariant: n is the number of bytes remaining to be filled * in the buffer. */ while (n) { size_t nread; int shortread; char *src = dst; nread = fread(dst, 1, n, stream); assert(nread <= n); if (nread == 0) break; n -= nread; /* assuming 1 byte out for each in; will adjust */ shortread = n != 0; /* true iff EOF or error */ while (nread--) { char c = *src++; if (c == '\r') { /* Save as LF and set flag to skip next LF. */ *dst++ = '\n'; skipnextlf = 1; } else if (skipnextlf && c == '\n') { /* Skip LF, and remember we saw CR LF. */ skipnextlf = 0; newlinetypes |= NEWLINE_CRLF; ++n; } else { /* Normal char to be stored in buffer. Also * update the newlinetypes flag if either this * is an LF or the previous char was a CR. */ if (c == '\n') newlinetypes |= NEWLINE_LF; else if (skipnextlf) newlinetypes |= NEWLINE_CR; *dst++ = c; skipnextlf = 0; } } if (shortread) { /* If this is EOF, update type flags. */ if (skipnextlf && feof(stream)) newlinetypes |= NEWLINE_CR; break; } } f->f_newlinetypes = newlinetypes; f->f_skipnextlf = skipnextlf; return dst - buf;} #ifdef __cplusplus}#endifLines 2001–2487 of 2487. Previous lines
if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:file", kwlist, &po, &mode, &bufsize)) { wideargument = 1; if (fill_file_fields(foself, NULL, po, mode, fclose) == NULL) goto Error; } else { /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); } } #endif if (!wideargument) { PyObject *o_name; if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:file", kwlist, Py_FileSystemDefaultEncoding, &name, &mode, &bufsize)) return -1; /* We parse again to get the name as a PyObject */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:file", kwlist, &o_name, &mode, &bufsize)) goto Error; if (fill_file_fields(foself, NULL, o_name, mode, fclose) == NULL) goto Error; } if (open_the_file(foself, name, mode) == NULL) goto Error; foself->f_setbuf = NULL; PyFile_SetBufSize(self, bufsize); goto Done; Error: ret = -1; /* fall through */ Done: PyMem_Free(name); /* free the encoded string */ return ret; } PyDoc_VAR(file_doc) = PyDoc_STR( "file(name[, mode[, buffering]]) -> file object\n" "\n" "Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n" "writing or appending. The file will be created if it doesn't exist\n" "when opened for writing or appending; it will be truncated when\n" "opened for writing. Add a 'b' to the mode for binary files.\n" "Add a '+' to the mode to allow simultaneous reading and writing.\n" "If the buffering argument is given, 0 means unbuffered, 1 means line\n" "buffered, and larger numbers specify the buffer size.\n" ) PyDoc_STR( "Add a 'U' to mode to open the file for input with universal newline\n" "support. Any line ending in the input file will be seen as a '\\n'\n" "in Python. Also, a file so opened gains the attribute 'newlines';\n" "the value for this attribute is one of None (no newline read yet),\n" "'\\r', '\\n', '\\r\\n' or a tuple containing all the newline types seen.\n" "\n" "'U' cannot be combined with 'w' or '+' mode.\n" ); PyTypeObject PyFile_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, "file", sizeof(PyFileObject), 0, (destructor)file_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)file_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ /* softspace is writable: we must supply tp_setattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ file_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PyFileObject, weakreflist), /* tp_weaklistoffset */ (getiterfunc)file_self, /* tp_iter */ (iternextfunc)file_iternext, /* tp_iternext */ file_methods, /* tp_methods */ file_memberlist, /* tp_members */ file_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ file_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ file_new, /* tp_new */ PyObject_Del, /* tp_free */ }; /* Interface for the 'soft space' between print items. */ int PyFile_SoftSpace(PyObject *f, int newflag) { long oldflag = 0; if (f == NULL) { /* Do nothing */ } else if (PyFile_Check(f)) { oldflag = ((PyFileObject *)f)->f_softspace; ((PyFileObject *)f)->f_softspace = newflag; } else { PyObject *v; v = PyObject_GetAttrString(f, "softspace"); if (v == NULL) PyErr_Clear(); else { if (PyInt_Check(v)) oldflag = PyInt_AsLong(v); assert(oldflag < INT_MAX); Py_DECREF(v); } v = PyInt_FromLong((long)newflag); if (v == NULL) PyErr_Clear(); else { if (PyObject_SetAttrString(f, "softspace", v) != 0) PyErr_Clear(); Py_DECREF(v); } } return (int)oldflag; } /* Interfaces to write objects/strings to file-like objects */ int PyFile_WriteObject(PyObject *v, PyObject *f, int flags) { PyObject *writer, *value, *args, *result; if (f == NULL) { PyErr_SetString(PyExc_TypeError, "writeobject with NULL file"); return -1; } else if (PyFile_Check(f)) { FILE *fp = PyFile_AsFile(f); #ifdef Py_USING_UNICODE PyObject *enc = ((PyFileObject*)f)->f_encoding; int result; #endif if (fp == NULL) { err_closed(); return -1; } #ifdef Py_USING_UNICODE if ((flags & Py_PRINT_RAW) && PyUnicode_Check(v) && enc != Py_None) { char *cenc = PyString_AS_STRING(enc); value = PyUnicode_AsEncodedString(v, cenc, "strict"); if (value == NULL) return -1; } else { value = v; Py_INCREF(value); } result = PyObject_Print(value, fp, flags); Py_DECREF(value); return result; #else return PyObject_Print(v, fp, flags); #endif } writer = PyObject_GetAttrString(f, "write"); if (writer == NULL) return -1; if (flags & Py_PRINT_RAW) { if (PyUnicode_Check(v)) { value = v; Py_INCREF(value); } else value = PyObject_Str(v); } else value = PyObject_Repr(v); if (value == NULL) { Py_DECREF(writer); return -1; } args = PyTuple_Pack(1, value); if (args == NULL) { Py_DECREF(value); Py_DECREF(writer); return -1; } result = PyEval_CallObject(writer, args); Py_DECREF(args); Py_DECREF(value); Py_DECREF(writer); if (result == NULL) return -1; Py_DECREF(result); return 0; } int PyFile_WriteString(const char *s, PyObject *f) { if (f == NULL) { /* Should be caused by a pre-existing error */ if (!PyErr_Occurred()) PyErr_SetString(PyExc_SystemError, "null file for PyFile_WriteString"); return -1; } else if (PyFile_Check(f)) { FILE *fp = PyFile_AsFile(f); if (fp == NULL) { err_closed(); return -1; } fputs(s, fp); return 0; } else if (!PyErr_Occurred()) { PyObject *v = PyString_FromString(s); int err; if (v == NULL) return -1; err = PyFile_WriteObject(v, f, Py_PRINT_RAW); Py_DECREF(v); return err; } else return -1; } /* Try to get a file-descriptor from a Python object. If the object is an integer or long integer, its value is returned. If not, the object's fileno() method is called if it exists; the method must return an integer or long integer, which is returned as the file descriptor value. -1 is returned on failure. */ int PyObject_AsFileDescriptor(PyObject *o) { int fd; PyObject *meth; if (PyInt_Check(o)) { fd = PyInt_AsLong(o); } else if (PyLong_Check(o)) { fd = PyLong_AsLong(o); } else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) { PyObject *fno = PyEval_CallObject(meth, NULL); Py_DECREF(meth); if (fno == NULL) return -1; if (PyInt_Check(fno)) { fd = PyInt_AsLong(fno); Py_DECREF(fno); } else if (PyLong_Check(fno)) { fd = PyLong_AsLong(fno); Py_DECREF(fno); } else { PyErr_SetString(PyExc_TypeError, "fileno() returned a non-integer"); Py_DECREF(fno); return -1; } } else { PyErr_SetString(PyExc_TypeError, "argument must be an int, or have a fileno() method."); return -1; } if (fd < 0) { PyErr_Format(PyExc_ValueError, "file descriptor cannot be a negative integer (%i)", fd); return -1; } return fd; } /* From here on we need access to the real fgets and fread */ #undef fgets #undef fread /* ** Py_UniversalNewlineFgets is an fgets variation that understands ** all of \r, \n and \r\n conventions. ** The stream should be opened in binary mode. ** If fobj is NULL the routine always does newline conversion, and ** it may peek one char ahead to gobble the second char in \r\n. ** If fobj is non-NULL it must be a PyFileObject. In this case there ** is no readahead but in stead a flag is used to skip a following ** \n on the next read. Also, if the file is open in binary mode ** the whole conversion is skipped. Finally, the routine keeps track of ** the different types of newlines seen. ** Note that we need no error handling: fgets() treats error and eof ** identically. */ char * Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) { char *p = buf; int c; int newlinetypes = 0; int skipnextlf = 0; int univ_newline = 1; if (fobj) { if (!PyFile_Check(fobj)) { errno = ENXIO; /* What can you do... */ return NULL; } univ_newline = ((PyFileObject *)fobj)->f_univ_newline; if ( !univ_newline ) return fgets(buf, n, stream); newlinetypes = ((PyFileObject *)fobj)->f_newlinetypes; skipnextlf = ((PyFileObject *)fobj)->f_skipnextlf; } FLOCKFILE(stream); c = 'x'; /* Shut up gcc warning */ while (--n > 0 && (c = GETC(stream)) != 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(stream); if (c == EOF) break; } else { /* ** Note that c == EOF also brings us here, ** so we're okay if the last char in the file ** is a CR. */ newlinetypes |= NEWLINE_CR; } } if (c == '\r') { /* A \r is translated into a \n, and we skip ** an adjacent \n, if any. We don't set the ** newlinetypes flag until we've seen the next char. */ skipnextlf = 1; c = '\n'; } else if ( c == '\n') { newlinetypes |= NEWLINE_LF; } *p++ = c; if (c == '\n') break; } if ( c == EOF && skipnextlf ) newlinetypes |= NEWLINE_CR; FUNLOCKFILE(stream); *p = '\0'; if (fobj) { ((PyFileObject *)fobj)->f_newlinetypes = newlinetypes; ((PyFileObject *)fobj)->f_skipnextlf = skipnextlf; } else if ( skipnextlf ) { /* If we have no file object we cannot save the ** skipnextlf flag. We have to readahead, which ** will cause a pause if we're reading from an ** interactive stream, but that is very unlikely ** unless we're doing something silly like ** execfile("/dev/tty"). */ c = GETC(stream); if ( c != '\n' ) ungetc(c, stream); } if (p == buf) return NULL; return buf; } /* ** Py_UniversalNewlineFread is an fread variation that understands ** all of \r, \n and \r\n conventions. ** The stream should be opened in binary mode. ** fobj must be a PyFileObject. In this case there ** is no readahead but in stead a flag is used to skip a following ** \n on the next read. Also, if the file is open in binary mode ** the whole conversion is skipped. Finally, the routine keeps track of ** the different types of newlines seen. */ size_t Py_UniversalNewlineFread(char *buf, size_t n, FILE *stream, PyObject *fobj) { char *dst = buf; PyFileObject *f = (PyFileObject *)fobj; int newlinetypes, skipnextlf; assert(buf != NULL); assert(stream != NULL); if (!fobj || !PyFile_Check(fobj)) { errno = ENXIO; /* What can you do... */ return 0; } if (!f->f_univ_newline) return fread(buf, 1, n, stream); newlinetypes = f->f_newlinetypes; skipnextlf = f->f_skipnextlf; /* Invariant: n is the number of bytes remaining to be filled * in the buffer. */ while (n) { size_t nread; int shortread; char *src = dst; nread = fread(dst, 1, n, stream); assert(nread <= n); if (nread == 0) break; n -= nread; /* assuming 1 byte out for each in; will adjust */ shortread = n != 0; /* true iff EOF or error */ while (nread--) { char c = *src++; if (c == '\r') { /* Save as LF and set flag to skip next LF. */ *dst++ = '\n'; skipnextlf = 1; } else if (skipnextlf && c == '\n') { /* Skip LF, and remember we saw CR LF. */ skipnextlf = 0; newlinetypes |= NEWLINE_CRLF; ++n; } else { /* Normal char to be stored in buffer. Also * update the newlinetypes flag if either this * is an LF or the previous char was a CR. */ if (c == '\n') newlinetypes |= NEWLINE_LF; else if (skipnextlf) newlinetypes |= NEWLINE_CR; *dst++ = c; skipnextlf = 0; } } if (shortread) { /* If this is EOF, update type flags. */ if (skipnextlf && feof(stream)) newlinetypes |= NEWLINE_CR; break; } } f->f_newlinetypes = newlinetypes; f->f_skipnextlf = skipnextlf; return dst - buf; } #ifdef __cplusplus } #endif