MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 #include "parse.hpp" 00002 00003 #include <iostream> 00004 #include <cctype> 00005 #include <cstdlib> 00006 #include <cstring> 00007 00008 using namespace moab; 00009 00010 void tag_syntax( std::ostream& s ) 00011 { 00012 s << "Tags are specified as <name>=[value], where the tag value " << std::endl 00013 << "is optional." << std::endl 00014 << std::endl 00015 << "Values of integral types (INTEGER, BIT, and HANDLE) are " << std::endl 00016 << "specified using standard C integer notation (a 0x prefix " << std::endl 00017 << "for hexidecimal, 0 prefix for octal, and no prefix for " << std::endl 00018 << "decimal.) The value of an opaque tag is interpreted as " << std::endl 00019 << "either a integral value or a character string. If the tag " << std::endl 00020 << "value begins with the prefix 0x it will be interpreted as a " << std::endl 00021 << "hexidecimal (base-16) number. If the value does not begin " << std::endl 00022 << "with the 0x prefix, it is interpreted as a character string." << std::endl 00023 << "Characater strings will be padded with null characters as" << std::endl 00024 << "necessary to fill the tag." << std::endl 00025 << "Floating-point (real) values must be specified in base-10." << std::endl 00026 << "C exponential notation (e.g. 1e-10) is accepted." << std::endl 00027 << std::endl 00028 << "If the tag is an array of integral or floating-point values " << std::endl 00029 << "then the tag value must be specified as a comma-separated " << std::endl 00030 << "list, with NO spaces." << std::endl 00031 << std::endl 00032 << "Tags are created with the syntax name=type:size[=default_value]." << std::endl 00033 << "where type is one of {int,double,opaque,handle,bit} and size is " << std::endl 00034 << "the number of values of the specified type, or the number of " << std::endl 00035 << "bytes if the type is 'opaque', A default value for the tag may " << std::endl 00036 << "be specified." << std::endl; 00037 } 00038 00039 // Check endian-ness of platform. Used when parsing numerical 00040 // value for opaque tags. 00041 inline static bool is_platform_little_endian(); 00042 00043 // Parse tag value from a string (vals). The passed size 00044 // is the number of values returned by MOAB from tag_get_length. 00045 static void* parse_values( const char* vals, DataType type, int size ); 00046 00047 // Parse opque tag data as either a hexidecimal number or 00048 // an ASCII string. 00049 static unsigned char* parse_opaque_value( const char* vals, int size ); 00050 00051 // Parse one or more non-opaque tag values in a comma-separated list. 00052 // The passed size is the size returned by MOAB (num values * sizeof(type)). 00053 template < typename T > 00054 T* parse_values_typed( const char* vals, int size ); 00055 00056 // Template function to parse a single non-opaque tag value. 00057 // Parses the value in the string pointed to by "iter" and updates 00058 // iter to point passed the parsed value. Returns zero on success. 00059 template < typename T > 00060 int parse_value( const char*& iter, T& value ); 00061 00062 // Convert an ASCII hexidecimal digit to its numerical value. 00063 static int hexdigit( char c ); 00064 00065 inline static bool is_platform_little_endian() 00066 { 00067 static const unsigned int one = 1; 00068 static const bool little = !*( (char*)&one ); 00069 return little; 00070 } 00071 00072 template < typename T > 00073 int parse_value( const char*& iter, T& value ) 00074 { 00075 char* endptr; 00076 long parsed_val = strtol( iter, &endptr, 0 ); 00077 if( endptr == iter ) return 1; 00078 iter = endptr; 00079 00080 value = (T)parsed_val; 00081 if( (long)value != parsed_val ) 00082 { 00083 std::cerr << "Value too large: " << iter << std::endl; 00084 return 2; 00085 } 00086 00087 return 0; 00088 } 00089 00090 template <> 00091 int parse_value< double >( const char*& iter, double& value ) 00092 { 00093 char* endptr; 00094 value = strtod( iter, &endptr ); 00095 if( endptr == iter ) return 1; 00096 iter = endptr; 00097 return 0; 00098 } 00099 00100 int hexdigit( char c ) 00101 { 00102 if( c >= '0' && c <= '9' ) 00103 return c - '0'; 00104 else if( c >= 'a' && c <= 'f' ) 00105 return 10 + c - 'a'; 00106 else if( c >= 'A' && c <= 'F' ) 00107 return 10 + c - 'A'; 00108 else 00109 return -1; 00110 } 00111 00112 unsigned char* parse_opaque_value( const char* vals, int size ) 00113 { 00114 unsigned char* data = (unsigned char*)malloc( size ); 00115 if( vals[0] && vals[0] == '0' && vals[1] && toupper( vals[1] ) == 'X' ) 00116 { 00117 unsigned char *iter, *end; 00118 int step; 00119 if( is_platform_little_endian() ) 00120 { 00121 iter = data; 00122 end = data + size; 00123 step = 1; 00124 } 00125 else 00126 { 00127 iter = data + size - 1; 00128 end = data - 1; 00129 step = -1; 00130 } 00131 00132 const char* vals_end = vals + 1; 00133 const char* vals_iter = vals + strlen( vals ) - 1; 00134 for( ; iter != end; iter += step ) 00135 { 00136 int less = 0; 00137 int most = 0; 00138 if( vals_iter != vals_end ) 00139 { 00140 less = hexdigit( *vals_iter ); 00141 --vals_iter; 00142 } 00143 if( vals_iter != vals_end ) 00144 { 00145 most = hexdigit( *vals_iter ); 00146 --vals_iter; 00147 } 00148 if( less < 0 || most < 0 ) 00149 { 00150 std::cerr << "Error parsing hex value: " << vals << std::endl; 00151 free( data ); 00152 return 0; 00153 } 00154 00155 *iter = 16 * most + less; 00156 } 00157 } 00158 else 00159 { 00160 memset( data, 0, size ); 00161 strcpy( (char*)data, vals + 2 ); 00162 } 00163 00164 return data; 00165 } 00166 00167 template < typename T > 00168 T* parse_values_typed( const char* vals, int count ) 00169 { 00170 if( !count ) return 0; 00171 00172 T* data = (T*)malloc( count * sizeof( T ) ); 00173 T* end = data + count; 00174 if( parse_value< T >( vals, *data ) ) 00175 { 00176 free( data ); 00177 return 0; 00178 } 00179 for( T* ptr = data + 1; ptr != end; ++ptr ) 00180 { 00181 if( *vals != ',' ) 00182 { 00183 std::cerr << "Expected ',' separating tag values: " << vals << std::endl; 00184 free( data ); 00185 return 0; 00186 } 00187 ++vals; 00188 if( parse_value< T >( vals, *ptr ) ) 00189 { 00190 free( data ); 00191 return 0; 00192 } 00193 } 00194 00195 return data; 00196 } 00197 00198 void* parse_values( const char* vals, DataType type, int size ) 00199 { 00200 switch( type ) 00201 { 00202 case MB_TYPE_OPAQUE: 00203 return parse_opaque_value( vals, size ); 00204 case MB_TYPE_INTEGER: 00205 return parse_values_typed< int >( vals, size ); 00206 case MB_TYPE_DOUBLE: 00207 return parse_values_typed< double >( vals, size ); 00208 case MB_TYPE_BIT: 00209 return parse_values_typed< bittype >( vals, size ); 00210 case MB_TYPE_HANDLE: 00211 return parse_values_typed< EntityHandle >( vals, size ); 00212 default: 00213 std::cerr << "Unknown tag data type: " << (int)type << std::endl; 00214 return 0; 00215 } 00216 } 00217 00218 int parse_tag_spec( char* name, TagSpec& result, Interface* iface ) 00219 { 00220 // Separate optional tag value from tag name 00221 char* val = strrchr( name, '=' ); 00222 if( val ) 00223 { 00224 // zero-length tag name> 00225 if( val == name ) 00226 { 00227 std::cerr << "Cannot create tag w/out name: " << name << std::endl; 00228 return 1; 00229 } 00230 *val = '\0'; 00231 if( !*++val ) // if name ends with an '=', set val to NULL. 00232 val = 0; 00233 } 00234 00235 // Get tag 00236 ErrorCode rval = iface->tag_get_handle( name, 0, MB_TYPE_OPAQUE, result.handle, MB_TAG_ANY ); 00237 if( MB_TAG_NOT_FOUND == rval ) 00238 { 00239 std::cerr << "Tag not found: " << name << std::endl; 00240 return 2; 00241 } 00242 else if( MB_SUCCESS != rval ) 00243 { 00244 std::cerr << "Error retrieving tag handle: " << name << std::endl; 00245 return 3; 00246 } 00247 00248 // Parse tag value 00249 result.value = 0; 00250 if( val ) 00251 { 00252 DataType type; 00253 rval = iface->tag_get_data_type( result.handle, type ); 00254 if( MB_SUCCESS != rval ) 00255 { 00256 std::cerr << "Error retrieving type for tag: " << name << std::endl; 00257 return 3; 00258 } 00259 00260 int size; 00261 rval = iface->tag_get_length( result.handle, size ); 00262 if( MB_SUCCESS != rval ) 00263 { 00264 std::cerr << "Error retrieving size for tag: " << name << std::endl; 00265 return 3; 00266 } 00267 00268 result.value = parse_values( val, type, size ); 00269 if( !result.value ) return 1; 00270 } 00271 00272 return 0; 00273 } 00274 00275 int parse_tag_create( char* name, TagSpec& result, Interface* iface ) 00276 { 00277 // split at '=' signs 00278 00279 char* eq1 = strrchr( name, '=' ); 00280 if( !eq1 ) 00281 { 00282 std::cerr << "Invalid tag specification: " << name << std::endl; 00283 return 1; 00284 } 00285 *eq1 = '\0'; 00286 ++eq1; 00287 char *type_str = eq1, *val = 0; 00288 00289 char* eq2 = strrchr( name, '=' ); 00290 if( eq2 ) 00291 { 00292 *eq2 = '\0'; 00293 ++eq2; 00294 val = ( '\0' == eq1[0] ) ? 0 : eq1; 00295 type_str = eq2; 00296 } 00297 00298 // parse type data 00299 char* size_str = strchr( type_str, ':' ); 00300 if( !size_str ) 00301 { 00302 std::cerr << "Invalid tag type specification: " << type_str << std::endl; 00303 return 1; 00304 } 00305 *size_str = '\0'; 00306 ++size_str; 00307 DataType type; 00308 if( !strcmp( type_str, "int" ) ) 00309 { 00310 type = MB_TYPE_INTEGER; 00311 } 00312 else if( !strcmp( type_str, "double" ) ) 00313 { 00314 type = MB_TYPE_DOUBLE; 00315 } 00316 else if( !strcmp( type_str, "bit" ) ) 00317 { 00318 type = MB_TYPE_BIT; 00319 } 00320 else if( !strcmp( type_str, "handle" ) ) 00321 { 00322 type = MB_TYPE_HANDLE; 00323 } 00324 else if( !strcmp( type_str, "opaque" ) ) 00325 { 00326 type = MB_TYPE_OPAQUE; 00327 } 00328 else 00329 { 00330 std::cerr << "Invalid tag type specification: " << type_str << std::endl; 00331 return 1; 00332 } 00333 char* end_ptr; 00334 int count = (int)strtol( size_str, &end_ptr, 0 ); 00335 if( !*size_str || *end_ptr || count < 1 ) 00336 { 00337 std::cerr << "Invalid tag size specification: " << size_str << std::endl; 00338 return 1; 00339 } 00340 00341 // parse default value 00342 result.value = 0; 00343 if( val ) 00344 { 00345 result.value = parse_values( val, type, count ); 00346 if( !result.value ) return 1; 00347 } 00348 00349 // check if tag exists 00350 if( MB_SUCCESS == iface->tag_get_handle( name, 0, MB_TYPE_OPAQUE, result.handle, MB_TAG_ANY ) ) 00351 { 00352 // make sure it matches 00353 DataType etype; 00354 int esize; 00355 if( MB_SUCCESS != iface->tag_get_data_type( result.handle, etype ) || 00356 MB_SUCCESS != iface->tag_get_length( result.handle, esize ) ) 00357 { 00358 std::cerr << "Error accessing properties of tag: " << name << std::endl; 00359 return 3; 00360 } 00361 00362 if( etype != type || esize != count ) 00363 { 00364 std::cerr << "Tag already exists with different type: " << name << std::endl; 00365 return 1; 00366 } 00367 00368 std::vector< unsigned char > value( esize ); 00369 if( result.value ) 00370 { 00371 ErrorCode rval = iface->tag_get_default_value( result.handle, &value[0] ); 00372 if( rval != MB_ENTITY_NOT_FOUND && rval != MB_SUCCESS ) 00373 { 00374 std::cerr << "Error checking default value of tag: " << name << std::endl; 00375 return 3; 00376 } 00377 else if( rval == MB_ENTITY_NOT_FOUND || memcmp( &value[0], result.value, esize ) ) 00378 { 00379 std::cerr << "Tag already exists and default value doesn't match: " << name << std::endl; 00380 return 1; 00381 } 00382 } 00383 } 00384 else 00385 { 00386 ErrorCode rval = 00387 iface->tag_get_handle( name, count, type, result.handle, MB_TAG_SPARSE | MB_TAG_CREAT, result.value ); 00388 if( MB_SUCCESS != rval ) 00389 { 00390 std::cerr << "Failed to create tag: " << name << std::endl; 00391 return 3; 00392 } 00393 } 00394 00395 return 0; 00396 }