view trunk/src/dil/Settings.d @ 505:3bb94ba21490

Refactored a great amount of code. Changed many declaration types from Token* to Identifier*. Fix in parseStructInitializer(): append null to idents in else body. Fixed class Parameter and parseParameterList().
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Wed, 12 Dec 2007 02:25:42 +0100
parents 325714d8aa6c
children 6160ab7b1816
line wrap: on
line source

/++
  Author: Aziz Köksal
  License: GPL3
+/
module dil.Settings;
import dil.Messages;
import dil.Parser, dil.SyntaxTree, dil.Declarations, dil.Expressions;
import dil.File;
import tango.io.FilePath;
import common;

struct GlobalSettings
{
static:
  string language; /// Language of loaded messages catalogue.
  string[] messages; /// Table of localized compiler messages.
  string[] importPaths; /// Array of import paths to look for modules.
  void load()
  {
    scope execPath = new FilePath(GetExecutableFilePath());
    auto fileName = execPath.file("config.d").toUtf8();
    auto sourceText = loadFile(fileName);
    auto parser = new Parser(sourceText, fileName);
    auto root = parser.start();

    if (parser.errors.length || parser.lx.errors.length)
    {
      throw new Exception("There are errors in " ~ fileName ~ ".");
    }

    foreach (decl; root.children)
    {
      auto v = Cast!(VariableDeclaration)(decl);
      if (v is null)
        continue;
      auto vname = v.idents[0].str;
      if (vname == "langfile")
      {
        auto e = v.values[0];
        if (!e)
          throw new Exception("langfile variable has no value set.");
        auto val = Cast!(StringExpression)(e);
        if (val)
          // Set fileName to d-file with messages table.
          fileName = val.getString();
      }
      else if (vname == "import_paths")
      {
        auto e = v.values[0];
        if (e is null)
          throw new Exception("import_paths variable has no variable set.");
        if (auto array = Cast!(ArrayInitializer)(e))
        {
          foreach (value; array.values)
            if (auto str = Cast!(StringExpression)(value))
              GlobalSettings.importPaths ~= str.getString();
        }
        else
          throw new Exception("import_paths variable is set to "~e.classinfo.name~" instead of an ArrayInitializer.");
      }
    }

    // Load messages
    sourceText = loadFile(execPath.file(fileName).toUtf8());
    parser = new Parser(sourceText, fileName);
    root = parser.start();

    if (parser.errors.length || parser.lx.errors.length)
    {
      throw new Exception("There are errors in "~fileName~".");
    }

    char[][] messages;
    foreach (decl; root.children)
    {
      auto v = Cast!(VariableDeclaration)(decl);
      if (v is null)
        continue;
      if (v.idents[0].str == "messages")
      {
        auto e = v.values[0];
        if (!e)
          throw new Exception("messages variable in "~fileName~" has no value set.");
        if (auto array = Cast!(ArrayInitializer)(e))
        {
          foreach (value; array.values)
          {
            if (auto str = Cast!(StringExpression)(value))
              messages ~= str.getString();
          }
        }
        else
          throw new Exception("messages variable is set to "~e.classinfo.name~" instead of an ArrayInitializer.");
      }
      else if(v.idents[0].str == "lang_code")
      {
        auto e = v.values[0];
        if (!e)
          throw new Exception("lang_code variable in "~fileName~" has no value set.");
        if (auto str = Cast!(StringExpression)(e))
            GlobalSettings.language = str.getString();
      }
    }
    if (messages.length != MID.max+1)
      throw new Exception(Format("messages table in {0} must exactly have {1} entries, but {2} were found.", fileName, MID.max+1, messages.length));
    GlobalSettings.messages = messages;
    dil.Messages.SetMessages(messages);
  }
}

version(Windows)
{
private extern(Windows) uint GetModuleFileNameA(void*, char*, uint);
/++
  Get the fully qualified path to this executable.
+/
char[] GetExecutableFilePath()
{
  alias GetModuleFileNameA GetModuleFileName;
  char[] buffer = new char[256];
  uint count;

  while (1)
  {
    if (buffer is null)
      return null;

    count = GetModuleFileName(null, buffer.ptr, buffer.length);
    if (count == 0)
      return null;
    if (buffer.length != count && buffer[count] == 0)
      break;
    // Increase size of buffer
    buffer.length = buffer.length * 2;
  }
  assert(buffer[count] == 0);
  // Reduce buffer to the actual length of the string (excluding '\0'.)
  if (count < buffer.length)
    buffer.length = count;
  return buffer;
}
}
else version(linux)
{
private extern(C) size_t readlink(char* path, char* buf, size_t bufsize);
/++
  Get the fully qualified path to this executable.
+/
char[] GetExecutableFilePath()
{
  char[] buffer = new char[256];
  size_t count;

  while (1)
  {
    // This won't work on very old Linux systems.
    count = readlink("/proc/self/exe".ptr, buffer.ptr, buffer.length);
    if (count == -1)
      return null;
    if (count < buffer.length)
      break;
    buffer.length = buffer.length * 2;
  }
  buffer.length = count;
  return buffer;
}
}
else
  static assert(0, "GetExecutableFilePath() is not implemented on your platform.");