os/ossrv/genericopenlibs/cstdlib/LSTDIO/FSEEK.C
changeset 0 bde4ae8d615e
     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 +}