00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #include "RConfigure.h"
00067
00068 #include <string.h>
00069 #include <stdio.h>
00070 #include <stdlib.h>
00071 #include <ctype.h>
00072
00073 #include "TEnv.h"
00074 #include "TROOT.h"
00075 #include "TSystem.h"
00076 #include "THashList.h"
00077 #include "TError.h"
00078
00079
00080 TEnv *gEnv;
00081
00082
00083 static struct BoolNameTable_t {
00084 const char *fName;
00085 Int_t fValue;
00086 } gBoolNames[]= {
00087 { "TRUE", 1 },
00088 { "FALSE", 0 },
00089 { "ON", 1 },
00090 { "OFF", 0 },
00091 { "YES", 1 },
00092 { "NO", 0 },
00093 { "OK", 1 },
00094 { "NOT", 0 },
00095 { 0, 0 }
00096 };
00097
00098
00099
00100
00101 class TEnvParser {
00102
00103 private:
00104 FILE *fIfp;
00105
00106 protected:
00107 TEnv *fEnv;
00108
00109 public:
00110 TEnvParser(TEnv *e, FILE *f) : fIfp(f), fEnv(e) { }
00111 virtual ~TEnvParser() { }
00112 virtual void KeyValue(const TString&, const TString&, const TString&) { }
00113 virtual void Char(Int_t) { }
00114 void Parse();
00115 };
00116
00117
00118 void TEnvParser::Parse()
00119 {
00120
00121
00122
00123 TString name(1024);
00124 TString type(1024);
00125 TString value(1024);
00126 int c, state = 0;
00127
00128 while ((c = fgetc(fIfp)) != EOF) {
00129 if (c == 13)
00130 continue;
00131 if (c == '\n') {
00132 state = 0;
00133 if (name.Length() > 0) {
00134 KeyValue(name, value, type);
00135 name.Clear();
00136 value.Clear();
00137 type.Clear();
00138 }
00139 Char(c);
00140 continue;
00141 }
00142 switch (state) {
00143 case 0:
00144 switch (c) {
00145 case ' ':
00146 case '\t':
00147 break;
00148 case '#':
00149 state = 1;
00150 break;
00151 default:
00152 state = 2;
00153 break;
00154 }
00155 break;
00156
00157 case 1:
00158 break;
00159
00160 case 2:
00161 switch (c) {
00162 case ' ':
00163 case '\t':
00164 case ':':
00165 state = 3;
00166 break;
00167 case '(':
00168 state = 7;
00169 break;
00170 default:
00171 break;
00172 }
00173 break;
00174
00175 case 3:
00176 if (c != ' ' && c != '\t')
00177 state = 4;
00178 break;
00179
00180 case 4:
00181 break;
00182
00183 case 5:
00184 if (c == ')')
00185 state = 6;
00186 break;
00187
00188 case 6:
00189 state = (c == ':') ? 3 : 4;
00190 break;
00191
00192 case 7:
00193 state = (c == ')') ? 6 : 5;
00194 break;
00195
00196 }
00197 switch (state) {
00198 case 2:
00199 name.Append(c);
00200 break;
00201 case 4:
00202 value.Append(c);
00203 break;
00204 case 5:
00205 type.Append(c);
00206 break;
00207 }
00208 if (state != 4)
00209 Char(c);
00210 }
00211 }
00212
00213
00214
00215 class TReadEnvParser : public TEnvParser {
00216
00217 private:
00218 EEnvLevel fLevel;
00219
00220 public:
00221 TReadEnvParser(TEnv *e, FILE *f, EEnvLevel l) : TEnvParser(e, f), fLevel(l) { }
00222 void KeyValue(const TString &name, const TString &value, const TString &type)
00223 { fEnv->SetValue(name, value, fLevel, type); }
00224 };
00225
00226
00227
00228 class TWriteEnvParser : public TEnvParser {
00229
00230 private:
00231 FILE *fOfp;
00232
00233 public:
00234 TWriteEnvParser(TEnv *e, FILE *f, FILE *of) : TEnvParser(e, f), fOfp(of) { }
00235 void KeyValue(const TString &name, const TString &value, const TString &type);
00236 void Char(Int_t c) { fputc(c, fOfp); }
00237 };
00238
00239
00240 void TWriteEnvParser::KeyValue(const TString &name, const TString &value,
00241 const TString &)
00242 {
00243
00244
00245 TEnvRec *er = fEnv->Lookup(name);
00246 if (er && er->fModified) {
00247 er->fModified = kFALSE;
00248 fprintf(fOfp, "%s", er->fValue.Data());
00249 } else
00250 fprintf(fOfp, "%s", value.Data());
00251 }
00252
00253
00254
00255
00256
00257 TEnvRec::TEnvRec(const char *n, const char *v, const char *t, EEnvLevel l)
00258 : fName(n), fType(t), fLevel(l)
00259 {
00260
00261
00262 fValue = ExpandValue(v);
00263 fModified = (l == kEnvChange);
00264 }
00265
00266
00267 void TEnvRec::ChangeValue(const char *v, const char *, EEnvLevel l,
00268 Bool_t append, Bool_t ignoredup)
00269 {
00270
00271
00272 if (l != kEnvChange && fLevel == l && !append) {
00273
00274
00275 if (fValue != v && !ignoredup)
00276 ::Warning("TEnvRec::ChangeValue",
00277 "duplicate entry <%s=%s> for level %d; ignored", fName.Data(), v, l);
00278 return;
00279 }
00280 if (!append) {
00281 if (fValue != v) {
00282 if (l == kEnvChange)
00283 fModified = kTRUE;
00284 else
00285 fModified = kFALSE;
00286 fLevel = l;
00287 fValue = ExpandValue(v);
00288 }
00289 } else {
00290 if (l == kEnvChange)
00291 fModified = kTRUE;
00292 fLevel = l;
00293 fValue += " ";
00294 fValue += ExpandValue(v);
00295 }
00296 }
00297
00298
00299 Int_t TEnvRec::Compare(const TObject *op) const
00300 {
00301
00302
00303 return fName.CompareTo(((TEnvRec*)op)->fName);
00304 }
00305
00306
00307 TString TEnvRec::ExpandValue(const char *value)
00308 {
00309
00310
00311
00312 const char *vv;
00313 char *v, *vorg = StrDup(value);
00314 v = vorg;
00315
00316 char *s1, *s2;
00317 int len = 0;
00318 while ((s1 = (char*)strstr(v, "$("))) {
00319 s1 += 2;
00320 s2 = (char*)strchr(s1, ')');
00321 if (!s2) {
00322 len = 0;
00323 break;
00324 }
00325 *s2 = 0;
00326 vv = gSystem->Getenv(s1);
00327 if (vv) len += strlen(vv);
00328 *s2 = ')';
00329 v = s2 + 1;
00330 }
00331
00332 if (!len) {
00333 delete [] vorg;
00334 return TString(value);
00335 }
00336
00337 v = vorg;
00338 int nch = strlen(v) + len;
00339 char *nv = new char[nch];
00340 *nv = 0;
00341
00342 while ((s1 = (char*)strstr(v, "$("))) {
00343 *s1 = 0;
00344 strlcat(nv, v,nch);
00345 *s1 = '$';
00346 s1 += 2;
00347 s2 = (char*)strchr(s1, ')');
00348 *s2 = 0;
00349 vv = gSystem->Getenv(s1);
00350 if (vv) strlcat(nv, vv,nch);
00351 *s2 = ')';
00352 v = s2 + 1;
00353 }
00354
00355 if (*v) strlcat(nv, v,nch);
00356
00357 TString val = nv;
00358 delete [] nv;
00359 delete [] vorg;
00360
00361 return val;
00362 }
00363
00364
00365
00366
00367 ClassImp(TEnv)
00368
00369
00370 TEnv::TEnv(const char *name)
00371 {
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 fIgnoreDup = kFALSE;
00382
00383 if (!name || !strlen(name) || !gSystem)
00384 fTable = 0;
00385 else {
00386 fTable = new THashList(1000);
00387 fRcName = name;
00388
00389 TString sname = "system";
00390 sname += name;
00391 #ifdef ROOTETCDIR
00392 char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
00393 #else
00394 TString etc = gRootDir;
00395 #ifdef WIN32
00396 etc += "\\etc";
00397 #else
00398 etc += "/etc";
00399 #endif
00400 #if defined(R__MACOSX) && (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
00401
00402 etc = gRootDir;
00403 #endif
00404 char *s = gSystem->ConcatFileName(etc, sname);
00405 #endif
00406 ReadFile(s, kEnvGlobal);
00407 delete [] s;
00408 if (!gSystem->Getenv("ROOTENV_NO_HOME")) {
00409 s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
00410 ReadFile(s, kEnvUser);
00411 delete [] s;
00412 if (strcmp(gSystem->HomeDirectory(), gSystem->WorkingDirectory()))
00413 ReadFile(name, kEnvLocal);
00414 } else
00415 ReadFile(name, kEnvLocal);
00416 }
00417 }
00418
00419
00420 TEnv::~TEnv()
00421 {
00422
00423
00424 if (fTable) {
00425 fTable->Delete();
00426 SafeDelete(fTable);
00427 }
00428 }
00429
00430
00431 const char *TEnv::Getvalue(const char *name)
00432 {
00433
00434
00435 Bool_t haveProgName = kFALSE;
00436 if (gProgName && strlen(gProgName) > 0)
00437 haveProgName = kTRUE;
00438
00439 TString aname;
00440 TEnvRec *er = 0;
00441 if (haveProgName && gSystem && gProgName) {
00442 aname = gSystem->GetName(); aname += "."; aname += gProgName;
00443 aname += "."; aname += name;
00444 er = Lookup(aname);
00445 }
00446 if (er == 0 && gSystem && gROOT) {
00447 aname = gSystem->GetName(); aname += "."; aname += gROOT->GetName();
00448 aname += "."; aname += name;
00449 er = Lookup(aname);
00450 }
00451 if (er == 0 && gSystem) {
00452 aname = gSystem->GetName(); aname += ".*."; aname += name;
00453 er = Lookup(aname);
00454 }
00455 if (er == 0 && haveProgName && gProgName) {
00456 aname = gProgName; aname += "."; aname += name;
00457 er = Lookup(aname);
00458 }
00459 if (er == 0 && gROOT) {
00460 aname = gROOT->GetName(); aname += "."; aname += name;
00461 er = Lookup(aname);
00462 }
00463 if (er == 0) {
00464 aname = "*.*."; aname += name;
00465 er = Lookup(aname);
00466 }
00467 if (er == 0) {
00468 aname = "*."; aname += name;
00469 er = Lookup(aname);
00470 }
00471 if (er == 0) {
00472 er = Lookup(name);
00473 }
00474 if (er == 0)
00475 return 0;
00476 return er->fValue;
00477 }
00478
00479
00480 Int_t TEnv::GetValue(const char *name, Int_t dflt)
00481 {
00482
00483
00484
00485 const char *cp = TEnv::Getvalue(name);
00486 if (cp) {
00487 char buf2[512], *cp2 = buf2;
00488
00489 while (isspace((int)*cp))
00490 cp++;
00491 if (*cp) {
00492 BoolNameTable_t *bt;
00493 if (isdigit((int)*cp) || *cp == '-' || *cp == '+')
00494 return atoi(cp);
00495 while (isalpha((int)*cp))
00496 *cp2++ = toupper((int)*cp++);
00497 *cp2 = 0;
00498 for (bt = gBoolNames; bt->fName; bt++)
00499 if (strcmp(buf2, bt->fName) == 0)
00500 return bt->fValue;
00501 }
00502 }
00503 return dflt;
00504 }
00505
00506
00507 Double_t TEnv::GetValue(const char *name, Double_t dflt)
00508 {
00509
00510
00511
00512 const char *cp = TEnv::Getvalue(name);
00513 if (cp) {
00514 char *endptr;
00515 Double_t val = strtod(cp, &endptr);
00516 if (val == 0.0 && cp == endptr)
00517 return dflt;
00518 return val;
00519 }
00520 return dflt;
00521 }
00522
00523
00524 const char *TEnv::GetValue(const char *name, const char *dflt)
00525 {
00526
00527
00528
00529 const char *cp = TEnv::Getvalue(name);
00530 if (cp)
00531 return cp;
00532 return dflt;
00533 }
00534
00535
00536 TEnvRec *TEnv::Lookup(const char *name)
00537 {
00538
00539
00540
00541 if (!fTable) return 0;
00542 return (TEnvRec*) fTable->FindObject(name);
00543 }
00544
00545
00546 void TEnv::Print(Option_t *opt) const
00547 {
00548
00549
00550 if (!opt || !strlen(opt)) {
00551 PrintEnv();
00552 return;
00553 }
00554
00555 if (!strcmp(opt, "global"))
00556 PrintEnv(kEnvGlobal);
00557 if (!strcmp(opt, "user"))
00558 PrintEnv(kEnvUser);
00559 if (!strcmp(opt, "local"))
00560 PrintEnv(kEnvLocal);
00561 }
00562
00563
00564 void TEnv::PrintEnv(EEnvLevel level) const
00565 {
00566
00567
00568 if (!fTable) return;
00569
00570 TIter next(fTable);
00571 TEnvRec *er;
00572 static const char *lc[] = { "Global", "User", "Local", "Changed", "All" };
00573
00574 while ((er = (TEnvRec*) next()))
00575 if (er->fLevel == level || level == kEnvAll)
00576 Printf("%-25s %-30s [%s]", Form("%s:", er->fName.Data()),
00577 er->fValue.Data(), lc[er->fLevel]);
00578 }
00579
00580
00581 Int_t TEnv::ReadFile(const char *fname, EEnvLevel level)
00582 {
00583
00584
00585
00586 if (!fname || !strlen(fname)) {
00587 Error("ReadFile", "no file name specified");
00588 return -1;
00589 }
00590
00591 FILE *ifp;
00592 if ((ifp = fopen(fname, "r"))) {
00593 TReadEnvParser rp(this, ifp, level);
00594 rp.Parse();
00595 fclose(ifp);
00596 return 0;
00597 }
00598
00599
00600
00601 return -1;
00602 }
00603
00604
00605 Int_t TEnv::WriteFile(const char *fname, EEnvLevel level)
00606 {
00607
00608
00609
00610
00611 if (!fname || !strlen(fname)) {
00612 Error("WriteFile", "no file name specified");
00613 return -1;
00614 }
00615
00616 if (!fTable) {
00617 Error("WriteFile", "TEnv table is empty");
00618 return -1;
00619 }
00620
00621 FILE *ofp;
00622 if ((ofp = fopen(fname, "w"))) {
00623 TIter next(fTable);
00624 TEnvRec *er;
00625 while ((er = (TEnvRec*) next()))
00626 if (er->fLevel == level || level == kEnvAll)
00627 fprintf(ofp, "%-40s %s\n", Form("%s:", er->fName.Data()),
00628 er->fValue.Data());
00629 fclose(ofp);
00630 return 0;
00631 }
00632
00633 Error("WriteFile", "cannot open %s for writing", fname);
00634 return -1;
00635 }
00636
00637
00638 void TEnv::Save()
00639 {
00640
00641
00642
00643 if (fRcName == "") {
00644 Error("Save", "no resource file name specified");
00645 return;
00646 }
00647
00648 SaveLevel(kEnvLocal);
00649 SaveLevel(kEnvUser);
00650 SaveLevel(kEnvGlobal);
00651 }
00652
00653
00654 void TEnv::SaveLevel(EEnvLevel level)
00655 {
00656
00657
00658 if (fRcName == "") {
00659 Error("SaveLevel", "no resource file name specified");
00660 return;
00661 }
00662
00663 if (!fTable) {
00664 Error("SaveLevel", "TEnv table is empty");
00665 return;
00666 }
00667
00668 TString rootrcdir;
00669 FILE *ifp, *ofp;
00670
00671 if (level == kEnvGlobal) {
00672
00673 TString sname = "system";
00674 sname += fRcName;
00675 #ifdef ROOTETCDIR
00676 char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
00677 #else
00678 TString etc = gRootDir;
00679 #ifdef WIN32
00680 etc += "\\etc";
00681 #else
00682 etc += "/etc";
00683 #endif
00684 char *s = gSystem->ConcatFileName(etc, sname);
00685 #endif
00686 rootrcdir = s;
00687 delete [] s;
00688 } else if (level == kEnvUser) {
00689 char *s = gSystem->ConcatFileName(gSystem->HomeDirectory(), fRcName);
00690 rootrcdir = s;
00691 delete [] s;
00692 } else if (level == kEnvLocal)
00693 rootrcdir = fRcName;
00694 else
00695 return;
00696
00697 if ((ofp = fopen(Form("%s.new", rootrcdir.Data()), "w"))) {
00698 ifp = fopen(rootrcdir.Data(), "r");
00699 if (ifp == 0) {
00700 ifp = fopen(rootrcdir.Data(), "w");
00701 if (ifp) {
00702 fclose(ifp);
00703 ifp = 0;
00704 }
00705 }
00706 if (ifp || (ifp = fopen(rootrcdir.Data(), "r"))) {
00707 TWriteEnvParser wp(this, ifp, ofp);
00708 wp.Parse();
00709
00710 TIter next(fTable);
00711 TEnvRec *er;
00712 while ((er = (TEnvRec*) next())) {
00713 if (er->fModified) {
00714
00715
00716 if (er->fLevel == kEnvChange) er->fLevel = level;
00717 if (er->fLevel == level) {
00718 er->fModified = kFALSE;
00719 fprintf(ofp, "%-40s %s\n", Form("%s:", er->fName.Data()),
00720 er->fValue.Data());
00721 }
00722 }
00723 }
00724 fclose(ifp);
00725 fclose(ofp);
00726 gSystem->Rename(rootrcdir.Data(), Form("%s.bak", rootrcdir.Data()));
00727 gSystem->Rename(Form("%s.new", rootrcdir.Data()), rootrcdir.Data());
00728 return;
00729 }
00730 fclose(ofp);
00731 } else
00732 Error("SaveLevel", "cannot write to file %s", rootrcdir.Data());
00733 }
00734
00735
00736 void TEnv::SetValue(const char *name, const char *value, EEnvLevel level,
00737 const char *type)
00738 {
00739
00740
00741 if (!fTable)
00742 fTable = new THashList(1000);
00743
00744 const char *nam = name;
00745 Bool_t append = kFALSE;
00746 if (name[0] == '+') {
00747 nam = &name[1];
00748 append = kTRUE;
00749 }
00750
00751 TEnvRec *er = Lookup(nam);
00752 if (er)
00753 er->ChangeValue(value, type, level, append, fIgnoreDup);
00754 else
00755 fTable->Add(new TEnvRec(nam, value, type, level));
00756 }
00757
00758
00759 void TEnv::SetValue(const char *name, EEnvLevel level)
00760 {
00761
00762
00763
00764
00765 TString buf = name;
00766 int l = buf.Index("=");
00767 if (l > 0) {
00768 TString nm = buf(0, l);
00769 TString val = buf(l+1, buf.Length());
00770 SetValue(nm, val, level);
00771 } else
00772 SetValue(name, "1", level);
00773 }
00774
00775
00776 void TEnv::SetValue(const char *name, Int_t value)
00777 {
00778
00779
00780 SetValue(name, Form("%d", value));
00781 }
00782
00783
00784 void TEnv::SetValue(const char *name, double value)
00785 {
00786
00787
00788 SetValue(name, Form("%g", value));
00789 }
00790
00791
00792 Bool_t TEnv::IgnoreDuplicates(Bool_t ignore)
00793 {
00794
00795
00796
00797 Bool_t ret = fIgnoreDup;
00798 fIgnoreDup = ignore;
00799 return ret;
00800 }