cgma
|
00001 00006 #include "CGMFileOptions.hpp" 00007 00008 #include <ctype.h> 00009 #include <stdlib.h> 00010 #include <string.h> 00011 00012 const char DEFAULT_SEPARATOR = ';'; 00013 00014 static inline bool strempty( const char* s ) { return !*s; } 00015 00016 CGMFileOptions::CGMFileOptions( const char* str ) 00017 : mData(0) 00018 { 00019 // if option string is null, just return 00020 if (!str) 00021 return; 00022 00023 // check if alternate separator is specified 00024 char separator[2] = { DEFAULT_SEPARATOR, '\0' }; 00025 if (*str == DEFAULT_SEPARATOR) { 00026 ++str; 00027 if (strempty(str)) 00028 return; 00029 separator[0] = *str; 00030 ++str; 00031 } 00032 00033 // don't bother allocating copy of input string if 00034 // input string is empty. 00035 if (!strempty(str)) 00036 { 00037 // tokenize at separator character 00038 mData = strdup( str ); 00039 for (char* i = strtok( mData, separator ); i; i = strtok( 0, separator )) 00040 if (!strempty(i)) // skip empty strings 00041 mOptions.push_back( i ); 00042 } 00043 } 00044 00045 CGMFileOptions::CGMFileOptions( const CGMFileOptions& copy ) : 00046 mData(0), mOptions( copy.mOptions.size() ) 00047 { 00048 if (!copy.mOptions.empty()) { 00049 const char* last = copy.mOptions.back(); 00050 const char* endptr = last + strlen(last) + 1; 00051 size_t len = endptr - copy.mData; 00052 mData = (char*)malloc( len ); 00053 memcpy( mData, copy.mData, len ); 00054 for (size_t i = 0; i < mOptions.size(); ++i) 00055 mOptions[i] = mData + (copy.mOptions[i] - copy.mData); 00056 } 00057 } 00058 00059 CGMFileOptions& CGMFileOptions::operator=( const CGMFileOptions& copy ) 00060 { 00061 free( mData ); 00062 mData = 0; 00063 mOptions.resize( copy.mOptions.size() ); 00064 00065 if (!copy.mOptions.empty()) { 00066 const char* last = copy.mOptions.back(); 00067 const char* endptr = last + strlen(last) + 1; 00068 size_t len = endptr - copy.mData; 00069 mData = (char*)malloc( len ); 00070 memcpy( mData, copy.mData, len ); 00071 for (size_t i = 0; i < mOptions.size(); ++i) 00072 mOptions[i] = mData + (copy.mOptions[i] - copy.mData); 00073 } 00074 00075 return *this; 00076 } 00077 00078 CGMFileOptions::~CGMFileOptions() 00079 { 00080 free( mData ); 00081 } 00082 00083 CGMFOErrorCode CGMFileOptions::get_null_option( const char* name ) const 00084 { 00085 const char* s; 00086 CGMFOErrorCode rval = get_option( name, s ); 00087 if (FO_SUCCESS != rval) 00088 return rval; 00089 return strempty(s) ? FO_SUCCESS : FO_TYPE_OUT_OF_RANGE; 00090 } 00091 00092 CGMFOErrorCode CGMFileOptions::get_int_option( const char* name, int& value ) const 00093 { 00094 const char* s; 00095 CGMFOErrorCode rval = get_option( name, s ); 00096 if (FO_SUCCESS != rval) 00097 return rval; 00098 00099 // empty string 00100 if (strempty(s)) 00101 return FO_TYPE_OUT_OF_RANGE; 00102 00103 // parse value 00104 char* endptr; 00105 long int pval = strtol( s, &endptr, 0 ); 00106 if (!strempty(endptr)) // syntax error 00107 return FO_TYPE_OUT_OF_RANGE; 00108 00109 // check for overflow (parsing long int, returning int) 00110 value = pval; 00111 if (pval != (long int)value) 00112 return FO_TYPE_OUT_OF_RANGE; 00113 00114 return FO_SUCCESS; 00115 } 00116 00117 CGMFOErrorCode CGMFileOptions::get_ints_option( const char* name, 00118 std::vector<int>& values) const 00119 { 00120 const char* s; 00121 CGMFOErrorCode rval = get_option( name, s ); 00122 if (FO_SUCCESS != rval) 00123 return rval; 00124 00125 // empty string 00126 if (strempty(s)) 00127 return FO_TYPE_OUT_OF_RANGE; 00128 00129 // parse values 00130 while (!strempty(s)) { 00131 char* endptr; 00132 long int sval = strtol( s, &endptr, 0 ); 00133 00134 #define EATSPACE(a) while ((!strncmp(a, " ", 1) || \ 00135 !strncmp(a, ",", 1)) && !strempty(a)) a++; 00136 //EATSPACE(endptr); 00137 00138 while ((!strncmp(endptr, " ", 1) || 00139 !strncmp(endptr, ",", 1)) && !strempty(endptr)) { 00140 endptr++; 00141 } 00142 00143 long int eval = sval; 00144 if (!strcmp(endptr, "-")) { 00145 endptr++; 00146 s = endptr; 00147 eval = strtol(s, &endptr, 0); 00148 EATSPACE(endptr); 00149 } 00150 00151 // check for overflow (parsing long int, returning int) 00152 int value = sval; 00153 if (sval != (long int)value) 00154 return FO_TYPE_OUT_OF_RANGE; 00155 value = eval; 00156 if (eval != (long int)value) 00157 return FO_TYPE_OUT_OF_RANGE; 00158 00159 for (int i = sval; i <= eval; i++) 00160 values.push_back(i); 00161 00162 s = endptr; 00163 } 00164 00165 return FO_SUCCESS; 00166 } 00167 00168 CGMFOErrorCode CGMFileOptions::get_real_option ( const char* name, double& value ) const 00169 { 00170 const char* s; 00171 CGMFOErrorCode rval = get_option( name, s ); 00172 if (FO_SUCCESS != rval) 00173 return rval; 00174 00175 // empty string 00176 if (strempty(s)) 00177 return FO_TYPE_OUT_OF_RANGE; 00178 00179 // parse value 00180 char* endptr; 00181 value = strtod( s, &endptr ); 00182 if (!strempty(endptr)) // syntax error 00183 return FO_TYPE_OUT_OF_RANGE; 00184 00185 return FO_SUCCESS; 00186 } 00187 00188 CGMFOErrorCode CGMFileOptions::get_str_option( const char* name, std::string& value ) const 00189 { 00190 const char* s; 00191 CGMFOErrorCode rval = get_option( name, s ); 00192 if (FO_SUCCESS != rval) 00193 return rval; 00194 if (strempty(s)) 00195 return FO_TYPE_OUT_OF_RANGE; 00196 value = s; 00197 return FO_SUCCESS; 00198 } 00199 00200 CGMFOErrorCode CGMFileOptions::get_option( const char* name, std::string& value ) const 00201 { 00202 const char* s; 00203 CGMFOErrorCode rval = get_option( name, s ); 00204 if (FO_SUCCESS != rval) 00205 return rval; 00206 00207 value = s; 00208 return FO_SUCCESS; 00209 } 00210 00211 CGMFOErrorCode CGMFileOptions::get_option( const char* name, const char*& value ) const 00212 { 00213 std::vector<const char*>::const_iterator i; 00214 for (i = mOptions.begin(); i != mOptions.end(); ++i) { 00215 const char* opt = *i; 00216 if (compare( name, opt )) { 00217 value = opt + strlen(name); 00218 // if compare returned true, next char after option 00219 // name must be either the null char or an equals symbol. 00220 if (*value == '=') 00221 ++value; 00222 00223 return FO_SUCCESS; 00224 } 00225 } 00226 00227 return FO_ENTITY_NOT_FOUND; 00228 } 00229 00230 CGMFOErrorCode CGMFileOptions::match_option( const char* name, 00231 const char* value ) const 00232 { 00233 int idx; 00234 const char* array[] = { value, NULL }; 00235 return match_option( name, array, idx ); 00236 } 00237 00238 CGMFOErrorCode CGMFileOptions::match_option( const char* name, 00239 const char* const* values, 00240 int& index ) const 00241 { 00242 const char* optval; 00243 CGMFOErrorCode rval = get_option( name, optval ); 00244 if (FO_SUCCESS != rval) 00245 return rval; 00246 00247 for (index = 0; values[index]; ++index) 00248 if (compare( optval, values[index] )) 00249 return FO_SUCCESS; 00250 00251 index = -1; 00252 return FO_FAILURE; 00253 } 00254 00255 00256 bool CGMFileOptions::compare( const char* name, const char* option ) 00257 { 00258 while (!strempty(name) && toupper(*name) == toupper(*option)) { 00259 ++name; 00260 ++option; 00261 } 00262 // match if name matched option for length of name, 00263 // and option either matched entirely or matches up to 00264 // and equals sign. 00265 return strempty(name) && (strempty(option) || *option == '='); 00266 } 00267 00268 void CGMFileOptions::get_options( std::vector<std::string>& list ) const 00269 { 00270 list.clear(); 00271 list.resize( mOptions.size() ); 00272 std::copy( mOptions.begin(), mOptions.end(), list.begin() ); 00273 } 00274