diff options
-rw-r--r-- | doc/lispref/ChangeLog | 6 | ||||
-rw-r--r-- | doc/lispref/files.texi | 10 | ||||
-rw-r--r-- | src/ChangeLog | 9 | ||||
-rw-r--r-- | src/fileio.c | 59 |
4 files changed, 47 insertions, 37 deletions
diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 2631bdf708a..851f727621e 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,9 @@ +2013-01-19 Paul Eggert <eggert@cs.ucla.edu> + + Allow floating-point file offsets. + * files.texi (Reading from Files, Writing to Files): + Say that file offsets can be numbers, not just integers. + 2013-01-09 Glenn Morris <rgm@gnu.org> * commands.texi (Interactive Codes): diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 114eb1f38ea..be44590f2ec 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -533,9 +533,9 @@ is visiting the file @var{filename}: these include the buffer's visited file name and its last save file modtime. This feature is used by @code{find-file-noselect} and you probably should not use it yourself. -If @var{beg} and @var{end} are non-@code{nil}, they should be integers -specifying the portion of the file to insert. In this case, @var{visit} -must be @code{nil}. For example, +If @var{beg} and @var{end} are non-@code{nil}, they should be numbers +that are byte offsets specifying the portion of the file to insert. +In this case, @var{visit} must be @code{nil}. For example, @example (insert-file-contents filename nil 0 500) @@ -605,8 +605,8 @@ that string, rather than text from the buffer. @var{end} is ignored in this case. If @var{append} is non-@code{nil}, then the specified text is appended -to the existing file contents (if any). If @var{append} is an -integer, @code{write-region} seeks to that byte offset from the start +to the existing file contents (if any). If @var{append} is a +number, @code{write-region} seeks to that byte offset from the start of the file and writes the data from there. If @var{mustbenew} is non-@code{nil}, then @code{write-region} asks diff --git a/src/ChangeLog b/src/ChangeLog index 4bee4fc5ed7..c6bd70e2a04 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2013-01-19 Paul Eggert <eggert@cs.ucla.edu> + + Allow floating-point file offsets. + Problem reported by Vitalie Spinu in + <http://lists.gnu.org/archive/html/emacs-devel/2013-01/msg00411.html>. + * fileio.c (emacs_lseek): Remove. + (file_offset): New function. + (Finsert_file_contents, Fwrite_region): Use it. + 2013-01-19 Chong Yidong <cyd@gnu.org> * emacs.c (Fkill_emacs): Set waiting_for_input to 0 to avoid diff --git a/src/fileio.c b/src/fileio.c index 616f1c50f91..ab37bf2bd8f 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3443,19 +3443,25 @@ read_contents_quit (Lisp_Object ignore) return Qnil; } -/* Reposition FD to OFFSET, based on WHENCE. This acts like lseek - except that it also tests for OFFSET being out of lseek's range. */ +/* Return the file offset that VAL represents, checking for type + errors and overflow. */ static off_t -emacs_lseek (int fd, EMACS_INT offset, int whence) +file_offset (Lisp_Object val) { - /* Use "&" rather than "&&" to suppress a bogus GCC warning; see - <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43772>. */ - if (! ((offset >= TYPE_MINIMUM (off_t)) & (offset <= TYPE_MAXIMUM (off_t)))) + if (RANGED_INTEGERP (0, val, TYPE_MAXIMUM (off_t))) + return XINT (val); + + if (FLOATP (val)) { - errno = EINVAL; - return -1; + double v = XFLOAT_DATA (val); + if (0 <= v + && (sizeof (off_t) < sizeof v + ? v <= TYPE_MAXIMUM (off_t) + : v < TYPE_MAXIMUM (off_t))) + return v; } - return lseek (fd, offset, whence); + + wrong_type_argument (intern ("file-offset"), val); } /* Return a special time value indicating the error number ERRNUM. */ @@ -3606,20 +3612,12 @@ by calling `format-decode', which see. */) } if (!NILP (beg)) - { - if (! RANGED_INTEGERP (0, beg, TYPE_MAXIMUM (off_t))) - wrong_type_argument (intern ("file-offset"), beg); - beg_offset = XFASTINT (beg); - } + beg_offset = file_offset (beg); else beg_offset = 0; if (!NILP (end)) - { - if (! RANGED_INTEGERP (0, end, TYPE_MAXIMUM (off_t))) - wrong_type_argument (intern ("file-offset"), end); - end_offset = XFASTINT (end); - } + end_offset = file_offset (end); else { if (not_regular) @@ -4714,7 +4712,7 @@ If START is a string, then output that string to the file instead of any buffer contents; END is ignored. Optional fourth argument APPEND if non-nil means - append to existing file contents (if any). If it is an integer, + append to existing file contents (if any). If it is a number, seek to that offset in the file before writing. Optional fifth argument VISIT, if t or a string, means set the last-save-file-modtime of buffer to this file's modtime @@ -4743,6 +4741,7 @@ This calls `write-region-annotate-functions' at the start, and (Lisp_Object start, Lisp_Object end, Lisp_Object filename, Lisp_Object append, Lisp_Object visit, Lisp_Object lockname, Lisp_Object mustbenew) { int desc; + off_t offset; bool ok; int save_errno = 0; const char *fn; @@ -4864,13 +4863,14 @@ This calls `write-region-annotate-functions' at the start, and encoded_filename = ENCODE_FILE (filename); fn = SSDATA (encoded_filename); + offset = 0; desc = -1; if (!NILP (append)) -#ifdef DOS_NT - desc = emacs_open (fn, O_WRONLY | O_BINARY, 0); -#else /* not DOS_NT */ - desc = emacs_open (fn, O_WRONLY, 0); -#endif /* not DOS_NT */ + { + if (NUMBERP (append)) + offset = file_offset (append); + desc = emacs_open (fn, O_WRONLY | O_BINARY, 0); + } if (desc < 0 && (NILP (append) || errno == ENOENT)) #ifdef DOS_NT @@ -4897,14 +4897,9 @@ This calls `write-region-annotate-functions' at the start, and record_unwind_protect (close_file_unwind, make_number (desc)); - if (!NILP (append) && !NILP (Ffile_regular_p (filename))) + if (!NILP (append)) { - off_t ret; - - if (NUMBERP (append)) - ret = emacs_lseek (desc, XINT (append), SEEK_CUR); - else - ret = lseek (desc, 0, SEEK_END); + off_t ret = lseek (desc, offset, NUMBERP (append) ? SEEK_SET : SEEK_END); if (ret < 0) { #ifdef CLASH_DETECTION |