/* dj_startup -- Start-up code for GNU Fileutils under MS-DOS/DJGPP

   Written by Eli Zaretskii <eliz@is.elta.co.il>

   This code may be freely distributed, provided that this
   copyright notice is left intact.  There is no warranty on
   this code.

   Commentary:
   ----------

   GNU Fileutils deal with files, and are notorious (as most other
   Unix file-related utilities) for hardcoded assumptions about
   filenames, especially regarding the slash character and the
   insistance on knowing the fact that a filename that begins with
   anything other than a slash is a relative filename (what about
   DOS d:/file pathnames?).  To make these programs work on MSDOS,
   it makes sense to convert all the filename arguments to the
   forward-slash Unix-style notation at start-up.  This would
   eliminate multiple #ifdef's in the programs' code.  The only
   thing to take care of is to leave the options alone.

   This module is supplied to do this kind of automagic, by using the
   static constructor hooks provided in DJGPP v2.0 and above.  It
   should be linked with every program from this package and will be
   called automatically by the DJGPP start-up code (on crt1.c) just
   before the `main' function is called.

   There are a few other small services that this module does, while
   at that:

   * It sets the default file open mode to BINARY, which is
     appropriate for file I/O in this package and removes another
     reason for #ifdef's in the main code;

   * It sets the flag bits for the `stat' and `fstat' functions so
     as to avoid computing fields of `struct stat' that are expensive,
     unless that program really needs these fields.

   WARNING WARNING WARNING!!!

   This code relies heavily on the assumption that it will be called
   for a single command-line only once during the entire life of the
   program!  Thus all the flag variables are static.

   Also note that some of the code below relies on the program name
   in argv[0] and will break if you rename the program executable file!

   You HAVE been warned!

   WARNING WARNING WARNING!!!
*/

/*
 * Copied from Fileutils 3.16 DJGPP port for use in Fileutils 4.0.
 * Some slight modifications were made for use in Fileutils 4.1
 * by Richard Dawe <rich@phekda.freeserve.co.uk>.
 */

#include <config.h>

#ifdef __DJGPP__

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

#if (__DJGPP__ >= 3) || ((__DJGPP__ == 2) && (__DJGPP_MINOR__ >= 4))
#include <sys/xdevices.h>
#endif

int _crt0_startup_flags = _CRT0_FLAG_DROP_EXE_SUFFIX;

#ifndef _POSIX_SOURCE
/* Let's punish the user as little as we can by requesting
   the fastest possible version of `stat' for each program.
   Note that `ls' is not here because it sets the bits at
   run time, given the options on its command line.  */
#define  DEFAULT_STAT_BITS  (_STAT_WRITEBIT   | \
			     _STAT_ROOT_TIME  | \
			     _STAT_DIRSIZE    | \
			     _STAT_EXEC_MAGIC | \
			     _STAT_EXEC_EXT)

static struct {
  char *name;
  unsigned short stat_bits;
} prog_bits[] = {
    {"chmod",   ~(_STAT_DIRSIZE | _STAT_EXEC_EXT | _STAT_EXEC_MAGIC)},
    {"chown",   ~_STAT_DIRSIZE},
    {"cp",      ~(_STAT_DIRSIZE | _STAT_EXEC_EXT)},
    {"ln",      ~_STAT_EXEC_EXT},
    {"mv",	~(_STAT_DIRSIZE | _STAT_EXEC_EXT)},
    {"rm",	~(_STAT_DIRSIZE | _STAT_EXEC_EXT)},
    {"touch",	~_STAT_ROOT_TIME}
};
#endif

static void
init_stat_bits (const char *prog_name)
{
#ifndef _POSIX_SOURCE
  int i;

  _djstat_flags = DEFAULT_STAT_BITS;

  for (i = 0; i < sizeof (prog_bits) / sizeof (prog_bits[0]); i++)
    if (strcasecmp (prog_name, prog_bits[i].name) == 0)
      {
	_djstat_flags &= prog_bits[i].stat_bits;
	break;
      }
#endif
}

static void
init_file_io (const char *prog_name)
{
  _fmode = O_BINARY;

  /* Only `dd' needs to switch standard streams to binary.  */
  if (strcasecmp (prog_name, "dd") == 0)
    {
      if (!isatty (fileno (stdin)))
	setmode (fileno (stdin), O_BINARY);
      if (!isatty (fileno (stdout)))
	setmode (fileno (stdout), O_BINARY);
    }
}

static int options_first;       /* options preceed non-options */
static int no_more_options = 0; /* did we see all of the options yet? */

extern int    __crt0_argc;	/* defined by the DJGPP startup code */
extern char **__crt0_argv;

static void __attribute__((constructor))
djgpp_fileutils_startup (void)
{
  char *  argv0base, *dot;
  char ** arg_walker = __crt0_argv;
  int     arg_count  = __crt0_argc;

  /* Convert all non-option ARGV[] elements to forward slashes.  */
  if (!options_first)
    options_first = getenv("POSIXLY_CORRECT") != (char *)0;

  while (arg_count--)
    {
      char *p = *arg_walker++;

      if (no_more_options == 0)
	{
	  if (p[0] == '-')
	    {
	      if (p[1] == '-' && p[2] == '\0')
		no_more_options = 1;
	      continue;
	    }
	  else if (options_first)
	    no_more_options = 1;
	}
      while (*p)
	{
	  if (*p == '\\')
	    *p = '/';
	  p++;
	}
    }

  /* Find out what's the name of the program.  */
  argv0base = strrchr (*__crt0_argv, '/');
  if (!argv0base)
    argv0base = strrchr (*__crt0_argv, ':');
  if (argv0base)
    argv0base++;
  else
    argv0base = *__crt0_argv;

  /* When we are called by another DJGPP program, the
     _CRT0_FLAG_DROP_EXE_SUFFIX bit does not always work.  */
  if ((dot = strchr (argv0base, '.')))
    *dot = '\0';

  /* Richard Dawe <rich@phekda.freeserve.co.uk>: Use argv0base as
   * the actual program name. */
  __crt0_argv[0] = argv0base;

  init_stat_bits (argv0base);
  init_file_io (argv0base);

#if (__DJGPP__ >= 3) || ((__DJGPP__ == 2) && (__DJGPP_MINOR__ >= 4))
  __install_dev_zero();
  __install_dev_full();
#endif
}

#endif /* __DJGPP__ */
