Panda3D
 All Classes Functions Variables Enumerations
configDeclaration.cxx
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 }
 All Classes Functions Variables Enumerations