]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/uclibc/lib/contrib/uclibc/libc/stdio/_adjust_pos.c
update
[l4.git] / l4 / pkg / uclibc / lib / contrib / uclibc / libc / stdio / _adjust_pos.c
1 /* Copyright (C) 2004       Manuel Novoa III    <mjn3@codepoet.org>
2  *
3  * GNU Library General Public License (LGPL) version 2 or later.
4  *
5  * Dedicated to Toni.  See uClibc/DEDICATION.mjn3 for details.
6  */
7
8 #include "_stdio.h"
9
10 /* Both ftell() and fseek() (for SEEK_CUR) need to correct the stream's
11  * position to take into account buffered data and ungotten chars.
12  *
13  * If successful, store corrected position in *pos and return >= 0.
14  * Otherwise return < 0.
15  *
16  * If position is unrepresentable, set errno to EOVERFLOW.
17  */
18
19 int attribute_hidden __stdio_adjust_position(register FILE * __restrict stream,
20                                                         register __offmax_t *pos)
21 {
22         __offmax_t oldpos;
23         int corr;
24
25         if ((corr = stream->__modeflags & __MASK_READING) != 0) {
26                 --corr; /* Correct for ungots. Assume narrow, and fix below. */
27         }
28
29 #ifdef __UCLIBC_HAS_WCHAR__
30         if (corr && __STDIO_STREAM_IS_WIDE(stream)) {
31                 /* A wide stream and we have at least one ungotten wchar.
32                  * If it is a user ungot, we need to fail since position
33                  * is unspecified as per C99. */
34                 if ((corr > 1) || stream->__ungot[1]) { /* User ungetwc, */
35                         return -1;                      /* so position is undefined. */
36                 }
37                 corr -= (1 + stream->__ungot_width[1]);
38                 if (stream->__state.__mask > 0) { /* Incomplete (bad?) mb char. */
39                         corr -= stream->__ungot_width[0];
40                 }
41         }
42 #endif
43
44 #ifdef __STDIO_BUFFERS
45         corr += (((__STDIO_STREAM_IS_WRITING(stream))
46                           ? stream->__bufstart : stream->__bufread)
47                          - stream->__bufpos);
48 #endif
49
50         oldpos = *pos;
51
52         /* Range checking cases:
53          * (pos - corr >  pos) && (corr >  0) : underflow?  return -corr < 0
54          * (pos - corr >  pos) && (corr <  0) : ok .. return -corr > 0
55          * (pos - corr <= pos) && (corr >= 0) : ok .. return  corr > 0
56          * (pos - corr <= pos) && (corr <  0) : overflow ..  return corr < 0
57          */
58
59         if ((*pos -= corr) > oldpos) {
60                 corr = -corr;
61         }
62
63         if (corr < 0) {
64                 __set_errno(EOVERFLOW);
65         }
66
67         return corr;
68 }