WvStreams
wvdiriter.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4  *
5  * Directory iterator. Recursively uses opendir and readdir, so you don't
6  * have to. Basically implements 'find'.
7  *
8  */
9 
10 #include "wvdiriter.h"
11 
12 #if defined(_WIN32) && !defined(S_ISDIR)
13 #define S_ISDIR(x) (_S_IFDIR | (x))
14 #endif
15 #ifdef _WIN32
16 #define lstat stat
17 #endif
18 
19 WvDirIter::WvDirIter( WvStringParm _dirname,
20  bool _recurse, bool _skip_mounts, size_t sizeof_stat )
21  : relpath(""), dir(dirs)
22 /****************************************************************************/
23 {
24  // if this assertion fails, then you probably used different compiler
25  // options for the wvstreams library and the calling program. Check
26  // for defines like _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE.
27  assert(sizeof_stat == sizeof(struct stat));
28 
29  recurse = _recurse;
30  go_up = false;
31  skip_mounts = _skip_mounts;
32  found_top = false;
33 
34  WvString dirname(_dirname);
35  int dl = strlen(dirname);
36  if (dl != 0 && dirname[dl-1] == '/')
37  dirname.edit()[dl-1] = 0;
38 
39  DIR * d = opendir( dirname );
40  if( d ) {
41  Dir * dd = new Dir( d, dirname );
42  dirs.prepend( dd, true );
43  }
44 }
45 
46 WvDirIter::~WvDirIter()
47 /*********************/
48 {
49  dirs.zap();
50 }
51 
52 bool WvDirIter::isok() const
53 /**************************/
54 {
55  return( !dirs.isempty() );
56 }
57 
58 bool WvDirIter::isdir() const
59 /***************************/
60 {
61  return( S_ISDIR( info.st_mode ) );
62 }
63 
64 void WvDirIter::rewind()
65 /**********************/
66 {
67  // have to closedir() everything that isn't the one we started with,
68  // and rewind that.
69  while( dirs.count() > 1 ) {
70  dir.rewind();
71  dir.next();
72  dir.unlink();
73  }
74 
75  if( isok() ) {
76  dir.rewind();
77  dir.next();
78  rewinddir( dir->d );
79  }
80 }
81 
82 
83 bool WvDirIter::next()
84 /********************/
85 // use readdir... and if that returns a directory, opendir() it and prepend
86 // it to dirs, so we start reading it until it's done.
87 {
88  struct dirent * dent = NULL;
89 
90  if( !isok() )
91  return( false );
92 
93  bool tryagain;
94  do {
95  bool ok = false;
96  tryagain = false;
97 
98  // unrecurse if the user wants to
99  if( go_up ) {
100  go_up = false;
101  if( dirs.count() > 1 ) {
102  dir.unlink();
103  dir.rewind();
104  dir.next();
105  } else
106  return( false );
107  }
108 
109  do {
110  dent = readdir( dir->d );
111  if( dent ) {
112  info.fullname = WvString( "%s/%s", dir->dirname, dent->d_name );
113  info.name = dent->d_name;
114 
115  if (relpath == "")
116  info.relname = info.name;
117  else
118  info.relname = WvString("%s%s", relpath, info.name);
119 
120  ok = ( lstat( info.fullname, &info ) == 0
121  && strcmp( dent->d_name, "." )
122  && strcmp( dent->d_name, ".." ) );
123 
124  if (ok && !found_top)
125  {
126  lstat(info.fullname, &topdir);
127  topdir.fullname = info.fullname;
128  topdir.name = info.name;
129  topdir.relname = info.relname;
130  found_top = true;
131  }
132  }
133  } while( dent && !ok );
134 
135  if( dent ) {
136  // recurse?
137  if( recurse && S_ISDIR( info.st_mode ) &&
138  ( !skip_mounts || info.st_dev == topdir.st_dev) ) {
139  DIR * d = opendir( info.fullname );
140  if( d ) {
141  relpath = WvString( "%s%s/", relpath, info.name );
142  Dir * dd = new Dir( d, info.fullname );
143  dirs.prepend( dd, true );
144  dir.rewind();
145  dir.next();
146  }
147  }
148  } else {
149  // end of directory. if we recursed, unlink it and go up a
150  // notch. if this is the top level, DON'T close it, so that
151  // the user can ::rewind() again if he wants.
152  if( dirs.count() > 1 ) {
153  if (dirs.count() == 2)
154  relpath = WvString("");
155  else
156  relpath = WvString( "%s/", getdirname(relpath) );
157 
158  dir.unlink();
159  dir.rewind();
160  dir.next();
161  tryagain = true;
162  }
163  }
164  } while( tryagain );
165 
166  return( dent != NULL );
167 }
168 
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329