Since several tools and examples want JIT support, factor out the process of
[oota-llvm.git] / tools / llvmc / Configuration.cpp
index 94949c405de98f0fc323866628f4874d0fdc2a47..6b5d33975f2c0a4f2a57c0e5317bf772f5661dc5 100644 (file)
@@ -1,4 +1,4 @@
-//===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
+//===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
 // 
 //                     The LLVM Compiler Infrastructure
 //
 //
 //===------------------------------------------------------------------------===
 
-#include "ConfigData.h"
+#include "Configuration.h"
+#include "ConfigLexer.h"
 #include "CompilerDriver.h"
-#include "Support/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/ADT/StringExtras.h"
 #include <iostream>
+#include <fstream>
 
 using namespace llvm;
 
+namespace sys {
+  // From CompilerDriver.cpp (for now)
+  extern bool FileIsReadable(const std::string& fname);
+}
+
+namespace llvm {
+  ConfigLexerInfo ConfigLexerState;
+  InputProvider* ConfigLexerInput = 0;
+
+  InputProvider::~InputProvider() {}
+  void InputProvider::error(const std::string& msg) {
+    std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " << 
+      msg << "\n";
+    errCount++;
+  }
+
+  void InputProvider::checkErrors() {
+    if (errCount > 0) {
+      std::cerr << name << " had " << errCount << " errors. Terminating.\n";
+      exit(errCount);
+    }
+  }
+
+}
+
 namespace {
 
-// This array of strings provides the input for ".ll" files (LLVM Assembly)
-// to the configuration file parser. This data is just "built-in" to 
-// llvmc so it doesn't have to be read from a configuration file.
-static const char* LL_Data[] = {
-  "lang.name=LLVM Assembly", 
-  "lang.translator.preprocesses=false",
-  "lang.translator.optimizes=No",
-  "lang.translator.groks_dash_O=No",
-  "lang.preprocessor.needed=0",
-  "preprocessor.prog=",
-  "preprocessor.args=",
-  "translator.prog=llvm-as",
-  "translator.args=@in@ -o @out@",
-  "optimizer.prog=opt",
-  "optimizer.args=@in@ -o @out@",
-  "assembler.prog=llc",
-  "assembler.args=@in@ -o @out@",
-  "linker.prog=llvm-link",
-  "linker.args=@in@ -o @out@"
-};
-
-// This array of strings provides the input for ".st" files (Stacker).
-static const char* ST_Data[] = {
-  "lang.name=Stacker", 
-  "lang.translator.preprocesses=false",
-  "lang.translator.optimizes=true",
-  "lang.translator.groks_dash_O=0",
-  "lang.preprocessor.needed=0",
-  "preprocessor.prog=cp",
-  "preprocessor.args=@in@ @out@",
-  "translator.prog=stkrc",
-  "translator.args=@in@ -o @out@ -S 2048",
-  "optimizer.prog=opt",
-  "optimizer.args=@in@ -o @out@",
-  "assembler.prog=llc",
-  "assembler.args=@in@ -o @out@",
-  "linker.prog=llvm-link",
-  "linker.args=@in@ -o @out@"
-};
-
-class InputProvider {
-  public:
-    virtual bool getLine(std::string& line) = 0;
-    virtual void error(const std::string& msg) = 0;
-    virtual bool errorOccurred() = 0;
-};
-
-class StaticInputProvider : public InputProvider {
-  public:
-    StaticInputProvider(const char *data[], size_t count,
-        const std::string& nam) { 
-      TheData = data; 
-      limit = count;
-      where = 0;
-      name = nam;
-      errCount = 0;
+  class FileInputProvider : public InputProvider {
+    public:
+      FileInputProvider(const std::string & fname)
+        : InputProvider(fname) 
+        , F(fname.c_str()) {
+        ConfigLexerInput = this;
+      }
+      virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
+      virtual unsigned read(char *buffer, unsigned max_size) {
+        if (F.good()) {
+          F.read(buffer,max_size);
+          if ( F.gcount() ) return F.gcount() - 1;
+        }
+        return 0;
+      }
+
+      bool okay() { return F.good(); }
+    private:
+      std::ifstream F;
+  };
+
+  cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden, cl::init(false),
+    cl::desc("Dump lexical tokens (debug use only)."));
+
+  struct Parser
+  {
+    Parser() {
+      token = EOFTOK;
+      provider = 0;
+      confDat = 0;
+      ConfigLexerState.lineNum = 1;
+      ConfigLexerState.in_value = false;
+      ConfigLexerState.StringVal.clear();
+      ConfigLexerState.IntegerVal = 0;
+    };
+
+    ConfigLexerTokens token;
+    InputProvider* provider;
+    CompilerDriver::ConfigData* confDat;
+
+    inline int next() { 
+      token = Configlex();
+      if (DumpTokens) 
+        std::cerr << token << "\n";
+      return token;
     }
-    virtual ~StaticInputProvider() {}
-    virtual bool getLine(std::string& line) {
-      if ( where >= limit ) return false;
-      line = TheData[where++];
-      return true;
+
+    inline bool next_is_real() { 
+      next();
+      return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
     }
 
-    virtual void error(const std::string& msg) {
-      std::cerr << name << ":" << where << ": Error: " << msg << "\n";
-      errCount++;
+    inline void eatLineRemnant() {
+      while (next_is_real()) ;
     }
 
-    virtual bool errorOccurred() { return errCount > 0; };
+    void error(const std::string& msg, bool skip = true) {
+      provider->error(msg);
+      if (skip)
+        eatLineRemnant();
+    }
 
-  private:
-    const char**TheData;
-    size_t limit;
-    size_t where;
-    std::string name;
-    size_t errCount;
-};
+    std::string parseName() {
+      std::string result;
+      if (next() == EQUALS) {
+        while (next_is_real()) {
+          switch (token ) {
+            case STRING :
+            case OPTION : 
+              result += ConfigLexerState.StringVal + " ";
+              break;
+            default:
+              error("Invalid name");
+              break;
+          }
+        }
+        if (result.empty())
+          error("Name exepected");
+        else
+          result.erase(result.size()-1,1);
+      } else
+        error("= expected");
+      return result;
+    }
 
-inline bool recognize(const char*& p, const char*token) {
-  while (*p == *token && *token != '\0')
-    ++token, p++;
-  return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
-}
+    bool parseBoolean() {
+      bool result = true;
+      if (next() == EQUALS) {
+        if (next() == FALSETOK) {
+          result = false;
+        } else if (token != TRUETOK) {
+          error("Expecting boolean value");
+          return false;
+        }
+        if (next() != EOLTOK && token != 0) {
+          error("Extraneous tokens after boolean");
+        }
+      }
+      else
+        error("Expecting '='");
+      return result;
+    }
 
-inline bool getBoolean(const std::string& value) {
-  switch (value[0]) {
-    case 't':
-    case 'T':
-    case '1':
-    case 'y':
-    case 'Y':
+    bool parseSubstitution(CompilerDriver::StringVector& optList) {
+      switch (token) {
+        case ARGS_SUBST:        optList.push_back("%args%"); break;
+        case DEFS_SUBST:        optList.push_back("%defs%"); break;
+        case FORCE_SUBST:       optList.push_back("%force%"); break;
+        case IN_SUBST:          optList.push_back("%in%"); break;
+        case INCLS_SUBST:       optList.push_back("%incls%"); break;
+        case LIBS_SUBST:        optList.push_back("%libs%"); break;
+        case OPT_SUBST:         optList.push_back("%opt%"); break;
+        case OUT_SUBST:         optList.push_back("%out%"); break;
+        case TARGET_SUBST:      optList.push_back("%target%"); break;
+        case STATS_SUBST:       optList.push_back("%stats%"); break;
+        case TIME_SUBST:        optList.push_back("%time%"); break;
+        case VERBOSE_SUBST:     optList.push_back("%verbose%"); break;
+        default:
+          return false;
+      }
       return true;
-    default :
-      return false;
-  }
-  return false;
-}
-
-inline void skipWhitespace( size_t& pos, const std::string& line ) {
-  while (pos < line.size() && (
-           line[pos] == ' ' ||  // Space
-           line[pos] == '\t' || // Horizontal Tab
-           line[pos] == '\n' || // New Line
-           line[pos] == '\v' || // Vertical Tab
-           line[pos] == '\f' || // Form Feed
-           line[pos] == '\r')   // Carriate Return
-        )
-      pos++;
-}
+    }
 
-inline void parseArgs(CompilerDriver::Action& pat, 
-                      const std::string& value, 
-                      InputProvider& provider )
-{
-  const char* p = value.c_str();
-  const char* argStart = p;
-  while (*p != '\0') {
-    switch (*p) {
-      case ' ':
-        if (argStart != p)
-          pat.args.push_back(std::string(argStart, p-argStart));
-        argStart = ++p;
-        break;
-      case '@' : 
-        {
-          if (argStart != p)
-            pat.args.push_back(std::string(argStart,p-argStart));
-          const char* token = ++p;
-          while (*p != '@' && *p != 0) 
-            p++;
-          if ( *p != '@' ) {
-            provider.error("Unterminated substitution token");
-            return;
-          } else {
-            p++;
-            bool legal = false;
-            switch (token[0]) {
-              case 'i':
-                if (token[1] == 'n' && token[2] == '@' ) {
-                  pat.inputAt = pat.args.size();
-                  pat.args.push_back("in");
-                  legal = true; 
-                  argStart = p;
-                }
-                break;
-              case 'o':
-                if (token[1] == 'u' && token[2] == 't' && token[3] == '@') {
-                  pat.outputAt = pat.args.size();
-                  pat.args.push_back("out");
-                  legal = true;
-                  argStart = p;
-                }
-                break;
-              default:
-                break;
-            }
-            if (!legal) {
-              provider.error("Invalid substitution token");
-              return;
-            }
+    void parseOptionList(CompilerDriver::StringVector& optList ) {
+      if (next() == EQUALS) {
+        while (next_is_real()) {
+          if (token == STRING || token == OPTION)
+            optList.push_back(ConfigLexerState.StringVal);
+          else if (!parseSubstitution(optList)) {
+            error("Expecting a program argument or substitution", false);
+            break;
           }
         }
-        break;
-      default :
-        p++;
-        break;
+      } else
+        error("Expecting '='");
     }
-  }
-}
 
-CompilerDriver::ConfigData*
-ParseConfigData(InputProvider& provider) {
-  std::string line;
-  CompilerDriver::ConfigData data;
-  while ( provider.getLine(line) ) {
-    // Check line length first
-    size_t lineLen = line.size();
-    if (lineLen > 4096)
-      provider.error("length of input line (" + utostr(lineLen) + 
-                     ") is too long");
-
-    // First, skip whitespace
-    size_t stPos = 0;
-    skipWhitespace(stPos, line);
-
-    // See if there's a hash mark. It and everything after it is 
-    // ignored so lets delete that now.
-    size_t hashPos = line.find('#');
-    if (hashPos != std::string::npos)
-      line.erase(hashPos);
-
-    // Make sure we have something left to parse
-    if (line.size() == 0)
-      continue; // ignore full-line comment or whitespace line
-
-    // Find the equals sign
-    size_t eqPos = line.find('=');
-    if (eqPos == std::string::npos) 
-      provider.error("Configuration directive is missing an =");
-
-    // extract the item name
-    std::string name(line, stPos, eqPos-stPos);
-
-    // directives without names are illegal
-    if (name.empty())
-      provider.error("Configuration directive name is empty");
-
-    // Skip whitespace in the value
-    size_t valPos = eqPos + 1;
-    skipWhitespace(valPos, line);
-
-    // Skip white space at end of value
-    size_t endPos = line.length() - 1;
-    while (line[endPos] == ' ') 
-      endPos--;
-    // extract the item value
-    std::string value(line, valPos, endPos-valPos+1);
-
-    // Get the configuration item as a char pointer
-    const char*p = name.c_str();
-
-    // Indicate we haven't found an invalid item yet.
-    bool invalidItem = false;
-
-    // Parse the contents by examining first character and
-    // using the recognize function strategically
-    switch (*p++) {
-      case 'l' :
-        // could it be "lang."
-        if (*p == 'a') {         // "lang." ?
-          if (recognize(p,"ang")) {
-            p++;
-            switch (*p++) {
-              case 'n':
-                if (recognize(p,"ame"))
-                  data.langName = value;
-                else
-                  invalidItem = true;
-                break;
-              case 't':
-                if (recognize(p,"ranslator")) {
-                  p++;
-                  if (recognize(p,"preprocesses")) 
-                    data.TranslatorPreprocesses = getBoolean(value);
-                  else if (recognize(p, "optimizes")) 
-                    data.TranslatorOptimizes = getBoolean(value);
-                  else if (recognize(p, "groks_dash_O"))
-                    data.TranslatorGroksDashO = getBoolean(value);
-                  else
-                    invalidItem = true;
-                }
-                else
-                  invalidItem = true;
-                break;
-              case 'p':
-                if (recognize(p,"reprocessor")) {
-                  p++;
-                  if (recognize(p,"needed")) {
-                    data.PreprocessorNeeded = getBoolean(value);
-                  } else
-                    invalidItem = true;
-                }
-                else
-                  invalidItem = true;
-                break;
-                  
-              default:
-                invalidItem = true;
-                break;
-            }
-          }
-        } else if (*p == 'i') {  // "linker." ?
-          if (recognize(p,"inker")) {
-            p++;
-            if (recognize(p,"prog"))
-              data.Linker.program = value;
-            else if (recognize(p,"args"))
-              parseArgs(data.Linker,value,provider);
-            else
-              invalidItem = true;
-          }
+    void parseVersion() {
+      if (next() == EQUALS) {
+        while (next_is_real()) {
+          if (token == STRING || token == OPTION)
+            confDat->version = ConfigLexerState.StringVal;
           else
-            invalidItem = true;
-        } else {
-          invalidItem = true;
-        }
-        break;
-
-      case 'p' :
-        if (*p == 'r') {         // "preprocessor." ?
-          if (recognize(p, "reprocessor")) {
-            p++;
-            if (recognize(p,"prog")) 
-              data.PreProcessor.program = value;
-            else if (recognize(p,"args"))
-              parseArgs(data.PreProcessor,value,provider);
-            else
-              invalidItem = true;
-          } else
-            invalidItem = true;
-        } else {
-          invalidItem = true;
+            error("Expecting a version string");
         }
-        break;
-
-      case 't' :
-        if (*p == 'r') {         // "translator." ?
-          if (recognize(p, "ranslator")) {
-            p++;
-            if (recognize(p,"prog")) 
-              data.Translator.program = value;
-            else if (recognize(p,"args"))
-              parseArgs(data.Translator,value,provider);
-            else
-              invalidItem = true;
-          } else
-            invalidItem = true;
+      } else
+        error("Expecting '='");
+    }
+
+    void parseLang() {
+      switch (next() ) {
+        case NAME: 
+          confDat->langName = parseName(); 
+          break;
+        case OPT1: 
+          parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]); 
+          break;
+        case OPT2: 
+          parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]); 
+          break;
+        case OPT3: 
+          parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]); 
+          break;
+        case OPT4: 
+          parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]); 
+          break;
+        case OPT5: 
+          parseOptionList(
+            confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
+          break;
+        default:   
+          error("Expecting 'name' or 'optN' after 'lang.'"); 
+          break;
+      }
+    }
+
+    void parseCommand(CompilerDriver::Action& action) {
+      if (next() == EQUALS) {
+        if (next() == EOLTOK) {
+          // no value (valid)
+          action.program.clear();
+          action.args.clear();
         } else {
-          invalidItem = true;
+          if (token == STRING || token == OPTION) {
+            action.program.set_file(ConfigLexerState.StringVal);
+          } else {
+            error("Expecting a program name");
+          }
+          while (next_is_real()) {
+            if (token == STRING || token == OPTION) {
+              action.args.push_back(ConfigLexerState.StringVal);
+            } else if (!parseSubstitution(action.args)) {
+              error("Expecting a program argument or substitution", false);
+              break;
+            }
+          }
         }
-        break;
-
-      case 'o' :
-        if (*p == 'p') {         // "optimizer." ?
-          if (recognize(p, "ptimizer")) {
-            p++;
-            if (recognize(p,"prog")) 
-              data.Optimizer.program = value;
-            else if (recognize(p,"args"))
-              parseArgs(data.Optimizer,value,provider);
-            else
-              invalidItem = true;
-          } else
-            invalidItem = true;
+      }
+    }
+
+    void parsePreprocessor() {
+      switch (next()) {
+        case COMMAND:
+          parseCommand(confDat->PreProcessor);
+          break;
+        case REQUIRED:
+          if (parseBoolean())
+            confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
+          else
+            confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
+          break;
+        default:
+          error("Expecting 'command' or 'required' but found '" +
+              ConfigLexerState.StringVal);
+          break;
+      }
+    }
+
+    bool parseOutputFlag() {
+      if (next() == EQUALS) {
+        if (next() == ASSEMBLY) {
+          return true;
+        } else if (token == BYTECODE) {
+          return false;
         } else {
-          invalidItem = true;
+          error("Expecting output type value");
+          return false;
         }
-        break;
-      case 'a' :
-        if (*p == 's') {         // "assembler." ?
-          if (recognize(p, "ssembler")) {
-            p++;
-            if (recognize(p,"prog")) 
-              data.Assembler.program = value;
-            else if (recognize(p,"args"))
-              parseArgs(data.Assembler,value,provider);
-            else
-              invalidItem = true;
-          } else
-            invalidItem = true;
-        } else {
-          invalidItem = true;
+        if (next() != EOLTOK && token != 0) {
+          error("Extraneous tokens after output value");
         }
-        break;
+      }
+      else
+        error("Expecting '='");
+      return false;
+    }
+
+    void parseTranslator() {
+      switch (next()) {
+        case COMMAND: 
+          parseCommand(confDat->Translator);
+          break;
+        case REQUIRED:
+          if (parseBoolean())
+            confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
+          else
+            confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
+          break;
+        case PREPROCESSES:
+          if (parseBoolean())
+            confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
+          else 
+            confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
+          break;
+        case OUTPUT:
+          if (parseOutputFlag())
+            confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+          else
+            confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+          break;
+
+        default:
+          error("Expecting 'command', 'required', 'preprocesses', or "
+                "'output' but found '" + ConfigLexerState.StringVal +
+                "' instead");
+          break;
+      }
+    }
+
+    void parseOptimizer() {
+      switch (next()) {
+        case COMMAND:
+          parseCommand(confDat->Optimizer);
+          break;
+        case PREPROCESSES:
+          if (parseBoolean())
+            confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
+          else
+            confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
+          break;
+        case TRANSLATES:
+          if (parseBoolean())
+            confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
+          else
+            confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
+          break;
+        case REQUIRED:
+          if (parseBoolean())
+            confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
+          else
+            confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
+          break;
+        case OUTPUT:
+          if (parseOutputFlag())
+            confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+          else
+            confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+          break;
+        default:
+          error(std::string("Expecting 'command', 'preprocesses', ") +
+              "'translates' or 'output' but found '" + 
+              ConfigLexerState.StringVal + "' instead");
+          break;
+      }
+    }
+
+    void parseAssembler() {
+      switch(next()) {
+        case COMMAND:
+          parseCommand(confDat->Assembler);
+          break;
+        default:
+          error("Expecting 'command'");
+          break;
+      }
+    }
+
+    void parseLinker() {
+      switch(next()) {
+        case LIBS:
+          break; //FIXME
+        case LIBPATHS:
+          break; //FIXME
+        default:
+          error("Expecting 'libs' or 'libpaths'");
+          break;
+      }
     }
-    if (invalidItem)
-      provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos));
+
+    void parseAssignment() {
+      switch (token) {
+        case VERSION:       parseVersion(); break;
+        case LANG:          parseLang(); break;
+        case PREPROCESSOR:  parsePreprocessor(); break;
+        case TRANSLATOR:    parseTranslator(); break;
+        case OPTIMIZER:     parseOptimizer(); break;
+        case ASSEMBLER:     parseAssembler(); break;
+        case LINKER:        parseLinker(); break;
+        case EOLTOK:        break; // just ignore
+        case ERRORTOK:
+        default:          
+          error("Invalid top level configuration item");
+          break;
+      }
+    }
+
+    void parseFile() {
+      while ( next() != EOFTOK ) {
+        if (token == ERRORTOK)
+          error("Invalid token");
+        else if (token != EOLTOK)
+          parseAssignment();
+      }
+      provider->checkErrors();
+    }
+  };
+
+  void
+  ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
+    Parser p;
+    p.token = EOFTOK;
+    p.provider = &provider;
+    p.confDat = &confDat;
+    p.parseFile();
   }
-  return new CompilerDriver::ConfigData(data);
 }
 
 CompilerDriver::ConfigData*
-ReadConfigData(const std::string& ftype) {
-  if ( ftype == "ll" ) {
-    StaticInputProvider sip(LL_Data, sizeof(LL_Data)/sizeof(LL_Data[0]), 
-      "LLVM Assembly (internal)");
-    return ParseConfigData(sip);
-  } else if (ftype == "st") {
-    StaticInputProvider sip(ST_Data, sizeof(ST_Data)/sizeof(ST_Data[0]),
-      "Stacker (internal)");
-    return ParseConfigData(sip);
+LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
+  CompilerDriver::ConfigData* result = 0;
+  sys::Path confFile;
+  if (configDir.is_empty()) {
+    // Try the environment variable
+    const char* conf = getenv("LLVM_CONFIG_DIR");
+    if (conf) {
+      confFile.set_directory(conf);
+      confFile.append_file(ftype);
+      if (!confFile.readable())
+        throw std::string("Configuration file for '") + ftype + 
+                          "' is not available.";
+    } else {
+      // Try the user's home directory
+      confFile = sys::Path::GetUserHomeDirectory();
+      if (!confFile.is_empty()) {
+        confFile.append_directory(".llvm");
+        confFile.append_directory("etc");
+        confFile.append_file(ftype);
+        if (!confFile.readable())
+          confFile.clear();
+      }
+      if (!confFile.is_empty()) {
+        // Okay, try the LLVM installation directory
+        confFile = sys::Path::GetLLVMConfigDir();
+        confFile.append_file(ftype);
+        if (!confFile.readable()) {
+          // Okay, try the "standard" place
+          confFile = sys::Path::GetLLVMDefaultConfigDir();
+          confFile.append_file(ftype);
+          if (!confFile.readable()) {
+            throw std::string("Configuration file for '") + ftype + 
+                              "' is not available.";
+          }
+        }
+      }
+    }
+  } else {
+    confFile = configDir;
+    confFile.append_file(ftype);
+    if (!confFile.readable())
+      throw std::string("Configuration file for '") + ftype + 
+                        "' is not available.";
   }
-  return 0;
-}
-
-}
-
-LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider() 
-  : Configurations() 
-  , configDir() 
-{
-  Configurations.clear();
+  FileInputProvider fip( confFile.get() );
+  if (!fip.okay()) {
+    throw std::string("Configuration file for '") + ftype + 
+                      "' is not available.";
+  }
+  result = new CompilerDriver::ConfigData();
+  ParseConfigData(fip,*result);
+  return result;
 }
 
 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
@@ -432,7 +497,7 @@ LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
     // The configuration data doesn't exist, we have to go read it.
     result = ReadConfigData(filetype);
     // If we got one, cache it
-    if ( result != 0 )
+    if (result != 0)
       Configurations.insert(std::make_pair(filetype,result));
   }
   return result; // Might return 0