#ifndef MCH_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++;
    }

#ifdef ORIG
    putchar ('\t');
#endif

    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 MCH_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 /* MCH_AMIGA */
