gloox  0.9.9.12
tag.cpp
1 /*
2  Copyright (c) 2005-2008 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 #include "tag.h"
15 
16 #include <stdlib.h>
17 
18 #ifdef _WIN32_WCE
19 # include <cmath>
20 #else
21 # include <sstream>
22 #endif
23 
24 #include <algorithm>
25 #include <cstring>
26 
27 namespace gloox
28 {
30  : m_parent( 0 ), m_type( StanzaUndefined ), m_incoming( false ), m_valid( false )
31  {
32  }
33 
34  Tag::Tag( const std::string& name, const std::string& cdata, bool incoming )
35  : m_name( incoming ? relax( name ) : name ),
36  m_cdata( incoming ? relax( cdata ) : cdata ),
37  m_parent( 0 ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
38  {
39  m_valid = !m_name.empty();
40  }
41 
42  Tag::Tag( Tag *parent, const std::string& name, const std::string& cdata, bool incoming )
43  : m_name( incoming ? relax( name ) : name ),
44  m_cdata( incoming ? relax( cdata ) : cdata ),
45  m_parent( parent ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
46  {
47  if( m_parent )
48  m_parent->addChild( this );
49  m_valid = !m_name.empty();
50  }
51 
52  Tag::Tag( const std::string& name, const std::string& attrib, const std::string& value, bool incoming )
53  : m_name( incoming ? relax( name ) : name ),
54  m_parent( 0 ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
55  {
56  addAttribute( attrib, value );
57  m_valid = !m_name.empty();
58  }
59 
60  Tag::Tag( Tag *parent, const std::string& name, const std::string& attrib, const std::string& value,
61  bool incoming )
62  : m_name( incoming ? relax( name ) : name ),
63  m_parent( parent ), m_type( StanzaUndefined ), m_incoming( incoming ), m_valid( true )
64  {
65  if( m_parent )
66  m_parent->addChild( this );
67  addAttribute( attrib, value );
68  m_valid = !m_name.empty();
69  }
70 
72  {
73  TagList::iterator it = m_children.begin();
74  for( ; it != m_children.end(); ++it )
75  {
76  delete (*it);
77  }
78  m_parent = 0;
79  }
80 
81  bool Tag::operator==( const Tag &right ) const
82  {
83  if( m_name != right.m_name || m_attribs != right.m_attribs
84  || m_children.size() != right.m_children.size() )
85  return false;
86 
87  TagList::const_iterator it = m_children.begin();
88  TagList::const_iterator it_r = right.m_children.begin();
89  while( it != m_children.end() && it_r != right.m_children.end() && *(*it) == *(*it_r) )
90  {
91  ++it;
92  ++it_r;
93  }
94  return it == m_children.end();
95  }
96 
97  const std::string Tag::xml() const
98  {
99  std::string xml = "<";
100  xml += escape( m_name );
101  if( !m_attribs.empty() )
102  {
103  AttributeList::const_iterator it_a = m_attribs.begin();
104  for( ; it_a != m_attribs.end(); ++it_a )
105  {
106  xml += " ";
107  xml += escape( (*it_a).first );
108  xml += "='";
109  xml += escape( (*it_a).second );
110  xml += "'";
111  }
112  }
113 
114  if( m_cdata.empty() && !m_children.size() )
115  xml += "/>";
116  else if( m_children.size() )
117  {
118  xml += ">";
119  TagList::const_iterator it_c = m_children.begin();
120  for( ; it_c != m_children.end(); ++it_c )
121  {
122  xml += (*it_c)->xml();
123  }
124  xml += "</";
125  xml += escape( m_name );
126  xml += ">";
127  }
128  else if( !m_cdata.empty() )
129  {
130  xml += ">";
131  xml += escape( m_cdata );
132  xml += "</";
133  xml += escape( m_name );
134  xml += ">";
135  }
136 
137  return xml;
138  }
139 
140  static const char escape_chars[] = { '&', '<', '>', '\'', '"', '<', '>',
141  '\'', '"', '<', '>', '<', '>', '\'', '"', '<', '>', '<', '>', '\'', '"' };
142 
143  static const std::string escape_seqs[] = { "amp;", "lt;", "gt;", "apos;",
144  "quot;", "#60;", "#62;", "#39;", "#34;", "#x3c;", "#x3e;", "#x3C;",
145  "#x3E;", "#x27;", "#x22;", "#X3c;", "#X3e;", "#X3C;", "#X3E;", "#X27;",
146  "#X22;" };
147 
148  static const unsigned nb_escape = sizeof(escape_chars)/sizeof(char);
149  static const unsigned escape_size = 5;
150 
151  const std::string Tag::escape( std::string esc )
152  {
153  for( unsigned val, i = 0; i < esc.length(); ++i )
154  {
155  for( val = 0; val < escape_size; ++val )
156  {
157  if( esc[i] == escape_chars[val] )
158  {
159  esc[i] = '&';
160  esc.insert( i+1, escape_seqs[val] );
161  i += escape_seqs[val].length();
162  break;
163  }
164  }
165  }
166  return esc;
167  }
168 
169  /*
170  * When a sequence is found, do not repack the string directly, just set
171  * the new symbol and mark the rest for deletation (0).
172  */
173  const std::string Tag::relax( std::string esc )
174  {
175  const unsigned int l = esc.length();
176  unsigned int p = 0;
177  unsigned int i = 0;
178 
179  for( unsigned int val; i < l; ++i )
180  {
181  if( esc[i] != '&' )
182  continue;
183 
184  for( val = 0; val < nb_escape; ++val )
185  {
186  if( ( i + escape_seqs[val].length() <= l )
187  && !strncmp( esc.data()+i+1, escape_seqs[val].data(),
188  escape_seqs[val].length() ) )
189  {
190  esc[i] = escape_chars[val];
191  for( p=1; p <= escape_seqs[val].length(); ++p )
192  esc[i+p] = 0;
193  i += p-1;
194  break;
195  }
196  }
197  }
198  if( p )
199  {
200  for( p = 0, i = 0; i < l; ++i )
201  {
202  if( esc[i] != 0 )
203  {
204  if( esc[p] == 0 )
205  {
206  esc[p] = esc[i];
207  esc[p+1] = 0;
208  }
209  ++p;
210  }
211  }
212  esc.resize( p );
213  }
214  return esc;
215  }
216 
217  void Tag::addAttribute( const std::string& name, const std::string& value )
218  {
219  if( name.empty() || value.empty() )
220  return;
221 
222  AttributeList::iterator it = m_attribs.begin();
223  for( ; it != m_attribs.end(); ++it )
224  {
225  if( (*it).first == ( m_incoming ? relax( name ) : name ) )
226  {
227  (*it).second = m_incoming ? relax( value ) : value;
228  return;
229  }
230  }
231 
232  m_attribs.push_back( Attribute( m_incoming ? relax( name ) : name,
233  m_incoming ? relax( value ) : value ) );
234  }
235 
236  void Tag::addAttribute( const std::string& name, int value )
237  {
238  if( !name.empty() )
239  {
240 #ifdef _WIN32_WCE
241  const int len = 4 + (int)std::log10( value ) + 1;
242  char *tmp = new char[len];
243  sprintf( tmp, "%d", value );
244  std::string ret( tmp, len );
245  addAttribute( name, ret );
246  delete[] tmp;
247 #else
248  std::ostringstream oss;
249  oss << value;
250  addAttribute( name, oss.str() );
251 #endif
252  }
253  }
254 
255  void Tag::addAttribute( const std::string& name, long value )
256  {
257  if( !name.empty() )
258  {
259 #ifdef _WIN32_WCE
260  const int len = 4 + (int)std::log10( value ) + 1;
261  char *tmp = new char[len];
262  sprintf( tmp, "%ld", value );
263  std::string ret( tmp, len );
264  addAttribute( name, ret );
265  delete[] tmp;
266 #else
267  std::ostringstream oss;
268  oss << value;
269  addAttribute( name, oss.str() );
270 #endif
271  }
272  }
273 
274  void Tag::addChild( Tag *child )
275  {
276  if( child )
277  {
278  m_children.push_back( child );
279  child->m_parent = this;
280  }
281  }
282 
283  void Tag::addChildCopy( const Tag *child )
284  {
285  if( child )
286  {
287  Tag *t = child->clone();
288  m_children.push_back( t );
289  t->m_parent = this;
290  }
291  }
292 
293  const std::string Tag::findAttribute( const std::string& name ) const
294  {
295  AttributeList::const_iterator it = m_attribs.begin();
296  for( ; it != m_attribs.end(); ++it )
297  if( (*it).first == ( m_incoming ? relax( name ) : name ) )
298  return (*it).second;
299 
300  return std::string();
301  }
302 
303  bool Tag::hasAttribute( const std::string& name, const std::string& value ) const
304  {
305  if( name.empty() )
306  return true;
307 
308  AttributeList::const_iterator it = m_attribs.begin();
309  for( ; it != m_attribs.end(); ++it )
310  if( (*it).first == ( m_incoming ? relax( name ) : name )
311  && ( value.empty() || (*it).second == ( m_incoming ? relax( value ) : value ) ) )
312  return true;
313 
314  return false;
315  }
316 
317  Tag* Tag::findChild( const std::string& name ) const
318  {
319  TagList::const_iterator it = m_children.begin();
320  while( it != m_children.end() && (*it)->name() != ( m_incoming ? relax( name ) : name ) )
321  ++it;
322  return it != m_children.end() ? (*it) : 0;
323  }
324 
325  Tag* Tag::findChild( const std::string& name, const std::string& attr,
326  const std::string& value ) const
327  {
328  if( name.empty() )
329  return 0;
330 
331  TagList::const_iterator it = m_children.begin();
332  while( it != m_children.end()
333  && ( (*it)->name() != ( m_incoming ? relax( name ) : name )
334  || ! (*it)->hasAttribute( attr, value ) ) )
335  ++it;
336  return it != m_children.end() ? (*it) : 0;
337  }
338 
339  bool Tag::hasChildWithCData( const std::string& name, const std::string& cdata ) const
340  {
341  TagList::const_iterator it = m_children.begin();
342  while( it != m_children.end() && ( (*it)->name() != ( m_incoming ? relax( name ) : name )
343  || ( !cdata.empty() && (*it)->cdata() != ( m_incoming ? relax( cdata ) : cdata ) ) ) )
344  ++it;
345  return it != m_children.end();
346  }
347 
348  Tag* Tag::findChildWithAttrib( const std::string& attr, const std::string& value ) const
349  {
350  TagList::const_iterator it = m_children.begin();
351  while( it != m_children.end() && ! (*it)->hasAttribute( attr, value ) )
352  ++it;
353  return it != m_children.end() ? (*it) : 0;
354  }
355 
356  Tag* Tag::clone() const
357  {
358  Tag *t = new Tag( name(), cdata(), m_incoming );
359  t->m_attribs = m_attribs;
360  t->m_type = m_type;
361 
362  Tag::TagList::const_iterator it = m_children.begin();
363  for( ; it != m_children.end(); ++it )
364  {
365  t->addChild( (*it)->clone() );
366  }
367 
368  return t;
369  }
370 
371  Tag::TagList Tag::findChildren( const std::string& name ) const
372  {
373  return findChildren( m_children, name );
374  }
375 
376  Tag::TagList Tag::findChildren( const Tag::TagList& list, const std::string& name ) const
377  {
378  Tag::TagList ret;
379  Tag::TagList::const_iterator it = list.begin();
380  for( ; it != list.end(); ++it )
381  {
382  if( (*it)->name() == ( m_incoming ? relax( name ) : name ) )
383  ret.push_back( (*it) );
384  }
385  return ret;
386  }
387 
388  Tag* Tag::findTag( const std::string& expression )
389  {
390  const Tag::TagList& l = findTagList( expression );
391  return !l.empty() ? l.front() : 0;
392  }
393 
394  Tag::TagList Tag::findTagList( const std::string& expression )
395  {
396  Tag::TagList l;
397  if( expression == "/" || expression == "//" )
398  return l;
399 
400  if( m_parent && expression.length() >= 2 && expression.substr( 0, 1 ) == "/"
401  && expression.substr( 1, 1 ) != "/" )
402  return m_parent->findTagList( expression );
403 
404  unsigned len = 0;
405  Tag *p = parse( expression, len );
406 // if( p )
407 // printf( "parsed tree: %s\n", p->xml().c_str() );
408  l = evaluateTagList( p );
409  delete p;
410  return l;
411  }
412 
413  Tag::TagList Tag::evaluateTagList( Tag *token )
414  {
415  Tag::TagList result;
416  if( !token )
417  return result;
418 
419 // printf( "evaluateTagList called in Tag %s and Token %s (type: %s)\n", name().c_str(),
420 // token->name().c_str(), token->findAttribute( "type" ).c_str() );
421 
422  TokenType tokenType = (TokenType)atoi( token->findAttribute( "type" ).c_str() );
423  switch( tokenType )
424  {
425  case XTUnion:
426  add( result, evaluateUnion( token ) );
427  break;
428  case XTElement:
429  {
430 // printf( "in XTElement, token: %s\n", token->name().c_str() );
431  if( token->name() == name() || token->name() == "*" )
432  {
433 // printf( "found %s\n", name().c_str() );
434  const Tag::TagList& tokenChildren = token->children();
435  if( tokenChildren.size() )
436  {
437  bool predicatesSucceeded = true;
438  Tag::TagList::const_iterator cit = tokenChildren.begin();
439  for( ; cit != tokenChildren.end(); ++cit )
440  {
441  if( (*cit)->hasAttribute( "predicate", "true" ) )
442  {
443  predicatesSucceeded = evaluatePredicate( (*cit) );
444  if( !predicatesSucceeded )
445  return result;
446  }
447  }
448 
449  bool hasElementChildren = false;
450  cit = tokenChildren.begin();
451  for( ; cit != tokenChildren.end(); ++cit )
452  {
453  if( (*cit)->hasAttribute( "predicate", "true" ) ||
454  (*cit)->hasAttribute( "number", "true" ) )
455  continue;
456 
457  hasElementChildren = true;
458 
459 // printf( "checking %d children of token %s\n", tokenChildren.size(), token->name().c_str() );
460  if( !m_children.empty() )
461  {
462  Tag::TagList::const_iterator it = m_children.begin();
463  for( ; it != m_children.end(); ++it )
464  {
465  add( result, (*it)->evaluateTagList( (*cit) ) );
466  }
467  }
468  else if( atoi( (*cit)->findAttribute( "type" ).c_str() ) == XTDoubleDot && m_parent )
469  {
470  (*cit)->addAttribute( "type", XTDot );
471  add( result, m_parent->evaluateTagList( (*cit) ) );
472  }
473  }
474 
475  if( !hasElementChildren )
476  result.push_back( this );
477  }
478  else
479  {
480 // printf( "adding %s to result set\n", name().c_str() );
481  result.push_back( this );
482  }
483  }
484 // else
485 // printf( "found %s != %s\n", token->name().c_str(), name().c_str() );
486 
487  break;
488  }
489  case XTDoubleSlash:
490  {
491 // printf( "in XTDoubleSlash\n" );
492  Tag *t = token->clone();
493 // printf( "original token: %s\ncloned token: %s\n", token->xml().c_str(), n->xml().c_str() );
494  t->addAttribute( "type", XTElement );
495  add( result, evaluateTagList( t ) );
496  const Tag::TagList& res2 = allDescendants();
497  Tag::TagList::const_iterator it = res2.begin();
498  for( ; it != res2.end(); ++it )
499  {
500  add( result, (*it)->evaluateTagList( t ) );
501  }
502  delete t;
503  break;
504  }
505  case XTDot:
506  {
507  const Tag::TagList& tokenChildren = token->children();
508  if( !tokenChildren.empty() )
509  {
510  add( result, evaluateTagList( tokenChildren.front() ) );
511  }
512  else
513  result.push_back( this );
514  break;
515  }
516  case XTDoubleDot:
517  {
518 // printf( "in XTDoubleDot\n" );
519  if( m_parent )
520  {
521  const Tag::TagList& tokenChildren = token->children();
522  if( tokenChildren.size() )
523  {
524  Tag *testtoken = tokenChildren.front();
525  if( testtoken->name() == "*" )
526  {
527  add( result, m_parent->evaluateTagList( testtoken ) );
528  }
529  else
530  {
531  Tag *t = token->clone();
532  t->addAttribute( "type", XTElement );
533  t->m_name = m_parent->m_name;
534  add( result, m_parent->evaluateTagList( t ) );
535  delete t;
536  }
537  }
538  else
539  {
540  result.push_back( m_parent );
541  }
542  }
543  }
544  case XTInteger:
545  {
546  const Tag::TagList& l = token->children();
547  if( !l.size() )
548  break;
549 
550  const Tag::TagList& res = evaluateTagList( l.front() );
551 
552  int pos = atoi( token->name().c_str() );
553 // printf( "checking index %d\n", pos );
554  if( pos > 0 && pos <= (int)res.size() )
555  {
556  Tag::TagList::const_iterator it = res.begin();
557  while ( --pos )
558  {
559  ++it;
560  }
561  result.push_back( *it );
562  }
563  break;
564  }
565  default:
566  break;
567  }
568  return result;
569  }
570 
571  bool Tag::evaluateBoolean( Tag *token )
572  {
573  if( !token )
574  return false;
575 
576  bool result = false;
577  TokenType tokenType = (TokenType)atoi( token->findAttribute( "type" ).c_str() );
578  switch( tokenType )
579  {
580  case XTAttribute:
581  if( token->name() == "*" && m_attribs.size() )
582  result = true;
583  else
584  result = hasAttribute( token->name() );
585  break;
586  case XTOperatorEq:
587  result = evaluateEquals( token );
588  break;
589  case XTOperatorLt:
590  break;
591  case XTOperatorLtEq:
592  break;
593  case XTOperatorGtEq:
594  break;
595  case XTOperatorGt:
596  break;
597  case XTUnion:
598  case XTElement:
599  {
600  Tag *t = new Tag( "." );
601  t->addAttribute( "type", XTDot );
602  t->addChild( token );
603  result = !evaluateTagList( t ).empty();
604  t->removeChild( token );
605  delete t;
606  break;
607  }
608  default:
609  break;
610  }
611 
612  return result;
613  }
614 
615  bool Tag::evaluateEquals( Tag *token )
616  {
617  if( !token || token->children().size() != 2 )
618  return false;
619 
620  bool result = false;
621  Tag::TagList::const_iterator it = token->children().begin();
622  Tag *ch1 = (*it);
623  Tag *ch2 = (*++it);
624 
625  TokenType tt1 = (TokenType)atoi( ch1->findAttribute( "type" ).c_str() );
626  TokenType tt2 = (TokenType)atoi( ch2->findAttribute( "type" ).c_str() );
627  switch( tt1 )
628  {
629  case XTAttribute:
630  switch( tt2 )
631  {
632  case XTInteger:
633  case XTLiteral:
634  result = ( findAttribute( ch1->name() ) == ch2->name() );
635  break;
636  case XTAttribute:
637  result = ( hasAttribute( ch1->name() ) && hasAttribute( ch2->name() ) &&
638  findAttribute( ch1->name() ) == findAttribute( ch2->name() ) );
639  break;
640  default:
641  break;
642  }
643  break;
644  case XTInteger:
645  case XTLiteral:
646  switch( tt2 )
647  {
648  case XTAttribute:
649  result = ( ch1->name() == findAttribute( ch2->name() ) );
650  break;
651  case XTLiteral:
652  case XTInteger:
653  result = ( ch1->name() == ch2->name() );
654  break;
655  default:
656  break;
657  }
658  break;
659  default:
660  break;
661  }
662 
663  return result;
664  }
665 
666  Tag::TagList Tag::allDescendants()
667  {
668  Tag::TagList result;
669  Tag::TagList::const_iterator it = m_children.begin();
670  for( ; it != m_children.end(); ++it )
671  {
672  result.push_back( (*it) );
673  add( result, (*it)->allDescendants() );
674  }
675  return result;
676  }
677 
678  Tag::TagList Tag::evaluateUnion( Tag *token )
679  {
680  Tag::TagList result;
681  if( !token )
682  return result;
683 
684  const Tag::TagList& l = token->children();
685  Tag::TagList::const_iterator it = l.begin();
686  for( ; it != l.end(); ++it )
687  {
688  add( result, evaluateTagList( (*it) ) );
689  }
690  return result;
691  }
692 
693  void Tag::closePreviousToken( Tag** root, Tag** current, Tag::TokenType& type, std::string& tok )
694  {
695  if( !tok.empty() )
696  {
697  addToken( root, current, type, tok );
698  type = XTElement;
699  tok = "";
700  }
701  }
702 
703  Tag* Tag::parse( const std::string& expression, unsigned& len, Tag::TokenType border )
704  {
705  Tag *root = 0;
706  Tag *current = root;
707  std::string token;
708 
709 // XPathError error = XPNoError;
710 // XPathState state = Init;
711 // int expected = 0;
712 // bool run = true;
713 // bool ws = false;
714 
715  Tag::TokenType type = XTElement;
716 
717  char c;
718  for( ; len < expression.length(); ++len )
719  {
720  c = expression[len];
721  if( type == XTLiteralInside && c != '\'' )
722  {
723  token += c;
724  continue;
725  }
726 
727  switch( c )
728  {
729  case '/':
730  closePreviousToken( &root, &current, type, token );
731 
732  if( len < expression.length()-1 && expression[len+1] == '/' )
733  {
734 // addToken( &root, &current, XTDoubleSlash, "//" );
735  type = XTDoubleSlash;
736  ++len;
737  }
738 // else
739 // {
740 // if( !current )
741 // addToken( &root, &current, XTSlash, "/" );
742 // }
743  break;
744  case ']':
745  closePreviousToken( &root, &current, type, token );
746  ++len;
747  return root;
748  case '[':
749  {
750  closePreviousToken( &root, &current, type, token );
751  Tag *t = parse( expression, ++len, XTRightBracket );
752  if( !addPredicate( &root, &current, t ) )
753  delete t;
754  break;
755  }
756  case '(':
757  {
758  closePreviousToken( &root, &current, type, token );
759  Tag *t = parse( expression, ++len, XTRightParenthesis );
760  if( current )
761  {
762 // printf( "added %s to %s\n", t->xml().c_str(), current->xml().c_str() );
763  t->addAttribute( "argument", "true" );
764  current->addChild( t );
765  }
766  else
767  {
768  root = t;
769 // printf( "made %s new root\n", t->xml().c_str() );
770  }
771  break;
772  }
773  case ')':
774  closePreviousToken( &root, &current, type, token );
775  ++len;
776  return root;
777  case '\'':
778  if( type == XTLiteralInside )
779  if( expression[len - 2] == '\\' )
780  token[token.length() - 2] = c;
781  else
782  type = XTLiteral;
783  else
784  type = XTLiteralInside;
785  break;
786  case '@':
787  type = XTAttribute;
788  break;
789  case '.':
790  token += c;
791  if( token.size() == 1 )
792  {
793  if( len < expression.length()-1 && expression[len+1] == '.' )
794  {
795  type = XTDoubleDot;
796  ++len;
797  token += c;
798  }
799  else
800  {
801  type = XTDot;
802  }
803  }
804  break;
805  case '*':
806 // if( !root || ( current && ( current->tokenType() == XTSlash
807 // || current->tokenType() == XTDoubleSlash ) ) )
808 // {
809 // addToken( &root, &current, type, "*" );
810 // break;
811 // }
812  addToken( &root, &current, type, "*" );
813  type = XTElement;
814  break;
815  case '+':
816  case '>':
817  case '<':
818  case '=':
819  case '|':
820  {
821  closePreviousToken( &root, &current, type, token );
822  std::string s( 1, c );
823  Tag::TokenType ttype = getType( s );
824  if( ttype <= border )
825  return root;
826  Tag *t = parse( expression, ++len, ttype );
827  addOperator( &root, &current, t, ttype, s );
828  if( border == XTRightBracket )
829  return root;
830  break;
831  }
832  default:
833  token += c;
834  }
835  }
836 
837  if( !token.empty() )
838  addToken( &root, &current, type, token );
839 
840 // if( error != XPNoError )
841 // printf( "error: %d\n", error );
842  return root;
843  }
844 
845  void Tag::addToken( Tag **root, Tag **current, Tag::TokenType type,
846  const std::string& token )
847  {
848  Tag *t = new Tag( token );
849  if( t->isNumber() && !t->children().size() )
850  type = XTInteger;
851  t->addAttribute( "type", type );
852 
853  if( *root )
854  {
855 // printf( "new current %s, type: %d\n", token.c_str(), type );
856  (*current)->addChild( t );
857  *current = t;
858  }
859  else
860  {
861 // printf( "new root %s, type: %d\n", token.c_str(), type );
862  *current = *root = t;
863  }
864  }
865 
866  void Tag::addOperator( Tag **root, Tag **current, Tag *arg,
867  Tag::TokenType type, const std::string& token )
868  {
869  Tag *t = new Tag( token );
870  t->addAttribute( "type", type );
871 // printf( "new operator: %s (arg1: %s, arg2: %s)\n", t->name().c_str(), (*root)->xml().c_str(),
872 // arg->xml().c_str() );
873  t->addAttribute( "operator", "true" );
874  t->addChild( *root );
875  t->addChild( arg );
876  *current = *root = t;
877  }
878 
879  bool Tag::addPredicate( Tag **root, Tag **current, Tag *token )
880  {
881  if( !*root || !*current )
882  return false;
883 
884  if( ( token->isNumber() && !token->children().size() ) || token->name() == "+" )
885  {
886 // printf( "found Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
887  if( !token->hasAttribute( "operator", "true" ) )
888  {
889  token->addAttribute( "type", XTInteger );
890  }
891  if( *root == *current )
892  {
893  *root = token;
894 // printf( "made Index new root\n" );
895  }
896  else
897  {
898  (*root)->removeChild( *current );
899  (*root)->addChild( token );
900 // printf( "added Index somewhere between root and current\n" );
901  }
902  token->addChild( *current );
903 // printf( "added Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
904  }
905  else
906  {
907  token->addAttribute( "predicate", "true" );
908  (*current)->addChild( token );
909  }
910 
911  return true;
912  }
913 
914  Tag::TokenType Tag::getType( const std::string& c )
915  {
916  if( c == "|" )
917  return XTUnion;
918  if( c == "<" )
919  return XTOperatorLt;
920  if( c == ">" )
921  return XTOperatorGt;
922  if( c == "*" )
923  return XTOperatorMul;
924  if( c == "+" )
925  return XTOperatorPlus;
926  if( c == "=" )
927  return XTOperatorEq;
928 
929  return XTNone;
930  }
931 
932  bool Tag::isWhitespace( const char c )
933  {
934  return ( c == 0x09 || c == 0x0a || c == 0x0d || c == 0x20 );
935  }
936 
937  bool Tag::isNumber()
938  {
939  if( m_name.empty() )
940  return false;
941 
942  std::string::size_type l = m_name.length();
943  std::string::size_type i = 0;
944  while( i < l && isdigit( m_name[i] ) )
945  ++i;
946  return i == l;
947  }
948 
949  void Tag::add( Tag::TagList& one, const Tag::TagList& two )
950  {
951  Tag::TagList::const_iterator it = two.begin();
952  for( ; it != two.end(); ++it )
953  if( std::find( one.begin(), one.end(), (*it) ) == one.end() )
954  one.push_back( (*it) );
955  }
956 
957 }