/* fseek.c (emx+gcc) -- Copyright (c) 1990-1993 by Eberhard Mattes */

#include <sys/emx.h>
#include <stdio.h>
#include <io.h>
#include <errno.h>

int fseek (FILE *stream, long offset, int origin)
{
  long pos;

  if (!(stream->flags & _IOOPEN) || origin < 0 || origin > 2
      || (stream->flags & _IOSPECIAL))
    {
      errno = EINVAL;
      return (EOF);
    }

  /* fflush() is not required if all of the following conditions are met: */
  /* - stream is a read-only file                                         */
  /* - _IOREREAD not set (that is, ungetc() has not been called)          */
  /* - stream is buffered                                                 */
  /* - new position is within buffer                                      */

  if ((stream->flags & (_IORW|_IOREAD|_IOWRT|_IOREREAD)) == _IOREAD
      && bbuf (stream))
    {
      long file_pos, cur_pos, end_pos, buf_pos;

      file_pos = lseek (stream->handle, 0L, SEEK_CUR);
      if (file_pos == -1)
        return (EOF);
      cur_pos = file_pos - stream->rcount;
      if (origin == SEEK_CUR)
        {
          offset += cur_pos;
          origin = SEEK_SET;
        }
      else if (origin == SEEK_END)
        {
          end_pos = lseek (stream->handle, 0L, SEEK_END);
          lseek (stream->handle, file_pos, SEEK_SET);
          if (end_pos == -1)
            return (EOF);
          offset += end_pos;
          origin = SEEK_SET;
        }
      buf_pos = cur_pos - (stream->ptr - stream->buffer);
      if (offset >= buf_pos && offset < file_pos)
        {
          stream->ptr = stream->buffer + (offset - buf_pos);
          stream->rcount = file_pos - offset;
          stream->flags &= ~_IOEOF;
          return (0);
        }
    }
  fflush (stream);
  stream->flags &= ~_IOEOF;
  if (stream->flags & _IORW)
    stream->flags &= ~(_IOREAD|_IOWRT);
  if (origin == SEEK_CUR)
    {
      pos = ftell (stream);
      if (pos == -1L) return (EOF);
      offset += pos;
      origin = SEEK_SET;
    }
  return ((lseek (stream->handle, offset, origin) == -1L) ? EOF : 0);
}
