Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  2. /*
  3.  * Recursively descent the directory hierarchy rooted in DIR,
  4.  * calling FUNC for each object in the hierarchy.  We cannot
  5.  * use ftw(), because it uses some non-ANSI functions which
  6.  * will pollute ANSI namespace, while we need this function
  7.  * in some ANSI functions (e.g., rename()).  Thus, this function
  8.  * is closely modeled on ftw(), but uses DOS directory search
  9.  * functions and structures instead of opendir()/readdir()/stat().
  10.  *
  11.  * Copyright (c) 1995 Eli Zaretskii <eliz@is.elta.co.il>
  12.  *
  13.  * This software may be used freely as long as this copyright notice is
  14.  * left intact.  There is no warranty on this software.
  15.  *
  16.  */
  17.  
  18. #include <libc/stubs.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <errno.h>
  22. #include <ctype.h>
  23. #include <dir.h>
  24.  
  25. #define FA_ALL  (FA_RDONLY|FA_HIDDEN|FA_SYSTEM|FA_LABEL|FA_DIREC|FA_ARCH)
  26.  
  27. int
  28. __file_tree_walk(const char *dir,
  29.                int (*func)(const char *, const struct ffblk *))
  30. {
  31.   struct ffblk  ff;
  32.   unsigned char searchspec[FILENAME_MAX];
  33.   unsigned char found[FILENAME_MAX], *dir_end;
  34.   int e = errno;
  35.  
  36.   if (dir == 0 || func == 0)
  37.     {
  38.       errno = EFAULT;
  39.       return -1;
  40.     }
  41.  
  42.   if (*dir == '\0')
  43.     {
  44.       errno = ENOENT;
  45.       return -1;
  46.     }
  47.  
  48.   /* Construct the search spec for findfirst().  Treat ``d:'' as ``d:.''.  */
  49.   strcpy(searchspec, dir);
  50.   dir_end = searchspec + strlen(searchspec) - 1;
  51.   if (*dir_end == ':')
  52.     {
  53.       *++dir_end = '.';
  54.       *++dir_end = '\0';
  55.     }
  56.   else if (*dir_end == '/' || *dir_end == '\\')
  57.     *dir_end   = '\0';
  58.   else
  59.     ++dir_end;
  60.   strcpy(dir_end, "/*.*");
  61.  
  62.   /* Prepare the buffer where the full pathname of the found files
  63.      will be placed.  */
  64.   strcpy(found, dir);
  65.   dir_end = found + strlen(found) - 1;
  66.   if (*dir_end == ':')
  67.     {
  68.       *++dir_end = '.';
  69.       dir_end[1] = '\0';
  70.     }
  71.   if (*dir_end != '/' && *dir_end != '\\')
  72.     {
  73.       /* Try to preserve user's forward/backward slash style.  */
  74.       *++dir_end = strchr(found, '\\') == 0 ? '/': '\\';
  75.       *++dir_end   = '\0';
  76.     }
  77.   else
  78.     ++dir_end;
  79.  
  80.   if (findfirst(searchspec, &ff, FA_ALL))
  81.     return -1;
  82.  
  83.   do
  84.     {
  85.       int func_result;
  86.       unsigned char *p = dir_end;
  87.  
  88.       /* Skip `.' and `..' entries.  */
  89.       if (ff.ff_name[0] == '.' &&
  90.           (ff.ff_name[1] == '\0' || ff.ff_name[1] == '.'))
  91.         continue;
  92.  
  93.       /* Construct full pathname in FOUND[].  */
  94.       strcpy(dir_end, ff.ff_name);
  95.  
  96.       /* Convert name of found file to lower-case.  Cannot use
  97.          strlwr() because it's non-ANSI.  Sigh... */
  98.       while (*p)
  99.         *p++ = tolower(*p);
  100.  
  101.       /* Invoke FUNC() on this file.  */
  102.       if ((func_result = (*func)(found, &ff)) != 0)
  103.         return func_result;
  104.  
  105.       /* If this is a directory, walk its siblings.  */
  106.       if (ff.ff_attrib & 0x10)
  107.         {
  108.           int subwalk_result;
  109.  
  110.           if ((subwalk_result = __file_tree_walk(found, func)) != 0)
  111.             return subwalk_result;
  112.         }
  113.     } while (findnext(&ff) == 0);
  114.  
  115.   if (errno == ENMFILE)     /* normal case: tree exhausted */
  116.     {
  117.       errno = e;    /* restore errno from previous syscall */
  118.       return 0;
  119.     }
  120.  
  121.   return -1;                /* error; errno set by findnext() */
  122. }
  123.  
  124. #ifdef  TEST
  125.  
  126. #include <stdlib.h>
  127.  
  128. int
  129. ff_walker(const char *path, const struct ffblk *ff)
  130. {
  131.   printf("%s:\t%lu\t", path, ff->ff_fsize);
  132.   if (ff->ff_attrib & 1)
  133.     printf("R");
  134.   if (ff->ff_attrib & 2)
  135.     printf("H");
  136.   if (ff->ff_attrib & 4)
  137.     printf("S");
  138.   if (ff->ff_attrib & 8)
  139.     printf("V");
  140.   if (ff->ff_attrib & 0x10)
  141.     printf("D");
  142.   if (ff->ff_attrib & 0x20)
  143.     printf("A");
  144.   printf("\n");
  145.  
  146.   if (strcmp(ff->ff_name, "XXXXX") == 0)
  147.     return 8;
  148.   return 0;
  149. }
  150.  
  151. int
  152. main(int argc, char *argv[])
  153. {
  154.   if (argc > 1)
  155.     {
  156.       char msg[80];
  157.  
  158.       sprintf(msg, "file_tree_walk: %d",
  159.                    file_tree_walk(argv[1], ff_walker));
  160.       if (errno)
  161.         perror(msg);
  162.       else
  163.         puts(msg);
  164.     }
  165.   else
  166.     printf("Usage: %s dir\n", argv[0]);
  167.  
  168.   return 0;
  169. }
  170.  
  171. #endif
  172.