Panda3D
|
00001 // Filename: configDeclaration.cxx 00002 // Created by: drose (15Oct04) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "configDeclaration.h" 00016 #include "configVariableCore.h" 00017 #include "pstrtod.h" 00018 00019 00020 //////////////////////////////////////////////////////////////////// 00021 // Function: ConfigDeclaration::Constructor 00022 // Access: Private 00023 // Description: Use the ConfigPage::make_declaration() interface to 00024 // create a new declaration. 00025 //////////////////////////////////////////////////////////////////// 00026 ConfigDeclaration:: 00027 ConfigDeclaration(ConfigPage *page, ConfigVariableCore *variable, 00028 const string &string_value, int decl_seq) : 00029 _page(page), 00030 _variable(variable), 00031 _string_value(string_value), 00032 _decl_seq(decl_seq), 00033 _got_words(false) 00034 { 00035 if (!_page->is_special()) { 00036 _variable->add_declaration(this); 00037 } 00038 } 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: ConfigDeclaration::Destructor 00042 // Access: Private 00043 // Description: Use the ConfigPage::delete_declaration() interface to 00044 // delete a declaration. 00045 //////////////////////////////////////////////////////////////////// 00046 ConfigDeclaration:: 00047 ~ConfigDeclaration() { 00048 if (!_page->is_special()) { 00049 _variable->remove_declaration(this); 00050 } 00051 } 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: ConfigDeclaration::set_string_word 00055 // Access: Public 00056 // Description: Changes the nth word to the indicated value without 00057 // affecting the other words. 00058 //////////////////////////////////////////////////////////////////// 00059 void ConfigDeclaration:: 00060 set_string_word(int n, const string &value) { 00061 if (!_got_words) { 00062 get_words(); 00063 } 00064 00065 while (n >= (int)_words.size()) { 00066 Word w; 00067 w._flags = 0; 00068 _words.push_back(w); 00069 } 00070 00071 _words[n]._str = value; 00072 _words[n]._flags = 0; 00073 00074 // Now recompose the overall string value. 00075 Words::const_iterator wi = _words.begin(); 00076 _string_value = (*wi)._str; 00077 ++wi; 00078 00079 while (wi != _words.end()) { 00080 _string_value += " "; 00081 _string_value += (*wi)._str; 00082 ++wi; 00083 } 00084 invalidate_cache(); 00085 } 00086 00087 //////////////////////////////////////////////////////////////////// 00088 // Function: ConfigDeclaration::set_bool_word 00089 // Access: Public 00090 // Description: Changes the nth word to the indicated value without 00091 // affecting the other words. 00092 //////////////////////////////////////////////////////////////////// 00093 void ConfigDeclaration:: 00094 set_bool_word(int n, bool value) { 00095 if (value) { 00096 set_string_word(n, "1"); 00097 } else { 00098 set_string_word(n, "0"); 00099 } 00100 00101 _words[n]._flags |= (F_checked_bool | F_valid_bool); 00102 _words[n]._bool = value; 00103 invalidate_cache(); 00104 } 00105 00106 //////////////////////////////////////////////////////////////////// 00107 // Function: ConfigDeclaration::set_int_word 00108 // Access: Public 00109 // Description: Changes the nth word to the indicated value without 00110 // affecting the other words. 00111 //////////////////////////////////////////////////////////////////// 00112 void ConfigDeclaration:: 00113 set_int_word(int n, int value) { 00114 ostringstream strm; 00115 strm << value; 00116 set_string_word(n, strm.str()); 00117 00118 _words[n]._flags |= (F_checked_int | F_valid_int); 00119 _words[n]._int = value; 00120 invalidate_cache(); 00121 } 00122 00123 //////////////////////////////////////////////////////////////////// 00124 // Function: ConfigDeclaration::set_int64_word 00125 // Access: Public 00126 // Description: Changes the nth word to the indicated value without 00127 // affecting the other words. 00128 //////////////////////////////////////////////////////////////////// 00129 void ConfigDeclaration:: 00130 set_int64_word(int n, PN_int64 value) { 00131 ostringstream strm; 00132 strm << value; 00133 set_string_word(n, strm.str()); 00134 00135 _words[n]._flags |= (F_checked_int64 | F_valid_int64); 00136 _words[n]._int_64 = value; 00137 invalidate_cache(); 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: ConfigDeclaration::set_double_word 00142 // Access: Public 00143 // Description: Changes the nth word to the indicated value without 00144 // affecting the other words. 00145 //////////////////////////////////////////////////////////////////// 00146 void ConfigDeclaration:: 00147 set_double_word(int n, double value) { 00148 ostringstream strm; 00149 strm << value; 00150 set_string_word(n, strm.str()); 00151 00152 _words[n]._flags |= (F_checked_double | F_valid_double); 00153 _words[n]._double = value; 00154 invalidate_cache(); 00155 } 00156 00157 //////////////////////////////////////////////////////////////////// 00158 // Function: ConfigDeclaration::output 00159 // Access: Public 00160 // Description: 00161 //////////////////////////////////////////////////////////////////// 00162 void ConfigDeclaration:: 00163 output(ostream &out) const { 00164 out << get_variable()->get_name() << " " << get_string_value(); 00165 } 00166 00167 //////////////////////////////////////////////////////////////////// 00168 // Function: ConfigDeclaration::write 00169 // Access: Public 00170 // Description: 00171 //////////////////////////////////////////////////////////////////// 00172 void ConfigDeclaration:: 00173 write(ostream &out) const { 00174 out << get_variable()->get_name() << " " << get_string_value(); 00175 if (!get_variable()->is_used()) { 00176 out << " (not used)"; 00177 } 00178 out << "\n"; 00179 } 00180 00181 //////////////////////////////////////////////////////////////////// 00182 // Function: ConfigDeclaration::get_words 00183 // Access: Private 00184 // Description: Separates the string value into words. 00185 //////////////////////////////////////////////////////////////////// 00186 void ConfigDeclaration:: 00187 get_words() { 00188 if (!_got_words) { 00189 _words.clear(); 00190 vector_string words; 00191 extract_words(_string_value, words); 00192 _words.reserve(words.size()); 00193 00194 for (vector_string::const_iterator wi = words.begin(); 00195 wi != words.end(); 00196 ++wi) { 00197 Word w; 00198 w._str = (*wi); 00199 w._flags = 0; 00200 _words.push_back(w); 00201 } 00202 00203 _got_words = true; 00204 } 00205 } 00206 00207 //////////////////////////////////////////////////////////////////// 00208 // Function: ConfigDeclaration::check_bool_word 00209 // Access: Private 00210 // Description: Checks whether the nth word can be interpreted as a 00211 // boolean value. 00212 //////////////////////////////////////////////////////////////////// 00213 void ConfigDeclaration:: 00214 check_bool_word(int n) { 00215 if (!_got_words) { 00216 get_words(); 00217 } 00218 00219 if (n >= 0 && n < (int)_words.size()) { 00220 Word &word = _words[n]; 00221 if ((word._flags & F_checked_bool) == 0) { 00222 word._flags |= F_checked_bool; 00223 00224 string s = downcase(word._str); 00225 if (s.empty()) { 00226 word._bool = false; 00227 00228 } else if (s == "#t" || s == "1" || s[0] == 't') { 00229 word._bool = true; 00230 00231 } else if (s == "#f" || s == "0" || s[0] == 'f') { 00232 word._bool = false; 00233 00234 } else { 00235 // Not a recognized bool value. 00236 check_double_word(n); 00237 if ((word._flags & F_checked_double) != 0) { 00238 word._bool = (word._double != 0.0); 00239 } else { 00240 word._bool = false; 00241 } 00242 00243 prc_cat->warning() 00244 << "Invalid bool value for ConfigVariable " 00245 << get_variable()->get_name() << ": " << word._str << "\n"; 00246 return; 00247 } 00248 00249 word._flags |= F_valid_bool; 00250 } 00251 } 00252 } 00253 00254 //////////////////////////////////////////////////////////////////// 00255 // Function: ConfigDeclaration::check_int_word 00256 // Access: Private 00257 // Description: Checks whether the nth word can be interpreted as an 00258 // integer value. 00259 //////////////////////////////////////////////////////////////////// 00260 void ConfigDeclaration:: 00261 check_int_word(int n) { 00262 if (!_got_words) { 00263 get_words(); 00264 } 00265 00266 if (n >= 0 && n < (int)_words.size()) { 00267 Word &word = _words[n]; 00268 if ((word._flags & F_checked_int) == 0) { 00269 word._flags |= F_checked_int; 00270 00271 // We scan the word by hand, rather than relying on strtol(), so 00272 // we can check for overflow of the 32-bit value. 00273 word._int = 0; 00274 bool overflow = false; 00275 00276 string::const_iterator pi = word._str.begin(); 00277 if (pi != word._str.end() && (*pi) == '-') { 00278 ++pi; 00279 // Negative number. 00280 while (pi != word._str.end() && isdigit(*pi)) { 00281 int next = word._int * 10 - (int)((*pi) - '0'); 00282 if ((int)(next / 10) != word._int) { 00283 // Overflow. 00284 overflow = true; 00285 } 00286 word._int = next; 00287 ++pi; 00288 } 00289 00290 } else { 00291 // Positive number. 00292 while (pi != word._str.end() && isdigit(*pi)) { 00293 int next = word._int * 10 + (int)((*pi) - '0'); 00294 if ((int)(next / 10) != word._int) { 00295 // Overflow. 00296 overflow = true; 00297 } 00298 word._int = next; 00299 ++pi; 00300 } 00301 } 00302 00303 if (pi == word._str.end() && !overflow) { 00304 word._flags |= F_valid_int; 00305 } else { 00306 prc_cat->warning() 00307 << "Invalid integer value for ConfigVariable " 00308 << get_variable()->get_name() << ": " << word._str << "\n"; 00309 } 00310 } 00311 } 00312 } 00313 00314 //////////////////////////////////////////////////////////////////// 00315 // Function: ConfigDeclaration::check_int64_word 00316 // Access: Private 00317 // Description: Checks whether the nth word can be interpreted as an 00318 // integer value. 00319 //////////////////////////////////////////////////////////////////// 00320 void ConfigDeclaration:: 00321 check_int64_word(int n) { 00322 if (!_got_words) { 00323 get_words(); 00324 } 00325 00326 if (n >= 0 && n < (int)_words.size()) { 00327 Word &word = _words[n]; 00328 if ((word._flags & F_checked_int64) == 0) { 00329 word._flags |= F_checked_int64; 00330 00331 word._int_64 = 0; 00332 bool overflow = false; 00333 00334 string::const_iterator pi = word._str.begin(); 00335 if (pi != word._str.end() && (*pi) == '-') { 00336 ++pi; 00337 // Negative number. 00338 while (pi != word._str.end() && isdigit(*pi)) { 00339 PN_int64 next = word._int_64 * 10 - (int)((*pi) - '0'); 00340 if ((PN_int64)(next / 10) != word._int_64) { 00341 // Overflow. 00342 overflow = true; 00343 } 00344 word._int_64 = next; 00345 ++pi; 00346 } 00347 00348 } else { 00349 // Positive number. 00350 while (pi != word._str.end() && isdigit(*pi)) { 00351 PN_int64 next = word._int_64 * 10 + (int)((*pi) - '0'); 00352 if ((PN_int64)(next / 10) != word._int_64) { 00353 // Overflow. 00354 overflow = true; 00355 } 00356 word._int_64 = next; 00357 ++pi; 00358 } 00359 } 00360 00361 if (pi == word._str.end() && !overflow) { 00362 word._flags |= F_valid_int64; 00363 } else { 00364 prc_cat->warning() 00365 << "Invalid int64 value for ConfigVariable " 00366 << get_variable()->get_name() << ": " << word._str << "\n"; 00367 } 00368 } 00369 } 00370 } 00371 00372 //////////////////////////////////////////////////////////////////// 00373 // Function: ConfigDeclaration::check_double_word 00374 // Access: Private 00375 // Description: Checks whether the nth word can be interpreted as a 00376 // floating-point value. 00377 //////////////////////////////////////////////////////////////////// 00378 void ConfigDeclaration:: 00379 check_double_word(int n) { 00380 if (!_got_words) { 00381 get_words(); 00382 } 00383 00384 if (n >= 0 && n < (int)_words.size()) { 00385 Word &word = _words[n]; 00386 if ((word._flags & F_checked_double) == 0) { 00387 word._flags |= F_checked_double; 00388 00389 const char *nptr = word._str.c_str(); 00390 char *endptr; 00391 word._double = pstrtod(nptr, &endptr); 00392 00393 if (*endptr == '\0') { 00394 word._flags |= F_valid_double; 00395 } else { 00396 prc_cat->warning() 00397 << "Invalid floating-point value for ConfigVariable " 00398 << get_variable()->get_name() << ": " << word._str << "\n"; 00399 } 00400 } 00401 } 00402 } 00403 00404 //////////////////////////////////////////////////////////////////// 00405 // Function: ConfigDeclaration::extract_words 00406 // Access: Public, Static 00407 // Description: Divides the string into a number of words according 00408 // to whitespace. The words vector should be cleared by 00409 // the user before calling; otherwise, the list of words 00410 // in the string will be appended to the end of whatever 00411 // was there before. 00412 // 00413 // The return value is the number of words extracted. 00414 //////////////////////////////////////////////////////////////////// 00415 int ConfigDeclaration:: 00416 extract_words(const string &str, vector_string &words) { 00417 int num_words = 0; 00418 00419 size_t pos = 0; 00420 while (pos < str.length() && isspace((unsigned int)str[pos])) { 00421 pos++; 00422 } 00423 while (pos < str.length()) { 00424 size_t word_start = pos; 00425 while (pos < str.length() && !isspace((unsigned int)str[pos])) { 00426 pos++; 00427 } 00428 words.push_back(str.substr(word_start, pos - word_start)); 00429 num_words++; 00430 00431 while (pos < str.length() && isspace((unsigned int)str[pos])) { 00432 pos++; 00433 } 00434 } 00435 00436 return num_words; 00437 } 00438 00439 //////////////////////////////////////////////////////////////////// 00440 // Function: ConfigDeclaration::downcase 00441 // Access: Public, Static 00442 // Description: Returns the input string with all uppercase letters 00443 // converted to lowercase. 00444 //////////////////////////////////////////////////////////////////// 00445 string ConfigDeclaration:: 00446 downcase(const string &s) { 00447 string result; 00448 result.reserve(s.size()); 00449 string::const_iterator p; 00450 for (p = s.begin(); p != s.end(); ++p) { 00451 result += tolower(*p); 00452 } 00453 return result; 00454 }