#ifdef R__HAVE_CONFIG
#include "RConfigure.h"
#endif
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "TEnv.h"
#include "TROOT.h"
#include "TSystem.h"
#include "THashList.h"
#include "TError.h"
TEnv *gEnv;
static struct BoolNameTable_t {
   const char *fName;
   Int_t       fValue;
} gBoolNames[]= {
   { "TRUE",  1 },
   { "FALSE", 0 },
   { "ON",    1 },
   { "OFF",   0 },
   { "YES",   1 },
   { "NO",    0 },
   { "OK",    1 },
   { "NOT",   0 },
   { 0, 0 }
};
class TEnvParser {
private:
   FILE    *fIfp;
protected:
   TEnv    *fEnv;
public:
   TEnvParser(TEnv *e, FILE *f) : fIfp(f), fEnv(e) { }
   virtual ~TEnvParser() { }
   virtual void KeyValue(const TString&, const TString&, const TString&) { }
   virtual void Char(Int_t) { }
   void Parse();
};
void TEnvParser::Parse()
{
   
   
   TString name(1024);
   TString type(1024);
   TString value(1024);
   int c, state = 0;
   while ((c = fgetc(fIfp)) != EOF) {
      if (c == 13)        
         continue;
      if (c == '\n') {
         state = 0;
         if (name.Length() > 0) {
            KeyValue(name, value, type);
            name  = "";
            value = "";
            type  = "";
         }
         Char(c);
         continue;
      }
      switch (state) {
      case 0:             
         switch (c) {
         case ' ':
         case '\t':
            break;
         case '#':
            state = 1;
            break;
         default:
            state = 2;
            break;
         }
         break;
      case 1:             
         break;
      case 2:             
         switch (c) {
         case ' ':
         case '\t':
         case ':':
            state = 3;
            break;
         case '(':
            state = 7;
            break;
         default:
            break;
         }
         break;
      case 3:             
         if (c != ' ' && c != '\t')
            state = 4;
         break;
      case 4:             
         break;
      case 5:             
         if (c == ')')
            state = 6;
         break;
      case 6:             
         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);
   }
}
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, value, fLevel, type); }
};
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 &)
{
   
   TEnvRec *er = fEnv->Lookup(name);
   if (er && er->fModified) {
      er->fModified = kFALSE;
      fprintf(fOfp, "%s", er->fValue.Data());
   } else
      fprintf(fOfp, "%s", value.Data());
}
TEnvRec::TEnvRec(const char *n, const char *v, const char *t, EEnvLevel l)
   : fName(n), fType(t), fLevel(l)
{
   
   fValue = ExpandValue(v);
   fModified = (l == kEnvChange);
}
void TEnvRec::ChangeValue(const char *v, const char *, EEnvLevel l,
                          Bool_t append, Bool_t ignoredup)
{
   
   if (l != kEnvChange && fLevel == l && !append) {
      
      
      if (fValue != v && !ignoredup)
         ::Warning("TEnvRec::ChangeValue",
           "duplicate entry <%s=%s> for level %d; ignored", fName.Data(), v, l);
      return;
   }
   if (!append) {
      if (fValue != v) {
         if (l == kEnvChange)
            fModified = kTRUE;
         else
            fModified = kFALSE;
         fLevel = l;
         fValue = ExpandValue(v);
      }
   } else {
      if (l == kEnvChange)
         fModified = kTRUE;
      fLevel = l;
      fValue += " ";
      fValue += ExpandValue(v);
   }
}
Int_t TEnvRec::Compare(const TObject *op) const
{
   
   return fName.CompareTo(((TEnvRec*)op)->fName);
}
TString TEnvRec::ExpandValue(const char *value)
{
   
   
   const char *vv;
   char *v, *vorg = StrDup(value);
   v = vorg;
   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) {
      delete [] vorg;
      return TString(value);
   }
   v = vorg;
   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;
   delete [] vorg;
   return val;
}
ClassImp(TEnv)
TEnv::TEnv(const char *name)
{
   
   
   
   
   
   fIgnoreDup = kFALSE;
   if (!name || !strlen(name) || !gSystem)
      fTable = 0;
   else {
      fTable  = new THashList(1000);
      fRcName = name;
      TString sname = "system";
      sname += name;
#ifdef ROOTETCDIR
      char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
#else
      TString etc = gRootDir;
#ifdef WIN32
      etc += "\\etc";
#else
      etc += "/etc";
#endif
      char *s = gSystem->ConcatFileName(etc, sname);
#endif
      ReadFile(s, kEnvGlobal);
      delete [] s;
      s = gSystem->ConcatFileName(gSystem->HomeDirectory(), name);
      ReadFile(s, kEnvUser);
      delete [] s;
      if (strcmp(gSystem->HomeDirectory(), gSystem->WorkingDirectory()))
         ReadFile(name, kEnvLocal);
   }
}
TEnv::~TEnv()
{
   
   if (fTable) {
      fTable->Delete();
      SafeDelete(fTable);
   }
}
const char *TEnv::Getvalue(const char *name)
{
   
   Bool_t haveProgName = kFALSE;
   if (gProgName && strlen(gProgName) > 0)
      haveProgName = kTRUE;
   TString aname;
   TEnvRec *er = 0;
   if (haveProgName && gSystem && gProgName) {
      aname = gSystem->GetName(); aname += "."; aname += gProgName;
      aname += "."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0 && gSystem && gROOT) {
      aname = gSystem->GetName(); aname += "."; aname += gROOT->GetName();
      aname += "."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0 && gSystem) {
      aname = gSystem->GetName(); aname += ".*."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0 && haveProgName && gProgName) {
      aname = gProgName; aname += "."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0 && gROOT) {
      aname = gROOT->GetName(); aname += "."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0) {
      aname = "*.*."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0) {
      aname = "*."; aname += name;
      er = Lookup(aname);
   }
   if (er == 0) {
      er = Lookup(name);
   }
   if (er == 0)
      return 0;
   return er->fValue;
}
Int_t TEnv::GetValue(const char *name, Int_t dflt)
{
   
   
   const char *cp = TEnv::Getvalue(name);
   if (cp) {
      char buf2[512], *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 = gBoolNames; bt->fName; bt++)
            if (strcmp(buf2, bt->fName) == 0)
               return bt->fValue;
      }
   }
   return dflt;
}
Double_t TEnv::GetValue(const char *name, Double_t dflt)
{
   
   
   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)
{
   
   
   const char *cp = TEnv::Getvalue(name);
   if (cp)
      return cp;
   return dflt;
}
TEnvRec *TEnv::Lookup(const char *name)
{
   
   
   if (!fTable) return 0;
   return (TEnvRec*) fTable->FindObject(name);
}
void TEnv::Print(Option_t *opt) const
{
   
   if (!opt || !strlen(opt)) {
      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) const
{
   
   if (!fTable) return;
   TIter next(fTable);
   TEnvRec *er;
   static const char *lc[] = { "Global", "User", "Local", "Changed" };
   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]);
}
Int_t TEnv::ReadFile(const char *fname, EEnvLevel level)
{
   
   
   if (!fname || !strlen(fname)) {
      Error("ReadFile", "no file name specified");
      return -1;
   }
   FILE *ifp;
   if ((ifp = fopen(fname, "r"))) {
      TReadEnvParser rp(this, ifp, level);
      rp.Parse();
      fclose(ifp);
      return 0;
   }
   
   
   return -1;
}
Int_t TEnv::WriteFile(const char *fname, EEnvLevel level)
{
   
   
   
   if (!fname || !strlen(fname)) {
      Error("WriteFile", "no file name specified");
      return -1;
   }
   if (!fTable) {
      Error("WriteFile", "TEnv table is empty");
      return -1;
   }
   FILE *ofp;
   if ((ofp = fopen(fname, "w"))) {
      TIter next(fTable);
      TEnvRec *er;
      while ((er = (TEnvRec*) next()))
         if (er->fLevel == level || level == kEnvAll)
            fprintf(ofp, "%-40s %s\n", Form("%s:", er->fName.Data()),
                    er->fValue.Data());
      fclose(ofp);
      return 0;
   }
   Error("WriteFile", "cannot open %s for writing", fname);
   return -1;
}
void TEnv::Save()
{
   
   
   if (fRcName == "") {
      Error("Save", "no resource file name specified");
      return;
   }
   SaveLevel(kEnvLocal);  
   SaveLevel(kEnvUser);
   SaveLevel(kEnvGlobal);
}
void TEnv::SaveLevel(EEnvLevel level)
{
   
   if (fRcName == "") {
      Error("SaveLevel", "no resource file name specified");
      return;
   }
   if (!fTable) {
      Error("SaveLevel", "TEnv table is empty");
      return;
   }
   TString   rootrcdir;
   FILE     *ifp, *ofp;
   if (level == kEnvGlobal) {
      TString sname = "system";
      sname += fRcName;
#ifdef ROOTETCDIR
      char *s = gSystem->ConcatFileName(ROOTETCDIR, sname);
#else
      TString etc = gRootDir;
#ifdef WIN32
      etc += "\\etc";
#else
      etc += "/etc";
#endif
      char *s = gSystem->ConcatFileName(etc, sname);
#endif
      rootrcdir = s;
      delete [] s;
   } else if (level == kEnvUser) {
      char *s = gSystem->ConcatFileName(gSystem->HomeDirectory(), fRcName);
      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) {     
         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();
         TIter next(fTable);
         TEnvRec *er;
         while ((er = (TEnvRec*) next())) {
            if (er->fModified) {
               
               if (er->fLevel == kEnvChange) er->fLevel = level;
               if (er->fLevel == level) {
                  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);
   } else
      Error("SaveLevel", "cannot write to file %s", rootrcdir.Data());
}
void TEnv::SetValue(const char *name, const char *value, EEnvLevel level,
                    const char *type)
{
   
   if (!fTable)
      fTable  = new THashList(1000);
   const char *nam = name;
   Bool_t append = kFALSE;
   if (name[0] == '+') {
      nam    = &name[1];
      append = kTRUE;
   }
   TEnvRec *er = Lookup(nam);
   if (er)
      er->ChangeValue(value, type, level, append, fIgnoreDup);
   else
      fTable->Add(new TEnvRec(nam, value, type, level));
}
void TEnv::SetValue(const char *name, EEnvLevel level)
{
   
   
   
   TString buf = name;
   int l = buf.Index("=");
   if (l > 0) {
      TString nm  = buf(0, l);
      TString val = buf(l+1, buf.Length());
      SetValue(nm, val, level);
   } else
      SetValue(name, "1", level);
}
void TEnv::SetValue(const char *name, Int_t value)
{
   
   SetValue(name, Form("%d", value));
}
void TEnv::SetValue(const char *name, double value)
{
   
   SetValue(name, Form("%g", value));
}
Bool_t TEnv::IgnoreDuplicates(Bool_t ignore)
{
   
   
   Bool_t ret = fIgnoreDup;
   fIgnoreDup = ignore;
   return ret;
}
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.