/* execute.c
 * v0.91
 * 
 * Holger Danielsson
 * (dani@lara.prima.ruhr.de)
 * 6.9.1996
 */
 
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <string.h>
#include <sys/wait.h>

#include "token.h"
#include "files.h"
#include "echo.h"
#include "set.h"
#include "goto.h"
#include "if.h"
#include "help.h"

/* Prototypen */
int execute_batchfile(char *argvec[]);

/* enthält den Exitcode der Programme */
int progexitcode=0;

/* enthält den Zustand der Environment-Variablen TERM */
int ansi;

/* Original-Environment des Programmes */
static char **org_env;


typedef enum {
    DEFAULT, SET, ORGENV, DIR, CD, CD2, DRIVE, ECHO, ECHO2, ECHO3, CLS, DEL, 
    HELP,  EXIT, RENAME, MKDIR, RMDIR, REM, GOTO, IF, CALL
} commands;

typedef struct {
    char *cp;
    commands t;
} item;

static item cmds[] =
{
    {"set",    SET    },
    {"orgenv", ORGENV },
    {"dir",    DIR    },
    {"cd",     CD     },
    {"cd..",   CD2    },
    {"drive",  DRIVE  },
    {"echo",   ECHO   },
    {"@echo",  ECHO2  },
    {"echo.",  ECHO3  },
    {"del",    DEL    },
    {"help",   HELP   },
    {"exit",   EXIT   },
    {"cls",    CLS    },
    {"rename", RENAME },
    {"mkdir",  MKDIR  },
    {"md",     MKDIR  },
    {"rmdir",  RMDIR  },
    {"rd",     RMDIR  },
    {"rem",    REM    },
    {"goto",   GOTO   },
    {"if",     IF     },
    {"call",   CALL   },
    {NULL,     0      }
};

/* die Original-Environment speichern */
void save_environment(char **env)
{
   org_env = env;
}

/* alle Token des aktuellen Kommandos ausgeben */ 
void write_command(char *argv[])
{
   int i = 0;
   while ( argv[i] ) 
      printf("%s ",argv[i++]);
   printf("\n");
}

/* ein Kommando als Echo ausgeben */
static void echo_command(char *argv[])
{
   char buffer[255];
   
   _getcwd2(buffer,255);
   if (ansi)  
      printf("\033[1;32m%s> \033[1;34m",buffer);
   else
      printf("%s> ",buffer);
   write_command(argv);
   if (ansi)
      printf("\033[0;1m");
}

/* Kommando bestimmen. Wenn kein gültiges Kommando erkannt wird,
 * wird das Ergebnis DEFAULT zurcükgegeben.
 */
static int get_command(char *argv[])
{
   int i;
   for (i = 0; cmds[i].cp; i++) {
      if (stricmp(cmds[i].cp, argv[0]) == 0) {
         return cmds[i].t;      /* Kommando gefunden: abbrechen */
      }
   }
   return DEFAULT;              /* Kommando nicht erkannt */
}

/* Kommando bearbeiten */
int execute_command(char *argv[], FILE *fd)
{
   int cmd;
   
   /* wenn ein Label entdeckt wird, können wir gleich aufhören.
    * Labels sind dadurch gekennzeichnet, daß die Zeile sofort mit
    * einem Doppelpunkt beginnt. Daran muß sich sofort der Name
    * des Labels anschließen.
    */
   if ( *argv[0]==':' ) 
      return 0;                  
   
   /* sonst suchen wir der Reihe nach alle Kommandos ab. Wird kein
    * passendes Kommando gefunden, wird die Voreinstellung
    * cmd=DEFAULT belassen.
    */ 
   cmd = get_command(argv);    
   
   /* Wenn der Echomodus eingestellt ist und nicht gerade der @ECHO-Befehl
    * entdeckt wurde, wird die ganze Befehlszeile ausgegeben.
    */
   if ( (echomode==1) && (cmd!=ECHO2) )
      echo_command(argv);
   
   /* gefundenes Kommando bearbeiten */
   switch (cmd) {
      case SET:
         execute_set(&argv[1]);
      break;

      case ORGENV:
         environ = org_env;
      break;

      case DIR:
         execute_dir(&argv[1]);
      break;

     case CD:
         execute_cd(&argv[1]);
      break;

      case CD2:
         _chdir2("..");
      break;

      case DRIVE:
         execute_drive(&argv[1]);
      break;

      case ECHO:              /* Echo (eventuell auch mit Echo) */
      case ECHO2:             /* Echo (auf alle Fälle ohne Echo) */
         execute_echo(&argv[1],1);
      break;
   
      case ECHO3:             /* Echo von reinem Text (ohne on/off) */ 
         execute_echo(&argv[1],0);
      break;  
   
      case REM:               /* ganz schwere Implementierung */
      break;
   
      case CLS:
         printf("\033[2J");
         printf("\033[H");
      break;

      case RENAME:
         execute_rename(&argv[1]);
      break;
   
      case MKDIR:
         execute_mkdir(&argv[1]);
      break;
   
      case RMDIR:
         execute_rmdir(&argv[1]);
      break;

      case DEL:
         execute_del(&argv[1]);
      break;

      case HELP:
         execute_help();
      break;

      case EXIT:
         exit(1);

      case GOTO:
         execute_goto(&argv[1],fd);
      break;
    
      case IF:
         execute_if(&argv[1],fd);
      break;
    
      /* Aufruf einer Batchdatei aus einer Batchdatei heraus */
      case CALL:
         if (strstr(argv[1], ".bat")) 
            return execute_batchfile(&argv[1]);
         else {
            puts("call without batchfile");
            return 1;
         }
      break;
      
      /* kein Kommando erkannt - damit bleiben zwei Möglichkeiten 
       *  1) Wechsel des Laufwerks: z.B. 'd:'
       *  2) Start eines Programmes
       */
      case DEFAULT:
         /* Wechsel des Laufwerks */
         if (strlen(argv[0]) == 2 && argv[0][1] == ':') {
            _chdrive(argv[0][0]);
            break;
         }

         /* Start eines Programmes:
          * Damit der Programm-Exitcode immer einen definierten Wert hat, 
          * wird er mit 0 initialisiert.
          */
         if (!strstr(argv[0], ".bat")) {
            progexitcode = 0;
            if (spawnvpe(P_NOWAIT, argv[0], argv, environ) == -1) {
               printf("error running program '%s'\n", argv[0]);
               return 1;
            }
            else
               putchar('\n');
         } 
            
   } /* switch */

   return 0;
}









