Panda3D
|
00001 // Filename: rangeDescription.cxx 00002 // Created by: drose (07Sep03) 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 "rangeDescription.h" 00016 #include "string_utils.h" 00017 #include "pnotify.h" 00018 00019 //////////////////////////////////////////////////////////////////// 00020 // Function: RangeDescription::Constructor 00021 // Access: Public 00022 // Description: 00023 //////////////////////////////////////////////////////////////////// 00024 RangeDescription:: 00025 RangeDescription() { 00026 } 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: RangeDescription::parse_parameter 00030 // Access: Public 00031 // Description: Parses a string of comma- and hyphen-delimited 00032 // unicode values, in decimal and/or hex, including 00033 // possible bracket-delimited ASCII characters, as may 00034 // have been passed on a command line. Returns true if 00035 // the parameter is parsed correctly, false otherwise. 00036 //////////////////////////////////////////////////////////////////// 00037 bool RangeDescription:: 00038 parse_parameter(const string ¶m) { 00039 // First, go through and separate the string by commas. We have to 00040 // do this by hand instead of calling tokenize(), because we also 00041 // have to scan for square brackets, which may contain nested 00042 // commas. 00043 size_t p = 0; 00044 while (p < param.length()) { 00045 size_t q = param.find_first_of("[,", p); 00046 if (q == string::npos) { 00047 return parse_word(trim(param.substr(p))); 00048 } 00049 if (!parse_word(trim(param.substr(p, q - p)))) { 00050 return false; 00051 } 00052 00053 if (param[q] == '[') { 00054 // A square bracket means we must search for the matching square 00055 // bracket. However, a right bracket immediately after the left 00056 // bracket doesn't count; we start the scan after that. 00057 p = param.find("]", q + 2); 00058 if ( p == string::npos) { 00059 nout << "Unclosed open bracket.\n"; 00060 return false; 00061 } 00062 if (!parse_bracket(param.substr(q + 1, p - q - 1))) { 00063 return false; 00064 } 00065 p = p + 1; 00066 00067 } else { 00068 // Otherwise, if the separator was just a comma, the next 00069 // character begins the next word. 00070 p = q + 1; 00071 } 00072 } 00073 00074 return true; 00075 } 00076 00077 //////////////////////////////////////////////////////////////////// 00078 // Function: RangeDescription::output 00079 // Access: Public 00080 // Description: 00081 //////////////////////////////////////////////////////////////////// 00082 void RangeDescription:: 00083 output(ostream &out) const { 00084 bool first_time = true; 00085 RangeList::const_iterator ri; 00086 for (ri = _range_list.begin(); ri != _range_list.end(); ++ri) { 00087 const Range &range = (*ri); 00088 if (!first_time) { 00089 out << ","; 00090 } 00091 first_time = false; 00092 if (range._from_code == range._to_code) { 00093 out << range._from_code; 00094 } else { 00095 out << range._from_code << "-" << range._to_code; 00096 } 00097 } 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: RangeDescription::parse_word 00102 // Access: Private 00103 // Description: Parses a single "word", i.e. the text delimited by 00104 // commas, that might be listed on the command line. 00105 // This is generally either the empty string, a single 00106 // number, or a pair of numbers separated by a hyphen. 00107 //////////////////////////////////////////////////////////////////// 00108 bool RangeDescription:: 00109 parse_word(const string &word) { 00110 if (word.empty()) { 00111 return true; 00112 } 00113 00114 // It's not empty, so see if it includes a hyphen. 00115 size_t hyphen = word.find('-'); 00116 if (hyphen == string::npos) { 00117 // Nope, just one number. 00118 int code; 00119 if (!parse_code(word, code)) { 00120 return false; 00121 } 00122 add_singleton(code); 00123 00124 } else { 00125 // Two numbers separated by a hyphen. 00126 int from_code, to_code; 00127 if (!parse_code(word.substr(0, hyphen), from_code)) { 00128 return false; 00129 } 00130 if (!parse_code(word.substr(hyphen + 1), to_code)) { 00131 return false; 00132 } 00133 add_range(from_code, to_code); 00134 } 00135 00136 return true; 00137 } 00138 00139 //////////////////////////////////////////////////////////////////// 00140 // Function: RangeDescription::parse_code 00141 // Access: Private 00142 // Description: Parses a single numeric value, either decimal or 00143 // hexadecimal, and stores it in the indicated 00144 // parameter. Returns true if successful, false 00145 // otherwise. 00146 //////////////////////////////////////////////////////////////////// 00147 bool RangeDescription:: 00148 parse_code(const string &word, int &code) { 00149 string str = trim(word); 00150 const char *nptr = str.c_str(); 00151 char *endptr; 00152 code = strtol(nptr, &endptr, 0); 00153 if (*endptr == '\0') { 00154 return true; 00155 } 00156 00157 nout << "Invalid Unicode value: " << word << "\n"; 00158 return false; 00159 } 00160 00161 //////////////////////////////////////////////////////////////////// 00162 // Function: RangeDescription::parse_bracket 00163 // Access: Private 00164 // Description: Parses the text listed between square brackets on the 00165 // command line. 00166 //////////////////////////////////////////////////////////////////// 00167 bool RangeDescription:: 00168 parse_bracket(const string &str) { 00169 string::const_iterator si; 00170 si = str.begin(); 00171 while (si != str.end()) { 00172 int ch = (*si); 00173 ++si; 00174 if (si != str.end() && (*si) == '-') { 00175 // A hyphen indicates a range. 00176 ++si; 00177 if (si == str.end()) { 00178 // Unless the hyphen is the last character. 00179 add_singleton(ch); 00180 add_singleton('-'); 00181 } else { 00182 add_range(ch, (*si)); 00183 ++si; 00184 } 00185 } else { 00186 // Anything other than a hyphen indicates a singleton. 00187 add_singleton(ch); 00188 } 00189 } 00190 00191 return true; 00192 }