#ifndef AMIGA
#  include <errno.h>
#endif

#ifdef MSDOS
#  include <bdos.h>
#endif

#include <stdio.h>
#include <ctype.h>
#include "make.h"

#ifndef FALSE
#  define FALSE (0)
#endif

#ifndef TRUE
#  define TRUE (1)
#endif

#define BUFFSIZ (256)

#ifdef MSDOS
extern char *searchpath ();
#endif

extern char *getenv ();

#ifdef MSDOS
extern int _envseg;
#ifndef NOREALEXECUTE
static char param[256];
static char cmd[256];
static char *cmds[] = {
    "break",
    "chdir",
    "cd",
    "cls",
    "copy",
    "ctty",
    "date",
    "del",
    "erase",
    "dir",
    "echo",
    "exit",
    "for",
    "goto",
    "if",
    "mkdir",
    "md",
    "path",
    "pause",
    "prompt",
    "rem",
    "ren",
    "rename",
    "rmdir",
    "rd",
    "set",
    "shift",
    "time",
    "type",
    "ver",
    "verify",
    "vol",
    0
};
#endif	/* !NOREALEXECUTE */
#endif	/* MSDOS */

execute (str, noexecflag)
char *str;
int noexecflag;
{
    auto char tmp[BUFFSIZ];
    auto char buf[10];
    register int index = 0;
    register int rval;
    extern int ignore_errors;

    DBUG_ENTER ("execute");
    tmp[0] = EOS;
    while (*str != EOS) {
	if (*str == '\n') {
	    tmp[index] = EOS;
	    index = 0;
	    str++;
	    if ((rval = run (tmp, noexecflag)) != 0 && !ignore_errors) {
		fputs ("***Error Code ", stderr);
		itoa (rval, buf);
		fputs (buf, stderr);
		fputc ('\n', stderr);
		DBUG_RETURN (rval);
	    }
	} else if (index == (BUFFSIZ - 1)) {
	    fputs ("Command Too Long: ", stderr);
	    fputs (str, stderr);
	    fputs ("\nShorten.\n", stderr);
	    DBUG_RETURN (-1);
	} else {
	    tmp[index++] = *str++;
	}
    }
    DBUG_RETURN (0);
}



#ifdef TESTING
main ()
{
    auto char temp[128];

    for (;;) {
	printf ("Command: ");
	gets (temp);
	if (temp[0] == EOS) {
	    break;
	}
	printf ("        Execute: %d\n", run (temp));
    }
}
#endif

/* run(str)
 * char *str;
 *		returns the value of the executed command.  If the command is
 *		an MS-DOS resident command the command.com is executed else
 *		the program is invoked (looking down the PATH).
 *
 *		Written: Bradley N. Davis  University of Utah VCIS group
 *		Date: 4-Jan-84
 *
 */

static int run (str, noexecflag)
char *str;
int noexecflag;
{
#ifdef MSDOS
    auto struct execp ep;
    auto struct SREGS segs;
#else
    extern int system ();
#endif
    auto int status = 0;

    DBUG_ENTER ("run");
    while (*str == '\t' || *str == ' ') {
	str++;
    }
    putchar ('\t');
    puts (str);
    fflush (stdout);
    if (!noexecflag) {
#ifndef NOREALEXECUTE
#ifdef MSDOS
	if (str[0] == EOS) {	/* Blank Line? push to subshell */
	    strcpy (cmd, getenv ("COMSPEC"));
	    param[0] = EOS;
	    segread (&segs);
	    ep.ex_envseg = _envseg;
	    ep.ex_cmdadd = (unsigned) param;
	    ep.ex_cmdseg = segs.ss;
	    ep.ex_fcb1ad = 0;
	    ep.ex_fcb1sg = 0;
	    ep.ex_fcb2ad = 0;
	    ep.ex_fcb2sg = 0;
	    status = (exec (cmd, 0, &ep));
	} else if (resident (str)) {
	    status = (system (str));
	} else {
	    status = (program (cmd, param));
	}
#else
	CHECK_ABORT;
	status = system (str);
#endif	/* MSDOS */
#endif  /* !NOREALEXECUTE */
    }
    DBUG_3 ("sys", "subcommand returns status %d", status);
    DBUG_RETURN (status);
}

/*
 * resident(str)
 * char *str;
 *		returns true if the command in str is an MS-DOS resident
 *		command.
 *
 *		Written: Bradley N. Davis  University of Utah VCIS group
 *		Date: 4-Jan-84
 *
 */

#define iswhite(ch) (ch == ' ' || ch == '\t')

#ifdef MSDOS
#ifndef NOREALEXECUTE
static int resident (str)
char *str;
{
    register char **t;
    extern char *strpbrk ();
    register int i;
    register int j;

    DBUG_ENTER ("resident");
    while (iswhite (*str)) {
	str++;			/* trim blanks */
    }
    if (str[1] == ':' && isalpha (str[0])) {	/* look for x: */
	DBUG_RETURN (TRUE);
    }
    if (strpbrk (str, "<>|") != NULL) {		/* redirection? use system */
	DBUG_RETURN (TRUE);
    }
    i = 0;
    while (isalnum (*str)) {
	if (isupper (*str)) {
	    cmd[i++] = *str++ - 'A' + 'a';
	} else {
	    cmd[i++] = *str++;
	}
    }
    cmd[i] = EOS;
    for (t = cmds; *t; t++) {
	if (strcmp (*t, cmd) == 0) {
	    DBUG_RETURN (TRUE);
	}
    }
    strcat (cmd, ".bat");	/* Batch file? use system */
    if (searchpath (cmd) != 0) {
	cmd[i] = EOS;
	DBUG_RETURN (TRUE);
    }
    cmd[i] = EOS;
    j = strlen (str);
    i = 1;
    while ((param[i++] = *str++) != 0);
    param[0] = j;
    param[j + 1] = '\r';
    DBUG_RETURN (FALSE);
}

static int program (pcmd, pparam)
char *pcmd;
char *pparam;
{
#ifdef MSDOS
    auto struct execp ep;
    auto struct SREGS segs;
    register char *pathp;
    register int len;

    DBUG_ENTER ("program");
    len = strlen (pcmd);
    strcat (pcmd, ".com");
    pathp = searchpath (pcmd);
    if (pathp == 0) {
	pcmd[len] = EOS;
	strcat (pcmd, ".exe");
	pathp = searchpath (pcmd);
	if (pathp == 0) {
	    pcmd[len] = EOS;
	    errno = ENOENT;
	    DBUG_RETURN (-1);
	}
    }
    segread (&segs);
    ep.ex_envseg = _envseg;
    ep.ex_cmdadd = (unsigned) pparam;
    ep.ex_cmdseg = segs.ss;
    ep.ex_fcb1ad = 0;
    ep.ex_fcb1sg = 0;
    ep.ex_fcb2ad = 0;
    ep.ex_fcb2sg = 0;
    DBUG_RETURN (exec (pathp, 0, &ep));
#else
    fprintf (stderr, "Urk -- 'program()' unimplemented!\n");
    DBUG_RETURN (0);
#endif
}
#endif	/* !NOREALEXECUTE */
#endif	/* MSDOS */


#ifdef AMIGA
/*
 *	Do explicit check for abort.  When Enable_Abort is non-zero,
 *	Chk_Abort() cause program termination if CNTRL-C or CNTRL-D has
 *	been received.  Thus, we temporarily set it back to zero while we
 *	do the explicit test, so we can do our own clean up and exit.
 *	Note that if the -V flag was used, we spit out a confirming message
 *	that we are quitting.
 *
 */
 
void Check_Abort ()
{
    DBUG_ENTER ("Check_Abort");
    DBUG_2 ("abort", "do explicit test for CNTRL-C");
    DISABLE_ABORT;
    if (Chk_Abort () != 0) {
	exit (1);
    }
    ENABLE_ABORT;
    DBUG_VOID_RETURN;
}

#endif	/* AMIGA */
