Panda3D
 All Classes Functions Variables Enumerations
configDeclaration.cxx
1 // Filename: configDeclaration.cxx
2 // Created by: drose (15Oct04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "configDeclaration.h"
16 #include "configVariableCore.h"
17 #include "config_prc.h"
18 #include "pstrtod.h"
19 #include "string_utils.h"
20 
21 ////////////////////////////////////////////////////////////////////
22 // Function: ConfigDeclaration::Constructor
23 // Access: Private
24 // Description: Use the ConfigPage::make_declaration() interface to
25 // create a new declaration.
26 ////////////////////////////////////////////////////////////////////
27 ConfigDeclaration::
28 ConfigDeclaration(ConfigPage *page, ConfigVariableCore *variable,
29  const string &string_value, int decl_seq) :
30  _page(page),
31  _variable(variable),
32  _string_value(string_value),
33  _decl_seq(decl_seq),
34  _got_words(false)
35 {
36  if (!_page->is_special()) {
37  _variable->add_declaration(this);
38  }
39 }
40 
41 ////////////////////////////////////////////////////////////////////
42 // Function: ConfigDeclaration::Destructor
43 // Access: Private
44 // Description: Use the ConfigPage::delete_declaration() interface to
45 // delete a declaration.
46 ////////////////////////////////////////////////////////////////////
47 ConfigDeclaration::
48 ~ConfigDeclaration() {
49  if (!_page->is_special()) {
50  _variable->remove_declaration(this);
51  }
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: ConfigDeclaration::set_string_word
56 // Access: Public
57 // Description: Changes the nth word to the indicated value without
58 // affecting the other words.
59 ////////////////////////////////////////////////////////////////////
61 set_string_word(int n, const string &value) {
62  if (!_got_words) {
63  get_words();
64  }
65 
66  while (n >= (int)_words.size()) {
67  Word w;
68  w._flags = 0;
69  _words.push_back(w);
70  }
71 
72  _words[n]._str = value;
73  _words[n]._flags = 0;
74 
75  // Now recompose the overall string value.
76  Words::const_iterator wi = _words.begin();
77  _string_value = (*wi)._str;
78  ++wi;
79 
80  while (wi != _words.end()) {
81  _string_value += " ";
82  _string_value += (*wi)._str;
83  ++wi;
84  }
85  invalidate_cache();
86 }
87 
88 ////////////////////////////////////////////////////////////////////
89 // Function: ConfigDeclaration::set_bool_word
90 // Access: Public
91 // Description: Changes the nth word to the indicated value without
92 // affecting the other words.
93 ////////////////////////////////////////////////////////////////////
95 set_bool_word(int n, bool value) {
96  set_string_word(n, value ? "1" : "0");
97 
98  _words[n]._flags |= (F_checked_bool | F_valid_bool);
99  _words[n]._bool = value;
100  invalidate_cache();
101 }
102 
103 ////////////////////////////////////////////////////////////////////
104 // Function: ConfigDeclaration::set_int_word
105 // Access: Public
106 // Description: Changes the nth word to the indicated value without
107 // affecting the other words.
108 ////////////////////////////////////////////////////////////////////
110 set_int_word(int n, int value) {
111  set_string_word(n, format_string(value));
112 
113  _words[n]._flags |= (F_checked_int | F_valid_int);
114  _words[n]._int = value;
115  invalidate_cache();
116 }
117 
118 ////////////////////////////////////////////////////////////////////
119 // Function: ConfigDeclaration::set_int64_word
120 // Access: Public
121 // Description: Changes the nth word to the indicated value without
122 // affecting the other words.
123 ////////////////////////////////////////////////////////////////////
125 set_int64_word(int n, PN_int64 value) {
126  set_string_word(n, format_string(value));
127 
128  _words[n]._flags |= (F_checked_int64 | F_valid_int64);
129  _words[n]._int_64 = value;
130  invalidate_cache();
131 }
132 
133 ////////////////////////////////////////////////////////////////////
134 // Function: ConfigDeclaration::set_double_word
135 // Access: Public
136 // Description: Changes the nth word to the indicated value without
137 // affecting the other words.
138 ////////////////////////////////////////////////////////////////////
140 set_double_word(int n, double value) {
141  set_string_word(n, format_string(value));
142 
143  _words[n]._flags |= (F_checked_double | F_valid_double);
144  _words[n]._double = value;
145  invalidate_cache();
146 }
147 
148 ////////////////////////////////////////////////////////////////////
149 // Function: ConfigDeclaration::output
150 // Access: Public
151 // Description:
152 ////////////////////////////////////////////////////////////////////
153 void ConfigDeclaration::
154 output(ostream &out) const {
155  out << get_variable()->get_name() << " " << get_string_value();
156 }
157 
158 ////////////////////////////////////////////////////////////////////
159 // Function: ConfigDeclaration::write
160 // Access: Public
161 // Description:
162 ////////////////////////////////////////////////////////////////////
163 void ConfigDeclaration::
164 write(ostream &out) const {
165  out << get_variable()->get_name() << " " << get_string_value();
166  //if (!get_variable()->is_used()) {
167  // out << " (not used)";
168  //}
169  out << "\n";
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: ConfigDeclaration::get_words
174 // Access: Private
175 // Description: Separates the string value into words.
176 ////////////////////////////////////////////////////////////////////
177 void ConfigDeclaration::
178 get_words() {
179  if (!_got_words) {
180  _words.clear();
181  vector_string words;
182  extract_words(_string_value, words);
183  _words.reserve(words.size());
184 
185  for (vector_string::const_iterator wi = words.begin();
186  wi != words.end();
187  ++wi) {
188  Word w;
189  w._str = (*wi);
190  w._flags = 0;
191  _words.push_back(w);
192  }
193 
194  _got_words = true;
195  }
196 }
197 
198 ////////////////////////////////////////////////////////////////////
199 // Function: ConfigDeclaration::check_bool_word
200 // Access: Private
201 // Description: Checks whether the nth word can be interpreted as a
202 // boolean value.
203 ////////////////////////////////////////////////////////////////////
204 void ConfigDeclaration::
205 check_bool_word(int n) {
206  if (!_got_words) {
207  get_words();
208  }
209 
210  if (n >= 0 && n < (int)_words.size()) {
211  Word &word = _words[n];
212  if ((word._flags & F_checked_bool) == 0) {
213  word._flags |= F_checked_bool;
214 
215  string s = downcase(word._str);
216  if (s.empty()) {
217  word._bool = false;
218 
219  } else if (s == "#t" || s == "1" || s[0] == 't') {
220  word._bool = true;
221 
222  } else if (s == "#f" || s == "0" || s[0] == 'f') {
223  word._bool = false;
224 
225  } else {
226  // Not a recognized bool value.
227  check_double_word(n);
228  if ((word._flags & F_checked_double) != 0) {
229  word._bool = (word._double != 0.0);
230  } else {
231  word._bool = false;
232  }
233 
234  prc_cat->warning()
235  << "Invalid bool value for ConfigVariable "
236  << get_variable()->get_name() << ": " << word._str << "\n";
237  return;
238  }
239 
240  word._flags |= F_valid_bool;
241  }
242  }
243 }
244 
245 ////////////////////////////////////////////////////////////////////
246 // Function: ConfigDeclaration::check_int_word
247 // Access: Private
248 // Description: Checks whether the nth word can be interpreted as an
249 // integer value.
250 ////////////////////////////////////////////////////////////////////
251 void ConfigDeclaration::
252 check_int_word(int n) {
253  if (!_got_words) {
254  get_words();
255  }
256 
257  if (n >= 0 && n < (int)_words.size()) {
258  Word &word = _words[n];
259  if ((word._flags & F_checked_int) == 0) {
260  word._flags |= F_checked_int;
261 
262  // We scan the word by hand, rather than relying on strtol(), so
263  // we can check for overflow of the 32-bit value.
264  word._int = 0;
265  bool overflow = false;
266 
267  string::const_iterator pi = word._str.begin();
268  if (pi != word._str.end() && (*pi) == '-') {
269  ++pi;
270  // Negative number.
271  while (pi != word._str.end() && isdigit(*pi)) {
272  int next = word._int * 10 - (int)((*pi) - '0');
273  if ((int)(next / 10) != word._int) {
274  // Overflow.
275  overflow = true;
276  }
277  word._int = next;
278  ++pi;
279  }
280 
281  } else {
282  // Positive number.
283  while (pi != word._str.end() && isdigit(*pi)) {
284  int next = word._int * 10 + (int)((*pi) - '0');
285  if ((int)(next / 10) != word._int) {
286  // Overflow.
287  overflow = true;
288  }
289  word._int = next;
290  ++pi;
291  }
292  }
293 
294  if (pi == word._str.end() && !overflow) {
295  word._flags |= F_valid_int;
296  } else {
297  prc_cat->warning()
298  << "Invalid integer value for ConfigVariable "
299  << get_variable()->get_name() << ": " << word._str << "\n";
300  }
301  }
302  }
303 }
304 
305 ////////////////////////////////////////////////////////////////////
306 // Function: ConfigDeclaration::check_int64_word
307 // Access: Private
308 // Description: Checks whether the nth word can be interpreted as an
309 // integer value.
310 ////////////////////////////////////////////////////////////////////
311 void ConfigDeclaration::
312 check_int64_word(int n) {
313  if (!_got_words) {
314  get_words();
315  }
316 
317  if (n >= 0 && n < (int)_words.size()) {
318  Word &word = _words[n];
319  if ((word._flags & F_checked_int64) == 0) {
320  word._flags |= F_checked_int64;
321 
322  word._int_64 = 0;
323  bool overflow = false;
324 
325  string::const_iterator pi = word._str.begin();
326  if (pi != word._str.end() && (*pi) == '-') {
327  ++pi;
328  // Negative number.
329  while (pi != word._str.end() && isdigit(*pi)) {
330  PN_int64 next = word._int_64 * 10 - (int)((*pi) - '0');
331  if ((PN_int64)(next / 10) != word._int_64) {
332  // Overflow.
333  overflow = true;
334  }
335  word._int_64 = next;
336  ++pi;
337  }
338 
339  } else {
340  // Positive number.
341  while (pi != word._str.end() && isdigit(*pi)) {
342  PN_int64 next = word._int_64 * 10 + (int)((*pi) - '0');
343  if ((PN_int64)(next / 10) != word._int_64) {
344  // Overflow.
345  overflow = true;
346  }
347  word._int_64 = next;
348  ++pi;
349  }
350  }
351 
352  if (pi == word._str.end() && !overflow) {
353  word._flags |= F_valid_int64;
354  } else {
355  prc_cat->warning()
356  << "Invalid int64 value for ConfigVariable "
357  << get_variable()->get_name() << ": " << word._str << "\n";
358  }
359  }
360  }
361 }
362 
363 ////////////////////////////////////////////////////////////////////
364 // Function: ConfigDeclaration::check_double_word
365 // Access: Private
366 // Description: Checks whether the nth word can be interpreted as a
367 // floating-point value.
368 ////////////////////////////////////////////////////////////////////
369 void ConfigDeclaration::
370 check_double_word(int n) {
371  if (!_got_words) {
372  get_words();
373  }
374 
375  if (n >= 0 && n < (int)_words.size()) {
376  Word &word = _words[n];
377  if ((word._flags & F_checked_double) == 0) {
378  word._flags |= F_checked_double;
379 
380  const char *nptr = word._str.c_str();
381  char *endptr;
382  word._double = pstrtod(nptr, &endptr);
383 
384  if (*endptr == '\0') {
385  word._flags |= F_valid_double;
386  } else {
387  prc_cat->warning()
388  << "Invalid floating-point value for ConfigVariable "
389  << get_variable()->get_name() << ": " << word._str << "\n";
390  }
391  }
392  }
393 }
394 
395 ////////////////////////////////////////////////////////////////////
396 // Function: ConfigDeclaration::extract_words
397 // Access: Public, Static
398 // Description: Divides the string into a number of words according
399 // to whitespace. The words vector should be cleared by
400 // the user before calling; otherwise, the list of words
401 // in the string will be appended to the end of whatever
402 // was there before.
403 //
404 // The return value is the number of words extracted.
405 ////////////////////////////////////////////////////////////////////
407 extract_words(const string &str, vector_string &words) {
408  int num_words = 0;
409 
410  size_t pos = 0;
411  while (pos < str.length() && isspace((unsigned int)str[pos])) {
412  pos++;
413  }
414  while (pos < str.length()) {
415  size_t word_start = pos;
416  while (pos < str.length() && !isspace((unsigned int)str[pos])) {
417  pos++;
418  }
419  words.push_back(str.substr(word_start, pos - word_start));
420  num_words++;
421 
422  while (pos < str.length() && isspace((unsigned int)str[pos])) {
423  pos++;
424  }
425  }
426 
427  return num_words;
428 }
429 
430 ////////////////////////////////////////////////////////////////////
431 // Function: ConfigDeclaration::downcase
432 // Access: Public, Static
433 // Description: Returns the input string with all uppercase letters
434 // converted to lowercase.
435 ////////////////////////////////////////////////////////////////////
436 string ConfigDeclaration::
437 downcase(const string &s) {
438  string result;
439  result.reserve(s.size());
440  string::const_iterator p;
441  for (p = s.begin(); p != s.end(); ++p) {
442  result += tolower(*p);
443  }
444  return result;
445 }
The internal definition of a ConfigVariable.
const string & get_name() const
Returns the name of the variable.
const string & get_string_value() const
Returns the value assigned to this variable.
void set_int64_word(int n, PN_int64 value)
Changes the nth word to the indicated value without affecting the other words.
bool is_special() const
Returns true if this is the special &quot;default&quot; or &quot;local&quot; page, or false if it is an ordinary page...
Definition: configPage.I:58
static int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
void set_bool_word(int n, bool value)
Changes the nth word to the indicated value without affecting the other words.
void set_int_word(int n, int value)
Changes the nth word to the indicated value without affecting the other words.
A page of ConfigDeclarations that may be loaded or unloaded.
Definition: configPage.h:33
ConfigVariableCore * get_variable() const
Returns the variable that this declaration names.
static string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
void set_string_word(int n, const string &value)
Changes the nth word to the indicated value without affecting the other words.
void set_double_word(int n, double value)
Changes the nth word to the indicated value without affecting the other words.