- Use obstacks for memory allocation for lispfiles and DrawingRequests,
authorMatthias Braun <matze@braunis.de>
Wed, 28 Feb 2007 18:16:37 +0000 (18:16 +0000)
committerMatthias Braun <matze@braunis.de>
Wed, 28 Feb 2007 18:16:37 +0000 (18:16 +0000)
  this should speedup the game a bit (esp. on windows where malloc is slow)
- fixed a bunch of memory leaks
- some experiments with the camera (disable and they didn't work out too well)

SVN-Revision: 4882

31 files changed:
src/Jamfile
src/audio/stream_sound_source.cpp
src/game_session.cpp
src/gameconfig.cpp
src/level.cpp
src/lisp/lexer.cpp
src/lisp/lexer.hpp
src/lisp/lisp.cpp
src/lisp/lisp.hpp
src/lisp/list_iterator.hpp
src/lisp/parser.cpp
src/lisp/parser.hpp
src/main.cpp
src/mainloop.cpp
src/object/camera.cpp
src/object/camera.hpp
src/object/player.cpp
src/object_factory.cpp
src/obstack/obstack.c [new file with mode: 0644]
src/obstack/obstack.h [new file with mode: 0644]
src/obstack/obstackpp.hpp [new file with mode: 0644]
src/resources.cpp
src/sprite/sprite_manager.cpp
src/textscroller.cpp
src/tile_manager.cpp
src/title.cpp
src/video/drawing_context.cpp
src/video/drawing_context.hpp
src/video/texture_manager.cpp
src/world.cpp
src/worldmap/worldmap.cpp

index ef13706..6371251 100644 (file)
@@ -20,6 +20,7 @@ sources =
     [ Wildcard trigger : *.cpp *.hpp ]
     [ Wildcard video : *.cpp *.hpp ]
     [ Wildcard worldmap : *.cpp *.hpp ]
+       [ Wildcard obstack : *.c *.h ]
 ;
 TRANSLATABLE_SOURCES += [ SearchSource $(sources) ] ;
 
index 958ef6f..5a01723 100644 (file)
@@ -132,12 +132,12 @@ StreamSoundSource::fillBufferAndQueue(ALuint buffer)
   if(bytesread > 0) {
     ALenum format = SoundManager::get_sample_format(file);
     alBufferData(buffer, format, bufferdata, bytesread, file->rate);
-    delete[] bufferdata;
     SoundManager::check_al_error("Couldn't refill audio buffer: ");
 
     alSourceQueueBuffers(source, 1, &buffer);
     SoundManager::check_al_error("Couldn't queue audio buffer: ");
   }
+  delete[] bufferdata;
 
   // return false if there aren't more buffers to fill
   return bytesread >= STREAMFRAGMENTSIZE;
index 2abb68c..014dc2d 100644 (file)
@@ -432,6 +432,11 @@ GameSession::setup()
   Menu::set_current(NULL);
   current_ = this;
 
+  if(currentsector != Sector::current()) {
+       currentsector->activate(currentsector->player->get_pos());
+  }
+  currentsector->play_music(LEVEL_MUSIC);
+
   // Eat unneeded events
   SDL_Event event;
   while(SDL_PollEvent(&event))
index 43f2ce0..8947005 100644 (file)
@@ -57,7 +57,7 @@ void
 Config::load()
 {
   lisp::Parser parser;
-  std::auto_ptr<lisp::Lisp> root (parser.parse("config"));
+  const lisp::Lisp* root = parser.parse("config");
 
   const lisp::Lisp* config_lisp = root->get_lisp("supertux-config");
   if(!config_lisp)
index c0f5b25..1c740e7 100644 (file)
@@ -58,7 +58,7 @@ Level::load(const std::string& filepath)
 {
   try {
     lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(filepath));
+    const lisp::Lisp* root = parser.parse(filepath);
 
     const lisp::Lisp* level = root->get_lisp("supertux-level");
     if(!level)
index 7352c82..4e4f2fb 100644 (file)
@@ -16,7 +16,6 @@
 //  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>
 
 #include <sstream>
index f541abd..1cd062b 100644 (file)
@@ -16,7 +16,6 @@
 //  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.
-
 #ifndef __LISPLEXER_H__
 #define __LISPLEXER_H__
 
index 39313d2..f5d8864 100644 (file)
@@ -31,22 +31,17 @@ Lisp::Lisp(LispType newtype)
 
 Lisp::~Lisp()
 {
-  if(type == TYPE_SYMBOL || type == TYPE_STRING)
-    delete[] v.string;
-  if(type == TYPE_CONS) {
-    delete v.cons.cdr;
-    delete v.cons.car;
-  }
+  // resources should be on parser obstack, so no need to delete anything
 }
 
-Lisp*
+const Lisp*
 Lisp::get_lisp(const char* name) const
 {
   for(const Lisp* p = this; p != 0; p = p->get_cdr()) {
-    Lisp* child = p->get_car();
+    const Lisp* child = p->get_car();
     if(!child || child->get_type() != TYPE_CONS)
       continue;
-    Lisp* childname = child->get_car();
+    const Lisp* childname = child->get_car();
     if(!childname)
       continue;
     std::string childName;
index 2f14641..38d6605 100644 (file)
@@ -44,9 +44,9 @@ public:
   LispType get_type() const
   { return type; }
 
-  Lisp* get_car() const
+  const Lisp* get_car() const
   { return v.cons.car; }
-  Lisp* get_cdr() const
+  const Lisp* get_cdr() const
   { return v.cons.cdr; }
 
   bool get(std::string& val) const
@@ -162,8 +162,8 @@ public:
     return true;
   }
 
-  Lisp* get_lisp(const char* name) const;
-  Lisp* get_lisp(const std::string& name) const
+  const Lisp* get_lisp(const char* name) const;
+  const Lisp* get_lisp(const std::string& name) const
   { return get_lisp(name.c_str()); }
 
   // for debugging
@@ -178,8 +178,8 @@ private:
   {
     struct
     {
-      Lisp* car;
-      Lisp* cdr;
+      const Lisp* car;
+      const Lisp* cdr;
     } cons;
 
     char* string;
index 092b672..0cb5b54 100644 (file)
@@ -36,15 +36,15 @@ public:
 
   const std::string& item() const
   { return current_item; }
-  lisp::Lisp* lisp() const
+  const lisp::Lisp* lisp() const
   { return current_lisp; }
-  lisp::Lisp* value() const
+  const lisp::Lisp* value() const
   { return current_lisp->get_car(); }
   bool next();
 
 private:
   std::string current_item;
-  lisp::Lisp* current_lisp;
+  const lisp::Lisp* current_lisp;
   const lisp::Lisp* cur;
 };
 
index 526d57a..52e87b2 100644 (file)
@@ -16,7 +16,6 @@
 //  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>
 
 #include <sstream>
@@ -29,6 +28,7 @@
 #include "physfs/physfs_stream.hpp"
 #include "parser.hpp"
 #include "lisp.hpp"
+#include "obstack/obstackpp.hpp"
 
 namespace lisp
 {
@@ -40,15 +40,18 @@ Parser::Parser(bool translate)
     dictionary_manager = new TinyGetText::DictionaryManager();
     dictionary_manager->set_charset("UTF-8");
   }
+
+  obstack_init(&obst);
 }
 
 Parser::~Parser()
 {
+  obstack_free(&obst, NULL);
   delete lexer;
   delete dictionary_manager;
 }
 
-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,13 +60,12 @@ static std::string dirname(std::string filename)
   return filename.substr(0, p+1);
 }
 
-Lisp*
+const Lisp*
 Parser::parse(const std::string& filename)
 {
   IFileStreambuf ins(filename);
   std::istream in(&ins);
 
-  this->filename = filename;
   if(!in.good()) {
     std::stringstream msg;
     msg << "Parser problem: Couldn't open file '" << filename << "'.";
@@ -75,17 +77,19 @@ Parser::parse(const std::string& filename)
     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;
 
@@ -96,7 +100,7 @@ Parser::parse(std::istream& stream)
 }
 
 void
-Parser::parse_error(const char* msg)
+Parser::parse_error(const char* msg) const
 {
   std::stringstream emsg;
   emsg << "Parse Error at '" << filename << "' line " << lexer->getLineNumber()
@@ -104,7 +108,7 @@ Parser::parse_error(const char* msg)
   throw std::runtime_error(emsg.str());
 }
 
-Lisp*
+const Lisp*
 Parser::read()
 {
   Lisp* result;
@@ -116,7 +120,7 @@ Parser::read()
       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) {
@@ -132,14 +136,14 @@ Parser::read()
         if(token != Lexer::TOKEN_STRING)
                  parse_error("Expected string after '(_'");
 
-        result = new Lisp(Lisp::TYPE_STRING);
+        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];
+          result->v.string = new(obst) char[len];
           memcpy(result->v.string, lexer->getString(), len);
         }
         token = lexer->getNextToken();
@@ -155,40 +159,41 @@ 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);
+      result = new(obst) Lisp(Lisp::TYPE_INTEGER);
       sscanf(lexer->getString(), "%d", &result->v.integer);
       break;
     case Lexer::TOKEN_REAL:
-      result = new Lisp(Lisp::TYPE_REAL);
+      result = new(obst) Lisp(Lisp::TYPE_REAL);
       sscanf(lexer->getString(), "%f", &result->v.real);
       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;
 
index 5f0ad0f..d4a986e 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <string>
 #include "lexer.hpp"
+#include "obstack/obstack.h"
 
 namespace TinyGetText {
 class Dictionary;
@@ -32,6 +33,7 @@ namespace lisp
 {
 
 class Lisp;
+class LispFile;
 
 class Parser
 {
@@ -39,18 +41,29 @@ public:
   Parser(bool translate = true);
   ~Parser();
 
-  Lisp* parse(const std::string& filename);
-  Lisp* parse(std::istream& stream);
+  /**
+   * Parses a lispfile and returns the s-expression structure.
+   * Note that all memory is held by the parser so don't destroy the parser
+   * before you are finished with the lisp tree
+   */
+  const Lisp* parse(const std::string& filename);
+  /**
+   * Same as parse but reads from a generic std::istream. The sourcename is
+   * used for errormessages to indicate the source of the data.
+   */
+  const Lisp* parse(std::istream& stream, const std::string& sourcename);
 
 private:
-  void parse_error(const char* msg);
-  Lisp* read();
+  void parse_error(const char* msg) const;
+  const Lisp* read();
 
   Lexer* lexer;
   std::string filename;
   TinyGetText::DictionaryManager* dictionary_manager;
   TinyGetText::Dictionary* dictionary;
   Lexer::TokenType token;
+
+  struct obstack obst;
 };
 
 } // end of namespace lisp
index 7308098..d1d5860 100644 (file)
@@ -204,8 +204,10 @@ static void init_physfs(const char* argv0)
   PHYSFS_permitSymbolicLinks(1);
 
   //show search Path
-  for(char** i = PHYSFS_getSearchPath(); *i != NULL; i++)
+  char** searchpath = PHYSFS_getSearchPath();
+  for(char** i = searchpath; *i != NULL; i++)
     log_info << "[" << *i << "] is in the search path" << std::endl;
+  PHYSFS_freeList(searchpath);
 }
 
 static void print_usage(const char* argv0)
@@ -503,7 +505,9 @@ int main(int argc, char** argv)
 {
   int result = 0;
 
+#ifndef NO_CATCH
   try {
+#endif
 
     if(pre_parse_commandline(argc, argv))
       return 0;
@@ -567,6 +571,7 @@ int main(int argc, char** argv)
 
     //init_rand(); PAK: this call might subsume the above 3, but I'm chicken!
     main_loop->run();
+#ifndef NO_CATCH
   } catch(std::exception& e) {
     log_fatal << "Unexpected exception: " << e.what() << std::endl;
     result = 1;
@@ -574,6 +579,7 @@ int main(int argc, char** argv)
     log_fatal << "Unexpected exception" << std::endl;
     result = 1;
   }
+#endif
 
   delete main_loop;
   main_loop = NULL;
index 5f9230f..07d8536 100644 (file)
@@ -49,7 +49,7 @@ static const int MAX_FRAME_SKIP = 2;
 MainLoop* main_loop = NULL;
 
 MainLoop::MainLoop()
-  : speed(1.0), nextpop(false), nextpush(false)
+  : speed(1.0), nextpop(false), nextpush(false), fps(0)
 {
   using namespace Scripting;
   TimeScheduler::instance = new TimeScheduler();
index b6f2a01..e4fd50a 100644 (file)
@@ -16,7 +16,6 @@
 //  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>
 
 #include <stdexcept>
@@ -40,8 +39,8 @@
 #include "path_walker.hpp"
 
 namespace {
-  enum CameraStyle { CameraStyleYI, CameraStyleKD };
-  const CameraStyle cameraStyle = CameraStyleKD;
+  enum CameraStyle { CameraStyleYI, CameraStyleKD, CameraStyleEXP };
+  const CameraStyle cameraStyle = CameraStyleYI;
 }
 
 Camera::Camera(Sector* newsector, std::string name)
@@ -261,9 +260,53 @@ Camera::update_scroll_normal_kd(float elapsed_time)
   shake();
 }
 
+template<typename T>
+T clamp(T min, T max, T val)
+{
+  if(val < min)
+    return min;
+  if(val > max)
+    return max;
+
+  return val;
+}
+
+void
+Camera::update_scroll_normal_exp(float elapsed_time)
+{
+  static const Vector camera_speed = Vector(300, 100);
+
+  Player* player = sector->player;
+  const Vector& player_pos = player->get_bbox().get_middle();
+  static Vector last_player_pos = player_pos;
+  static Vector camera_delta = Vector(0, 0);
+
+  (void) elapsed_time;
+
+  Vector player_delta_x = player_pos - last_player_pos;
+  last_player_pos = player_pos;
+
+  Vector camera_delta_antic = Vector(0, 0) + player_delta_x * 25;
+  Vector myspeed = (camera_delta_antic - camera_delta) / elapsed_time;
+  myspeed.x = clamp(-camera_speed.x, camera_speed.x, myspeed.x);
+  myspeed.y = clamp(-camera_speed.y, camera_speed.y, myspeed.y);
+
+  camera_delta += myspeed * elapsed_time;
+
+  translation.x = camera_delta.x + player_pos.x - 0.5f * SCREEN_WIDTH;
+  translation.y = camera_delta.y + player_pos.y - 0.5f * SCREEN_HEIGHT;
+
+  keep_in_bounds(translation);
+  shake();
+}
+
 void
 Camera::update_scroll_normal(float elapsed_time)
 {
+  if (cameraStyle == CameraStyleEXP) {
+    update_scroll_normal_exp(elapsed_time);
+    return;
+  }
   if (cameraStyle == CameraStyleKD) {
     update_scroll_normal_kd(elapsed_time);
     return;
index e02c306..260a612 100644 (file)
@@ -90,6 +90,7 @@ public:
 private:
   void update_scroll_normal(float elapsed_time);
   void update_scroll_normal_kd(float elapsed_time);
+  void update_scroll_normal_exp(float elapsed_time);
   void update_scroll_autoscroll(float elapsed_time);
   void update_scroll_to(float elapsed_time);
   void keep_in_bounds(Vector& vector);
index 5fa91de..d070c29 100644 (file)
@@ -56,20 +56,33 @@ static const float SHOOTING_TIME = .150f;
 /// time before idle animation starts
 static const float IDLE_TIME = 2.5f;
 
+/** acceleration in horizontal direction when walking
+ * (all acceleratiosn are in  pixel/s^2) */
 static const float WALK_ACCELERATION_X = 300;
+/** acceleration in horizontal direction when running */ 
 static const float RUN_ACCELERATION_X = 400;
+/** acceleration when skidding */
 static const float SKID_XM = 200;
+/** time of skidding in seconds */
 static const float SKID_TIME = .3f;
+/** maximum walk velocity (pixel/s) */
 static const float MAX_WALK_XM = 230;
+/** maximum run velcoity (pixel/s) */
 static const float MAX_RUN_XM = 320;
+/** maximum horizontal climb velocity */
 static const float MAX_CLIMB_XM = 48;
+/** maximum vertical climb velocity */
 static const float MAX_CLIMB_YM = 128;
+/** instant velocity when tux starts to walk */
 static const float WALK_SPEED = 100;
 
+/** time of the kick (kicking mriceblock) animation */
 static const float KICK_TIME = .3f;
+/** time of tux cheering (currently unused) */
 static const float CHEER_TIME = 1.0f;
 
-static const float UNDUCK_HURT_TIME = 0.25f; /**< if Tux cannot unduck for this long, he will get hurt */
+/** if Tux cannot unduck for this long, he will get hurt */
+static const float UNDUCK_HURT_TIME = 0.25f;
 
 // growing animation
 Surface* growingtux_left[GROWING_FRAMES];
index 0b69169..4e40fd6 100644 (file)
@@ -48,6 +48,8 @@ GameObject* create_object(const std::string& name, const Vector& pos)
            << " (y " << pos.y << "))";
 
   lisp::Parser parser;
-  std::auto_ptr<lisp::Lisp> lisp (parser.parse(lisptext));
-  return create_object(name, *lisp);
+  const lisp::Lisp* lisp = parser.parse(lisptext, "create_object");
+  GameObject* object = create_object(name, *lisp);
+
+  return object;
 }
diff --git a/src/obstack/obstack.c b/src/obstack/obstack.c
new file mode 100644 (file)
index 0000000..75440d9
--- /dev/null
@@ -0,0 +1,441 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _LIBC
+# include <obstack.h>
+# include <shlib-compat.h>
+#else
+# include "obstack.h"
+#endif
+
+/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
+   incremented whenever callers compiled using an old obstack.h can no
+   longer properly call the functions in this obstack.c.  */
+#define OBSTACK_INTERFACE_VERSION 1
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself, and the installed library
+   supports the same library interface we do.  This code is part of the GNU
+   C Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object
+   files, it is simpler to just do this in the source for each such file.  */
+
+#include <stdio.h>             /* Random thing to get __GNU_LIBRARY__.  */
+#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
+# include <gnu-versions.h>
+# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#include <stddef.h>
+
+#ifndef ELIDE_CODE
+
+
+# if HAVE_INTTYPES_H
+#  include <inttypes.h>
+# endif
+# if HAVE_STDINT_H || defined _LIBC
+#  include <stdint.h>
+# endif
+
+/* Determine default alignment.  */
+union fooround
+{
+  uintmax_t i;
+  long double d;
+  void *p;
+};
+struct fooalign
+{
+  char c;
+  union fooround u;
+};
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+   But in fact it might be less smart and round addresses to as much as
+   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
+enum
+  {
+    DEFAULT_ALIGNMENT = offsetof (struct fooalign, u),
+    DEFAULT_ROUNDING = sizeof (union fooround)
+  };
+
+/* When we copy a long block of data, this is the unit to do it with.
+   On some machines, copying successive ints does not work;
+   in such a case, redefine COPYING_UNIT to `long' (if that works)
+   or `char' as a last resort.  */
+# ifndef COPYING_UNIT
+#  define COPYING_UNIT int
+# endif
+
+
+/* The functions allocating more room by calling `obstack_chunk_alloc'
+   jump to the handler pointed to by `obstack_alloc_failed_handler'.
+   This can be set to a user defined function which should either
+   abort gracefully or use longjump - but shouldn't return.  This
+   variable by default points to the internal function
+   `print_and_abort'.  */
+static void print_and_abort (void);
+void (*obstack_alloc_failed_handler) (void) = print_and_abort;
+
+/* Exit value used when `print_and_abort' is used.  */
+# include <stdlib.h>
+# ifdef _LIBC
+int obstack_exit_failure = EXIT_FAILURE;
+# else
+#  include "exitfail.h"
+#  define obstack_exit_failure exit_failure
+# endif
+
+# ifdef _LIBC
+#  if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+/* A looong time ago (before 1994, anyway; we're not sure) this global variable
+   was used by non-GNU-C macros to avoid multiple evaluation.  The GNU C
+   library still exports it because somebody might use it.  */
+struct obstack *_obstack_compat;
+compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0);
+#  endif
+# endif
+
+/* Define a macro that either calls functions with the traditional malloc/free
+   calling interface, or calls functions with the mmalloc/mfree interface
+   (that adds an extra first argument), based on the state of use_extra_arg.
+   For free, do not use ?:, since some compilers, like the MIPS compilers,
+   do not allow (expr) ? void : void.  */
+
+# define CALL_CHUNKFUN(h, size) \
+  (((h) -> use_extra_arg) \
+   ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+   : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size)))
+
+# define CALL_FREEFUN(h, old_chunk) \
+  do { \
+    if ((h) -> use_extra_arg) \
+      (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+    else \
+      (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \
+  } while (0)
+
+\f
+/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
+   Objects start on multiples of ALIGNMENT (0 means use default).
+   CHUNKFUN is the function to use to allocate chunks,
+   and FREEFUN the function to free them.
+
+   Return nonzero if successful, calls obstack_alloc_failed_handler if
+   allocation fails.  */
+
+int
+_obstack_begin (struct obstack *h,
+               int size, int alignment,
+               void *(*chunkfun) (long),
+               void (*freefun) (void *))
+{
+  register struct _obstack_chunk *chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+        Use the values for range checking, because if range checking is off,
+        the extra bytes won't be missed terribly, but if range checking is on
+        and we used a larger request, a whole extra 4096 bytes would be
+        allocated.
+
+        These number are irrelevant to the new GNU malloc.  I suspect it is
+        less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+                   + 4 + DEFAULT_ROUNDING - 1)
+                  & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun;
+  h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+  h->use_extra_arg = 0;
+
+  chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+  if (!chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+                                              alignment - 1);
+  h->chunk_limit = chunk->limit
+    = (char *) chunk + h->chunk_size;
+  chunk->prev = 0;
+  /* The initial chunk now contains no empty object.  */
+  h->maybe_empty_object = 0;
+  h->alloc_failed = 0;
+  return 1;
+}
+
+int
+_obstack_begin_1 (struct obstack *h, int size, int alignment,
+                 void *(*chunkfun) (void *, long),
+                 void (*freefun) (void *, void *),
+                 void *arg)
+{
+  register struct _obstack_chunk *chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+        Use the values for range checking, because if range checking is off,
+        the extra bytes won't be missed terribly, but if range checking is on
+        and we used a larger request, a whole extra 4096 bytes would be
+        allocated.
+
+        These number are irrelevant to the new GNU malloc.  I suspect it is
+        less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+                   + 4 + DEFAULT_ROUNDING - 1)
+                  & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+  h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+  h->extra_arg = arg;
+  h->use_extra_arg = 1;
+
+  chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+  if (!chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+                                              alignment - 1);
+  h->chunk_limit = chunk->limit
+    = (char *) chunk + h->chunk_size;
+  chunk->prev = 0;
+  /* The initial chunk now contains no empty object.  */
+  h->maybe_empty_object = 0;
+  h->alloc_failed = 0;
+  return 1;
+}
+
+/* Allocate a new current chunk for the obstack *H
+   on the assumption that LENGTH bytes need to be added
+   to the current object, or a new object of length LENGTH allocated.
+   Copies any partial object from the end of the old chunk
+   to the beginning of the new one.  */
+
+void
+_obstack_newchunk (struct obstack *h, int length)
+{
+  register struct _obstack_chunk *old_chunk = h->chunk;
+  register struct _obstack_chunk *new_chunk;
+  register long        new_size;
+  register long obj_size = h->next_free - h->object_base;
+  register long i;
+  long already;
+  char *object_base;
+
+  /* Compute size for new chunk.  */
+  new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100;
+  if (new_size < h->chunk_size)
+    new_size = h->chunk_size;
+
+  /* Allocate and initialize the new chunk.  */
+  new_chunk = CALL_CHUNKFUN (h, new_size);
+  if (!new_chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->chunk = new_chunk;
+  new_chunk->prev = old_chunk;
+  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+  /* Compute an aligned object_base in the new chunk */
+  object_base =
+    __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
+
+  /* Move the existing object to the new chunk.
+     Word at a time is fast and is safe if the object
+     is sufficiently aligned.  */
+  if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+    {
+      for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+          i >= 0; i--)
+       ((COPYING_UNIT *)object_base)[i]
+         = ((COPYING_UNIT *)h->object_base)[i];
+      /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+        but that can cross a page boundary on a machine
+        which does not do strict alignment for COPYING_UNITS.  */
+      already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+    }
+  else
+    already = 0;
+  /* Copy remaining bytes one by one.  */
+  for (i = already; i < obj_size; i++)
+    object_base[i] = h->object_base[i];
+
+  /* If the object just copied was the only data in OLD_CHUNK,
+     free that chunk and remove it from the chain.
+     But not if that chunk might contain an empty object.  */
+  if (! h->maybe_empty_object
+      && (h->object_base
+         == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
+                         h->alignment_mask)))
+    {
+      new_chunk->prev = old_chunk->prev;
+      CALL_FREEFUN (h, old_chunk);
+    }
+
+  h->object_base = object_base;
+  h->next_free = h->object_base + obj_size;
+  /* The new chunk certainly contains no empty object yet.  */
+  h->maybe_empty_object = 0;
+}
+# ifdef _LIBC
+libc_hidden_def (_obstack_newchunk)
+# endif
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+   This is here for debugging.
+   If you use it in a program, you are probably losing.  */
+
+/* Suppress -Wmissing-prototypes warning.  We don't want to declare this in
+   obstack.h because it is just for debugging.  */
+int _obstack_allocated_p (struct obstack *h, void *obj);
+
+int
+_obstack_allocated_p (struct obstack *h, void *obj)
+{
+  register struct _obstack_chunk *lp;  /* below addr of any objects in this chunk */
+  register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+  lp = (h)->chunk;
+  /* We use >= rather than > since the object cannot be exactly at
+     the beginning of the chunk but might be an empty object exactly
+     at the end of an adjacent chunk.  */
+  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+    {
+      plp = lp->prev;
+      lp = plp;
+    }
+  return lp != 0;
+}
+\f
+/* Free objects in obstack H, including OBJ and everything allocate
+   more recently than OBJ.  If OBJ is zero, free everything in H.  */
+
+# undef obstack_free
+
+void
+obstack_free (struct obstack *h, void *obj)
+{
+  register struct _obstack_chunk *lp;  /* below addr of any objects in this chunk */
+  register struct _obstack_chunk *plp; /* point to previous chunk if any */
+
+  lp = h->chunk;
+  /* We use >= because there cannot be an object at the beginning of a chunk.
+     But there can be an empty object at that address
+     at the end of another chunk.  */
+  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+    {
+      plp = lp->prev;
+      CALL_FREEFUN (h, lp);
+      lp = plp;
+      /* If we switch chunks, we can't tell whether the new current
+        chunk contains an empty object, so assume that it may.  */
+      h->maybe_empty_object = 1;
+    }
+  if (lp)
+    {
+      h->object_base = h->next_free = (char *) (obj);
+      h->chunk_limit = lp->limit;
+      h->chunk = lp;
+    }
+  else if (obj != 0)
+    /* obj is not in any of the chunks! */
+    abort ();
+}
+
+# ifdef _LIBC
+/* Older versions of libc used a function _obstack_free intended to be
+   called by non-GCC compilers.  */
+strong_alias (obstack_free, _obstack_free)
+# endif
+\f
+int
+_obstack_memory_used (struct obstack *h)
+{
+  register struct _obstack_chunk* lp;
+  register int nbytes = 0;
+
+  for (lp = h->chunk; lp != 0; lp = lp->prev)
+    {
+      nbytes += lp->limit - (char *) lp;
+    }
+  return nbytes;
+}
+\f
+/* Define the error handler.  */
+# ifdef _LIBC
+#  include <libintl.h>
+# else
+#  include "gettext.h"
+# endif
+# ifndef _
+#  define _(msgid) gettext (msgid)
+# endif
+
+# ifdef _LIBC
+#  include <libio/iolibio.h>
+# endif
+
+# ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later.  */
+#  if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#   define __attribute__(Spec) /* empty */
+#  endif
+# endif
+
+static void
+__attribute__ ((noreturn))
+print_and_abort (void)
+{
+  /* Don't change any of these strings.  Yes, it would be possible to add
+     the newline to the string and use fputs or so.  But this must not
+     happen because the "memory exhausted" message appears in other places
+     like this and the translation should be reused instead of creating
+     a very similar string which requires a separate translation.  */
+# ifdef _LIBC
+  (void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
+# else
+  fprintf (stderr, "%s\n", _("memory exhausted"));
+# endif
+  exit (obstack_exit_failure);
+}
+
+#endif /* !ELIDE_CODE */
diff --git a/src/obstack/obstack.h b/src/obstack/obstack.h
new file mode 100644 (file)
index 0000000..206fe55
--- /dev/null
@@ -0,0 +1,509 @@
+/* obstack.h - object stack macros
+   Copyright (C) 1988-1994,1996-1999,2003,2004,2005
+       Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects.  Each object starts life
+small, and may grow to maturity.  (Consider building a word syllable
+by syllable.)  An object can move while it is growing.  Once it has
+been "finished" it never changes address again.  So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'.  On occasion, they free chunks,
+by calling `obstack_chunk_free'.  You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables.  Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols.  At the time you are reading a symbol you don't know
+how long it is.  One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer.  This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently.  Use one obstack for all symbol
+names.  As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it.  Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses.  When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk.  When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies.  No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk.  We then carry on
+accreting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object.  This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+       We allocate large chunks.
+       We carve out one object at a time from the current chunk.
+       Once carved, an object never moves.
+       We are free to append data of any size to the currently
+         growing object.
+       Exactly one object is growing in an obstack at any one time.
+       You can run one obstack per control block.
+       You may have as many control blocks as you dare.
+       Because of the way we do it, you can `unwind' an obstack
+         back to a previous state. (You may remove objects much
+         as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once.  */
+
+#ifndef _OBSTACK_H
+#define _OBSTACK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+\f
+/* We need the type of a pointer subtraction.  If __PTRDIFF_TYPE__ is
+   defined, as with GNU C, use that; that way we don't pollute the
+   namespace with <stddef.h>'s symbols.  Otherwise, include <stddef.h>
+   and use ptrdiff_t.  */
+
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+#endif
+
+/* If B is the base of an object addressed by P, return the result of
+   aligning P to the next multiple of A + 1.  B and P must be of type
+   char *.  A + 1 must be a power of 2.  */
+
+#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
+
+/* Similiar to _BPTR_ALIGN (B, P, A), except optimize the common case
+   where pointers can be converted to integers, aligned as integers,
+   and converted back again.  If PTR_INT_TYPE is narrower than a
+   pointer (e.g., the AS/400), play it safe and compute the alignment
+   relative to B.  Otherwise, use the faster strategy of computing the
+   alignment relative to 0.  */
+
+#define __PTR_ALIGN(B, P, A)                                               \
+  __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
+               P, A)
+
+#include <string.h>
+
+struct _obstack_chunk          /* Lives at front of each chunk. */
+{
+  char  *limit;                        /* 1 past end of this chunk */
+  struct _obstack_chunk *prev; /* address of prior chunk or NULL */
+  char contents[4];            /* objects begin here */
+};
+
+struct obstack         /* control current object in current chunk */
+{
+  long chunk_size;             /* preferred size to allocate chunks in */
+  struct _obstack_chunk *chunk;        /* address of current struct obstack_chunk */
+  char *object_base;           /* address of object we are building */
+  char *next_free;             /* where to add next char to current object */
+  char *chunk_limit;           /* address of char after current chunk */
+  union
+  {
+    PTR_INT_TYPE tempint;
+    void *tempptr;
+  } temp;                      /* Temporary for some macros.  */
+  int   alignment_mask;                /* Mask of alignment for each object. */
+  /* These prototypes vary based on `use_extra_arg', and we use
+     casts to the prototypeless function type in all assignments,
+     but having prototypes here quiets -Wstrict-prototypes.  */
+  struct _obstack_chunk *(*chunkfun) (void *, long);
+  void (*freefun) (void *, struct _obstack_chunk *);
+  void *extra_arg;             /* first arg for chunk alloc/dealloc funcs */
+  unsigned use_extra_arg:1;    /* chunk alloc/dealloc funcs take extra arg */
+  unsigned maybe_empty_object:1;/* There is a possibility that the current
+                                  chunk contains a zero-length object.  This
+                                  prevents freeing the chunk if we allocate
+                                  a bigger chunk to replace it. */
+  unsigned alloc_failed:1;     /* No longer used, as we now call the failed
+                                  handler on error, but retained for binary
+                                  compatibility.  */
+};
+
+/* Declare the external functions we use; they are in obstack.c.  */
+
+extern void _obstack_newchunk (struct obstack *, int);
+extern int _obstack_begin (struct obstack *, int, int,
+                           void *(*) (long), void (*) (void *));
+extern int _obstack_begin_1 (struct obstack *, int, int,
+                            void *(*) (void *, long),
+                            void (*) (void *, void *), void *);
+extern int _obstack_memory_used (struct obstack *);
+
+void obstack_free (struct obstack *obstack, void *block);
+
+\f
+/* Error handler called when `obstack_chunk_alloc' failed to allocate
+   more memory.  This can be set to a user defined function which
+   should either abort gracefully or use longjump - but shouldn't
+   return.  The default action is to print a message and abort.  */
+extern void (*obstack_alloc_failed_handler) (void);
+
+/* Exit value used when `print_and_abort' is used.  */
+extern int obstack_exit_failure;
+\f
+/* Pointer to beginning of object being allocated or to be allocated next.
+   Note that this might not be the final address of the object
+   because a new chunk might be needed to hold the final size.  */
+
+#define obstack_base(h) ((void *) (h)->object_base)
+
+/* Size for allocating ordinary chunks.  */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk.  */
+
+#define obstack_next_free(h)   ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object.  */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+/* To prevent prototype warnings provide complete argument list.  */
+#define obstack_init(h)                                                \
+  _obstack_begin ((h), 0, 0,                                   \
+                 (void *(*) (long)) obstack_chunk_alloc,       \
+                 (void (*) (void *)) obstack_chunk_free)
+
+#define obstack_begin(h, size)                                 \
+  _obstack_begin ((h), (size), 0,                              \
+                 (void *(*) (long)) obstack_chunk_alloc,       \
+                 (void (*) (void *)) obstack_chunk_free)
+
+#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)  \
+  _obstack_begin ((h), (size), (alignment),                               \
+                 (void *(*) (long)) (chunkfun),                           \
+                 (void (*) (void *)) (freefun))
+
+#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+  _obstack_begin_1 ((h), (size), (alignment),                          \
+                   (void *(*) (void *, long)) (chunkfun),              \
+                   (void (*) (void *, void *)) (freefun), (arg))
+
+#define obstack_chunkfun(h, newchunkfun) \
+  ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+
+#define obstack_freefun(h, newfreefun) \
+  ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#define obstack_memory_used(h) _obstack_memory_used (h)
+\f
+#if defined __GNUC__ && defined __STDC__ && __STDC__
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+   does not implement __extension__.  But that compiler doesn't define
+   __GNUC_MINOR__.  */
+# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+#  define __extension__
+# endif
+
+/* For GNU C, if not -traditional,
+   we can define these macros to compute all args only once
+   without using a global variable.
+   Also, we can avoid using the `temp' slot, to make faster code.  */
+
+# define obstack_object_size(OBSTACK)                                  \
+  __extension__                                                                \
+  ({ struct obstack const *__o = (OBSTACK);                            \
+     (unsigned) (__o->next_free - __o->object_base); })
+
+# define obstack_room(OBSTACK)                                         \
+  __extension__                                                                \
+  ({ struct obstack const *__o = (OBSTACK);                            \
+     (unsigned) (__o->chunk_limit - __o->next_free); })
+
+# define obstack_make_room(OBSTACK,length)                             \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   if (__o->chunk_limit - __o->next_free < __len)                      \
+     _obstack_newchunk (__o, __len);                                   \
+   (void) 0; })
+
+# define obstack_empty_p(OBSTACK)                                      \
+  __extension__                                                                \
+  ({ struct obstack const *__o = (OBSTACK);                            \
+     (__o->chunk->prev == 0                                            \
+      && __o->next_free == __PTR_ALIGN ((char *) __o->chunk,           \
+                                       __o->chunk->contents,           \
+                                       __o->alignment_mask)); })
+
+# define obstack_grow(OBSTACK,where,length)                            \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   if (__o->next_free + __len > __o->chunk_limit)                      \
+     _obstack_newchunk (__o, __len);                                   \
+   memcpy (__o->next_free, where, __len);                              \
+   __o->next_free += __len;                                            \
+   (void) 0; })
+
+# define obstack_grow0(OBSTACK,where,length)                           \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   if (__o->next_free + __len + 1 > __o->chunk_limit)                  \
+     _obstack_newchunk (__o, __len + 1);                               \
+   memcpy (__o->next_free, where, __len);                              \
+   __o->next_free += __len;                                            \
+   *(__o->next_free)++ = 0;                                            \
+   (void) 0; })
+
+# define obstack_1grow(OBSTACK,datum)                                  \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   if (__o->next_free + 1 > __o->chunk_limit)                          \
+     _obstack_newchunk (__o, 1);                                       \
+   obstack_1grow_fast (__o, datum);                                    \
+   (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers
+   or ints, and that the data added so far to the current object
+   shares that much alignment.  */
+
+# define obstack_ptr_grow(OBSTACK,datum)                               \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   if (__o->next_free + sizeof (void *) > __o->chunk_limit)            \
+     _obstack_newchunk (__o, sizeof (void *));                         \
+   obstack_ptr_grow_fast (__o, datum); })                              \
+
+# define obstack_int_grow(OBSTACK,datum)                               \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   if (__o->next_free + sizeof (int) > __o->chunk_limit)               \
+     _obstack_newchunk (__o, sizeof (int));                            \
+   obstack_int_grow_fast (__o, datum); })
+
+# define obstack_ptr_grow_fast(OBSTACK,aptr)                           \
+__extension__                                                          \
+({ struct obstack *__o1 = (OBSTACK);                                   \
+   *(const void **) __o1->next_free = (aptr);                          \
+   __o1->next_free += sizeof (const void *);                           \
+   (void) 0; })
+
+# define obstack_int_grow_fast(OBSTACK,aint)                           \
+__extension__                                                          \
+({ struct obstack *__o1 = (OBSTACK);                                   \
+   *(int *) __o1->next_free = (aint);                                  \
+   __o1->next_free += sizeof (int);                                    \
+   (void) 0; })
+
+# define obstack_blank(OBSTACK,length)                                 \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   int __len = (length);                                               \
+   if (__o->chunk_limit - __o->next_free < __len)                      \
+     _obstack_newchunk (__o, __len);                                   \
+   obstack_blank_fast (__o, __len);                                    \
+   (void) 0; })
+
+# define obstack_alloc(OBSTACK,length)                                 \
+__extension__                                                          \
+({ struct obstack *__h = (OBSTACK);                                    \
+   obstack_blank (__h, (length));                                      \
+   obstack_finish (__h); })
+
+# define obstack_copy(OBSTACK,where,length)                            \
+__extension__                                                          \
+({ struct obstack *__h = (OBSTACK);                                    \
+   obstack_grow (__h, (where), (length));                              \
+   obstack_finish (__h); })
+
+# define obstack_copy0(OBSTACK,where,length)                           \
+__extension__                                                          \
+({ struct obstack *__h = (OBSTACK);                                    \
+   obstack_grow0 (__h, (where), (length));                             \
+   obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+   when obstack_blank is called.  */
+# define obstack_finish(OBSTACK)                                       \
+__extension__                                                          \
+({ struct obstack *__o1 = (OBSTACK);                                   \
+   void *__value = (void *) __o1->object_base;                         \
+   if (__o1->next_free == __value)                                     \
+     __o1->maybe_empty_object = 1;                                     \
+   __o1->next_free                                                     \
+     = __PTR_ALIGN (__o1->object_base, __o1->next_free,                        \
+                   __o1->alignment_mask);                              \
+   if (__o1->next_free - (char *)__o1->chunk                           \
+       > __o1->chunk_limit - (char *)__o1->chunk)                      \
+     __o1->next_free = __o1->chunk_limit;                              \
+   __o1->object_base = __o1->next_free;                                        \
+   __value; })
+
+# define obstack_free(OBSTACK, OBJ)                                    \
+__extension__                                                          \
+({ struct obstack *__o = (OBSTACK);                                    \
+   void *__obj = (OBJ);                                                        \
+   if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit)  \
+     __o->next_free = __o->object_base = (char *)__obj;                        \
+   else (obstack_free) (__o, __obj); })
+\f
+#else /* not __GNUC__ or not __STDC__ */
+
+# define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+# define obstack_room(h)               \
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+# define obstack_empty_p(h) \
+ ((h)->chunk->prev == 0                                                        \
+  && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk,               \
+                                   (h)->chunk->contents,               \
+                                   (h)->alignment_mask))
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+   so that we can avoid having void expressions
+   in the arms of the conditional expression.
+   Casting the third operand to void was tried before,
+   but some compilers won't accept it.  */
+
+# define obstack_make_room(h,length)                                   \
+( (h)->temp.tempint = (length),                                                \
+  (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)             \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0))
+
+# define obstack_grow(h,where,length)                                  \
+( (h)->temp.tempint = (length),                                                \
+  (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)             \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),             \
+  memcpy ((h)->next_free, where, (h)->temp.tempint),                   \
+  (h)->next_free += (h)->temp.tempint)
+
+# define obstack_grow0(h,where,length)                                 \
+( (h)->temp.tempint = (length),                                                \
+  (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit)         \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0),         \
+  memcpy ((h)->next_free, where, (h)->temp.tempint),                   \
+  (h)->next_free += (h)->temp.tempint,                                 \
+  *((h)->next_free)++ = 0)
+
+# define obstack_1grow(h,datum)                                                \
+( (((h)->next_free + 1 > (h)->chunk_limit)                             \
+   ? (_obstack_newchunk ((h), 1), 0) : 0),                             \
+  obstack_1grow_fast (h, datum))
+
+# define obstack_ptr_grow(h,datum)                                     \
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit)               \
+   ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0),               \
+  obstack_ptr_grow_fast (h, datum))
+
+# define obstack_int_grow(h,datum)                                     \
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit)                  \
+   ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0),                  \
+  obstack_int_grow_fast (h, datum))
+
+# define obstack_ptr_grow_fast(h,aptr)                                 \
+  (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
+
+# define obstack_int_grow_fast(h,aint)                                 \
+  (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
+
+# define obstack_blank(h,length)                                       \
+( (h)->temp.tempint = (length),                                                \
+  (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint)             \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),             \
+  obstack_blank_fast (h, (h)->temp.tempint))
+
+# define obstack_alloc(h,length)                                       \
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+# define obstack_copy(h,where,length)                                  \
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_copy0(h,where,length)                                 \
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_finish(h)                                             \
+( ((h)->next_free == (h)->object_base                                  \
+   ? (((h)->maybe_empty_object = 1), 0)                                        \
+   : 0),                                                               \
+  (h)->temp.tempptr = (h)->object_base,                                        \
+  (h)->next_free                                                       \
+    = __PTR_ALIGN ((h)->object_base, (h)->next_free,                   \
+                  (h)->alignment_mask),                                \
+  (((h)->next_free - (char *) (h)->chunk                               \
+    > (h)->chunk_limit - (char *) (h)->chunk)                          \
+   ? ((h)->next_free = (h)->chunk_limit) : 0),                         \
+  (h)->object_base = (h)->next_free,                                   \
+  (h)->temp.tempptr)
+
+# define obstack_free(h,obj)                                           \
+( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk,            \
+  ((((h)->temp.tempint > 0                                             \
+    && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk))    \
+   ? (int) ((h)->next_free = (h)->object_base                          \
+           = (h)->temp.tempint + (char *) (h)->chunk)                  \
+   : (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0)))
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#ifdef __cplusplus
+}      /* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/src/obstack/obstackpp.hpp b/src/obstack/obstackpp.hpp
new file mode 100644 (file)
index 0000000..6c345f5
--- /dev/null
@@ -0,0 +1,49 @@
+//  $Id$
+//
+//  SuperTux
+//  Copyright (C) 2007 Matthias Braun <matze@braunis.de>
+//
+//  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 distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  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.
+#ifndef OBSTACKPP_H_
+#define OBSTACKPP_H_
+
+#include "obstack.h"
+
+inline void*
+operator new (size_t bytes, struct obstack& obst)
+{
+  return obstack_alloc(&obst, bytes);
+}
+
+inline void*
+operator new[] (size_t bytes, struct obstack& obst)
+{
+  return obstack_alloc(&obst, bytes);
+}
+
+static inline void* obstack_chunk_alloc(size_t size)
+{
+  return new char[size];
+}
+
+static inline void obstack_chunk_free(void* data)
+{
+  char* ptr = static_cast<char*> (data);
+  delete[] ptr;
+}
+
+#endif
+
index 5dee002..f0e6037 100644 (file)
@@ -122,6 +122,7 @@ void unload_shared()
 {
   /* Free global images: */
   delete gold_text;
+  delete gold_fixed_text;
   delete white_text;
   delete blue_text;
   delete gray_text;
@@ -145,4 +146,7 @@ void unload_shared()
 
   /* Free mouse-cursor */
   delete mouse_cursor;
+
+  delete player_status;
+  player_status = NULL;
 }
index 0878e62..f1de683 100644 (file)
@@ -69,15 +69,15 @@ SpriteData*
 SpriteManager::load(const std::string& filename)
 {
   lisp::Parser parser;
-  std::auto_ptr<lisp::Lisp> root;
+  const lisp::Lisp* root;
 
   try {
-    root.reset(parser.parse(filename));
+    root = parser.parse(filename);
   } catch(const std::exception& e) {
-       std::ostringstream msg;
-       msg << "Parse error when trying to load sprite '" << filename
-               << "': " << e.what() << "\n";
-       throw std::runtime_error(msg.str());
+    std::ostringstream msg;
+    msg << "Parse error when trying to load sprite '" << filename
+        << "': " << e.what() << "\n";
+    throw std::runtime_error(msg.str());
   }
 
   const lisp::Lisp* sprite = root->get_lisp("supertux-sprite");
index bca514c..759a9c7 100644 (file)
@@ -51,7 +51,7 @@ TextScroller::TextScroller(const std::string& filename)
 
   lisp::Parser parser;
   try {
-    std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
+    const lisp::Lisp* root = parser.parse(filename);
 
     const lisp::Lisp* text_lisp = root->get_lisp("supertux-text");
     if(!text_lisp)
index 391fc55..df1f90d 100644 (file)
@@ -69,7 +69,7 @@ void TileManager::load_tileset(std::string filename)
   }
 
   lisp::Parser parser;
-  std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
+  const lisp::Lisp* root = parser.parse(filename);
 
   const lisp::Lisp* tiles_lisp = root->get_lisp("supertux-tiles");
   if(!tiles_lisp)
index 79bc574..56b1e45 100644 (file)
@@ -146,7 +146,7 @@ TitleScreen::get_level_name(const std::string& filename)
 {
   try {
     lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
+    const lisp::Lisp* root = parser.parse(filename);
 
     const lisp::Lisp* level = root->get_lisp("supertux-level");
     if(!level)
@@ -474,7 +474,7 @@ TitleScreen::get_slotinfo(int slot)
 
   try {
     lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(slotfile));
+    const lisp::Lisp* root = parser.parse(slotfile);
 
     const lisp::Lisp* savegame = root->get_lisp("supertux-savegame");
     if(!savegame)
index 4c5f179..89a92f2 100644 (file)
@@ -16,9 +16,9 @@
 //  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>
 
+#include <functional>
 #include <algorithm>
 #include <cassert>
 #include <iostream>
 #include "glutil.hpp"
 #include "texture.hpp"
 #include "texture_manager.hpp"
+#include "obstack/obstackpp.hpp"
 #define LIGHTMAP_DIV 5
 
+enum RequestType
+{
+  SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, LIGHTMAPREQUEST, GETLIGHT
+};
+
+struct SurfacePartRequest
+{
+  const Surface* surface;
+  Vector source, size;
+};
+
+struct TextRequest
+{
+  const Font* font;
+  std::string text;
+  FontAlignment alignment;
+};
+
+struct GradientRequest
+{
+  Color top, bottom;
+  Vector size;
+};
+
+struct FillRectRequest
+{
+  Color color;
+  Vector size;
+};
+
+struct DrawingRequest
+{
+  RequestType type;
+  Vector pos;
+
+  int layer;
+  DrawingEffect drawing_effect;
+  float alpha;
+  Blend blend;
+  float angle;
+  Color color;
+
+  void* request_data;
+
+  DrawingRequest()
+    : angle(0.0f),
+      color(1.0f, 1.0f, 1.0f, 1.0f)
+  {}
+
+  bool operator<(const DrawingRequest& other) const
+  {
+    return layer < other.layer;
+  }
+};
+
+struct GetLightRequest
+{
+  Color* color_ptr;
+};
+
 static inline int next_po2(int val)
 {
   int result = 1;
@@ -45,7 +106,7 @@ static inline int next_po2(int val)
 }
 
 DrawingContext::DrawingContext()
-  : ambient_color( 1.0f, 1.0f, 1.0f, 1.0f )
+  : ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL)
 {
   screen = SDL_GetVideoSurface();
 
@@ -61,10 +122,14 @@ DrawingContext::DrawingContext()
   texture_manager->register_texture(lightmap);
 
   requests = &drawing_requests;
+
+  obstack_init(&obst);
 }
 
 DrawingContext::~DrawingContext()
 {
+  obstack_free(&obst, NULL);
+
   texture_manager->remove_texture(lightmap);
   delete lightmap;
 }
@@ -76,24 +141,24 @@ DrawingContext::draw_surface(const Surface* surface, const Vector& position,
 {
   assert(surface != 0);
 
-  DrawingRequest request;
+  DrawingRequest* request = new(obst) DrawingRequest();
 
-  request.type = SURFACE;
-  request.pos = transform.apply(position);
+  request->type = SURFACE;
+  request->pos = transform.apply(position);
 
-  if(request.pos.x >= SCREEN_WIDTH || request.pos.y >= SCREEN_HEIGHT
-      || request.pos.x + surface->get_width() < 0
-      || request.pos.y + surface->get_height() < 0)
+  if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
+      || request->pos.x + surface->get_width() < 0
+      || request->pos.y + surface->get_height() < 0)
     return;
 
-  request.layer = layer;
-  request.drawing_effect = transform.drawing_effect;
-  request.alpha = transform.alpha;
-  request.angle = angle;
-  request.color = color;
-  request.blend = blend;
+  request->layer = layer;
+  request->drawing_effect = transform.drawing_effect;
+  request->alpha = transform.alpha;
+  request->angle = angle;
+  request->color = color;
+  request->blend = blend;
 
-  request.request_data = const_cast<Surface*> (surface);
+  request->request_data = const_cast<Surface*> (surface);
 
   requests->push_back(request);
 }
@@ -111,35 +176,35 @@ DrawingContext::draw_surface_part(const Surface* surface, const Vector& source,
 {
   assert(surface != 0);
 
-  DrawingRequest request;
+  DrawingRequest* request = new(obst) DrawingRequest();
 
-  request.type = SURFACE_PART;
-  request.pos = transform.apply(dest);
-  request.layer = layer;
-  request.drawing_effect = transform.drawing_effect;
-  request.alpha = transform.alpha;
+  request->type = SURFACE_PART;
+  request->pos = transform.apply(dest);
+  request->layer = layer;
+  request->drawing_effect = transform.drawing_effect;
+  request->alpha = transform.alpha;
 
-  SurfacePartRequest* surfacepartrequest = new SurfacePartRequest();
+  SurfacePartRequest* surfacepartrequest = new(obst) SurfacePartRequest();
   surfacepartrequest->size = size;
   surfacepartrequest->source = source;
   surfacepartrequest->surface = surface;
 
   // clip on screen borders
-  if(request.pos.x < 0) {
-    surfacepartrequest->size.x += request.pos.x;
+  if(request->pos.x < 0) {
+    surfacepartrequest->size.x += request->pos.x;
     if(surfacepartrequest->size.x <= 0)
       return;
-    surfacepartrequest->source.x -= request.pos.x;
-    request.pos.x = 0;
+    surfacepartrequest->source.x -= request->pos.x;
+    request->pos.x = 0;
   }
-  if(request.pos.y < 0) {
-    surfacepartrequest->size.y += request.pos.y;
+  if(request->pos.y < 0) {
+    surfacepartrequest->size.y += request->pos.y;
     if(surfacepartrequest->size.y <= 0)
       return;
-    surfacepartrequest->source.y -= request.pos.y;
-    request.pos.y = 0;
+    surfacepartrequest->source.y -= request->pos.y;
+    request->pos.y = 0;
   }
-  request.request_data = surfacepartrequest;
+  request->request_data = surfacepartrequest;
 
   requests->push_back(request);
 }
@@ -148,19 +213,19 @@ void
 DrawingContext::draw_text(const Font* font, const std::string& text,
     const Vector& position, FontAlignment alignment, int layer)
 {
-  DrawingRequest request;
+  DrawingRequest* request = new(obst) DrawingRequest();
 
-  request.type = TEXT;
-  request.pos = transform.apply(position);
-  request.layer = layer;
-  request.drawing_effect = transform.drawing_effect;
-  request.alpha = transform.alpha;
+  request->type = TEXT;
+  request->pos = transform.apply(position);
+  request->layer = layer;
+  request->drawing_effect = transform.drawing_effect;
+  request->alpha = transform.alpha;
 
-  TextRequest* textrequest = new TextRequest;
+  TextRequest* textrequest = new(obst) TextRequest();
   textrequest->font = font;
   textrequest->text = text;
   textrequest->alignment = alignment;
-  request.request_data = textrequest;
+  request->request_data = textrequest;
 
   requests->push_back(request);
 }
@@ -176,19 +241,19 @@ DrawingContext::draw_center_text(const Font* font, const std::string& text,
 void
 DrawingContext::draw_gradient(const Color& top, const Color& bottom, int layer)
 {
-  DrawingRequest request;
+  DrawingRequest* request = new(obst) DrawingRequest();
 
-  request.type = GRADIENT;
-  request.pos = Vector(0,0);
-  request.layer = layer;
+  request->type = GRADIENT;
+  request->pos = Vector(0,0);
+  request->layer = layer;
 
-  request.drawing_effect = transform.drawing_effect;
-  request.alpha = transform.alpha;
+  request->drawing_effect = transform.drawing_effect;
+  request->alpha = transform.alpha;
 
-  GradientRequest* gradientrequest = new GradientRequest;
+  GradientRequest* gradientrequest = new(obst) GradientRequest();
   gradientrequest->top = top;
   gradientrequest->bottom = bottom;
-  request.request_data = gradientrequest;
+  request->request_data = gradientrequest;
 
   requests->push_back(request);
 }
@@ -197,20 +262,20 @@ void
 DrawingContext::draw_filled_rect(const Vector& topleft, const Vector& size,
                                  const Color& color, int layer)
 {
-  DrawingRequest request;
+  DrawingRequest* request = new(obst) DrawingRequest();
 
-  request.type = FILLRECT;
-  request.pos = transform.apply(topleft);
-  request.layer = layer;
+  request->type = FILLRECT;
+  request->pos = transform.apply(topleft);
+  request->layer = layer;
 
-  request.drawing_effect = transform.drawing_effect;
-  request.alpha = transform.alpha;
+  request->drawing_effect = transform.drawing_effect;
+  request->alpha = transform.alpha;
 
-  FillRectRequest* fillrectrequest = new FillRectRequest;
+  FillRectRequest* fillrectrequest = new(obst) FillRectRequest();
   fillrectrequest->size = size;
   fillrectrequest->color = color;
   fillrectrequest->color.alpha = color.alpha * transform.alpha;
-  request.request_data = fillrectrequest;
+  request->request_data = fillrectrequest;
 
   requests->push_back(request);
 }
@@ -219,20 +284,20 @@ void
 DrawingContext::draw_filled_rect(const Rect& rect, const Color& color,
                                  int layer)
 {
-  DrawingRequest request;
+  DrawingRequest* request = new(obst) DrawingRequest();
 
-  request.type = FILLRECT;
-  request.pos = transform.apply(rect.p1);
-  request.layer = layer;
+  request->type = FILLRECT;
+  request->pos = transform.apply(rect.p1);
+  request->layer = layer;
 
-  request.drawing_effect = transform.drawing_effect;
-  request.alpha = transform.alpha;
+  request->drawing_effect = transform.drawing_effect;
+  request->alpha = transform.alpha;
 
-  FillRectRequest* fillrectrequest = new FillRectRequest;
+  FillRectRequest* fillrectrequest = new(obst) FillRectRequest;
   fillrectrequest->size = Vector(rect.get_width(), rect.get_height());
   fillrectrequest->color = color;
   fillrectrequest->color.alpha = color.alpha * transform.alpha;
-  request.request_data = fillrectrequest;
+  request->request_data = fillrectrequest;
 
   requests->push_back(request);
 }
@@ -246,28 +311,29 @@ DrawingContext::get_light(const Vector& position, Color* color)
     return;
   }
 
-  DrawingRequest request;
-  request.type = GETLIGHT;
-  request.pos = transform.apply(position);
+  DrawingRequest* request = new(obst) DrawingRequest();
+  request->type = GETLIGHT;
+  request->pos = transform.apply(position);
 
   //There is no light offscreen.
-  if(request.pos.x >= SCREEN_WIDTH || request.pos.y >= SCREEN_HEIGHT
-      || request.pos.x < 0 || request.pos.y < 0){
+  if(request->pos.x >= SCREEN_WIDTH || request->pos.y >= SCREEN_HEIGHT
+      || request->pos.x < 0 || request->pos.y < 0){
     *color = Color( 0, 0, 0);
     return;
   }
 
-  request.layer = LAYER_GUI; //make sure all get_light requests are handled last.
-  GetLightRequest* getlightrequest = new GetLightRequest;
+  request->layer = LAYER_GUI; //make sure all get_light requests are handled last.
+  GetLightRequest* getlightrequest = new(obst) GetLightRequest();
   getlightrequest->color_ptr = color;
-  request.request_data = getlightrequest;
+  request->request_data = getlightrequest;
   lightmap_requests.push_back(request);
 }
 
 void
-DrawingContext::get_light(DrawingRequest& request)
+DrawingContext::get_light(const DrawingRequest& request) const
 {
-  GetLightRequest* getlightrequest = (GetLightRequest*) request.request_data;
+  const GetLightRequest* getlightrequest 
+    = (GetLightRequest*) request.request_data;
 
   float pixels[3];
   for( int i = 0; i<3; i++)
@@ -278,14 +344,12 @@ DrawingContext::get_light(DrawingRequest& request)
   glReadPixels((GLint) posX, (GLint) posY , 1, 1, GL_RGB, GL_FLOAT, pixels);
     *(getlightrequest->color_ptr) = Color( pixels[0], pixels[1], pixels[2]);
   //printf("get_light %f/%f =>%f/%f r%f g%f b%f\n", request.pos.x, request.pos.y, posX, posY, pixels[0], pixels[1], pixels[2]);
-
-  delete getlightrequest;
 }
 
 void
-DrawingContext::draw_surface_part(DrawingRequest& request)
+DrawingContext::draw_surface_part(const DrawingRequest& request) const
 {
-  SurfacePartRequest* surfacepartrequest
+  const SurfacePartRequest* surfacepartrequest
     = (SurfacePartRequest*) request.request_data;
 
   surfacepartrequest->surface->draw_part(
@@ -293,14 +357,13 @@ DrawingContext::draw_surface_part(DrawingRequest& request)
       request.pos.x, request.pos.y,
       surfacepartrequest->size.x, surfacepartrequest->size.y,
       request.alpha, request.drawing_effect);
-
-  delete surfacepartrequest;
 }
 
 void
-DrawingContext::draw_gradient(DrawingRequest& request)
+DrawingContext::draw_gradient(const DrawingRequest& request) const
 {
-  GradientRequest* gradientrequest = (GradientRequest*) request.request_data;
+  const GradientRequest* gradientrequest 
+    = (GradientRequest*) request.request_data;
   const Color& top = gradientrequest->top;
   const Color& bottom = gradientrequest->bottom;
 
@@ -314,25 +377,22 @@ DrawingContext::draw_gradient(DrawingRequest& request)
   glVertex2f(0, SCREEN_HEIGHT);
   glEnd();
   glEnable(GL_TEXTURE_2D);
-
-  delete gradientrequest;
 }
 
 void
-DrawingContext::draw_text(DrawingRequest& request)
+DrawingContext::draw_text(const DrawingRequest& request) const
 {
-  TextRequest* textrequest = (TextRequest*) request.request_data;
+  const TextRequest* textrequest = (TextRequest*) request.request_data;
 
   textrequest->font->draw(textrequest->text, request.pos,
       textrequest->alignment, request.drawing_effect, request.alpha);
-
-  delete textrequest;
 }
 
 void
-DrawingContext::draw_filled_rect(DrawingRequest& request)
+DrawingContext::draw_filled_rect(const DrawingRequest& request) const
 {
-  FillRectRequest* fillrectrequest = (FillRectRequest*) request.request_data;
+  const FillRectRequest* fillrectrequest
+    = (FillRectRequest*) request.request_data;
 
   float x = request.pos.x;
   float y = request.pos.y;
@@ -350,12 +410,10 @@ DrawingContext::draw_filled_rect(DrawingRequest& request)
   glVertex2f(x, y+h);
   glEnd();
   glEnable(GL_TEXTURE_2D);
-
-  delete fillrectrequest;
 }
 
 void
-DrawingContext::draw_lightmap(DrawingRequest& request)
+DrawingContext::draw_lightmap(const DrawingRequest& request) const
 {
   const Texture* texture = reinterpret_cast<Texture*> (request.request_data);
 
@@ -423,57 +481,77 @@ DrawingContext::do_drawing()
     glEnable(GL_BLEND);
 
     // add a lightmap drawing request into the queue
-    DrawingRequest request;
-    request.type = LIGHTMAPREQUEST;
-    request.layer = LAYER_HUD - 1;
-    request.request_data = lightmap;
+    DrawingRequest* request = new(obst) DrawingRequest();
+    request->type = LIGHTMAPREQUEST;
+    request->layer = LAYER_HUD - 1;
+    request->request_data = lightmap;
     requests->push_back(request);
   }
 
   //glClear(GL_COLOR_BUFFER_BIT);
   handle_drawing_requests(drawing_requests);
   drawing_requests.clear();
+  obstack_free(&obst, NULL);
+  obstack_init(&obst);
   assert_gl("drawing");
 
   SDL_GL_SwapBuffers();
 }
 
+class RequestPtrCompare
+  :  public std::binary_function<const DrawingRequest*,
+                                 const DrawingRequest*, 
+                                 bool>
+{
+public:
+  bool operator()(const DrawingRequest* r1, const DrawingRequest* r2) const
+  {
+    return *r1 < *r2;
+  }
+};
+
 void
-DrawingContext::handle_drawing_requests(DrawingRequests& requests)
+DrawingContext::handle_drawing_requests(DrawingRequests& requests) const
 {
-  std::stable_sort(requests.begin(), requests.end());
+  std::stable_sort(requests.begin(), requests.end(), RequestPtrCompare());
+
+  DrawingRequests::const_iterator i;
+  for(i = requests.begin(); i != requests.end(); ++i) {
+    const DrawingRequest& request = **i;
 
-  for(DrawingRequests::iterator i = requests.begin();
-      i != requests.end(); ++i) {
-    switch(i->type) {
+    switch(request.type) {
       case SURFACE:
       {
-        const Surface* surface = (const Surface*) i->request_data;
-        if (i->angle == 0.0f &&
-            i->color.red == 1.0f && i->color.green == 1.0f  &&
-            i->color.blue == 1.0f &&  i->color.alpha == 1.0f  )
-          surface->draw(i->pos.x, i->pos.y, i->alpha, i->drawing_effect);
-        else
-          surface->draw(i->pos.x, i->pos.y, i->alpha, i->angle, i->color, i->blend, i->drawing_effect);
+        const Surface* surface = (const Surface*) request.request_data;
+        if (request.angle == 0.0f &&
+            request.color.red == 1.0f && request.color.green == 1.0f  &&
+            request.color.blue == 1.0f &&  request.color.alpha == 1.0f) {
+          surface->draw(request.pos.x, request.pos.y, request.alpha,
+              request.drawing_effect);
+        } else {
+          surface->draw(request.pos.x, request.pos.y,
+              request.alpha, request.angle, request.color,
+              request.blend, request.drawing_effect);
+        }
         break;
       }
       case SURFACE_PART:
-        draw_surface_part(*i);
+        draw_surface_part(request);
         break;
       case GRADIENT:
-        draw_gradient(*i);
+        draw_gradient(request);
         break;
       case TEXT:
-        draw_text(*i);
+        draw_text(request);
         break;
       case FILLRECT:
-        draw_filled_rect(*i);
+        draw_filled_rect(request);
         break;
       case LIGHTMAPREQUEST:
-        draw_lightmap(*i);
+        draw_lightmap(request);
         break;
       case GETLIGHT:
-        get_light(*i);
+        get_light(request);
         break;
     }
   }
@@ -535,10 +613,12 @@ void
 DrawingContext::set_target(Target target)
 {
   this->target = target;
-  if(target == LIGHTMAP)
+  if(target == LIGHTMAP) {
     requests = &lightmap_requests;
-  else
+  } else {
+    assert(target == NORMAL);
     requests = &drawing_requests;
+  }
 }
 
 void
index 4839239..de882a7 100644 (file)
@@ -16,7 +16,6 @@
 //  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.
-
 #ifndef SUPERTUX_DRAWINGCONTEXT_H
 #define SUPERTUX_DRAWINGCONTEXT_H
 
@@ -29,6 +28,7 @@
 #include <stdint.h>
 #include <memory>
 
+#include "obstack/obstack.h"
 #include "math/vector.hpp"
 #include "math/rect.hpp"
 #include "surface.hpp"
@@ -37,6 +37,7 @@
 
 class Surface;
 class Texture;
+struct DrawingRequest;
 
 // some constants for predefined layer values
 enum {
@@ -163,76 +164,16 @@ private:
   std::vector<Blend> blend_stack;
   Blend blend_mode;
 
-  enum RequestType
-  {
-    SURFACE, SURFACE_PART, TEXT, GRADIENT, FILLRECT, LIGHTMAPREQUEST, GETLIGHT
-  };
-
-  struct SurfacePartRequest
-  {
-    const Surface* surface;
-    Vector source, size;
-  };
-
-  struct TextRequest
-  {
-    const Font* font;
-    std::string text;
-    FontAlignment alignment;
-  };
-
-  struct GradientRequest
-  {
-    Color top, bottom;
-    Vector size;
-  };
-
-  struct FillRectRequest
-  {
-    Color color;
-    Vector size;
-  };
-
-  struct DrawingRequest
-  {
-    RequestType type;
-    Vector pos;
-
-    int layer;
-    DrawingEffect drawing_effect;
-    float alpha;
-    Blend blend;
-    float angle;
-    Color color;
-
-    void* request_data;
-
-    DrawingRequest()
-      : angle(0.0f),
-        color(1.0f, 1.0f, 1.0f, 1.0f)
-    {}
-
-    bool operator<(const DrawingRequest& other) const
-    {
-      return layer < other.layer;
-    }
-  };
-
-  struct GetLightRequest
-  {
-    Color* color_ptr;
-  };
-
-  typedef std::vector<DrawingRequest> DrawingRequests;
+  typedef std::vector<DrawingRequest*> DrawingRequests;
 
-  void handle_drawing_requests(DrawingRequests& requests);
-  void draw_surface_part(DrawingRequest& request);
-  void draw_text(DrawingRequest& request);
-  void draw_text_center(DrawingRequest& request);
-  void draw_gradient(DrawingRequest& request);
-  void draw_filled_rect(DrawingRequest& request);
-  void draw_lightmap(DrawingRequest& request);
-  void get_light(DrawingRequest& request);
+  void handle_drawing_requests(DrawingRequests& requests) const;
+  void draw_surface_part(const DrawingRequest& request) const;
+  void draw_text(const DrawingRequest& request) const;
+  void draw_text_center(const DrawingRequest& request) const;
+  void draw_gradient(const DrawingRequest& request) const;
+  void draw_filled_rect(const DrawingRequest& request) const;
+  void draw_lightmap(const DrawingRequest& request) const;
+  void get_light(const DrawingRequest& request) const;
 
   DrawingRequests drawing_requests;
   DrawingRequests lightmap_requests;
@@ -246,6 +187,10 @@ private:
   Texture* lightmap;
   int lightmap_width, lightmap_height;
   float lightmap_uv_right, lightmap_uv_bottom;
+
+  /* obstack holding the memory of the drawing requests */
+  struct obstack obst;
 };
 
 #endif
+
index d45eb84..6326d04 100644 (file)
@@ -120,8 +120,10 @@ TextureManager::create_image_texture(const std::string& filename)
       0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
 #endif
 
-  if(convert == 0)
+  if(convert == 0) {
+    SDL_FreeSurface(image);
     throw std::runtime_error("Couldn't create texture: out of memory");
+  }
 
   SDL_SetAlpha(image, 0, 0);
   SDL_BlitSurface(image, 0, convert, 0);
@@ -134,10 +136,12 @@ TextureManager::create_image_texture(const std::string& filename)
     result->image_height = image->h;
   } catch(...) {
     delete result;
+    SDL_FreeSurface(image);
     SDL_FreeSurface(convert);
     throw;
   }
 
+  SDL_FreeSurface(image);
   SDL_FreeSurface(convert);
   return result;
 }
index 9301adc..8fd4599 100644 (file)
@@ -86,7 +86,7 @@ World::load(const std::string& filename)
   basedir = FileSystem::dirname(filename);
 
   lisp::Parser parser;
-  std::auto_ptr<lisp::Lisp> root (parser.parse(filename));
+  const lisp::Lisp* root = parser.parse(filename);
 
   const lisp::Lisp* info = root->get_lisp("supertux-world");
   if(info == NULL)
@@ -198,7 +198,7 @@ World::load_state()
 
   try {
     lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(savegame_filename));
+    const lisp::Lisp* root = parser.parse(savegame_filename);
 
     const lisp::Lisp* lisp = root->get_lisp("supertux-savegame");
     if(lisp == NULL)
index cc4ec20..65cb1f0 100644 (file)
@@ -247,7 +247,7 @@ WorldMap::load(const std::string& filename)
 
   try {
     lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(map_filename));
+    const lisp::Lisp* root = parser.parse(map_filename);
 
     const lisp::Lisp* lisp = root->get_lisp("supertux-level");
     if(!lisp)
@@ -323,7 +323,7 @@ WorldMap::get_level_title(LevelTile& level)
 
   try {
     lisp::Parser parser;
-    std::auto_ptr<lisp::Lisp> root (parser.parse(levels_path + level.get_name()));
+    const lisp::Lisp* root = parser.parse(levels_path + level.get_name());
 
     const lisp::Lisp* level_lisp = root->get_lisp("supertux-level");
     if(!level_lisp)