Fix level names when language is set to auto-detect
[supertux.git] / src / lisp / parser.cpp
index 54af44f..2a09de8 100644 (file)
@@ -1,13 +1,10 @@
-//  $Id$
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
 //
-//  TuxKart - a fun racing game with go-kart
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.de>
-//  code in this file based on lispreader from Mark Probst
-//
-//  This program is free software; you can redistribute it and/or
-//  modify it under the terms of the GNU General Public License
-//  as published by the Free Software Foundation; either version 2
-//  of the License, or (at your option) any later version.
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
 //
 //  This program is distributed in the hope that it will be useful,
 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
 //  GNU General Public License for more details.
 //
 //  You should have received a copy of the GNU General Public License
-//  along with this program; if not, write to the Free Software
-//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
-#include <config.h>
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 #include <sstream>
 #include <stdexcept>
-#include <fstream>
-#include <cassert>
-#include <iostream>
-
-#include "tinygettext/tinygettext.hpp"
-#include "physfs/physfs_stream.hpp"
-#include "parser.hpp"
-#include "lisp.hpp"
-
-namespace lisp
-{
-
-Parser::Parser(bool translate)
-  : lexer(0), dictionary_manager(0), dictionary(0)
+#include <tinygettext/tinygettext.hpp>
+#include <physfs.h>
+
+#include "lisp/lisp.hpp"
+#include "lisp/parser.hpp"
+#include "util/gettext.hpp"
+#include "util/obstackpp.hpp"
+#include "physfs/ifile_stream.hpp"
+#include "physfs/ifile_streambuf.hpp"
+#include "supertux/globals.hpp"
+
+#include "supertux/gameconfig.hpp"
+
+namespace lisp {
+
+Parser::Parser(bool translate) :
+  lexer(0),
+  filename(),
+  dictionary_manager(0),
+  dictionary(0),
+  token(),
+  searchpath(),
+  obst()
 {
   if(translate) {
-    dictionary_manager = new TinyGetText::DictionaryManager();
+    dictionary_manager = new tinygettext::DictionaryManager();
     dictionary_manager->set_charset("UTF-8");
+    if (g_config) {
+      if (g_config->locale != "") {
+        dictionary_manager->set_language(tinygettext::Language::from_name(g_config->locale));
+      }
+      else if(g_dictionary_manager && g_dictionary_manager->get_language()) {
+        // Language set to auto-detect?
+        dictionary_manager->set_language(g_dictionary_manager->get_language());
+      }
+    }
   }
+
+  obstack_init(&obst);
+  searchpath = PHYSFS_getSearchPath();
 }
 
 Parser::~Parser()
 {
+  obstack_free(&obst, NULL);
   delete lexer;
   delete dictionary_manager;
+  PHYSFS_freeList(searchpath);
 }
 
-static std::string dirname(std::string filename)
+static std::string dirname(const std::string& filename)
 {
   std::string::size_type p = filename.find_last_of('/');
   if(p == std::string::npos)
@@ -57,61 +75,73 @@ static std::string dirname(std::string filename)
   return filename.substr(0, p+1);
 }
 
-Lisp*
-Parser::parse(const std::string& filename)
+const Lisp*
+Parser::parse(const std::string& filename_)
 {
-  IFileStream in(filename);
+  IFileStreambuf ins(filename_);
+  std::istream in(&ins);
+
   if(!in.good()) {
     std::stringstream msg;
-    msg << "Parser problem: Couldn't open file '" << filename << "'.";
+    msg << "Parser problem: Couldn't open file '" << filename_ << "'.";
     throw std::runtime_error(msg.str());
   }
 
   if(dictionary_manager) {
-    dictionary_manager->add_directory(dirname(filename));
+    std::string rel_dir = dirname (filename_);
+    for(char** i = searchpath; *i != NULL; i++)
+    {
+      std::string abs_dir = std::string (*i) + PHYSFS_getDirSeparator () + rel_dir;
+      dictionary_manager->add_directory (abs_dir);
+    }
     dictionary = & (dictionary_manager->get_dictionary());
   }
-  
-  return parse(in);
+
+  return parse(in, filename_);
 }
 
-Lisp*
-Parser::parse(std::istream& stream)
+const Lisp*
+Parser::parse(std::istream& stream, const std::string& sourcename)
 {
   delete lexer;
   lexer = new Lexer(stream);
 
+  this->filename = sourcename;
   token = lexer->getNextToken();
-  Lisp* result = new Lisp(Lisp::TYPE_CONS);
+
+  Lisp* result = new(obst) Lisp(Lisp::TYPE_CONS);
   result->v.cons.car = read();
   result->v.cons.cdr = 0;
-  
+
   delete lexer;
   lexer = 0;
 
-  return result;    
+  return result;
+}
+
+void
+Parser::parse_error(const char* msg) const
+{
+  std::stringstream emsg;
+  emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber()
+       << ": " << msg;
+  throw std::runtime_error(emsg.str());
 }
 
-Lisp*
+const Lisp*
 Parser::read()
 {
   Lisp* result;
   switch(token) {
     case Lexer::TOKEN_EOF: {
-      std::stringstream msg;
-      msg << "Parse Error at line " << lexer->getLineNumber() << ": "
-        << "Unexpected EOF.";
-      throw std::runtime_error(msg.str());
+      parse_error("Unexpected EOF.");
     }
     case Lexer::TOKEN_CLOSE_PAREN: {
-      std::stringstream msg;
-      msg << "Parse Error at line " << lexer->getLineNumber() << ": "
-        << "Unexpected ')'.";
-      throw std::runtime_error(msg.str());
+      parse_error("Unexpected ')'.");
     }
     case Lexer::TOKEN_OPEN_PAREN: {
-      result = new Lisp(Lisp::TYPE_CONS);
-      
+      result = new(obst) Lisp(Lisp::TYPE_CONS);
+
       token = lexer->getNextToken();
       if(token == Lexer::TOKEN_CLOSE_PAREN) {
         result->v.cons.car = 0;
@@ -120,25 +150,25 @@ Parser::read()
       }
 
       if(token == Lexer::TOKEN_SYMBOL &&
-          strcmp(lexer->getString(), "_") == 0) {
+         strcmp(lexer->getString(), "_") == 0) {
         // evaluate translation function (_ str) in place here
         token = lexer->getNextToken();
         if(token != Lexer::TOKEN_STRING)
-          throw std::runtime_error("Expected string after '(_'");
-        
-        result = new Lisp(Lisp::TYPE_STRING);
+          parse_error("Expected string after '(_'");
+
+        result = new(obst) Lisp(Lisp::TYPE_STRING);
         if(dictionary) {
           std::string translation = dictionary->translate(lexer->getString());
-          result->v.string = new char[translation.size()+1];
+          result->v.string = new(obst) char[translation.size()+1];
           memcpy(result->v.string, translation.c_str(), translation.size()+1);
         } else {
-          size_t len = strlen(lexer->getString()) + 1;                                
-          result->v.string = new char[len];
+          size_t len = strlen(lexer->getString()) + 1;
+          result->v.string = new(obst) char[len];
           memcpy(result->v.string, lexer->getString(), len);
         }
         token = lexer->getNextToken();
         if(token != Lexer::TOKEN_CLOSE_PAREN)
-          throw std::runtime_error("Expected ')' after '(_ string'");
+          parse_error("Expected ')' after '(_ string'");
         break;
       }
 
@@ -149,45 +179,47 @@ Parser::read()
           cur->v.cons.cdr = 0;
           break;
         }
-        cur->v.cons.cdr = new Lisp(Lisp::TYPE_CONS);
-        cur = cur->v.cons.cdr;
+        Lisp *newcur = new(obst) Lisp(Lisp::TYPE_CONS);
+        cur->v.cons.cdr = newcur;
+        cur = newcur;
       } while(1);
 
       break;
     }
     case Lexer::TOKEN_SYMBOL: {
-      result = new Lisp(Lisp::TYPE_SYMBOL);
+      result = new(obst) Lisp(Lisp::TYPE_SYMBOL);
       size_t len = strlen(lexer->getString()) + 1;
-      result->v.string = new char[len];
+      result->v.string = new(obst) char[len];
       memcpy(result->v.string, lexer->getString(), len);
       break;
     }
     case Lexer::TOKEN_STRING: {
-      result = new Lisp(Lisp::TYPE_STRING);
+      result = new(obst) Lisp(Lisp::TYPE_STRING);
       size_t len = strlen(lexer->getString()) + 1;
-      result->v.string = new char[len];
+      result->v.string = new(obst) char[len];
       memcpy(result->v.string, lexer->getString(), len);
       break;
     }
     case Lexer::TOKEN_INTEGER:
-      result = new Lisp(Lisp::TYPE_INTEGER);
-      sscanf(lexer->getString(), "%d", &result->v.integer);
+      result = new(obst) Lisp(Lisp::TYPE_INTEGER);
+      result->v.integer = atoi(lexer->getString());
       break;
     case Lexer::TOKEN_REAL:
-      result = new Lisp(Lisp::TYPE_REAL);
-      sscanf(lexer->getString(), "%f", &result->v.real);
+      result = new(obst) Lisp(Lisp::TYPE_REAL);
+      result->v.real = strtof(lexer->getString(), NULL);
       break;
     case Lexer::TOKEN_TRUE:
-      result = new Lisp(Lisp::TYPE_BOOLEAN);
+      result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
       result->v.boolean = true;
       break;
     case Lexer::TOKEN_FALSE:
-      result = new Lisp(Lisp::TYPE_BOOLEAN);
+      result = new(obst) Lisp(Lisp::TYPE_BOOLEAN);
       result->v.boolean = false;
       break;
 
     default:
       // this should never happen
+      result = NULL;
       assert(false);
   }
 
@@ -196,3 +228,5 @@ Parser::read()
 }
 
 } // end of namespace lisp
+
+/* EOF */