/*----------------------------------------------------------------
                                RED
                      Remove Empty Directory
 
 Questo  programma  richiede  in linea il nome di una directory in
 cui si abbia anche, ma  soprattutto,  il  diritto  di  scrittura.
 Legge  ricorsivamente  le directory sottostanti eliminando quelle
 vuote. Se del caso, rimuove anche quella passata  come  parametro
 in linea.
 
 Benche` abbia eseguito vari controlli e posto la massima cura non
 posso escludere malfunzionamenti. Chiunque puo' usarlo, ma a pro-
 prio  rischio  e pericolo. Non sono assolutamente responsabile di
 danni e/o perdite di dati riconducibili alla sua esecuzione.

 
      Configurazione
 
 Il  programma  lavora  silenziosamente.  La  variabile d'ambiente
 RED_VERBOSE se posta a yes oppure si oppure 1 attiva la modalita'
 verbose (vengono stampate le directory rimosse). In  caso contra-
 rio oppure in sua mancanza la disattiva.
 
 
      Messaggistica
 
 Uso: red nome directory
      al programma va passata obbligatoriamente una directory
 
 directory xxxx errata|non esiste
      la directory passata in linea non esiste oppure non puo' es-
      sere acceduta
 
 errore apertura directory xxxx
      la directory in questione non puo' essere aperta per l'ispe-
      zione
 
 stat errata per xxxx
      impossibile determinare il tipo di file
 
 path (xxx/xxx) troppo lungo
      il nome  della directory, compreso il path, e' superiore  al
      massimo consentito
  
 xxxx non cancellata
      la directory in questione non puo' essere rimossa

 xxxx cancellata
      la directory e' stata rimossa  (solo se la modalita' VERBOSE
      e' attivata)
----------------------------------------------------------------*/

#include <dirent.h>
#include <linux/limits.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main (int argc, char **argv)
{
  char       dovesono [PATH_MAX+NAME_MAX], *p;
  int        leggidir (char *, int, int), stampa;
  extern int match (char *, char *, regmatch_t *);
  regmatch_t pmatch;

  if (argc != 2)
    {
      fprintf (stderr, "Uso: %s nome directory\n", argv[0]);
      exit (EXIT_FAILURE);
    }
  memset (dovesono, (int) NULL, sizeof dovesono);
  getcwd (dovesono, sizeof dovesono);
  strcat (strcat (dovesono, "/"), argv[1]);
  if (chdir (dovesono) == -1)
    {
      fprintf (stderr, "directory %s errata|non esiste\n", argv[1]);
      exit (EXIT_FAILURE);
    }
  p = getenv ("RED_VERBOSE");
  if (p == NULL)
    stampa = 0;
  else
    stampa = match (p, "[yY][eE][Ss]|[Ss][iI]|^1$", &pmatch);
  (void) leggidir (dovesono, sizeof dovesono, stampa);
  exit (EXIT_SUCCESS);
}

int leggidir (char *dir, int len, int stampa)
{
  char          *p;
  DIR           *d;
  int           n, nentry;
  struct dirent *ds;
  struct stat   buffer;

  if ((d = opendir (dir)) == NULL)
    {
      fprintf (stderr, "errore apertura directory %s\n", dir);
      exit (EXIT_FAILURE);
    }
  nentry = 0;
  while ((ds = readdir (d)))
    {
      if (stat (ds->d_name, &buffer) == -1)
        {
          fprintf (stderr, "stat errata per %s\n", ds->d_name);
          exit (EXIT_FAILURE);
        }
      nentry++;
      if (S_ISDIR (buffer.st_mode))
        if (strcmp (ds->d_name, ".") && strcmp (ds->d_name, ".."))
          {
            n = strlen (ds->d_name);
            if ((n+1+strlen(dir)) > len)
              {
                fprintf (stderr, "path (%s/%s) troppo lungo\n",
                  dir, ds->d_name);
                exit (EXIT_FAILURE);
              }
            strcat (strcat (dir, "/"), ds->d_name);
            chdir (dir);
            nentry += leggidir (dir, len, stampa);
            for (p = strrchr (dir, '/'); n; n--)
              *p++ = (int) NULL;
            chdir (dir);
          }
    }
  closedir (d);
  if (nentry == 2)
    {
      if (rmdir (dir) == -1)
        {
          fprintf (stderr, "%s non cancellata\n", dir);
          exit (EXIT_FAILURE);
        }
      if (stampa)
        printf ("%s cancellata\n", dir);
      return -1;
    }
  else
    return 0;
}