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 
__stdio_adjust_position(register FILE * __restrict stream,register __offmax_t * pos)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 }
69