diff options
-rw-r--r-- | newlib/ChangeLog | 11 | ||||
-rw-r--r-- | newlib/libc/include/sys/reent.h | 2 | ||||
-rw-r--r-- | newlib/libc/stdio/fseek.c | 271 | ||||
-rw-r--r-- | newlib/libc/stdio/fseeko.c | 355 | ||||
-rw-r--r-- | newlib/libc/stdio/ftell.c | 55 | ||||
-rw-r--r-- | newlib/libc/stdio/ftello.c | 140 |
6 files changed, 502 insertions, 332 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 0faa9abf8..c6a9758d7 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,14 @@ +2012-11-29 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * libc/include/sys/reent.h (__sFILE): Change type of _offset + from int to _off_t. + * libc/stdio/ftell.c: Use _ftello_r(). + * libc/stdio/ftello.c: Copy implementation from previous + _ftell_r(). + * libc/stdio/fseek.c: Use _fseeko_r(). + * libc/stdio/fseeko.c: Copy implementation from previous + _fseek_r(). + 2012-11-26 Sebastian Huber <sebastian.huber@embedded-brains.de> * libc/include/inttypes.h: Add and use __INTTYPES_EXP(). diff --git a/newlib/libc/include/sys/reent.h b/newlib/libc/include/sys/reent.h index 8518964f9..7e321e053 100644 --- a/newlib/libc/include/sys/reent.h +++ b/newlib/libc/include/sys/reent.h @@ -203,7 +203,7 @@ struct __sFILE { /* Unix stdio files get aligned to block boundaries on fseek() */ int _blksize; /* stat.st_blksize (may be != _bf._size) */ - int _offset; /* current lseek offset */ + _off_t _offset; /* current lseek offset */ #ifndef _REENT_SMALL struct _reent *_data; /* Here for binary compatibility? Remove? */ diff --git a/newlib/libc/stdio/fseek.c b/newlib/libc/stdio/fseek.c index 099a95892..34147faff 100644 --- a/newlib/libc/stdio/fseek.c +++ b/newlib/libc/stdio/fseek.c @@ -101,21 +101,9 @@ Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, #include <_ansi.h> #include <reent.h> #include <stdio.h> -#include <string.h> -#include <time.h> -#include <fcntl.h> -#include <stdlib.h> #include <errno.h> -#include <sys/stat.h> #include "local.h" -#define POS_ERR (-(_fpos_t)1) - -/* - * Seek the given file to the given offset. - * `Whence' must be one of the three SEEK_* macros. - */ - int _DEFUN(_fseek_r, (ptr, fp, offset, whence), struct _reent *ptr _AND @@ -123,264 +111,7 @@ _DEFUN(_fseek_r, (ptr, fp, offset, whence), long offset _AND int whence) { - _fpos_t _EXFNPTR(seekfn, (struct _reent *, _PTR, _fpos_t, int)); - _fpos_t target; - _fpos_t curoff = 0; - size_t n; -#ifdef __USE_INTERNAL_STAT64 - struct stat64 st; -#else - struct stat st; -#endif - int havepos; - - /* Make sure stdio is set up. */ - - CHECK_INIT (ptr, fp); - - _newlib_flockfile_start (fp); - - /* If we've been doing some writing, and we're in append mode - then we don't really know where the filepos is. */ - - if (fp->_flags & __SAPP && fp->_flags & __SWR) - { - /* So flush the buffer and seek to the end. */ - _fflush_r (ptr, fp); - } - - /* Have to be able to seek. */ - - if ((seekfn = fp->_seek) == NULL) - { - ptr->_errno = ESPIPE; /* ??? */ - _newlib_flockfile_exit (fp); - return EOF; - } - - /* - * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. - * After this, whence is either SEEK_SET or SEEK_END. - */ - - switch (whence) - { - case SEEK_CUR: - /* - * In order to seek relative to the current stream offset, - * we have to first find the current stream offset a la - * ftell (see ftell for details). - */ - _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ - if (fp->_flags & __SOFF) - curoff = fp->_offset; - else - { - curoff = seekfn (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR); - if (curoff == -1L) - { - _newlib_flockfile_exit (fp); - return EOF; - } - } - if (fp->_flags & __SRD) - { - curoff -= fp->_r; - if (HASUB (fp)) - curoff -= fp->_ur; - } - else if (fp->_flags & __SWR && fp->_p != NULL) - curoff += fp->_p - fp->_bf._base; - - offset += curoff; - whence = SEEK_SET; - havepos = 1; - break; - - case SEEK_SET: - case SEEK_END: - havepos = 0; - break; - - default: - ptr->_errno = EINVAL; - _newlib_flockfile_exit (fp); - return (EOF); - } - - /* - * Can only optimise if: - * reading (and not reading-and-writing); - * not unbuffered; and - * this is a `regular' Unix file (and hence seekfn==__sseek). - * We must check __NBF first, because it is possible to have __NBF - * and __SOPT both set. - */ - - if (fp->_bf._base == NULL) - __smakebuf_r (ptr, fp); - if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) - goto dumb; - if ((fp->_flags & __SOPT) == 0) - { - if (seekfn != __sseek - || fp->_file < 0 -#ifdef __USE_INTERNAL_STAT64 - || _fstat64_r (ptr, fp->_file, &st) -#else - || _fstat_r (ptr, fp->_file, &st) -#endif - || (st.st_mode & S_IFMT) != S_IFREG) - { - fp->_flags |= __SNPT; - goto dumb; - } -#ifdef HAVE_BLKSIZE - fp->_blksize = st.st_blksize; -#else - fp->_blksize = 1024; -#endif - fp->_flags |= __SOPT; - } - - /* - * We are reading; we can try to optimise. - * Figure out where we are going and where we are now. - */ - - if (whence == SEEK_SET) - target = offset; - else - { -#ifdef __USE_INTERNAL_STAT64 - if (_fstat64_r (ptr, fp->_file, &st)) -#else - if (_fstat_r (ptr, fp->_file, &st)) -#endif - goto dumb; - target = st.st_size + offset; - } - if ((long)target != target) - { - ptr->_errno = EOVERFLOW; - _newlib_flockfile_exit (fp); - return EOF; - } - - if (!havepos) - { - if (fp->_flags & __SOFF) - curoff = fp->_offset; - else - { - curoff = seekfn (ptr, fp->_cookie, 0L, SEEK_CUR); - if (curoff == POS_ERR) - goto dumb; - } - curoff -= fp->_r; - if (HASUB (fp)) - curoff -= fp->_ur; - } - - /* - * Compute the number of bytes in the input buffer (pretending - * that any ungetc() input has been discarded). Adjust current - * offset backwards by this count so that it represents the - * file offset for the first byte in the current input buffer. - */ - - if (HASUB (fp)) - { - curoff += fp->_r; /* kill off ungetc */ - n = fp->_up - fp->_bf._base; - curoff -= n; - n += fp->_ur; - } - else - { - n = fp->_p - fp->_bf._base; - curoff -= n; - n += fp->_r; - } - - /* - * If the target offset is within the current buffer, - * simply adjust the pointers, clear EOF, undo ungetc(), - * and return. - */ - - if (target >= curoff && target < curoff + n) - { - register int o = target - curoff; - - fp->_p = fp->_bf._base + o; - fp->_r = n - o; - if (HASUB (fp)) - FREEUB (ptr, fp); - fp->_flags &= ~__SEOF; - memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); - _newlib_flockfile_exit (fp); - return 0; - } - - /* - * The place we want to get to is not within the current buffer, - * but we can still be kind to the kernel copyout mechanism. - * By aligning the file offset to a block boundary, we can let - * the kernel use the VM hardware to map pages instead of - * copying bytes laboriously. Using a block boundary also - * ensures that we only read one block, rather than two. - */ - - curoff = target & ~(fp->_blksize - 1); - if (seekfn (ptr, fp->_cookie, curoff, SEEK_SET) == POS_ERR) - goto dumb; - fp->_r = 0; - fp->_p = fp->_bf._base; - if (HASUB (fp)) - FREEUB (ptr, fp); - fp->_flags &= ~__SEOF; - n = target - curoff; - if (n) - { - if (__srefill_r (ptr, fp) || fp->_r < n) - goto dumb; - fp->_p += n; - fp->_r -= n; - } - memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); - _newlib_flockfile_exit (fp); - return 0; - - /* - * We get here if we cannot optimise the seek ... just - * do it. Allow the seek function to change fp->_bf._base. - */ - -dumb: - if (_fflush_r (ptr, fp) - || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) - { - _newlib_flockfile_exit (fp); - return EOF; - } - /* success: clear EOF indicator and discard ungetc() data */ - if (HASUB (fp)) - FREEUB (ptr, fp); - fp->_p = fp->_bf._base; - fp->_r = 0; - /* fp->_w = 0; *//* unnecessary (I think...) */ - fp->_flags &= ~__SEOF; - /* Reset no-optimization flag after successful seek. The - no-optimization flag may be set in the case of a read - stream that is flushed which by POSIX/SUSv3 standards, - means that a corresponding seek must not optimize. The - optimization is then allowed if no subsequent flush - is performed. */ - fp->_flags &= ~__SNPT; - memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); - _newlib_flockfile_end (fp); - return 0; + return _fseeko_r (ptr, fp, offset, whence); } #ifndef _REENT_ONLY diff --git a/newlib/libc/stdio/fseeko.c b/newlib/libc/stdio/fseeko.c index 0d655d0e7..97eafd9ca 100644 --- a/newlib/libc/stdio/fseeko.c +++ b/newlib/libc/stdio/fseeko.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Red Hat Inc. + * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -15,9 +15,106 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +/* +FUNCTION +<<fseek>>, <<fseeko>>---set file position + +INDEX + fseek +INDEX + fseeko +INDEX + _fseek_r +INDEX + _fseeko_r + +ANSI_SYNOPSIS + #include <stdio.h> + int fseek(FILE *<[fp]>, long <[offset]>, int <[whence]>) + int fseeko(FILE *<[fp]>, off_t <[offset]>, int <[whence]>) + int _fseek_r(struct _reent *<[ptr]>, FILE *<[fp]>, + long <[offset]>, int <[whence]>) + int _fseeko_r(struct _reent *<[ptr]>, FILE *<[fp]>, + off_t <[offset]>, int <[whence]>) + +TRAD_SYNOPSIS + #include <stdio.h> + int fseek(<[fp]>, <[offset]>, <[whence]>) + FILE *<[fp]>; + long <[offset]>; + int <[whence]>; + + int fseeko(<[fp]>, <[offset]>, <[whence]>) + FILE *<[fp]>; + off_t <[offset]>; + int <[whence]>; + + int _fseek_r(<[ptr]>, <[fp]>, <[offset]>, <[whence]>) + struct _reent *<[ptr]>; + FILE *<[fp]>; + long <[offset]>; + int <[whence]>; + + int _fseeko_r(<[ptr]>, <[fp]>, <[offset]>, <[whence]>) + struct _reent *<[ptr]>; + FILE *<[fp]>; + off_t <[offset]>; + int <[whence]>; + +DESCRIPTION +Objects of type <<FILE>> can have a ``position'' that records how much +of the file your program has already read. Many of the <<stdio>> functions +depend on this position, and many change it as a side effect. + +You can use <<fseek>>/<<fseeko>> to set the position for the file identified by +<[fp]>. The value of <[offset]> determines the new position, in one +of three ways selected by the value of <[whence]> (defined as macros +in `<<stdio.h>>'): + +<<SEEK_SET>>---<[offset]> is the absolute file position (an offset +from the beginning of the file) desired. <[offset]> must be positive. + +<<SEEK_CUR>>---<[offset]> is relative to the current file position. +<[offset]> can meaningfully be either positive or negative. + +<<SEEK_END>>---<[offset]> is relative to the current end of file. +<[offset]> can meaningfully be either positive (to increase the size +of the file) or negative. + +See <<ftell>>/<<ftello>> to determine the current file position. + +RETURNS +<<fseek>>/<<fseeko>> return <<0>> when successful. On failure, the +result is <<EOF>>. The reason for failure is indicated in <<errno>>: +either <<ESPIPE>> (the stream identified by <[fp]> doesn't support +repositioning) or <<EINVAL>> (invalid file position). + +PORTABILITY +ANSI C requires <<fseek>>. + +<<fseeko>> is defined by the Single Unix specification. + +Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, +<<lseek>>, <<read>>, <<sbrk>>, <<write>>. +*/ + #include <_ansi.h> #include <reent.h> #include <stdio.h> +#include <string.h> +#include <time.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> +#include "local.h" + +#define POS_ERR (-(_fpos_t)1) + +/* + * Seek the given file to the given offset. + * `Whence' must be one of the three SEEK_* macros. + */ int _DEFUN(_fseeko_r, (ptr, fp, offset, whence), @@ -26,7 +123,258 @@ _DEFUN(_fseeko_r, (ptr, fp, offset, whence), _off_t offset _AND int whence) { - return _fseek_r (ptr, fp, (long)offset, whence); + _fpos_t _EXFNPTR(seekfn, (struct _reent *, _PTR, _fpos_t, int)); + _fpos_t target; + _fpos_t curoff = 0; + size_t n; +#ifdef __USE_INTERNAL_STAT64 + struct stat64 st; +#else + struct stat st; +#endif + int havepos; + + /* Make sure stdio is set up. */ + + CHECK_INIT (ptr, fp); + + _newlib_flockfile_start (fp); + + /* If we've been doing some writing, and we're in append mode + then we don't really know where the filepos is. */ + + if (fp->_flags & __SAPP && fp->_flags & __SWR) + { + /* So flush the buffer and seek to the end. */ + _fflush_r (ptr, fp); + } + + /* Have to be able to seek. */ + + if ((seekfn = fp->_seek) == NULL) + { + ptr->_errno = ESPIPE; /* ??? */ + _newlib_flockfile_exit (fp); + return EOF; + } + + /* + * Change any SEEK_CUR to SEEK_SET, and check `whence' argument. + * After this, whence is either SEEK_SET or SEEK_END. + */ + + switch (whence) + { + case SEEK_CUR: + /* + * In order to seek relative to the current stream offset, + * we have to first find the current stream offset a la + * ftell (see ftell for details). + */ + _fflush_r (ptr, fp); /* may adjust seek offset on append stream */ + if (fp->_flags & __SOFF) + curoff = fp->_offset; + else + { + curoff = seekfn (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR); + if (curoff == -1L) + { + _newlib_flockfile_exit (fp); + return EOF; + } + } + if (fp->_flags & __SRD) + { + curoff -= fp->_r; + if (HASUB (fp)) + curoff -= fp->_ur; + } + else if (fp->_flags & __SWR && fp->_p != NULL) + curoff += fp->_p - fp->_bf._base; + + offset += curoff; + whence = SEEK_SET; + havepos = 1; + break; + + case SEEK_SET: + case SEEK_END: + havepos = 0; + break; + + default: + ptr->_errno = EINVAL; + _newlib_flockfile_exit (fp); + return (EOF); + } + + /* + * Can only optimise if: + * reading (and not reading-and-writing); + * not unbuffered; and + * this is a `regular' Unix file (and hence seekfn==__sseek). + * We must check __NBF first, because it is possible to have __NBF + * and __SOPT both set. + */ + + if (fp->_bf._base == NULL) + __smakebuf_r (ptr, fp); + if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT)) + goto dumb; + if ((fp->_flags & __SOPT) == 0) + { + if (seekfn != __sseek + || fp->_file < 0 +#ifdef __USE_INTERNAL_STAT64 + || _fstat64_r (ptr, fp->_file, &st) +#else + || _fstat_r (ptr, fp->_file, &st) +#endif + || (st.st_mode & S_IFMT) != S_IFREG) + { + fp->_flags |= __SNPT; + goto dumb; + } +#ifdef HAVE_BLKSIZE + fp->_blksize = st.st_blksize; +#else + fp->_blksize = 1024; +#endif + fp->_flags |= __SOPT; + } + + /* + * We are reading; we can try to optimise. + * Figure out where we are going and where we are now. + */ + + if (whence == SEEK_SET) + target = offset; + else + { +#ifdef __USE_INTERNAL_STAT64 + if (_fstat64_r (ptr, fp->_file, &st)) +#else + if (_fstat_r (ptr, fp->_file, &st)) +#endif + goto dumb; + target = st.st_size + offset; + } + + if (!havepos) + { + if (fp->_flags & __SOFF) + curoff = fp->_offset; + else + { + curoff = seekfn (ptr, fp->_cookie, 0L, SEEK_CUR); + if (curoff == POS_ERR) + goto dumb; + } + curoff -= fp->_r; + if (HASUB (fp)) + curoff -= fp->_ur; + } + + /* + * Compute the number of bytes in the input buffer (pretending + * that any ungetc() input has been discarded). Adjust current + * offset backwards by this count so that it represents the + * file offset for the first byte in the current input buffer. + */ + + if (HASUB (fp)) + { + curoff += fp->_r; /* kill off ungetc */ + n = fp->_up - fp->_bf._base; + curoff -= n; + n += fp->_ur; + } + else + { + n = fp->_p - fp->_bf._base; + curoff -= n; + n += fp->_r; + } + + /* + * If the target offset is within the current buffer, + * simply adjust the pointers, clear EOF, undo ungetc(), + * and return. + */ + + if (target >= curoff && target < curoff + n) + { + register int o = target - curoff; + + fp->_p = fp->_bf._base + o; + fp->_r = n - o; + if (HASUB (fp)) + FREEUB (ptr, fp); + fp->_flags &= ~__SEOF; + memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); + _newlib_flockfile_exit (fp); + return 0; + } + + /* + * The place we want to get to is not within the current buffer, + * but we can still be kind to the kernel copyout mechanism. + * By aligning the file offset to a block boundary, we can let + * the kernel use the VM hardware to map pages instead of + * copying bytes laboriously. Using a block boundary also + * ensures that we only read one block, rather than two. + */ + + curoff = target & ~(fp->_blksize - 1); + if (seekfn (ptr, fp->_cookie, curoff, SEEK_SET) == POS_ERR) + goto dumb; + fp->_r = 0; + fp->_p = fp->_bf._base; + if (HASUB (fp)) + FREEUB (ptr, fp); + fp->_flags &= ~__SEOF; + n = target - curoff; + if (n) + { + if (__srefill_r (ptr, fp) || fp->_r < n) + goto dumb; + fp->_p += n; + fp->_r -= n; + } + memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); + _newlib_flockfile_exit (fp); + return 0; + + /* + * We get here if we cannot optimise the seek ... just + * do it. Allow the seek function to change fp->_bf._base. + */ + +dumb: + if (_fflush_r (ptr, fp) + || seekfn (ptr, fp->_cookie, offset, whence) == POS_ERR) + { + _newlib_flockfile_exit (fp); + return EOF; + } + /* success: clear EOF indicator and discard ungetc() data */ + if (HASUB (fp)) + FREEUB (ptr, fp); + fp->_p = fp->_bf._base; + fp->_r = 0; + /* fp->_w = 0; *//* unnecessary (I think...) */ + fp->_flags &= ~__SEOF; + /* Reset no-optimization flag after successful seek. The + no-optimization flag may be set in the case of a read + stream that is flushed which by POSIX/SUSv3 standards, + means that a corresponding seek must not optimize. The + optimization is then allowed if no subsequent flush + is performed. */ + fp->_flags &= ~__SNPT; + memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); + _newlib_flockfile_end (fp); + return 0; } #ifndef _REENT_ONLY @@ -37,8 +385,7 @@ _DEFUN(fseeko, (fp, offset, whence), _off_t offset _AND int whence) { - /* for now we simply cast since off_t should be long */ - return _fseek_r (_REENT, fp, (long)offset, whence); + return _fseeko_r (_REENT, fp, offset, whence); } #endif /* !_REENT_ONLY */ diff --git a/newlib/libc/stdio/ftell.c b/newlib/libc/stdio/ftell.c index 54a656c09..5af0709cb 100644 --- a/newlib/libc/stdio/ftell.c +++ b/newlib/libc/stdio/ftell.c @@ -105,64 +105,13 @@ _DEFUN(_ftell_r, (ptr, fp), { _fpos_t pos; - /* Ensure stdio is set up. */ - - CHECK_INIT (ptr, fp); - - _newlib_flockfile_start (fp); - - if (fp->_seek == NULL) - { - ptr->_errno = ESPIPE; - _newlib_flockfile_exit (fp); - return -1L; - } - - /* Find offset of underlying I/O object, then adjust for buffered - bytes. Flush a write stream, since the offset may be altered if - the stream is appending. Do not flush a read stream, since we - must not lose the ungetc buffer. */ - if (fp->_flags & __SWR) - _fflush_r (ptr, fp); - if (fp->_flags & __SOFF) - pos = fp->_offset; - else - { - pos = fp->_seek (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR); - if (pos == -1L) - { - _newlib_flockfile_exit (fp); - return pos; - } - } - if (fp->_flags & __SRD) - { - /* - * Reading. Any unread characters (including - * those from ungetc) cause the position to be - * smaller than that in the underlying object. - */ - pos -= fp->_r; - if (HASUB (fp)) - pos -= fp->_ur; - } - else if ((fp->_flags & __SWR) && fp->_p != NULL) - { - /* - * Writing. Any buffered characters cause the - * position to be greater than that in the - * underlying object. - */ - pos += fp->_p - fp->_bf._base; - } - - _newlib_flockfile_end (fp); + pos = _ftello_r (ptr, fp); if ((long)pos != pos) { pos = -1; ptr->_errno = EOVERFLOW; } - return pos; + return (long)pos; } #ifndef _REENT_ONLY diff --git a/newlib/libc/stdio/ftello.c b/newlib/libc/stdio/ftello.c index 216d88453..3a1885e81 100644 --- a/newlib/libc/stdio/ftello.c +++ b/newlib/libc/stdio/ftello.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Red Hat Inc. + * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted @@ -15,17 +15,149 @@ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +/* +FUNCTION +<<ftell>>, <<ftello>>---return position in a stream or file + +INDEX + ftell +INDEX + ftello +INDEX + _ftell_r +INDEX + _ftello_r + +ANSI_SYNOPSIS + #include <stdio.h> + long ftell(FILE *<[fp]>); + off_t ftello(FILE *<[fp]>); + long _ftell_r(struct _reent *<[ptr]>, FILE *<[fp]>); + off_t _ftello_r(struct _reent *<[ptr]>, FILE *<[fp]>); + +TRAD_SYNOPSIS + #include <stdio.h> + long ftell(<[fp]>) + FILE *<[fp]>; + + off_t ftello(<[fp]>) + FILE *<[fp]>; + + long _ftell_r(<[ptr]>, <[fp]>) + struct _reent *<[ptr]>; + FILE *<[fp]>; + + off_t _ftello_r(<[ptr]>, <[fp]>) + struct _reent *<[ptr]>; + FILE *<[fp]>; + +DESCRIPTION +Objects of type <<FILE>> can have a ``position'' that records how much +of the file your program has already read. Many of the <<stdio>> functions +depend on this position, and many change it as a side effect. + +The result of <<ftell>>/<<ftello>> is the current position for a file +identified by <[fp]>. If you record this result, you can later +use it with <<fseek>>/<<fseeko>> to return the file to this +position. The difference between <<ftell>> and <<ftello>> is that +<<ftell>> returns <<long>> and <<ftello>> returns <<off_t>>. + +In the current implementation, <<ftell>>/<<ftello>> simply uses a character +count to represent the file position; this is the same number that +would be recorded by <<fgetpos>>. + +RETURNS +<<ftell>>/<<ftello>> return the file position, if possible. If they cannot do +this, they return <<-1L>>. Failure occurs on streams that do not support +positioning; the global <<errno>> indicates this condition with the +value <<ESPIPE>>. + +PORTABILITY +<<ftell>> is required by the ANSI C standard, but the meaning of its +result (when successful) is not specified beyond requiring that it be +acceptable as an argument to <<fseek>>. In particular, other +conforming C implementations may return a different result from +<<ftell>> than what <<fgetpos>> records. + +<<ftello>> is defined by the Single Unix specification. + +No supporting OS subroutines are required. +*/ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "%W% (Berkeley) %G%"; +#endif /* LIBC_SCCS and not lint */ + +/* + * ftello: return current offset. + */ + #include <_ansi.h> #include <reent.h> #include <stdio.h> +#include <errno.h> +#include "local.h" _off_t _DEFUN(_ftello_r, (ptr, fp), struct _reent * ptr _AND register FILE * fp) { - /* for now we simply cast since off_t should be long */ - return (_off_t)_ftell_r (ptr, fp); + _fpos_t pos; + + /* Ensure stdio is set up. */ + + CHECK_INIT (ptr, fp); + + _newlib_flockfile_start (fp); + + if (fp->_seek == NULL) + { + ptr->_errno = ESPIPE; + _newlib_flockfile_exit (fp); + return -1L; + } + + /* Find offset of underlying I/O object, then adjust for buffered + bytes. Flush a write stream, since the offset may be altered if + the stream is appending. Do not flush a read stream, since we + must not lose the ungetc buffer. */ + if (fp->_flags & __SWR) + _fflush_r (ptr, fp); + if (fp->_flags & __SOFF) + pos = fp->_offset; + else + { + pos = fp->_seek (ptr, fp->_cookie, (_fpos_t) 0, SEEK_CUR); + if (pos == -1L) + { + _newlib_flockfile_exit (fp); + return pos; + } + } + if (fp->_flags & __SRD) + { + /* + * Reading. Any unread characters (including + * those from ungetc) cause the position to be + * smaller than that in the underlying object. + */ + pos -= fp->_r; + if (HASUB (fp)) + pos -= fp->_ur; + } + else if ((fp->_flags & __SWR) && fp->_p != NULL) + { + /* + * Writing. Any buffered characters cause the + * position to be greater than that in the + * underlying object. + */ + pos += fp->_p - fp->_bf._base; + } + + _newlib_flockfile_end (fp); + return pos; } #ifndef _REENT_ONLY @@ -34,7 +166,7 @@ _off_t _DEFUN(ftello, (fp), register FILE * fp) { - return (_off_t)_ftell_r (_REENT, fp); + return _ftello_r (_REENT, fp); } #endif /* !_REENT_ONLY */ |