FileSpec.cpp

Go to the documentation of this file.
00001 #pragma ident "$Id: FileSpec.cpp 3143 2012-06-19 16:19:50Z snelsen $"
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 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 <algorithm>
00052 
00053 #include "FileSpec.hpp"
00054 #include "TimeString.hpp"
00055 #include "StringUtils.hpp"
00056 
00057 using namespace std;
00058 using namespace gpstk;
00059 using namespace gpstk::StringUtils;
00060 
00061 namespace gpstk
00062 {
00063       // operator-- for FileSpecType
00064    FileSpec::FileSpecType& operator-- (FileSpec::FileSpecType& fst, int)
00065    {
00066       return fst = (fst == FileSpec::unknown) ? 
00067          FileSpec::end : FileSpec::FileSpecType(fst-1);
00068    }
00069 
00070       // operator++ for FileSpecType
00071    FileSpec::FileSpecType& operator++ (FileSpec::FileSpecType& fst, int)
00072    {
00073       return fst = (fst == FileSpec::end) ? 
00074          FileSpec::unknown : FileSpec::FileSpecType(fst+1);
00075    }
00076 
00077       // compares substrings of \a l and \a r
00078    bool FileSpec::FileSpecSort::operator() (const std::string& l, 
00079                                             const std::string& r) const
00080    {
00081          // if there are directories, don't include them in the comparison
00082       std::string tl(l, offset + l.find_last_of(slash) + 1, length);
00083       std::string tr(r, offset + r.find_last_of(slash) + 1, length);
00084       if (sortBy == ascending)
00085          return tl < tr;
00086       else
00087          return tl > tr;
00088    }
00089    
00090    string FileSpec::convertFileSpecType(const FileSpecType fst)
00091       throw(FileSpecException)
00092    {
00093       if (fst == station)          return string("n");
00094       else if (fst == receiver)    return string("r");
00095       else if (fst == prn)         return string("p");
00096       else if (fst == selected)    return string("t");
00097       else if (fst == sequence)    return string("I");
00098       else if (fst == version)     return string("v");
00099       else if (fst == fixed)       return string("");
00100       else if (fst == clock)       return string("k");
00101       else if (fst == text)        return string("x");
00102 
00103       else if (fst == year)        return string("y");
00104       else if (fst == month)       return string("m");
00105       else if (fst == dayofmonth)  return string("d");
00106       else if (fst == hour)        return string("H");
00107       else if (fst == minute)      return string("M");
00108       else if (fst == second)      return string("S");
00109       else if (fst == fsecond)     return string("f");
00110       else if (fst == gpsweek)     return string("G");
00111       else if (fst == fullgpsweek) return string("F");
00112       else if (fst == gpssecond)   return string("g");
00113       else if (fst == mjd)         return string("Q");
00114       else if (fst == dayofweek)   return string("w");
00115       else if (fst == day)         return string("j");
00116       else if (fst == doysecond)   return string("s");
00117       else if (fst == zcount)      return string("Z");
00118       else if (fst == zcountfloor) return string("z");
00119       else if (fst == unixsec)     return string("U");
00120       else if (fst == unixusec)    return string("u");
00121       else if (fst == fullzcount)  return string("C");
00122       else
00123       {
00124          FileSpecException fse("Unknown FileSpecType: " + asString(fst));
00125          GPSTK_THROW(fse);
00126       }
00127    }
00128 
00129    FileSpec::FileSpecType FileSpec::convertFileSpecType(const string& fst)
00130       throw(FileSpecException)
00131    {
00132       if (fst == string("n"))        return station;
00133       else if (fst == string("r"))   return receiver;
00134       else if (fst == string("p"))   return prn;
00135       else if (fst == string("t"))   return selected;
00136       else if (fst == string("I"))   return sequence;
00137       else if (fst == string("v"))   return version;
00138       else if (fst == string("k"))   return clock;
00139       else if (fst == string("x"))   return text;
00140 
00141       else if (fst == string("Y") || 
00142                fst == string("y"))   return year;
00143       else if (fst == string("m"))   return month;
00144       else if (fst == string("d"))   return dayofmonth;
00145       else if (fst == string("H"))   return hour;
00146       else if (fst == string("M"))   return minute;
00147       else if (fst == string("S"))   return second;
00148       else if (fst == string("f"))   return fsecond;
00149       else if (fst == string("G"))   return gpsweek;
00150       else if (fst == string("F"))   return fullgpsweek;
00151       else if (fst == string("g"))   return gpssecond;
00152       else if (fst == string("Q"))   return mjd;
00153       else if (fst == string("w"))   return dayofweek;
00154       else if (fst == string("j"))   return day;
00155       else if (fst == string("s"))   return doysecond;
00156       else if (fst == string("Z"))   return zcount;
00157       else if (fst == string("z"))   return zcountfloor;
00158       else if (fst == string("U"))   return unixsec;
00159       else if (fst == string("u"))   return unixusec;
00160       else if (fst == string("C") ||
00161                fst == string("c"))   return fullzcount;
00162       else
00163       {
00164          FileSpecException fse("Unknown FileSpecType: " + fst);
00165          GPSTK_THROW(fse);
00166       }
00167    }
00168 
00169 
00170    string FileSpec::createSearchString() const
00171       throw(FileSpecException)
00172    {
00173       string searchString;
00174 
00175          // go through the file spec element list...
00176       vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
00177       while (itr != fileSpecList.end())
00178       {
00179             // the error case first...
00180          if ( ((*itr).type <= unknown) || ((*itr).type >= end) )
00181          {
00182             FileSpecException fse("Unknown FileSpecType: " + 
00183                                   asString((*itr).type));
00184             GPSTK_THROW(fse);
00185          }
00186             // just add the fixed fields
00187          else if ((*itr).type == fixed)
00188          {
00189             searchString += (*itr).field;
00190          }
00191             // replace all the others with question marks for searching
00192          else
00193          {
00194             searchString += string((*itr).numCh, '?');
00195          }
00196 
00197          itr++;
00198       }
00199 
00200       return searchString;
00201    }
00202 
00203    string FileSpec::extractField(const string& filename, 
00204                                  const FileSpecType fst) const
00205       throw(FileSpecException)
00206    {
00207          // stupidity check - is it a valid FST?
00208       if ((fst <= unknown) || (fst >= end))
00209       {
00210          FileSpecException fse("Unknown FileSpecType: " + 
00211                                convertFileSpecType(fst));
00212          GPSTK_THROW(fse);
00213       }
00214 
00215          // check the FileSpec for this type of FST
00216       vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
00217       while (itr != fileSpecList.end())
00218       {
00219             // found it - get the substring and return
00220          if ((*itr).type == fst)
00221          {
00222             return filename.substr((*itr).offset, (*itr).numCh);
00223          }
00224 
00225             // didn't find it on this iteration
00226          itr++;
00227       }
00228          // oops - didn't find it.
00229       FileSpecException fse("Couldn't find specified FileSpecType: " +
00230                             convertFileSpecType(fst));
00231       GPSTK_THROW(fse);
00232    }
00233 
00234    bool FileSpec::hasField(const FileSpecType fst) const
00235       throw(FileSpecException)
00236    {
00237       vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
00238       while (itr != fileSpecList.end())
00239       {
00240             // stupidity check - is it a valid FST?
00241          if (((*itr).type <= unknown) || ((*itr).type >= end))
00242          {
00243             FileSpecException fse("Unknown FileSpecType: " + 
00244                                   convertFileSpecType((*itr).type));
00245             GPSTK_THROW(fse);
00246          }
00247          if ((*itr).type == fst)
00248             return true;
00249          itr++;
00250       }
00251       return false;
00252    }
00253 
00254 
00255    CommonTime FileSpec::extractCommonTime(const string& filename) const
00256       throw(FileSpecException)
00257    {
00258          // this uses CommonTime::setToString to get the time out
00259       try
00260       {
00261          CommonTime dt(0.L);
00262          mixedScanTime(dt, filename, fileSpecString);
00263          return dt;
00264       }
00265       catch(Exception& exc)
00266       {
00267             // too ambiguous - throw an exception
00268          FileSpecException fse(exc);
00269          fse.addText("Can't generate a CommonTime for this FileSpec");
00270          GPSTK_THROW(fse);
00271       }
00272       catch(std::exception& exc)
00273       {
00274          FileSpecException fse("std::exception: " + string(exc.what()));
00275          fse.addText("Can't generate a CommonTime for this FileSpec");
00276          GPSTK_THROW(fse);
00277       }
00278       catch(...)
00279       {
00280          FileSpecException fse("unknown exception");
00281          fse.addText("Can't generate a CommonTime for this FileSpec");
00282          GPSTK_THROW(fse);
00283       }
00284       
00285    }
00286 
00287    std::string FileSpec::toString(const gpstk::CommonTime& dt,
00288                                   const FSTStringMap& fstsMap) const
00289    {
00290       string toReturn;
00291 
00292          // Go through the list and insert all the non-date elements
00293          // into the string.  In other words, fill in the string with data
00294          // from the FSTSMap first.. For date elements, put the FileSpec string
00295          // directly into the file name (i.e. '%3j').  Then use CommonTime::printf
00296          // to fill in all the date elements at the end.
00297       vector<FileSpecElement>::const_iterator fslItr = fileSpecList.begin();
00298       while (fslItr != fileSpecList.end())
00299       {
00300          FSTStringMap::const_iterator fstsItr = fstsMap.find((*fslItr).type);
00301             // once again, it its found in the map, replace that part of
00302             // the file spec. otherwise, just put the fixed field in.
00303          if (fstsItr != fstsMap.end())
00304          {
00305                // special case for 'text': just print it
00306             if ((*fstsItr).first == text)
00307             {
00308                toReturn += (*fstsItr).second;
00309             }
00310             else
00311             {
00312                toReturn += 
00313                   rightJustify((*fstsItr).second, (*fslItr).numCh, '0');
00314             }
00315          }
00316          else
00317          {
00318             toReturn += (*fslItr).field;
00319          }
00320 
00321          fslItr++;
00322       }
00323 
00324       toReturn = printTime(dt,toReturn);
00325 
00326       return toReturn;
00327    }
00328 
00329    void FileSpec::sortList(vector<string>& fileList, 
00330                            const FileSpecSortType fsst) const
00331       throw(FileSpecException)
00332    {
00333          // gotta sort them in order as they appear in FileSpecType.
00334          // This is kinda like Radix sort... sort one field at a time.
00335       for(FileSpecType fst = FileSpecType(end-1); fst > unknown; fst--)
00336       {
00337          if (hasField(fst))
00338          {
00339                // check the FileSpec for this type of FST
00340             vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
00341             string::size_type ofs, len;
00342             while (itr != fileSpecList.end())
00343             {
00344                   // found it - get the substring and return
00345                if ((*itr).type == fst)
00346                {
00347                   ofs = (*itr).offset;
00348                   len = (*itr).numCh;
00349                   if (fsst != none)
00350                   {
00351                      FileSpecSort q(ofs, len, fsst);
00352                      stable_sort(fileList.begin(), fileList.end(), q);
00353                   }
00354                }
00355                
00356                   // didn't find it on this iteration
00357                itr++;
00358             }
00359          }
00360       }
00361 
00362          // to filter out versions, generate a list of the version FSEs first
00363          // and copy the file list.  then make a map of the file name without
00364          // the version field to the name with the version field. since its
00365          // sorted, the highest version will be the last one set and the map
00366          // will only have the latest versions...
00367          // 
00368          // ex.  a1a a2a a3a a4a a5a     file spec: a%1va
00369          // copyOfFileList after versions removed:  aa aa aa aa aa
00370          // versionMap[aa] = a1a then a2a, a3a, a4a, and finally a5a
00371          // 
00372          // note that this only handles 1 version field right now, not that
00373          // it couldnt do more but it gets very difficult...
00374 
00375          // filter out older versions here
00376       if (hasField(version))
00377       {
00378             // copy the file list
00379          vector<string> copyOfFileList = fileList;
00380 
00381             // find all the version elements in this file spec
00382          vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
00383          vector<FileSpecElement> versionVec;
00384          while (itr != fileSpecList.end())
00385          {
00386             if ((*itr).type == version)
00387                versionVec.push_back(*itr);
00388             itr++;
00389          }
00390             // remove the version fields from the copied list, but only for the
00391             // last directory/file entry in this name
00392          vector<string>::size_type index;
00393          for (index = 0; index < copyOfFileList.size(); index++)
00394          {
00395             string::size_type slashpos = copyOfFileList[index].rfind(slash);
00396             if (slashpos != string::npos)
00397                copyOfFileList[index].erase(0, slashpos + 1);
00398             copyOfFileList[index].erase(versionVec[0].offset,
00399                                         versionVec[0].numCh);
00400          }
00401 
00402             // now make one more pass on the copied list. whenever two strings
00403             // match, go to the original list and compare the version numbers.
00404             // erase the lower version. 
00405 
00406             // FIX: this will only compare the first version field encountered.
00407             // it could be changed to do more, but it's not essential now...
00408          map<string, string> versionMap;
00409          for (index = 0; index < copyOfFileList.size(); index++)
00410             versionMap[copyOfFileList[index]] = fileList[index];
00411 
00412          fileList.erase(fileList.begin(), fileList.end());
00413          map<string, string>::iterator mapitr = versionMap.begin();
00414          while (mapitr != versionMap.end())
00415          {
00416             fileList.push_back((*mapitr).second);
00417             mapitr++;
00418          }
00419       }
00420    }
00421 
00422    void FileSpec::dump(ostream& o) const
00423    {
00424       o << "FileSpec string: " << fileSpecString << endl;
00425 
00426       o << "offset numch  type  field" << endl;
00427       vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
00428       while (itr != fileSpecList.end())
00429       {
00430          o << setw(6) << (*itr).offset << setw(6) << (*itr).numCh
00431            << setw(6) << convertFileSpecType((*itr).type) 
00432                // this makes the field bigger if the string is
00433                // bigger than 5 characters
00434            << setw(6 + ((*itr).field.size() > 5 ? ((*itr).field.size()-5): 0))
00435            << (*itr).field << endl;
00436          itr++;
00437       }
00438    }
00439 
00440    void FileSpec::init(const string& fileSpec)
00441       throw(FileSpecException)
00442    {
00443       try
00444       {
00445          fileSpecList.clear();
00446          fileSpecString.clear();
00447 
00448          fileSpecString = fileSpec;
00449 
00450             // holds the offset for where we would be in the real file
00451             // name
00452          string::size_type offset = 0;
00453 
00454             // copy the string so we can mess with it
00455          string fs(fileSpec);
00456          
00457             // bit by bit, parse out the string into FileSpecElements,
00458             // stripping out the used parts as we go
00459          while (!fs.empty())
00460          {
00461             string atom;
00462                // if fs[0] == '%', then stop to parse.  also stop at
00463                // the end of the string
00464             string::size_type pos = fs.find('%');
00465             atom = fs.substr(0,pos);
00466             fs.erase(0,pos);
00467 
00468                // if it's at the end of the string...
00469                // make a FileSpecElement of any remaining
00470                // characters and return (fall through the while loop)
00471             if (fs.empty())
00472             {
00473                if (!atom.empty())
00474                {
00475                   FileSpecElement fse(atom.size(), offset, fixed, atom);
00476                   fileSpecList.push_back(fse);
00477                }
00478             }
00479                // found a '%' so parse out this little bit of a file spec,
00480                // but make sure to add atom to the FileSpec (if there is any)
00481             else
00482             {
00483                if (!atom.empty())
00484                {
00485                   FileSpecElement fse(atom.size(), offset, fixed, atom);
00486                   fileSpecList.push_back(fse);
00487                   offset += atom.size();
00488                   atom.erase(atom.begin(), atom.end());
00489                }
00490                
00491                   // erase the '%'
00492                   // also make sure that atom holds the string that
00493                   // makes up this element.
00494                atom += fs[0];
00495                fs.erase(0,1);
00496                
00497                   // get any integers that come before the letter we're lookin 
00498                   // for, then erase them
00499                int numChs = asInt(fs);
00500                if (numChs == 0)
00501                   numChs = 1;
00502                
00503                if (fs[0] == '0')
00504                   atom += '0';
00505 
00506                stripLeading(fs, "0");
00507                stripLeading(fs, asString(numChs));
00508 
00509                atom += asString(numChs);
00510                
00511                   // get the file spec type and erase that part of the string
00512                FileSpecType fst = convertFileSpecType(fs.substr(0,1));
00513                atom += fs[0];
00514 
00515                   // super special case - %Y -> %4y  FIX shouldn't this be <4?
00516                if ((fs.substr(0,1) == string("Y")) && (numChs != 4))
00517                   numChs = 4;
00518                fs.erase(0,1);
00519                
00520                FileSpecElement fse(numChs, offset, fst, atom);
00521                fileSpecList.push_back(fse);
00522                offset += numChs;
00523             }
00524             
00525          } // while !fs.empty()
00526       }
00527       catch(FileSpecException& e)
00528       {
00529          e.addText("Check your file spec for errors: " + fileSpec);
00530          GPSTK_RETHROW(e);
00531       }
00532       catch(StringException& e)
00533       {
00534          FileSpecException fse(e);
00535          fse.addText("String exception: Check the file spec for errors: " + fileSpec);
00536          GPSTK_THROW(fse);
00537       }
00538       catch(std::exception& e)
00539       {
00540          FileSpecException fse("std::exception: " + string(e.what()));
00541          fse.addText("Check the file spec for errors: " + fileSpec);
00542          GPSTK_THROW(fse);
00543       }
00544       catch(...)
00545       {
00546          FileSpecException fse("Unknown exception: Check the file spec for errors: " + fileSpec);
00547          GPSTK_THROW(fse);
00548       }
00549    }
00550 
00551 } // namespace

Generated on Sat May 18 03:31:04 2013 for GPS ToolKit Software Library by  doxygen 1.3.9.1