Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
parse.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines