/////////////////////////////////////////////////////////////// // nav.cpp -- recursively walk a directory tree // // ver 1.8 starting at a specified path // // // // Language: Visual C++, ver 7.1 // // Platform: Dell Dimension 8300, Windows XP, SP2 // // Application: CSE687 Project #1, Spring 2005 // // Author: Jim Fawcett, CST 2-187, (315) 443-3948 // // jfawcett@twcny.rr.com // /////////////////////////////////////////////////////////////// #include // standard output for test #include // output formatting #include #include "fileInfo.h" #include "nav.h" using namespace std; //----< default dir name display function >-------------------- void defProc::dirsProc(const string &dirName) { cout << "\n " << dirName.c_str() << endl; } //----< default file data display function >------------------- void defProc:: fileProc(const fileInfo &fi) { fi.showData(cout); } // //----< save user's working directory >------------------------ navig::navig(defProc &DP) : dp_(DP) { // save user's working directory char buffer[PathBufferSize]; GetCurrentDirectory( PathBufferSize, buffer); userDir_ = buffer; } //----< restore user's working directory >--------------------- navig::~navig() { SetCurrentDirectory(userDir_.c_str()); } //----< specify starting directory and initiate walk >--------- void navig::start( string dir, const std::string& fileMask) { // save current directory for restoration char buffer[PathBufferSize]; GetCurrentDirectory(PathBufferSize,buffer); string startDir = buffer; // convert "." or ".." into full path name if( ( dir == "." ) || ( dir == ".." ) ) { if( !SetCurrentDirectory( dir.c_str() ) ) cout << "could not find dir " << dir << endl; GetCurrentDirectory( PathBufferSize, buffer); dir = buffer; } // start recursive directory walk walk(dir, fileMask); // restore starting directory SetCurrentDirectory( startDir.c_str() ); } // //----< walk directory tree rooted at dir >-------------------- void navig::walk(const string &dir, const std::string& fileMask) { // string fileMask = "*.*"; char *fileName; char curDir[ PathBufferSize ]; char fullName[ PathBufferSize ]; vector dirs; // save current dir so can restore it if( !GetCurrentDirectory( PathBufferSize, curDir) ) return; // if the directory name is neither . or .. then // change to it, otherwise ignore it if( (dir != ".") && (dir != "..") ) { if( !SetCurrentDirectory( dir.c_str() ) ) return; } else return; // process the current directory name if( !GetFullPathName( fileMask.c_str(), PathBufferSize, fullName, &fileName ) ) return; else { GetCurrentDirectory(PathBufferSize,fullName); dp_.dirsProc(fullName); } // Loop through all files in the directory fileInfo fi; bool found = fi.firstFile( fileMask.c_str()); while ( found ) { // If the name is a directory, save for traversal later. // Otherwise process the file if( fi.isDirectory() && fi.name() != "." && fi.name() != ".." ) { string subdir = string(fullName) + "\\" + fi.name(); dirs.push_back(subdir); } else dp_.fileProc(fi); found = fi.nextFile(); } // now recursively walk subdirectories for(unsigned int i=0; i < dirs.size(); ++i) walk(dirs[i], fileMask); // clean up and restore directory fi.closeFile(); SetCurrentDirectory( curDir ); } // //----< test stub >-------------------------------------------- // // - Recursively walk directory subtree pointed to // by the last command line argument. // - use default navig processing each time a directory // or file is encountered // - replace default processing with user defined processing // and repeat // #ifdef TEST_NAV void main(int argc, char *argv[]) { cout << "\n Testing Directory Navigator " << "\n =============================\n"; if(argc == 1) { cout << "\n please enter starting path\n"; return; } // create default processing object and start navigation cout << "\n testing default dir/file processing: " << "\n --------------------------------------\n"; cout << "\n starting path = " << fileInfo::getPath() << "\n"; defProc dp; navig nav(dp); nav.start(argv[argc-1]); cout << "\n ending path = " << fileInfo::getPath() << "\n\n"; // User defined processing definded here. Note that // local classes can be defined as long as all members // are inline. Otherwise, just declare and define above // main. // // These do nothing but prepend each output with some // "-" characters to show that user defined processing // is actually being used. In a real application user // defined processing will certainly be quite different // from the default class userProc : public defProc { public: virtual void fileProc(const fileInfo &fi) { fileInfo newfi = fi; newfi.showDate(false); newfi.showData(cout); } virtual void dirsProc(const string &dir) { cout << "\n " << dir.c_str() << endl; } }; // // restart with user defined processing cout << "\n testing modified dir/file processing: " << "\n ---------------------------------------\n"; cout << "\n starting path = " << fileInfo::getPath() << "\n"; userProc udp; navig newNav(udp); newNav.start(argv[argc-1]); cout << "\n ending path = " << newNav.getPath(); cout << "\n\n"; } #endif