mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@28543 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			627 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			627 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file was developed by Reid Spencer and is distributed under the
 | |
| // University of Illinois Open Source License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file implements the parsing of configuration files for the LLVM Compiler
 | |
| // Driver (llvmc).
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "Configuration.h"
 | |
| #include "ConfigLexer.h"
 | |
| #include "CompilerDriver.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 {
 | |
| 
 | |
|   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;
 | |
|     }
 | |
| 
 | |
|     inline bool next_is_real() {
 | |
|       next();
 | |
|       return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
 | |
|     }
 | |
| 
 | |
|     inline void eatLineRemnant() {
 | |
|       while (next_is_real()) ;
 | |
|     }
 | |
| 
 | |
|     void error(const std::string& msg, bool skip = true) {
 | |
|       provider->error(msg);
 | |
|       if (skip)
 | |
|         eatLineRemnant();
 | |
|     }
 | |
| 
 | |
|     bool parseCompleteItem(std::string& result) {
 | |
|       result.clear();
 | |
|       while (next_is_real()) {
 | |
|         switch (token ) {
 | |
|           case STRING :
 | |
|           case OPTION :
 | |
|             result += ConfigLexerState.StringVal;
 | |
|             break;
 | |
|           case SEPARATOR:
 | |
|             result += ".";
 | |
|             break;
 | |
|           case SPACE:
 | |
|             return true;
 | |
|           default:
 | |
|             return false;
 | |
|         }
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     std::string parseName() {
 | |
|       std::string result;
 | |
|       if (next() == EQUALS) {
 | |
|         if (parseCompleteItem(result))
 | |
|           eatLineRemnant();
 | |
|         if (result.empty())
 | |
|           error("Name exepected");
 | |
|       } else
 | |
|         error("Expecting '='");
 | |
|       return result;
 | |
|     }
 | |
| 
 | |
|     bool parseBoolean() {
 | |
|       bool result = true;
 | |
|       if (next() == EQUALS) {
 | |
|         if (next() == SPACE)
 | |
|           next();
 | |
|         if (token == 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;
 | |
|     }
 | |
| 
 | |
|     bool parseSubstitution(CompilerDriver::StringVector& optList) {
 | |
|       switch (token) {
 | |
|         case ARGS_SUBST:        optList.push_back("%args%"); break;
 | |
|         case BINDIR_SUBST:      optList.push_back("%bindir%"); break;
 | |
|         case DEFS_SUBST:        optList.push_back("%defs%"); break;
 | |
|         case IN_SUBST:          optList.push_back("%in%"); break;
 | |
|         case INCLS_SUBST:       optList.push_back("%incls%"); break;
 | |
|         case LIBDIR_SUBST:      optList.push_back("%libdir%"); 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;
 | |
|         case FOPTS_SUBST:       optList.push_back("%fOpts%"); break;
 | |
|         case MOPTS_SUBST:       optList.push_back("%Mopts%"); break;
 | |
|         case WOPTS_SUBST:       optList.push_back("%Wopts%"); break;
 | |
|         default:
 | |
|           return false;
 | |
|       }
 | |
|       return true;
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|           }
 | |
|         }
 | |
|       } else
 | |
|         error("Expecting '='");
 | |
|     }
 | |
| 
 | |
|     void parseVersion() {
 | |
|       if (next() != EQUALS)
 | |
|         error("Expecting '='");
 | |
|       while (next_is_real()) {
 | |
|         if (token == STRING || token == OPTION)
 | |
|           confDat->version = ConfigLexerState.StringVal;
 | |
|         else
 | |
|           error("Expecting a version string");
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void parseLibs() {
 | |
|       if (next() != EQUALS)
 | |
|         error("Expecting '='");
 | |
|       std::string lib;
 | |
|       while (parseCompleteItem(lib)) {
 | |
|         if (!lib.empty()) {
 | |
|           confDat->libpaths.push_back(lib);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void parseLang() {
 | |
|       if (next() != SEPARATOR)
 | |
|         error("Expecting '.'");
 | |
|       switch (next() ) {
 | |
|         case LIBS:
 | |
|           parseLibs();
 | |
|           break;
 | |
|         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;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     bool parseProgramName(std::string& str) {
 | |
|       str.clear();
 | |
|       do {
 | |
|         switch (token) {
 | |
|           case OPTION:
 | |
|           case STRING:
 | |
|           case ARGS_SUBST:
 | |
|           case DEFS_SUBST:
 | |
|           case IN_SUBST:
 | |
|           case INCLS_SUBST:
 | |
|           case LIBS_SUBST:
 | |
|           case OPT_SUBST:
 | |
|           case OUT_SUBST:
 | |
|           case STATS_SUBST:
 | |
|           case TARGET_SUBST:
 | |
|           case TIME_SUBST:
 | |
|           case VERBOSE_SUBST:
 | |
|           case FOPTS_SUBST:
 | |
|           case MOPTS_SUBST:
 | |
|           case WOPTS_SUBST:
 | |
|             str += ConfigLexerState.StringVal;
 | |
|             break;
 | |
|           case SEPARATOR:
 | |
|             str += ".";
 | |
|             break;
 | |
|           case ASSEMBLY:
 | |
|             str += "assembly";
 | |
|             break;
 | |
|           case BYTECODE:
 | |
|             str += "bytecode";
 | |
|             break;
 | |
|           case TRUETOK:
 | |
|             str += "true";
 | |
|             break;
 | |
|           case FALSETOK:
 | |
|             str += "false";
 | |
|             break;
 | |
|           default:
 | |
|             break;
 | |
|         }
 | |
|         next();
 | |
|       } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
 | |
|                token != ERRORTOK);
 | |
|       return !str.empty();
 | |
|     }
 | |
| 
 | |
|     void parseCommand(CompilerDriver::Action& action) {
 | |
|       if (next() != EQUALS)
 | |
|         error("Expecting '='");
 | |
|       switch (next()) {
 | |
|         case EOLTOK:
 | |
|           // no value (valid)
 | |
|           action.program.clear();
 | |
|           action.args.clear();
 | |
|           break;
 | |
|         case SPACE:
 | |
|           next();
 | |
|           /* FALL THROUGH */
 | |
|         default:
 | |
|         {
 | |
|           std::string progname;
 | |
|           if (parseProgramName(progname))
 | |
|             action.program.set(progname);
 | |
|           else
 | |
|             error("Expecting a program name");
 | |
| 
 | |
|           // Get the options
 | |
|           std::string anOption;
 | |
|           while (next_is_real()) {
 | |
|             switch (token) {
 | |
|               case STRING:
 | |
|               case OPTION:
 | |
|                 anOption += ConfigLexerState.StringVal;
 | |
|                 break;
 | |
|               case ASSEMBLY:
 | |
|                 anOption += "assembly";
 | |
|                 break;
 | |
|               case BYTECODE:
 | |
|                 anOption += "bytecode";
 | |
|                 break;
 | |
|               case TRUETOK:
 | |
|                 anOption += "true";
 | |
|                 break;
 | |
|               case FALSETOK:
 | |
|                 anOption += "false";
 | |
|                 break;
 | |
|               case SEPARATOR:
 | |
|                 anOption += ".";
 | |
|                 break;
 | |
|               case SPACE:
 | |
|                 action.args.push_back(anOption);
 | |
|                 anOption.clear();
 | |
|                 break;
 | |
|               default:
 | |
|                 if (!parseSubstitution(action.args))
 | |
|                   error("Expecting a program argument or substitution", false);
 | |
|                 break;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void parsePreprocessor() {
 | |
|       if (next() != SEPARATOR)
 | |
|         error("Expecting '.'");
 | |
|       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() == SPACE)
 | |
|           next();
 | |
|         if (token == ASSEMBLY) {
 | |
|           return true;
 | |
|         } else if (token == BYTECODE) {
 | |
|           return false;
 | |
|         } else {
 | |
|           error("Expecting output type value");
 | |
|           return false;
 | |
|         }
 | |
|         if (next() != EOLTOK && token != 0) {
 | |
|           error("Extraneous tokens after output value");
 | |
|         }
 | |
|       }
 | |
|       else
 | |
|         error("Expecting '='");
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     void parseTranslator() {
 | |
|       if (next() != SEPARATOR)
 | |
|         error("Expecting '.'");
 | |
|       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() {
 | |
|       if (next() != SEPARATOR)
 | |
|         error("Expecting '.'");
 | |
|       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() {
 | |
|       if (next() != SEPARATOR)
 | |
|         error("Expecting '.'");
 | |
|       switch(next()) {
 | |
|         case COMMAND:
 | |
|           parseCommand(confDat->Assembler);
 | |
|           break;
 | |
|         default:
 | |
|           error("Expecting 'command'");
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void parseLinker() {
 | |
|       if (next() != SEPARATOR)
 | |
|         error("Expecting '.'");
 | |
|       switch(next()) {
 | |
|         case LIBS:
 | |
|           break; //FIXME
 | |
|         case LIBPATHS:
 | |
|           break; //FIXME
 | |
|         default:
 | |
|           error("Expecting 'libs' or 'libpaths'");
 | |
|           break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void parseAssignment() {
 | |
|       switch (token) {
 | |
|         case VERSION_TOK:   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();
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| CompilerDriver::ConfigData*
 | |
| LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
 | |
|   CompilerDriver::ConfigData* result = 0;
 | |
|   sys::Path confFile;
 | |
|   if (configDir.isEmpty()) {
 | |
|     // Try the environment variable
 | |
|     const char* conf = getenv("LLVM_CONFIG_DIR");
 | |
|     if (conf) {
 | |
|       confFile.set(conf);
 | |
|       confFile.appendComponent(ftype);
 | |
|       if (!confFile.canRead())
 | |
|         throw std::string("Configuration file for '") + ftype +
 | |
|                           "' is not available.";
 | |
|     } else {
 | |
|       // Try the user's home directory
 | |
|       confFile = sys::Path::GetUserHomeDirectory();
 | |
|       if (!confFile.isEmpty()) {
 | |
|         confFile.appendComponent(".llvm");
 | |
|         confFile.appendComponent("etc");
 | |
|         confFile.appendComponent(ftype);
 | |
|         if (!confFile.canRead())
 | |
|           confFile.clear();
 | |
|       }
 | |
|       if (confFile.isEmpty()) {
 | |
|         // Okay, try the LLVM installation directory
 | |
|         confFile = sys::Path::GetLLVMConfigDir();
 | |
|         confFile.appendComponent(ftype);
 | |
|         if (!confFile.canRead()) {
 | |
|           // Okay, try the "standard" place
 | |
|           confFile = sys::Path::GetLLVMDefaultConfigDir();
 | |
|           confFile.appendComponent(ftype);
 | |
|           if (!confFile.canRead()) {
 | |
|             throw std::string("Configuration file for '") + ftype +
 | |
|                               "' is not available.";
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     confFile = configDir;
 | |
|     confFile.appendComponent(ftype);
 | |
|     if (!confFile.canRead())
 | |
|       throw std::string("Configuration file for '") + ftype +
 | |
|                         "' is not available.";
 | |
|   }
 | |
|   FileInputProvider fip( confFile.toString() );
 | |
|   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()
 | |
| {
 | |
|   ConfigDataMap::iterator cIt = Configurations.begin();
 | |
|   while (cIt != Configurations.end()) {
 | |
|     CompilerDriver::ConfigData* cd = cIt->second;
 | |
|     ++cIt;
 | |
|     delete cd;
 | |
|   }
 | |
|   Configurations.clear();
 | |
| }
 | |
| 
 | |
| CompilerDriver::ConfigData*
 | |
| LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
 | |
|   CompilerDriver::ConfigData* result = 0;
 | |
|   if (!Configurations.empty()) {
 | |
|     ConfigDataMap::iterator cIt = Configurations.find(filetype);
 | |
|     if ( cIt != Configurations.end() ) {
 | |
|       // We found one in the case, return it.
 | |
|       result = cIt->second;
 | |
|     }
 | |
|   }
 | |
|   if (result == 0) {
 | |
|     // The configuration data doesn't exist, we have to go read it.
 | |
|     result = ReadConfigData(filetype);
 | |
|     // If we got one, cache it
 | |
|     if (result != 0)
 | |
|       Configurations.insert(std::make_pair(filetype,result));
 | |
|   }
 | |
|   return result; // Might return 0
 | |
| }
 |