Panda3D
 All Classes Functions Variables Enumerations
rangeDescription.cxx
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 &param) {
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 }
 All Classes Functions Variables Enumerations