/* seeker.c; part of GNU CSSC.
 *
 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007,
 * 2008, 2009, 2010, 2001, 2014, 2019, 2024, 2026 Free Software
 * Foundation, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Program that determines if the target system can seek on its standard
 * input.
 */
#include <config.h>

#include <locale.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>

#include "gettext.h"
#include "progname.h"

#define ERR_USAGE (1)

void usage(const char *name, int retval);

#ifdef HAVE_FSETPOS
static void try_getpos(FILE *f)
{
  fpos_t pos;
  int rv;

  rv = fgetpos(f, &pos);
  printf("fgetpos() returns %d\n", rv);
  rv = fsetpos(f, &pos);
  printf("fsetpos() returns %d\n", rv);
}
#endif

static void try_fseek(FILE *f)
{
  long lrv;
  int rv;

  lrv = ftell(f);
  printf("ftell() returns %ld\n", lrv);
  rv = fseek(f, SEEK_SET, lrv);
  printf("fseek() returns %d\n", rv);
}

static void try_lseek()
{
  off_t pos;
  pos = lseek(0, 0, SEEK_CUR);
  printf("lseek() returns %ld [SEEK_CUR]\n", (long) pos);
  pos = lseek(0, pos, SEEK_CUR);
  printf("lseek() returns %ld [SEEK_SET]\n", (long) pos);
}


int do_help(const char *name)
{
  usage(name, 0);
  return 0;
}

int do_unbuffered(const char *name)
{
  (void) name;
  printf("stdin is unbuffered\n");
  setvbuf(stdin, (char *) NULL, _IONBF, 0u);
  return 0;
}

int do_blockbuffered(const char *name)
{
  (void) name;
  printf("stdin is fully-buffered\n");
  setvbuf(stdin, (char *) NULL, _IOFBF, BUFSIZ);
  return 0;
}

int do_linebuffered(const char *name)
{
  (void) name;
  printf("stdin is line-buffered\n");
  setvbuf(stdin, (char *) NULL, _IOLBF, 0);
  return 0;
}

int do_nothing(const char *name)
{
  (void) name;
  printf("stdin is buffered in the default way\n");
  return 0;
}


struct optact
{
  const char *option;
  int (*action)(const char *);
};
struct optact actions[] = {
  {"--help", do_help},
  {"--unbuffered", do_unbuffered},
  {"--fully-buffered", do_blockbuffered},
  {"--line-buffered", do_linebuffered},
  {"--default-buffering", do_nothing}
};

#define NOPTIONS (sizeof(actions)/sizeof(actions[0]))



void usage(const char *name, int retval)
{
  unsigned int j;

  fprintf(stderr, "usage: %s ", name);
  for (j = 0u; j < NOPTIONS; ++j)
    fprintf(stderr, "[%s] ", actions[j].option);
  fprintf(stderr, "\n");
  exit(retval);
}

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

  set_program_name(argv[0]);
  if (NULL == setlocale(LC_ALL, ""))
    {
      /* If we can't set the locale as the user wishes,
       * emit an error message and continue.   The error
       * message will of course be in the "C" locale.
       */
      perror("Error setting locale");
    }
  bindtextdomain(PACKAGE, LOCALEDIR);
  textdomain(PACKAGE);

  for (i = 1; i < argc; ++i)
    {
      if ('-' == argv[i][0])
	{
	  for (j = 0u; j < NOPTIONS; ++j)
	    {
	      if (0 == strcmp(argv[i], actions[j].option))
		{
		  (*actions[j].action) (argv[0]);
		  break;
		}
	    }

	  if (NOPTIONS == j)
	    {
	      fprintf(stderr, "Unknown option `%s'\n", argv[i]);
	      usage(argv[0], ERR_USAGE);	/* unknown option */
	    }
	}
      else			/* not an option */
	{
	  usage(argv[0], ERR_USAGE);
	}
    }
#ifdef HAVE_FSETPOS
  try_getpos(stdin);
#else
  printf("fgetpos() not supported.\n");
#endif
  try_fseek(stdin);
  try_lseek();
  return 0;
}
