Logo ROOT  
Reference Guide
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
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
28namespace {
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
47namespace 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
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,
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
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}
#define c(i)
Definition: RSha256.hxx:101
bool Bool_t
Definition: RtypesCore.h:59
static bool IsANumber(const std::string &source, bool acceptHex=false)
Check if given string consists of digits.
static std::string Trim(const std::string &source)
static void SplitDeclaration(const std::string &source, std::list< std::pair< ROOT::Internal::TSchemaType, std::string > > &result)
static bool ProcessVersion(const std::string &source, std::pair< Int_t, Int_t > &result)
static void SplitList(const std::string &source, std::list< std::string > &result, char delimiter=',')
std::map< std::string, std::string > MembersMap_t
Definition: TSchemaType.h:20
VSD Structures.
Definition: StringConv.hxx:21
std::list< std::pair< ROOT::Internal::TSchemaType, std::string > > SourceTypeList_t
std::map< std::string, std::list< SchemaRuleMap_t > > SchemaRuleClassMap_t
static void WriteAutoVariables(const std::list< std::string > &target, const SourceTypeList_t &source, MembersTypeMap_t &members, std::string &className, std::string &mappedName, std::ostream &output)
Write down the sources.
static std::string::size_type FindEndSymbol(std::string &command)
static void StrReplace(std::string &proc, const std::string &pat, const std::string &tr)
Replace all accurances of given string with other string.
void ProcessReadPragma(const char *args, std::string &error_string)
I am being called when a read pragma is encountered.
void WriteSchemaList(std::list< SchemaRuleMap_t > &rules, const std::string &listName, std::ostream &output)
Write schema rules.
std::map< std::string, ROOT::Internal::TSchemaType > MembersTypeMap_t
void WriteReadRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for Read rule, the function name is being written to rule["funcname"].
static Bool_t ValidateRule(const std::map< std::string, std::string > &rule, std::string &error_string)
Validate if the user specified rules are correct.
R__EXTERN SchemaRuleClassMap_t gReadRules
std::map< std::string, std::string > SchemaRuleMap_t
bool HasValidDataMembers(SchemaRuleMap_t &rule, MembersTypeMap_t &members, std::string &error_string)
Check if given rule contains references to valid data members.
void GetRuleIncludes(std::list< std::string > &result)
Get the list of includes specified in the shema rules.
void WriteReadRawRuleFunc(SchemaRuleMap_t &rule, int index, std::string &mappedName, MembersTypeMap_t &members, std::ostream &output)
Write the conversion function for ReadRaw rule, the function name is being written to rule["funcname"...
void ProcessReadRawPragma(const char *args, std::string &error_string)
I am being called then a readraw pragma is encountered.
R__EXTERN SchemaRuleClassMap_t gReadRawRules
bool ParseRule(std::string rule, ROOT::Internal::MembersMap_t &result, std::string &error_string)
Parse the schema rule as specified in the LinkDef file.
void GetNormalizedName(std::string &norm_name, std::string_view name)
Return the normalized name.
Definition: TClassEdit.cxx:832
static constexpr double s
auto * l
Definition: textangle.C:4
static void output(int code)
Definition: gifencode.c:226