00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <ctype.h>
00021 #include "TMakeProject.h"
00022 #include "TClass.h"
00023 #include "TClassEdit.h"
00024 #include "TROOT.h"
00025 #include "TMD5.h"
00026 #include "TStreamerInfo.h"
00027 #include "TStreamerElement.h"
00028 #include "TError.h"
00029
00030
00031 void TMakeProject::AddUniqueStatement(FILE *fp, const char *statement, char *inclist)
00032 {
00033
00034
00035 if (!strstr(inclist, statement)) {
00036 if (strlen(inclist)+strlen(statement) >= 50000) {
00037 Fatal("AddUniqueStatement","inclist too short need %u instead of 500000",UInt_t(strlen(inclist)+strlen(statement)));
00038 }
00039 strcat(inclist, statement);
00040 fprintf(fp, "%s", statement);
00041 }
00042 }
00043
00044
00045 void TMakeProject::AddInclude(FILE *fp, const char *header, Bool_t system, char *inclist)
00046 {
00047
00048
00049 TString what;
00050 if (system) {
00051 what.Form("#include <%s>\n", header);
00052 } else {
00053 what.Form("#include \"%s\"\n", header);
00054 }
00055 AddUniqueStatement(fp, what.Data(), inclist);
00056 }
00057
00058
00059 void TMakeProject::ChopFileName(TString &name, Int_t limit)
00060 {
00061
00062
00063
00064 if (name.Length() >= limit) {
00065 bool has_extension = (strcmp(name.Data() + name.Length() - 2, ".h") == 0);
00066 if (has_extension) {
00067 name.Remove(name.Length()-2);
00068 }
00069 TMD5 md;
00070 md.Update((const UChar_t*)name.Data(),name.Length());
00071 md.Final();
00072 name.Remove( limit - 32 - 5);
00073 name.Append( md.AsString() );
00074 if (has_extension) {
00075 name.Append( ".h" );
00076 }
00077 }
00078
00079 }
00080
00081
00082 TString TMakeProject::GetHeaderName(const char *in_name, const TList *extrainfos, Bool_t includeNested)
00083 {
00084
00085 TString result;
00086 std::string strname( TClassEdit::GetLong64_Name( in_name ) );
00087 const char *name = strname.c_str();
00088 Int_t len = strlen(name);
00089 Int_t nest = 0;
00090 for (Int_t i = 0; i < len; ++i) {
00091 switch (name[i]) {
00092 case '<':
00093 ++nest;
00094 result.Append('_');
00095 break;
00096 case '>':
00097 --nest;
00098 result.Append('_');
00099 break;
00100 case ':':
00101 if (nest == 0 && name[i+1] == ':') {
00102 TString nsname(name, i);
00103 TClass *cl = gROOT->GetClass(nsname);
00104 Bool_t definedInParent = !includeNested && cl && (cl->Size() != 0 || (cl->Size()==0 && cl->GetClassInfo()==0 ));
00105 if (!definedInParent && cl==0 && extrainfos!=0) {
00106 TStreamerInfo *clinfo = (TStreamerInfo*)extrainfos->FindObject(nsname);
00107 if (clinfo && clinfo->GetClassVersion() == -5) {
00108 definedInParent = kTRUE;
00109 }
00110 }
00111 if (definedInParent) {
00112
00113
00114
00115
00116 if (strcmp(name + strlen(name) - 2, ".h") == 0) {
00117 result.Append(".h");
00118 }
00119 ChopFileName(result,255);
00120 return result;
00121 }
00122 }
00123 result.Append('_');
00124 break;
00125 case ',':
00126 case '*':
00127 case '[':
00128 case ']':
00129 case ' ':
00130 case '(':
00131 case ')':
00132 result.Append('_');
00133 break;
00134 case '/':
00135 case '\\':
00136 default:
00137 result.Append(name[i]);
00138 }
00139 }
00140 ChopFileName(result,255);
00141 return result;
00142 }
00143
00144
00145 UInt_t TMakeProject::GenerateClassPrefix(FILE *fp, const char *clname, Bool_t top, TString &protoname,
00146 UInt_t *numberOfClasses, Int_t implementEmptyClass, Bool_t needGenericTemplate)
00147 {
00148
00149
00150
00151
00152 Int_t numberOfNamespaces = 0;
00153 const char *fullname = clname;
00154
00155 Bool_t istemplate = kFALSE;
00156 if (strchr(clname, ':')) {
00157
00158 Int_t len = strlen(clname);
00159 const char *name = clname;
00160 UInt_t nest = 0;
00161 for (Int_t cur = 0; cur < len; ++cur) {
00162 switch (clname[cur]) {
00163 case '<':
00164 ++nest;
00165 istemplate = kTRUE;
00166 break;
00167 case '>':
00168 --nest;
00169 break;
00170 case ':': {
00171 if (nest == 0 && clname[cur+1] == ':') {
00172
00173 TString nsname(clname, cur);
00174 TClass *cl = gROOT->GetClass(nsname);
00175 if (top) {
00176 if (cl == 0 || (cl && cl->Size() == 0)) {
00177 TString last(name, cur - (name - clname));
00178 if ((numberOfClasses == 0 || *numberOfClasses == 0) && strchr(last.Data(), '<') == 0) {
00179 fprintf(fp, "namespace %s {\n", last.Data());
00180 ++numberOfNamespaces;
00181 } else {
00182 TString headername(GetHeaderName(last,0));
00183 fprintf(fp, "#ifndef %s_h\n", headername.Data());
00184 fprintf(fp, "#define %s_h\n", headername.Data());
00185 GenerateClassPrefix(fp, last.Data(), top, protoname, 0);
00186 fprintf(fp, "{\n");
00187 fprintf(fp, "public:\n");
00188 if (numberOfClasses) ++(*numberOfClasses);
00189 istemplate = kFALSE;
00190 }
00191 name = clname + cur + 2;
00192 }
00193 } else {
00194 istemplate = kFALSE;
00195 name = clname + cur + 2;
00196 }
00197 }
00198 break;
00199 }
00200 }
00201 }
00202 clname = name;
00203 } else {
00204 istemplate = strstr(clname, "<") != 0;
00205 }
00206
00207 protoname = clname;
00208
00209 if (implementEmptyClass==1) {
00210 TString headername(GetHeaderName(fullname,0));
00211 fprintf(fp, "#ifndef %s_h\n", headername.Data());
00212 fprintf(fp, "#define %s_h\n", headername.Data());
00213 }
00214 if (istemplate) {
00215 std::vector<const char*> argtype;
00216
00217 Ssiz_t pos = protoname.First('<');
00218 UInt_t nparam = 1;
00219 if (pos != kNPOS) {
00220 if (isdigit(protoname[pos+1])) {
00221 argtype.push_back("int");
00222 } else {
00223 argtype.push_back("typename");
00224 }
00225 UInt_t nest = 0;
00226 for (Ssiz_t i = pos; i < protoname.Length(); ++i) {
00227 switch (protoname[i]) {
00228 case '<':
00229 ++nest;
00230 break;
00231 case '>':
00232 --nest;
00233 break;
00234 case ',':
00235 if (nest == 1) {
00236 if (isdigit(protoname[i+1])) {
00237 argtype.push_back("int");
00238 } else {
00239 argtype.push_back("typename");
00240 }
00241 ++nparam;
00242 }
00243 break;
00244 }
00245 }
00246 protoname.Remove(pos);
00247 }
00248
00249
00250 fprintf(fp, "template <");
00251 for (UInt_t p = 0; p < nparam; ++p) {
00252 if (p >= argtype.size() ) {
00253 fprintf(fp, "/* missing */ T%d", p);
00254 } else {
00255 fprintf(fp, "%s T%d", argtype[p], p);
00256 }
00257 if (p != (nparam - 1)) fprintf(fp, ", ");
00258 }
00259 if (needGenericTemplate) {
00260 fprintf(fp, "> class %s", protoname.Data());
00261 } else {
00262 fprintf(fp, "> class %s;\n", protoname.Data());
00263 fprintf(fp, "template <> ");
00264 }
00265 }
00266
00267 if (implementEmptyClass) {
00268 if (istemplate) {
00269 if (!needGenericTemplate) {
00270 fprintf(fp, "class %s", clname);
00271 }
00272 fprintf(fp, " {\n");
00273 if (numberOfClasses) ++(*numberOfClasses);
00274 fprintf(fp, "public:\n");
00275 fprintf(fp, "operator int() { return 0; };\n");
00276 } else {
00277 fprintf(fp, "enum %s { kDefault_%s };\n", clname, clname);
00278
00279
00280 if (implementEmptyClass==1) {
00281 if (strchr(fullname, ':') == 0) {
00282
00283 fprintf(fp, "%s", Form("#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n", fullname));
00284 }
00285 fprintf(fp, "#endif\n");
00286 }
00287 }
00288 } else {
00289 if (!(istemplate && needGenericTemplate)) {
00290 fprintf(fp, "class %s", clname);
00291 }
00292 }
00293 return numberOfNamespaces;
00294 }
00295
00296
00297 void TMakeProject::GenerateMissingStreamerInfo(TList *extrainfos, const char *clname, Bool_t iscope)
00298 {
00299
00300
00301
00302
00303 if (!TClassEdit::IsStdClass(clname) && !TClass::GetClass(clname) && gROOT->GetType(clname) == 0) {
00304
00305 TStreamerInfo *info = (TStreamerInfo*)extrainfos->FindObject(clname);
00306 if (!info) {
00307
00308 TStreamerInfo *newinfo = new TStreamerInfo();
00309 newinfo->SetName(clname);
00310 if (clname[strlen(clname)-1]=='>') {
00311 newinfo->SetTitle("Generated by MakeProject as an empty class template instantiation");
00312 newinfo->SetClassVersion(1);
00313 } else if (iscope) {
00314 newinfo->SetTitle("Generated by MakeProject as a namespace");
00315 newinfo->SetClassVersion(-4 );
00316 } else {
00317 newinfo->SetTitle("Generated by MakeProject as an enum");
00318 newinfo->SetClassVersion(-3 );
00319 }
00320 extrainfos->Add(newinfo);
00321 } else {
00322 if (iscope) {
00323 if (info->GetClassVersion() == -3) {
00324
00325
00326 info->SetTitle("Generated by MakeProject as an empty class");
00327 info->SetClassVersion(-5 );
00328 }
00329 } else {
00330 if (info->GetClassVersion() == -4) {
00331
00332
00333 info->SetTitle("Generated by MakeProject as an empty class");
00334 info->SetClassVersion(-5 );
00335 }
00336 }
00337 }
00338 }
00339 }
00340
00341
00342 void TMakeProject::GenerateMissingStreamerInfos(TList *extrainfos, const char *clname)
00343 {
00344
00345
00346
00347
00348 UInt_t len = strlen(clname);
00349 UInt_t nest = 0;
00350 UInt_t last = 0;
00351 Bool_t istemplate = kFALSE;
00352
00353 for (UInt_t i = 0; i < len; ++i) {
00354 switch (clname[i]) {
00355 case ':':
00356 if (nest == 0 && clname[i+1] == ':') {
00357 TString incName(clname, i);
00358 GenerateMissingStreamerInfo(extrainfos, incName.Data(), kTRUE);
00359 istemplate = kFALSE;
00360 }
00361 break;
00362 case '<':
00363 ++nest;
00364 if (nest == 1) last = i + 1;
00365 break;
00366 case '>':
00367 --nest;
00368 case ',':
00369 if ((clname[i] == ',' && nest == 1) || (clname[i] == '>' && nest == 0)) {
00370 TString incName(clname + last, i - last);
00371 incName = TClassEdit::ShortType(incName.Data(), TClassEdit::kDropTrailStar | TClassEdit::kLong64);
00372 if (clname[i] == '>' && nest == 1) incName.Append(">");
00373
00374 if (isdigit(incName[0])) {
00375
00376 } else {
00377 GenerateMissingStreamerInfos(extrainfos,incName.Data());
00378 }
00379 last = i + 1;
00380 }
00381 }
00382 }
00383 GenerateMissingStreamerInfo(extrainfos,TClassEdit::ShortType(clname, TClassEdit::kDropTrailStar | TClassEdit::kLong64).c_str(),kFALSE);
00384 }
00385
00386
00387 void TMakeProject::GenerateMissingStreamerInfos(TList *extrainfos, TStreamerElement *element)
00388 {
00389
00390
00391
00392
00393 if (element->IsBase()) {
00394 GenerateMissingStreamerInfos(extrainfos,element->GetClassPointer()->GetName());
00395 } else {
00396 GenerateMissingStreamerInfos(extrainfos,element->GetTypeName());
00397 }
00398
00399 }
00400
00401
00402 UInt_t TMakeProject::GenerateForwardDeclaration(FILE *fp, const char *clname, char *inclist, Bool_t implementEmptyClass, Bool_t needGenericTemplate, const TList *extrainfos)
00403 {
00404
00405
00406 UInt_t ninc = 0;
00407
00408 if (strchr(clname, '<')) {
00409 ninc += GenerateIncludeForTemplate(fp, clname, inclist, kTRUE, extrainfos);
00410 }
00411 TString protoname;
00412 UInt_t numberOfClasses = 0;
00413 UInt_t numberOfNamespaces = GenerateClassPrefix(fp, clname, kTRUE, protoname, &numberOfClasses, implementEmptyClass, needGenericTemplate);
00414
00415 if (!implementEmptyClass) fprintf(fp, ";\n");
00416 for (UInt_t i = 0;i < numberOfClasses;++i) {
00417 fprintf(fp, "}; // end of class.\n");
00418 fprintf(fp, "#endif\n");
00419 }
00420 for (UInt_t i = 0;i < numberOfNamespaces;++i) {
00421 fprintf(fp, "} // end of namespace.\n");
00422 }
00423
00424 return ninc;
00425 }
00426
00427
00428 UInt_t TMakeProject::GenerateIncludeForTemplate(FILE *fp, const char *clname, char *inclist, Bool_t forward, const TList *extrainfos)
00429 {
00430
00431
00432
00433 UInt_t ninc = 0;
00434 UInt_t len = strlen(clname);
00435 UInt_t nest = 0;
00436 UInt_t last = 0;
00437
00438
00439 for (UInt_t i = 0; i < len; ++i) {
00440 switch (clname[i]) {
00441 case '<':
00442 ++nest;
00443 if (nest == 1) last = i + 1;
00444 break;
00445 case '>':
00446 --nest;
00447 case ',':
00448 if ((clname[i] == ',' && nest == 1) || (clname[i] == '>' && nest == 0)) {
00449 TString incName(clname + last, i - last);
00450 incName = TClassEdit::ShortType(incName.Data(), TClassEdit::kDropTrailStar | TClassEdit::kLong64);
00451 if (clname[i] == '>' && nest == 1) incName.Append(">");
00452 Int_t stlType;
00453 if (isdigit(incName[0])) {
00454
00455 } else if ((stlType = TClassEdit::IsSTLCont(incName))) {
00456 const char *what = "";
00457 switch (TMath::Abs(stlType)) {
00458 case TClassEdit::kVector:
00459 what = "vector";
00460 break;
00461 case TClassEdit::kList:
00462 what = "list";
00463 break;
00464 case TClassEdit::kDeque:
00465 what = "deque";
00466 break;
00467 case TClassEdit::kMap:
00468 what = "map";
00469 break;
00470 case TClassEdit::kMultiMap:
00471 what = "map";
00472 break;
00473 case TClassEdit::kSet:
00474 what = "set";
00475 break;
00476 case TClassEdit::kMultiSet:
00477 what = "set";
00478 break;
00479 case TClassEdit::kBitSet:
00480 what = "bitset";
00481 break;
00482 default:
00483 what = "undetermined_stl_container";
00484 break;
00485 }
00486 AddInclude(fp, what, kTRUE, inclist);
00487 fprintf(fp, "namespace std {} using namespace std;\n");
00488 ninc += GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
00489 } else if (strncmp(incName.Data(), "pair<", strlen("pair<")) == 0) {
00490 AddInclude(fp, "utility", kTRUE, inclist);
00491 ninc += GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
00492 } else if (strncmp(incName.Data(), "auto_ptr<", strlen("auto_ptr<")) == 0) {
00493 AddInclude(fp, "memory", kTRUE, inclist);
00494 ninc += GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
00495 } else if (TClassEdit::IsStdClass(incName)) {
00496
00497 } else {
00498 TClass *cl = gROOT->GetClass(incName);
00499 if (!forward && cl) {
00500 if (cl->GetClassInfo()) {
00501
00502
00503 const char *include = cl->GetDeclFileName();
00504 if (include && strlen(include) != 0) {
00505
00506 if (strncmp(include, "include/", 8) == 0) {
00507 include += 8;
00508 }
00509 if (strncmp(include, "include\\", 9) == 0) {
00510 include += 9;
00511 }
00512 TMakeProject::AddInclude(fp, include, kFALSE, inclist);
00513 }
00514 GenerateIncludeForTemplate(fp, incName, inclist, forward, extrainfos);
00515 } else {
00516 incName = GetHeaderName(incName,extrainfos);
00517 incName.Append(".h");
00518 AddInclude(fp, incName, kFALSE, inclist);
00519 }
00520 } else if (incName.Length() && incName[0] != ' ' && gROOT->GetType(incName) == 0) {
00521 Bool_t emptyclass = !cl;
00522 if (emptyclass && extrainfos) {
00523 TStreamerInfo *info = (TStreamerInfo*)extrainfos->FindObject(incName);
00524 if (info && info->GetClassVersion() == -5) {
00525 emptyclass = kFALSE;
00526 }
00527 }
00528 GenerateForwardDeclaration(fp, incName, inclist, emptyclass, kFALSE, extrainfos);
00529 }
00530 }
00531 last = i + 1;
00532 }
00533 }
00534 }
00535
00536 Int_t stlType = TClassEdit::IsSTLCont(clname);
00537 if (stlType) {
00538 std::vector<std::string> inside;
00539 int nestedLoc;
00540 TClassEdit::GetSplit( clname, inside, nestedLoc, TClassEdit::kLong64 );
00541 Int_t stlkind = TClassEdit::STLKind(inside[0].c_str());
00542 TClass *key = TClass::GetClass(inside[1].c_str());
00543 if (key) {
00544 TString what;
00545 switch (stlkind) {
00546 case TClassEdit::kMap:
00547 case TClassEdit::kMultiMap: {
00548 what = "pair<";
00549 what += UpdateAssociativeToVector( inside[1].c_str() );
00550 what += ",";
00551 what += UpdateAssociativeToVector( inside[2].c_str() );
00552 what += " >";
00553 what.ReplaceAll("std::","");
00554
00555 TClass *paircl = TClass::GetClass(what.Data());
00556 if (paircl == 0 || paircl->GetClassInfo() == 0) {
00557 AddUniqueStatement(fp, Form("#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n", what.Data()), inclist);
00558 }
00559 break;
00560 }
00561 }
00562 }
00563 }
00564
00565 if (strncmp(clname, "auto_ptr<", strlen("auto_ptr<")) == 0) {
00566 AddUniqueStatement(fp, Form("#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n", clname), inclist);
00567 }
00568 return ninc;
00569 }
00570
00571
00572
00573 void TMakeProject::GeneratePostDeclaration(FILE *fp, const TVirtualStreamerInfo *info, char *inclist)
00574 {
00575
00576
00577
00578 TIter next(info->GetElements());
00579 TStreamerElement *element;
00580 while( (element = (TStreamerElement*)next()) ) {
00581 Int_t stlType = TClassEdit::IsSTLCont(element->GetTypeName());
00582 if (stlType) {
00583 std::vector<std::string> inside;
00584 int nestedLoc;
00585 TClassEdit::GetSplit( element->GetTypeName(), inside, nestedLoc, TClassEdit::kLong64 );
00586 Int_t stlkind = TClassEdit::STLKind(inside[0].c_str());
00587 TClass *key = TClass::GetClass(inside[1].c_str());
00588 TString what;
00589 if (strncmp(inside[1].c_str(),"pair<",strlen("pair<"))==0) {
00590 what = inside[1].c_str();
00591 } else if (key) {
00592 switch (stlkind) {
00593 case TClassEdit::kMap:
00594 case TClassEdit::kMultiMap:
00595 {
00596
00597 break;
00598 }
00599 default:
00600 break;
00601 }
00602 }
00603 if (what.Length()) {
00604 AddUniqueStatement(fp, Form("#ifdef __MAKECINT__\n#pragma link C++ class %s+;\n#endif\n",what.Data()), inclist);
00605 }
00606 }
00607 }
00608 }
00609
00610
00611 TString TMakeProject::UpdateAssociativeToVector(const char *name)
00612 {
00613
00614
00615
00616
00617
00618
00619 TString newname( name );
00620
00621 if (strchr(name,'<')!=0) {
00622 std::vector<std::string> inside;
00623 int nestedLoc;
00624 unsigned int narg = TClassEdit::GetSplit( name, inside, nestedLoc, TClassEdit::kLong64 );
00625 if (nestedLoc) --narg;
00626 Int_t stlkind = TMath::Abs(TClassEdit::STLKind(inside[0].c_str()));
00627
00628 for(unsigned int i = 1; i<narg; ++i) {
00629 inside[i] = UpdateAssociativeToVector( inside[i].c_str() );
00630 }
00631
00632 switch (stlkind) {
00633 case TClassEdit::kVector:
00634 case TClassEdit::kList:
00635 case TClassEdit::kDeque:
00636 if (narg>2 && strncmp(inside[2].c_str(),"std::allocator<",strlen("std::allocator<"))==0) {
00637 --narg;
00638 }
00639 break;
00640 case TClassEdit::kSet:
00641 case TClassEdit::kMultiSet:
00642 case TClassEdit::kMap:
00643 case TClassEdit::kMultiMap:
00644 if (narg>4 && strncmp(inside[4].c_str(),"std::allocator<",strlen("std::allocator<"))==0) {
00645 --narg;
00646 }
00647 break;
00648 }
00649 if (stlkind!=0) {
00650 TClass *key = TClass::GetClass(inside[1].c_str());
00651
00652 if (key) {
00653
00654
00655 std::string what;
00656 switch ( stlkind ) {
00657 case TClassEdit::kMap:
00658 case TClassEdit::kMultiMap: {
00659 what = "std::pair<";
00660 what += inside[1];
00661 what += ",";
00662 what += inside[2];
00663 if (what[what.size()-1]=='>') {
00664 what += " >";
00665 } else {
00666 what += ">";
00667 }
00668 inside.clear();
00669 inside.push_back("std::vector");
00670 inside.push_back(what);
00671 narg = 2;
00672 break;
00673 }
00674 case TClassEdit::kSet:
00675 case TClassEdit::kMultiSet:
00676 inside[0] = "std::vector";
00677 break;
00678 }
00679 }
00680 if (strncmp(inside[0].c_str(),"std::",5) != 0) {
00681 inside[0] = "std::" + inside[0];
00682 }
00683 } else {
00684 static const char *stlnames[] = { "pair", "greater", "less", "allocator" };
00685 for(unsigned int in = 0; in < sizeof(stlnames)/sizeof(stlnames[0]); ++in) {
00686 if (strncmp( inside[0].c_str(), stlnames[in], strlen(stlnames[in])) == 0 ) {
00687 inside[0] = "std::" + inside[0];
00688 break;
00689 }
00690 }
00691 }
00692 newname = inside[0];
00693 newname.Append("<");
00694 newname.Append(inside[1]);
00695 for(unsigned int j=2; j<narg; ++j) {
00696 newname.Append(",");
00697 newname.Append(inside[j]);
00698 }
00699 if (newname[newname.Length()-1]=='>') {
00700 newname.Append(" >");
00701 } else {
00702 newname.Append(">");
00703 }
00704 if (nestedLoc) newname.Append(inside[nestedLoc]);
00705 } else if ( newname == "string" ) {
00706 newname = "std::string";
00707 }
00708 return newname;
00709 }