yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame^] | 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 | } |