WvStreams
|
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Directory iterator. Recursively uses opendir and readdir, so you don't 00006 * have to. Basically implements 'find'. 00007 * 00008 */ 00009 00010 #include "wvdiriter.h" 00011 00012 #if defined(_WIN32) && !defined(S_ISDIR) 00013 #define S_ISDIR(x) (_S_IFDIR | (x)) 00014 #endif 00015 #ifdef _WIN32 00016 #define lstat stat 00017 #endif 00018 00019 WvDirIter::WvDirIter( WvStringParm _dirname, 00020 bool _recurse, bool _skip_mounts, size_t sizeof_stat ) 00021 : relpath(""), dir(dirs) 00022 /****************************************************************************/ 00023 { 00024 // if this assertion fails, then you probably used different compiler 00025 // options for the wvstreams library and the calling program. Check 00026 // for defines like _FILE_OFFSET_BITS=64 and _LARGEFILE_SOURCE. 00027 assert(sizeof_stat == sizeof(struct stat)); 00028 00029 recurse = _recurse; 00030 go_up = false; 00031 skip_mounts = _skip_mounts; 00032 found_top = false; 00033 00034 WvString dirname(_dirname); 00035 int dl = strlen(dirname); 00036 if (dl != 0 && dirname[dl-1] == '/') 00037 dirname.edit()[dl-1] = 0; 00038 00039 DIR * d = opendir( dirname ); 00040 if( d ) { 00041 Dir * dd = new Dir( d, dirname ); 00042 dirs.prepend( dd, true ); 00043 } 00044 } 00045 00046 WvDirIter::~WvDirIter() 00047 /*********************/ 00048 { 00049 dirs.zap(); 00050 } 00051 00052 bool WvDirIter::isok() const 00053 /**************************/ 00054 { 00055 return( !dirs.isempty() ); 00056 } 00057 00058 bool WvDirIter::isdir() const 00059 /***************************/ 00060 { 00061 return( S_ISDIR( info.st_mode ) ); 00062 } 00063 00064 void WvDirIter::rewind() 00065 /**********************/ 00066 { 00067 // have to closedir() everything that isn't the one we started with, 00068 // and rewind that. 00069 while( dirs.count() > 1 ) { 00070 dir.rewind(); 00071 dir.next(); 00072 dir.unlink(); 00073 } 00074 00075 if( isok() ) { 00076 dir.rewind(); 00077 dir.next(); 00078 rewinddir( dir->d ); 00079 } 00080 } 00081 00082 00083 bool WvDirIter::next() 00084 /********************/ 00085 // use readdir... and if that returns a directory, opendir() it and prepend 00086 // it to dirs, so we start reading it until it's done. 00087 { 00088 struct dirent * dent = NULL; 00089 00090 if( !isok() ) 00091 return( false ); 00092 00093 bool tryagain; 00094 do { 00095 bool ok = false; 00096 tryagain = false; 00097 00098 // unrecurse if the user wants to 00099 if( go_up ) { 00100 go_up = false; 00101 if( dirs.count() > 1 ) { 00102 dir.unlink(); 00103 dir.rewind(); 00104 dir.next(); 00105 } else 00106 return( false ); 00107 } 00108 00109 do { 00110 dent = readdir( dir->d ); 00111 if( dent ) { 00112 info.fullname = WvString( "%s/%s", dir->dirname, dent->d_name ); 00113 info.name = dent->d_name; 00114 00115 if (relpath == "") 00116 info.relname = info.name; 00117 else 00118 info.relname = WvString("%s%s", relpath, info.name); 00119 00120 ok = ( lstat( info.fullname, &info ) == 0 00121 && strcmp( dent->d_name, "." ) 00122 && strcmp( dent->d_name, ".." ) ); 00123 00124 if (ok && !found_top) 00125 { 00126 lstat(info.fullname, &topdir); 00127 topdir.fullname = info.fullname; 00128 topdir.name = info.name; 00129 topdir.relname = info.relname; 00130 found_top = true; 00131 } 00132 } 00133 } while( dent && !ok ); 00134 00135 if( dent ) { 00136 // recurse? 00137 if( recurse && S_ISDIR( info.st_mode ) && 00138 ( !skip_mounts || info.st_dev == topdir.st_dev) ) { 00139 DIR * d = opendir( info.fullname ); 00140 if( d ) { 00141 relpath = WvString( "%s%s/", relpath, info.name ); 00142 Dir * dd = new Dir( d, info.fullname ); 00143 dirs.prepend( dd, true ); 00144 dir.rewind(); 00145 dir.next(); 00146 } 00147 } 00148 } else { 00149 // end of directory. if we recursed, unlink it and go up a 00150 // notch. if this is the top level, DON'T close it, so that 00151 // the user can ::rewind() again if he wants. 00152 if( dirs.count() > 1 ) { 00153 if (dirs.count() == 2) 00154 relpath = WvString(""); 00155 else 00156 relpath = WvString( "%s/", getdirname(relpath) ); 00157 00158 dir.unlink(); 00159 dir.rewind(); 00160 dir.next(); 00161 tryagain = true; 00162 } 00163 } 00164 } while( tryagain ); 00165 00166 return( dent != NULL ); 00167 } 00168