ewmscp  ..
Classes | Enumerations | Functions
shellScriptOptionParser.cpp File Reference

(v0.19-24-g0617ca1 with changes)

#include "OptionsChrono.h"
#include <limits>
#include <ratio>
#include <set>
#include <unistd.h>
Include dependency graph for shellScriptOptionParser.cpp:

Go to the source code of this file.

Classes

class  arrayOption< T >
 
class  mapOption< T >
 
class  listOption< T >
 

Enumerations

enum  typeModifierType { kSimple, kAsArray, kAsMap, kAsList }
 

Functions

template<typename T >
options::basefOptionFromStream (std::istream &aStream, T defaultValue, typeModifierType aAsWhat)
 
int main (int argc, const char *argv[])
 

Enumeration Type Documentation

◆ typeModifierType

Enumerator
kSimple 
kAsArray 
kAsMap 
kAsList 

Definition at line 76 of file shellScriptOptionParser.cpp.

76  {
77  kSimple,
78  kAsArray,
79  kAsMap,
80  kAsList
81 };

Function Documentation

◆ fOptionFromStream()

template<typename T >
options::base* fOptionFromStream ( std::istream &  aStream,
defaultValue,
typeModifierType  aAsWhat 
)

Definition at line 83 of file shellScriptOptionParser.cpp.

83  {
84  char shortName;
85  std::string longName;
86  std::string description;
87 
88  aStream >> shortName;
89  aStream >> longName;
90  aStream.ignore(std::numeric_limits<std::streamsize>::max(), ' ');
91  std::getline(aStream, description);
92 
93  if (shortName == '-') {
94  shortName = '\0';
95  }
96  switch (aAsWhat) {
97  case kSimple:
98  return new options::single<T>(shortName, longName, description, defaultValue);
99  case kAsArray:
100  return new arrayOption<T>(shortName, longName, description);
101  case kAsMap:
102  return new mapOption<T>(shortName, longName, description);
103  case kAsList:
104  return new listOption<T>(shortName, longName, description);
105  }
106  return nullptr;
107 }

References kAsArray, kAsList, kAsMap, and kSimple.

Referenced by main().

Here is the caller graph for this function:

◆ main()

int main ( int  argc,
const char *  argv[] 
)

Definition at line 110 of file shellScriptOptionParser.cpp.

110  {
111  std::string description;
112  if (isatty(0) != 1) {
113  while (std::cin.good()) {
114  std::string line;
115  if (std::cin.eof()) {
116  break;
117  }
118  std::getline(std::cin, line);
119  if (line.compare("options:") == 0) {
120  break;
121  }
122  description += line;
123  description += "\n";
124  }
125  }
126  if (description.empty() || description == "\n") {
127  std::cout << argv[0] << ": shell script option parser.\n"
128  "\treads description of options from stdandard input and writes shell\n"
129  "\tcommands that set variables to the parsed options to standard output\n"
130  "typical invocation looks like this:\n"
131  ". <(shellScriptOptionParser $\"(cd \"$(dirname \"$0\")\"; echo \"$(pwd)/$(basename \"$0\")\")\" \"$@\"<<EOF\n"
132  "description of script\n"
133  "options:\n"
134  "<options>\n"
135  "trailer:\n"
136  "trailing rest of explanation\n"
137  "EOF\n"
138  "test $? != 0 && echo exit\n"
139  ")\n"
140  "Option sytax is:\n"
141  "[export|array|map|list][positional number] type shortOpt longOpt descripton\n"
142  "\ttype may be one of 'int', 'uint', 'bool' or 'string'\n"
143  "\tfor (file)sizes the type 'size' which understands kMG.. postfixes\n"
144  "\tfor durations the type 'seconds' is provided\n"
145  "\tfor short durations the type 'milliseconds' is provided\n"
146  "\tfor very short durations the type 'microseconds' is provided\n"
147  "\tfor time stamps the type 'date' is provided with fractional seconds\n"
148  "\tfor time stamps the type 'idate' is provided with integer seconds\n"
149  "\tshortOpt is the one-letter variant, use '-' to have none\n"
150  "\tlongOpt is the long variant and the name of the shell variable\n"
151  "\tthe rest of the line is the description\n"
152  "\tif 'array' is set the option will be a shell array, which can be\n"
153  "\t expanded with \"${longOpt[@]}\" which will produce words preserving spaces\n"
154  "\tif 'map' is set the option will be a shell array, which can be\n"
155  "\t expanded with \"${longOpt[@]}\" which will produce words preserving spaces\n"
156  "\t other than the 'array' variant maps have string subscripts\n"
157  "\tif 'list' is set the option will be a list, i.e. a variable with the\n"
158  "\t values separated by spaces, i.e. values may not contain spaces\n"
159  "\tif 'export' is set the shell variable will be exported\n"
160  "\tif 'positional' is set the variable will be set as postional,\n"
161  "\t with 'number' defining the order in the positional parameter list.\n"
162  "\tif the next line starts with 'range' the values following are added\n"
163  "\tto the allowed value range of the option, many range lines may follow!\n"
164  "\tif only two are given they denote a true range in the closed interval\n"
165  "\tif the next line starts with 'default' a default value\n"
166  "\t (the rest of line) is set\n"
167  "\tThe keyword 'minusMinusSpecialTreatment' will put the parameters\n"
168  "\tfollowing '--' into the shell variable following that keyword\n"
169  "\tThe keyword 'noPath' clears the search path for config files\n"
170  "\tThe keyword 'path' adds the (escaped) rest of the line\n"
171  "\tto the search path for config files\n"
172  "\tThe keyword 'minUnusedParameters' sets the min number of params\n"
173  "\tThe keyword 'maxUnusedParameters' sets the max number of params\n";
174 
175  return (1);
176  }
177 
178  std::vector<options::base*> options;
179  std::set<const options::base*> exportedOptions;
180  std::string minusMinusSpecialTreatment = "";
181  std::vector<std::string> searchPath({"/etc/", "~/.", "~/.config/", "./."});
182 
183  unsigned int minUnusedParameters = 0;
184  unsigned int maxUnusedParameters = std::numeric_limits<unsigned int>::max();
185  {
186  options::parser throwAwayInstance("tAI1");
187  std::string keyWord;
188  bool exportNextOption = false;
189  typeModifierType nextOptionAsWhat = kSimple;
190  int nextOptionPositional = 0;
191  while (std::cin.good()) {
192  std::cin >> keyWord;
193  if (std::cin.eof()) {
194  break;
195  }
196  if (keyWord == "string") {
197  options.push_back(fOptionFromStream<std::string>(std::cin, "", nextOptionAsWhat));
198  } else if (keyWord == "int") {
199  options.push_back(fOptionFromStream<int>(std::cin, 0, nextOptionAsWhat));
200  } else if (keyWord == "uint") {
201  options.push_back(fOptionFromStream<unsigned int>(std::cin, 0, nextOptionAsWhat));
202  } else if (keyWord == "size") {
203  options.push_back(fOptionFromStream<options::postFixedNumber<size_t>>(std::cin, 0, nextOptionAsWhat));
204  } else if (keyWord == "bool") {
205  options.push_back(fOptionFromStream<bool>(std::cin, false, nextOptionAsWhat));
206  } else if (keyWord == "seconds") {
207  options.push_back(fOptionFromStream<std::chrono::duration<long long>>(std::cin, std::chrono::seconds(1), nextOptionAsWhat));
208  } else if (keyWord == "milliseconds") {
209  options.push_back(fOptionFromStream<std::chrono::duration<long long, std::milli>>(std::cin, std::chrono::seconds(1), nextOptionAsWhat));
210  } else if (keyWord == "microseconds") {
211  options.push_back(fOptionFromStream<std::chrono::duration<long long, std::micro>>(std::cin, std::chrono::seconds(1), nextOptionAsWhat));
212  } else if (keyWord == "date") {
213  options.push_back(fOptionFromStream<std::chrono::system_clock::time_point>(std::cin, std::chrono::system_clock::now(), nextOptionAsWhat));
214  } else if (keyWord == "idate") {
215  options.push_back(fOptionFromStream<std::chrono::system_clock::time_point>(std::cin, std::chrono::system_clock::now(), nextOptionAsWhat));
217  if (opt) {
218  opt->fSetValuePrinter([](std::ostream & aStream, const std::chrono::system_clock::time_point & aValue)->void {aStream << std::chrono::duration_cast<std::chrono::duration<long>>(aValue.time_since_epoch()).count();});
219  }
220  } else if (keyWord == "range") {
221  options.back()->fAddToRangeFromStream(std::cin);
222  } else if (keyWord == "default") {
223  options.back()->fAddDefaultFromStream(std::cin);
224  } else if (keyWord == "export") {
225  exportNextOption = true;
226  continue;
227  } else if (keyWord == "array") {
228  nextOptionAsWhat = kAsArray;
229  continue;
230  } else if (keyWord == "map") {
231  nextOptionAsWhat = kAsMap;
232  continue;
233  } else if (keyWord == "list") {
234  nextOptionAsWhat = kAsList;
235  continue;
236  } else if (keyWord == "positional") {
237  std::cin >> nextOptionPositional;
238  continue;
239  } else if (keyWord == "minusMinusSpecialTreatment") {
240  std::cin >> minusMinusSpecialTreatment;
241  continue;
242  } else if (keyWord == "minUnusedParameters") {
243  std::cin >> minUnusedParameters;
244  continue;
245  } else if (keyWord == "maxUnusedParameters") {
246  std::cin >> maxUnusedParameters;
247  continue;
248  } else if (keyWord == "noPath") {
249  searchPath.clear();
250  continue;
251  } else if (keyWord == "path") {
252  std::string buffer;
253  using options::escapedIO::operator>>;
254  std::cin >> buffer;
255  searchPath.push_back(buffer);
256  } else if (keyWord == "trailer:") {
257  break;
258  } else {
259  std::cerr << "illegal option type '" << keyWord << "', giving up" << std::endl;
260  return 1;
261  }
262  if (nextOptionPositional != 0) {
263  options::internal::positional_base(nextOptionPositional, options.back());
264  }
265  if (exportNextOption) {
266  exportedOptions.insert(options.back());
267  }
268  exportNextOption = false;
269  nextOptionAsWhat = kSimple;
270  nextOptionPositional = 0;
271  }
272  }
273  std::string trailer;
274  while (std::cin.good()) {
275  std::string line;
276  if (std::cin.eof()) {
277  break;
278  }
279  std::getline(std::cin, line);
280  trailer += line;
281  trailer += "\n";
282  }
283 
284  options::parser parser(description, trailer, searchPath);
285  parser.fSetMessageStream(&std::cerr);
286  parser.fSetHelpReturnValue(1);
287  parser.fSetExecutableName(argv[1]);
288  if (! minusMinusSpecialTreatment.empty()) {
289  parser.fSetMinusMinusStartsExtraList();
290  }
291 
292  auto unusedOptions = parser.fParse(argc - 1, argv + 1);
293 
294  if (unusedOptions.size() < minUnusedParameters ||
295  unusedOptions.size() > maxUnusedParameters) {
296  std::cerr << "illegal number of non-option parameters " << unusedOptions.size() << ", must be between " << minUnusedParameters << " and " << maxUnusedParameters << std::endl;
297  parser.fHelp();
298  return (1);
299  }
300 
301 
302  for (auto option : options) {
303  if (exportedOptions.find(option) != exportedOptions.end()) {
304  std::cout << "export ";
305  }
306  std::cout << option->fGetLongName() << "=";
307  option->fWriteValue(std::cout);
308  std::cout << "\n";
309  }
310  std::cout << "shift $#\n";
311  if (unusedOptions.empty() == false) {
312  std::cout << "set --";
313  for (auto & unusedOption : unusedOptions) {
314  std::cout << " " << unusedOption;
315  }
316  std::cout << "\n";
317  }
318  if (parser.fGetStuffAfterMinusMinus().empty() == false) {
319  std::cout << minusMinusSpecialTreatment << "=\"";
320  for (auto it = parser.fGetStuffAfterMinusMinus().begin(); it != parser.fGetStuffAfterMinusMinus().end(); ++it) {
321  if (it != parser.fGetStuffAfterMinusMinus().begin()) {
322  std::cout << " ";
323  }
324  std::cout << *it;
325  }
326  std::cout << "\"\n";
327  }
328 
329  return 0;
330 }

References options::parser::fGetStuffAfterMinusMinus(), options::parser::fHelp(), fOptionFromStream(), options::parser::fParse(), options::parser::fSetExecutableName(), options::parser::fSetHelpReturnValue(), options::parser::fSetMessageStream(), options::parser::fSetMinusMinusStartsExtraList(), options::valuePrinter< T >::fSetValuePrinter(), kAsArray, kAsList, kAsMap, and kSimple.

Here is the call graph for this function:
kAsMap
@ kAsMap
Definition: shellScriptOptionParser.cpp:79
options::parser
class that contains the parser, i.e. does that option handling
Definition: Options.h:363
options::single
generic option class with any type that can be used with std::istream and std::ostream
Definition: Options.h:533
typeModifierType
typeModifierType
Definition: shellScriptOptionParser.cpp:76
arrayOption
Definition: shellScriptOptionParser.cpp:24
kAsList
@ kAsList
Definition: shellScriptOptionParser.cpp:80
options
Definition: Options.h:33
options::valuePrinter::fSetValuePrinter
virtual void fSetValuePrinter(valuePrinterType aValuePrinter)
Definition: Options.h:182
options::valuePrinter< std::chrono::system_clock::time_point >
options::internal::positional_base
Definition: Options.h:345
kSimple
@ kSimple
Definition: shellScriptOptionParser.cpp:77
mapOption
Definition: shellScriptOptionParser.cpp:40
kAsArray
@ kAsArray
Definition: shellScriptOptionParser.cpp:78
listOption
Definition: shellScriptOptionParser.cpp:56
options::postFixedNumber
Definition: Options.h:104
fOptionFromStream
options::base * fOptionFromStream(std::istream &aStream, T defaultValue, typeModifierType aAsWhat)
Definition: shellScriptOptionParser.cpp:83