/*Aus dem Buch C-Kompaktreferenz von Helmut Herold*/
/*Bitte passen sie die Headerdateien Ihrem System an*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys\stat.h>
#include <unistd.h>
#include <dir.h>

/*Konstanten------------------------------------------*/
#define NODIRECT       1 /*Datei ist kein Directory*/
#define DIRECTOR       2 /*Datei ist ein Directory*/
#define NOREADDIRCT 3 /*Nichtlesbares Verzeichnis*/
#define NOSTAT           4 /*Datei auf die stat erfolglos ist*/
#define MAX 1000
#define FEHLER(string) {fprintf(stderr,"%s\n",(string));exit(1);}
/*-----------------------------------------------------------*/

/*Typendefinition------------------------------------------*/
typedef int AUSWERTUNG(const char *, const struct stat *,int);
static AUSWERTUNG auswertung;
/*---------------------------------------------------------*/

/*Globale Variablen-----------*/
static char pfadname[MAX];
static char suchstring[MAX];
static char gefundenin[MAX];
static int tiefe;
static long int dateizahl;
int gefunden=0;
/*----------------------------*/

/*Funktionsdeklarationen------------------*/
static int ebene_tiefer(char *,AUSWERTUNG *);
static int pfad_behandeln(AUSWERTUNG *);
/*-------------------------------------------*/

/*Funktionen==============================================*/
/*Baum um eine ebene tiefer absteigen---------------------*/
int ebene_tiefer(char *pfad, AUSWERTUNG *funktion)
{
 char dirname[MAX];
 int n;

/*Wir ermitteln den Working - Directory - Namen
und schreiben diesen an die Adresse von dirname*/
 if(getcwd(dirname,MAX) == NULL)
    FEHLER("Konnte den Namen des Working Directorys nicht ermitteln");

/*Wir wechseln in den Angegebenen Pfad*/
 if(chdir(pfad) == -1)
    FEHLER("Konnte nicht in den gewuenschten Pfad wechseln")

/*Wir ermitteln den Absoluten Pfadnamen und schreiben diesen
an die Adresse von pfadname*/
 if(getcwd(pfadname,MAX) == NULL)
    FEHLER("Konnte den Absolut. Pfadnamen nicht ermitteln...")

/*Wir wollen den aktuellen Pfad behandeln und schauen was
sich so darin befindet*/
 n=pfad_behandeln(funktion);
 printf("\n==== %ld ====\n",dateizahl);

/*Wenn der ganze Directorybaum durchlaufen ist geht es wieder
zurück zu unserem ursprünglichen Directory das wir am Anfang
dieser Funktion mit getcwd ermittelt und an die Adresse von
dirname übergeben haben*/
 if(chdir(dirname) == -1)
    FEHLER("Kann nicht in das urspr. Directory zurueckwechseln")

 return(n);
}
/*----------------------------------------------------------*/


/*----------------------------------------------------------*/
/*Funktion zur Behandlung des Pfades. Diese Funktion wird in
der Funktion ebene_tiefer(..) aufgerufen*/
static int pfad_behandeln(AUSWERTUNG *funktion)
{
 struct stat attribut;
 struct dirent *name;
 DIR *dir;
 int n;
 char *zeiger;

/*Wir wollen schauen ob unsere Globale Variable pfadname
deren Inhalt wir in der Funktion ebene_tiefer() gegeben
haben ein Directory ist oder nicht*/
 if(stat(pfadname,&attribut) == -1)
    return(funktion(pfadname, &attribut, NOSTAT)); /*Fehler stat*/

/*Ist es ein Directory oder keines(==0) (S_IFDIR)?*/
 if((attribut.st_mode & S_IFDIR) == 0)
    return(funktion(pfadname, &attribut, NODIRECT)); /*Kein Directory*/

/*Wenn wir bis hierhin gekommen sind liegt ein Directory vor*/
/*Ist das Directory überhaupt lesbar?(opendir)*/
 if((dir = opendir(pfadname)) == NULL)
  { /*Nicht Lesbar*/
   closedir(dir);
   return(funktion(pfadname, &attribut, NOREADDIRCT));
  }

/*Wir geben unseren Directorypfad aus*/
 if((n=funktion(pfadname, &attribut, DIRECTOR)) !=0)
     return (n);

/*Slash an den Pfadnamen hängen*/
 zeiger=pfadname+strlen(pfadname); /*Zeiger zeigt auf das Ende von pfadname*/
 *zeiger++ = '\\'; /*Slash hinhängen, bei Linux '/' */
 *zeiger = '\0'; /*String terminieren*/

/*Wir lesen den Inhalt von pfadnamen aus (readdir) */
 while((name=readdir(dir)) != NULL)
  {/*Falls es . und .. sind -> ignorieren*/
   if(strcmp((*name).d_name,".") && strcmp((*name).d_name,".."))
    {
     strcpy(zeiger,(*name).d_name); /*Dateiname nach dem Slash hängen*/
     tiefe++;
/*Bei der zu suchenden Datei ist auf Gross und Klein-
schreibung zu achten.*/
     if(strcmp((*name).d_name,suchstring) == 0)
      {
       gefunden=1;
       strcpy(gefundenin,pfadname);
      }

/*Achtung - Jetzt kommt eine Rekursion. Ein Rekursion ruft eine Funktion
immer wieder selbst auf bis die Abruchbedienung erfüllte ist*/
     if(pfad_behandeln(funktion) != 0) /*Rekursion*/
      {
        tiefe--;
        break;
       }
    tiefe--;
   }
  }//Ende while
 *(zeiger-1)= '\0';

 if(closedir(dir))
    FEHLER("Kann den erwuenschten Pfad nicht mehr schliessen")

 return(n);
}
/*-----------------------------------------------------------------*/

/*----------------------------------------------------------------*/
/*Funktion zur Auswertung und Ausgabe auf dem Bildschirm*/
static int auswertung(const char *pfad,const struct stat *zeiger,int dateityp)
{
 static int erstemal=1;
 int i;

 dateizahl++;
 if(!erstemal)
  {
   for(i=1; i<=tiefe; i++)
      printf("%4c",' ');
   printf("----%s",strrchr(pfad,'\\')+1);
  }
 else
  {
   printf("%s",pfad);
   erstemal=0;
  }

  switch(dateityp)
   {
     case NODIRECT :      if((*zeiger).st_mode & S_IFCHR) printf(" c\n");
                                    else if((*zeiger).st_mode & S_IFREG) printf("\n");
                                    break;
     case DIRECTOR :       printf("\\\n");
                                     break;
     case NOREADDIRCT : printf("\\-\n");
                                     break;
     case NOSTAT :           fprintf(stderr,"Fehler bei stat auf Datei %s\n",pfad);
                                     break;
     default :                    FEHLER("...Unbekannter Dateityp........exit")
   }
 return 0;
}
/*-------------------------------------------------------------------------*/
/*Ende der Funktionen======================================================*/

/*main - Funktion==========================================================*/
int main(int argc, char *argv[])
{
 char jn;
 char *z;
 if(argc != 3)
  {
   fprintf(stderr,"Benutzung %s Directory Datei\n",argv[0]);
   exit (1);
  }
 strcpy(suchstring,argv[2]);
 ebene_tiefer(argv[1], auswertung);

 if(gefunden==1)
  {
   z=gefundenin+strlen(gefundenin);
   while(*z-- != '\\');
   *++z='\0';

   printf("Datei gefunden in %s\n",gefundenin);
   printf("Wollen sie in das Verzeichnis wechseln (j/n) ? ");
   scanf("%c",&jn);
   if(jn=='j')
      chdir(gefundenin);
  }
 else
   printf("Konnte die Datei %s nicht finden\n",suchstring);


 return 0;
}
/*Ende Main und Ende Programm ==============================================*/