Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RConversionRuleParser.cxx
Go to the documentation of this file.
1 // @(#)root/core:$Id$
2 /// \file RConversionRuleParser.cxx
3 /// \ingroup Base
4 /// \author Victor Perev
5 /// \author Philippe Canal
6 /// \date 04/10/2003
7 
8 /*************************************************************************
9  * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10  * All rights reserved. *
11  * *
12  * For the licensing terms see $ROOTSYS/LICENSE. *
13  * For the list of contributors see $ROOTSYS/README/CREDITS. *
14  *************************************************************************/
15 
16 #include "RConversionRuleParser.h"
17 #include "TSchemaRuleProcessor.h"
18 #include "TClassEdit.h"
19 
20 #include <algorithm>
21 #include <iostream>
22 #include <map>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 namespace {
29  static void RemoveEscapeSequences(std::string& rawString)
30  {
31  const std::vector<std::pair<std::string, std::string>> subPairs { {"\\\\","\\"},
32  {"\\\"","\""},
33  {"\\\'","\'"}};
34  size_t start_pos = 0;
35  for (auto const & subPair : subPairs){
36  start_pos = 0;
37  auto from = subPair.first;
38  auto to = subPair.second;
39  while((start_pos = rawString.find(from, start_pos)) != std::string::npos) {
40  rawString.replace(start_pos, from.length(), to);
41  start_pos += to.length();
42  }
43  }
44  }
45 }
46 
47 namespace ROOT
48 {
49  using namespace Internal;
50 
51  typedef std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > SourceTypeList_t;
52 
53  //--------------------------------------------------------------------------
54  // Allocate global variables
55  /////////////////////////////////////////////////////////////////////////////
56 
57  SchemaRuleClassMap_t gReadRules;
58  SchemaRuleClassMap_t gReadRawRules;
59 
60  static Bool_t ValidateRule( const std::map<std::string, std::string>& rule, std::string &error_string );
61 
62  static std::string::size_type FindEndSymbol(std::string &command)
63  {
64  // Find the end of a symbol.
65 
66  if (command.length() == 0) return std::string::npos;
67  std::string::size_type cursor;
68  unsigned int level = 0;
69  for (cursor = 0 ; cursor < command.length(); ++cursor)
70  {
71  switch( command[cursor] ) {
72  case ' ':
73  case '\t':
74  case '\r':
75  case '=': if (level==0) {
76  std::string::size_type sub_cursor = cursor;
77  while( isspace(command[sub_cursor]) ) {
78  ++sub_cursor;
79  }
80  if ( command[sub_cursor] == '=' ) {
81  return sub_cursor;
82  } else {
83  return cursor;
84  }
85  } else {
86  break;
87  }
88  case '<': ++level; break;
89  case '>': if (level==0) { return std::string::npos; }
90  --level; break;
91  default: {
92  // nothing to do
93  }
94  };
95  }
96  return cursor;
97  }
98 
99 
100  /////////////////////////////////////////////////////////////////////////////
101  /// Parse the schema rule as specified in the LinkDef file
102 
103  Bool_t ParseRule( std::string command,
104  ROOT::Internal::MembersMap_t &result,
105  std::string &error_string )
106  {
107  std::string::size_type l=0;
108  command = TSchemaRuleProcessor::Trim( command );
109 
110  //-----------------------------------------------------------------------
111  // Remove the semicolon from the end if declared
112  //////////////////////////////////////////////////////////////////////////
113 
114  if( command[command.size()-1] == ';' )
115  command = command.substr( 0, command.size()-1 );
116 
117  //-----------------------------------------------------------------------
118  // If the first symbol does not end is not followed by equal then it
119  // defaults to being the sourceClass.
120  //////////////////////////////////////////////////////////////////////////
121 
122  {
123  std::string::size_type endsymbol = FindEndSymbol( command );
124  if ( endsymbol == command.length() || command[endsymbol] == ' ' || command[endsymbol] == '\t' ) {
125 
126 // std::string::size_type space_pos = command.find( ' ' );
127 // std::string::size_type equal_pos = command.find( '=' );
128 // if ( space_pos < equal_pos) {
129  std::string value = TSchemaRuleProcessor::Trim( command.substr( 0, endsymbol ) );
130  result["sourceClass"] = value;
131  result["targetClass"] = value;
132  if (endsymbol < command.length()) {
133  command = TSchemaRuleProcessor::Trim( command.substr( endsymbol+1 ) );
134  } else {
135  command.clear();
136  }
137 
138  //-----------------------------------------------------------------------
139  // If the first symbol is the targetClass then the 2nd symbol can be
140  // the source data member name.
141  //-----------------------------------------------------------------------
142 // space_pos = command.find( ' ' );
143 // equal_pos = command.find( '=' );
144 // if ( space_pos < equal_pos ) {
145  endsymbol = FindEndSymbol( command );
146  if ( endsymbol == command.length() || command[endsymbol] == ' ' || command[endsymbol] == '\t' ) {
147  std::string membervalue = TSchemaRuleProcessor::Trim( command.substr( 0, endsymbol ) );
148  result["source"] = membervalue;
149  result["target"] = membervalue;
150  command = TSchemaRuleProcessor::Trim( command.substr( endsymbol+1 ) );
151  }
152  }
153  }
154 
155  //-----------------------------------------------------------------------
156  // Process the input until there are no characters left
157  //////////////////////////////////////////////////////////////////////////
158 
159  while( !command.empty() ) {
160  //--------------------------------------------------------------------
161  // Find key token
162  ///////////////////////////////////////////////////////////////////////
163 
164  std::string::size_type pos = command.find( '=' );
165 
166  //--------------------------------------------------------------------
167  // No equality sign found - no keys left
168  ///////////////////////////////////////////////////////////////////////
169 
170  if( pos == std::string::npos ) {
171  error_string = "Parsing error, no key found!";
172  return false;
173  }
174 
175  //--------------------------------------------------------------------
176  // The key was found - process the arguments
177  ///////////////////////////////////////////////////////////////////////
178 
179  std::string key = TSchemaRuleProcessor::Trim( command.substr( 0, pos ) );
180  command = TSchemaRuleProcessor::Trim( command.substr( pos+1 ) );
181 
182  //--------------------------------------------------------------------
183  // Nothing left to be processed
184  ///////////////////////////////////////////////////////////////////////
185 
186  if( command.size() < 1 ) {
187  error_string = "Parsing error, wrond or no value specified for key: " + key;
188  return false;
189  }
190 
191  Bool_t hasquote = command[0] == '"';
192 
193  //--------------------------------------------------------------------
194  // Processing code tag: "{ code }"
195  ///////////////////////////////////////////////////////////////////////
196 
197  if( key == "code" ) {
198  if( command[1] != '{' ) {
199  error_string = "Parsing error while processing key: code\n";
200  error_string += "Expected \"{ at the beginning of the value.";
201  return false;
202  }
203  l = command.find( "}\"" );
204  if( l == std::string::npos ) {
205  error_string = "Parsing error while processing key: \"" + key + "\"\n";
206  error_string += "Expected }\" at the end of the value.";
207  return false;
208  }
209  auto rawCode = command.substr( 2, l-2 );
210  RemoveEscapeSequences(rawCode);
211  result[key] = rawCode;
212  ++l;
213  }
214  //--------------------------------------------------------------------
215  // Processing normal tag: "value"
216  ///////////////////////////////////////////////////////////////////////
217 
218  else {
219  if( hasquote) {
220  l = command.find( '"', 1 );
221  if (l == std::string::npos ) {
222  error_string = "\nParsing error while processing key: \"" + key + "\"\n";
223  error_string += "Expected \" at the end of the value.";
224  return false;
225  }
226  result[key] = command.substr( 1, l-1 );
227  } else {
228  l = command.find(' ', 1);
229  if (l == std::string::npos) l = command.size();
230  result[key] = command.substr( 0, l );
231  }
232  }
233 
234  //--------------------------------------------------------------------
235  // Everything went ok
236  ///////////////////////////////////////////////////////////////////////
237 
238  if( l == command.size() )
239  break;
240  command = command.substr( l+1 );
241  }
242  std::map<std::string, std::string>::const_iterator it1;
243  it1 = result.find("oldtype");
244  if ( it1 != result.end() ) {
245  std::map<std::string, std::string>::const_iterator it2;
246  it2 = result.find("source");
247  if ( it2 != result.end() ) {
248  result["source"] = it1->second + " " + it2->second;
249  }
250  }
251  if ( result.find("version") == result.end() && result.find("checksum") == result.end() ) {
252  result["version"] = "[1-]";
253  }
254 
255  //------------------------------------------------------------------------
256  // "include" tag. Replace ";" with "," for backwards compatibility with
257  // ROOT5
258  //////////////////////////////////////////////////////////////////////////
259 
260  auto const includeKeyName = "include";
261  auto includeTag = result.find(includeKeyName);
262  if (includeTag != result.end()){
263  auto & includeTagValue = includeTag->second;
264  std::replace_if (includeTagValue.begin(),
265  includeTagValue.end(),
266  [](char c){ return c == ';';},
267  ',');
268  result[includeKeyName] = includeTagValue;
269  }
270 
271  return ValidateRule( result, error_string);
272  }
273 
274  /////////////////////////////////////////////////////////////////////////////
275  /// Validate if the user specified rules are correct
276 
277  static Bool_t ValidateRule( const std::map<std::string, std::string>& rule, std::string &error_string )
278  {
279  //-----------------------------------------------------------------------
280  // Check if we have target class name
281  //////////////////////////////////////////////////////////////////////////
282 
283  std::map<std::string, std::string>::const_iterator it1, it2;
284  std::list<std::string> lst;
285 
286  it1 = rule.find( "targetClass" );
287  if( it1 == rule.end() ) {
288  error_string = "You always have to specify the targetClass ";
289  error_string += "when specyfying an IO rule";
290  return false;
291  }
292 
293  std::string className = TSchemaRuleProcessor::Trim( it1->second );
294  std::string warning = "IO rule for class " + className;
295 
296  //-----------------------------------------------------------------------
297  // Check if we have the source tag
298  //////////////////////////////////////////////////////////////////////////
299 
300  it1 = rule.find( "sourceClass" );
301  if( it1 == rule.end())
302  {
303  error_string = warning + " - sourceClass parameter is missing";
304  return false;
305  }
306 
307  //-----------------------------------------------------------------------
308  // Check if we have either version or checksum specified
309  //////////////////////////////////////////////////////////////////////////
310 
311  it1 = rule.find( "version" );
312  it2 = rule.find( "checksum" );
313  if( it1 == rule.end() && it2 == rule.end() ) {
314  error_string = warning + " - you need to specify either version or ";
315  error_string += "checksum";
316  return false;
317  }
318 
319  //-----------------------------------------------------------------------
320  // Check if the checksum has been set to right value
321  //////////////////////////////////////////////////////////////////////////
322 
323  if( it2 != rule.end() ) {
324  if( it2->second.size() < 2 || it2->second[0] != '[' ||
325  it2->second[it2->second.size()-1] != ']' ) {
326  error_string = warning + " - a comma separated list of ints";
327  error_string += " enclosed in square brackets expected";
328  error_string += " as a value of checksum parameter";
329  return false;
330  }
331 
332  TSchemaRuleProcessor::SplitList( it2->second.substr( 1, it2->second.size()-2 ),
333  lst );
334  if( lst.empty() ) {
335  error_string += warning + " - the list of checksums is empty\n";
336  }
337 
338  for( const auto& chk : lst ) {
339  if( !TSchemaRuleProcessor::IsANumber(chk, true) ) {
340  error_string = warning + " - " + chk + " is not a valid value";
341  error_string += " of checksum parameter - an integer (decimal/hex) expected";
342  return false;
343  }
344  }
345  }
346 
347  //-----------------------------------------------------------------------
348  // Check if the version is correct
349  //////////////////////////////////////////////////////////////////////////
350 
351  std::pair<Int_t, Int_t> ver;
352  if( it1 != rule.end() ) {
353  if( it1->second.size() < 2 || it1->second[0] != '[' ||
354  it1->second[it1->second.size()-1] != ']' ) {
355  error_string = warning + " - a comma separated list of version specifiers ";
356  error_string += "enclosed in square brackets expected";
357  error_string += "as a value of version parameter";
358  return false;
359  }
360 
361  TSchemaRuleProcessor::SplitList( it1->second.substr( 1, it1->second.size()-2 ),
362  lst );
363  if( lst.empty() ) {
364  error_string = warning + " - the list of versions is empty";
365  }
366 
367  for( const auto& version : lst )
368  if( !TSchemaRuleProcessor::ProcessVersion( version, ver ) ) {
369  error_string = warning + " - " + version + " is not a valid value";
370  error_string += " of version parameter";
371  return false;
372  }
373  }
374 
375  //-----------------------------------------------------------------------
376  // Check if we're dealing with renameing declaration - sourceClass,
377  // targetClass and either version or checksum required
378  //////////////////////////////////////////////////////////////////////////
379 
380  if( rule.size() == 3 || (rule.size() == 4 && it1 != rule.end() && it2 != rule.end()) )
381  return true;
382 
383  //-----------------------------------------------------------------------
384  // Check if we have all the keys we need
385  //-----------------------------------------------------------------------
386  std::string keys[] = {"target", "source"};
387  for( int i = 0; i < 2; ++i ) {
388  it1 = rule.find( keys[i] );
389  if( it1 == rule.end() ) {
390  error_string = warning + " - required parameter is missing: ";
391  error_string += keys[i];
392  return false;
393  }
394  }
395 
396  //-----------------------------------------------------------------------
397  // Check the source contains proper declarations.
398  //////////////////////////////////////////////////////////////////////////
399 
400  it1 = rule.find("code");
401  if (it1 != rule.end() && it1->second != "") {
402  SourceTypeList_t source;
403  TSchemaRuleProcessor::SplitDeclaration( rule.find("source")->second, source );
404  SourceTypeList_t::const_iterator it;
405  for( it = source.begin(); it != source.end(); ++it ) {
406  if ( ( it->first.fType == "" && it->second != "") ) {
407  error_string = warning + " - type required when listing a rule's source: ";
408  error_string += "source=\""+ rule.find("source")->second +"\"";
409  return false;
410  }
411  }
412  }
413 
414  //-----------------------------------------------------------------------
415  // Check if we have an embed parameter and if so if it has been set to
416  // the right value
417  //////////////////////////////////////////////////////////////////////////
418 
419  it1 = rule.find( "embed" );
420  if( it1 != rule.end() ) {
421  std::string emValue = TSchemaRuleProcessor::Trim( it1->second );
422  if( emValue != "true" && emValue != "false" ) {
423  error_string = warning + " - true or false expected as a value ";
424  error_string += "of embed parameter";
425  return false;
426  }
427  }
428 
429  //-----------------------------------------------------------------------
430  // Check if the include list is not empty
431  //////////////////////////////////////////////////////////////////////////
432 
433  it1 = rule.find( "include" );
434  if( it1 != rule.end() ) {
435  if( it1->second.empty() ) {
436  error_string = warning + " - the include list is empty";
437  return false;
438  }
439  }
440 
441  return true;
442  }
443 
444  /////////////////////////////////////////////////////////////////////////////
445  /// Check if given rule contains references to valid data members
446 
447  Bool_t HasValidDataMembers(SchemaRuleMap_t& rule,
448  MembersTypeMap_t& members,
449  std::string& error_string)
450  {
451  std::list<std::string> mem;
452  std::list<std::string>::iterator it;
453  // MembersMap_t::iterator rIt;
454 
455  TSchemaRuleProcessor::SplitList( rule["target"], mem );
456 
457  //-----------------------------------------------------------------------
458  // Loop over the data members
459  //////////////////////////////////////////////////////////////////////////
460 
461  for( it = mem.begin(); it != mem.end(); ++it ) {
462  if( members.find( *it ) == members.end() ) {
463  error_string += "IO rule for class " + rule["targetClass"]
464  + " data member: " + *it + " was specified as a "
465  "target in the rule but doesn't seem to appear in "
466  "target class\n";
467  return false;
468  }
469  }
470  return true;
471  }
472 
473  /////////////////////////////////////////////////////////////////////////////
474  /// Write down the sources
475 
476  static void WriteAutoVariables( const std::list<std::string>& target,
477  const SourceTypeList_t& source,
478  MembersTypeMap_t& members,
479  std::string& className, std::string& mappedName,
480  std::ostream& output )
481  {
482  if (!source.empty()) {
483  Bool_t start = true;
484  SourceTypeList_t::const_iterator it;
485 
486  //--------------------------------------------------------------------
487  // Write IDs and check if we should generate the onfile structure
488  // this is done if the type was declared
489  ///////////////////////////////////////////////////////////////////////
490 
491  Bool_t generateOnFile = false;
492  output << "#if 0" << std::endl; // this is to be removed later
493  for( it = source.begin(); it != source.end(); ++it ) {
494  output << " ";
495  output << "static Int_t id_" << it->second << " = oldObj->GetId(";
496  output << "\"" << it->second << "\");" << std::endl;
497 
498  if( it->first.fType != "" )
499  generateOnFile = true;
500  }
501  output << "#endif" << std::endl; // this is to be removed later
502 
503  //--------------------------------------------------------------------
504  // Declare the on-file structure - if needed
505  ///////////////////////////////////////////////////////////////////////
506 
507  if( generateOnFile ) {
508  std::string onfileStructName = mappedName + "_Onfile";
509  output << " ";
510  output << "struct " << onfileStructName << " {\n";
511 
512  //-----------------------------------------------------------------
513  // List the data members with non-empty type declarations
514  ////////////////////////////////////////////////////////////////////
515  /// fprintf(stderr, "Seeing %s %s %s\n", it->first.fType.c_str(), it->second.c_str(), it->first.fDimensions.c_str());
516 
517  for( it = source.begin(); it != source.end(); ++it ) {
518  if( it->first.fType.size() ) {
519  if ( it->first.fDimensions.size() ) {
520  output << " typedef " << it->first.fType;
521  output << " onfile_" << it->second << "_t" << it->first.fDimensions << ";\n";
522  output << " ";
523  output << "onfile_" << it->second << "_t &" << it->second << ";\n";
524 
525  } else {
526  output << " ";
527  output << it->first.fType << " &" << it->second << ";\n";
528  }
529  }
530  }
531 
532  //-----------------------------------------------------------------
533  // Generate the constructor
534  ////////////////////////////////////////////////////////////////////
535 
536  output << " " << onfileStructName << "(";
537  for( start = true, it = source.begin(); it != source.end(); ++it ) {
538  if( it->first.fType.size() == 0)
539  continue;
540 
541  if( !start )
542  output << ", ";
543  else
544  start = false;
545 
546  if (it->first.fDimensions.size() == 0) {
547  output << it->first.fType << " &onfile_" << it->second;
548  } else {
549  output << " onfile_" << it->second << "_t" << " &onfile_" << it->second;
550  }
551  }
552  output << " ): ";
553 
554  //-----------------------------------------------------------------
555  // Generate the constructor's initializer list
556  ////////////////////////////////////////////////////////////////////
557 
558  for( start = true, it = source.begin(); it != source.end(); ++it ) {
559  if( it->first.fType == "" )
560  continue;
561 
562  if( !start )
563  output << ", ";
564  else
565  start = false;
566 
567  output << it->second << "(onfile_" << it->second << ")";
568  }
569  output << " {}\n";
570  output << " " << "};\n";
571 
572  //-----------------------------------------------------------------
573  // Initialize the structure - to be changed later
574  ////////////////////////////////////////////////////////////////////
575 
576  for( it = source.begin(); it != source.end(); ++it ) {
577  output << " ";
578  output << "static Long_t offset_Onfile_" << mappedName;
579  output << "_" << it->second << " = oldObj->GetClass()->GetDataMemberOffset(\"";
580  output << it->second << "\");\n";
581  }
582  output << " " << "char *onfile_add = (char*)oldObj->GetObject();\n";
583  output << " " << mappedName << "_Onfile onfile(\n";
584 
585  for( start = true, it = source.begin(); it != source.end(); ++it ) {
586  if( it->first.fType == "" )
587  continue;
588 
589  if( !start )
590  output << ",\n";
591 
592  else
593  start = false;
594 
595  output << " ";
596  output << "*(";
597  if (it->first.fDimensions.size() == 0) {
598  output << it->first.fType;
599  } else {
600  output << mappedName << "_Onfile::onfile_" << it->second << "_t";
601  }
602  output << "*)(onfile_add+offset_Onfile_";
603  output << mappedName << "_" << it->second << ")";
604  }
605  output << " );\n\n";
606  }
607  }
608 
609  //-----------------------------------------------------------------------
610  // Write down the targets
611  //////////////////////////////////////////////////////////////////////////
612 
613  if( !target.empty() ) {
614  output << " static TClassRef cls(\"";
615  output << className << "\");" << std::endl;
616 
617  std::list<std::string>::const_iterator it;
618  for( it = target.begin(); it != target.end(); ++it ) {
619  Internal::TSchemaType memData = members[*it];
620  output << " static Long_t offset_" << *it << " = ";
621  output << "cls->GetDataMemberOffset(\"" << *it << "\");";
622  output << std::endl;
623  if (memData.fDimensions.size()) {
624  output << " typedef " << memData.fType << " " << *it << "_t" << memData.fDimensions << ";" << std::endl;
625  output << " " << *it << "_t& " << *it << " = ";
626  output << "*(" << *it << "_t *)(target+offset_" << *it;
627  output << ");" << std::endl;
628  } else {
629  output << " " << memData.fType << "& " << *it << " = ";
630  output << "*(" << memData.fType << "*)(target+offset_" << *it;
631  output << ");" << std::endl;
632  }
633  }
634  }
635  }
636 
637  /////////////////////////////////////////////////////////////////////////////
638  /// Write the conversion function for Read rule, the function name
639  /// is being written to rule["funcname"]
640 
641  void WriteReadRuleFunc( SchemaRuleMap_t& rule, int index,
642  std::string& mappedName, MembersTypeMap_t& members,
643  std::ostream& output )
644  {
645  std::string className = rule["targetClass"];
646 
647  //-----------------------------------------------------------------------
648  // Create the function name
649  //////////////////////////////////////////////////////////////////////////
650 
651  std::ostringstream func;
652  func << "read_" << mappedName << "_" << index;
653  rule["funcname"] = func.str();
654 
655  //-----------------------------------------------------------------------
656  // Write the header
657  //////////////////////////////////////////////////////////////////////////
658 
659  output << " static void " << func.str();
660  output << "( char* target, TVirtualObject *oldObj )" << std::endl;
661  output << " {" << std::endl;
662  output << " //--- Automatically generated variables ---" << std::endl;
663 
664  //-----------------------------------------------------------------------
665  // Write the automatically generated variables
666  //////////////////////////////////////////////////////////////////////////
667 
668  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > source;
669  std::list<std::string> target;
670  TSchemaRuleProcessor::SplitDeclaration( rule["source"], source );
671  TSchemaRuleProcessor::SplitList( rule["target"], target );
672 
673  WriteAutoVariables( target, source, members, className, mappedName, output );
674  output << " " << className << "* newObj = (" << className;
675  output << "*)target;" << std::endl;
676  output << " // Supress warning message.\n";
677  output << " " << "(void)oldObj;\n\n";
678  output << " " << "(void)newObj;\n\n";
679 
680  //-----------------------------------------------------------------------
681  // Write the user's code
682  //////////////////////////////////////////////////////////////////////////
683 
684  output << " //--- User's code ---" << std::endl;
685  output << " " << rule["code"] << std::endl;
686  output << " }" << std::endl;
687  }
688 
689 
690  /////////////////////////////////////////////////////////////////////////////
691  /// Write the conversion function for ReadRaw rule, the function name
692  /// is being written to rule["funcname"]
693 
694  void WriteReadRawRuleFunc( SchemaRuleMap_t& rule, int index,
695  std::string& mappedName, MembersTypeMap_t& members,
696  std::ostream& output )
697  {
698  std::string className = rule["targetClass"];
699 
700  //-----------------------------------------------------------------------
701  // Create the function name
702  //////////////////////////////////////////////////////////////////////////
703 
704  std::ostringstream func;
705  func << "readraw_" << mappedName << "_" << index;
706  rule["funcname"] = func.str();
707 
708  //-----------------------------------------------------------------------
709  // Write the header
710  //////////////////////////////////////////////////////////////////////////
711 
712  output << " static void " << func.str();
713  output << "( char* target, TBuffer &b )" << std::endl;
714  output << " {" << std::endl;
715  output << "#if 0" << std::endl;
716  output << " //--- Automatically generated variables ---" << std::endl;
717 
718  //-----------------------------------------------------------------------
719  // Write the automatically generated variables
720  //////////////////////////////////////////////////////////////////////////
721 
722  std::list<std::pair<ROOT::Internal::TSchemaType,std::string> > source;
723  std::list<std::string> target;
724  TSchemaRuleProcessor::SplitList( rule["target"], target );
725 
726  WriteAutoVariables( target, source, members, className, mappedName, output );
727  output << " " << className << "* newObj = (" << className;
728  output << "*)target;" << std::endl << std::endl;
729 
730  //-----------------------------------------------------------------------
731  // Write the user's code
732  //////////////////////////////////////////////////////////////////////////
733 
734  output << " //--- User's code ---" << std::endl;
735  output << rule["code"] << std::endl;
736  output << "#endif" << std::endl;
737  output << " }" << std::endl;
738  }
739 
740  /////////////////////////////////////////////////////////////////////////////
741  /// Replace all accurances of given string with other string
742 
743  static void StrReplace( std::string& proc, const std::string& pat,
744  const std::string& tr )
745  {
746  std::string::size_type it = 0;
747  std::string::size_type s = pat.size();
748  std::string::size_type tr_len= tr.size();
749 
750  if( s == 0 ) return;
751 
752  while( 1 ) {
753  it = proc.find( pat, it );
754  if( it == std::string::npos )
755  break;
756 
757  proc.replace( it, s, tr );
758  it += tr_len;
759  }
760  }
761 
762  /////////////////////////////////////////////////////////////////////////////
763  /// Write schema rules
764 
765  void WriteSchemaList( std::list<SchemaRuleMap_t>& rules,
766  const std::string& listName, std::ostream& output )
767  {
768  std::list<SchemaRuleMap_t>::iterator it;
769  int i = 0;
770 
771  //-----------------------------------------------------------------------
772  // Loop over the rules
773  //////////////////////////////////////////////////////////////////////////
774 
775  for( it = rules.begin(); it != rules.end(); ++it ) {
776  output << " rule = &" << listName << "[" << i++;
777  output << "];" << std::endl;
778 
779  //--------------------------------------------------------------------
780  // Write down the mandatory fields
781  ///////////////////////////////////////////////////////////////////////
782 
783  output << " rule->fSourceClass = \"" << (*it)["sourceClass"];
784  output << "\";" << std::endl;
785 
786  if( it->find( "target" ) != it->end() ) {
787  output << " rule->fTarget = \"" << (*it)["target"];
788  output << "\";" << std::endl;
789  }
790 
791  if( it->find( "source" ) != it->end() ) {
792  output << " rule->fSource = \"" << (*it)["source"];
793  output << "\";" << std::endl;
794  }
795 
796  //--------------------------------------------------------------------
797  // Deal with non mandatory keys
798  ///////////////////////////////////////////////////////////////////////
799 
800  if( it->find( "funcname" ) != it->end() ) {
801  std::string code = (*it)["code"];
802  StrReplace( code, "\n", "\\n" );
803  StrReplace( code, "\"", "\\\"");
804 
805  output << " rule->fFunctionPtr = (void *)TFunc2void( ";
806  output << (*it)["funcname"] << ");" << std::endl;
807  output << " rule->fCode = \"" << code;
808  output << "\";" << std::endl;
809  }
810 
811  if( it->find( "version" ) != it->end() ) {
812  output << " rule->fVersion = \"" << (*it)["version"];
813  output << "\";" << std::endl;
814  }
815 
816  if( it->find( "checksum" ) != it->end() ) {
817  output << " rule->fChecksum = \"" << (*it)["checksum"];
818  output << "\";" << std::endl;
819  }
820 
821  if( it->find( "embed" ) != it->end() ) {
822  output << " rule->fEmbed = " << (*it)["embed"];
823  output << ";" << std::endl;
824  }
825 
826  if( it->find( "include" ) != it->end() ) {
827  output << " rule->fInclude = \"" << (*it)["include"];
828  output << "\";" << std::endl;
829  }
830 
831  if( it->find( "attributes" ) != it->end() ) {
832  output << " rule->fAttributes = \"" << (*it)["attributes"];
833  output << "\";" << std::endl;
834  }
835  }
836  }
837 
838  /////////////////////////////////////////////////////////////////////////////
839  /// Get the list of includes specified in the shema rules
840 
841  void GetRuleIncludes( std::list<std::string> &result )
842  {
843  std::list<std::string> tmp;
844  std::list<SchemaRuleMap_t>::iterator rule;
845  SchemaRuleMap_t::iterator attr;
846  SchemaRuleClassMap_t::iterator it;
847 
848  //-----------------------------------------------------------------------
849  // Processing read rules
850  //////////////////////////////////////////////////////////////////////////
851 
852  for( it = gReadRules.begin(); it != gReadRules.end(); ++it ) {
853  for( rule = it->second.begin(); rule != it->second.end(); ++rule ) {
854  attr = rule->find( "include" );
855  if( attr == rule->end() ) continue;
856  TSchemaRuleProcessor::SplitList( attr->second, tmp );
857  result.splice( result.begin(), tmp, tmp.begin(), tmp.end() );
858  }
859  }
860 
861  //-----------------------------------------------------------------------
862  // Processing read raw rules
863  //////////////////////////////////////////////////////////////////////////
864 
865  for( it = gReadRawRules.begin(); it != gReadRawRules.end(); ++it ) {
866  for( rule = it->second.begin(); rule != it->second.end(); ++rule ) {
867  attr = rule->find( "include" );
868  if( attr == rule->end() ) continue;
869  TSchemaRuleProcessor::SplitList( attr->second, tmp );
870  result.splice( result.begin(), tmp, tmp.begin(), tmp.end() );
871  }
872  }
873 
874  //-----------------------------------------------------------------------
875  // Removing duplicates
876  //////////////////////////////////////////////////////////////////////////
877 
878  result.sort();
879  result.unique();
880  }
881 
882  /////////////////////////////////////////////////////////////////////////////
883  /// I am being called when a read pragma is encountered
884 
885  void ProcessReadPragma( const char* args, std::string& error_string )
886  {
887  //-----------------------------------------------------------------------
888  // Parse the rule and check it's validity
889  //////////////////////////////////////////////////////////////////////////
890 
891  std::map<std::string, std::string> rule;
892  if( !ParseRule( args, rule, error_string ) ) {
893  error_string += "\nThe following rule has been omitted:\n read ";
894  error_string += args;
895  error_string += "\n";
896  return;
897  }
898 
899  //-----------------------------------------------------------------------
900  // Append the rule to the list
901  //////////////////////////////////////////////////////////////////////////
902 
903  SchemaRuleClassMap_t::iterator it;
904  std::string targetClass = rule["targetClass"];
905  std::string normalizedTargetName;
906  TClassEdit::GetNormalizedName(normalizedTargetName, targetClass);
907 
908  it = gReadRules.find( normalizedTargetName );
909  if( it == gReadRules.end() ) {
910  std::list<SchemaRuleMap_t> lst;
911  lst.push_back( rule );
912  gReadRules[normalizedTargetName] = lst;
913  }
914  else
915  it->second.push_back( rule );
916  }
917 
918  /////////////////////////////////////////////////////////////////////////////
919  /// I am being called then a readraw pragma is encountered
920 
921  void ProcessReadRawPragma( const char* args, std::string& error_string)
922  {
923  //-----------------------------------------------------------------------
924  // Parse the rule and check it's validity
925  //////////////////////////////////////////////////////////////////////////
926 
927  std::map<std::string, std::string> rule;
928  if( !ParseRule( args, rule, error_string ) ) {
929  error_string += "\nThe following rule has been omitted:\n readraw ";
930  error_string += args;
931  error_string += "\n";
932  return;
933  }
934 
935  //-----------------------------------------------------------------------
936  // Append the rule to the list
937  //////////////////////////////////////////////////////////////////////////
938 
939  SchemaRuleClassMap_t::iterator it;
940  std::string targetClass = rule["targetClass"];
941  std::string normalizedTargetName;
942  TClassEdit::GetNormalizedName(normalizedTargetName, targetClass);
943  it = gReadRawRules.find( normalizedTargetName );
944  if( it == gReadRawRules.end() ) {
945  std::list<SchemaRuleMap_t> lst;
946  lst.push_back( rule );
947  gReadRawRules[normalizedTargetName] = lst;
948  }
949  else
950  it->second.push_back( rule );
951  }
952 
953 
954 }