/* -geschrieben unter Kickstart V1.3
   -läuft auch unter Kickstart V2.0
   -übersetzt mit Aztec C-Compiler V5.0 
    Aufruf: cc all -pa -wd -wp -wr -wu
            ln all c.lib 
   -läßt sich auch problemlos mit DICE übersetzen */
#include <string.h>
#include <stdlib.h>
#include <functions.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#define PUT(s)  Write((BPTR) OutputFile, s, (long) strlen(s))
#define BREAK   ((SetSignal(0L, 0L) & 4096L) == 4096L)
#define	HI_ON	"\033[33m"	
#define	HI_OFF	"\033[0m"	

enum Fehler { Kein_Fehler, Speicher_Fehler, Disk_Fehler, 
              Befehl_Fehler, Falscher_Aufruf, Abbruch };
enum wann { Anfang, Ende };           


void Aufruf(char *FName, struct FileHandle *OutputFile)
{
  PUT("Aufruf:  "HI_ON); PUT(FName); 
  PUT(HI_OFF"  [-A] [-E] Verzeichnis Befehl1 [Befehl2 Befehl3 ...]\n");
  PUT("\t "); PUT(FName); 
  PUT(" durchläuft rekursiv einen Verzeichnisbaum und führt\n");
  PUT("\t dabei die angegebene Befehlsfolge aus.\n");
  PUT("\t Verzeichnis    Name des Verzeichnisses, welches\n");
  PUT("\t                den Verzeichnisbaum festlegt.\n");
  PUT("\t                \"\" steht fuer das aktuelle Verzeichnis.\n");
  PUT("\t Befehl1        DOS-Befehle, die in den Verzeichnissen des\n");
  PUT("\t [Befehl2 ...]  Verzeichnisbaumes ausgeführt werden sollen.\n");
  PUT("\t                Mindestens ein Befehl muß angegeben werden.\n");
  PUT("\t                Da unter AMIGA-DOS keine Anführungszeichen\n");
  PUT("\t                übergeben werden können, muß man stattdessen\n");
  PUT("\t                ein Hochkomma (Alt+Ä) übergeben.\n");
  PUT("\t                \'\' steht für das Hochkomma selber.\n");
  PUT("\t [-A] [-E]      Über diese optionalen Parameter wird festgelegt in\n");
  PUT("\t                welcher Reihenfolge die Verzeichnisse abgearbeitet\n");
  PUT("\t                werden. Wird -E gewählt, so wird mit dem Ende des\n");
  PUT("\t                Verzeichnisbaumes begonnen; bei -A mit dem Anfang.\n");
  PUT("\t                -A ist voreingestellt, muß also nicht explizit\n");
  PUT("\t                angegeben werden.\n\n");
  PUT("\t                Tritt ein Fehler auf oder wird durch CTR-C abge-\n");
  PUT("\t                brochen, liefert "); PUT(FName); 
                         PUT(" den Fehlercode 10.\n\n");    
  PUT(HI_ON"\t                (c)M&T - geschrieben von Daniel Görtz\n\n"HI_OFF);
}

void Hochkomma_beruecksichtigen(char **Befehle)
{
  char *Befehl;

  while(*Befehle)
  {
    Befehl = *Befehle;
    while(*Befehl)
    {
      if(*Befehl == '\'' && *(Befehl+1) == '\'')
      {
        char *Dummy = Befehl;
        while(*Befehl = *(Befehl+1)) Befehl++;
        Befehl = Dummy;
      }
      else
        if(*Befehl == '\'') *Befehl = '\"';
      Befehl++;
    }
    Befehle++;
  }
}

enum Fehler Befehle_ausfuehren(char **Befehle, struct FileHandle *OutputFile)
{
  while(*Befehle)
    if(!(Execute(*Befehle++, NULL, OutputFile)))
      return Befehl_Fehler;
  return Kein_Fehler;
}

enum Fehler durchlaufe_Verzeichnis(char *Verzeichnis, char **Befehle, 
                                   struct FileHandle *OutputFile, 
                                   enum wann Zeitpunkt)
{
  enum Fehler Error = Kein_Fehler;
  struct FileLock *lock = NULL, *oldlock = NULL;
  struct FileInfoBlock *InfoBlock = NULL;

  if(!(lock = (struct FileLock *) Lock(Verzeichnis, ACCESS_READ))) 
     { Error = Disk_Fehler; goto FunkEnde; }
  oldlock = (struct FileLock *) CurrentDir((struct FileLock *) lock);      
  if(!(InfoBlock = (struct FileInfoBlock *)
       malloc(sizeof(struct FileInfoBlock))))
     { Error = Speicher_Fehler; goto FunkEnde; } 
  if(!(Examine((BPTR) lock, (BPTR) InfoBlock))) 
     { Error = Disk_Fehler; goto FunkEnde; } 
  
  if(Zeitpunkt == Anfang) 
    Error = Befehle_ausfuehren(Befehle, OutputFile);

  while(ExNext((BPTR) lock, (BPTR) InfoBlock) && Error == Kein_Fehler)
  {
    if(InfoBlock->fib_DirEntryType >= 0) 
      durchlaufe_Verzeichnis(InfoBlock->fib_FileName, Befehle, 
                             OutputFile, Zeitpunkt);
    if(BREAK) { Error = Abbruch; goto FunkEnde; }
  }

  if(Zeitpunkt == Ende)
    Error = Befehle_ausfuehren(Befehle, OutputFile);

  FunkEnde:
  if(lock) 
  {
    UnLock((BPTR) lock);
    CurrentDir(oldlock);
  }
  if(InfoBlock) free(InfoBlock);

  return Error;
}


void main(int argc, char **argv)
{
  struct FileHandle *OutputFile;
  enum wann Zeitpunkt = Anfang;
  enum Fehler Error;

  OutputFile = (struct FileHandle *) Output();
  if(argc >= 3)
  {
    Hochkomma_beruecksichtigen(argv);
    if(!strcmp(argv[1], "-e") || !strcmp(argv[1], "-E"))
      Zeitpunkt = Ende; 
    if(!strcmp(argv[1], "-a") || !strcmp(argv[1], "-A") || Zeitpunkt == Ende)
      Error = durchlaufe_Verzeichnis(argv[2], argv+3, OutputFile, Zeitpunkt);
    else
      Error = durchlaufe_Verzeichnis(argv[1], argv+2, OutputFile, Zeitpunkt);
  }
  else 
    Error = Falscher_Aufruf;

  switch(Error)
  {
    case Speicher_Fehler:
      PUT("Fehler wegen Speichermangels aufgetreten !\n");
      exit(10);
    case Disk_Fehler:
      PUT("Verzeichnis nicht vorhanden oder zerstört !\n");
      exit(10);
    case Befehl_Fehler:
      PUT("Befehl konnte nicht ordnungsgemäß ausgeführt werden !\n");
      exit(10);
    case Falscher_Aufruf:
      Aufruf(argv[0], OutputFile);
      exit(10);
    case Abbruch:
      PUT("*** BREAK\n");
      exit(10);
    case Kein_Fehler: 
      exit(0);
  }
}

