/*
 *  This file is part of ixemul.library for the Amiga.
 *  Copyright (C) 1991, 1992  Markus M. Wild
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define KERNEL
#include "ixemul.h"
#include "kprintf.h"
#include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

/* 2.0 support */
#include <utility/tagitem.h>
#include <dos/dostags.h>


#define	PRB_CLI		0L	/* Do a CLI, not a shell	*/
#define	PRB_BACKGROUND	1L	/* Background shell		*/
#define	PRB_EXECUTE	2L	/* Do as EXECUTE...		*/
#define	PRB_INTERACTIVE	3L	/* Run an interactive shell	*/
#define	PRB_FB		7L	/* Alt function bit...		*/

#define	PRF_CLI		(1L << PRB_CLI)
#define	PRF_BACKGROUND	(1L << PRB_BACKGROUND)
#define	PRF_EXECUTE	(1L << PRB_EXECUTE)
#define	PRF_INTERACTIVE	(1L << PRB_INTERACTIVE)
#define	PRF_FB		(1L << PRB_FB)

#define	EXECUTE_ME		(PRF_FB|PRF_BACKGROUND|PRF_EXECUTE)	/* aptly named, doncha think?	*/

#define SYSSTACKSIZE (4096)	/* The typical default system stack size. */
#define STACKNAME ("IXSTACK")	/* Environment variable for minimum stack size */
#define STACKSIZE (250000)	/* Minimum to use if no IXSTACK and stack is SYSSTACKSIZE */

#define alloca __builtin_alloca

#undef MAX
#define	MAX(a,b) (((a)>(b))?(a):(b))

int
system (const char *cmd)
{
  int rc = -1, err = 0;
  int stack_size;
  int env_stack_size = 0;
  struct CommandLineInterface *CLI;
  struct Process *me;
  extern struct ixemul_base *ixemulbase;
  int omask;
  char *temp;

  if (cmd == NULL)
    return 1;
  /* I retry with our new signal mechanism ;-) */
  omask = syscall (SYS_sigsetmask, ~0);

  me = (struct Process *)FindTask(0);
  CLI = BTOCPTR (me->pr_CLI);

  /* Find out what the current stack size is.  If there is an environment
     variable (STACKNAME) that sets the minimum stack, and that stack value
     is at least as large as the system default stack value (SYSSTACKSIZE),
     then use either that value or the current value, whichever is larger.
     Otherwise, if the current stack value is the system default, which
     indicates the user has not set a specific stack, then default to a
     value (STACKSIZE) that should be large enough for most cases. */

  stack_size = CLI ? CLI->cli_DefaultStack * 4 : me->pr_StackSize;
  if ((temp = getenv (STACKNAME)) != NULL && (env_stack_size = atoi (temp)) >= SYSSTACKSIZE)
    stack_size = MAX (stack_size, env_stack_size);
  else if (stack_size <= SYSSTACKSIZE)
    stack_size = STACKSIZE;

  /* limited support to allow starting of files in the current directory
   * with `./foo'. The better approach would use the __plock() trick to
   * parse the command, LoadSeg it. But then this approach would have to
   * do the whole redirection stuff on its own.. */
  while (isspace (*cmd)) cmd++;
  while (cmd[0] == '.' && cmd[1] == '/') cmd += 2;
  /* convert absolute path names if enabled in ixemulbase */
  if (ixemulbase->ix_translate_slash && cmd[0] == '/')
    {
     char *path_sep = NULL;

     cmd++;
     if (path_sep = strchr (cmd, '/'))  *path_sep = ':';
    }

if (1)
	{
      struct TagItem tags [] = {
	/* a stack of 4K is generally ways too small.. */
	{ NP_StackSize, stack_size, },
	{ TAG_END, 0, }
      };

      rc = SystemTagList ((UBYTE *)cmd, tags);
      err = __ioerr_to_errno (IoErr ());

  syscall (SYS_sigsetmask, omask);

  if (rc > 128)
    {
      errno = EINTR;
    }
  else 
    {
      errno = err;
    }
  KPRINTF (("&errno = %lx, errno = %ld\n", &errno, errno));

  /* according to the BSD manual, system() should return the `exit status'
   * of the shell, the implementation returns the wait-status. So I return
   * an artificial wait status for now ... */
  return (rc >= 128) ? W_EXITCODE (0, rc & 0x7f) : W_EXITCODE (rc, 0);
	}
}
