=== modified file 'src/fileio.c' --- src/fileio.c 2013-01-17 06:29:40 +0000 +++ src/fileio.c 2013-01-17 16:54:32 +0000 @@ -3408,13 +3408,13 @@ return Qnil; } -/* Read from a non-regular file. STATE is a Lisp_Save_Value +/* Check quit and read from file. STATE is a Lisp_Save_Value object where slot 0 is the file descriptor, slot 1 specifies an offset to put the read bytes, and slot 2 is the maximum amount of bytes to read. Value is the number of bytes read. */ static Lisp_Object -read_non_regular (Lisp_Object state) +read_contents (Lisp_Object state) { int nbytes; @@ -3425,15 +3425,15 @@ + XSAVE_INTEGER (state, 1)), XSAVE_INTEGER (state, 2)); immediate_quit = 0; + /* Fast recycle this object for the likely next call. */ + free_misc (state); return make_number (nbytes); } - -/* Condition-case handler used when reading from non-regular files - in insert-file-contents. */ +/* Condition-case handler used when reading files in insert-file-contents. */ static Lisp_Object -read_non_regular_quit (Lisp_Object ignore) +read_contents_quit (Lisp_Object ignore) { return Qnil; } @@ -3506,7 +3506,7 @@ Lisp_Object p; ptrdiff_t total = 0; bool not_regular = 0; - int save_errno = 0; + int save_errno = 0, read_errno = 0; char read_buf[READ_BUF_SIZE]; struct coding_system coding; char buffer[1 << 14]; @@ -4213,88 +4213,71 @@ Fcons (orig_filename, Qnil)); } - /* In the following loop, HOW_MUCH contains the total bytes read so - far for a regular file, and not changed for a special file. But, - before exiting the loop, it is set to a negative value if I/O - error occurs. */ + /* In the following loop, HOW_MUCH contains the total bytes read + so far for a regular file, and not changed for a special file. */ how_much = 0; /* Total bytes inserted. */ inserted = 0; - /* Here, we don't do code conversion in the loop. It is done by - decode_coding_gap after all data are read into the buffer. */ - { - ptrdiff_t gap_size = GAP_SIZE; - - while (how_much < total) - { - /* try is reserved in some compilers (Microsoft C) */ - ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); - ptrdiff_t this; - - if (not_regular) - { - Lisp_Object nbytes; - - /* Maybe make more room. */ - if (gap_size < trytry) - { - make_gap (total - gap_size); - gap_size = GAP_SIZE; - } - - /* Read from the file, capturing `quit'. When an - error occurs, end the loop, and arrange for a quit - to be signaled after decoding the text we read. */ - nbytes = internal_condition_case_1 - (read_non_regular, - make_save_value ("iii", (ptrdiff_t) fd, inserted, trytry), - Qerror, read_non_regular_quit); - - if (NILP (nbytes)) - { - read_quit = 1; - break; - } - - this = XINT (nbytes); - } - else - { - /* Allow quitting out of the actual I/O. We don't make text - part of the buffer until all the reading is done, so a C-g - here doesn't do any harm. */ - immediate_quit = 1; - QUIT; - this = emacs_read (fd, - ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE - + inserted), - trytry); - immediate_quit = 0; - } - - if (this <= 0) - { - how_much = this; - break; - } - - gap_size -= this; - - /* For a regular file, where TOTAL is the real size, - count HOW_MUCH to compare with it. - For a special file, where TOTAL is just a buffer size, - so don't bother counting in HOW_MUCH. - (INSERTED is where we count the number of characters inserted.) */ - if (! not_regular) - how_much += this; - inserted += this; - } - } - - /* Now we have read all the file data into the gap. - If it was empty, undo marking the buffer modified. */ + /* Here we don't do code conversion in the loop. It is done by + decode_coding_gap after all data are read into the buffer, or + read is interrupted due to quit or I/O error. */ + while (how_much < total) + { + ptrdiff_t nread, maxread = min (total - how_much, READ_BUF_SIZE); + Lisp_Object result; + + /* For a special file, gap is enlarged as we read, + so GAP_SIZE should be checked every time. */ + if (not_regular && (GAP_SIZE < maxread)) + make_gap (maxread - GAP_SIZE); + + /* Read from the file, capturing `quit'. */ + result = internal_condition_case_1 + (read_contents, + make_save_value ("iii", (ptrdiff_t) fd, inserted, maxread), + Qerror, read_contents_quit); + if (NILP (result)) + { + /* Quit was signaled. End the loop and arrange + real quit after decoding the text we read. */ + read_quit = 1; + break; + } + nread = XINT (result); + if (nread <= 0) + { + /* End of file or I/O error. End the loop and + save error code in case of I/O error. */ + if (nread < 0) + read_errno = errno; + break; + } + + /* Adjust gap and end positions. */ + GAP_SIZE -= nread; + GPT += nread; + ZV += nread; + Z += nread; + GPT_BYTE += nread; + ZV_BYTE += nread; + Z_BYTE += nread; + if (GAP_SIZE > 0) + *(GPT_ADDR) = 0; + + /* For a regular file, where TOTAL is the real size, count HOW_MUCH to + compare with it. For a special file, where TOTAL is just a buffer + size, don't bother counting in HOW_MUCH, but always accumulate the + number of bytes read in INSERTED. */ + if (! not_regular) + how_much += nread; + inserted += nread; + } + + /* Now we have either read all the file data into the gap, + or stop reading on I/O error or quit. If nothing was + read, undo marking the buffer modified. */ if (inserted == 0) { @@ -4307,28 +4290,11 @@ else Vdeactivate_mark = Qt; - /* Make the text read part of the buffer. */ - GAP_SIZE -= inserted; - GPT += inserted; - GPT_BYTE += inserted; - ZV += inserted; - ZV_BYTE += inserted; - Z += inserted; - Z_BYTE += inserted; - - if (GAP_SIZE > 0) - /* Put an anchor to ensure multi-byte form ends at gap. */ - *GPT_ADDR = 0; - emacs_close (fd); /* Discard the unwind protect for closing the file. */ specpdl_ptr--; - if (how_much < 0) - error ("IO error reading %s: %s", - SDATA (orig_filename), emacs_strerror (errno)); - notfound: if (NILP (coding_system)) @@ -4617,14 +4583,18 @@ report_file_error ("Opening input file", Fcons (orig_filename, Qnil)); } + /* There was an error reading file. */ + if (read_errno) + error ("IO error reading %s: %s", + SDATA (orig_filename), emacs_strerror (read_errno)); + + /* Quit was signaled. */ if (read_quit) Fsignal (Qquit, Qnil); - /* ??? Retval needs to be dealt with in all cases consistently. */ + /* Otherwise make the consistent return value. */ if (NILP (val)) - val = Fcons (orig_filename, - Fcons (make_number (inserted), - Qnil)); + val = list2 (orig_filename, make_number (inserted)); RETURN_UNGCPRO (unbind_to (count, val)); }