FileSpec.cpp
Go to the documentation of this file.
1 //==============================================================================
2 //
3 // This file is part of GNSSTk, the ARL:UT GNSS Toolkit.
4 //
5 // The GNSSTk is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU Lesser General Public License as published
7 // by the Free Software Foundation; either version 3.0 of the License, or
8 // any later version.
9 //
10 // The GNSSTk is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with GNSSTk; if not, write to the Free Software Foundation,
17 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
18 //
19 // This software was developed by Applied Research Laboratories at the
20 // University of Texas at Austin.
21 // Copyright 2004-2022, The Board of Regents of The University of Texas System
22 //
23 //==============================================================================
24 
25 //==============================================================================
26 //
27 // This software was developed by Applied Research Laboratories at the
28 // University of Texas at Austin, under contract to an agency or agencies
29 // within the U.S. Department of Defense. The U.S. Government retains all
30 // rights to use, duplicate, distribute, disclose, or release this software.
31 //
32 // Pursuant to DoD Directive 523024
33 //
34 // DISTRIBUTION STATEMENT A: This software has been approved for public
35 // release, distribution is unlimited.
36 //
37 //==============================================================================
38 
44 #include <algorithm>
45 
46 #include "FileSpec.hpp"
47 #include "TimeString.hpp"
48 #include "StringUtils.hpp"
49 
50 using namespace std;
51 using namespace gnsstk;
52 using namespace gnsstk::StringUtils;
53 
54 namespace gnsstk
55 {
56  // operator-- for FileSpecType
58  {
59  return fst = (fst == FileSpec::unknown) ?
60  FileSpec::end : FileSpec::FileSpecType(fst-1);
61  }
62 
63  // operator++ for FileSpecType
65  {
66  return fst = (fst == FileSpec::end) ?
67  FileSpec::unknown : FileSpec::FileSpecType(fst+1);
68  }
69 
70 
71  bool FileSpec::FileSpecSort::operator() (const std::string& l,
72  const std::string& r)
73  const
74  {
75  // This sort operator compares all fields in the order
76  // defined in the FileSpecType enum.
77  for(FileSpecType fst = FileSpecType(unknown+1); fst < end; fst++)
78  {
79  if (fileSpec.hasField(fst))
80  {
81  for (unsigned i = 0; i < fileSpec.fileSpecList.size(); i++)
82  {
83  std::string::size_type offset = fileSpec.fileSpecList[i].offset;
84  std::string::size_type numCh = fileSpec.fileSpecList[i].numCh;
85  if (fileSpec.fileSpecList[i].type == fst)
86  {
87  std::string lsub(l.substr(offset, numCh));
88  std::string rsub(r.substr(offset, numCh));
89  if (((sortDir == ascending) && (lsub < rsub)) ||
90  ((sortDir == descending) && (lsub > rsub)))
91  {
92  return true; // l comes before r
93  }
94  if (lsub == rsub)
95  {
96  continue; // l and r are the same for this field
97  }
98  return false; // r comes before l
99  }
100  }
101  }
102  }
103  return false; // r and l are the same
104  }
105 
106  string FileSpec::convertFileSpecType(const FileSpecType fst)
107  {
108  if (fst == station) return string("n");
109  else if (fst == receiver) return string("r");
110  else if (fst == prn) return string("p");
111  else if (fst == selected) return string("t");
112  else if (fst == sequence) return string("I");
113  else if (fst == version) return string("v");
114  else if (fst == fixed) return string("");
115  else if (fst == clock) return string("k");
116  else if (fst == text) return string("x");
117 
118  else if (fst == year) return string("y");
119  else if (fst == month) return string("m");
120  else if (fst == dayofmonth) return string("d");
121  else if (fst == hour) return string("H");
122  else if (fst == minute) return string("M");
123  else if (fst == second) return string("S");
124  else if (fst == fsecond) return string("f");
125  else if (fst == gpsweek) return string("G");
126  else if (fst == fullgpsweek) return string("F");
127  else if (fst == gpssecond) return string("g");
128  else if (fst == mjd) return string("Q");
129  else if (fst == dayofweek) return string("w");
130  else if (fst == day) return string("j");
131  else if (fst == doysecond) return string("s");
132  else if (fst == zcount) return string("Z");
133  else if (fst == zcountfloor) return string("z");
134  else if (fst == unixsec) return string("U");
135  else if (fst == unixusec) return string("u");
136  else if (fst == fullzcount) return string("C");
137  else
138  {
139  FileSpecException fse("Unknown FileSpecType: " + asString(fst));
140  GNSSTK_THROW(fse);
141  }
142  }
143 
144  FileSpec::FileSpecType FileSpec::convertFileSpecType(const std::string& fst)
145  {
146  if (fst == string("n")) return station;
147  else if (fst == string("r")) return receiver;
148  else if (fst == string("p")) return prn;
149  else if (fst == string("t")) return selected;
150  else if (fst == string("I")) return sequence;
151  else if (fst == string("v")) return version;
152  else if (fst == string("k")) return clock;
153  else if (fst == string("x")) return text;
154 
155  else if (fst == string("Y") ||
156  fst == string("y")) return year;
157  else if (fst == string("m")) return month;
158  else if (fst == string("d")) return dayofmonth;
159  else if (fst == string("H")) return hour;
160  else if (fst == string("M")) return minute;
161  else if (fst == string("S")) return second;
162  else if (fst == string("f")) return fsecond;
163  else if (fst == string("G")) return gpsweek;
164  else if (fst == string("F")) return fullgpsweek;
165  else if (fst == string("g")) return gpssecond;
166  else if (fst == string("Q")) return mjd;
167  else if (fst == string("w")) return dayofweek;
168  else if (fst == string("j")) return day;
169  else if (fst == string("s")) return doysecond;
170  else if (fst == string("Z")) return zcount;
171  else if (fst == string("z")) return zcountfloor;
172  else if (fst == string("U")) return unixsec;
173  else if (fst == string("u")) return unixusec;
174  else if (fst == string("C") ||
175  fst == string("c")) return fullzcount;
176  else
177  {
178  FileSpecException fse("Unknown FileSpecType: " + fst);
179  GNSSTK_THROW(fse);
180  }
181  }
182 
183 
184  string FileSpec::createSearchString() const
185  {
186  string searchString;
187 
188  // go through the file spec element list...
189  vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
190  while (itr != fileSpecList.end())
191  {
192  // the error case first...
193  if ( ((*itr).type <= unknown) || ((*itr).type >= end) )
194  {
195  FileSpecException fse("Unknown FileSpecType: " +
196  asString((*itr).type));
197  GNSSTK_THROW(fse);
198  }
199  // just add the fixed fields
200  else if ((*itr).type == fixed)
201  {
202  searchString += (*itr).field;
203  }
204  // replace all the others with question marks for searching
205  else
206  {
207  searchString += string((*itr).numCh, '?');
208  }
209 
210  itr++;
211  }
212 
213  return searchString;
214  }
215 
216  string FileSpec::extractField(const string& filename,
217  const FileSpecType fst) const
218  {
219  // stupidity check - is it a valid FST?
220  if ((fst <= unknown) || (fst >= end))
221  {
222  FileSpecException fse("Unknown FileSpecType: " +
223  convertFileSpecType(fst));
224  GNSSTK_THROW(fse);
225  }
226 
227  // check the FileSpec for this type of FST
228  vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
229  while (itr != fileSpecList.end())
230  {
231  // found it - get the substring and return
232  if ((*itr).type == fst)
233  {
234  return filename.substr((*itr).offset, (*itr).numCh);
235  }
236 
237  // didn't find it on this iteration
238  itr++;
239  }
240  // oops - didn't find it.
241  FileSpecException fse("Couldn't find specified FileSpecType: " +
242  convertFileSpecType(fst));
243  GNSSTK_THROW(fse);
244  }
245 
246 
247  CommonTime FileSpec::extractCommonTime(const string& filename) const
248  {
249  // this uses CommonTime::setToString to get the time out
250  try
251  {
252  CommonTime dt;
253  mixedScanTime(dt, filename, fileSpecString);
254  return dt;
255  }
256  catch(Exception& exc)
257  {
258  // too ambiguous - throw an exception
259  FileSpecException fse(exc);
260  fse.addText("Can't generate a CommonTime for this FileSpec");
261  GNSSTK_THROW(fse);
262  }
263  catch(std::exception& exc)
264  {
265  FileSpecException fse("std::exception: " + string(exc.what()));
266  fse.addText("Can't generate a CommonTime for this FileSpec");
267  GNSSTK_THROW(fse);
268  }
269  catch(...)
270  {
271  FileSpecException fse("unknown exception");
272  fse.addText("Can't generate a CommonTime for this FileSpec");
273  GNSSTK_THROW(fse);
274  }
275 
276  }
277 
278  std::string FileSpec::toString(const gnsstk::CommonTime& dt,
279  const FSTStringMap& fstsMap) const
280  {
281  string toReturn;
282 
283  // Go through the list and insert all the non-date elements
284  // into the string. In other words, fill in the string with data
285  // from the FSTSMap first.. For date elements, put the FileSpec string
286  // directly into the file name (i.e. '%3j'). Then use CommonTime::printf
287  // to fill in all the date elements at the end.
288  vector<FileSpecElement>::const_iterator fslItr = fileSpecList.begin();
289  while (fslItr != fileSpecList.end())
290  {
291  FSTStringMap::const_iterator fstsItr = fstsMap.find((*fslItr).type);
292  // once again, it its found in the map, replace that part of
293  // the file spec. otherwise, just put the fixed field in.
294  if (fstsItr != fstsMap.end())
295  {
296  if ((*fstsItr).first == text)
297  {
298  // Don't fill text fields with "0". Filling with
299  // space isn't the best idea either but it's better
300  // than the original implementation which simply
301  // didn't set the field width even if one was
302  // specified (which would cause RTT failures).
303  // Also, if width is unspecified (0), copy the
304  // entire text field into the file spec.
305  if ((*fslItr).numCh == 0)
306  {
307  // Use as much space as necessary
308  toReturn += (*fstsItr).second;
309  }
310  else
311  {
312  // Use at most numCh characters
313  toReturn +=
314  leftJustify((*fstsItr).second, (*fslItr).numCh);
315  }
316  }
317  else
318  {
319  toReturn +=
320  rightJustify((*fstsItr).second, (*fslItr).numCh, '0');
321  }
322  }
323  else
324  {
325  toReturn += (*fslItr).field;
326  }
327 
328  fslItr++;
329  }
330 
331  toReturn = printTime(dt,toReturn);
332 
333  return toReturn;
334  }
335 
336  void FileSpec::sortList(vector<string>& fileList,
337  const FileSpecSortType fsst) const
338  {
339  FileSpecSort q(*this, fsst);
340  stable_sort(fileList.begin(), fileList.end(), q);
341 
342  // to filter out versions, generate a list of the version FSEs first
343  // and copy the file list. then make a map of the file name without
344  // the version field to the name with the version field. since its
345  // sorted, the highest version will be the last one set and the map
346  // will only have the latest versions...
347  //
348  // ex. a1a a2a a3a a4a a5a file spec: a%1va
349  // copyOfFileList after versions removed: aa aa aa aa aa
350  // versionMap[aa] = a1a then a2a, a3a, a4a, and finally a5a
351  //
352  // note that this only handles 1 version field right now, not that
353  // it couldnt do more but it gets very difficult...
354 
355  // filter out older versions here
356  if (hasField(version))
357  {
358  // copy the file list
359  vector<string> copyOfFileList = fileList;
360 
361  // find all the version elements in this file spec
362  vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
363  vector<FileSpecElement> versionVec;
364  while (itr != fileSpecList.end())
365  {
366  if ((*itr).type == version)
367  versionVec.push_back(*itr);
368  itr++;
369  }
370  // remove the version fields from the copied list, but only for the
371  // last directory/file entry in this name
372  vector<string>::size_type index;
373  for (index = 0; index < copyOfFileList.size(); index++)
374  {
375  string::size_type slashpos = copyOfFileList[index].rfind(slash);
376  if (slashpos != string::npos)
377  copyOfFileList[index].erase(0, slashpos + 1);
378  copyOfFileList[index].erase(versionVec[0].offset,
379  versionVec[0].numCh);
380  }
381 
382  // now make one more pass on the copied list. whenever two strings
383  // match, go to the original list and compare the version numbers.
384  // erase the lower version.
385 
386  // FIX: this will only compare the first version field encountered.
387  // it could be changed to do more, but it's not essential now...
388  map<string, string> versionMap;
389  for (index = 0; index < copyOfFileList.size(); index++)
390  versionMap[copyOfFileList[index]] = fileList[index];
391 
392  fileList.erase(fileList.begin(), fileList.end());
393  map<string, string>::iterator mapitr = versionMap.begin();
394  while (mapitr != versionMap.end())
395  {
396  fileList.push_back((*mapitr).second);
397  mapitr++;
398  }
399  }
400  }
401 
402  void FileSpec::dump(ostream& o) const
403  {
404  o << "FileSpec string: " << fileSpecString << endl;
405 
406  o << "offset numch type field" << endl;
407  vector<FileSpecElement>::const_iterator itr = fileSpecList.begin();
408  while (itr != fileSpecList.end())
409  {
410  o << setw(6) << (*itr).offset << setw(6) << (*itr).numCh
411  << setw(6) << convertFileSpecType((*itr).type)
412  // this makes the field bigger if the string is
413  // bigger than 5 characters
414  << setw(6 + ((*itr).field.size() > 5 ? ((*itr).field.size()-5): 0))
415  << (*itr).field << endl;
416  itr++;
417  }
418  }
419 
420  void FileSpec::init(const string& fileSpec)
421  {
422  try
423  {
424  fileSpecList.clear();
425  fileSpecString.clear();
426 
427  fileSpecString = fileSpec;
428 
429  // holds the offset for where we would be in the real file
430  // name
431  string::size_type offset = 0;
432 
433  // copy the string so we can mess with it
434  string fs(fileSpec);
435 
436  // bit by bit, parse out the string into FileSpecElements,
437  // stripping out the used parts as we go
438  while (!fs.empty())
439  {
440  string atom;
441  // if fs[0] == '%', then stop to parse. also stop at
442  // the end of the string
443  string::size_type pos = fs.find('%');
444  atom = fs.substr(0,pos);
445  fs.erase(0,pos);
446 
447  // if it's at the end of the string...
448  // make a FileSpecElement of any remaining
449  // characters and return (fall through the while loop)
450  if (fs.empty())
451  {
452  if (!atom.empty())
453  {
454  FileSpecElement fse(atom.size(), offset, fixed, atom);
455  fileSpecList.push_back(fse);
456  }
457  }
458  // found a '%' so parse out this little bit of a file spec,
459  // but make sure to add atom to the FileSpec (if there is any)
460  else
461  {
462  if (!atom.empty())
463  {
464  FileSpecElement fse(atom.size(), offset, fixed, atom);
465  fileSpecList.push_back(fse);
466  offset += atom.size();
467  atom.erase(atom.begin(), atom.end());
468  }
469 
470  // erase the '%'
471  // also make sure that atom holds the string that
472  // makes up this element.
473  atom += fs[0];
474  fs.erase(0,1);
475 
476  // get any integers that come before the letter we're lookin
477  // for, then erase them
478  int rawNumChs = asInt(fs);
479  int numChs = (rawNumChs == 0) ? 1 : rawNumChs;
480 
481  if (fs[0] == '0')
482  atom += '0';
483 
484  stripLeading(fs, "0");
485  stripLeading(fs, asString(numChs));
486 
487  // get the file spec type
488  FileSpecType fst = convertFileSpecType(fs.substr(0,1));
489 
490  // super special case - %x -> %0x
491  if ((fs.substr(0,1) == string("x")) && (rawNumChs == 0))
492  numChs = 0;
493 
494  // super special case - %Y -> %4y
495  if ((fs.substr(0,1) == string("Y")) && (numChs < 4))
496  numChs = 4;
497 
498  atom += asString(numChs);
499  atom += fs[0];
500 
501  // erase the file spec element type character
502  fs.erase(0,1);
503 
504  FileSpecElement fse(numChs, offset, fst, atom);
505  fileSpecList.push_back(fse);
506  fileSpecSet.insert(fst);
507  offset += numChs;
508  }
509 
510  } // while !fs.empty()
511  }
512  catch(FileSpecException& e)
513  {
514  e.addText("Check your file spec for errors: " + fileSpec);
515  GNSSTK_RETHROW(e);
516  }
517  catch(StringException& e)
518  {
519  FileSpecException fse(e);
520  fse.addText("String exception: Check the file spec for errors: " + fileSpec);
521  GNSSTK_THROW(fse);
522  }
523  catch(std::exception& e)
524  {
525  FileSpecException fse("std::exception: " + string(e.what()));
526  fse.addText("Check the file spec for errors: " + fileSpec);
527  GNSSTK_THROW(fse);
528  }
529  catch(...)
530  {
531  FileSpecException fse("Unknown exception: Check the file spec for errors: " + fileSpec);
532  GNSSTK_THROW(fse);
533  }
534  }
535 
536 } // namespace
gnsstk::FileSpec::FSTStringMap
std::map< FileSpecType, std::string > FSTStringMap
Definition: FileSpec.hpp:136
gnsstk::dump
void dump(vector< SatPass > &SatPassList, ostream &os, bool rev, bool dbug)
Definition: SatPassUtilities.cpp:59
gnsstk::StringUtils::asInt
long asInt(const std::string &s)
Definition: StringUtils.hpp:713
example6.mjd
mjd
Definition: example6.py:102
example6.day
day
Definition: example6.py:66
gnsstk::FileSpec::FileSpecElement
Definition: FileSpec.hpp:269
StringUtils.hpp
example6.year
year
Definition: example6.py:64
gnsstk::FileSpec::FileSpecSort
Definition: FileSpec.hpp:292
slash
const char slash
Definition: FileSpec.hpp:57
example6.hour
hour
Definition: example6.py:67
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
example6.minute
minute
Definition: example6.py:68
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::StringUtils::stripLeading
std::string & stripLeading(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1426
gnsstk::Exception
Definition: Exception.hpp:151
example6.second
second
Definition: example6.py:69
gnsstk::mixedScanTime
void mixedScanTime(CommonTime &t, const string &str, const string &fmt)
Definition: TimeString.cpp:432
FileSpec.hpp
gnsstk::FileSpec::FileSpecSortType
FileSpecSortType
Definition: FileSpec.hpp:141
gnsstk::operator--
FileSpec::FileSpecType & operator--(FileSpec::FileSpecType &fst, int)
Operator– for FileSpecType.
Definition: FileSpec.cpp:57
gnsstk::CommonTime
Definition: CommonTime.hpp:84
version
string version(string("2.4 9/23/15 rev"))
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
example4.pos
pos
Definition: example4.py:125
gnsstk::FileSpec::FileSpecType
FileSpecType
Definition: FileSpec.hpp:93
gnsstk::StringUtils
Definition: IonexStoreStrategy.cpp:44
gnsstk::StringUtils::rightJustify
std::string & rightJustify(std::string &s, const std::string::size_type length, const char pad=' ')
Definition: StringUtils.hpp:1557
gnsstk::printTime
std::string printTime(const CommonTime &t, const std::string &fmt)
Definition: TimeString.cpp:64
std
Definition: Angle.hpp:142
gnsstk::StringUtils::leftJustify
std::string & leftJustify(std::string &s, const std::string::size_type length, const char pad=' ')
Definition: StringUtils.hpp:1582
GNSSTK_THROW
#define GNSSTK_THROW(exc)
Definition: Exception.hpp:366
example6.month
month
Definition: example6.py:65
gnsstk::operator++
FileSpec::FileSpecType & operator++(FileSpec::FileSpecType &fst, int)
Operator++ for FileSpecType.
Definition: FileSpec.cpp:64
TimeString.hpp


gnsstk
Author(s):
autogenerated on Wed Oct 25 2023 02:40:39