annotate lib/freadseek.c @ 12559:c2cbabec01dd

update nearly all FSF copyright year lists to include 2010 Use the same procedure as for 2009, outlined in http://thread.gmane.org/gmane.comp.lib.gnulib.bugs/20081
author Jim Meyering <meyering@redhat.com>
date Fri, 01 Jan 2010 10:31:12 +0100
parents e8d2c6fc33ad
children 6fa9f46e6153
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
1 /* Skipping input from a FILE stream.
12559
c2cbabec01dd update nearly all FSF copyright year lists to include 2010
Jim Meyering <meyering@redhat.com>
parents: 12421
diff changeset
2 Copyright (C) 2007-2010 Free Software Foundation, Inc.
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
3
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
4 This program is free software: you can redistribute it and/or modify
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
5 it under the terms of the GNU General Public License as published by
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
6 the Free Software Foundation; either version 3 of the License, or
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
7 (at your option) any later version.
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
8
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9 This program is distributed in the hope that it will be useful,
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12 GNU General Public License for more details.
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
14 You should have received a copy of the GNU General Public License
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
16
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
17 #include <config.h>
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
18
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
19 /* Specification. */
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
20 #include "freadseek.h"
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
21
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
22 #include <stdlib.h>
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
23 #include <unistd.h>
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
24
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
25 #include "freadahead.h"
9819
9ccce8a9bf52 Pass test-freadseek on cygwin.
Eric Blake <ebb9@byu.net>
parents: 9738
diff changeset
26 #include "freadptr.h"
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
27
9980
2c1ba629f5d5 New private include file lib/stdio-impl.h.
Bruno Haible <bruno@clisp.org>
parents: 9928
diff changeset
28 #include "stdio-impl.h"
2c1ba629f5d5 New private include file lib/stdio-impl.h.
Bruno Haible <bruno@clisp.org>
parents: 9928
diff changeset
29
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
30 /* Increment the in-memory pointer. INCREMENT must be at most the buffer size
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
31 returned by freadptr().
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
32 This is very cheap (no system calls). */
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
33 static inline void
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
34 freadptrinc (FILE *fp, size_t increment)
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
35 {
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
36 /* Keep this code in sync with freadptr! */
10780
5c7a68d31801 Add support for Haiku.
Bruno Haible <bruno@clisp.org>
parents: 10404
diff changeset
37 #if defined _IO_ftrylockfile || __GNU_LIBRARY__ == 1 /* GNU libc, BeOS, Haiku, Linux libc5 */
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
38 fp->_IO_read_ptr += increment;
9981
e3d6988a9347 Add tentative support for DragonFly BSD.
Bruno Haible <bruno@clisp.org>
parents: 9980
diff changeset
39 #elif defined __sferror || defined __DragonFly__ /* FreeBSD, NetBSD, OpenBSD, DragonFly, MacOS X, Cygwin */
e3d6988a9347 Add tentative support for DragonFly BSD.
Bruno Haible <bruno@clisp.org>
parents: 9980
diff changeset
40 fp_->_p += increment;
e3d6988a9347 Add tentative support for DragonFly BSD.
Bruno Haible <bruno@clisp.org>
parents: 9980
diff changeset
41 fp_->_r -= increment;
9881
e21211210418 Port the extended stdio functions to emx+gcc.
Bruno Haible <bruno@clisp.org>
parents: 9876
diff changeset
42 #elif defined __EMX__ /* emx+gcc */
e21211210418 Port the extended stdio functions to emx+gcc.
Bruno Haible <bruno@clisp.org>
parents: 9876
diff changeset
43 fp->_ptr += increment;
e21211210418 Port the extended stdio functions to emx+gcc.
Bruno Haible <bruno@clisp.org>
parents: 9876
diff changeset
44 fp->_rcount -= increment;
9876
057a5220dfd5 Add tentative support for OpenServer.
Bruno Haible <bruno@clisp.org>
parents: 9826
diff changeset
45 #elif defined _IOERR /* AIX, HP-UX, IRIX, OSF/1, Solaris, OpenServer, mingw */
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
46 fp_->_ptr += increment;
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
47 fp_->_cnt -= increment;
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
48 #elif defined __UCLIBC__ /* uClibc */
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
49 # ifdef __STDIO_BUFFERS
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
50 fp->__bufpos += increment;
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
51 # else
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
52 abort ();
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
53 # endif
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
54 #elif defined __QNX__ /* QNX */
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
55 fp->_Next += increment;
11236
d4475bf2a2bf Add tentative support for FreeMiNT.
Bruno Haible <bruno@clisp.org>
parents: 10780
diff changeset
56 #elif defined __MINT__ /* Atari FreeMiNT */
d4475bf2a2bf Add tentative support for FreeMiNT.
Bruno Haible <bruno@clisp.org>
parents: 10780
diff changeset
57 fp->__bufp += increment;
10404
4611578c5669 Add conditional code for SLOW_BUT_NO_HACKS.
Bruno Haible <bruno@clisp.org>
parents: 9981
diff changeset
58 #elif defined SLOW_BUT_NO_HACKS /* users can define this */
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
59 #else
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
60 #error "Please port gnulib freadseek.c to your platform! Look at the definition of getc, getc_unlocked on your system, then report this to bug-gnulib."
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
61 #endif
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
62 }
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
63
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
64 int
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
65 freadseek (FILE *fp, size_t offset)
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
66 {
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
67 size_t total_buffered;
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
68 int fd;
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
69
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
70 if (offset == 0)
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
71 return 0;
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
72
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
73 /* Seek over the already read and buffered input as quickly as possible,
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
74 without doing any system calls. */
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
75 total_buffered = freadahead (fp);
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
76 /* This loop is usually executed at most twice: once for ungetc buffer (if
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
77 present) and once for the main buffer. */
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
78 while (total_buffered > 0)
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
79 {
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
80 size_t buffered;
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
81
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
82 if (freadptr (fp, &buffered) != NULL && buffered > 0)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
83 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
84 size_t increment = (buffered < offset ? buffered : offset);
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
85
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
86 freadptrinc (fp, increment);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
87 offset -= increment;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
88 if (offset == 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
89 return 0;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
90 total_buffered -= increment;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
91 if (total_buffered == 0)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
92 break;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
93 }
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
94 /* Read one byte. If we were reading from the ungetc buffer, this
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
95 switches the stream back to the main buffer. */
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
96 if (fgetc (fp) == EOF)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
97 goto eof;
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
98 offset--;
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
99 if (offset == 0)
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
100 return 0;
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
101 total_buffered--;
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
102 }
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
103
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
104 /* Test whether the stream is seekable or not. */
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
105 fd = fileno (fp);
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
106 if (fd >= 0 && lseek (fd, 0, SEEK_CUR) >= 0)
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
107 {
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
108 /* FP refers to a regular file. fseek is most efficient in this case. */
12255
83ddd76ac091 fflush, freadseek: use fseeko, not fseek
Eric Blake <ebb9@byu.net>
parents: 11236
diff changeset
109 return fseeko (fp, offset, SEEK_CUR);
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
110 }
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
111 else
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
112 {
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
113 /* FP is a non-seekable stream, possibly not even referring to a file
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
114 descriptor. Read OFFSET bytes explicitly and discard them. */
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
115 char buf[4096];
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
116
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
117 do
12421
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
118 {
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
119 size_t count = (sizeof (buf) < offset ? sizeof (buf) : offset);
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
120 if (fread (buf, 1, count, fp) < count)
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
121 goto eof;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
122 offset -= count;
e8d2c6fc33ad Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents: 12255
diff changeset
123 }
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
124 while (offset > 0);
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
125
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
126 return 0;
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
127 }
9826
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
128
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
129 eof:
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
130 /* EOF, or error before or while reading. */
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
131 if (ferror (fp))
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
132 return EOF;
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
133 else
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
134 /* Encountered EOF. */
c421fead68d3 Improve freadseek's efficiency after ungetc.
Bruno Haible <bruno@clisp.org>
parents: 9825
diff changeset
135 return 0;
9738
923434ebe936 New module 'freadseek'.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
136 }