ROSE  0.11.83.1
IntervalParser.h
1 #ifndef ROSE_CommandLine_IntervalParser_H
2 #define ROSE_CommandLine_IntervalParser_H
3 
4 #include <Rose/StringUtility/Escape.h>
5 #include <Rose/StringUtility/NumberToString.h>
6 
7 #include <boost/lexical_cast.hpp>
8 #include <boost/numeric/conversion/cast.hpp>
9 #include <cstring>
10 #include <ctype.h>
11 #include <errno.h>
12 #include <rose_strtoull.h>
13 #include <Sawyer/CommandLine.h>
14 #include <Sawyer/Interval.h>
15 #include <Sawyer/IntervalSet.h>
16 #include <string>
17 
18 namespace Rose {
19 namespace CommandLine {
20 
31 template<class Interval>
33 protected:
34  IntervalParser() {}
35 
37  : Sawyer::CommandLine::ValueParser(valueSaver) {}
38 
39 public:
44 
46  static Ptr instance() {
47  return Ptr(new IntervalParser);
48  }
49 
52  return Ptr(new IntervalParser(valueSaver));
53  }
54 
56  static std::string docString(const std::string &interval = "interval", const std::string &value = "value") {
57  return ("The " + interval + " can be specified in a number of forms:"
58  " a single " + value + " represents a singleton " + interval + ";"
59  " a first and inclusive last " + value + " separated by a comma;"
60  " a begin and exclusive end " + value + " separated by a hyphen;"
61  " a begin " + value + " and count separated by a plus sign;"
62  " the word \"all\" represents the universal " + interval + ";"
63  " and the word \"empty\" or an empty string represents the empty " + interval + "."
64 
65  " When the " + interval + " is specified as a range, the first " + value + " must be less than or equal to"
66  " the second value. A " + value + " can be specified in decimal, hexadecimal (leading \"0x\"),"
67  " octal (leading \"0\"), or binary (leading \"0b\"). The upper " + value + " can be the word \"max\" when"
68  " appearing after a comma.");
69  }
70 
75  static Interval parse(const char *input, const char **rest) {
76  const char *s = input;
77  char *r = nullptr;
78  bool hadRangeError = false, isEmpty = false;
79  while (isspace(*s)) ++s;
80 
81  if (!strcmp(s, "all")) {
82  *rest = s + 3;
83  return Interval::whole();
84  }
85 
86  if (!strcmp(s, "empty")) {
87  *rest += 5;
88  return Interval();
89  }
90 
91  // Minimum
92  errno = 0;
93  uint64_t least64 = rose_strtoull(s, &r, 0);
94  if (r == s)
95  throw std::runtime_error("unsigned integer expected for interval minimum");
96  if (ERANGE == errno)
97  hadRangeError = true;
98  typename Interval::Value least{};
99  try {
100  least = boost::numeric_cast<typename Interval::Value>(least64);
101  } catch (const boost::bad_numeric_cast&) {
102  hadRangeError = true;
103  }
104  s = r;
105 
106  // Maximum, end, size, or nothing
107  typename Interval::Value greatest = least;
108  while (isspace(*s)) ++s;
109  if (',' == *s) { // ',' means a max value is specified
110  ++s;
111  if (0 == strncmp(s, "max", 3)) {
112  greatest = Interval::whole().greatest();
113  s += 3;
114  r = const_cast<char*>(s);
115  } else {
116  errno = 0;
117  uint64_t greatest64 = rose_strtoull(s, &r, 0);
118  if (r == s)
119  throw std::runtime_error("unsigned integer expected for interval maximum");
120  if (ERANGE == errno)
121  hadRangeError = true;
122  try {
123  greatest = boost::numeric_cast<typename Interval::Value>(greatest64);
124  } catch (const boost::bad_numeric_cast&) {
125  hadRangeError = true;
126  }
127  s = r;
128  }
129  } else if ('-' == *s) { // '-' means an exclusive end address is specified (think "-" 1)
130  ++s;
131  errno = 0;
132  uint64_t greatest64 = rose_strtoull(s, &r, 0);
133  if (r == s)
134  throw std::runtime_error("unsigned integer expected for interval end");
135  if (ERANGE == errno)
136  hadRangeError = true;
137  try {
138  greatest = boost::numeric_cast<typename Interval::Value>(greatest64);
139  } catch (const boost::bad_numeric_cast&) {
140  hadRangeError = true;
141  }
142  if (greatest == least)
143  isEmpty = true;
144  --greatest;
145  s = r;
146  } else if ('+' == *s) { // '+' means a size follows (zero is allowed)
147  ++s;
148  errno = 0;
149  uint64_t size64 = rose_strtoull(s, &r, 0);
150  if (r == s)
151  throw std::runtime_error("unsigned integer expected for interval size");
152  if (ERANGE == errno)
153  hadRangeError = true;
154  typename Interval::Value size{};
155  try {
156  size = boost::numeric_cast<typename Interval::Value>(size64);
157  } catch (const boost::bad_numeric_cast&) {
158  hadRangeError = true;
159  }
160  if (0 == size)
161  isEmpty = true;
162  greatest = least + size - 1;
163  s = r;
164  } else if (!*s) { // end-of-string means the interval is a singleton
165  /*void*/
166  }
167 
168  // Successful parsing?
169  *rest = r;
170  std::string parsed(input, *rest - input);
171  if (hadRangeError)
172  throw std::range_error("overflow when parsing \"" + parsed + "\"");
173  if (greatest < least)
174  throw std::range_error("interval seems backward: \"" + parsed + "\"");
175 
176  if (!isEmpty) {
177  return Interval::hull(least, greatest);
178  } else {
179  return Interval();
180  }
181  }
182 
188  static Interval parse(const std::string &input) {
189  const char *s = input.c_str();
190  const char *rest = nullptr;
191  Interval retval = parse(s, &rest);
192  while (isspace(*rest)) ++rest;
193  if (*rest)
194  throw std::runtime_error("extra text after end of interval specification: \"" + StringUtility::cEscape(rest) + "\"");
195  return retval;
196  }
197 
199  static std::string toString(const Interval &interval) {
200  if (interval.isEmpty()) {
201  return "empty";
202  } else if (interval == Interval::whole()) {
203  return "all";
204  } else if (interval.least() == interval.greatest()) {
205  if (interval.least() < 256) {
206  return boost::lexical_cast<std::string>(interval.least());
207  } else {
208  return StringUtility::addrToString(interval.least());
209  }
210  } else {
211  if (interval.greatest() < 256) {
212  return boost::lexical_cast<std::string>(interval.least()) + "," +
213  boost::lexical_cast<std::string>(interval.greatest());
214  } else {
215  return StringUtility::addrToString(interval.least()) + "," +
216  StringUtility::addrToString(interval.greatest());
217  }
218  }
219  }
220 
221 private:
222  virtual Sawyer::CommandLine::ParsedValue operator()(const char *input, const char **rest,
223  const Sawyer::CommandLine::Location &loc) override {
224  Interval val = parse(input, rest);
225  std::string parsed(input, *rest - input);
226  return Sawyer::CommandLine::ParsedValue(val, loc, parsed, valueSaver());
227  }
228 };
229 
230 template<class Interval>
231 typename IntervalParser<Interval>::Ptr intervalParser(Interval &storage) {
233 }
234 
235 template<class Interval>
236 typename IntervalParser<Interval>::Ptr intervalParser(std::vector<Interval> &storage) {
237  return IntervalParser<Interval>::instance(Sawyer::CommandLine::TypedSaver<std::vector<Interval>>::instance(storage));
238 }
239 
240 template<class Interval>
241 typename IntervalParser<Interval>::Ptr intervalParser(Sawyer::Container::IntervalSet<Interval> &storage) {
242  return IntervalParser<Interval>
244 }
245 
246 template<class Interval>
247 typename IntervalParser<Interval>::Ptr intervalParser() {
249 }
250 
251 } // namespace
252 } // namespace
253 
254 #endif
const ValueSaver::Ptr valueSaver() const
Property: functor responsible for saving a parsed value in user storage.
static std::string toString(const Interval &interval)
Unparse an interval to a string.
Main namespace for the ROSE library.
ROSE_UTIL_API std::string cEscape(const std::string &, char context= '"')
Escapes characters that are special to C/C++.
static Ptr instance()
Default allocating constructor.
static Ptr instance(const Sawyer::CommandLine::ValueSaver::Ptr &valueSaver)
Allocating constructor.
Information about a parsed switch value.
static Interval parse(const std::string &input)
Parse an interval from a C++ string.
ROSE_UTIL_API std::string addrToString(uint64_t value, size_t nbits=0)
Convert a virtual address to a string.
static std::string docString(const std::string &interval="interval", const std::string &value="value")
Runtime documentation.
static Interval parse(const char *input, const char **rest)
Parse an interval from a C string.
Position within a command-line.
Base class parsing a value from input.
Sawyer::SharedPointer< IntervalParser > Ptr
Shared-ownership pointer to an IntervalParser.