Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TMakeProject.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id$
2 // Author: Rene Brun 12/10/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /*
13 \class TMakeProject TMakeProject.cxx
14 \ingroup IO
15 
16 Helper class implementing the TFile::MakeProject.
17 **/
18 
19 #include <ctype.h>
20 #include "TMakeProject.h"
21 #include "TClass.h"
22 #include "TClassEdit.h"
23 #include "TROOT.h"
24 #include "TMD5.h"
25 #include "TStreamerInfo.h"
26 #include "TStreamerElement.h"
27 #include "TError.h"
28 
29 ////////////////////////////////////////////////////////////////////////////////
30 /// Add an include statement, if it has not already been added.
31 
32 void TMakeProject::AddUniqueStatement(FILE *fp, const char *statement, char *inclist)
33 {
34  if (!strstr(inclist, statement)) {
35  if (strlen(inclist)+strlen(statement) >= 50000) {
36  Fatal("AddUniqueStatement","inclist too short need %u instead of 500000",UInt_t(strlen(inclist)+strlen(statement)));
37  }
38  strcat(inclist, statement);
39  fprintf(fp, "%s", statement);
40  }
41 }
42 
43 ////////////////////////////////////////////////////////////////////////////////
44 /// Add an include statement, if it has not already been added.
45 
46 void TMakeProject::AddInclude(FILE *fp, const char *header, Bool_t system, char *inclist)
47 {
48  TString what;
49  if (system) {
50  what.Form("#include <%s>\n", header);
51  } else {
52  what.Form("#include \"%s\"\n", header);
53  }
54  AddUniqueStatement(fp, what.Data(), inclist);
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 /// Chop the name by replacing the ending (before a potential extension) with
59 /// a md5 summary of the name.
60 
61 void TMakeProject::ChopFileName(TString &name, Int_t limit)
62 {
63  Ssiz_t len = name.Length();
64  Bool_t has_extension = name.EndsWith(".h");
65  if (has_extension)
66  len -= 2;
67  if (len >= limit) {
68  if (has_extension) {
69  name.Remove(name.Length()-2);
70  }
71  TMD5 md;
72  md.Update((const UChar_t*)name.Data(),name.Length());
73  md.Final();
74  name.Remove( limit - 32 - 5); // Chop the part longer than 255 and keep space for the md5 and leave space for an extension
75  name.Append( md.AsString() );
76  if (has_extension) {
77  name.Append( ".h" );
78  }
79  }
80 
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// Return the header name containing the description of name.
85 
86 TString TMakeProject::GetHeaderName(const char *in_name, const TList *extrainfos, Bool_t includeNested)
87 {
88  TString result;
89  std::string strname( TClassEdit::GetLong64_Name( in_name ) );
90  const char *name = strname.c_str();
91  Int_t len = strlen(name);
92  Int_t nest = 0;
93  for (Int_t i = 0; i < len; ++i) {
94  switch (name[i]) {
95  case '<':
96  ++nest;
97  result.Append('_');
98  break;
99  case '>':
100  --nest;
101  result.Append('_');
102  break;
103  case ':':
104  if (nest == 0 && name[i+1] == ':') {
105  TString nsname(name, i);
106  TClass *cl = gROOT->GetClass(nsname);
107  Bool_t definedInParent = !includeNested && cl && (cl->Size() != 0 || (cl->Size()==0 && !cl->HasInterpreterInfo() /*empty 'base' class on file*/));
108  if (!definedInParent && cl==0 && extrainfos!=0) {
109  TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
110  if (clinfo && clinfo->GetClassVersion() == -5) {
111  definedInParent = kTRUE;
112  }
113  }
114  if (definedInParent) {
115  // The requested class is actually nested inside
116  // the class whose name we already 'copied' to
117  // result. The declaration will be in the same
118  // header file as the outer class.
119  if (strcmp(name + strlen(name) - 2, ".h") == 0) {
120  result.Append(".h");
121  }
122  ChopFileName(result,127);
123  return result;
124  }
125 #ifndef WIN32
126  }
127  result.Append('_');
128 #else
129  }
130  if (name[i+1] == '/') {
131  // don't replace the colon ':' in the case it's part of the drive name in a Windows path
132  // e.g. don't convert from "c:/root/..." to "c_/root/..."
133  result.Append(name[i]);
134  } else {
135  result.Append('_');
136  }
137 #endif
138  break;
139  case ',':
140  case '*':
141  case '[':
142  case ']':
143  case ' ':
144  case '(':
145  case ')':
146  result.Append('_');
147  break;
148  case '/':
149  case '\\':
150  default:
151  result.Append(name[i]);
152  }
153  }
154  ChopFileName(result,127);
155  return result;
156 }
157 
158 ////////////////////////////////////////////////////////////////////////////////
159 /// Write the start of the class (forward) declaration.
160 /// If 'implementEmptyClass' is 3 then never add a #pragma
161 
162 UInt_t TMakeProject::GenerateClassPrefix(FILE *fp, const char *clname, Bool_t top, TString &protoname,
163  UInt_t *numberOfClasses, Int_t implementEmptyClass, Bool_t needGenericTemplate)
164 {
165  // First open the namespace (if any)
166  Int_t numberOfNamespaces = 0;
167  const char *fullname = clname;
168 
169  Bool_t istemplate = kFALSE;
170  if (strchr(clname, ':')) {
171  // We might have a namespace in front of the classname.
172  Int_t len = strlen(clname);
173  const char *name = clname;
174  UInt_t nest = 0;
175  for (Int_t cur = 0; cur < len; ++cur) {
176  switch (clname[cur]) {
177  case '<':
178  ++nest;
179  istemplate = kTRUE;
180  break;
181  case '>':
182  if (nest) --nest;
183  break;
184  case ':': {
185  if (nest == 0 && clname[cur+1] == ':') {
186  // We have a scope
187  TString nsname(clname, cur);
188  TClass *cl = gROOT->GetClass(nsname);
189  if (top) {
190  if (cl == 0 || (cl && cl->Size() == 0)) {
191  TString last(name, cur - (name - clname));
192  if ((numberOfClasses == 0 || *numberOfClasses == 0) && strchr(last.Data(), '<') == 0) {
193  fprintf(fp, "namespace %s {\n", last.Data());
194  ++numberOfNamespaces;
195  } else {
196  TString headername(GetHeaderName(last,0));
197  fprintf(fp, "#ifndef %s_h\n", headername.Data());
198  fprintf(fp, "#define %s_h\n", headername.Data());
199  GenerateClassPrefix(fp, last.Data(), top, protoname, 0);
200  fprintf(fp, "{\n");
201  fprintf(fp, "public:\n");
202  if (numberOfClasses) ++(*numberOfClasses);
203  istemplate = kFALSE;
204  }
205  name = clname + cur + 2;
206  }
207  } else {
208  istemplate = kFALSE;
209  name = clname + cur + 2;
210  }
211  }
212  break;
213  }
214  }
215  }
216  clname = name;
217  } else {
218  istemplate = strstr(clname, "<") != 0;
219  }
220 
221  protoname = clname;
222 
223  if (implementEmptyClass==1) {
224  TString headername(GetHeaderName(fullname,0));
225  fprintf(fp, "#ifndef %s_h\n", headername.Data());
226  fprintf(fp, "#define %s_h\n", headername.Data());
227  }
228  if (istemplate) {
229  std::vector<const char*> argtype;
230 
231  Ssiz_t pos = protoname.First('<');
232  UInt_t nparam = 1;
233  if (pos != kNPOS) {
234  if (isdigit(protoname[pos+1])) {
235  argtype.push_back("int");
236  } else {
237  argtype.push_back("typename");
238  }
239  UInt_t nest = 0;
240  for (Ssiz_t i = pos; i < protoname.Length(); ++i) {
241  switch (protoname[i]) {
242  case '<':
243  ++nest;
244  break;
245  case '>':
246  if (nest) --nest;
247  break;
248  case ',':
249  if (nest == 1) {
250  if (isdigit(protoname[i+1])) {
251  argtype.push_back("int");
252  } else {
253  argtype.push_back("typename");
254  }
255  ++nparam;
256  }
257  break;
258  }
259  }
260  protoname.Remove(pos);
261  }
262 
263  // Forward declaration of template.
264  fprintf(fp, "template <");
265  for (UInt_t p = 0; p < nparam; ++p) {
266  if (p >= argtype.size() ) {
267  fprintf(fp, "/* missing */ T%d", p);
268  } else {
269  fprintf(fp, "%s T%d", argtype[p], p);
270  }
271  if (p != (nparam - 1)) fprintf(fp, ", ");
272  }
273  if (needGenericTemplate) {
274  fprintf(fp, "> class %s", protoname.Data());
275  } else {
276  fprintf(fp, "> class %s;\n", protoname.Data());
277  fprintf(fp, "template <> ");
278  }
279  }
280 
281  if (implementEmptyClass) {
282  if (istemplate) {
283  if (!needGenericTemplate) {
284  fprintf(fp, "class %s", clname);
285  }
286  fprintf(fp, " {\n");
287  if (numberOfClasses) ++(*numberOfClasses);
288  fprintf(fp, "public:\n");
289  fprintf(fp, "operator int() { return 0; };\n");
290  } else {
291  fprintf(fp, "enum %s { kDefault_%s };\n", clname, clname);
292  // The nesting space of this class may not be #pragma declared (and without it
293  // the dictionary is broken), so for now skip those
294  if (implementEmptyClass==1) {
295  if (strchr(fullname, ':') == 0) {
296  // yes this is too aggressive, this needs to be fixed properly by moving the #pragma out of band.
297  fprintf(fp, "#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n", fullname);
298  }
299  fprintf(fp, "#endif\n");
300  }
301  }
302  } else {
303  if (!(istemplate && needGenericTemplate)) {
304  fprintf(fp, "class %s", clname);
305  }
306  }
307  return numberOfNamespaces;
308 }
309 
310 ////////////////////////////////////////////////////////////////////////////////
311 /// Generate an empty StreamerInfo for the given type (no recursion) if it is not
312 /// not known in the list of class.
313 ///
314 /// If the type itself is a template,
315 /// we mark it with version 1 (a class) otherwise we mark it as version -3 (an enum).
316 
317 void TMakeProject::GenerateMissingStreamerInfo(TList *extrainfos, const char *clname, Bool_t iscope)
318 {
319  if (!TClassEdit::IsStdClass(clname) && !TClass::GetClass(clname) && gROOT->GetType(clname) == 0) {
320 
321  TStreamerInfo *info = (TStreamerInfo*)extrainfos->FindObject(clname);
322  if (!info) {
323  // The class does not exist, let's create it
324  TStreamerInfo *newinfo = new TStreamerInfo();
325  newinfo->SetName(clname);
326  if (clname[strlen(clname)-1]=='>') {
327  newinfo->SetTitle("Generated by MakeProject as an empty class template instantiation");
328  newinfo->SetClassVersion(1);
329  } else if (iscope) {
330  newinfo->SetTitle("Generated by MakeProject as a namespace");
331  newinfo->SetClassVersion(-4 /*namespace*/);
332  } else {
333  newinfo->SetTitle("Generated by MakeProject as an enum");
334  newinfo->SetClassVersion(-3 /*enum*/);
335  }
336  extrainfos->Add(newinfo);
337  } else {
338  if (iscope) {
339  if (info->GetClassVersion() == -3) {
340  // This was marked as an enum but is also used as a scope,
341  // so it was actually a class.
342  info->SetTitle("Generated by MakeProject as an empty class");
343  info->SetClassVersion(-5 /*class*/);
344  }
345  } else {
346  if (info->GetClassVersion() == -4) {
347  // This was marked as a 'namespace' but it is also used as a template parameter,
348  // so it was actually a class.
349  info->SetTitle("Generated by MakeProject as an empty class");
350  info->SetClassVersion(-5 /*class*/);
351  }
352  }
353  }
354  }
355 }
356 
357 ////////////////////////////////////////////////////////////////////////////////
358 /// Generate an empty StreamerInfo for types that are used in templates parameters
359 /// but are not known in the list of class.
360 ///
361 /// If the type itself is a template, we mark it with version 1 (a class)
362 /// otherwise we mark it as version -3 (an enum).
363 
364 void TMakeProject::GenerateMissingStreamerInfos(TList *extrainfos, const char *clname)
365 {
366  UInt_t len = strlen(clname);
367  UInt_t nest = 0;
368  UInt_t last = 0;
369  //Bool_t istemplate = kFALSE; // mark whether the current right most entity is a class template.
370 
371  for (UInt_t i = 0; i < len; ++i) {
372  switch (clname[i]) {
373  case ':':
374  if (nest == 0 && clname[i+1] == ':') {
375  TString incName(clname, i);
376  GenerateMissingStreamerInfo(extrainfos, incName.Data(), kTRUE);
377  //istemplate = kFALSE;
378  }
379  break;
380  case '<':
381  ++nest;
382  if (nest == 1) last = i + 1;
383  break;
384  case '>':
385  if (nest == 0) return; // The name is not well formed, give up.
386  --nest; /* intentional fall through to the next case */
387  case ',':
388  if ((clname[i] == ',' && nest == 1) || (clname[i] == '>' && nest == 0)) {
389  TString incName(clname + last, i - last);
390  incName = TClassEdit::ShortType(incName.Data(), TClassEdit::kDropTrailStar | TClassEdit::kLong64);
391  if (clname[i] == '>' && nest == 1) incName.Append(">");
392 
393  if (isdigit(incName[0])) {
394  // Not a class name, nothing to do.
395  } else {
396  GenerateMissingStreamerInfos(extrainfos,incName.Data());
397  }
398  last = i + 1;
399  }
400  }
401  }
402  GenerateMissingStreamerInfo(extrainfos,TClassEdit::ShortType(clname, TClassEdit::kDropTrailStar | TClassEdit::kLong64).c_str(),kFALSE);
403 }
404 
405 ////////////////////////////////////////////////////////////////////////////////
406 /// Generate an empty StreamerInfo for types that are used in templates parameters
407 /// but are not known in the list of class.
408 ///
409 /// If the type itself is a template,
410 /// we mark it with version 1 (a class) otherwise we mark it as version -3 (an enum).
411 
412 void TMakeProject::GenerateMissingStreamerInfos(TList *extrainfos, TStreamerElement *element)
413 {
414  if (element->IsBase()) {
415  TClass *elemCl = element->GetClassPointer();
416  if (elemCl) GenerateMissingStreamerInfos(extrainfos,elemCl->GetName());
417  else GenerateMissingStreamerInfos(extrainfos,element->GetTypeName());
418  } else {
419  GenerateMissingStreamerInfos(extrainfos,element->GetTypeName());
420  }
421 
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 /// Insert a (complete) forward declaration for the class 'clname'
426 
427 UInt_t TMakeProject::GenerateForwardDeclaration(FILE *fp, const char *clname, char *inclist, Bool_t implementEmptyClass, Bool_t needGenericTemplate, const TList *extrainfos)
428 {
429  UInt_t ninc = 0;
430 
431  if (strchr(clname, '<')) {
432  ninc += GenerateIncludeForTemplate(fp, clname, inclist, kTRUE, extrainfos);
433  }
434  TString protoname;
435  UInt_t numberOfClasses = 0;
436  UInt_t numberOfNamespaces = GenerateClassPrefix(fp, clname, kTRUE, protoname, &numberOfClasses, implementEmptyClass, needGenericTemplate);
437 
438  if (!implementEmptyClass) fprintf(fp, ";\n");
439  for (UInt_t i = 0;i < numberOfClasses;++i) {
440  fprintf(fp, "}; // end of class.\n");
441  fprintf(fp, "#endif\n");
442  }
443  for (UInt_t i = 0;i < numberOfNamespaces;++i) {
444  fprintf(fp, "} // end of namespace.\n");
445  }
446 
447  return ninc;
448 }
449 
450 ////////////////////////////////////////////////////////////////////////////////
451 /// Add to the header file, the \#include needed for the argument of
452 /// this template.
453 
454 UInt_t TMakeProject::GenerateIncludeForTemplate(FILE *fp, const char *clname, char *inclist, Bool_t forward, const TList *extrainfos)
455 {
456  UInt_t ninc = 0;
457  UInt_t len = strlen(clname);
458  UInt_t nest = 0;
459  UInt_t last = 0;
460 
461 
462  for (UInt_t i = 0; i < len; ++i) {
463  switch (clname[i]) {
464  case '<':
465  ++nest;
466  if (nest == 1) last = i + 1;
467  break;
468  case '>':
469  if (nest==0) return ninc; // the name is not well formed, give up.
470  --nest; /* intentional fall through to the next case */
471  case ',':
472  if ((clname[i] == ',' && nest == 1) || (clname[i] == '>' && nest == 0)) {
473  TString incName(clname + last, i - last);
474  incName = TClassEdit::ShortType(incName.Data(), TClassEdit::kDropTrailStar | TClassEdit::kLong64);
475  if (clname[i] == '>' && nest == 1) incName.Append(">");
476  Int_t stlType;
477  if (isdigit(incName[0])) {
478  // Not a class name, nothing to do.
479  } else if ((stlType = TClassEdit::IsSTLCont(incName))) {
480  const char *what = "";
481  switch (TMath::Abs(stlType)) {
482  case ROOT::kSTLvector:
483  what = "vector";
484  break;
485  case ROOT::kSTLlist:
486  what = "list";
487  break;
488  case ROOT::kSTLforwardlist:
489  what = "forward_list";
490  break;
491  case ROOT::kSTLdeque:
492  what = "deque";
493  break;
494  case ROOT::kSTLmap:
495  case ROOT::kSTLmultimap:
496  what = "map";
497  break;
498  case ROOT::kSTLunorderedmap:
499  case ROOT::kSTLunorderedmultimap:
500  what = "unordered_map";
501  break;
502  case ROOT::kSTLset:
503  case ROOT::kSTLmultiset:
504  what = "set";
505  break;
506  case ROOT::kSTLunorderedset:
507  case ROOT::kSTLunorderedmultiset:
508  what = "unordered_set";
509  break;
510  case ROOT::kSTLbitset:
511  what = "bitset";
512  break;
513  default:
514  what = "undetermined_stl_container";
515  break;
516  }
517  AddInclude(fp, what, kTRUE, inclist);
518  fprintf(fp, "namespace std {} using namespace std;\n");
519  ninc += GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
520  } else if (strncmp(incName.Data(), "pair<", strlen("pair<")) == 0) {
521  AddInclude(fp, "utility", kTRUE, inclist);
522  ninc += GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
523  } else if (strncmp(incName.Data(), "auto_ptr<", strlen("auto_ptr<")) == 0) {
524  AddInclude(fp, "memory", kTRUE, inclist);
525  ninc += GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
526  } else if (TClassEdit::IsStdClass(incName)) {
527  // Do nothing.
528  } else {
529  TClass *cl = gROOT->GetClass(incName);
530  if (!forward && cl) {
531  if (cl->HasInterpreterInfo()) {
532  // We have the real dictionary for this class.
533 
534  const char *include = cl->GetDeclFileName();
535  if (include && include[0]) {
536 
537  if (strncmp(include, "include/", 8) == 0) {
538  include += 8;
539  }
540  if (strncmp(include, "include\\", 9) == 0) {
541  include += 9;
542  }
543  TMakeProject::AddInclude(fp, include, kFALSE, inclist);
544  }
545  GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
546  } else {
547  incName = GetHeaderName(incName,extrainfos);
548  incName.Append(".h");
549  AddInclude(fp, incName, kFALSE, inclist);
550  }
551  } else if (incName.Length() && incName[0] != ' ' && gROOT->GetType(incName) == 0) {
552  Bool_t emptyclass = !cl;
553  if (emptyclass && extrainfos) {
554  TStreamerInfo *info = (TStreamerInfo*)extrainfos->FindObject(incName);
555  if (info && info->GetClassVersion() == -5) {
556  emptyclass = kFALSE;
557  }
558  }
559  GenerateForwardDeclaration(fp, incName, inclist, emptyclass, kFALSE, extrainfos);
560  }
561  }
562  last = i + 1;
563  }
564  }
565  }
566 
567  Int_t stlType = TClassEdit::IsSTLCont(clname);
568  if (stlType) {
569  std::vector<std::string> inside;
570  int nestedLoc;
571  TClassEdit::GetSplit( clname, inside, nestedLoc, TClassEdit::kLong64 );
572  Int_t stlkind = TClassEdit::STLKind(inside[0]);
573  TClass *key = TClass::GetClass(inside[1].c_str());
574  if (key) {
575  TString what;
576  switch (stlkind) {
577  case ROOT::kSTLmap:
578  case ROOT::kSTLmultimap: {
579  what = "pair<";
580  what += UpdateAssociativeToVector( inside[1].c_str() );
581  what += ",";
582  what += UpdateAssociativeToVector( inside[2].c_str() );
583  what += " >";
584  what.ReplaceAll("std::","");
585  // Only ask for it if needed.
586  TClass *paircl = TClass::GetClass(what.Data());
587  if (paircl == 0 || !paircl->HasInterpreterInfo()) {
588  AddUniqueStatement(fp, TString::Format("#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n", what.Data()), inclist);
589  }
590  break;
591  }
592  }
593  }
594  }
595 
596  return ninc;
597 }
598 
599 
600 ////////////////////////////////////////////////////////////////////////////////
601 /// Add to the header file anything that need to appear after the class
602 /// declaration (this includes some \#pragma link).
603 
604 void TMakeProject::GeneratePostDeclaration(FILE *fp, const TVirtualStreamerInfo *info, char *inclist)
605 {
606  TIter next(info->GetElements());
607  TStreamerElement *element;
608  while( (element = (TStreamerElement*)next()) ) {
609  Int_t stlType = TClassEdit::IsSTLCont(element->GetTypeName());
610  if (stlType) {
611  std::vector<std::string> inside;
612  int nestedLoc;
613  TClassEdit::GetSplit( element->GetTypeName(), inside, nestedLoc, TClassEdit::kLong64 );
614  Int_t stlkind = TClassEdit::STLKind(inside[0]);
615  TClass *key = TClass::GetClass(inside[1].c_str());
616  TString what;
617  if (strncmp(inside[1].c_str(),"pair<",strlen("pair<"))==0) {
618  what = inside[1].c_str();
619  } else if (key) {
620  switch (stlkind) {
621  case ROOT::kSTLmap:
622  case ROOT::kSTLmultimap:
623  {
624  // Already done (see GenerateIncludeForTemplate
625  break;
626  }
627  default:
628  break;
629  }
630  }
631  if (what.Length()) {
632  // Only ask for it if needed.
633  TClass *paircl = TClass::GetClass(what.Data());
634  if (paircl == 0 || !paircl->HasInterpreterInfo()) {
635  AddUniqueStatement(fp, TString::Format("#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n",what.Data()), inclist);
636  }
637  }
638  }
639  }
640 }
641 
642 ////////////////////////////////////////////////////////////////////////////////
643 /// If we have a map, multimap, set or multiset, plus unordered partners,
644 /// and the key is a class, we need to replace the
645 /// container by a vector since we don't have the
646 /// comparator function.
647 /// The 'name' is modified to return the change in the name,
648 /// if any.
649 
650 static constexpr int str_length(const char* str)
651 {
652  return *str ? 1 + str_length(str + 1) : 0;
653 }
654 
655 TString TMakeProject::UpdateAssociativeToVector(const char *name)
656 {
657  TString newname( name );
658 
659  constexpr auto auto_ptr_len = str_length("auto_ptr<");
660  if (strncmp(name, "auto_ptr<", auto_ptr_len) == 0) {
661  newname = "unique_ptr<";
662  newname += (name + auto_ptr_len);
663  } else if (strchr(name,'<')!=0) {
664  std::vector<std::string> inside;
665  int nestedLoc;
666  unsigned int narg = TClassEdit::GetSplit( name, inside, nestedLoc, TClassEdit::kLong64 );
667 
668  Int_t stlkind = TMath::Abs(TClassEdit::STLKind(inside[0]));
669 
670  for(unsigned int i = 1; i<narg; ++i) {
671  inside[i] = UpdateAssociativeToVector( inside[i].c_str() );
672  }
673 
674  if (nestedLoc) narg = nestedLoc;
675 
676  // Remove default allocator if any.
677  static const char* allocPrefix = "std::allocator<";
678  static const unsigned int allocPrefixLen (strlen(allocPrefix));
679  switch (stlkind) {
680  case ROOT::kSTLvector:
681  case ROOT::kSTLlist:
682  case ROOT::kSTLforwardlist:
683  case ROOT::kSTLdeque:
684  if (narg>2 && strncmp(inside[2].c_str(),allocPrefix,allocPrefixLen)==0) {
685  --narg;
686  }
687  break;
688  case ROOT::kSTLset:
689  case ROOT::kSTLmultiset:
690  case ROOT::kSTLmap:
691  case ROOT::kSTLmultimap:
692  if (narg>4 && strncmp(inside[4].c_str(),allocPrefix,allocPrefixLen)==0) {
693  --narg;
694  }
695  break;
696  case ROOT::kSTLunorderedset:
697  case ROOT::kSTLunorderedmultiset:
698  if (narg>5 && strncmp(inside[5].c_str(),allocPrefix,allocPrefixLen)==0) {
699  --narg;
700  }
701  break;
702  case ROOT::kSTLunorderedmap:
703  case ROOT::kSTLunorderedmultimap:
704  if (narg>6 && strncmp(inside[6].c_str(),allocPrefix,allocPrefixLen)==0) {
705  --narg;
706  }
707  break;
708  }
709  if (stlkind!=0) {
710  TClass *key = TClass::GetClass(inside[1].c_str());
711 
712  if (key) {
713  // We only need to translate to a vector is the key is a class
714  // (for which we do not know the sorting).
715  std::string what;
716  switch ( stlkind ) {
717  case ROOT::kSTLmap:
718  case ROOT::kSTLunorderedmap:
719  case ROOT::kSTLmultimap:
720  case ROOT::kSTLunorderedmultimap: {
721  what = "std::pair<";
722  what += inside[1];
723  what += ",";
724  what += inside[2];
725  if (what[what.size()-1]=='>') {
726  what += " >";
727  } else {
728  what += ">";
729  }
730  inside.clear();
731  inside.push_back("std::vector");
732  inside.push_back(what);
733  narg = 2;
734  break;
735  }
736  case ROOT::kSTLset:
737  case ROOT::kSTLunorderedset:
738  case ROOT::kSTLmultiset:
739  case ROOT::kSTLunorderedmultiset:
740  inside[0] = "std::vector";
741  break;
742  }
743  }
744  if (strncmp(inside[0].c_str(),"std::",5) != 0) {
745  inside[0] = "std::" + inside[0];
746  }
747  } else {
748  static const char *stlnames[] = { "pair", "greater", "less", "allocator" };
749  for(unsigned int in = 0; in < sizeof(stlnames)/sizeof(stlnames[0]); ++in) {
750  if (strncmp( inside[0].c_str(), stlnames[in], strlen(stlnames[in])) == 0 ) {
751  inside[0] = "std::" + inside[0];
752  break;
753  }
754  }
755  }
756  newname = inside[0];
757  newname.Append("<");
758  newname.Append(inside[1]);
759  for(unsigned int j=2; j<narg; ++j) {
760  if (!inside[j].empty()) {
761  newname.Append(",");
762  newname.Append(inside[j]);
763  }
764  }
765  if (newname[newname.Length()-1]=='>') {
766  newname.Append(" >");
767  } else {
768  newname.Append(">");
769  }
770  if (nestedLoc) newname.Append(inside[nestedLoc]);
771  } else if ( newname == "string" ) {
772  newname = "std::string";
773  }
774  return newname;
775 }