/* ---------------------------------------------------------------------
   (c) ED 2005
   Project      : CLIB
   Function     : traverse directories recursively
   Module       : DIR
   File         : dir.c
   Created      : 05-09-2005
   Modified     : 15-09-2005
   --------------------------------------------------------------------- */

/* ---------------------------------------------------------------------
   Log

   1.1 15-09-2005 Improved the consistency of the interfaces (const)
   1.0 05-09-2005 Initial version files : "", "*.*", "*.x"
   0.0 05-09-2005 Created

   This code is not standard C but POSIX.1

   --------------------------------------------------------------------- */
#ifdef __cplusplus
#error This is not C++. Please use a C compiler.
#endif

#include "ed/inc/dir.h"

#include <string.h>
#include <stdio.h>

#ifndef __BORLANDC__
#include <unistd.h>
#else
#include <dir.h>
#endif

#include <dirent.h>

#include "ed/inc/tok.h"

#ifdef __TURBOC__
#include "ed/inc/str.h"
#define PATH_MAX MAXPATH
#else
#include <limits.h>
#endif

#if !defined (PATH_MAX)
#error PATH_MAX is not defined
#endif

/* macros ============================================================== */

#define ID "DIR"
#define VER "1.1"

/* constants =========================================================== */
/* types =============================================================== */
/* structures ========================================================== */
/* private data ======================================================== */
/* private functions =================================================== */

#if 0
/* ---------------------------------------------------------------------
   prt_cwd ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void prt_cwd (void)
{
   char s_path[PATH_MAX];
   char const *p_dir = getcwd (s_path, sizeof s_path);

   if (p_dir != NULL)
   {
      printf ("cwd: %s\n", p_dir);
   }
}
#endif

/* ---------------------------------------------------------------------
   dir_r ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
static void dir_r (char const *s_path
                   ,char const *s_files
                   ,dir_f * pf
                   ,void *p_user)
{
   int err = chdir (s_path);

   if (!err)
   {
      /* traverse the current directory */
      char s_cwd[PATH_MAX];
      char const *p_cwd = getcwd (s_cwd, sizeof s_cwd);

      if (p_cwd != NULL)
      {
         /* open the current directory */
         DIR *p_dir = opendir (".");

         if (p_dir != NULL)
         {
            /* traverse it */
            struct dirent *p_entry;
            int stop = 0;

            while ((p_entry = readdir (p_dir)) != NULL && !stop)
            {
               struct dirent entry = *p_entry;

#ifdef __BORLANDC__
               STR_tolower (entry.d_name);
#endif
               if (strcmp (entry.d_name, ".") == 0)
               {
                  /* to be defined */
               }
               else if (strcmp (entry.d_name, "..") == 0)
               {
                  /* to be defined */
               }
               else
               {
                  if (strcmp (s_files, "") == 0)
                  {
                     /* call all */

                     if (pf != NULL)
                     {
                        stop = pf (p_user, s_cwd, entry.d_name);
                     }
                  }
                  else
                  {
                     /* get the tokens */
                     tok_s *p_tok = tok_create (s_files, " ", NULL);

                     if (p_tok != NULL)
                     {
                        tok_info_s info;

                        tok_get (p_tok, &info);

                        {
                           int i;

                           for (i = 0; i < info.argc; i++)
                           {
                              if (strcmp (info.argv[i], "*.*") == 0)
                              {
                                 /* print all */
                                 if (pf != NULL)
                                 {
                                    stop = pf (p_user, s_cwd, entry.d_name);
                                 }
                              }
                              else
                              {
                                 if (strncmp (info.argv[i], "*.", 2) == 0)
                                 {
                                    char *p_ext = strchr (info.argv[i], '.');

                                    if (p_ext != NULL)
                                    {
                                       char *p_file_ext = strrchr (entry.d_name, '.');

                                       if (p_file_ext != NULL)
                                       {
                                          if (strcmp (p_ext, p_file_ext) == 0)
                                          {
                                             if (pf != NULL)
                                             {
                                                stop = pf (p_user, s_cwd, entry.d_name);
                                             }
                                          }
                                       }
                                    }
                                 }
                              }
                           }
                        }
                        tok_delete (p_tok), p_tok = NULL;
                     }
                  }

                  dir_r (entry.d_name, s_files, pf, p_user);

               }
            }
            closedir (p_dir), p_dir = NULL;
            (void) chdir ("..");
         }
      }
   }
}

/* internal public data ================================================ */
/* internal public functions =========================================== */
/* entry points ======================================================== */

/* ---------------------------------------------------------------------
   dir_sid ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *dir_sid (void)
{
   return ID;
}

/* ---------------------------------------------------------------------
   dir_sver ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
char const *dir_sver (void)
{
   return VER;
}

/* ---------------------------------------------------------------------
   dir ()
   ---------------------------------------------------------------------

   ---------------------------------------------------------------------
   I:
   O:
   --------------------------------------------------------------------- */
int dir (char *s_path, char *s_files, dir_f * pf, void *p_data)
{
   int err = 0;
   if (s_path != NULL)
   {
      if (s_files != NULL)
      {

#ifdef __BORLANDC__
         STR_tolower (s_path);
         STR_tolower (s_files);
#endif

         printf ("processing files '%s' from '%s'\n"
                 ,s_files
                 ,s_path);

         {
            char s_init_dir[PATH_MAX];
            char const *p_init_dir = getcwd (s_init_dir, sizeof s_init_dir);

            if (p_init_dir != NULL)
            {
               printf ("The initial directory is '%s'\n", p_init_dir);

               /* process the directory */
               dir_r (s_path, s_files, pf, p_data);

               /* restore the initial directory */
               err = chdir (p_init_dir);

               if (err)
               {
                  perror (p_init_dir);
               }
            }
         }
      }
      else
      {
         err = 1;
      }
   }
   else
   {
      err = 1;
   }

   return err;
}

/* public data ========================================================= */
