Fix compilation with old g++ 3.3.5 and debian-sarge.
[wvstreams.git] / utils / wvdiriter.cc
blobeb68e86d513f27f3dc384b7f047a366045dc6808
1 /*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * Directory iterator. Recursively uses opendir and readdir, so you don't
6 * have to. Basically implements 'find'.
8 */
10 #include "wvdiriter.h"
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
19 WvDirIter::WvDirIter( WvStringParm _dirname,
20 bool _recurse, bool _skip_mounts, size_t sizeof_stat )
21 : relpath(""), dir(dirs)
22 /****************************************************************************/
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));
29 recurse = _recurse;
30 go_up = false;
31 skip_mounts = _skip_mounts;
32 found_top = false;
34 WvString dirname(_dirname);
35 int dl = strlen(dirname);
36 if (dl != 0 && dirname[dl-1] == '/')
37 dirname.edit()[dl-1] = 0;
39 DIR * d = opendir( dirname );
40 if( d ) {
41 Dir * dd = new Dir( d, dirname );
42 dirs.prepend( dd, true );
46 WvDirIter::~WvDirIter()
47 /*********************/
49 dirs.zap();
52 bool WvDirIter::isok() const
53 /**************************/
55 return( !dirs.isempty() );
58 bool WvDirIter::isdir() const
59 /***************************/
61 return( S_ISDIR( info.st_mode ) );
64 void WvDirIter::rewind()
65 /**********************/
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();
75 if( isok() ) {
76 dir.rewind();
77 dir.next();
78 rewinddir( dir->d );
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.
88 struct dirent * dent = NULL;
90 if( !isok() )
91 return( false );
93 bool tryagain;
94 do {
95 bool ok = false;
96 tryagain = false;
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 );
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;
115 if (relpath == "")
116 info.relname = info.name;
117 else
118 info.relname = WvString("%s%s", relpath, info.name);
120 ok = ( lstat( info.fullname, &info ) == 0
121 && strcmp( dent->d_name, "." )
122 && strcmp( dent->d_name, ".." ) );
124 if (ok && !found_top)
126 lstat(info.fullname, &topdir);
127 topdir.fullname = info.fullname;
128 topdir.name = info.name;
129 topdir.relname = info.relname;
130 found_top = true;
133 } while( dent && !ok );
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();
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) );
158 dir.unlink();
159 dir.rewind();
160 dir.next();
161 tryagain = true;
164 } while( tryagain );
166 return( dent != NULL );