Panda3D
rangeDescription.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file rangeDescription.cxx
10  * @author drose
11  * @date 2003-09-07
12  */
13 
14 #include "rangeDescription.h"
15 #include "string_utils.h"
16 #include "pnotify.h"
17 
18 using std::string;
19 
20 /**
21  *
22  */
23 RangeDescription::
24 RangeDescription() {
25 }
26 
27 /**
28  * Parses a string of comma- and hyphen-delimited unicode values, in decimal
29  * and/or hex, including possible bracket-delimited ASCII characters, as may
30  * have been passed on a command line. Returns true if the parameter is
31  * parsed correctly, false otherwise.
32  */
34 parse_parameter(const string &param) {
35  // First, go through and separate the string by commas. We have to do this
36  // by hand instead of calling tokenize(), because we also have to scan for
37  // square brackets, which may contain nested commas.
38  size_t p = 0;
39  while (p < param.length()) {
40  size_t q = param.find_first_of("[,", p);
41  if (q == string::npos) {
42  return parse_word(trim(param.substr(p)));
43  }
44  if (!parse_word(trim(param.substr(p, q - p)))) {
45  return false;
46  }
47 
48  if (param[q] == '[') {
49  // A square bracket means we must search for the matching square
50  // bracket. However, a right bracket immediately after the left bracket
51  // doesn't count; we start the scan after that.
52  p = param.find("]", q + 2);
53  if ( p == string::npos) {
54  nout << "Unclosed open bracket.\n";
55  return false;
56  }
57  if (!parse_bracket(param.substr(q + 1, p - q - 1))) {
58  return false;
59  }
60  p = p + 1;
61 
62  } else {
63  // Otherwise, if the separator was just a comma, the next character
64  // begins the next word.
65  p = q + 1;
66  }
67  }
68 
69  return true;
70 }
71 
72 /**
73  *
74  */
75 void RangeDescription::
76 output(std::ostream &out) const {
77  bool first_time = true;
78  RangeList::const_iterator ri;
79  for (ri = _range_list.begin(); ri != _range_list.end(); ++ri) {
80  const Range &range = (*ri);
81  if (!first_time) {
82  out << ",";
83  }
84  first_time = false;
85  if (range._from_code == range._to_code) {
86  out << range._from_code;
87  } else {
88  out << range._from_code << "-" << range._to_code;
89  }
90  }
91 }
92 
93 /**
94  * Parses a single "word", i.e. the text delimited by commas, that might be
95  * listed on the command line. This is generally either the empty string, a
96  * single number, or a pair of numbers separated by a hyphen.
97  */
98 bool RangeDescription::
99 parse_word(const string &word) {
100  if (word.empty()) {
101  return true;
102  }
103 
104  // It's not empty, so see if it includes a hyphen.
105  size_t hyphen = word.find('-');
106  if (hyphen == string::npos) {
107  // Nope, just one number.
108  int code;
109  if (!parse_code(word, code)) {
110  return false;
111  }
112  add_singleton(code);
113 
114  } else {
115  // Two numbers separated by a hyphen.
116  int from_code, to_code;
117  if (!parse_code(word.substr(0, hyphen), from_code)) {
118  return false;
119  }
120  if (!parse_code(word.substr(hyphen + 1), to_code)) {
121  return false;
122  }
123  add_range(from_code, to_code);
124  }
125 
126  return true;
127 }
128 
129 /**
130  * Parses a single numeric value, either decimal or hexadecimal, and stores it
131  * in the indicated parameter. Returns true if successful, false otherwise.
132  */
133 bool RangeDescription::
134 parse_code(const string &word, int &code) {
135  string str = trim(word);
136  const char *nptr = str.c_str();
137  char *endptr;
138  code = strtol(nptr, &endptr, 0);
139  if (*endptr == '\0') {
140  return true;
141  }
142 
143  nout << "Invalid Unicode value: " << word << "\n";
144  return false;
145 }
146 
147 /**
148  * Parses the text listed between square brackets on the command line.
149  */
150 bool RangeDescription::
151 parse_bracket(const string &str) {
152  string::const_iterator si;
153  si = str.begin();
154  while (si != str.end()) {
155  int ch = (*si);
156  ++si;
157  if (si != str.end() && (*si) == '-') {
158  // A hyphen indicates a range.
159  ++si;
160  if (si == str.end()) {
161  // Unless the hyphen is the last character.
162  add_singleton(ch);
163  add_singleton('-');
164  } else {
165  add_range(ch, (*si));
166  ++si;
167  }
168  } else {
169  // Anything other than a hyphen indicates a singleton.
170  add_singleton(ch);
171  }
172  }
173 
174  return true;
175 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool parse_parameter(const std::string &param)
Parses a string of comma- and hyphen-delimited unicode values, in decimal and/or hex,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string trim(const string &str)
Returns a new string representing the contents of the given string with both leading and trailing whi...