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

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


#define DQUOTE '"'
#define EOS    '\0'


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

/* Test, ob genügend Parameter definiert sind 
 * Ergebnis: 0 - es sind genügend Parameter definiert
 *               (ob sie sinnvoll sind, ist eine andere Frage)
 *           1 - fehlerhafte Anzahl von Parametern
 */
static int check_parameter(char *argv[], int n)
{
   int i = 0;
   for (i=0; i<n; i++) {
      if ( !argv[i] ) {
         puts("illegal IF command");
         return 1;
      }
   }
   return 0;
}

/* Status des NOT-Kommandos im IF-Befehl (0/1) */
static int negate;

/* IF-Kommando mit Abfrage des ERRORLEVEL:
 *
 * Syntax:  IF [NOT] ERRORLEVEL n command...
 * argv[]:                      0    1
 *
 * Das Kommando 'command' wird nur dann ausgeführt, wenn
 * der Exitcode eines vorher beendeten Programmes >= n ist.
 * Der optionale Parameter NOT kehrt die zu überprüfende
 * Bedingung um.
 */

static int execute_iferrorlevel(char *argv[], FILE *fd)
{
   char *p;
   int num;
   
   /* Anzahl der definierten Parameter testen */
   if ( check_parameter(argv,2) )
      return 1;

   /* der erste Parameter darf nur aus Ziffern bestehen */
   p = argv[0];               
   while (*p) {
      if ( !isdigit(*p++) ) {
         puts("wrong errorlevel");
         return 1;
      }
   }
   
   num = atoi( argv[0] );
   if ( ((negate==0) && (progexitcode>=num)) ||
        ((negate==1) && (progexitcode< num)) ) {
      return execute_command(&argv[1],fd);       /* Kommando ausführen */
   }
   else 
      return 0;
}

/* IF-Kommando mit der Existenz-Abfrage einer Datei/Directory:
 *
 * Syntax:  IF [NOT] EXIST name command...
 * argv[]:                  0      1
 *
 * Das Kommando 'command' wird nur dann ausgeführt, wenn
 * die angegebene Datei/Directory existiert. Der optionale Parameter 
 * NOT kehrt die zu überprüfende Bedingung um.
 */
 
static int execute_ifexist(char *argv[], FILE *fd)
{
   int exist;

   /* Anzahl der definierten Parameter testen */
   if ( check_parameter(argv,2) )
      return 1;

   exist = access(argv[0],0);  /* 0, wenn die Datei/Directory existiert */
   if ( ((negate==0) && (exist==0)) || ((negate==1) && (exist==-1))) { 
      return execute_command(&argv[1],fd);       /* Kommando ausführen */
   }
   else
      return 0;
}

/* IF-Kommando mit einem Stringvergleich:
 *
 * (a) Syntax:  IF [NOT] string1==string2 command...
 *     argv[]:                   0            1
 *
 * (b) Syntax:  IF [NOT] string1 == string2 command...
 *     argv[]:              0    1      2      3
 *
 * Das Kommando 'command' wird nur dann ausgeführt, wenn
 * der Stringvergleich ein wahres Ergebnis liefert. Der optionale 
 * Parameter NOT kehrt die zu überprüfende Bedingung um.
 * Die einzelnen Strings können direkt angegeben oder auch in 
 * Hochkommata eingeschlossen sein. Weiterhin können auch bis zu
 * 9 Parameter der Batchdatei angesprochen werden (%1,%2,...,%9)
 */

static int execute_ifcompare(char *argv[], FILE *fd)
{
   int result,cmdindex;
   char *p,*p1,*p2;
  
   /* Anzahl der definierten Parameter testen */
   if ( check_parameter(argv,2) )
      return 1;

   /* Testen, ob Fall (a) oder (b) vorliegt.
    * Im Fall (a) müssen die beiden zu vergleichenden Strings aus
    * argv[0] herausgefiltert werden.
    */
   p = strstr(argv[0],"==");
   if ( p ) {
      *p = EOS;
      p1 = argv[0];
      p2 = p + 2;
      cmdindex = 1;
   }
   else {
      /* Im Fall (b) existiert für jeden String ein eigener Eintrag.
       * Zusätlich muß in argv[1] der vergleichsoperator stehen.
       */
      if ( check_parameter(&argv[2],2) )  /* zwei weitere Parameter */
         return 1;
      if ( strcmp(argv[1],"==") ) {       /* Vergleichsoperator ?   */
         puts("illegal IF command");
         return 1;
      }
      p1 = argv[0];
      p2 = argv[2];
      cmdindex = 3;
   }
   
   /* vergleichen und auswerten */
   result = ( stricmp(p1,p2)==0 ) ? 0 : 1; 
   if ( ((negate==0) && (result==0)) || ((negate==1) && (result==1)) )
      return execute_command(&argv[cmdindex],fd);
   else
      return 0;
}

/* IF in einer Batchdatei ausführen:
 *
 * Zunächst wird geprüft, ob der optionale Parameter NOT vorhanden
 * ist. Das Ergebnis dieser Überprüfung wird in 'negate' festgehalten.
 * Danach wird geklärt, welcher der drei möglichen IF-Befehle vorliegt
 * und die entsprechende Funktion aufgerufen.
 *
 * Syntax: IF ERRORLEVEL n command ...
 *         IF EXIST command ...
 *         IF string1==string2 command ...
 *         IF string1 == string2 command ...
 *
 *         IF NOT ERRORLEVEL n command ...
 *         IF NOT EXIST command ...
 *         IF NOT string1==string2 command ...
 *         IF NOT string1 == string2 command ...
 *
 * In allen Fällen ist argv[0] das erste Argument hinter IF. Ist 
 * argv[0]=NOT, wird der übergebene Befehl an argv[1] erkannt, 
 * ohne NOT bereits an argv[0]. Der entsprechende Index stimmt damit
 * mit dem Wert der Variablen 'negate' überein.
 * 
 */
 
int execute_if(char *argv[], FILE *fd)
{
   int argindex;
   
   if ( !fd ) {
      puts("use IF only in batchfiles");
      return 0;
   }

   /* ein Parameter muß auf alle Fälle vorhanden sein */
   if ( check_parameter(argv,0) )  
      return 1;
   
   negate = ( stricmp(argv[0],"not")==0 ) ? 1 : 0; 
   argindex = negate;
   
   /* mit NOT auch noch ein weiterer Parameter */
   if ( (argindex==1) && (!argv[1]) ) {
      puts("illegal IF command");
      return 1;
   }
   
   /* die richtige Prozedur aufrufen */
   if ( stricmp(argv[argindex],"errorlevel")==0 ) 
      return execute_iferrorlevel(&argv[argindex+1],fd);
   else if ( stricmp(argv[argindex],"exist")==0) 
      return execute_ifexist(&argv[argindex+1],fd);
   else 
      return execute_ifcompare(&argv[argindex],fd);
}





















