FileHunter.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: FileHunter.cpp 1470 2008-11-20 00:35:59Z ckiesch $"
00002 
00003 
00004 
00005 //============================================================================
00006 //
00007 //  This file is part of GPSTk, the GPS Toolkit.
00008 //
00009 //  The GPSTk is free software; you can redistribute it and/or modify
00010 //  it under the terms of the GNU Lesser General Public License as published
00011 //  by the Free Software Foundation; either version 2.1 of the License, or
00012 //  any later version.
00013 //
00014 //  The GPSTk is distributed in the hope that it will be useful,
00015 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 //  GNU Lesser General Public License for more details.
00018 //
00019 //  You should have received a copy of the GNU Lesser General Public
00020 //  License along with GPSTk; if not, write to the Free Software Foundation,
00021 //  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //  
00023 //  Copyright 2004, The University of Texas at Austin
00024 //
00025 //============================================================================
00026 
00027 //============================================================================
00028 //
00029 //This software developed by Applied Research Laboratories at the University of
00030 //Texas at Austin, under contract to an agency or agencies within the U.S. 
00031 //Department of Defense. The U.S. Government retains all rights to use,
00032 //duplicate, distribute, disclose, or release this software. 
00033 //
00034 //Pursuant to DoD Directive 523024 
00035 //
00036 // DISTRIBUTION STATEMENT A: This software has been approved for public 
00037 //                           release, distribution is unlimited.
00038 //
00039 //=============================================================================
00040 
00041 
00042 
00043 
00044 
00045 
00051 #include "FileHunter.hpp"
00052 
00053 using namespace std;
00054 using namespace gpstk;
00055 using namespace gpstk::StringUtils;
00056 
00057 // headers for directory searching interface
00058 #ifndef _WIN32
00059 #include <unistd.h>
00060 #include <dirent.h>
00061 #else
00062 #include <io.h>
00063 #include <direct.h>
00064 #define PATH_MAX _MAX_PATH
00065 #endif
00066 
00067 namespace gpstk
00068 {
00069    FileHunter::FileHunter(const string& filespec)
00070       throw(FileHunterException)
00071    {
00072       try
00073       {
00074          init(filespec);
00075       }
00076       catch (FileHunterException& e)
00077       {
00078          GPSTK_RETHROW(e);
00079       }
00080    }
00081 
00082    FileHunter::FileHunter(const FileSpec& filespec)
00083       throw(FileHunterException)
00084    {
00085       try
00086       {
00087          init(filespec.getSpecString());
00088       }
00089       catch (FileHunterException& e)
00090       {
00091          GPSTK_RETHROW(e);
00092       }
00093    }
00094 
00095    FileHunter& FileHunter::newHunt(const string& filespec)
00096       throw(FileHunterException)
00097    {
00098       try
00099       {
00100          init(filespec);
00101       }
00102       catch (FileHunterException& e)
00103       {
00104          GPSTK_RETHROW(e);
00105       }
00106       return *this;
00107    }
00108 
00109    FileHunter& FileHunter::setFilter(const FileSpec::FileSpecType fst,
00110                                      const vector<string>& filter)
00111       throw(FileHunterException)
00112    {
00113          // try to find the field in the fileSpecList.
00114       vector<FileSpec>::iterator itr = fileSpecList.begin();
00115       while (itr != fileSpecList.end())
00116       {
00117          if ((*itr).hasField(fst))
00118             break;
00119          itr++;
00120       }
00121          // found the field - add the filter.
00122       if (itr != fileSpecList.end())
00123       {
00124          filterList.push_back(FilterPair(fst, filter));
00125          return *this;
00126       }
00127          // didn't find it - throw an exception
00128       else
00129       {
00130          FileHunterException fhe("The FileSpec does not have a field: " +
00131                                  FileSpec::convertFileSpecType(fst));
00132          return *this;
00133       }
00134    }
00135 
00136    vector<string> FileHunter::find(const DayTime& start,
00137                                    const DayTime& end,
00138                                    const FileSpec::FileSpecSortType fsst,
00139                                    enum FileChunking chunk) const
00140       throw(FileHunterException)
00141    {
00142       
00143       // stupidity check
00144       if (end < start)
00145       {
00146          FileHunterException fhe("The times are specified incorrectly");
00147          GPSTK_THROW(fhe);
00148       }
00149 
00150          // move the start time back to a boundary defined by the file
00151          // chunking
00152       DayTime exStart;
00153       switch(chunk)
00154       {
00155          case WEEK:
00156             exStart = DayTime(start.GPSfullweek(), 0.0, start.GPSyear());
00157             break;
00158          case DAY:
00159             exStart = DayTime(start.DOYyear(), start.DOYday(), 0.0);
00160             break;
00161          case HOUR:
00162             exStart = DayTime(start.year(), start.month(),
00163                               start.day(), start.hour(),
00164                               0, 0.0);
00165             break;
00166          case MINUTE:
00167             exStart = DayTime(start.year(), start.month(),
00168                               start.day(), start.hour(),
00169                               start.minute(), 0.0);
00170             break;
00171       }
00172       
00173       vector<string> toReturn;
00174          // seed the return vector with an empty string.  you'll see why later
00175       toReturn.push_back(string());
00176 
00177       try
00178       {
00179          vector<FileSpec>::const_iterator itr = fileSpecList.begin();
00180 
00181 #ifdef _WIN32
00182             // If Windows, we should seed it with the drive spec
00183          if (itr != fileSpecList.end())
00184          {
00185             toReturn[0] = (*itr).getSpecString() + string(1,'\\');
00186             itr++;
00187          }
00188 #endif
00189 #ifdef __CYGWIN__
00190             // If Cygwin AND the user is attempting to use DOS file paths,
00191             // need to see with the /cygdrive "head".
00192          if (itr != fileSpecList.end())
00193          { 
00194             toReturn[0] = string(1,slash) + (*itr).getSpecString();
00195             itr++;
00196          }
00197 #endif
00198          
00199          while (itr != fileSpecList.end())
00200          {
00201             vector<string> toReturnTemp;
00202             
00203                // counting variables
00204             vector<string>::size_type i,j;
00205 
00206             for(i = 0; i < toReturn.size(); i++)
00207             {
00208                   // search for the next entries
00209                   
00210          //Debug
00211          //printf("In .find() before call to serachHelper()\n");
00212          //string temp = (*itr).createSearchString();
00213          //printf(" toReturn[%d]:'%s', spec:'%s'\n",
00214          //         i,toReturn[i].c_str(),temp.c_str());
00215          
00216                vector<string> newEntries = searchHelper(toReturn[i],*itr);
00217          //Debug
00218          /*
00219          vector<string>::iterator itr1 = newEntries.begin();
00220          int j1 = 0;
00221          printf("In .find() after call to searchHelper\n");
00222          while (itr1 != newEntries.end())
00223          {
00224             printf("toReturn[%d],item %d,'%s'\n",i,j1,(*itr1).c_str());
00225             itr1++;
00226             j1++;
00227          }
00228          printf("In .find().  end of list\n");
00229          */
00230                   // after getting the potential entries, filter
00231                   // them based on the user criteria...
00232                filterHelper(newEntries, *itr);
00233 
00234          //Debug
00235          /*
00236          vector<string>::iterator itr2 = newEntries.begin();
00237          int j2 = 0;
00238          printf("In .find() after call to filterHelper\n");
00239          while (itr2 != newEntries.end())
00240          {
00241             printf("toReturn[%d],item %d,'%s'\n",i,j2,(*itr2).c_str());
00242             itr2++;
00243             j2++;
00244          }
00245          printf("In .find().  end of list\n");
00246          */
00247          
00248                   // for each new entry, check the time (if possible)
00249                   // then add it if it's in the correct time range.
00250                   // this is why we need to enter an empty string to 
00251                   // seed toReturn
00252                for(j = 0; j < newEntries.size(); j++)
00253                {
00254                   try
00255                   {
00256                      DayTime fileDT = (*itr).extractDayTime(newEntries[j]);
00257                      if ( (fileDT >= exStart) && (fileDT <= end) )
00258                      {
00259 #ifdef _WIN32
00260                         if (toReturn[i].empty())
00261                            toReturnTemp.push_back(newEntries[j]);
00262                         else
00263                         {
00264                            if ( toReturn[i][toReturn[i].size()-1]=='\\')
00265                               toReturnTemp.push_back(toReturn[i] + newEntries[j]);
00266                            else
00267                               toReturnTemp.push_back(toReturn[i] + string(1,'\\') + 
00268                                                newEntries[j]);
00269                         }
00270 #else
00271                         toReturnTemp.push_back(toReturn[i] + string(1,slash) + 
00272                                                newEntries[j]);
00273 #endif
00274                      }
00275                   }
00276                      // if you can't make a DayTime, just add it - 
00277                      // most likely, this is a field that you can't
00278                      // make a DayTime out of
00279                   catch (FileSpecException &e)
00280                   {
00281 #ifdef _WIN32
00282                         if (toReturn[i].empty())
00283                            toReturnTemp.push_back(newEntries[j]);
00284                         else
00285                         {
00286                            if ( toReturn[i][toReturn[i].size()-1]=='\\')
00287                               toReturnTemp.push_back(toReturn[i] + newEntries[j]);
00288                            else
00289                               toReturnTemp.push_back(toReturn[i] + string(1,'\\') + 
00290                                             newEntries[j]);
00291                         }
00292 #else
00293                         toReturnTemp.push_back(toReturn[i] + string(1,slash) + 
00294                                             newEntries[j]);
00295 #endif
00296                   }
00297                }
00298             }
00299             
00300             toReturn = toReturnTemp;
00301             
00302                // Debug
00303          /*
00304          vector<string>::iterator itr3 = toReturn.begin();
00305          int j3 = 0;
00306          printf("In .find() just above toReturn empty check.\n");
00307          while (itr3 != toReturn.end())
00308          {
00309             printf("toReturn[%d],'%s'\n",j3,(*itr3).c_str());
00310             itr3++;
00311             j3++;
00312          }
00313          printf("In .find().  end of list\n");
00314          */
00315 
00316                // if at any time toReturn is empty, then there are no matches
00317                // so just return
00318             if (toReturn.empty())
00319                return toReturn;
00320 
00321             itr++;
00322          }
00323 
00324             // sort the list by the file spec of the last field
00325          itr--;
00326          (*itr).sortList(toReturn, fsst);
00327 
00328          return toReturn;
00329       }
00330       catch(...)
00331       {
00332          return toReturn;
00333       }
00334    }
00335 
00336    void FileHunter::init(const string& filespec)
00337       throw(FileHunterException)
00338    {
00339       try
00340       {
00341          fileSpecList.clear();
00342          filterList.clear();
00343 
00344          string fs(filespec);
00345 
00346             // If working under Cygwin, then the file specification will be
00347             // handled as if it's a system rooted in '/'.  HOWEVER, if the 
00348             // user provided a spec that starts with a drive letter or
00349             // provided a relative path, it needs to be modified to fit the
00350             //
00351             // /cygdrive/<drive letter>/path
00352             //
00353             // For example,
00354             //     c:\ ->  /cygdrive/c
00355             //     something -> <cwd>/something
00356             //     c:\foo -> /cygdrive/c/foo
00357             //
00358             // form.
00359 #ifdef __CYGWIN__
00360          //printf(" Entering 'ifdef __CYGWIN__' branch.\n");
00361          char backSlash = '\\';
00362          string::size_type st;
00363          if (fs[1] == ':')
00364          {
00365             //printf("Cygwin 'if' branch.  fs = '%s'.  Size = %d\n",
00366             //      fs.c_str(),fs.size());
00367             char driveLetter = fs[0];
00368             
00369                // Change all '\' to '/'
00370             while ((st = fs.find( backSlash )) != fs.npos)
00371             {
00372                //printf(" st = %d, ",st);
00373                fs = fs.replace(st, 1, 1, slash );
00374             }
00375             //printf(" end of back slash replacement.\n");
00376             //printf("After backslash replace.  fs = '%s'.\n",fs.c_str());
00377             
00378                // Remove drive letter and colon
00379             fs.erase(0,2);
00380             //printf("After removing draft letter and colon.  fs = '%s'.\n",fs.c_str());
00381             
00382                // Prepend "/cygdrive/driveLetter" to filespec
00383             fs.insert(0, 1, driveLetter);
00384             fs.insert(0,"/cygdrive/");
00385          }
00386          else
00387          {
00388             //printf("Cygwin 'else' branch.  fs = '%s'.\n",fs.c_str());
00389                // Get current working directory.
00390             char* cwd = getcwd(NULL, PATH_MAX);
00391 
00392                // If strokes are in wrong directon, fix them
00393             while ((st = fs.find( backSlash )) != fs.npos)
00394             {
00395                //printf(" st = %d, ",st);
00396                fs = fs.replace(st, 1, 1, slash );
00397             }
00398             //printf("After backslash replace.  fs = '%s'.\n",fs.c_str());
00399 
00400                // Prepend cwd to filespec
00401             if (fs[0]!=slash)
00402             {
00403                fs.insert(0,string(1,slash));
00404                fs.insert(0,cwd);
00405             }
00406          }
00407          //printf(" Operating under Cygwin.  Filespec after modification:\n");
00408          //printf(" fs = %s.\n",fs.c_str());
00409 #endif
00410          
00411             // first, check if the file spec has a leading '/'.  if not
00412             // prepend the current directory to it.
00413 #ifndef _WIN32
00414          if (fs[0] != slash)
00415          {
00416 //                                                     #ifdef _WIN32
00417 //          char* cwd = _getcwd(NULL, PATH_MAX);
00418 //                                                     #else
00419             char* cwd = getcwd(NULL, PATH_MAX);
00420 //                                                     #endif
00421             if (cwd == NULL)
00422             {
00423                FileHunterException fhe("Cannot get working directory");
00424                GPSTK_THROW(fhe);
00425             }
00426             string wd(cwd);
00427                // append a trailing slash if needed
00428             if (wd[wd.size()-1] != slash)
00429                wd += std::string(1,slash);
00430             fs.insert(0, wd);
00431             free(cwd);
00432          }
00433             // Append a closing slash so the breakdown algorithm has a
00434             // means to terminate.
00435          if (fs[fs.size()-1] != '/') fs += std::string(1,'/');
00436 #else
00437             // If Windows, then check for leading drive name.
00438             // If not leading drivename, then prepend current working directory.
00439          if (fs[1]!=':')
00440          {
00441             char* cwdW = _getcwd(NULL, PATH_MAX);
00442             if (cwdW == NULL)
00443             {
00444                FileHunterException fhe("Cannot get working directory");
00445                GPSTK_THROW(fhe);
00446             }
00447             string wdW(cwdW);
00448             
00449                // append a trailing slash if needed
00450             if (wdW[wdW.size()-1] != '\\')
00451                wdW += std::string(1,'\\');
00452             fs.insert(0, wdW);
00453             free(cwdW);
00454          }
00455             // Append a closing slash so the breakdown algorithm has a
00456             // means to terminate.
00457          if (fs[fs.size()-1] != '\\') fs += std::string(1,'\\');
00458 #endif
00459 
00460             // break down the filespec directory by directory into the
00461             // storage vector
00462          while (!fs.empty())
00463          {
00464 #ifndef _WIN32
00465             if (fs[0] != slash)
00466             {
00467                FileHunterException fhe("Unexpected character: " + 
00468                                        fs.substr(0,1));
00469                GPSTK_THROW(fhe);
00470             }
00471             else
00472                // erase the leading slash
00473                fs.erase(0,1);
00474                
00475             string::size_type slashpos = fs.find(slash);
00476             FileSpec tempfs(fs.substr(0, slashpos));
00477 
00478                // debug
00479             //printf(" fs, slashpos, tempfs = '%s', %d, '%s'.\n",
00480             //   fs.c_str(),slashpos,tempfs.getSpecString().c_str());
00481 
00482             if (slashpos!=string::npos) fileSpecList.push_back(tempfs);
00483             fs.erase(0, slashpos);
00484 #else       
00485                // for Windows erase the leading backslash, if present
00486             if (fs[0] == '\\') fs.erase(0,1);
00487             string::size_type slashpos;
00488             slashpos = fs.find('\\');
00489             FileSpec tempfs(fs.substr(0, slashpos));
00490             
00491             if (slashpos!=string::npos) fileSpecList.push_back(tempfs);
00492             fs.erase(0, slashpos);
00493 #endif
00494          }
00495       }
00496       catch(FileHunterException &e)
00497       {
00498          GPSTK_RETHROW(e);
00499       }
00500       catch(FileSpecException &e)
00501       {
00502          FileHunterException fhe(e);
00503          fhe.addText("Error in the file spec");
00504          GPSTK_THROW(fhe);
00505       }
00506       catch(Exception &e)
00507       {
00508          FileHunterException fhe(e);
00509          GPSTK_THROW(fhe);
00510       }
00511       catch(std::exception &e)
00512       {
00513          FileHunterException fhe("std::exception caught: " + string(e.what()));
00514          GPSTK_THROW(fhe);
00515       }
00516       catch(...)
00517       {
00518          FileHunterException fhe("unknown exception caught");
00519          GPSTK_THROW(fhe);
00520       }
00521    } // init
00522    
00523    vector<string> FileHunter::searchHelper(const string& directory,
00524                                            const FileSpec& fs) const
00525       throw(FileHunterException)
00526    {
00527       try
00528       {
00529          vector<string> toReturn;
00530 
00531             // generate a search string
00532          string searchString = fs.createSearchString();
00533          
00534 #ifndef _WIN32
00535             // open the dir
00536          DIR* theDir;
00537 
00538          //printf(" In searchHelper(). About to call opendir.\n"); 
00539             // The first clause is a special kludge for Cygwin
00540             // referencing DOS drive structures
00541          //if (searchString.compare("cygdrive")==0)
00542          //{
00543          //   std::string tempFS =  std::string(1,slash) + searchString;
00544          //   theDir = opendir(tempFS.c_str());
00545          //}
00546          //else
00547          if (directory.empty())
00548             theDir = opendir(std::string(1,slash).c_str());
00549          else
00550             theDir = opendir(directory.c_str());
00551 
00552          //printf(" In searchHelper().  Back from opendir call.\n");
00553          
00554          if (theDir == NULL)
00555          {
00556             FileHunterException fhe("Cannot open directory: " + directory);
00557             GPSTK_THROW(fhe);
00558          }
00559          
00560             // get each dir/file entry and compare it to the search string
00561          struct dirent* entry;
00562          
00563          while ( (entry = readdir(theDir)) != NULL)
00564          {
00565             string filename(entry->d_name);
00566             
00567                // DEBUG
00568             //printf("Testing '%s'\n",filename.c_str());
00569             
00570             if ((filename.length() == searchString.length()) &&
00571                 (filename != ".") && (filename != "..") && 
00572                 isLike(filename, searchString, '*', '+', '?'))
00573             {
00574                toReturn.push_back(filename);
00575             }
00576          }
00577             // use filespec for extra verification?
00578          
00579             // cleanup
00580          if (closedir(theDir) != 0)
00581          {
00582             FileHunterException fhe("Error closing directory: " + 
00583                                     directory);
00584             GPSTK_THROW(fhe);
00585          }
00586 #endif
00587 #ifdef _WIN32
00588             // say 'hi' to old school MS io
00589          char* cwd = _getcwd(NULL, PATH_MAX);
00590          _chdir(directory.c_str());
00591          
00592          struct _finddata_t c_file;
00593          long hFile;
00594          
00595          if ( (hFile = _findfirst( searchString.c_str(), &c_file )) != -1 )
00596          {
00597             std::string filename(c_file.name);
00598             if ((filename != ".") && (filename != ".."))
00599             {
00600                toReturn.push_back(filename);
00601             }
00602             while( _findnext( hFile, &c_file ) == 0 )
00603             {
00604                filename = std::string(c_file.name);
00605                if ((filename != ".") && (filename != ".."))
00606                {
00607                   toReturn.push_back(filename);
00608                }
00609             }
00610          }
00611          _findclose(hFile);
00612          _chdir(cwd);
00613 #endif
00614          return toReturn;
00615       }
00616       catch(Exception& e)
00617       {
00618          FileHunterException fhe(e);
00619          fhe.addText("Search failed");
00620          GPSTK_THROW(fhe);
00621       }
00622       catch(std::exception& e)
00623       {
00624          FileHunterException fhe("std::exception caught: " + string(e.what()));
00625          fhe.addText("Search failed");
00626          GPSTK_THROW(fhe);
00627       }
00628       catch(...)
00629       {
00630          FileHunterException fhe("unknown exception");
00631          fhe.addText("Search failed");
00632          GPSTK_THROW(fhe);         
00633       }
00634    }
00635 
00636    void FileHunter::filterHelper(vector<std::string>& fileList, 
00637                                  const FileSpec& fs) const
00638       throw(FileHunterException)
00639    {
00640          // go through the filterList.  If the filespec has
00641          // any fields to filter, remove matches from fileList
00642 
00643          // for each element in the filter....
00644       vector<FilterPair>::const_iterator filterItr = filterList.begin();
00645       while(filterItr != filterList.end())
00646       {
00647             // if the file spec has that element...
00648          if (fs.hasField((*filterItr).first))
00649          {
00650 
00651                // then search through the file list and 
00652                // remove any files that don't match the filter.
00653             vector<string>::iterator fileListItr = fileList.begin();
00654             while (fileListItr != fileList.end())
00655             {
00656                   // thisField holds the part of the file name
00657                   // that we're searching for
00658                string thisField = fs.extractField(*fileListItr, 
00659                                                   (*filterItr).first);
00660                
00661                vector<string>::const_iterator filterStringItr = 
00662                   (*filterItr).second.begin();
00663 
00664                   // the iterator searches each element of the filter
00665                   // and compares it to thisField.  If there's a match
00666                   // then keep it.  if there's no match, delete it.
00667                while (filterStringItr != (*filterItr).second.end())
00668                {
00669                   if (thisField == rightJustify(*filterStringItr,
00670                                                thisField.size(),
00671                                                 '0'))
00672                      break;
00673                   filterStringItr++;
00674                }
00675                
00676                if (filterStringItr == (*filterItr).second.end())
00677                   fileList.erase(fileListItr);
00678                else
00679                   fileListItr++;
00680             }
00681          }
00682          filterItr++;
00683       }  
00684    }
00685 
00686 
00687    void FileHunter::dump(ostream& o) const
00688    {
00689       vector<FileSpec>::const_iterator itr = fileSpecList.begin();
00690       while(itr != fileSpecList.end())
00691       {
00692          (*itr).dump(o);
00693          itr++;
00694       }
00695    }
00696 
00697 } // namespace
00698 

Generated on Tue May 22 03:30:58 2012 for GPS ToolKit Software Library by  doxygen 1.3.9.1