1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericopenlibs/cstdlib/LSTDIO/FSEEK.C Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,318 @@
1.4 +/* FSEEK.C
1.5 + *
1.6 + * Portions Copyright (c) 1990-2004 Nokia Corporation and/or its subsidiary(-ies).
1.7 + * All rights reserved.
1.8 + */
1.9 +
1.10 +/*
1.11 + * Copyright (c) 1990 The Regents of the University of California.
1.12 + * All rights reserved.
1.13 + *
1.14 + * Redistribution and use in source and binary forms are permitted
1.15 + * provided that the above copyright notice and this paragraph are
1.16 + * duplicated in all such forms and that any documentation,
1.17 + * advertising materials, and other materials related to such
1.18 + * distribution and use acknowledge that the software was developed
1.19 + * by the University of California, Berkeley. The name of the
1.20 + * University may not be used to endorse or promote products derived
1.21 + * from this software without specific prior written permission.
1.22 + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1.23 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1.24 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1.25 + */
1.26 +
1.27 +/*
1.28 +FUNCTION
1.29 +<<fseek>>---set file position
1.30 +
1.31 +INDEX
1.32 + fseek
1.33 +
1.34 +ANSI_SYNOPSIS
1.35 + #include <stdio.h>
1.36 + int fseek(FILE *<[fp]>, long <[offset]>, int <[whence]>)
1.37 +
1.38 +TRAD_SYNOPSIS
1.39 + #include <stdio.h>
1.40 + int fseek(<[fp]>, <[offset]>, <[whence]>)
1.41 + FILE *<[fp]>;
1.42 + long <[offset]>;
1.43 + int <[whence]>;
1.44 +
1.45 +DESCRIPTION
1.46 +Objects of type <<FILE>> can have a ``position'' that records how much
1.47 +of the file your program has already read. Many of the <<stdio>> functions
1.48 +depend on this position, and many change it as a side effect.
1.49 +
1.50 +You can use <<fseek>> to set the position for the file identified by
1.51 +<[fp]>. The value of <[offset]> determines the new position, in one
1.52 +of three ways selected by the value of <[whence]> (defined as macros
1.53 +in `<<stdio.h>>'):
1.54 +
1.55 +<<SEEK_SET>>---<[offset]> is the absolute file position (an offset
1.56 +from the beginning of the file) desired. <[offset]> must be positive.
1.57 +
1.58 +<<SEEK_CUR>>---<[offset]> is relative to the current file position.
1.59 +<[offset]> can meaningfully be either positive or negative.
1.60 +
1.61 +<<SEEK_END>>---<[offset]> is relative to the current end of file.
1.62 +<[offset]> can meaningfully be either positive (to increase the size
1.63 +of the file) or negative.
1.64 +
1.65 +See <<ftell>> to determine the current file position.
1.66 +
1.67 +RETURNS
1.68 +<<fseek>> returns <<0>> when successful. If <<fseek>> fails, the
1.69 +result is <<EOF>>. The reason for failure is indicated in <<errno>>:
1.70 +either <<ESPIPE>> (the stream identified by <[fp]> doesn't support
1.71 +repositioning) or <<EINVAL>> (invalid file position).
1.72 +
1.73 +PORTABILITY
1.74 +ANSI C requires <<fseek>>.
1.75 +
1.76 +Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
1.77 +<<lseek>>, <<read>>, <<sbrk>>, <<write>>.
1.78 +*/
1.79 +
1.80 +#include <stdio_r.h>
1.81 +#include <time.h>
1.82 +#include <fcntl.h>
1.83 +#include <stdlib_r.h>
1.84 +#include <errno.h>
1.85 +#include <sys/stat.h>
1.86 +#include "LOCAL.H"
1.87 +
1.88 +#define POS_ERR (-(fpos_t)1)
1.89 +
1.90 +/*
1.91 + * Seek the given file to the given offset.
1.92 + * `Whence' must be one of the three SEEK_* macros.
1.93 + */
1.94 +
1.95 +/**
1.96 + Reposition stream's position indicator.
1.97 +@return If successful the function returns 0. Otherwise it returns nonzero.
1.98 +@param fp Pointer to an open file.
1.99 +@param offset Number of bytes from origin.
1.100 +@param whence Initial position from where offset is applied.
1.101 +*/
1.102 +EXPORT_C int
1.103 +fseek (register FILE *fp,long offset,int whence)
1.104 +{
1.105 + struct _reent *ptr;
1.106 + fpos_t (*seekfn)(void *, fpos_t, int);
1.107 + fpos_t target, curoff = -1;
1.108 + size_t n;
1.109 + struct stat st;
1.110 + int havepos;
1.111 +
1.112 + /* Make sure stdio is set up. */
1.113 +
1.114 + CHECK_INIT (fp);
1.115 + ptr = fp->_data;
1.116 +
1.117 + /* If we've been doing some writing, and we're in append mode
1.118 + then we don't really know where the filepos is. */
1.119 +
1.120 + if (fp->_flags & __SAPP && fp->_flags & __SWR)
1.121 + {
1.122 + /* So flush the buffer and seek to the end. */
1.123 + fflush (fp);
1.124 + }
1.125 +
1.126 + /* Have to be able to seek. */
1.127 +
1.128 + if ((seekfn = fp->_seek) == NULL)
1.129 + {
1.130 + ptr->_errno = ESPIPE; /* ??? */
1.131 + return EOF;
1.132 + }
1.133 +
1.134 + /*
1.135 + * Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
1.136 + * After this, whence is either SEEK_SET or SEEK_END.
1.137 + */
1.138 +
1.139 + switch (whence)
1.140 + {
1.141 + case SEEK_CUR:
1.142 + /*
1.143 + * In order to seek relative to the current stream offset,
1.144 + * we have to first find the current stream offset a la
1.145 + * ftell (see ftell for details).
1.146 + */
1.147 + if (fp->_flags & __SOFF)
1.148 + curoff = fp->_offset;
1.149 + else
1.150 + {
1.151 + curoff = (*seekfn) (fp->_cookie, (fpos_t) 0, SEEK_CUR);
1.152 + if (curoff == -1L)
1.153 + return EOF;
1.154 + }
1.155 + if (fp->_flags & __SRD)
1.156 + {
1.157 + curoff -= fp->_r;
1.158 + if (HASUB (fp))
1.159 + curoff -= fp->_ur;
1.160 + }
1.161 + else if (fp->_flags & __SWR && fp->_p != NULL)
1.162 + curoff += fp->_p - fp->_bf._base;
1.163 +
1.164 + offset += curoff;
1.165 + whence = SEEK_SET;
1.166 + havepos = 1;
1.167 + break;
1.168 +
1.169 + case SEEK_SET:
1.170 + case SEEK_END:
1.171 + havepos = 0;
1.172 + break;
1.173 +
1.174 + default:
1.175 + ptr->_errno = EINVAL;
1.176 + return (EOF);
1.177 + }
1.178 +
1.179 + /*
1.180 + * Can only optimise if:
1.181 + * reading (and not reading-and-writing);
1.182 + * not unbuffered; and
1.183 + * this is a `regular' Unix file (and hence seekfn==__sseek).
1.184 + * We must check __NBF first, because it is possible to have __NBF
1.185 + * and __SOPT both set.
1.186 + */
1.187 +
1.188 + if (fp->_bf._base == NULL)
1.189 + __smakebuf (fp);
1.190 + if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
1.191 + goto dumb;
1.192 + if ((fp->_flags & __SOPT) == 0)
1.193 + {
1.194 + if (seekfn != __sseek
1.195 + || fp->_file < 0
1.196 + || _fstat_r (ptr, fp->_file, &st)
1.197 + || (st.st_mode & S_IFMT) != S_IFREG)
1.198 + {
1.199 + fp->_flags |= __SNPT;
1.200 + goto dumb;
1.201 + }
1.202 +#ifdef HAVE_BLKSIZE
1.203 + fp->_blksize = st.st_blksize;
1.204 +#else
1.205 + fp->_blksize = 1024;
1.206 +#endif
1.207 + fp->_flags |= __SOPT;
1.208 + }
1.209 +
1.210 + /*
1.211 + * We are reading; we can try to optimise.
1.212 + * Figure out where we are going and where we are now.
1.213 + */
1.214 +
1.215 + if (whence == SEEK_SET)
1.216 + target = offset;
1.217 + else
1.218 + {
1.219 + if (_fstat_r (ptr, fp->_file, &st))
1.220 + goto dumb;
1.221 + target = st.st_size + offset;
1.222 + }
1.223 +
1.224 + if (!havepos)
1.225 + {
1.226 + if (fp->_flags & __SOFF)
1.227 + curoff = fp->_offset;
1.228 + else
1.229 + {
1.230 + curoff = (*seekfn) (fp->_cookie, 0L, SEEK_CUR);
1.231 + if (curoff == POS_ERR)
1.232 + goto dumb;
1.233 + }
1.234 + curoff -= fp->_r;
1.235 + if (HASUB (fp))
1.236 + curoff -= fp->_ur;
1.237 + }
1.238 +
1.239 + /*
1.240 + * Compute the number of bytes in the input buffer (pretending
1.241 + * that any ungetc() input has been discarded). Adjust current
1.242 + * offset backwards by this count so that it represents the
1.243 + * file offset for the first byte in the current input buffer.
1.244 + */
1.245 +
1.246 + if (HASUB (fp))
1.247 + {
1.248 + n = fp->_up - fp->_bf._base;
1.249 + curoff -= n;
1.250 + n += fp->_ur;
1.251 + }
1.252 + else
1.253 + {
1.254 + n = fp->_p - fp->_bf._base;
1.255 + curoff -= n;
1.256 + n += fp->_r;
1.257 + }
1.258 +
1.259 + /*
1.260 + * If the target offset is within the current buffer,
1.261 + * simply adjust the pointers, clear EOF, undo ungetc(),
1.262 + * and return. (If the buffer was modified, we have to
1.263 + * skip this; see fgetline.c.)
1.264 + */
1.265 +
1.266 + if ((fp->_flags & __SMOD) == 0 &&
1.267 + target >= curoff && target < (fpos_t)(curoff + n))
1.268 + {
1.269 + register int o = target - curoff;
1.270 +
1.271 + fp->_p = fp->_bf._base + o;
1.272 + fp->_r = n - o;
1.273 + if (HASUB (fp))
1.274 + FREEUB (fp);
1.275 + fp->_flags &= ~__SEOF;
1.276 + return 0;
1.277 + }
1.278 +
1.279 + /*
1.280 + * The place we want to get to is not within the current buffer,
1.281 + * but we can still be kind to the kernel copyout mechanism.
1.282 + * By aligning the file offset to a block boundary, we can let
1.283 + * the kernel use the VM hardware to map pages instead of
1.284 + * copying bytes laboriously. Using a block boundary also
1.285 + * ensures that we only read one block, rather than two.
1.286 + */
1.287 +
1.288 + curoff = target & ~(fp->_blksize - 1);
1.289 + if ((*seekfn) (fp->_cookie, curoff, SEEK_SET) == POS_ERR)
1.290 + goto dumb;
1.291 + fp->_r = 0;
1.292 + if (HASUB (fp))
1.293 + FREEUB (fp);
1.294 + fp->_flags &= ~__SEOF;
1.295 + n = target - curoff;
1.296 + if (n)
1.297 + {
1.298 + if (__srefill (fp) || fp->_r < (fpos_t)n)
1.299 + goto dumb;
1.300 + fp->_p += n;
1.301 + fp->_r -= n;
1.302 + }
1.303 + return 0;
1.304 +
1.305 + /*
1.306 + * We get here if we cannot optimise the seek ... just
1.307 + * do it. Allow the seek function to change fp->_bf._base.
1.308 + */
1.309 +
1.310 +dumb:
1.311 + if (fflush (fp) || (*seekfn) (fp->_cookie, offset, whence) == POS_ERR)
1.312 + return EOF;
1.313 + /* success: clear EOF indicator and discard ungetc() data */
1.314 + if (HASUB (fp))
1.315 + FREEUB (fp);
1.316 + fp->_p = fp->_bf._base;
1.317 + fp->_r = 0;
1.318 + /* fp->_w = 0; *//* unnecessary (I think...) */
1.319 + fp->_flags &= ~__SEOF;
1.320 + return 0;
1.321 +}