Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TSchemaRuleProcessor.h
Go to the documentation of this file.
1 // @(#)root/core:$Id$
2 // author: Lukasz Janyst <ljanyst@cern.ch>
3 
4 #ifndef ROOT_TSchemaRuleProcessor
5 #define ROOT_TSchemaRuleProcessor
6 
7 // NOTE: #included by libCore and libCling. All symbols must be inline.
8 
9 #include <stdlib.h>
10 #include <cstring>
11 #include <string>
12 #include <list>
13 #include <utility>
14 #include <cstdlib>
15 #include <iostream>
16 #include <algorithm>
17 #include "RtypesCore.h"
18 
19 #include "TSchemaType.h"
20 
21 namespace ROOT {
22 namespace Internal {
23  class TSchemaRuleProcessor
24  {
25  public:
26  //---------------------------------------------------------------------
27  static void SplitList( const std::string& source,
28  std::list<std::string>& result,
29  char delimiter=',')
30  {
31  // Split the string producing a list of substrings
32 
33  std::string::size_type curr;
34  std::string::size_type last = 0;
35  std::string::size_type size;
36  std::string elem;
37 
38  result.clear();
39 
40  while( last != source.size() ) {
41  curr = source.find( delimiter, last );
42 
43  if( curr == std::string::npos ) {
44  curr = source.size()-1;
45  size = curr-last+1;
46  }
47  else size = curr-last;
48 
49  elem = Trim( source.substr( last, size ) );
50  if( !elem.empty() )
51  result.push_back( elem );
52 
53  last = curr+1;
54  }
55  }
56 
57  static void SplitDeclaration( const std::string& source,
58  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> >& result)
59  {
60  // Split a declaration string producing a list of substrings
61  // Typically we have:
62  // int mem; SomeType mem2; SomeTmp<const key, const value> mem3;
63 
64  std::string::size_type curr;
65  std::string::size_type last = 0;
66  std::string::size_type size;
67  std::string elem;
68  std::string type;
69  std::string dims;
70 
71  result.clear();
72 
73  while( last != source.size() ) {
74  // Split on semi-colons.
75  curr = source.find( ';', last );
76 
77  if( curr == std::string::npos ) {
78  curr = source.size()-1;
79  size = curr-last+1;
80  }
81  else size = curr-last;
82 
83  // Extra spaces.
84  elem = Trim( source.substr( last, size ) );
85  if( !elem.empty() ) {
86  unsigned int level = 0;
87 
88  // Split between the typename and the membername
89  // Take in consideration template names.
90  for(std::string::size_type j=elem.size(); j>0; --j) {
91  std::string::size_type i = j-1;
92  if (elem[i]=='<') { ++level; }
93  else if (elem[i]=='>') { if (level==0) { continue; } ; --level; }
94  else if (level == 0 && isspace(elem[i])) {
95  type = elem.substr( 0, i );
96  // At the first iteration we know we have a space.
97  while( elem[i]=='*' || elem[i]=='&' || isspace(elem[i]) ) {
98  ++i;
99  if (strcmp("const",elem.c_str()+i)==0 && (i+5)>elem.size()
100  && ( elem[i+5]=='*' || elem[i+5]=='&' || isspace(elem[i+5])) ) {
101  i += 5;
102  type += "const ";
103  } else if (elem[i]=='*' || elem[i]=='&') {
104  type += elem[i];
105  }
106  }
107  std::string::size_type endvar = i;
108  while( endvar!=elem.size() && elem[endvar] != '[' ) {
109  ++endvar;
110  }
111  if (endvar != elem.size() ) {
112  dims = Trim( elem.substr(endvar, elem.size()-endvar) );
113  }
114  elem = Trim( elem.substr(i, endvar-i) );
115  break;
116  }
117  }
118  result.push_back( make_pair(ROOT::Internal::TSchemaType(type,dims),elem) );
119  }
120  last = curr+1;
121  }
122  }
123 
124  //---------------------------------------------------------------------
125  static std::string Trim( const std::string& source )
126  {
127  // Trim the whitespaces at the beginning and at the end of
128  // given source string
129 
130  std::string::size_type start, end;
131  for( start = 0; start < source.size(); ++start) {
132  if ( isspace(source[start]) ) {
133  continue;
134  } else if ( source[start] == '\\' && (start+1)<source.size() && (source[start+1]=='\n' || source[start+1]=='\r') ) {
135  ++start;
136  continue;
137  } else {
138  // Not a white space.
139  break;
140  }
141  }
142  if( start == source.size() )
143  return "";
144  for( end = source.size()-1; end > start; --end ) {
145  if ( (source[end]=='\n' || source[end]=='\r') && end > (start+1) && source[end-1] == '\\' ) {
146  --end;
147  continue;
148  } else if ( isspace(source[end]) ) {
149  continue;
150  } else {
151  // Not a white space.
152  break;
153  }
154  }
155  return source.substr( start, end-start+1 );
156  }
157 
158  //---------------------------------------------------------------------
159  static bool ProcessVersion( const std::string& source,
160  std::pair<Int_t, Int_t>& result )
161  {
162  // Check if a version is specified correctly
163  // The result is set the following way:
164  // x : first = x second = x
165  // -x : first = -10 second = x
166  // x-y : first = x second = y
167  // x- : first = x second = 50000
168  // if the given string is invalid (false is returned)
169  // then the state of the result is undefined
170 
171  std::string::size_type hyphenI;
172  std::string first;
173  std::string second;
174 
175  std::string version = Trim( source );
176 
177  if( version.empty() )
178  return false;
179 
180  //------------------------------------------------------------------
181  // Do we have a star?
182  //------------------------------------------------------------------
183  if( version == "*" ) {
184  result.first = -10;
185  result.second = 50000;
186  return true;
187  }
188 
189  //------------------------------------------------------------------
190  // Check if we have a minus somewhere, if not then single version
191  // number was specified
192  //------------------------------------------------------------------
193  hyphenI = version.find( '-' );
194  if( hyphenI == std::string::npos && IsANumber( version ) ) {
195  result.first = result.second = atoi( version.c_str() );
196  return true;
197  }
198 
199  //------------------------------------------------------------------
200  // We start with the hyphen
201  //------------------------------------------------------------------
202  if( hyphenI == 0 ) {
203  second = Trim( version.substr( 1 ) );
204  if( IsANumber( second ) ) {
205  result.first = -10;
206  result.second = atoi( second.c_str() );
207  return true;
208  }
209  }
210 
211  //------------------------------------------------------------------
212  // We end with the hyphen
213  //------------------------------------------------------------------
214  if( hyphenI == version.size()-1 ) {
215  first = Trim( version.substr( 0, version.size()-1 ) );
216  if( IsANumber( first ) ) {
217  result.first = atoi( first.c_str() );
218  result.second = 50000;
219  return true;
220  }
221  }
222 
223  //------------------------------------------------------------------
224  // We have the hyphen somewhere in the middle
225  //------------------------------------------------------------------
226  first = Trim( version.substr( 0, hyphenI ) );
227  second = Trim( version.substr( hyphenI+1, version.size()-hyphenI-1 ) );
228  if( IsANumber( first ) && IsANumber( second ) ) {
229  result.first = atoi( first.c_str() );
230  result.second = atoi( second.c_str() );
231  return true;
232  }
233 
234  return false;
235  }
236 
237  //---------------------------------------------------------------------
238  /// Check if given string consists of digits.
239  static bool IsANumber( const std::string& source, bool acceptHex = false )
240  {
241  if( source.empty() )
242  return false;
243 
244  if( acceptHex && source.size() > 2 && source[0] == '0' && source[1] == 'x'
245  && std::all_of(source.begin()+2, source.end(), [](unsigned char c){return std::isxdigit(c);}) )
246  return true;
247 
248  return std::all_of(source.begin(), source.end(), [](unsigned char c){return std::isdigit(c);});
249  }
250  };
251 } // namespace Internal
252 } // namespace ROOT
253 
254 #endif // ROOT_TSchemaRuleProcessor