changeset 839:4063da6f3edd default tip

Refactored the config file and how it is loaded.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Thu, 21 Aug 2008 17:51:04 +0200
parents 1ecf05e680ba
children
files src/Settings.d src/SettingsLoader.d src/config.d src/main.d
diffstat 4 files changed, 151 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/Settings.d	Wed Aug 20 20:39:16 2008 +0200
+++ b/src/Settings.d	Thu Aug 21 17:51:04 2008 +0200
@@ -9,6 +9,8 @@
 struct GlobalSettings
 {
 static:
+  /// Path to the data directory.
+  string dataDir = "data/";
   /// Predefined version identifiers.
   string[] versionIds;
   /// Path to the language file.
--- a/src/SettingsLoader.d	Wed Aug 20 20:39:16 2008 +0200
+++ b/src/SettingsLoader.d	Thu Aug 21 17:51:04 2008 +0200
@@ -16,9 +16,11 @@
 import common;
 
 import tango.io.FilePath;
+import tango.sys.Environment;
+import tango.text.Util : substitute;
 
 /// Loads settings from a D module file.
-class SettingsLoader
+abstract class SettingsLoader
 {
   InfoManager infoMan; /// Collects error messages.
   Module mod; /// Current module.
@@ -28,11 +30,6 @@
     this.infoMan = infoMan;
   }
 
-  static SettingsLoader opCall(InfoManager infoMan)
-  {
-    return new SettingsLoader(infoMan);
-  }
-
   /// Creates an error report.
   /// Params:
   ///   token = where the error occurred.
@@ -71,12 +68,50 @@
   }
 
   void load()
+  {}
+}
+
+/// Loads the configuration file of dil.
+class ConfigLoader : SettingsLoader
+{
+  static string configFileName = "config.d"; /// Name of the configuration file.
+  string executablePath; /// Absolute path to the executable of dil.
+  string executableDir; /// Absolte path to the directory of the executable of dil.
+  string dataDir; /// Absolute path to dil's data directory.
+  string homePath; /// Path to the home directory.
+
+  this(InfoManager infoMan)
   {
-    scope execPath = new FilePath(GetExecutableFilePath());
-    execPath = new FilePath(execPath.folder());
+    super(infoMan);
+  }
+
+  static ConfigLoader opCall(InfoManager infoMan)
+  {
+    return new ConfigLoader(infoMan);
+  }
 
-    // Load config.d
-    auto filePath = resolvePath(execPath, "config.d");
+  string expandVariables(string val)
+  {
+     val = substitute(val, "${DATADIR}", dataDir);
+     val = substitute(val, "${HOME}", homePath);
+     val = substitute(val, "${EXECDIR}", executableDir);
+     return val;
+  }
+
+  void load()
+  {
+    homePath = Environment.get("HOME");
+    executablePath = GetExecutableFilePath();
+    executableDir = (new FilePath(executablePath)).folder();
+
+    // Load the configuration file.
+    auto filePath = findConfigurationFilePath();
+    if (filePath is null)
+    {
+      infoMan ~= new Error(new Location("",0),
+        "the configuration file "~configFileName~" could not be found.");
+      return;
+    }
     mod = new Module(filePath, infoMan);
     mod.parse();
 
@@ -87,33 +122,40 @@
     auto pass1 = new SemanticPass1(mod, context);
     pass1.run();
 
-    if (auto array = getValue!(ArrayInitExpression)("version_ids"))
+    // Initialize the dataDir member.
+    if (auto val = getValue!(StringExpression)("DATADIR"))
+      dataDir = val.getString();
+    dataDir = resolvePath(executableDir, dataDir);
+    GlobalSettings.dataDir = dataDir;
+
+    if (auto array = getValue!(ArrayInitExpression)("VERSION_IDS"))
       foreach (value; array.values)
-        if (auto str = castTo!(StringExpression)(value))
-          GlobalSettings.versionIds ~= str.getString();
-    if (auto val = getValue!(StringExpression)("langfile"))
-      GlobalSettings.langFile = val.getString();
-    if (auto array = getValue!(ArrayInitExpression)("import_paths"))
-      foreach (value; array.values)
-        if (auto str = castTo!(StringExpression)(value))
-          GlobalSettings.importPaths ~= str.getString();
-    if (auto array = getValue!(ArrayInitExpression)("ddoc_files"))
+        if (auto val = castTo!(StringExpression)(value))
+          GlobalSettings.versionIds ~= val.getString();
+    if (auto val = getValue!(StringExpression)("LANG_FILE"))
+      GlobalSettings.langFile = expandVariables(val.getString());
+    if (auto array = getValue!(ArrayInitExpression)("IMPORT_PATHS"))
       foreach (value; array.values)
-        if (auto str = castTo!(StringExpression)(value))
-          GlobalSettings.ddocFilePaths ~= resolvePath(execPath, str.getString());
-    if (auto val = getValue!(StringExpression)("xml_map"))
-      GlobalSettings.xmlMapFile = val.getString();
-    if (auto val = getValue!(StringExpression)("html_map"))
-      GlobalSettings.htmlMapFile = val.getString();
-    if (auto val = getValue!(StringExpression)("lexer_error"))
+        if (auto val = castTo!(StringExpression)(value))
+          GlobalSettings.importPaths ~= expandVariables(val.getString());
+    if (auto array = getValue!(ArrayInitExpression)("DDOC_FILES"))
+      foreach (value; array.values)
+        if (auto val = castTo!(StringExpression)(value))
+          GlobalSettings.ddocFilePaths ~= expandVariables(val.getString());
+    if (auto val = getValue!(StringExpression)("XML_MAP"))
+      GlobalSettings.xmlMapFile = expandVariables(val.getString());
+    if (auto val = getValue!(StringExpression)("HTML_MAP"))
+      GlobalSettings.htmlMapFile = expandVariables(val.getString());
+    if (auto val = getValue!(StringExpression)("LEXER_ERROR"))
       GlobalSettings.lexerErrorFormat = val.getString();
-    if (auto val = getValue!(StringExpression)("parser_error"))
+    if (auto val = getValue!(StringExpression)("PARSER_ERROR"))
       GlobalSettings.parserErrorFormat = val.getString();
-    if (auto val = getValue!(StringExpression)("semantic_error"))
+    if (auto val = getValue!(StringExpression)("SEMANTIC_ERROR"))
       GlobalSettings.semanticErrorFormat = val.getString();
 
     // Load language file.
-    filePath = resolvePath(execPath, GlobalSettings.langFile);
+    // TODO: create a separate class for this?
+    filePath = expandVariables(GlobalSettings.langFile);
     mod = new Module(filePath);
     mod.parse();
 
@@ -127,8 +169,8 @@
     {
       char[][] messages;
       foreach (value; array.values)
-        if (auto str = castTo!(StringExpression)(value))
-          messages ~= str.getString();
+        if (auto val = castTo!(StringExpression)(value))
+          messages ~= val.getString();
       if (messages.length != MID.max+1)
         error(mod.firstToken,
               "messages table in {} must exactly have {} entries, but not {}.",
@@ -139,6 +181,31 @@
     if (auto val = getValue!(StringExpression)("lang_code"))
       GlobalSettings.langCode = val.getString();
   }
+
+  /// Searches for the configuration file of dil.
+  /// Returns: the filePath or null if the file couldn't be found.
+  string findConfigurationFilePath()
+  {
+    // 1. Look in environment variable DILCONF.
+    auto filePath = new FilePath(Environment.get("DILCONF"));
+    if (filePath.exists())
+      return filePath.toString();
+    // 2. Look in the current working directory.
+    filePath.set(this.configFileName);
+    if (filePath.exists())
+      return filePath.toString();
+    // 3. Look in the directory set by HOME.
+    filePath.set(this.homePath);
+    filePath.append(this.configFileName);
+    if (filePath.exists())
+      return filePath.toString();
+    // 4. Look in the binary's directory.
+    filePath.set(this.executableDir);
+    filePath.append(this.configFileName);
+    if (filePath.exists())
+      return filePath.toString();
+    return null;
+  }
 }
 
 /// Loads an associative array from a D module file.
@@ -183,11 +250,13 @@
 /// Resolves the path to a file from the executable's dir path
 /// if it is relative.
 /// Returns: filePath if it is absolute or execPath + filePath.
-string resolvePath(FilePath execPath, string filePath)
+string resolvePath(string execPath, string filePath)
 {
-  if ((new FilePath(filePath)).isAbsolute())
+  scope path = new FilePath(filePath);
+  if (path.isAbsolute())
     return filePath;
-  return execPath.dup.append(filePath).toString();
+  path.set(execPath).append(filePath);
+  return path.toString();
 }
 
 version(DDoc)
--- a/src/config.d	Wed Aug 20 20:39:16 2008 +0200
+++ b/src/config.d	Thu Aug 21 17:51:04 2008 +0200
@@ -1,34 +1,57 @@
 /// The configuration file of dil.
 ///
-/// Relative paths are resolved from the directory of the executable.
+/// The file is searched for in the following order:
+/// $(OL
+///   $(LI The environment variable DILCONF.)
+///   $(LI The current working directory.)
+///   $(LI The directory set in the environment variable HOME.)
+///   $(LI The executable's directory.)
+/// )
+/// The program will fail with an error msg if the file couldn't be found.$(BR)
+///
+/// The following variables are expanded inside strings (only where paths are expected):
+/// $(UL
+///   $(LI ${DATADIR} -> the data directory of dil (e.g. /home/user/dil/bin/data or C:\dil\bin\data).)
+///   $(LI ${HOME} -> the home directory (e.g. /home/name or C:\Documents and Settings\name).)
+///   $(LI ${EXECDIR} -> the absolute path to the directory of dil's executable (e.g. /home/name/dil/bin).)
+/// )
 module config;
 
+/// Files needed by dil are located in this directory.
+///
+/// A relative path is resolved from the directory of dil's executable.
+var DATADIR = "data/";
+
 /// Predefined version identifiers.
-var version_ids = ["X86", "linux", "LittleEndian"];
+var VERSION_IDS = ["X86", "linux", "LittleEndian"];
 // "X86_64", "Windows", "Win32", "Win64", "BigEndian"
 
-/// Path to the language file.
-var langfile = "lang_en.d";
-
 /// An array of import paths to look for modules.
-var import_paths = []; /// E.g.: ["src/", "import/"]
+///
+/// Relative paths are resolved from the current working directory.
+var IMPORT_PATHS = []; /// E.g.: ["src/", "import/"]
 
 /// DDoc macro file paths.
 ///
-/// Macro definitions in ddoc_files[n] override the ones in ddoc_files[n-1].
-var ddoc_files = ["predefined.ddoc"]; /// E.g.: ["src/mymacros.ddoc", "othermacros.ddoc"]
+/// Macro definitions in ddoc_files[n] override the ones in ddoc_files[n-1].$(BR)
+/// Relative paths are resolved from the current working directory.
+var DDOC_FILES = ["${DATADIR}/predefined.ddoc"]; /// E.g.: ["src/mymacros.ddoc", "othermacros.ddoc"]
 
-var xml_map = "xml_map.d";
-var html_map = "html_map.d";
+/// Path to the language file.
+var LANG_FILE = "${DATADIR}/lang_en.d";
+/// Path to the xml map.
+var XML_MAP = "${DATADIR}/xml_map.d";
+/// Path to the html map.
+var HTML_MAP = "${DATADIR}/html_map.d";
 
 /// Customizable formats for error messages.
 ///
-/// <ul>
-///   <li>0: file path to the source text.</li>
-///   <li>1: line number.</li>
-///   <li>2: column number.</li>
-///   <li>3: error message.</li>
-/// </ul>
-var lexer_error = "{0}({1},{2})L: {3}";
-var parser_error = "{0}({1},{2})P: {3}"; /// ditto
-var semantic_error = "{0}({1},{2})S: {3}"; /// ditto
+/// $(UL
+///   $(LI 0: file path to the source text.)
+///   $(LI 1: line number.)
+///   $(LI 2: column number.)
+///   $(LI 3: error message.)
+/// )
+var LEXER_ERROR = "{0}({1},{2})L: {3}";
+var PARSER_ERROR = "{0}({1},{2})P: {3}"; /// ditto
+var SEMANTIC_ERROR = "{0}({1},{2})S: {3}"; /// ditto
--- a/src/main.d	Wed Aug 20 20:39:16 2008 +0200
+++ b/src/main.d	Thu Aug 21 17:51:04 2008 +0200
@@ -46,7 +46,7 @@
 void main(char[][] args)
 {
   auto infoMan = new InfoManager();
-  SettingsLoader.SettingsLoader(infoMan).load();
+  ConfigLoader(infoMan).load();
   if (infoMan.hasInfo)
     return printErrors(infoMan);
 
@@ -391,6 +391,8 @@
       errorFormat = GlobalSettings.semanticErrorFormat;
     else if (info.classinfo is Warning.classinfo)
       errorFormat = "{0}: Warning: {3}";
+    else if (info.classinfo is dil.Information.Error.classinfo)
+      errorFormat = "Error: {3}";
     else
       continue;
     auto err = cast(Problem)info;