#include <string.h>
#include <stdio.h>
#include <dos.h>


/* AM - Needed by TC to compile ... */
#include <stdlib.h>
#include <process.h>

typedef unsigned char uint8;
typedef unsigned int uint16;

uint16 Version;

uint16 CheckForDOSEMU(void);
void usage (void);
send_command(char **argv);
void do_execute_dos (int argc, char **argv);
void do_set_dosenv (int agrc, char **argv);


int main(int argc, char **argv)
{
  if (argc == 1) {
    usage();
  }

  Version = CheckForDOSEMU();
  if (!Version) {
    printf ("This Command can only be used under DOSEMU.\n");
    exit (-1);
  }

  if (*argv[1] == '-') {
    /* Got a switch */
    switch ((argv[1])[1]) {
    case 'e':
    case 'E':
      /* EXECUTE dos command*/
      do_execute_dos (argc-2, argv+2);
      break;
    case 's':
    case 'S':
      /* SETENV */
      do_set_dosenv (argc-2, argv+2);
      break;
    default:
      usage();
    }
  }

  send_command (argv);

  return (0);
}

#define DOS_HELPER_INT            0xE6
#define DOS_HELPER_DOSEMU_CHECK   0x00

void (far * dosemu_id_proc)(void) = (void (far *)(void))MK_FP(0xfc00, 0x0000);
int  (far * unix_cmdline)(void)   = (int  (far *)(void))MK_FP(0xfc00, 0x0100);
int  (far * unix_finddos)(void)   = (int  (far *)(void))MK_FP(0xfc00, 0x0101);
int  (far * unix_envvar)(void)    = (int  (far *)(void))MK_FP(0xfc00, 0x0102);

void usage (void)
{
  printf ("Usage: UNIX [FLAG COMMAND]\n");
  printf ("Run Linux commands from DOSEMU\n\n");
  printf ("UNIX -e [ENVVAR]\n");
  printf ("  Execute the command given in the Linux environment variable \"ENVVAR\".\n");
  printf ("  If not given, use the argument to the -E flag of DOSEMU\n\n");
  printf ("UNIX command [arg1 ...]\n");
  printf ("  Execute the Linux command with the arguments given.\n\n");
  printf ("UNIX\n");
  printf ("  show this help screen\n\n\n");
  printf ("Note: Use UNIX only to run Linux commands that terminates without user\n");
  printf ("      interaction. Otherwise it will start and wait forever!\n");

  exit(-1);
}

/* returns non-zero major version number if DOSEMU is loaded */
uint16 CheckForDOSEMU(void)
{
    char far * id_string;

    _AH = 0xC0;
    geninterrupt(0x15);
    id_string = (char far *)MK_FP(_ES, _BX+10);
    if (_fstrncmp(id_string, "DOSEMU ", 7) == 0) {
       dosemu_id_proc();
       if (_AX == 0xaa55)
          return _BX;
    }

    _AH = 0x35;
    _AL = DOS_HELPER_INT;
    geninterrupt(0x21);
    if (_ES != 0 || _BX != 0) {
       _AL = DOS_HELPER_DOSEMU_CHECK;
       geninterrupt(DOS_HELPER_INT);
       if (_AX == 0xaa55)
          return _BX;
    }

    return (0);
}

send_command(char **argv)
{
    static char command_line[256] = "";
    struct REGPACK preg;

    argv++;

    while(*argv)
    {
	strcat(command_line, *argv);
	strcat(command_line, " ");
	argv++;
    }

    printf("Effective commandline: %s\n", command_line);

    if (Version >= 61) {
      _AX = _DS;
      _ES = _AX;
      _DX = (unsigned int) &command_line;
      unix_cmdline();
    }
    else {
      preg.r_ax = 0x50;
      preg.r_dx = (unsigned int) &command_line;
      preg.r_es = _DS;
      intr(0xe6, &preg);
    }

    return(0);
}


void do_execute_dos (int argc, char **argv)
{
  char data[256];
  struct REGPACK preg;

  if (Version >= 61) {
    if (argc == 0)
      data[0] = '\0';
    else
      strcpy(data, argv[0]);
    _AX = _DS;
    _ES = _AX;
    _DX = (unsigned int) &data;
    if (argc == 0)
      unix_finddos();
    else
      unix_envvar();
  }
  else {
    if (argc == 0) {
      data[0] = '\0';
      preg.r_ax = 0x51;
    } else {
      strcpy (data, argv[0]);
      preg.r_ax = 0x52;
    }
    preg.r_dx = (unsigned int) &data;
    preg.r_es = _DS;
    intr(0xe6, &preg);
    _AX = preg.r_ax;
  }

  if (!_AX) {
    /* SUCCESFUL */
    printf ("About to Execute : %s\n", data);

#ifdef GIBBER
    execvp (data, argv);   /* Search path - and replace ourselves ... */

    /* - unsuccesful exec ... */
    puts ("EXEC failed.\n");
#endif /* GIBBER */

    if (system (data)) {
      /* SYSTEM failed ... */
      fprintf (stderr, "SYSTEM failed ....(%d)", errno);
      exit (-1);
    }

    exit (0);
  } else {
    /* UNSUCESSFUL */
    puts ("FAILED to get DATA from DOSEMU.\n");

    exit (-1);
  }

}

void do_set_dosenv (int argc, char **argv)
{
  struct REGPACK preg;

  char data[256];

  if (argc == 0) {
    data[0] = '\0';
  } else {
    strcpy (data, argv[0]);
  }

  if (Version >= 61) {
    _AX = _DS;
    _ES = _AX;
    _DX = (unsigned int) &data;
    unix_envvar();
  }
  else {
    preg.r_ax = 0x52;
    preg.r_dx = (unsigned int) &data;
    preg.r_es = _DS;
    intr(0xe6, &preg);
    _AX = preg.r_ax;
  }

  if (!_AX) {
    /* SUCCESFUL */
    puts ("In the meantime, the environment variable would have been set to :\n");
    puts (data);

  } else {
    /* UNSUCCESFUL */
    printf ("Anyway, the lookup failed ...(%d)\n", _AX);
  }
  exit (-1);
}
