USGS

Isis 3.0 Object Programmers' Reference

Home

UserInterface.cpp
Go to the documentation of this file.
1 
22 #include "UserInterface.h"
23 
24 #include <sstream>
25 #include <vector>
26 
27 #include <QDir>
28 
29 #include "Application.h"
30 #include "FileName.h"
31 #include "Gui.h"
32 #include "IException.h"
33 #include "IString.h"
34 #include "Message.h"
35 #include "Preference.h"
36 #include "ProgramLauncher.h"
37 #include "TextFile.h"
38 
39 using namespace std;
40 namespace Isis {
41 
52  UserInterface::UserInterface(const QString &xmlfile, int &argc,
53  char *argv[]) : IsisAml::IsisAml(xmlfile) {
54  p_interactive = false;
55  p_info = false;
56  p_infoFileName = "";
57  p_gui = NULL;
58  p_errList = "";
59  p_saveFile = "";
60  p_abortOnError = true;
61  p_parentId = 0;
62 
63  // Make sure the user has a .Isis and .Isis/history directory
64  try {
65  FileName setup = "$HOME/.Isis/history";
66  // cannot completely test this if in unit test
67  if ( !setup.fileExists() ) {
68  setup.dir().mkpath(".");
69  }
70  }
71  catch (IException &) {
72  }
73 
74  // Parse the user input
75  loadCommandLine(argc, argv);
76 
77  // See if we need to create the gui
78  // can't unit test - don't want to create a Gui object while unit testing
79  if (p_interactive) {
80  Gui::checkX11();
81  p_gui = Gui::Create(*this, argc, argv);
82  }
83  }
84 
87  // can't unit test - p_gui will be NULL in unit test
88  if (p_gui) {
89  delete p_gui;
90  p_gui = NULL;
91  }
92  }
93 
101  return p_infoFileName;
102  }
103 
104 
112  return p_info;
113  }
114 
115 
125  //Clear all parameters currently in the gui
126  for (int k = 0; k < NumGroups(); k++) {
127  for (int j = 0; j < NumParams(k); j++) {
128  Clear( ParamName(k, j) );
129  }
130  }
131 
132  //Load the new parameters into the gui
133  cout << p_progName << " ";
134 
135  for (unsigned int currArgument = 1; currArgument < p_cmdline.size(); currArgument ++) {
136  QString paramName;
137  vector<QString> paramValue;
138 
139 
140  try {
141  getNextParameter(currArgument, paramName, paramValue);
142 
143  if (paramName[0] == '-')
144  continue;
145 
146  for (unsigned int value = 0; value < paramValue.size(); value++) {
147  IString thisValue = paramValue[value];
148  QString token = thisValue.Token("$").ToQt();
149 
150  QString newValue;
151 
152  while (thisValue != "") {
153  newValue += token;
154  try {
155  int j = toInt( thisValue.substr(0, 1).c_str() ) - 1;
156  newValue += p_batchList[i][j];
157  thisValue.replace(0, 1, "");
158  token = thisValue.Token("$").ToQt();
159  }
160  catch (IException &e) {
161  // Let the variable be parsed by the application
162  newValue += "$";
163  token = thisValue.Token("$").ToQt();
164  }
165  }
166 
167  if (token != "")
168  newValue += token;
169 
170  paramValue[value] = newValue;
171  }
172  }
173  // can't test with unit test - command line is already parsed before SetBatchList() is called
174  catch (IException &e) {
175  throw IException(IException::User, "Invalid command line", _FILEINFO_);
176  }
177 
178  PutAsString(paramName, paramValue);
179 
180  cout << paramName;
181 
182  if(paramValue.size() == 1) {
183  cout << "=" << paramValue[0] << " ";
184  }
185  else if (paramValue.size() > 1) {
186  cout << "=(";
187 
188  for (unsigned int value = 0; value < paramValue.size(); value++) {
189  if(value != 0)
190  cout << ",";
191 
192  cout << paramValue[value] << endl;
193  }
194 
195  cout << ") ";
196  }
197  }
198  cout << endl;
199 
200  // Verify the command line
201  VerifyAll();
202  }
203 
204 
216  if (p_errList != "") {
217  std::ofstream os;
218  QString fileName( FileName(p_errList).expanded() );
219  os.open(fileName.toAscii().data(), std::ios::app);
220 
221  // did not unit test since it is assumed ofstream will be instantiated correctly
222  if ( !os.good() ) {
223  QString msg = "Unable to create error list [" + p_errList
224  + "] Disk may be full or directory permissions not writeable";
226  }
227 
228  for (int j = 0; j < (int) p_batchList[i].size(); j++) {
229  os << p_batchList[i][j] << " ";
230  }
231 
232  os << endl;
233  os.close();
234  }
235  }
236 
237 
243 
244  // If history recording is off, return
245  Preference &p = Preference::Preferences();
246  PvlGroup &grp = p.findGroup("UserInterface", Isis::Pvl::Traverse);
247  if (grp["HistoryRecording"][0] == "Off")
248  return;
249 
250  // Get the current history file
251  Isis::FileName histFile(grp["HistoryPath"][0] + "/" + ProgramName() + ".par");
252 
253  // If a save file is specified, override the default file path
254  if (p_saveFile != "")
255  histFile = p_saveFile;
256 
257  // Get the current command line
258  Isis::Pvl cmdLine;
259  CommandLine(cmdLine);
260 
261  Isis::Pvl hist;
262 
263  // If the history file's Pvl is corrupted, then
264  // leave hist empty such that the history gets
265  // overwriten with the new entry.
266  try {
267  if ( histFile.fileExists() ) {
268  hist.read( histFile.expanded() );
269  }
270  }
271  catch (IException &) {
272  }
273 
274  // Add it
275  hist.addGroup( cmdLine.findGroup("UserParameters") );
276 
277  // See if we have exceeded history length
278  while( hist.groups() > toInt(grp["HistoryLength"][0]) ) {
279  hist.deleteGroup("UserParameters");
280  }
281 
282  // Write it
283  try {
284  hist.write( histFile.expanded() );
285  }
286  catch (IException &) {
287  }
288 
289  }
290 
291 
304  void UserInterface::loadBatchList(const QString file) {
305  // Read in the batch list
306  TextFile temp;
307  try {
308  temp.Open(file);
309  }
310  catch (IException &e) {
311  QString msg = "The batchlist file [" + file + "] could not be opened";
313  }
314 
315  p_batchList.resize( temp.LineCount() );
316 
317  for (int i = 0; i < temp.LineCount(); i++) {
318  QString t;
319  temp.GetLine(t);
320 
321  // Convert tabs to spaces but leave tabs inside quotes alone
322  t = IString(t).Replace("\t", " ", true).ToQt();
323 
324  t = IString(t).Compress().ToQt().trimmed();
325  // Allow " ," " , " or ", " as a valid single seperator
326  t = IString(t).Replace(" ,", ",", true).ToQt();
327  t = IString(t).Replace(", ", ",", true).ToQt();
328  // Convert all spaces to "," the use "," as delimiter
329  t = IString(t).Replace(" ", ",", true).ToQt();
330  int j = 0;
331 
332  QStringList tokens = t.split(",");
333 
334  foreach (QString token, tokens) {
335  // removes quotes from tokens. NOTE: also removes escaped quotes.
336  token = token.remove( QRegExp("[\"']") );
337  p_batchList[i].push_back(token);
338  j++ ;
339  }
340 
341  p_batchList[i].resize(j);
342  // Every row in the batchlist must have the same number of columns
343  if (i == 0)
344  continue;
345  if ( p_batchList[i - 1].size() != p_batchList[i].size() ) {
346  QString msg = "The number of columns must be constant in batchlist";
348  }
349  }
350  // The batchlist cannot be empty
351  if (p_batchList.size() < 1) {
352  QString msg = "The list file [" + file + "] does not contain any data";
354  }
355  }
356 
357 
373  void UserInterface::loadCommandLine(int argc, char *argv[]) {
374  // The program will be interactive if it has no arguments or
375  // if it has the name unitTest
376  p_progName = argv[0];
378  // cannot completely test in a unit test since unitTest will always evaluate to true
379  if ( (argc == 1) && (file.name() != "unitTest") ) {
380  p_interactive = true;
381  }
382 
383  p_cmdline.clear();
384  for (int i = 0; i < argc; i++) {
385  p_cmdline.push_back(argv[i]);
386  }
387 
388  // Check for special tokens (reserved parameters) (those beginning with a dash)
389  vector<QString> options;
390  options.push_back("-GUI");
391  options.push_back("-NOGUI");
392  options.push_back("-BATCHLIST");
393  options.push_back("-LAST");
394  options.push_back("-RESTORE");
395  options.push_back("-WEBHELP");
396  options.push_back("-HELP");
397  options.push_back("-ERRLIST");
398  options.push_back("-ONERROR");
399  options.push_back("-SAVE");
400  options.push_back("-INFO");
401  options.push_back("-PREFERENCE");
402  options.push_back("-LOG");
403  options.push_back("-VERBOSE");
404  options.push_back("-PID");
405 
406  bool usedDashLast = false;
407  bool usedDashRestore = false; //< for throwing -batchlist exceptions at end of function
408 
409  // pre-process command line for -HELP first
410  preProcess("-HELP", options);
411  // pre-process command line for -WEBHELP
412  preProcess("-WEBHELP", options);
413  // now, parse command line to evaluate -LAST
414  preProcess("-LAST", options);
415 
416  for (unsigned int currArgument = 1; currArgument < (unsigned)argc; currArgument++) {
417  QString paramName;
418  vector<QString> paramValue;
419 
420  getNextParameter(currArgument, paramName, paramValue);
421 
422  // we now have a name,value pair
423  if (paramName[0] == '-') {
424  paramName = paramName.toUpper();
425 
426  // where if(paramname == -last ) to continue } was originally
427 
428  if (paramValue.size() > 1) {
429  QString msg = "Invalid value for reserve parameter ["
430  + paramName + "]";
432  }
433 
434  // resolve the reserved parameter (e.g. set -h to -HELP)
435  paramName = resolveParameter(paramName, options);
436 
437  // Prevent double handling of -LAST to prevent conflicts
438  // Keep track of using -LAST to prevent conflicts with -BATCHLIST
439  if (paramName == "-LAST") {
440  usedDashLast = true;
441  continue;
442  }
443 
444 
445  // Keep track of using -RESTORE to prevent conflicts with -BATCHLIST
446  if (paramName == "-RESTORE") {
447  usedDashRestore = true;
448  }
449 
450 
451  QString realValue = "";
452 
453  if ( paramValue.size() ) {
454  realValue = paramValue[0];
455  }
456 
457  evaluateOption(paramName, realValue);
458  continue;
459  }
460 
461  try {
462  Clear(paramName);
463  PutAsString(paramName, paramValue);
464  }
465  catch (IException &e) {
466  throw IException(e, IException::User, "Invalid command line", _FILEINFO_);
467  }
468  }
469 
470  // Can't use the batchlist with the gui, save, last or restore option
471  if ( BatchListSize() != 0 && (p_interactive || usedDashLast || p_saveFile != ""
472  || usedDashRestore) ) {
473  QString msg = "-BATCHLIST cannot be used with -GUI, -SAVE, -RESTORE, ";
474  msg += "or -LAST";
476  }
477 
478  // Must use batchlist if using errorlist or onerror=continue
479  if ( (BatchListSize() == 0) && (!p_abortOnError || p_errList != "") ) {
480  QString msg = "-ERRLIST and -ONERROR=continue cannot be used without ";
481  msg += " the -BATCHLIST option";
483  }
484  }
485 
486 
498  void UserInterface::loadHistory(const QString file) {
499  Isis::FileName hist(file);
500  if ( hist.fileExists() ) {
501  try {
502  Isis::Pvl lab( hist.expanded() );
503 
504  int g = lab.groups() - 1;
505  if (g >= 0 && lab.group(g).isNamed("UserParameters") ) {
506  Isis::PvlGroup &up = lab.group(g);
507  for (int k = 0; k < up.keywords(); k++) {
508  QString keyword = up[k].name();
509 
510  vector<QString> values;
511 
512  for (int i = 0; i < up[k].size(); i++) {
513  values.push_back(up[k][i]);
514  }
515 
516  const IsisParameterData *paramData = ReturnParam(keyword);
517 
518  bool matchesDefault = false;
519  if (values.size() == 1 && paramData->internalDefault == values[0])
520  matchesDefault = true;
521 
522  if (!matchesDefault) {
523  matchesDefault =
524  (values.size() == paramData->defaultValues.size());
525 
526  for (int i = 0; matchesDefault && i < (int)values.size(); i++) {
527  matchesDefault = matchesDefault &&
528  values[i] == paramData->defaultValues[i];
529  }
530  }
531 
532  if (!matchesDefault)
533  PutAsString(keyword, values);
534  }
535  return;
536  }
537 
538  for (int o = lab.objects() - 1; o >= 0; o--) {
539  if ( lab.object(o).isNamed( ProgramName() ) ) {
540  Isis::PvlObject &obj = lab.object(o);
541  for (int g = obj.groups() - 1; g >= 0; g--) {
542  Isis::PvlGroup &up = obj.group(g);
543  if ( up.isNamed("UserParameters") ) {
544  for (int k = 0; k < up.keywords(); k++) {
545  QString keyword = up[k].name();
546  QString value = up[k][0];
547  PutAsString(keyword, value);
548  }
549  }
550  return;
551  }
552  }
553  }
554 
555  /*QString msg = "[" + hist.expanded() +
556  "] does not contain any parameters to restore";
557  throw Isis::iException::Message( Isis::iException::User, msg, _FILEINFO_ );*/
558  }
559  catch (...) {
560  QString msg = "The history file [" + file + "] is corrupt, please fix or delete this file";
562  }
563  }
564  else {
565  QString msg = "The history file [" + file + "] does not exist";
567  }
568  }
569 
570 
585  void UserInterface::evaluateOption(const QString name,
586  const QString value) {
587  // check to see if the program is a unitTest
588  bool unitTest = false;
589  if (FileName(p_progName).name() == "unitTest") {
590  unitTest = true;
591  }
592  Preference &p = Preference::Preferences();
593 
594  if (name == "-GUI") {
595  p_interactive = true;
596  }
597  else if (name == "-NOGUI") {
598  p_interactive = false;
599  }
600  else if (name == "-BATCHLIST") {
601  loadBatchList(value);
602  }
603  else if (name == "-LAST") {
604  QString histFile;
605  // need to handle for unit test since -LAST is preprocessed
606  if (unitTest) {
607  histFile = "./" + FileName(p_progName).name() + ".par";
608  }
609  else {
610  PvlGroup &grp = p.findGroup("UserInterface", Isis::Pvl::Traverse);
611  histFile = grp["HistoryPath"][0] + "/" + FileName(p_progName).name() + ".par";
612  }
613 
614  loadHistory(histFile);
615  }
616  else if(name == "-RESTORE") {
617  loadHistory(value);
618  }
619  else if(name == "-WEBHELP") {
620  Isis::PvlGroup &pref = Isis::Preference::Preferences().findGroup("UserInterface");
621  QString command = pref["GuiHelpBrowser"];
622  command += " $ISISROOT/doc/Application/presentation/Tabbed/";
623  command += FileName(p_progName).name() + "/" + FileName(p_progName).name() + ".html";
624  // cannot test else in unit test - don't want to open webhelp
625  if (unitTest) {
627  "Evaluating -WEBHELP should only throw this exception during a unitTest",
628  _FILEINFO_);
629  }
630  else {
632  exit(0);
633  }
634 
635  }
636  else if (name == "-INFO") {
637  p_info = true;
638 
639  // check for filename and set value
640  if (value.size() != 0) {
641  p_infoFileName = value;
642  }
643  }
644  else if (name == "-HELP") {
645  if (value.size() == 0) {
646  Pvl params;
647  params.setTerminator("");
648  for (int k = 0; k < NumGroups(); k++) {
649  for (int j = 0; j < NumParams(k); j++) {
650  if (ParamListSize(k, j) == 0) {
651  params += PvlKeyword( ParamName(k, j), ParamDefault(k, j) );
652  }
653  else {
654  PvlKeyword key( ParamName(k, j) );
655  QString def = ParamDefault(k, j);
656  for (int l = 0; l < ParamListSize(k, j); l++) {
657  if (ParamListValue(k, j, l) == def)
658  key.addValue("*" + def);
659  else
660  key.addValue( ParamListValue(k, j, l) );
661  }
662  params += key;
663  }
664  }
665  }
666  cout << params;
667  }
668  else {
669  Pvl param;
670  param.setTerminator("");
671  QString key = value;
672  for (int k = 0; k < NumGroups(); k++) {
673  for (int j = 0; j < NumParams(k); j++) {
674  if (ParamName(k, j) == key) {
675  param += PvlKeyword("ParameterName", key);
676  param += PvlKeyword( "Brief", ParamBrief(k, j) );
677  param += PvlKeyword( "Type", ParamType(k, j) );
678  if (PixelType(k, j) != "") {
679  param += PvlKeyword( "PixelType", PixelType(k, j) );
680  }
681  if (ParamInternalDefault(k, j) != "") {
682  param += PvlKeyword( "InternalDefault", ParamInternalDefault(k, j) );
683  }
684  else {
685  param += PvlKeyword( "Default", ParamDefault(k, j) );
686  }
687  if (ParamMinimum(k, j) != "") {
688  if (ParamMinimumInclusive(k, j).toUpper() == "YES") {
689  param += PvlKeyword( "GreaterThanOrEqual",
690  ParamMinimum(k, j) );
691  }
692  else {
693  param += PvlKeyword( "GreaterThan",
694  ParamMinimum(k, j) );
695  }
696  }
697  if (ParamMaximum(k, j) != "") {
698  if (ParamMaximumInclusive(k, j).toUpper() == "YES") {
699  param += PvlKeyword( "LessThanOrEqual",
700  ParamMaximum(k, j) );
701  }
702  else {
703  param += PvlKeyword( "LessThan",
704  ParamMaximum(k, j) );
705  }
706  }
707  if (ParamLessThanSize(k, j) > 0) {
708  PvlKeyword key("LessThan");
709  for(int l = 0; l < ParamLessThanSize(k, j); l++) {
710  key.addValue( ParamLessThan(k, j, l) );
711  }
712  param += key;
713  }
714  if (ParamLessThanOrEqualSize(k, j) > 0) {
715  PvlKeyword key("LessThanOrEqual");
716  for (int l = 0; l < ParamLessThanOrEqualSize(k, j); l++) {
717  key.addValue( ParamLessThanOrEqual(k, j, l) );
718  }
719  param += key;
720  }
721  if (ParamNotEqualSize(k, j) > 0) {
722  PvlKeyword key("NotEqual");
723  for (int l = 0; l < ParamNotEqualSize(k, j); l++) {
724  key.addValue( ParamNotEqual(k, j, l) );
725  }
726  param += key;
727  }
728  if (ParamGreaterThanSize(k, j) > 0) {
729  PvlKeyword key("GreaterThan");
730  for (int l = 0; l < ParamGreaterThanSize(k, j); l++) {
731  key.addValue( ParamGreaterThan(k, j, l) );
732  }
733  param += key;
734  }
735  if (ParamGreaterThanOrEqualSize(k, j) > 0) {
736  PvlKeyword key("GreaterThanOrEqual");
737  for(int l = 0; l < ParamGreaterThanOrEqualSize(k, j); l++) {
738  key.addValue( ParamGreaterThanOrEqual(k, j, l) );
739  }
740  param += key;
741  }
742  if (ParamIncludeSize(k, j) > 0) {
743  PvlKeyword key("Inclusions");
744  for (int l = 0; l < ParamIncludeSize(k, j); l++) {
745  key.addValue( ParamInclude(k, j, l) );
746  }
747  param += key;
748  }
749  if (ParamExcludeSize(k, j) > 0) {
750  PvlKeyword key("Exclusions");
751  for (int l = 0; l < ParamExcludeSize(k, j); l++) {
752  key.addValue( ParamExclude(k, j, l) );
753  }
754  param += key;
755  }
756  if (ParamOdd(k, j) != "") {
757  param += PvlKeyword( "Odd", ParamOdd(k, j) );
758  }
759  if (ParamListSize(k, j) != 0) {
760  for (int l = 0; l < ParamListSize(k, j); l++) {
761  PvlGroup grp( ParamListValue(k, j, l) );
762  grp += PvlKeyword( "Brief", ParamListBrief(k, j, l) );
763  if (ParamListIncludeSize(k, j, l) != 0) {
764  PvlKeyword include("Inclusions");
765  for (int m = 0; m < ParamListIncludeSize(k, j, l); m++) {
766  include.addValue( ParamListInclude(k, j, l, m) );
767  }
768  grp += include;
769  }
770  if (ParamListExcludeSize(k, j, l) != 0) {
771  PvlKeyword exclude("Exclusions");
772  for (int m = 0; m < ParamListExcludeSize(k, j, l); m++) {
773  exclude.addValue( ParamListExclude(k, j, l, m) );
774  }
775  grp += exclude;
776  }
777  param.addGroup(grp);
778  }
779  }
780  cout << param;
781  }
782  }
783  }
784  }
785  // we must throw an exception for unitTest to handle to continue testing
786  if (unitTest) {
788  "Evaluating -HELP should only throw this exception during a unitTest",
789  _FILEINFO_);
790  }
791  // all other apps shall exit when -HELP is present
792  else {
793  exit(0);
794  }
795  }
796  else if (name == "-PID") {
797  p_parentId = toInt(value);
798  }
799  else if (name == "-ERRLIST") {
800  p_errList = value;
801 
802  if (value == "") {
803  QString msg = "-ERRLIST expects a file name";
805  }
806 
807  if ( FileName(p_errList).fileExists() ) {
808  QFile::remove(p_errList);
809  }
810  }
811  else if (name == "-ONERROR") {
812  if (value.toUpper() == "CONTINUE") {
813  p_abortOnError = false;
814  }
815 
816  else if (value.toUpper() == "ABORT") {
817  p_abortOnError = true;
818  }
819 
820  else {
821  QString msg = "[" + value
822  + "] is an invalid value for -ONERROR, options are ABORT or CONTINUE";
824  }
825  }
826  else if (name == "-SAVE") {
827  if (value.size() == 0) {
828  p_saveFile = ProgramName() + ".par";
829  }
830  else {
831  p_saveFile = value;
832  }
833  }
834  else if (name == "-PREFERENCE") {
835  p.Load(value);
836  }
837  else if (name == "-LOG") {
838  if( value.isEmpty() ) {
839  p.findGroup("SessionLog")["FileOutput"].setValue("On");
840  }
841  else {
842  p.findGroup("SessionLog")["FileOutput"].setValue("On");
843  p.findGroup("SessionLog")["FileName"].setValue(value);
844  }
845  }
846  // this only evaluates to true in unit test since this is last else if
847  else if (name == "-VERBOSE") {
848  p.findGroup("SessionLog")["TerminalOutput"].setValue("On");
849  }
850 
851  // Can't have a parent id and the gui
852  if (p_parentId > 0 && p_interactive) {
853  QString msg = "-GUI and -PID are incompatible arguments";
855  }
856  }
857 
858 
870  void UserInterface::getNextParameter(unsigned int &curPos,
871  QString &name,
872  std::vector<QString> &value) {
873  QString paramName = p_cmdline[curPos];
874  QString paramValue = "";
875 
876  // we need to split name and value, they can either be in 1, 2 or 3 arguments,
877  // try to see if "=" is end of argument to distinguish. Some options have no
878  // "=" and they are value-less (-gui for example).
879  if ( !paramName.contains("=") ) {
880  // This looks value-less, but lets make sure
881  // the next argument is not an equals sign by
882  // itself
883  if (curPos < p_cmdline.size() - 2) {
884  if (QString(p_cmdline[curPos + 1]).compare("=") == 0) {
885  paramValue = p_cmdline[curPos + 2];
886 
887  // increment extra to skip 2 elements next time around
888  curPos += 2;
889  }
890  }
891  }
892  // = is end of parameter, next item must be value
893  else if ( paramName.endsWith("=") ) {
894  paramName = paramName.mid(0, paramName.size() - 1);
895 
896  if (curPos + 1 < p_cmdline.size() ) {
897  paramValue = p_cmdline[curPos + 1];
898  }
899 
900  // increment extra to skip next element next time around
901  curPos++ ;
902  }
903  // we found "=" in the middle
904  else if (paramName.indexOf("=") > 0) {
905  QString parameterLiteral = p_cmdline[curPos];
906  paramName = parameterLiteral.mid( 0, parameterLiteral.indexOf("=") );
907  paramValue = parameterLiteral.mid(parameterLiteral.indexOf("=") + 1);
908  }
909  // We found "=" at the beginning - did we find "appname param =value" ?
910  else {
911  // parameters can not start with "="
912  QString msg = "Unknown parameter [" + QString(p_cmdline[curPos])
913  + "]";
915  }
916 
917  name = paramName;
918  value.clear();
919 
920  // read arrays out of paramValue
921  paramValue = paramValue.trimmed();
922 
923  if (paramValue.length() > 0 && paramValue[0] != '(') {
924  // We dont have an array... if they escaped
925  // an open paren, undo their escape
926 
927  // escape: \( result: (
928  if (paramValue.length() > 1 && paramValue.mid(0, 2) =="\\(") {
929  paramValue = paramValue.mid(1);
930  }
931  // escape: \\( result: \(
932  else if (paramValue.length() > 2 && paramValue.mid(0, 3) == "\\\\(") {
933  paramValue = paramValue.mid(1);
934  }
935 
936  value.push_back(paramValue);
937  }
938  else if ( paramValue.length() ) {
939  // We have an array...
940  value = readArray(paramValue);
941  }
942  }
943 
944 
957  void UserInterface::preProcess(QString fullReservedName,
958  std::vector<QString> &reservedParams) {
959  for (unsigned int currArgument = 1; currArgument < (unsigned)p_cmdline.size();
960  currArgument++) {
961 
962  QString paramName = p_cmdline[currArgument];
963  QString trueParamValue = "";
964  vector<QString> paramValue;
965 
966  // reserved parameters start with -
967  if (paramName[0] == '-') {
968 
969  // grab the current argument
970  getNextParameter(currArgument, paramName, paramValue);
971  paramName = paramName.toUpper();
972 
973  // grab the argument's value
974  if ( paramValue.size() ) {
975  trueParamValue = paramValue[0].toUpper();
976  }
977 
978  // resolve the reserved parameter token
979  paramName = resolveParameter(paramName, reservedParams, false);
980 
981  // evaluate the resolved parameter if it matches fullReservedName
982  if (fullReservedName == paramName) {
983  evaluateOption(paramName, trueParamValue);
984  }
985  }
986  }
987  }
988 
989 
1003  std::vector<QString> UserInterface::readArray(QString arrayString) {
1004  std::vector<QString> values;
1005 
1006  bool inDoubleQuotes = false;
1007  bool inSingleQuotes = false;
1008  bool arrayClosed = false;
1009  bool nextElementStarted = false;
1010  QString currElement = "";
1011 
1012  for (int strPos = 0; strPos < arrayString.size(); strPos++) {
1013  if (strPos == 0) {
1014  if (arrayString[strPos] != '(') {
1015  QString msg = "Invalid array format [" + arrayString + "]";
1016  throw IException(IException::User, msg, _FILEINFO_);
1017  }
1018 
1019  continue;
1020  }
1021 
1022  // take literally anything that is escaped and not quoted
1023  if ( arrayString[strPos] == '\\' && strPos + 1 < (int)arrayString.size() ) {
1024  currElement += arrayString[strPos+1];
1025  strPos++;
1026  continue;
1027  }
1028  // ends in a backslash??
1029  else if (arrayString[strPos] == '\\') {
1030  QString msg = "Invalid array format [" + arrayString + "]";
1031  throw IException(IException::User, msg, _FILEINFO_);
1032  }
1033 
1034  // not in quoted part of QString
1035  if (!inDoubleQuotes && !inSingleQuotes) {
1036  if (arrayClosed) {
1037  QString msg = "Invalid array format [" + arrayString + "]";
1038  throw IException(IException::User, msg, _FILEINFO_);
1039  }
1040 
1041  nextElementStarted = (nextElementStarted || arrayString[strPos] != ' ');
1042 
1043  if (!nextElementStarted) {
1044  continue;
1045  }
1046 
1047  if (arrayString[strPos] == '"') {
1048  inDoubleQuotes = true;
1049  }
1050  else if (arrayString[strPos] == '\'') {
1051  inSingleQuotes = true;
1052  }
1053  else if (arrayString[strPos] == ',') {
1054  values.push_back(currElement);
1055  currElement = "";
1056  nextElementStarted = false;
1057  }
1058  else if (arrayString[strPos] == ')') {
1059  values.push_back(currElement);
1060  currElement = "";
1061  arrayClosed = true;
1062  nextElementStarted = false;
1063  }
1064  else if (nextElementStarted && arrayString[strPos] == ' ') {
1065  // Make sure there's something before the next ',' or ')'
1066  bool onlyWhite = true;
1067  int closingPos = strPos + 1;
1068 
1069  for( int pos = strPos;
1070  onlyWhite && arrayString[pos] != ',' && arrayString[pos] != ')' &&
1071  pos < arrayString.size(); pos++) {
1072  closingPos++;
1073  onlyWhite &= (arrayString[pos] == ' ');
1074  }
1075 
1076  if (!onlyWhite) {
1077  currElement += arrayString[strPos];
1078  }
1079  }
1080  else if (nextElementStarted) {
1081  currElement += arrayString[strPos];
1082  }
1083  }
1084  else if (inSingleQuotes) {
1085  if(arrayString[strPos] == '\'') {
1086  inSingleQuotes = false;
1087  }
1088  else {
1089  currElement += arrayString[strPos];
1090  }
1091  }
1092  // in double quotes
1093  else {
1094  if (arrayString[strPos] == '"') {
1095  inDoubleQuotes = false;
1096  }
1097  else {
1098  currElement += arrayString[strPos];
1099  }
1100  }
1101  }
1102 
1103  if (!arrayClosed || currElement != "") {
1104  QString msg = "Invalid array format [" + arrayString + "]";
1105  throw IException(IException::User, msg, _FILEINFO_);
1106  }
1107 
1108  return values;
1109  }
1110 
1111 
1130  QString UserInterface::resolveParameter(QString &unresolvedParam,
1131  std::vector<QString> &reservedParams,
1132  bool handleNoMatches) {
1133  // index of the reserved parameter in options that matches the cmdline parameter
1134  int matchOption = -1;
1135  // determine if the reserved parameter on cmdline is shortened (e.g. -h for -HELP)
1136  for (int option = 0; option < (int)reservedParams.size(); option++) {
1137 
1138  // If our option starts with the parameter name so far, this is it
1139  if ( reservedParams[option].startsWith(unresolvedParam) ) {
1140  if (matchOption >= 0) {
1141  QString msg = "Ambiguous Reserve Parameter ["
1142  + unresolvedParam + "]. Please clarify.";
1143  throw IException(IException::User, msg, _FILEINFO_);
1144  }
1145  // set match to current iteration in loop
1146  matchOption = option;
1147  }
1148  }
1149  // handle matches by default
1150  if (handleNoMatches) {
1151  // handle no matches
1152  if (matchOption < 0) {
1153  QString msg = "Invalid Reserve Parameter Option ["
1154  + unresolvedParam + "]. Choices are ";
1155 
1156  QString msgOptions;
1157  for (int option = 0; option < (int)reservedParams.size(); option++) {
1158  // Make sure not to show -PID as an option
1159  if (reservedParams[option].compare("-PID") == 0) {
1160  continue;
1161  }
1162 
1163  msgOptions += reservedParams[option];
1164  msgOptions += ",";
1165 
1166  // this condition will never evaluate to FALSE -
1167  // this condition is only reachable when reservedParams.size() == 0 (empty) -
1168  // if this is the case, this for loop will never be entered
1169 // if ( !reservedParams.empty() ) {
1170 // msgOptions += ",";
1171 // }
1172  }
1173 
1174  // remove the terminating ',' from msgOptions
1175  msgOptions.chop(1);
1176  msg += " [" + msgOptions + "]";
1177 
1178  throw IException(IException::User, msg, _FILEINFO_);
1179  }
1180  }
1181  if (matchOption < 0) {
1182  return "";
1183  }
1184  else {
1185  return reservedParams[matchOption];
1186  }
1187  }
1188 } // end namespace isis