diff options
author | Manuel Novoa III <mjn3@codepoet.org> | 2004-02-11 23:48:50 +0000 |
---|---|---|
committer | Manuel Novoa III <mjn3@codepoet.org> | 2004-02-11 23:48:50 +0000 |
commit | 082e680bd54e999f2bb4eb77141958938b1e9ee9 (patch) | |
tree | 203c45b85ca608e1550d8ffc459456fc9cf0b30b /libc/stdio/_adjust_pos.c | |
parent | 17c21765b4a97c6f0b74ba8466073e5a3f97cdee (diff) |
New stdio core. Should be more maintainable. Fixes a couple of bugs.
Codepaths streamlined. Improved performance for nonthreaded apps
when linked with a thread-enabled libc.
Minor iconv bug and some locale/thread related startup issues fixed.
These showed up in getting a gcj-compiled java helloworld app running.
Removed some old extension functions... _stdio_fdout and _stdio_fsfopen.
Diffstat (limited to 'libc/stdio/_adjust_pos.c')
-rw-r--r-- | libc/stdio/_adjust_pos.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/libc/stdio/_adjust_pos.c b/libc/stdio/_adjust_pos.c new file mode 100644 index 000000000..bc48d32b7 --- /dev/null +++ b/libc/stdio/_adjust_pos.c @@ -0,0 +1,68 @@ +/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> + * + * GNU Library General Public License (LGPL) version 2 or later. + * + * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. + */ + +#include "_stdio.h" + +/* Both ftell() and fseek() (for SEEK_CUR) need to correct the stream's + * position to take into account buffered data and ungotten chars. + * + * If successful, store corrected position in *pos and return >= 0. + * Otherwise return < 0. + * + * If position is unrepresentable, set errno to EOVERFLOW. + */ + +int __stdio_adjust_position(register FILE * __restrict stream, + register __offmax_t *pos) +{ + __offmax_t oldpos; + int corr; + + if ((corr = stream->__modeflags & __MASK_READING) != 0) { + --corr; /* Correct for ungots. Assume narrow, and fix below. */ + } + +#ifdef __UCLIBC_HAS_WCHAR__ + if (corr && __STDIO_STREAM_IS_WIDE(stream)) { + /* A wide stream and we have at least one ungotten wchar. + * If it is a user ungot, we need to fail since position + * is unspecified as per C99. */ + if ((corr > 1) || stream->__ungot[1]) { /* User ungetwc, */ + return -1; /* so position is undefined. */ + } + corr -= (1 + stream->__ungot_width[1]); + if (stream->__state.__mask > 0) { /* Incomplete (bad?) mb char. */ + corr -= stream->__ungot_width[0]; + } + } +#endif + +#ifdef __STDIO_BUFFERS + corr += (((__STDIO_STREAM_IS_WRITING(stream)) + ? stream->__bufstart : stream->__bufread) + - stream->__bufpos); +#endif + + oldpos = *pos; + + /* Range checking cases: + * (pos - corr > pos) && (corr > 0) : underflow? return -corr < 0 + * (pos - corr > pos) && (corr < 0) : ok .. return -corr > 0 + * (pos - corr <= pos) && (corr >= 0) : ok .. return corr > 0 + * (pos - corr <= pos) && (corr < 0) : overflow .. return corr < 0 + */ + + if ((*pos -= corr) > oldpos) { + corr = -corr; + } + + if (corr < 0) { + __set_errno(EOVERFLOW); + } + + return corr; +} |