/*****************************************************************************
 *
 * FILE: rshell.c
 *
 *	Copyright (c) 1994-1996 by Rainer Schnitker
 *	Copyright (c)	   1996 by Holger Danielsson
 *	[...this place is reserved for your name...]
 *
 * AUTHORS:
 *	Rainer Schnitker (rainer@mathematik.uni-bielefeld.de)
 *	Holger Danielsson (dani@lara.prima.ruhr.de)
 *
 *
 * HISTORY:
 *	- 00.00.1995  initial version for rsxwin2 (rainer)
 *	- 28.02.1996  new features like command.com (dani)
 *	- 01.03.1996  new features, bugs fixed (dani)
 *	- 06.09.1996  Expandierung von Env.-Var. (dani)
 *	- 07.09.1996  bugs fixed (rainer)
 *
 *
 *
 *  This file is part of rshell
 *
 *  rshell is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  rshell 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with GNU CC; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *
 *****************************************************************************/

#include <emx/syscalls.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <malloc.h>
#include <process.h>
#include <signal.h>
#include <sys/wait.h>

#include "token.h"
#include "execute.h"

#define RUN_RSX   0x1000L
#define EOS	  '\0'
#define BUFLEN	  256

/* Prototypen */
int execute_command(char *argv[], FILE *fd);

/* Anzahl der Parameter beim Aufruf einer Batchdatei */
static int  parameterzahl;
/* Name der Batchdatei und maximal 9 Parameter merken */
static char *batchparameter[10];

/* String-Copy, bei dem der Zeiger auf das EOS-Zeichen des
 * Zielstrings zurückgeliefert wird.
 */
static char *strpcpy(char *dest, const char *source)
{
   while ((*dest++ = *source++) != 0)
    ;
   return dest - 1;
}

/* alle Parameter einer Batch-Datei speichern
 *  0 :  Name der Datei
 *  1-9: mögliche Einträge
 *	 (die Liste der Einträge ist mit NULL abgeschlossen)
 */
static void save_batchparameter(char *argv[])
{
   int i;
   for (i=0; i<10; i++) {
      if ( !argv[i] ) {
	 batchparameter[i] = NULL;
	 parameterzahl = i;
	 return;
      }
      batchparameter[i] = strdup(argv[i]);
   }
   parameterzahl = 10;

}

/* alle Parameter einer Batch-Datei wieder freigeben */
static void free_batchparameter(void)
{
   int i;
   for (i=0; i<parameterzahl; i++)
      free(batchparameter[i]);
}

/* expandiere alle gültigen Einträge in argv[]:
 *  - %% wird zu % "expandiert"
 *  - %0 zum Basisnamen der Batchdatei
 *  - %1..%9 zum übergebenen Parameter oder dem Leerstring
 %  - alle anderen Vorkommen von % werden nicht verändert
 *
 * Zu Beginn dieser Prozedur zeigen die Werte 'argv[]' in die
 * Eingabezeile. Da die Strings eventuell erweitert werden,
 * werden alle Daten lokal gepuffert. Dies gilt auch, wenn sie gar
 * nicht erweitert worden sind. Damit ist die spätere Freigabe des
 * Speichers leichter zu handhaben.
 */

static void expand_arguments(char **argv)
{
   int n;
   char *d, *s, *env, *dd;
   char buffer[1024];

   while ( *argv ) {
      /* printf("EXP %s --> ",*argv); */
      s = *argv;
      d = buffer;
      while (*s) {
	 /* Schauen, ob ein Expandierungszeichen vorliegt */
	 if ( *s == '%' ) {
	    s++;			 /* nächstes Zeichen */
	    if ( *s == '%' )             /* noch ein '%' ?   */
	       *d++ = *s++;		 /* %% --> %	     */
	    else if ( isdigit(*s) ) {	 /* eine Ziffer ?    */
	       n = *s++ - '0';           /* %0..%9 ersetzen  */
	       if ( n < parameterzahl )
		  d = strpcpy(d,batchparameter[n]);
	    }
	    else {			 /* anderes Zeichen? */
	       dd = d;
	       *d++ = '%';
	       while ( isalnum(*s) )
		  *d++ = *s++;
	       *d = '\0';
	       if ( *s == '%' ) {
		  env = getenv(strupr(dd+1));
		  if ( env ) {
		    /* printf("[%s](%s)",dd+1,env); */
		     strcpy(dd,env);
		     d = dd + strlen(env);
		     s++;
		  /*   printf("(%s) (%s) (%c)(%c)(%s)\n",dd,buffer,s[-1],*s,s);  */
		  } else
		     *d++ = *s++;
		} else
		   *d++ = *s++;
	    }
	 }
	 else
	    *d++ = *s++;	   /* alles andere übernehmen */
      }
      *d = EOS;
      *argv++ = strdup(buffer);
      /* printf("%s   (param=%d)\n",buffer1,parameterzahl);   */
   }
}

/* Puffer für alle Argumente wieder freigeben */
static void free_arguments(char **argv)
{
   while ( *argv )  {
      /* printf("FREE (%s)\n",*argv); */
      free(*argv++);
   }
}

/* Version ausgeben */
static void print_version(void)
{
   if (_emx_env & RUN_RSX) {
      int rsx_env = _emx_rev >> 16;
      int rsx_ver = _emx_rev & 0xFFFF;

      if (rsx_env == 1) {
	 printf("\033[31m This shell is running under RSXWIN , version %X", rsx_ver);
	 printf("\033[0m\n");
      }
      else if (rsx_env == 2)
	 printf("This shell is running under RSXNT , version %X\n", rsx_ver);
      else
	 printf("This shell is running under RSX , version %X\n", rsx_ver);
   }
   else
      printf("This shell is running under EMX , revision %X\n", _emx_rev);
}

void signal_sigcld(int signo)
{
    int rc, status;

    rc = wait(&status);

    if (rc != -1) {
	if (WIFEXITED (status)) {
	    progexitcode =  WEXITSTATUS(status);
	    /*
	    printf("TEST: Process %d exit with code %d\n", rc, progexitcode);
	    */
	   }
	else if (WIFSTOPPED(status))
	    printf("Process %d stopped by signal %d\n", rc, WSTOPSIG (status));
	else
	    printf("Process %d exit by signal %d\n", rc, WTERMSIG (status));

	fflush (stdout);
    }

    signal(SIGCLD, SIG_ACK);	 /* emx signal handling */
}

/* Test, ob es sich bei dem Kommando um eine Batchdatei handelt:
 * Ergebnis: 1 - ja
 *	     0 - nein
 *
 * 1) Test, auf das Kommando mit '.bat' aufhört. Dann ist es logischerweise
 *    eine Batchdatei.
 * 2) Die Endung '.bat' wird an das Kommando angehängt. Wenn diese Datei
 *    im aktuellen Verzeichnis existiert, ist auch eine Batchdatei gefunden.
 * In beiden Fällen wird der Name der gefundenen Batchdatei separat
 * zurückgegeben.
 */
static int isbatch(char *cmdname, char *buffer, int size)
{
   int len = strlen(cmdname);

   strcpy(buffer,cmdname);
   if ( stricmp(buffer+len-4,".bat") == 0 )
      return 1;

   strcpy(buffer + len,".exe");
   if ( access(buffer,0) == 0 )
      return 0;

   strcpy(buffer + len,".bat");
   if ( access(buffer,0) == 0 )
      return 1;
   else
      return 0;
}

/* Eine Batchdatei ausführen:
 *
 * 1) alle Argumente aus 'argvec' werden separat gesichert, da sie für
 *    spätere Expandierungen benötigt werden (save_batchparameter).
 * 2) Dann werden in einer Schleife alle Zeilen mit 'readline' eingelesen.
 * 3) Die aktuelle Zeile wird in einzelne Token zerlegt (make_tokens).
 *    Die gefundenen Token (argvec) zeigen dabei in die Eingabezeile.
 *    Wenn kein Token vorliegt, wird direkt zum Schleifenanfang gesprungen.
 * 4) Die einzelnen Token werden gegebenfalls expandiert (expand_arguments).
 *    Da die Strings eventuell erweitert werden müssen, müssen für alle Token
 *    'argvec' lokale Puffer angelegt werden,
 * 5) Das Kommando wird bearbeitet (execute_command).
 * 6) Die lokalen Puffer (argvec) für die angelegten Puffer werden wieder
 *    freigegeben (free_arguments).
 * 7) Zum Abschluß müssen die globalen Parameter der Batchdatei noch
 *    freigegeben werden (free_batchparameter).
 */
int execute_batchfile(char *argvec[])
{
   int result;
   char cline[512];
   FILE *fd;

   fd = fopen(argvec[0], "rt");
   if (!fd) {
      printf("batchfile '%s' doesn't exist\n",argvec[0]);
      return 1;
   }

   result = 0;
   progexitcode = 0;
   save_batchparameter(argvec);
   while (readline(fd, cline) >= 0) {
      if (!make_tokens(cline, argvec))
	 continue;
      expand_arguments(argvec);
      result = execute_command(argvec,fd);
      free_arguments(argvec);
      if ( result==1 )	break;
   }

   free_batchparameter();
   fclose(fd);
   return result;
}

#include <rsxioapp.h>

char rsxio_window_title[] = "RSXWIN32: rsxwin 32-bit test version";
int rsxio_window_close = 1;

int rsxio_main(int argc, char **argv, char **env)
{
   char cline[512],buffer[BUFLEN];
   char *argvec[64];

   signal(SIGCLD, signal_sigcld);
   signal(SIGINT, SIG_IGN);	    /* kein Control-c */

   save_environment(environ);
   ansi = 1; // ( getenv("TERM") ) ? 1 : 0;

   /* Ist es eine Batchdatei ? */
   if (argv[1] && isbatch(argv[1],buffer,BUFLEN)) {
      argv[1] = buffer; 	    /* Namen der Batch-Datei übernehmen */
      execute_batchfile(&argv[1]);  /* Batchdatei ausführen und fertig	*/
   }
   /* sonst gehen wir für die Kommandos in eine Warteschleife */
   else for (print_version();;) {
      /* aktuelles Verzeichnis bestimmen */
      cline[0] = _getdrive();
      cline[1] = ':';
      getcwd(cline+2, BUFLEN);
      strlwr(cline);
      /* aktuelles Verzeichnis ausgeben */
      if (ansi)
	 printf("\033[1;32m%s> \033[1;31m",cline);
      else
	 printf("%s> ", cline);

      /* Kommando einlesen */
      if (readline(stdin, cline) < 0)
	 continue;
      if (ansi)
	 printf("\033[0;1m");

      /* Kommando in Token zerlegen */
      if (!make_tokens(cline, argvec))
	 continue;

      /* expand cmdline like 'echo %VAR%' */
      expand_arguments(argvec);

      /* Kommando ausführen */
      if ( isbatch(argvec[0],buffer,BUFLEN)) {
	 argvec[0] = buffer;
	 execute_batchfile(argvec);
      }
      else
	 execute_command(argvec,NULL);
   }
   return 0;
}

