dirDepthC.cc

/**
   @file      dirDepthC.cc
   @author    Mitch Richling <http://www.mitchr.me/>
   @Copyright Copyright 1995 by Mitch Richling.  All rights reserved.
   @brief     Depth first traversal of UNIX directory trees@EOL
   @Keywords  UNIX readdir depth first directory traversal
   @Std       ISOC POSIX UNIX98 BSD4.3 SYSV3

              This C++ program is intended to illustrate how to
              traverse a directory tree depth first.  That is to say,
              that all files at a particular level of the tree are
              stated before the program descends.  It simply prints
              out the names of all files found.
              
              This program reads all the file names in a directory and
              places any subdirectory names into an STL container to
              be traversed later.  A C version of this program uses a
              home grown linked list (dirDepth.c).
              
              The string handling is C-style, as that is what natively
              works with the UNIX C APIs.  chdir'ing instead of
              constructing strings might be faster on some systems.
              On many systems a memcpy function will operate faster
              than a strcpy/strcat.  The lengths of the strings are
              computed anyway, so a memcpy is the way to go.
              
              Note that this implementation doesn't suffer from
              any limitations on the number of open directory
              descriptors -- this implementation only has one open
              directory descriptor at any time.
              
              The functions used are all POSIX or ISO C++ and thus
              this program will run on most BSD and SRV
              implementations of UNIX.

   @Build     
              - MacOS X.2: c++ dirDepthC.cc

   @Tested    
              - Solaris 2.8
              - MacOS X.2
              - Linux (RH 7.3)
*/

#include <queue>                /* STL queue       C++   */
#include <list>                 /* STL list        C++   */
#include <stdio.h>              /* I/O lib         ISOC  */
#include <string.h>             /* Strings         ISOC  */
#include <sys/types.h>          /* UNIX types      POSIX */
#include <dirent.h>             /* UNIX dirs       POSIX */
#include <errno.h>              /* error stf       POSIX */
#include <utime.h>              /* utime           POSIX */
#include <sys/stat.h>           /* UNIX stat       POSIX */
#include <time.h>               /* time            ISOC  */
#include <stdlib.h>             /* Standard Lib    ISOC  */

int main(int argc, char *argv[]);

int main(int argc, char *argv[]) {
  struct stat s;                                    /** Used to stat each file. */
  std::queue<char *, std::list<char *> > listOdirs; /** Hold the names for dirs to traverse next */

  /* Stat the root of the tree we are to traverse. */
  if((argc == 2) && (lstat(argv[1], &s) < 0)) {
    printf("ERROR: Bad first argument\n");
    exit(1);
  }
  /* Now that we have stat'ed the thing, we push it onto the list of directories */
  char *wrkBuf = (char *)malloc(strlen(argv[1]) + 1);
  strcpy(wrkBuf, argv[1]);
  listOdirs.push(wrkBuf);

  while(!(listOdirs.empty())) {
    char *curDir = listOdirs.front();
    DIR *dp;
    if((dp = opendir(curDir)) == NULL) {
      printf("ERROR: dirDepth: %s: %s\n", curDir, strerror(errno));
    } else {
      /* We have opened the directory, now we read each file name from
         it and store the file names that correspond to sub
         directories in our linked list for traversal later. */
      long len_curDir = strlen(curDir);
      struct dirent *dep;
      while((dep = readdir(dp)) != NULL) {
        /* Make sure we don't process .. and . */
        if((strcmp(dep->d_name, "..") != 0) && (strcmp(dep->d_name, ".") != 0)) {
          /* Allocate space for and construct the complete path name. */
          long len_d_name = strlen(dep->d_name);
          char *name = (char *)malloc(len_d_name + len_curDir + 2);
          strcpy(name, curDir);
          strcat(name, "/");
          strcat(name, dep->d_name);
          /* Now that we have a complete path name, let's stat the file in question. */
          if(lstat(name, &s) < 0) {
            printf("ERROR: dirDepth: %s: %s\n", name, strerror(errno));
            free(name);
          } else {
            /* We have successfully stated the file, now let's process it: */
            if(S_ISDIR(s.st_mode)) {    /* Process directories. */
              /* This is a directory, so we must add it to our list of directories to traverse. */
              listOdirs.push(name);
              printf(" D: %s\n", name);
            } else {            /* Process non-directories. */
              printf("ND: %s\n", name);
              /* Free up the space for the pathname. */
              free(name);
            } /* end if/else */
          } /* end if/else */
        } /* end if */
      } /* end while */
      closedir(dp);
    } /* end if/else */
    /* We have finished walking the current directory, so we remove it from the list. */
    free(curDir);
    listOdirs.pop();
  } /* end while */

  return 0;
} /* end func main */

Generated by GNU Enscript 1.6.5.2.