Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
parse.cpp
Go to the documentation of this file.
1 #include "parse.hpp"
2 
3 #include <iostream>
4 #include <cctype>
5 #include <cstdlib>
6 #include <cstring>
7 
8 using namespace moab;
9 
10 void tag_syntax( std::ostream& s )
11 {
12  s << "Tags are specified as <name>=[value], where the tag value " << std::endl
13  << "is optional." << std::endl
14  << std::endl
15  << "Values of integral types (INTEGER, BIT, and HANDLE) are " << std::endl
16  << "specified using standard C integer notation (a 0x prefix " << std::endl
17  << "for hexidecimal, 0 prefix for octal, and no prefix for " << std::endl
18  << "decimal.) The value of an opaque tag is interpreted as " << std::endl
19  << "either a integral value or a character string. If the tag " << std::endl
20  << "value begins with the prefix 0x it will be interpreted as a " << std::endl
21  << "hexidecimal (base-16) number. If the value does not begin " << std::endl
22  << "with the 0x prefix, it is interpreted as a character string." << std::endl
23  << "Characater strings will be padded with null characters as" << std::endl
24  << "necessary to fill the tag." << std::endl
25  << "Floating-point (real) values must be specified in base-10." << std::endl
26  << "C exponential notation (e.g. 1e-10) is accepted." << std::endl
27  << std::endl
28  << "If the tag is an array of integral or floating-point values " << std::endl
29  << "then the tag value must be specified as a comma-separated " << std::endl
30  << "list, with NO spaces." << std::endl
31  << std::endl
32  << "Tags are created with the syntax name=type:size[=default_value]." << std::endl
33  << "where type is one of {int,double,opaque,handle,bit} and size is " << std::endl
34  << "the number of values of the specified type, or the number of " << std::endl
35  << "bytes if the type is 'opaque', A default value for the tag may " << std::endl
36  << "be specified." << std::endl;
37 }
38 
39 // Check endian-ness of platform. Used when parsing numerical
40 // value for opaque tags.
41 inline static bool is_platform_little_endian();
42 
43 // Parse tag value from a string (vals). The passed size
44 // is the number of values returned by MOAB from tag_get_length.
45 static void* parse_values( const char* vals, DataType type, int size );
46 
47 // Parse opque tag data as either a hexidecimal number or
48 // an ASCII string.
49 static unsigned char* parse_opaque_value( const char* vals, int size );
50 
51 // Parse one or more non-opaque tag values in a comma-separated list.
52 // The passed size is the size returned by MOAB (num values * sizeof(type)).
53 template < typename T >
54 T* parse_values_typed( const char* vals, int size );
55 
56 // Template function to parse a single non-opaque tag value.
57 // Parses the value in the string pointed to by "iter" and updates
58 // iter to point passed the parsed value. Returns zero on success.
59 template < typename T >
60 int parse_value( const char*& iter, T& value );
61 
62 // Convert an ASCII hexidecimal digit to its numerical value.
63 static int hexdigit( char c );
64 
65 inline static bool is_platform_little_endian()
66 {
67  static const unsigned int one = 1;
68  static const bool little = !*( (char*)&one );
69  return little;
70 }
71 
72 template < typename T >
73 int parse_value( const char*& iter, T& value )
74 {
75  char* endptr;
76  long parsed_val = strtol( iter, &endptr, 0 );
77  if( endptr == iter ) return 1;
78  iter = endptr;
79 
80  value = (T)parsed_val;
81  if( (long)value != parsed_val )
82  {
83  std::cerr << "Value too large: " << iter << std::endl;
84  return 2;
85  }
86 
87  return 0;
88 }
89 
90 template <>
91 int parse_value< double >( const char*& iter, double& value )
92 {
93  char* endptr;
94  value = strtod( iter, &endptr );
95  if( endptr == iter ) return 1;
96  iter = endptr;
97  return 0;
98 }
99 
100 int hexdigit( char c )
101 {
102  if( c >= '0' && c <= '9' )
103  return c - '0';
104  else if( c >= 'a' && c <= 'f' )
105  return 10 + c - 'a';
106  else if( c >= 'A' && c <= 'F' )
107  return 10 + c - 'A';
108  else
109  return -1;
110 }
111 
112 unsigned char* parse_opaque_value( const char* vals, int size )
113 {
114  unsigned char* data = (unsigned char*)malloc( size );
115  if( vals[0] && vals[0] == '0' && vals[1] && toupper( vals[1] ) == 'X' )
116  {
117  unsigned char *iter, *end;
118  int step;
120  {
121  iter = data;
122  end = data + size;
123  step = 1;
124  }
125  else
126  {
127  iter = data + size - 1;
128  end = data - 1;
129  step = -1;
130  }
131 
132  const char* vals_end = vals + 1;
133  const char* vals_iter = vals + strlen( vals ) - 1;
134  for( ; iter != end; iter += step )
135  {
136  int less = 0;
137  int most = 0;
138  if( vals_iter != vals_end )
139  {
140  less = hexdigit( *vals_iter );
141  --vals_iter;
142  }
143  if( vals_iter != vals_end )
144  {
145  most = hexdigit( *vals_iter );
146  --vals_iter;
147  }
148  if( less < 0 || most < 0 )
149  {
150  std::cerr << "Error parsing hex value: " << vals << std::endl;
151  free( data );
152  return 0;
153  }
154 
155  *iter = 16 * most + less;
156  }
157  }
158  else
159  {
160  memset( data, 0, size );
161  strcpy( (char*)data, vals + 2 );
162  }
163 
164  return data;
165 }
166 
167 template < typename T >
168 T* parse_values_typed( const char* vals, int count )
169 {
170  if( !count ) return 0;
171 
172  T* data = (T*)malloc( count * sizeof( T ) );
173  T* end = data + count;
174  if( parse_value< T >( vals, *data ) )
175  {
176  free( data );
177  return 0;
178  }
179  for( T* ptr = data + 1; ptr != end; ++ptr )
180  {
181  if( *vals != ',' )
182  {
183  std::cerr << "Expected ',' separating tag values: " << vals << std::endl;
184  free( data );
185  return 0;
186  }
187  ++vals;
188  if( parse_value< T >( vals, *ptr ) )
189  {
190  free( data );
191  return 0;
192  }
193  }
194 
195  return data;
196 }
197 
198 void* parse_values( const char* vals, DataType type, int size )
199 {
200  switch( type )
201  {
202  case MB_TYPE_OPAQUE:
203  return parse_opaque_value( vals, size );
204  case MB_TYPE_INTEGER:
205  return parse_values_typed< int >( vals, size );
206  case MB_TYPE_DOUBLE:
207  return parse_values_typed< double >( vals, size );
208  case MB_TYPE_BIT:
209  return parse_values_typed< bittype >( vals, size );
210  case MB_TYPE_HANDLE:
211  return parse_values_typed< EntityHandle >( vals, size );
212  default:
213  std::cerr << "Unknown tag data type: " << (int)type << std::endl;
214  return 0;
215  }
216 }
217 
218 int parse_tag_spec( char* name, TagSpec& result, Interface* iface )
219 {
220  // Separate optional tag value from tag name
221  char* val = strrchr( name, '=' );
222  if( val )
223  {
224  // zero-length tag name>
225  if( val == name )
226  {
227  std::cerr << "Cannot create tag w/out name: " << name << std::endl;
228  return 1;
229  }
230  *val = '\0';
231  if( !*++val ) // if name ends with an '=', set val to NULL.
232  val = 0;
233  }
234 
235  // Get tag
236  ErrorCode rval = iface->tag_get_handle( name, 0, MB_TYPE_OPAQUE, result.handle, MB_TAG_ANY );
237  if( MB_TAG_NOT_FOUND == rval )
238  {
239  std::cerr << "Tag not found: " << name << std::endl;
240  return 2;
241  }
242  else if( MB_SUCCESS != rval )
243  {
244  std::cerr << "Error retrieving tag handle: " << name << std::endl;
245  return 3;
246  }
247 
248  // Parse tag value
249  result.value = 0;
250  if( val )
251  {
252  DataType type;
253  rval = iface->tag_get_data_type( result.handle, type );
254  if( MB_SUCCESS != rval )
255  {
256  std::cerr << "Error retrieving type for tag: " << name << std::endl;
257  return 3;
258  }
259 
260  int size;
261  rval = iface->tag_get_length( result.handle, size );
262  if( MB_SUCCESS != rval )
263  {
264  std::cerr << "Error retrieving size for tag: " << name << std::endl;
265  return 3;
266  }
267 
268  result.value = parse_values( val, type, size );
269  if( !result.value ) return 1;
270  }
271 
272  return 0;
273 }
274 
275 int parse_tag_create( char* name, TagSpec& result, Interface* iface )
276 {
277  // split at '=' signs
278 
279  char* eq1 = strrchr( name, '=' );
280  if( !eq1 )
281  {
282  std::cerr << "Invalid tag specification: " << name << std::endl;
283  return 1;
284  }
285  *eq1 = '\0';
286  ++eq1;
287  char *type_str = eq1, *val = 0;
288 
289  char* eq2 = strrchr( name, '=' );
290  if( eq2 )
291  {
292  *eq2 = '\0';
293  ++eq2;
294  val = ( '\0' == eq1[0] ) ? 0 : eq1;
295  type_str = eq2;
296  }
297 
298  // parse type data
299  char* size_str = strchr( type_str, ':' );
300  if( !size_str )
301  {
302  std::cerr << "Invalid tag type specification: " << type_str << std::endl;
303  return 1;
304  }
305  *size_str = '\0';
306  ++size_str;
307  DataType type;
308  if( !strcmp( type_str, "int" ) )
309  {
310  type = MB_TYPE_INTEGER;
311  }
312  else if( !strcmp( type_str, "double" ) )
313  {
314  type = MB_TYPE_DOUBLE;
315  }
316  else if( !strcmp( type_str, "bit" ) )
317  {
318  type = MB_TYPE_BIT;
319  }
320  else if( !strcmp( type_str, "handle" ) )
321  {
322  type = MB_TYPE_HANDLE;
323  }
324  else if( !strcmp( type_str, "opaque" ) )
325  {
326  type = MB_TYPE_OPAQUE;
327  }
328  else
329  {
330  std::cerr << "Invalid tag type specification: " << type_str << std::endl;
331  return 1;
332  }
333  char* end_ptr;
334  int count = (int)strtol( size_str, &end_ptr, 0 );
335  if( !*size_str || *end_ptr || count < 1 )
336  {
337  std::cerr << "Invalid tag size specification: " << size_str << std::endl;
338  return 1;
339  }
340 
341  // parse default value
342  result.value = 0;
343  if( val )
344  {
345  result.value = parse_values( val, type, count );
346  if( !result.value ) return 1;
347  }
348 
349  // check if tag exists
350  if( MB_SUCCESS == iface->tag_get_handle( name, 0, MB_TYPE_OPAQUE, result.handle, MB_TAG_ANY ) )
351  {
352  // make sure it matches
353  DataType etype;
354  int esize;
355  if( MB_SUCCESS != iface->tag_get_data_type( result.handle, etype ) ||
356  MB_SUCCESS != iface->tag_get_length( result.handle, esize ) )
357  {
358  std::cerr << "Error accessing properties of tag: " << name << std::endl;
359  return 3;
360  }
361 
362  if( etype != type || esize != count )
363  {
364  std::cerr << "Tag already exists with different type: " << name << std::endl;
365  return 1;
366  }
367 
368  std::vector< unsigned char > value( esize );
369  if( result.value )
370  {
371  ErrorCode rval = iface->tag_get_default_value( result.handle, &value[0] );
372  if( rval != MB_ENTITY_NOT_FOUND && rval != MB_SUCCESS )
373  {
374  std::cerr << "Error checking default value of tag: " << name << std::endl;
375  return 3;
376  }
377  else if( rval == MB_ENTITY_NOT_FOUND || memcmp( &value[0], result.value, esize ) )
378  {
379  std::cerr << "Tag already exists and default value doesn't match: " << name << std::endl;
380  return 1;
381  }
382  }
383  }
384  else
385  {
386  ErrorCode rval =
387  iface->tag_get_handle( name, count, type, result.handle, MB_TAG_SPARSE | MB_TAG_CREAT, result.value );
388  if( MB_SUCCESS != rval )
389  {
390  std::cerr << "Failed to create tag: " << name << std::endl;
391  return 3;
392  }
393  }
394 
395  return 0;
396 }