/////////////////////////////////////////////////////////////// // navExec.cpp - recursively walk a directory tree // // ver 1.1 starting at a specified path and list // // all the duplicate files and their paths // // encountered on the walk // // // // Language: Visual C++, ver 6.0 // // Platform: Micron Dual Pentium 200, Windows NT 4.0 // // Application: CRIOOD Project #2, S99 // // Author: Jim Fawcett, CST 2-187, (315) 443-3948 // // fawcett@ecs.syr.edu // /////////////////////////////////////////////////////////////// /* Module Operations: ================== This module, with the help of a reused nav module and a new filestor module finds all duplicate files existing in a dir- ectory subtree rooted at a path provided on the command line. To minimize storage only unique file names and unique paths are stored, using the services of the fileStor module. File name strings are keys in an STL map. Their map values are lists of iterators pointing into a set of paths. This is more complex than the simple scheme used in proto2.cpp but for a typical directory search could save 75% of the memory used by the simpler approach. The navExec module declares a dupsProc class, derived from the nav module's dProc. dupsProc class redefines virtual functions in dProc which determine how the program reacts when an object of the navig class, declared in module nav, encounters a new file or a new directory. In this module dupsProc stores unique file names and paths in a fileStor object. dupsProc usage: =============== dupsProc *pdp = new dupsProc; // create a dupsProc object // MUST BE ALLOCATED WITH NEW! nav.use(pdp); // ask nav to use dupsProc object nav.start(path); // start searching directory // subtree rooted at path pdp -> display(dupsProc::all); // display all files found pdp -> display(); // display just the duplicate files */ // /////////////////////////////////////////////////////////////// // Build Process // /////////////////////////////////////////////////////////////// // Files Required: // // proto2.cpp, nav.h nav.cpp // // // // Command Line Compiler Invocation: // // cl /GX proto2.cpp nav.cpp // /////////////////////////////////////////////////////////////// /* Maintenance History: ==================== ver 1.1 : 09 May 1999 - added filtering of fileStor elements to display duplicates - removed trailing "\*.*" found on many of the path strings returned by the navig object ver 1.0 : 29 Apr 1999 - first release */ // #pragma warning(disable : 4786) // near truncation #pragma warning(disable : 4503) // truncation #include // names and paths #include #include // win32 directory services #include // standard output for test #include // output formatting #include "nav.h" #include "fileStor.h" using namespace std; //----< derived directory info processor >--------------------- class dupsProc : public dProc { public: virtual void dirsProc(const char *dir); virtual void fileProc(const WIN32_FIND_DATA *fd); enum displayType { all, dups }; void display(displayType dt = dups); string& startPath(); private: fileStor fs; string currDir; string startDir; string makeLower(const char *s); }; inline string& dupsProc::startPath() { return startDir; } //----< convert string to lower case >------------------------- // // By converting all file names to lower case we do a case // independent sort string dupsProc::makeLower(const char *s) { string temp; int i = 0; while(i------------------------------- void dupsProc::dirsProc(const char *dir) { currDir = makeLower(dir); // eliminate trailing \*.* on path if present in string // returned by navig object int pos = currDir.find("*.*"); if(pos < currDir.size()) currDir.resize(pos-1); // save starting directory path static bool start = true; if(start) { startDir = currDir; start = false; } // display current directory to amuse user string display = currDir; display.resize(78,' '); cout << display << '\r'; } //----< process file info >------------------------------------ void dupsProc::fileProc(const WIN32_FIND_DATA *fd) { string temp = makeLower(fd->cFileName); fs.add(temp,currDir); } // //----< show files encountered with their paths >-------------- void dupsProc::display(displayType dt) { fileMap _files = fs.FileMap(); if(dt == all) { cout << '\n' << "\n All files found on subtree rooted at path: " << "\n \"" << startDir << "\"" << "\n --------------------------------------------\n"; // Iterate through the file map showing each file // and its associated list of paths fileMap::iterator it; for(it = _files.begin(); it != _files.end(); it++) { // show the fileMap's file key: cout << "\n " << (*it).first << "\n"; // for that key show each of the paths on its // associated list of path iterators itrList paths = (*it).second; itrList::iterator lit; // Walk through the iterator list showing each // path pointed to by the current iterator. // Remember that lit is an iterator on a list of // iterators - very like a pointer to a pointer. for(lit = paths.begin(); lit != paths.end(); lit++) cout << " " << *(*lit) << '\n'; } } else { cout << "\n All duplicate files found on subtree rooted at path: " << "\n \"" << startDir << "\"" << "\n ------------------------------------------------------\n"; fileMap::iterator it; for(it = _files.begin(); it != _files.end(); it++) { if((*it).second.size() > 1) { cout << "\n " << (*it).first << "\n"; itrList paths = (*it).second; itrList::iterator lit; for(lit = paths.begin(); lit != paths.end(); lit++) cout << " " << *(*lit) << '\n'; } } } } // //----< process a directory subtree >-------------------------- void main(int argc, char *argv[]) { if(argc == 1) { cout << "\n please enter starting path\n\n"; return; } navig nav; dupsProc *pdp = new dupsProc; pdp->startPath() = argv[1]; nav.use(pdp); nav.start(argv[1]); pdp->display(dupsProc::all); pdp->display(); cout << endl; }