CommandLine.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 
39 
40 // CommandLine.cpp Command line options and argument processing.
41 //
42 // NB LOG(DEBUG) (only) appears here, but --debug is not going to turn it on;
43 // for it to work, LOGlevel = ConfigureLOG:Level("DEBUG"); must be set explicitly
44 // before calling these routines; then debug will be set here and LOG(DEBUG) will work
45 // NB default for debug is -1
46 
47 // TD what if a vector option is given a duplicate value? ignore - let caller handle
48 // TD does Validate test two targets are equal? do we care?
49 // TD consider adding '[or -<shortopt>]' to syntax description
50 // TD is there a bug if --debugN appears twice?
51 // TD other bool types
52 // typeBool: --opt => target = true;
53 // typeBoolValue: --opt T => target = true;
54 // and --opt F => target = false;
55 // typeBoolToggle: --opt => target = !target;
56 
57 // system
58 #include <fstream>
59 #include <cmath>
60 // gnsstk
61 #include "Exception.hpp"
62 #include "StringUtils.hpp"
63 #include "stl_helpers.hpp"
64 // geomatics
65 #include "logstream.hpp"
66 #include "expandtilde.hpp"
67 
68 #include "CommandLine.hpp"
69 
70 using namespace std;
71 using namespace gnsstk::StringUtils;
72 
73 namespace gnsstk
74 {
75 // -----------------------------------------------------------------------------------
76 // the main entry point
80 int CommandLine::ProcessCommandLine(int argc, char** argv, string PrgmDesc,
81  string& Usage, string& Errors, vector<string>& Unrecog)
82 {
83 try {
84  int i,j;
85  string option,word;
86 
87  // if caller has set LOGlevel to DEBUG already, set debug here
88  if(ConfigureLOG::ReportingLevel() >= ConfigureLOG::Level("DEBUG")) {
89  debug = ConfigureLOG::ReportingLevel()-4;
90  LOG(DEBUG) << "CommandLine sets debug to "
91  << ConfigureLOG::ToString(ConfigureLOG::ReportingLevel());
92  }
93 
94  // preliminaries ------------------------------------------------------
95  helponly = foundErrors = false;
96  Usage = string();
97  Errors = string();
98  Unrecog.clear();
99 
100  if(syntaxPageBuilt == 0) {
101  word = string(argv[0]);
102  string::size_type pos = word.find_last_of("/\\");
103  if(pos != string::npos) word = word.substr(pos+1);
104  syntaxPage = "Usage: " + word + " [option] ...";
105  syntaxPageBuilt = 1;
106  }
107  if(syntaxPageBuilt == 1) {
108  syntaxPage += "\n" + PrgmDesc + "\n";
109  syntaxPageBuilt = 2;
110  }
111 
112  // validate the command line ------------------------------------------
113  if(!ValidateCommandLine(word)) { // word is a dummy here
114  Errors = word;
115  return -3;
116  }
117 
118  // build the syntax page ----------------------------------------------
119  BuildSyntaxPage();
120 
121  // define usage by getting the syntax page
122  Usage = SyntaxPage();
123 
124  // pre-processing -----------------------------------------------------
125  // no args means help
126  if(argc==1 && requireOneArg) helponly = true;
127 
128  // PreProcessArgs pulls out help, debug, verbose, file, deprecated and ignore args
129  vector<string> Args;
130  for(j=1; j<argc; j++) PreProcessArgs(argv[j],Args,Errors);
131  LOG(DEBUG) << "Return from CommandLine::PreProcessArgs: help is "
132  << (help ? "T":"F") << " and helponly is " << (helponly ? "T":"F");
133 
134  // PreProcessArgs may have removed all cmd line args....
135  if((requireOneArg && Args.size() == 0) || helponly) help = true;
136 
137  if(debug >= 0) {
138  ostringstream oss;
139  oss << "CommandLine argument list passed to parser:" << endl;
140  for(size_t k=0; k<Args.size(); k++)
141  oss << " arg[" << k << "] = " << Args[k] << endl;
142 
143  word = oss.str();
144  stripTrailing(word,'\n');
145  LOG(DEBUG) << word;
146  }
147 
148  // parse the command line ----------------------------------------------
149  // fill values for each option, and Errors and Unrecog
150  Parse(Args, Errors, Unrecog);
151 
152  // post-process: pull out the parsed input --------------------------------
153  Postprocess(Errors, Unrecog);
154 
155  // help exit
156  if(help) return 1;
157 
158  // error exit
159  if(!Errors.empty()) {
160  foundErrors = true;
161  return -1;
162  }
163 
164  // normal exit
165  return 0;
166 
167 } // end try
168 catch(Exception& e) { GNSSTK_RETHROW(e); }
169 catch(std::exception& e) {
170  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
171 }
172 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
173 }
174 
175 // -----------------------------------------------------------------------------------
176 // public
180 void CommandLine::DumpConfiguration(ostream& os, string tag)
181 {
182 try {
183  size_t i,j;
184  double d;
185  string str;
186  RinexSatID sat;
187  vector<string> values;
188  string::size_type pos;
189 
190  // loop over all options, output of the form:
191  // Description (--option) : value
192  for(i=0; i<options.size(); i++) {
193  if(!tag.empty()) os << tag << " ";
194  if(options[i].predesc.size()) {
195  str = options[i].predesc;
196  if(str[0] == '#' || str[0] == '\n') ; // do nothing
197  else str = string(" ") + str;
198  os << str << endl;
199  if(!tag.empty()) os << tag << " ";
200  }
201 
202  str = options[i].desc;
203  os << " " << str << " (--" << options[i].longOpt << ") : ";
204 
205  str = string();
206  switch(options[i].type) {
207  case typeBool:
208  os << (*((bool *)(options[i].p_output)) ? "true" : "false");
209  break;
210  case typeInt:
211  os << *((int *)(options[i].p_output));
212  break;
213  case typeVectorInt: {
214  vector<int> ints(*((vector<int> *)(options[i].p_output)));
215  if(ints.size() == 0)
216  os << "<none>";
217  else for(j=0; j<ints.size(); j++)
218  os << ints[j] << (j==ints.size()-1 ? "" : ",");
219  }
220  break;
221  case typeDouble:
222  d = *((double *)(options[i].p_output));
223  if(d == 0 || fabs(d) >= 0.1)
224  os << fixed << setprecision(2) << d;
225  else if(fabs(d) >= 0.01)
226  os << fixed << setprecision(3) << d;
227  else
228  os << scientific << setprecision(2) << d;
229  break;
230  case typeString:
231  if((*((string *)(options[i].p_output))).empty())
232  os << "<none>";
233  else
234  str = *((string *)(options[i].p_output));
235  break;
236  case typeVectorString:
237  values = *((vector<string> *)(options[i].p_output));
238  if(values.size() == 0)
239  os << "<none>";
240  else for(j=0; j<values.size(); j++)
241  str += values[j] + (j==values.size()-1 ? "" : ",");
242  break;
243  case typeSat: // RinexSatID
244  sat = *(RinexSatID *)(options[i].p_output);
245  if(sat.id == -1)
246  os << "<none>";
247  else
248  os << sat.toString();
249  break;
250  case typeVectorSat: { // vector<RinexSatID>
251  vector<RinexSatID> sats(*((vector<RinexSatID> *)(options[i].p_output)));
252  if(sats.size() == 0) os << "<none>";
253  else
254  for(j=0; j<sats.size(); j++)
255  str += sats[j].toString() + (j==sats.size()-1 ? "" : ",");
256  }
257  break;
258  case typeUndefined:
259  case typeCount:
260  break;
261  } // end switch(type)
262 
263  if(!str.empty()) {
264  pos = str.find_first_of(" \t");
265  if(pos != string::npos) str = string("\"") + str + string("\"");
266  os << str;
267  }
268 
269  os << endl;
270 
271  } // end loop over options
272 
273  // add verbose, debug and help
274  os << " Print extended output, including cmdline summary (--verbose) : "
275  << (verbose?"true":"false") << endl;
276  os << " Print debug output at level DEBUGn [n=0-7] (--debug<n>) : "
277  << debug << endl;
278  os << " Print this syntax page and quit (--help) : "
279  << (help?"true":"false") << endl;
280 
281 } // end try
282 catch(Exception& e) { GNSSTK_RETHROW(e); }
283 catch(std::exception& e) {
284  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
285 }
286 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
287 }
288 
289 // the rest are private
290 // -----------------------------------------------------------------------------------
294 bool CommandLine::ValidateCommandLine(string& msg)
295 {
296 try {
297  bool isValid(true);
298  size_t i,j;
299  string tag("Error (CommandLine): option ");
300  ostringstream oss;
301 
302  LOG(DEBUG) << "CommandLine::ValidateCommandLine()";
303  // are any valid options also being ignored?
304  for(i=0; i<options.size(); i++) {
305  string opt("--" + options[i].longOpt);
306  //LOG(DEBUG) << "Is " << opt << " valid?";
307  if(vectorindex(ignore_opts_with_arg,opt) != -1) {
308  isValid = false;
309  oss << tag << options[i].longOpt
310  << " (with arg) is both valid and to be ignored.\n";
311  }
312  //LOG(DEBUG) << " ignore_opts_with_arg ok";
313  if(vectorindex(ignore_opts_without_arg,opt) != -1) {
314  isValid = false;
315  oss << tag << options[i].longOpt
316  << " (w/o arg) is both valid and to be ignored.\n";
317  }
318  //LOG(DEBUG) << " ignore_opts_without_arg ok";
319  if(vectorindex(ignore_on_opts,opt) != -1) {
320  isValid = false;
321  oss << tag << options[i].longOpt
322  << " is both valid and an 'ignore on' option.\n";
323  }
324  //LOG(DEBUG) << " ignore_on_opts ok";
325  if(vectorindex(ignore_off_opts,opt) != -1) {
326  isValid = false;
327  oss << tag << options[i].longOpt
328  << " is both valid and an 'ignore off' option.\n";
329  }
330  //LOG(DEBUG) << " ignore_off_opts ok";
331 
332  for(j=0; j<i; j++) {
333  if(options[i].longOpt == options[j].longOpt) {
334  isValid = false;
335  oss << tag << "'" << options[i].longOpt << "' is repeated.\n";
336  }
337  if(options[i].shortOpt != 0 && options[i].shortOpt == options[j].shortOpt) {
338  isValid = false;
339  oss << tag << "'" << options[i].longOpt
340  << "' short form is already used in option '" << options[j].longOpt
341  << "'.\n";
342  }
343  }
344  }
345 
346  // deprecated options
347  map<string,string>::const_iterator it;
348  for(it=deprec_opts.begin(); it != deprec_opts.end(); ++it) {
349  LOG(DEBUG) << "Test deprec option " << it->first << " -> " << it->second;
350  bool found(false);
351  for(i=0; i<options.size(); i++) {
352  if(it->second == string("--") + options[i].longOpt ||
353  it->second == string("-") + options[i].shortOpt)
354  { found=true; break; }
355  }
356  if(!found) {
357  isValid = false;
358  oss << tag << it->second << ", the replacement for deprecated option "
359  << it->first << ", is not found.\n";
360  }
361  }
362  //LOG(DEBUG) << " deprec_opts ok";
363 
364  msg = oss.str();
365  if(!msg.empty()) { LOG(DEBUG) << "ValidateCommandLine finds " << msg; }
366 
367  return isValid;
368 
369 } // end try
370 catch(Exception& e) { GNSSTK_RETHROW(e); }
371 catch(std::exception& e) {
372  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
373 }
374 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
375 }
376 
377 // -----------------------------------------------------------------------------------
381 void CommandLine::BuildSyntaxPage(void)
382 {
383 try {
384  size_t i,j,k;
385  double d;
386  string option,deflt;
387 
388  // first determine the max size of the string '--option <arg>'
389  optionsize = 0; // member data
390  for(i=0; i<options.size(); i++) {
391  j = options[i].longOpt.length() + options[i].arg.length() + 7;
392  if(j > optionsize) optionsize = j;
393  }
394 
395  // build the command line ----------------------------------------
396  for(i=0; i<options.size(); i++) {
397  // ignore invalid types
398  if(options[i].type < typeBool || options[i].type >= typeCount)
399  continue; // throw?
400 
401  // get the padded string ' --option <arg> '
402  option = " --" + options[i].longOpt;
403  if(options[i].arg.length()) option += " <" + options[i].arg + "> ";
404  option = leftJustify(option,optionsize);
405 
406  // get the default string
407  switch(options[i].type) {
408  case typeBool:
409  deflt = ( *(bool *)(options[i].p_output) ? "do" : "don't");
410  break;
411  case typeInt:
412  deflt = asString(*(int *)(options[i].p_output));
413  break;
414  case typeVectorInt: {
415  vector<int> *iptr = (vector<int> *)(options[i].p_output);
416  deflt = string();
417  for(j=0; j<iptr->size(); j++)
418  deflt += (j>0 ? ",":"") + asString((*iptr)[j]);
419  }
420  break;
421  case typeDouble:
422  d = *((double *)(options[i].p_output));
423  if(d == 0 || fabs(d) >= 0.1)
424  deflt = asString(d,2);
425  else if(fabs(d) >= 0.01)
426  deflt = asString(d,3);
427  else
428  {
429  deflt = floatFormat(d, FFLead::NonZero, 3, 2);
430  }
431  break;
432  case typeString:
433  deflt = *(string *)(options[i].p_output);
434  break;
435  case typeVectorString: {
436  vector<string> *sptr = (vector<string> *)(options[i].p_output);
437  deflt = string("");
438  for(j=0; j<sptr->size(); j++)
439  deflt += (j>0 ? ",":"") + (*sptr)[j];
440  }
441  break;
442  case typeSat: {
443  RinexSatID *gptr = (RinexSatID *)(options[i].p_output);
444  if(gptr->id != -1) deflt = (*gptr).toString();
445  else deflt = string("");
446  }
447  break;
448  case typeVectorSat: {
449  vector<RinexSatID> *gptr = (vector<RinexSatID> *)(options[i].p_output);
450  deflt = string("");
451  for(k=0,j=0; j<gptr->size(); j++)
452  if((*gptr)[j].id > 0)
453  deflt += (k++>0 ? ",":"") + (*gptr)[j].toString();
454  }
455  break;
456  case typeUndefined:
457  case typeCount:
458  break;
459  }
460 
461  // build the syntax line
462  options[i].syntax = options[i].predesc
463  + (options[i].predesc.size() ? "\n" : "")
464  + option // --opt <arg>
465  + options[i].desc // desc
466  + (options[i].repeat ? " [repeatable]" : "") // add 'repeat'
467  + " (" + deflt + ")"; // add default
468  }
469 
470 } // end try
471 catch(Exception& e) { GNSSTK_RETHROW(e); }
472 catch(std::exception& e) {
473  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
474 }
475 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
476 }
477 
478 // -----------------------------------------------------------------------------------
479 // re-entrant!
483 void CommandLine::PreProcessArgs(const char *in_arg, vector<string>& Args,
484  string& Errors)
485 {
486 try {
487  static bool found_cfg_file=false;
488  static bool ignore_opts=false; // ignore args for now...
489  static bool ignore_once=false; // ignore one argument
490  int i,k;
491  string msg,sarg(in_arg);
492 
493  if(sarg == string()) return;
494  LOG(DEBUG) << "CommandLine::PreProcess arg " << sarg;
495 
496  if(ignore_once) { ignore_once = false; return; }
497 
498  // ignore these
499  for(i=0; i<ignore_opts_without_arg.size(); i++) { // note that -- is included
500  if(sarg == ignore_opts_without_arg[i]) {
501  LOG(DEBUG) << "CommandLine::PreProcess: ignoring option " << sarg;
502  return;
503  }
504  }
505  // ignore these and the follow arg
506  for(i=0; i<ignore_opts_with_arg.size(); i++) { // note that -- is included
507  if(sarg == ignore_opts_with_arg[i]) {
508  LOG(DEBUG) << "CommandLine::PreProcess: ignoring option " << sarg
509  << " and its argument";
510  ignore_once = true;
511  return;
512  }
513  }
514  // handle 'ignore on' args
515  for(i=0; i<ignore_on_opts.size(); i++) { // note that -- is included
516  if(sarg == ignore_on_opts[i]) {
517  LOG(DEBUG) << "CommandLine::PreProcess: start ignoring options: " << sarg;
518  ignore_opts = true;
519  return;
520  }
521  }
522  // handle 'ignore off' args
523  for(i=0; i<ignore_off_opts.size(); i++) { // note that -- is included
524  if(sarg == ignore_off_opts[i]) {
525  LOG(DEBUG) << "CommandLine::PreProcess: stop ignoring options: " << sarg;
526  ignore_opts = false;
527  return;
528  }
529  }
530  // it ignoring is 'on'
531  if(ignore_opts) {
532  LOG(DEBUG) << "CommandLine::PreProcess: ignoring option " << sarg;
533  return;
534  }
535 
536  // config file
537  if(sarg == "--file" || sarg == "-f") // strip out before found_cfg_file
538  found_cfg_file = true;
539 
540  // NB second test (in_arg[0]...) is for -f <file> embedded in another cfg file *1*
541  else if(found_cfg_file || (in_arg[0]=='-' && in_arg[1]=='f')) {
542  string filename(in_arg);
543  if(!found_cfg_file) filename.erase(0,2); else found_cfg_file = false;
544  LOG(DEBUG) << "CommandLine::PreProcess found a file of options: " << filename;
545  ifstream infile(filename.c_str());
546  if(!infile) {
547  LOG(ERROR) << "Error: could not open options file " << filename;
548  return;
549  }
550 
551  bool again_cfg_file=false;
552  string buffer,word;
553  while(1) {
554  getline(infile,buffer);
555  stripTrailing(buffer,'\r');
556  //LOG(DEBUG) << "Line in file " << filename << " is " << buffer;
557 
558  // process the buffer before checking eof or bad b/c there can be
559  // a line at EOF that has no CRLF...
560  while(!buffer.empty()) {
561  word = firstWord(buffer);
562  if(again_cfg_file) {
563  word = "-f" + word; // see above *1*
564  again_cfg_file = false;
565  PreProcessArgs(word.c_str(),Args,Errors);
566  }
567  else if(word[0] == '#') { // skip to end of line
568  buffer = "";
569  }
570  else if(word == "--file" || word == "-f")
571  again_cfg_file = true;
572  else if(word[0] == '"') {
573  word = stripFirstWord(buffer,'"');
574  buffer = "dummy " + buffer; // to be stripped below
575  PreProcessArgs(word.c_str(),Args,Errors);
576  }
577  else
578  PreProcessArgs(word.c_str(),Args,Errors);
579 
580  word = stripFirstWord(buffer);
581  }
582  if(infile.eof() || !infile.good()) break;
583  } // end loop over file
584 
585  ignore_opts = false;
586  }
587 
588  // other args to strip out
589  else if(sarg==string("-h") || sarg==string("--help")) {
590  help = true;
591  LOG(DEBUG) << "CommandLine::PreProcess found help option";
592  }
593  else if(sarg.substr(0,2)==string("-d") || sarg.substr(0,7)==string("--debug")) {
594  string level("DEBUG");
595  if(sarg==string("-d") || sarg==string("--debug"))
596  debug = 0;
597  else
598  debug = asInt(sarg[1]=='d' ? sarg.substr(2) : sarg.substr(7));
599 
600  if(debug >= 0 && debug <= 7) {
601  if(debug > 0) level += asString(debug);
602  ConfigureLOG::ReportingLevel() = ConfigureLOG::Level(level.c_str());
603  LOG(DEBUG) << "CommandLine found debug option at level " << debug
604  << ", logging level "
605  << ConfigureLOG::ToString(ConfigureLOG::ReportingLevel());
606  verbose = true; // NB debug implies verbose
607  }
608  }
609  else if(sarg==string("-v") || sarg==string("--verbose")) {
610  verbose = true;
611  // do NOT overwrite debug setting else serious subtle problems
612  if(debug == -1)
613  ConfigureLOG::ReportingLevel() = ConfigureLOG::Level("VERBOSE");
614  LOG(DEBUG) << "CommandLine::PreProcess found the verbose option";
615  }
616 
617  // deprecated options
618  // note that -- is included in both key and value
619  else if(deprec_opts.find(sarg) != deprec_opts.end())
620  Args.push_back(deprec_opts[sarg]);
621 
622  // regular argument
623  else {
624  LOG(DEBUG) << "CommandLine::PreProcess found regular arg " << sarg;
625  Args.push_back(sarg);
626  }
627 }
628 catch(Exception& e) { GNSSTK_RETHROW(e); }
629 catch(std::exception& e) {
630  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
631 }
632 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
633 }
634 
635 // -----------------------------------------------------------------------------------
639 void expand_args(vector<string>& oldvalues, vector<string>& newvalues, string& msg)
640 {
641 try {
642  string arg;
643 
644  for(size_t k=0; k<oldvalues.size(); k++) { // first split values on ','
645  while(!(arg = stripFirstWord(oldvalues[k],',')).empty()) {
646  if(arg.substr(0,1) == "@") { // list file
647  // remove the '@'
648  string filename(arg.substr(1));
649 
650  // expand ~ in the filename
651  expand_filename(filename);
652 
653  // open the file, read it and get new values (expandtilde.cpp)
654  if(!expand_list_file(filename,newvalues)) {
655  msg += " Error - Argument list file " + filename
656  + " could not be opened.";
657  continue;
658  }
659  else LOG(DEBUG) << "Opened arg list file " << filename;
660  }
661  else // just a value
662  newvalues.push_back(arg);
663 
664  } // end while
665  } // end for
666 } // end try
667 catch(Exception& e) { GNSSTK_RETHROW(e); }
668 catch(std::exception& e) {
669  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
670 }
671 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
672 }
673 
674 // -----------------------------------------------------------------------------------
675 // fill values for each option, and Errors and Unrecog
679 void CommandLine::Parse(vector<string>& Args, string& Errors, vector<string>& Unrecog)
680 {
681 try {
682  size_t i,j;
683  string arg,val;
684 
685  // parse args, saving values -----------------------
686  i = 0;
687  while(i < Args.size()) {
688  arg = Args[i]; // arg
689  // does it match an option?
690  for(j=0; j<options.size(); ++j) {
691  if((arg.size() == 2 && arg[0] == '-' && arg[1] == options[j].shortOpt) ||
692  (arg.substr(0,2) == "--" && arg.substr(2) == options[j].longOpt))
693  { // match
694  if(options[j].type > typeBool) { // find value
695  if(i == Args.size()-1) {
696  Errors += "Error - option " + arg + " without value.\n";
697  break;
698  }
699  else if(Args[i+1].substr(0,2) == "--") {
700  Errors += "Error - option " + arg + " without value.\n";
701  break;
702  }
703  else val = Args[++i]; // value
704  }
705  else val = string("T"); // bool 'value'
706 
707  LOG(DEBUG) << "CommandLine::Parse found arg[" << i << "] "
708  << arg << " = " << val;
709  options[j].values.push_back(val); // save it
710 
711  break;
712  } // end match
713  } // end loop over options
714 
715  if(j == options.size()) {
716  Unrecog.push_back(Args[i]);
717  LOG(DEBUG) << "CommandLine::Parse found unrecognized arg[" << i << "] "
718  << Args[i];
719  }
720 
721  // next arg
722  ++i;
723 
724  } // end loop over args
725 
726  // were all required options found? -----------------------
727  // were any non-repeatable options repeated? --------------
728  for(j=0; j<options.size(); ++j) {
729 
730  // do this here, after PreProcArguments() and before the code below
731  // define callers special targets, using values found in PreProcessArgs
732  if(help && options[j].longOpt == string("help")) {
733  LOG(DEBUG) << "CommandLine::Parse found help option and help";
734  *((bool *)(options[j].p_output)) = help;
735  options[j].values.push_back(string("T"));
736  }
737  else if(verbose && options[j].longOpt == string("verbose")) {
738  LOG(DEBUG) << "CommandLine::Parse found verbose option and verbose";
739  *((bool *)(options[j].p_output)) = verbose;
740  options[j].values.push_back(string("T"));
741  }
742  else if(debug > -1 && options[j].longOpt == string("debug")) {
743  LOG(DEBUG) << "CommandLine::Parse found debug option and debug = " << debug;
744  *((int *)(options[j].p_output)) = debug;
745  options[j].values.push_back(asString(debug));
746  }
747 
748  // required options that are not found
749  if(options[j].required && options[j].values.size() == 0)
750  Errors += "Required option " + options[j].longOpt + " is not found.\n";
751 
752  // non-repeatable options that are repeated
753  if(!options[j].repeat && options[j].values.size() > 1)
754  Errors += "Not-repeatable option "+options[j].longOpt+" was repeated.\n";
755  }
756 
757 }
758 catch(Exception& e) { GNSSTK_RETHROW(e); }
759 catch(std::exception& e) {
760  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
761 }
762 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
763 }
764 
765 // -----------------------------------------------------------------------------------
769 string CommandLine::SyntaxPage(void)
770 {
771 try {
772  if(syntaxPageBuilt == 2) {
773  if(options.size() > 0)
774  for(int i=0; i<options.size(); i++)
775  if(options[i].doc)
776  syntaxPage += options[i].syntax + "\n";
777 
778  // add verbose, debug and help, which are always there...
779  syntaxPage += //"# (automatic options)\n" +
780  leftJustify(" --verbose",optionsize)
781  + "Print extended output, including cmdline summary (don't)\n";
782  syntaxPage += leftJustify(" --debug<n>",optionsize)
783  + "Print debug output at LOGlevel n [n=0-7] (-1)\n";
784  syntaxPage += leftJustify(" --help",optionsize)
785  + "Print this syntax page and quit (don't)";
786 
787  syntaxPageBuilt = 3;
788  }
789 
790  return syntaxPage;
791 }
792 catch(Exception& e) { GNSSTK_RETHROW(e); }
793 catch(std::exception& e) {
794  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
795 }
796 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
797 }
798 
799 // -----------------------------------------------------------------------------------
803 void CommandLine::Postprocess(string& Errors, vector<string>& Unrecog)
804 {
805 try {
806  size_t i,k;
807  RinexSatID sat;
808  string msg,errStr;
809  vector<string> values;
810  ostringstream oss;
811 
812  // loop over options, parse out @file and value,value, and assign targets
813  for(i=0; i<options.size(); i++) {
814 
815  // was the option even found on the command line?
816  if(options[i].values.size() == 0) continue;
817  LOG(DEBUG) << "CommandLine::Postprocess parse " << options[i].longOpt
818  << " of type " << options[i].type << (options[i].doc ? "":" undocumented");
819 
820  // bool is special b/c values are ignored
821  if(options[i].type == typeBool) {
822  *((bool *)(options[i].p_output)) = ( options[i].toggle ?
823  ! (*((bool *)(options[i].p_output))) : true );
824  continue;
825  }
826 
827  // get the array of values (strings)
828  values = options[i].values;
829 
830  // parse out 'value,value' and '@file.lst'
831  if(options[i].expand && (options[i].type == typeVectorString ||
832  options[i].type == typeVectorSat ||
833  options[i].type == typeVectorInt))
834  {
835  vector<string> nvalues;
836  expand_args(values, nvalues, errStr);
837  if(!errStr.empty())
838  oss << errStr << " for option --" << options[i].longOpt << "\n";
839  values = nvalues;
840  }
841 
842  switch(options[i].type) {
843  case typeBool: // bool -- done above
844  break;
845 
846  case typeInt:
847  if(!isDigitString(values[0]))
848  oss << "Error: non-integer value for --" << options[i].longOpt
849  << ": " << values[0] << endl;
850  else
851  *((int *)(options[i].p_output)) = asInt(values[0]);
852  break;
853 
854  case typeVectorInt:
855  for(k=0; k<values.size(); k++) {
856  if(!isDigitString(values[k]))
857  oss << "Error: non-integer value for --" << options[i].longOpt
858  << ": " << values[k] << endl;
859  else
860  ((vector<int> *)(options[i].p_output))->push_back(asInt(values[k]));
861  }
862  break;
863 
864  case typeDouble:
865  if(!isScientificString(values[0]))
866  oss << "Error: invalid value for --" << options[i].longOpt
867  << ": " << values[0] << endl;
868  else
869  *((double *)(options[i].p_output))=asDouble(values[0]);
870  break;
871 
872  case typeString:
873  *((string *)(options[i].p_output)) = values[0];
874  break;
875 
876  case typeVectorString:
877  for(k=0; k<values.size(); k++)
878  ((vector<string> *)(options[i].p_output))->push_back(values[k]);
879  break;
880 
881  case typeSat:
882  sat = RinexSatID(values[0]);
883  *(RinexSatID *)(options[i].p_output) = sat;
884  break;
885 
886  case typeVectorSat:
887  for(k=0; k<values.size(); k++) {
888  sat = RinexSatID(values[k]);
889  ((vector<RinexSatID> *)(options[i].p_output))->push_back(sat);
890  }
891  break;
892  case typeUndefined:
893  case typeCount:
894  break;
895  }
896 
897  } // end loop over options
898 
899  // NO! ResCor has commas in REdit cmds.
900  // parse out @file and value,value from unrecognized args
901  //vector<string> nvalues;
902  //expand_args(Unrecog, nvalues, errStr);
903  //if(!errStr.empty()) Errors += errStr + " (an unrecognized arg)\n";
904  //Unrecog = nvalues;
905 
906  Errors += oss.str();
907 
908 } // end try
909 catch(Exception& e) { GNSSTK_RETHROW(e); }
910 catch(std::exception& e) {
911  Exception E("std except: "+string(e.what())); GNSSTK_THROW(E);
912 }
913 catch(...) { Exception e("Unknown exception"); GNSSTK_THROW(e); }
914 }
915 
916 // -----------------------------------------------------------------------------------
917 // -----------------------------------------------------------------------------------
918 }
expandtilde.hpp
gnsstk::StringUtils::asInt
long asInt(const std::string &s)
Definition: StringUtils.hpp:713
gnsstk::SatID::id
int id
Satellite identifier, e.g. PRN.
Definition: SatID.hpp:154
CommandLine.hpp
gnsstk::StringUtils::word
std::string word(const std::string &s, const std::string::size_type wordNum=0, const char delimiter=' ')
Definition: StringUtils.hpp:1112
gnsstk::typeString
std::string typeString()
Definition: TestUtil.hpp:238
StringUtils.hpp
stl_helpers.hpp
logstream.hpp
gnsstk::StringUtils::asString
std::string asString(IonexStoreStrategy e)
Convert a IonexStoreStrategy to a whitespace-free string name.
Definition: IonexStoreStrategy.cpp:46
gnsstk::expand_list_file
bool expand_list_file(string &filename, vector< string > &values)
Definition: expandtilde.cpp:95
gnsstk
For Sinex::InputHistory.
Definition: BasicFramework.cpp:50
gnsstk::expand_filename
void expand_filename(string &filename)
Definition: expandtilde.cpp:51
gnsstk::Exception
Definition: Exception.hpp:151
gnsstk::StringUtils::floatFormat
std::string floatFormat(double d, FFLead lead, unsigned mantissa, unsigned exponent, unsigned width, char expChar, FFSign sign, FFAlign align)
Definition: StringUtils.cpp:210
gnsstk::StringUtils::stripTrailing
std::string & stripTrailing(std::string &s, const std::string &aString, std::string::size_type num=std::string::npos)
Definition: StringUtils.hpp:1453
gnsstk::expand_args
void expand_args(vector< string > &oldvalues, vector< string > &newvalues, string &msg)
Definition: CommandLine.cpp:639
debug
#define debug
Definition: Rinex3ClockHeader.cpp:51
gnsstk::ERROR
@ ERROR
Definition: logstream.hpp:57
gnsstk::StringUtils::stripFirstWord
std::string stripFirstWord(std::string &s, const char delimiter=' ')
Definition: StringUtils.hpp:2253
arg
double arg
Definition: IERS1996UT1mUTCData.hpp:48
gnsstk::StringUtils::asDouble
double asDouble(const std::string &s)
Definition: StringUtils.hpp:705
GNSSTK_RETHROW
#define GNSSTK_RETHROW(exc)
Definition: Exception.hpp:369
example4.pos
pos
Definition: example4.py:125
gnsstk::StringUtils
Definition: IonexStoreStrategy.cpp:44
option
Definition: getopt.h:94
LOG
#define LOG(level)
define the macro that is used to write to the log stream
Definition: logstream.hpp:315
gnsstk::RinexSatID::toString
std::string toString() const noexcept
Definition: RinexSatID.cpp:204
gnsstk::RinexSatID
Definition: RinexSatID.hpp:63
Exception.hpp
std
Definition: Angle.hpp:142
gnsstk::StringUtils::firstWord
std::string firstWord(const std::string &s, const char delimiter=' ')
Definition: StringUtils.hpp:2138
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
gnsstk::DEBUG
@ DEBUG
Definition: logstream.hpp:57
gnsstk::StringUtils::isScientificString
bool isScientificString(const std::string &s)
Definition: StringUtils.hpp:1908
gnsstk::StringUtils::isDigitString
bool isDigitString(const std::string &s)
Definition: StringUtils.hpp:1871
gnsstk::vectorindex
int vectorindex(const std::vector< T > &vec, const T &value)
Definition: stl_helpers.hpp:123
docstring_generator.help
help
Definition: docstring_generator.py:98


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