/* ctrlz1.c (emx+gcc) */

/* Test lseek(), tell(), eof(), fseek(), and ftell() with a text-mode
   file that ends with Ctrl-Z. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

static int tell_after_ctrlz;
static int eof_at_ctrlz;
static int fd;
static FILE *f;
static char fname[] = "ctrlz1.inp";


static void check_fread (int read_count, const char *xstring, int xcount)
{
  int n;
  char buf[10];

  n = fread (buf, 1, read_count, f);
  if (n != xcount)
    {
      fprintf (stderr, "fread() returned %d instead of %d\n", n, xcount);
      exit (2);
    }
  if (memcmp (buf, xstring, n) != 0)
    {
      fprintf (stderr, "fread() read wrong data\n");
      exit (2);
    }
}


static void check_ftell (long x1, long x2)
{
  long n, expected;

  expected = (tell_after_ctrlz ? x2 : x1);
  n = ftell (f);
  if (n != expected)
    {
      fprintf (stderr, "ftell() returned %ld instead of %ld\n", n, expected);
      exit (2);
    }
}


static void test_stream (void)
{
#ifdef __IBMC__
  f = fopen (fname, "r");       /* CSet++ is broken */
#else
  f = fopen (fname, "rt");
#endif
  if (f == NULL)
    {
      perror ("fopen()");
      exit (2);
    }
  check_ftell (0, 0);
  check_fread (10, "abc", 3);
  check_ftell (3, 4);

  fseek (f, 0, SEEK_SET);
  check_fread (10, "abc", 3);
  check_ftell (3, 4);

  fseek (f, 1, SEEK_SET);
  check_fread (10, "bc", 2);
  check_ftell (3, 4);

  fseek (f, 0, SEEK_SET);
  check_fread (2, "ab", 2);
  check_ftell (2, 2);

  fseek (f, 1, SEEK_SET);
  check_fread (10, "bc", 2);
  check_ftell (3, 4);

  fseek (f, 0, SEEK_SET);
  check_fread (3, "abc", 3);
  check_ftell (3, 3);

  fseek (f, -1, SEEK_CUR);
  check_ftell (2, 2);
  check_fread (1, "c", 1);
  check_ftell (3, 3);

  fseek (f, -2, SEEK_CUR);
  check_ftell (1, 1);
  check_fread (2, "bc", 2);
  check_ftell (3, 3);

  fseek (f, 0, SEEK_SET);
  check_ftell (0, 0);
  check_fread (1, "a", 1);
  check_ftell (1, 1);
  fseek (f, 1, SEEK_CUR);
  check_ftell (2, 2);
  check_fread (1, "c", 1);
  check_ftell (3, 3);

  fclose (f);
}


static void check_tell (long x1, long x2)
{
  long n, expected;

  expected = (tell_after_ctrlz ? x2 : x1);
  n = tell (fd);
  if (n < 0)
    {
      perror ("tell()");
      exit (2);
    }
  if (n != expected)
    {
      fprintf (stderr, "tell() returned %ld instead of %ld\n", n, expected);
      exit (2);
    }
}


static void check_eof (int x1, int x2)
{
  int n, expected;

  expected = (eof_at_ctrlz ? x2 : x1);
  n = eof (fd);
  if (n < 0)
    {
      perror ("eof()");
      exit (2);
    }
  if (n != expected)
    {
      fprintf (stderr, "eof() returned %d instead of %d\n", n, expected);
      exit (2);
    }
}


static void check_read (int expected)
{
  int n, expn;
  char c;

  n = read (fd, &c, 1);
  if (n < 0)
    {
      perror ("read()");
      exit (2);
    }
  expn = (expected == -1 ? 0 : 1);
  if (n != expn)
    {
      fprintf (stderr, "read() returned %d instead of 0\n", n);
      exit (2);
    }
  if (expected != -1 && c != expected)
    {
      fprintf (stderr, "read() read %d instead of %d\n", c, expected);
      exit (2);
    }
}


static void test_lowio (void)
{
  fd = open (fname, O_TEXT | O_RDONLY);
  if (fd < 0)
    {
      perror ("open()");
      exit (1);
    }

  check_tell (0, 0);
  check_read ('a');
  check_tell (1, 1);
  check_read ('b');
  check_tell (2, 2);
  check_eof (0, 0);
  check_read ('c');
  check_eof (0, 0);
  check_tell (3, 3);
  check_eof (0, 1);
  check_read (-1);
  check_eof (1, 1);
  check_tell (3, 4);

  lseek (fd, 2, SEEK_SET);
  check_eof (0, 0);
  check_tell (2, 2);
  check_read ('c');
  check_tell (3, 3);

  lseek (fd, 2, SEEK_SET);
  check_tell (2, 2);
  check_read ('c');
  lseek (fd, -1, SEEK_CUR);
  check_tell (2, 2);
  check_read ('c');

  lseek (fd, 2, SEEK_SET);
  check_tell (2, 2);
  check_read ('c');
  lseek (fd, -2, SEEK_CUR);
  check_tell (1, 1);
  check_read ('b');

  lseek (fd, 0, SEEK_SET);
  check_tell (0, 0);
  check_read ('a');
  check_tell (1, 1);
  lseek (fd, 1, SEEK_CUR);
  check_tell (2, 2);
  check_read ('c');
  check_tell (3, 3);

  close (fd);
}


static void usage (void)
{
  puts ("Usage: ctrlz1 [-e] [-t]\n");
  puts ("Options:");
  puts ("  -e       eof() returns 1 at Ctrl-Z");
  puts ("  -t       tell() does not stop at Ctrl-Z");
  exit (1);
}


int main (int argc, char *argv[])
{
  int i;

  i = 1;
  while (i < argc)
    if (strcmp (argv[i], "-t") == 0)
      tell_after_ctrlz = 1, ++i;
    else if (strcmp (argv[i], "-e") == 0)
      eof_at_ctrlz = 1, ++i;
    else
      usage ();
  test_lowio ();
  test_stream ();
  return 0;
}
