// @(#)root/base:$Name: $:$Id: TEnv.cxx,v 1.2 2000/06/16 17:08:11 rdm Exp $
// Author: Fons Rademakers 22/09/95
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TEnv //
// //
// The TEnv class reads a config file, by default .rootrc. Three types //
// of .rootrc files are read: global, user and local files. The global //
// file resides in $ROOTSYS, the user file in ~/ and the local file in //
// the current working directory. //
// The format of the .rootrc file is similar to the .Xdefaults format: //
// //
// <SystemName>.<RootName|ProgName>.<name>[(type)]: <value> //
// //
// Where <SystemName> is either Unix, WinNT, MacOS or Vms, //
// <RootName> the root name as given in the TROOT ctor, //
// <ProgName> the current program name and //
// <name> is the resource name, with optionally a type specification. //
// //
// E.g.: //
// //
// Unix.rint.Root.DynamicPath: .:$ROOTSYS/lib:~/lib //
// Rint.Root.Debug: FALSE //
// TH.Root.Debug: YES //
// *.Root.MemStat: 1 //
// //
// <SystemName> and <ProgName> or <RootName> may be the wildcard "*". //
// A # in the first column starts comment line. //
// //
// Currently the following resources are defined: //
// Root.Debug (bool) (*) //
// Root.MemStat (bool) (*) //
// Root.MemStat.size (int) (*) //
// Root.MemStat.cnt (int) (*) //
// Root.ObjectStat (bool) (*) //
// Root.MacroPath (string) //
// Root.DynamicPath (string) //
// Rint.Logon (string) //
// Rint.Logoff (string) //
// //
// (*) work only with the <RootName> since no <ProgName> is available //
// at time of initialization. //
// //
// Note that the .rootrc config files contain the config for all ROOT //
// based applications. //
// //
//////////////////////////////////////////////////////////////////////////
#ifdef HAVE_CONFIG
#include "config.h"
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "RConfig.h"
#ifndef WIN32
# ifdef ANSILIB
# include <sstream.h>
# else
# include <strstream.h>
# endif
#else
# ifdef ANSILIB
# include <strstream>
# else
# include <strstrea.h>
# endif
#endif
#include "TEnv.h"
#include "TSystem.h"
#include "TOrdCollection.h"
#include "TError.h"
TEnv *gEnv;
static struct BoolNameTable_t {
const char *fName;
Int_t fValue;
} boolNames[]= {
{ "TRUE", 1 },
{ "FALSE", 0 },
{ "ON", 1 },
{ "OFF", 0 },
{ "YES", 1 },
{ "NO", 0 },
{ "OK", 1 },
{ "NOT", 0 },
{ 0, 0 }
};
//---- TEnvParser --------------------------------------------------------------
class TEnvParser {
private:
FILE *fIfp;
protected:
TEnv *fEnv;
public:
TEnvParser(TEnv *e, FILE *f) : fIfp(f), fEnv(e) { }
virtual void KeyValue(const TString&, const TString&, const TString&) { }
virtual void Char(Int_t) { }
void Parse();
};
//______________________________________________________________________________
void TEnvParser::Parse()
{
// Parse a line of the env file and create an entry in the resource
// dictionary (i.e. add a KeyValue pair).
TString name, type, value;
int c, state = 0;
while ((c = fgetc(fIfp)) != EOF) {
if (c == 'n') {
state = 0;
if (name.Length() > 0) {
KeyValue(name, value, type);
name = "";
value = "";
type = "";
}
Char(c);
continue;
}
switch (state) {
case 0: // start of line
switch (c) {
case ' ':
case 't':
break;
case '#':
state = 1;
break;
default:
state = 2;
break;
}
break;
case 1: // comment
break;
case 2: // name
switch (c) {
case ' ':
case 't':
case ':':
state = 3;
break;
case '(':
state = 7;
break;
default:
break;
}
break;
case 3: // ws before value
if (c != ' ' && c != 't')
state = 4;
break;
case 4: // value
break;
case 5: // type
if (c == ')')
state = 6;
break;
case 6: // optional ':'
state = (c == ':') ? 3 : 4;
break;
case 7:
state = (c == ')') ? 6 : 5;
break;
}
switch (state) {
case 2:
name.Append(c);
break;
case 4:
value.Append(c);
break;
case 5:
type.Append(c);
break;
}
if (state != 4)
Char(c);
}
}
//---- TReadEnvParser ----------------------------------------------------------
class TReadEnvParser : public TEnvParser {
private:
EEnvLevel fLevel;
public:
TReadEnvParser(TEnv *e, FILE *f, EEnvLevel l) : TEnvParser(e, f), fLevel(l) { }
void KeyValue(const TString &name, const TString &value, const TString &type)
{ fEnv->SetValue(name.Data(), value, fLevel, type.Data()); }
};
//---- TWriteEnvParser ---------------------------------------------------------
class TWriteEnvParser : public TEnvParser {
private:
FILE *fOfp;
public:
TWriteEnvParser(TEnv *e, FILE *f, FILE *of) : TEnvParser(e, f), fOfp(of) { }
void KeyValue(const TString &name, const TString &value, const TString &type);
void Char(Int_t c) { fputc(c, fOfp); }
};
//______________________________________________________________________________
void TWriteEnvParser::KeyValue(const TString &name, const TString &value,
const TString &)
{
// Write resources out to a new file.
TEnvRec *er = fEnv->Lookup(name.Data());
if (er && er->fModified) {
er->fModified = kFALSE;
if (er->fObject)
er->Write(er->fObject);
fprintf(fOfp, "%s", er->fValue.Data());
} else
fprintf(fOfp, "%s", value.Data());
}
//---- TEnvRec -----------------------------------------------------------------
//______________________________________________________________________________
TEnvRec::TEnvRec(const char *n, const char *v, const char *t, EEnvLevel l)
: fName(n), fType(t), fLevel(l), fObject(0)
{
// Ctor of a single resource.
fValue = ExpandValue(v);
fModified = (l == kEnvChange);
}
//______________________________________________________________________________
TEnvRec::TEnvRec(const char *n, const TString &v, const char *t, EEnvLevel l)
: fName(n), fType(t), fLevel(l), fObject(0)
{
// Ctor of a single resource.
fValue = ExpandValue(v.Data());
fModified = (l == kEnvChange);
}
//______________________________________________________________________________
void TEnvRec::Read(TObject *)
{
// Read a resource record.
#ifdef ANSILIB
#else
istrstream is((char*)fValue.Data(), fValue.Length());
#endif
//op->ReadFrom(is);
}
//______________________________________________________________________________
void TEnvRec::Write(TObject *)
{
// Write a changed resource record.
char *cp = new char[1000];
#ifdef ANSILIB
#else
ostrstream os(cp, 1000);
#endif
//op->PrintOn(os);
ChangeValue(cp, 0, kEnvChange);
delete cp;
}
//______________________________________________________________________________
void TEnvRec::ChangeValue(const char *v, const char*, EEnvLevel l)
{
// Change the value of a resource.
if (l != kEnvChange && fLevel == l) {
// use global Warning() since interpreter might not yet be initialized
// at this stage (called from TROOT ctor)
::Warning("TEnvRec::ChangeValue",
"duplicate entry <%s=%s> for level %d; ignored", fName.Data(), v, l);
return;
}
if (fValue != v) {
if (l == kEnvChange)
fModified = kTRUE;
else {
fModified = kFALSE;
fLevel = l;
}
fValue = ExpandValue(v);
if (fModified && fObject)
Read(fObject);
}
}
//______________________________________________________________________________
void TEnvRec::ChangeValue(const TString &v, const char *, EEnvLevel l)
{
// Change the value of a resource.
if (l != kEnvChange && fLevel == l) {
// use global Warning() since interpreter might not yet be initialized
// at this stage (called from TROOT ctor)
::Warning("TEnvRec::ChangeValue",
"duplicate entry <%s=%s> for level %d; ignored", fName.Data(), v.Data(), l);
return;
}
if (fValue != v) {
if (l == kEnvChange)
fModified = kTRUE;
else {
fModified = kFALSE;
fLevel = l;
}
fValue = ExpandValue(v.Data());
if (fModified && fObject)
Read(fObject);
}
}
//______________________________________________________________________________
Int_t TEnvRec::Compare(TObject *op)
{
// Comparison function for resources.
return fName.CompareTo(((TEnvRec*)op)->fName);
}
//______________________________________________________________________________
TString TEnvRec::ExpandValue(const char *value)
{
// Replace all $(XXX) strings by the value defined in the shell
// (obtained via TSystem::Getenv()).
const char *v = value;
const char *vv;
char *s1, *s2;
int len = 0;
while ((s1 = (char*)strstr(v, "$("))) {
s1 += 2;
s2 = (char*)strchr(s1, ')');
if (!s2) {
len = 0;
break;
}
*s2 = 0;
vv = gSystem->Getenv(s1);
if (vv) len += strlen(vv);
*s2 = ')';
v = s2 + 1;
}
if (!len)
return TString(value);
v = value;
char *nv = new char[strlen(v) + len];
*nv = 0;
while ((s1 = (char*)strstr(v, "$("))) {
*s1 = 0;
strcat(nv, v);
*s1 = '$';
s1 += 2;
s2 = (char*)strchr(s1, ')');
*s2 = 0;
vv = gSystem->Getenv(s1);
if (vv) strcat(nv, vv);
*s2 = ')';
v = s2 + 1;
}
if (*v) strcat(nv, v);
TString val = nv;
delete [] nv;
return val;
}
//---- TEnv --------------------------------------------------------------------
ClassImp(TEnv)
//______________________________________________________________________________
TEnv::TEnv(const char *name)
{
// Create a resource table and read the (possibly) three resource files, i.e
// $ROOTSYS/system<name> (or ROOTETCDIR/system<name>), $HOME/<name> and
// ./<name>. ROOT always reads ".rootrc" (in TROOT::InitSystem()). You can
// read additional user defined resource files by creating addtional TEnv
// object.
if (strlen(name) == 0)
fTable = 0;
else {
fTable = new TOrdCollection(1000);
fRcName = name;
char sname[128] = "system";
strcat(sname, name);
#ifdef ROOTETCDIR
char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
#else
char *s = gSystem->ConcatFileName(gRootDir, sname);
if (gSystem->AccessPathName(s)) {
// for backward compatibility check also <name> if "system<name>
// does not exist
delete [] s;
s = gSystem->ConcatFileName(gRootDir, name);
}
#endif
ReadFile(s, kEnvGlobal);
delete [] s;
s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
ReadFile(s, kEnvUser);
delete [] s;
ReadFile(name, kEnvLocal);
}
}
//______________________________________________________________________________
TEnv::~TEnv()
{
// Delete the resource table.
if (fTable) {
fTable->Delete();
SafeDelete(fTable);
}
}
//______________________________________________________________________________
const char *TEnv::Getvalue(const char *name)
{
// Returns the character value for a named resouce.
Bool_t haveProgName = kFALSE;
if (gProgName && strlen(gProgName) > 0)
haveProgName = kTRUE;
TEnvRec *er = 0;
if (haveProgName)
er = Lookup(Form("%s.%s.%s", gSystemName, gProgName, name));
if (er == 0)
er = Lookup(Form("%s.%s.%s", gSystemName, gRootName, name));
if (er == 0)
er = Lookup(Form("%s.*.%s", gSystemName, name));
if (er == 0 && haveProgName)
er = Lookup(Form("%s.%s", gProgName, name));
if (er == 0)
er = Lookup(Form("%s.%s", gRootName, name));
if (er == 0)
er = Lookup(Form("*.*.%s", name));
if (er == 0)
er = Lookup(Form("*.%s", name));
if (er == 0)
er = Lookup(name);
if (er == 0)
return 0;
return er->fValue.Data();
}
//______________________________________________________________________________
Int_t TEnv::GetValue(const char *name, Int_t dflt)
{
// Returns the integer value for a resource. If the resource is not found
// return the dflt value.
const char *cp = TEnv::Getvalue(name);
if (cp) {
char buf2[100], *cp2 = buf2;
while (isspace((int)*cp))
cp++;
if (*cp) {
BoolNameTable_t *bt;
if (isdigit((int)*cp) || *cp == '-' || *cp == '+')
return atoi(cp);
while (isalpha((int)*cp))
*cp2++ = toupper((int)*cp++);
*cp2 = 0;
for (bt = boolNames; bt->fName; bt++)
if (strcmp(buf2, bt->fName) == 0)
return bt->fValue;
}
}
return dflt;
}
//______________________________________________________________________________
Double_t TEnv::GetValue(const char *name, Double_t dflt)
{
// Returns the dobule value for a resource. If the resource is not found
// return the dflt value.
const char *cp = TEnv::Getvalue(name);
if (cp) {
char *endptr;
Double_t val = strtod(cp, &endptr);
if (val == 0.0 && cp == endptr)
return dflt;
return val;
}
return dflt;
}
//______________________________________________________________________________
const char *TEnv::GetValue(const char *name, const char *dflt)
{
// Returns the character value for a named resouce. If the resource is
// not found the dflt value is returned.
const char *cp = TEnv::Getvalue(name);
if (cp)
return cp;
return dflt;
}
//______________________________________________________________________________
TObject *TEnv::GetValue(const char *name, TObject *op)
{
// Read in object op the values of the resource and return the object.
TEnvRec *er = Lookup(Form("%s.%s", gProgName, name));
if (er == 0)
er = Lookup(Form("*.%s", name));
if (er == 0)
er = Lookup(name);
if (er) {
er->fObject = op;
er->Read(op);
}
return op;
}
//______________________________________________________________________________
TEnvRec *TEnv::Lookup(const char *name)
{
// Loop over all resource records and return the one with name.
// Return 0 in case name is not in the resoucre table.
TIter next(fTable);
TEnvRec *er;
while ((er = (TEnvRec*) next()))
if (er->fName == name)
return er;
return 0;
}
//______________________________________________________________________________
void TEnv::Print(Option_t *opt)
{
// Print all resources or the global, user or local resources separately.
if (strlen(opt) == 0) {
PrintEnv();
return;
}
if (!strcmp(opt, "global"))
PrintEnv(kEnvGlobal);
if (!strcmp(opt, "user"))
PrintEnv(kEnvUser);
if (!strcmp(opt, "local"))
PrintEnv(kEnvLocal);
}
//______________________________________________________________________________
void TEnv::PrintEnv(EEnvLevel level)
{
// Print all resources for a certain level (global, user, local).
TIter next(fTable);
TEnvRec *er;
static const char *lc[] = { "Global", "User", "Local" };
while ((er = (TEnvRec*) next()))
if (er->fLevel == level || level == kEnvAll)
Printf("%-25s %-30s [%s]", Form("%s:", er->fName.Data()),
er->fValue.Data(), lc[er->fLevel]);
}
//______________________________________________________________________________
void TEnv::ReadFile(const char *fname, EEnvLevel level)
{
// Read and parse the resource file for a certain level.
FILE *ifp;
if ((ifp = fopen(fname, "r"))) {
TReadEnvParser rp(this, ifp, level);
rp.Parse();
fclose(ifp);
}
}
//______________________________________________________________________________
void TEnv::Save()
{
// Write the resource files for each level. The new files have the same
// name as the original files. The old files are renamed to *.bak.
SaveLevel(kEnvGlobal);
SaveLevel(kEnvUser);
SaveLevel(kEnvLocal);
}
//______________________________________________________________________________
void TEnv::SaveLevel(EEnvLevel level)
{
// Write the resource file for a certain level.
TIter next(fTable);
TEnvRec *er;
while ((er = (TEnvRec*) next()))
if (er->fLevel == level)
break;
if (!er) return;
TString rootrcdir;
FILE *ifp, *ofp;
if (level == kEnvGlobal) {
#ifdef ROOTETCDIR
char sname[128] = "system";
strcat(sname, fRcName.Data());
char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
#else
char *s = gSystem->ConcatFileName(gRootDir, fRcName.Data());
#endif
rootrcdir = s;
delete [] s;
} else if (level == kEnvUser) {
char *s = gSystem->ConcatFileName(gSystem->HomeDirectory(), fRcName.Data());
rootrcdir = s;
delete [] s;
} else if (level == kEnvLocal)
rootrcdir = fRcName;
else
return;
if ((ofp = fopen(Form("%s.new", rootrcdir.Data()), "w"))) {
ifp = fopen(rootrcdir.Data(), "r");
if (ifp == 0) { // try to create file
ifp = fopen(rootrcdir.Data(), "w");
if (ifp) {
fclose(ifp);
ifp = 0;
}
}
if (ifp || (ifp = fopen(rootrcdir.Data(), "r"))) {
TWriteEnvParser wp(this, ifp, ofp);
wp.Parse();
next.Reset();
while ((er = (TEnvRec*) next()))
if (er->fModified) {
er->fModified = kFALSE;
fprintf(ofp, "%-40s %s\n", Form("%s:", er->fName.Data()),
er->fValue.Data());
}
fclose(ifp);
fclose(ofp);
gSystem->Rename(rootrcdir.Data(), Form("%s.bak", rootrcdir.Data()));
gSystem->Rename(Form("%s.new", rootrcdir.Data()), rootrcdir.Data());
return;
}
fclose(ofp);
}
}
//______________________________________________________________________________
void TEnv::SetValue(const char *name, const TString &value, EEnvLevel level, const char *type)
{
// Set the value of a resource or create a new resource.
TEnvRec *er = Lookup(name);
if (er)
er->ChangeValue(value, type, level);
else
fTable->Add(new TEnvRec(name, value, type, level));
}
//______________________________________________________________________________
void TEnv::SetValue(const char *name, const char *value, EEnvLevel level, const char *type)
{
// Set the value of a resource or create a new resource.
TEnvRec *er = Lookup(name);
if (er)
er->ChangeValue(value, type, level);
else
fTable->Add(new TEnvRec(name, value, type, level));
}
//______________________________________________________________________________
void TEnv::SetValue(const char *name, EEnvLevel level)
{
// Set the value of a resource or create a new resource.
TString buf = name;
int l = buf.Index("=");
if (l > 0) {
TString nm = buf(0, l);
TString val = buf(l+1, buf.Length());
SetValue(nm.Data(), val.Data(), level);
} else
SetValue(name, "1", level);
}
//______________________________________________________________________________
void TEnv::SetValue(const char *name, Int_t value)
{
// Set or create an integer resource value.
SetValue(name, Form("%d", value));
}
//______________________________________________________________________________
void TEnv::SetValue(const char *name, double value)
{
// Set or create a double resource value.
SetValue(name, Form("%f", value));
}
ROOT page - Class index - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.