<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_CLASS_HPP
#define FLUSSPFERD_CLASS_HPP

#include "native_function_base.hpp"
#include "create.hpp"
#include "init.hpp"
#include "local_root_scope.hpp"
#include <boost/ref.hpp>

namespace flusspferd {

namespace detail {

template<typename T>
struct class_constructor : native_function_base {
  class_constructor(unsigned arity, char const *name)
    : native_function_base(arity, name)
  {}

  void call(call_context &x) {
    x.result = create_native_object<T>(
        x.function.get_property("prototype").to_object(),
        boost::ref(x));
  }
};

}

struct class_info {
  static std::size_t constructor_arity() {
    return 0;
  }

  static void augment_constructor(object const &) {
  }

  static object create_prototype() {
    return create_object();
  }
};

template<typename T>
object load_class(object container = global()) {
  std::size_t const arity = T::class_info::constructor_arity::value;
  char const *name = T::class_info::constructor_name();

  local_root_scope scope;

  value previous = container.get_property(name);

  if (previous.is_object())
    return previous.get_object();

  function constructor(
    create_native_function<detail::class_constructor<T> >(arity, name));

  object prototype = T::class_info::create_prototype();

  get_current_context().add_prototype<T>(prototype);

  constructor.define_property(
    "prototype",
    prototype,
    object::dont_enumerate);

  T::class_info::augment_constructor(object(constructor));

  container.define_property(
    name,
    constructor,
    object::dont_enumerate);

  return constructor;
}

template<typename T>
bool load_internal_class() {
  local_root_scope scope;

  context ctx = get_current_context();

  object proto = ctx.get_prototype<T>();

  if (proto.is_valid())
    return false;

  proto = T::class_info::create_prototype();

  ctx.add_prototype<T>(proto);

  return true;
}

}

#endif
<commit_msg>Core: fix flusspferd::class_info<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2008 Aristid Breitkreuz, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_CLASS_HPP
#define FLUSSPFERD_CLASS_HPP

#include "native_function_base.hpp"
#include "create.hpp"
#include "init.hpp"
#include "local_root_scope.hpp"
#include <boost/mpl/size_t.hpp>
#include <boost/ref.hpp>

namespace flusspferd {

namespace detail {

template<typename T>
struct class_constructor : native_function_base {
  class_constructor(unsigned arity, char const *name)
    : native_function_base(arity, name)
  {}

  void call(call_context &x) {
    x.result = create_native_object<T>(
        x.function.get_property("prototype").to_object(),
        boost::ref(x));
  }
};

}

struct class_info {
  typedef boost::mpl::size_t<0> constructor_arity;

  static void augment_constructor(object const &) {
  }

  static object create_prototype() {
    return create_object();
  }
};

template<typename T>
object load_class(object container = global()) {
  std::size_t const arity = T::class_info::constructor_arity::value;
  char const *name = T::class_info::constructor_name();

  local_root_scope scope;

  value previous = container.get_property(name);

  if (previous.is_object())
    return previous.get_object();

  function constructor(
    create_native_function<detail::class_constructor<T> >(arity, name));

  object prototype = T::class_info::create_prototype();

  get_current_context().add_prototype<T>(prototype);

  constructor.define_property(
    "prototype",
    prototype,
    object::dont_enumerate);

  T::class_info::augment_constructor(object(constructor));

  container.define_property(
    name,
    constructor,
    object::dont_enumerate);

  return constructor;
}

template<typename T>
bool load_internal_class() {
  local_root_scope scope;

  context ctx = get_current_context();

  object proto = ctx.get_prototype<T>();

  if (proto.is_valid())
    return false;

  proto = T::class_info::create_prototype();

  ctx.add_prototype<T>(proto);

  return true;
}

}

#endif
<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessn and Per Larsson
 *
 *                                                         Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_GRAPHICS_HPP
#define GCN_GRAPHICS_HPP

#include <iosfwd>
#include <stack>

#include "guichan/cliprectangle.hpp"
#include "guichan/platform.hpp"

namespace gcn
{
    class Color;
    class Font;
    class Image;

    /**
     * Used for drawing graphics. It contains all vital functions for drawing.
     * We include implemented Graphics classes for some common platforms like
     * the Allegro library, the OpenGL library and the SDL library. To make
     * Guichan usable under another platform, a Graphics class must be
     * implemented.
     *
     * In Graphics you can set clip areas to limit drawing to certain
     * areas of the screen. Clip areas are put on a stack, which means that you
     * can push smaller and smaller clip areas onto the stack. All coordinates
     * will be relative to the topmost clip area. In most cases you won't have
     * to worry about the clip areas, unless you want to implement some really
     * complex widget. Pushing and poping of clip areas are handled
     * automatically by container widgets when their child widgets are drawn.
     *
     * IMPORTANT: Remember to pop each clip area that you pushed on the stack
     * after you are done with it.
     *
     * If you feel that Graphics is to restrictive for your needs, there is
     * no one stopping you from using your own code for drawing in Widgets.
     * You could for instance use pure SDL in the drawing of Widgets bypassing
     * Graphics. This might however hurt portability of your application.
     *
     * If you implement a Graphics class not present in Guichan we would be very
     * happy to add it to Guichan.
     *
     * @see AllegroGraphics, OpenGLGraphics, SDLGraphics, Image
     */
    class GCN_CORE_DECLSPEC Graphics
    {
    public:
        /**
         * Alignments for text drawing.
         */
        enum Alignment
        {
            LEFT = 0,
            CENTER,
            RIGHT
        };

        Graphics();

        virtual ~Graphics() { }

        /**
         * Initializes drawing. Called by the Gui when Gui::draw() is called.
         * It is needed by some implementations of Graphics to perform
         * preparations before drawing. An example of such an implementation
         * would be OpenGLGraphics.
         *
         * NOTE: You will never need to call this function yourself.
         *       Gui will do it for you.
         *
         * @see _endDraw, Gui::draw
         */
        virtual void _beginDraw() { }

        /**
         * Deinitializes drawing. Called by the Gui when a Gui::draw() is done.
         * done. It should reset any state changes made by _beginDraw().
         *
         * NOTE: You will never need to call this function yourself.
         *       Gui will do it for you.
         *
         * @see _beginDraw, Gui::draw
         */
        virtual void _endDraw() { }

        /**
         * Pushes a clip area onto the stack. The x and y coordinates in the
         * Rectangle will be relative to the last pushed clip area.
         * If the new area falls outside the current clip area, it will be
         * clipped as necessary.
         *
         * @param area the clip area to be pushed onto the stack.
         * @return false if the the new area lays totally outside the
         *         current clip area. Note that an empty clip area
         *         will be pused in this case.
         */
        virtual bool pushClipArea(Rectangle area);

        /**
         * Removes the topmost clip area from the stack.
         *
         * @throws Exception if the stack is empty.
         */
        virtual void popClipArea();

        /**
         * Gets the current clip area. Usefull if you want to do drawing
         * bypassing Graphics.
         *
         * @return the current clip area.
         */
        virtual const ClipRectangle& getCurrentClipArea();

        /**
         * Draws a part of an Image.
         *
         * NOTE: Width and height arguments will not scale the Image but
         *       specifies the size of the part to be drawn. If you want
         *       to draw the whole Image there is a simplified version of
         *       this function.
         *
         * EXAMPLE: @code drawImage(myImage, 10, 10, 20, 20, 40, 40); @endcode
         *          Will draw a rectangular piece of myImage starting at
         *          coordinate (10, 10) in myImage, with width and height 40.
         *          The piece will be drawn with it's top left corner at
         *          coordinate (20, 20).
         *
         * @param image the Image to draw.
         * @param srcX source Image x coordinate.
         * @param srcY source Image y coordinate.
         * @param dstX destination x coordinate.
         * @param dstY destination y coordinate.
         * @param width the width of the piece.
         * @param height the height of the piece.
         */
        virtual void drawImage(const Image* image,
                               int srcX,
                               int srcY,
                               int dstX,
                               int dstY,
                               int width,
                               int height) = 0;
        /**
         * Draws an image. A simplified version of the other drawImage.
         * It will draw a whole image at the coordinate you specify.
         * It is equivalent to calling:
         * @code drawImage(myImage, 0, 0, dstX, dstY, image->getWidth(), \
         image->getHeight()); @endcode
         */
        virtual void drawImage(const Image* image, int dstX, int dstY);

        /**
         * Draws a single point/pixel.
         *
         * @param x the x coordinate.
         * @param y the y coordinate.
         */
        virtual void drawPoint(int x, int y) = 0;

        /**
         * Ddraws a line.
         *
         * @param x1 the first x coordinate.
         * @param y1 the first y coordinate.
         * @param x2 the second x coordinate.
         * @param y2 the second y coordinate.
         */
        virtual void drawLine(int x1, int y1, int x2, int y2) = 0;

        /**
         * Draws a simple, non-filled, Rectangle with one pixel width.
         *
         * @param rectangle the Rectangle to draw.
         */
        virtual void drawRectangle(const Rectangle& rectangle) = 0;

        /**
         * Draws a filled Rectangle.
         *
         * @param rectangle the filled Rectangle to draw.
         */
        virtual void fillRectangle(const Rectangle& rectangle) = 0;

        /**
         * Sets the Color to use when drawing.
         *
         * @param color a Color.
         */
        virtual void setColor(const Color& color) = 0;

        /**
         * Gets the Color to use when drawing.
         *
         * @return the Color used when drawing.
         */
        virtual const Color& getColor() const = 0;

        /**
         * Sets the font to use when drawing text.
         *
         * @param font the Font to use when drawing.
         */
        virtual void setFont(Font* font);

        /**
         * Draws text.
         *
         * @param text the text to draw.
         * @param x the x coordinate where to draw the text.
         * @param y the y coordinate where to draw the text.
         * @param alignment Graphics::LEFT, Graphics::CENTER or Graphics::RIGHT.
         * @throws Exception when no Font is set.
         */
        virtual void drawText(const std::string& text,
                              int x,
                              int y,
                              Alignment alignment = LEFT);

    protected:
        std::stack<ClipRectangle> mClipStack;
        Font* mFont;
    };
}

#endif // end GCN_GRAPHICS_HPP

/*
 * yakslem - "little cake on cake, but that's the fall"
 * finalman - "skall jag skriva det?"
 * yakslem - "ja, varfor inte?"
 */

<commit_msg>Comments have been updated.<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessn and Per Larsson
 *
 *                                                         Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GCN_GRAPHICS_HPP
#define GCN_GRAPHICS_HPP

#include <iosfwd>
#include <stack>

#include "guichan/cliprectangle.hpp"
#include "guichan/platform.hpp"

namespace gcn
{
    class Color;
    class Font;
    class Image;

    /**
     * Used for drawing graphics. It contains all vital functions for drawing.
     * We include implemented Graphics classes for some common platforms like
     * the Allegro library, the OpenGL library and the SDL library. To make
     * Guichan usable under another platform, a Graphics class must be
     * implemented.
     *
     * In Graphics you can set clip areas to limit drawing to certain
     * areas of the screen. Clip areas are put on a stack, which means that you
     * can push smaller and smaller clip areas onto the stack. All coordinates
     * will be relative to the topmost clip area. In most cases you won't have
     * to worry about the clip areas, unless you want to implement some really
     * complex widget. Pushing and poping of clip areas are handled
     * automatically by container widgets when their child widgets are drawn.
     *
     * IMPORTANT: Remember to pop each clip area that you pushed on the stack
     * after you are done with it.
     *
     * If you feel that Graphics is to restrictive for your needs, there is
     * no one stopping you from using your own code for drawing in Widgets.
     * You could for instance use pure SDL in the drawing of Widgets bypassing
     * Graphics. This might however hurt portability of your application.
     *
     * If you implement a Graphics class not present in Guichan we would be very
     * happy to add it to Guichan.
     *
     * @see AllegroGraphics, OpenGLGraphics, SDLGraphics, Image
     */
    class GCN_CORE_DECLSPEC Graphics
    {
    public:
        /**
         * Alignments for text drawing.
         */
        enum Alignment
        {
            LEFT = 0,
            CENTER,
            RIGHT
        };

        Graphics();

        virtual ~Graphics() { }

        /**
         * Initializes drawing. Called by the Gui when Gui::draw() is called.
         * It is needed by some implementations of Graphics to perform
         * preparations before drawing. An example of such an implementation
         * would be OpenGLGraphics.
         *
         * NOTE: You will never need to call this function yourself, unless
         *       you use a Graphics object outside of Guichan.
         *
         * @see _endDraw, Gui::draw
         */
        virtual void _beginDraw() { }

        /**
         * Deinitializes drawing. Called by the Gui when a Gui::draw() is done.
         * done. It should reset any state changes made by _beginDraw().
         *
         * NOTE: You will never need to call this function yourself, unless
         *       you use a Graphics object outside of Guichan.
         *
         * @see _beginDraw, Gui::draw
         */
        virtual void _endDraw() { }

        /**
         * Pushes a clip area onto the stack. The x and y coordinates in the
         * Rectangle will be relative to the last pushed clip area.
         * If the new area falls outside the current clip area, it will be
         * clipped as necessary.
         *
         * @param area the clip area to be pushed onto the stack.
         * @return false if the the new area lays totally outside the
         *         current clip area. Note that an empty clip area
         *         will be pused in this case.
         */
        virtual bool pushClipArea(Rectangle area);

        /**
         * Removes the topmost clip area from the stack.
         *
         * @throws Exception if the stack is empty.
         */
        virtual void popClipArea();

        /**
         * Gets the current clip area. Usefull if you want to do drawing
         * bypassing Graphics.
         *
         * @return the current clip area.
         */
        virtual const ClipRectangle& getCurrentClipArea();

        /**
         * Draws a part of an Image.
         *
         * NOTE: Width and height arguments will not scale the Image but
         *       specifies the size of the part to be drawn. If you want
         *       to draw the whole Image there is a simplified version of
         *       this function.
         *
         * EXAMPLE: @code drawImage(myImage, 10, 10, 20, 20, 40, 40); @endcode
         *          Will draw a rectangular piece of myImage starting at
         *          coordinate (10, 10) in myImage, with width and height 40.
         *          The piece will be drawn with it's top left corner at
         *          coordinate (20, 20).
         *
         * @param image the Image to draw.
         * @param srcX source Image x coordinate.
         * @param srcY source Image y coordinate.
         * @param dstX destination x coordinate.
         * @param dstY destination y coordinate.
         * @param width the width of the piece.
         * @param height the height of the piece.
         */
        virtual void drawImage(const Image* image,
                               int srcX,
                               int srcY,
                               int dstX,
                               int dstY,
                               int width,
                               int height) = 0;
        /**
         * Draws an image. A simplified version of the other drawImage.
         * It will draw a whole image at the coordinate you specify.
         * It is equivalent to calling:
         * @code drawImage(myImage, 0, 0, dstX, dstY, image->getWidth(), \
         image->getHeight()); @endcode
         */
        virtual void drawImage(const Image* image, int dstX, int dstY);

        /**
         * Draws a single point/pixel.
         *
         * @param x the x coordinate.
         * @param y the y coordinate.
         */
        virtual void drawPoint(int x, int y) = 0;

        /**
         * Ddraws a line.
         *
         * @param x1 the first x coordinate.
         * @param y1 the first y coordinate.
         * @param x2 the second x coordinate.
         * @param y2 the second y coordinate.
         */
        virtual void drawLine(int x1, int y1, int x2, int y2) = 0;

        /**
         * Draws a simple, non-filled, Rectangle with one pixel width.
         *
         * @param rectangle the Rectangle to draw.
         */
        virtual void drawRectangle(const Rectangle& rectangle) = 0;

        /**
         * Draws a filled Rectangle.
         *
         * @param rectangle the filled Rectangle to draw.
         */
        virtual void fillRectangle(const Rectangle& rectangle) = 0;

        /**
         * Sets the Color to use when drawing.
         *
         * @param color a Color.
         */
        virtual void setColor(const Color& color) = 0;

        /**
         * Gets the Color to use when drawing.
         *
         * @return the Color used when drawing.
         */
        virtual const Color& getColor() const = 0;

        /**
         * Sets the font to use when drawing text.
         *
         * @param font the Font to use when drawing.
         */
        virtual void setFont(Font* font);

        /**
         * Draws text.
         *
         * @param text the text to draw.
         * @param x the x coordinate where to draw the text.
         * @param y the y coordinate where to draw the text.
         * @param alignment Graphics::LEFT, Graphics::CENTER or Graphics::RIGHT.
         * @throws Exception when no Font is set.
         */
        virtual void drawText(const std::string& text,
                              int x,
                              int y,
                              Alignment alignment = LEFT);

    protected:
        std::stack<ClipRectangle> mClipStack;
        Font* mFont;
    };
}

#endif // end GCN_GRAPHICS_HPP

/*
 * yakslem - "little cake on cake, but that's the fall"
 * finalman - "skall jag skriva det?"
 * yakslem - "ja, varfor inte?"
 */

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 Artem Pavlenko
 *
 * This 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.
 *
 * This 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_ELLIPSOID_HPP
#define MAPNIK_ELLIPSOID_HPP

namespace mapnik {
struct ellipsoid
{
    double a; // semi mayor axis
    double b; // semi minor axis
};
}

#endif // MAPNIK_ELLIPSOID_HPP
<commit_msg>Remove useless ellipsoid.hpp<commit_after><|endoftext|>


<commit_before>//! Copyright (c) 2013 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "allocator.h"

struct memory_t {
  memory_t* next;
};

struct chunk_t {
  chunk_t*  next;
  memory_t* data;
};

static inline size_t
freelist_index(size_t bytes)
{
  return ((bytes + (allocator_t::ALIGN - 1)) / allocator_t::ALIGN - 1);
}

static inline size_t
min(size_t a, size_t b)
{
  return (a < b ? a : b);
}

memory_t*
allocator_t::alloc_chunk(size_t index)
{
  size_t alloc_size = (index + 1) * ALIGN;
  size_t chunk_size =
    min(MAX_BYTES / alloc_size * alloc_size, alloc_size * MAX_NUMBER);

  if (NULL == free_list_[index]) {
    free_list_[index] = (memory_t*)malloc(chunk_size);
    assert(NULL != free_list_[index]);

    memory_t* node = free_list_[index];
    for (size_t i = 0; i < chunk_size - alloc_size; i += alloc_size)
      node = node->next = node + (index + 1) * ALIGN / sizeof(*node);
    node->next = NULL;
  }

  return free_list_[index];
}

allocator_t::allocator_t(void)
{
  memset(free_list_, 0, sizeof(free_list_));
  chunk_list_ = NULL;
}

allocator_t::~allocator_t(void)
{
  memory_t* chunk;
  while (NULL != chunk_list_) {
    chunk = chunk_list_->data;
    chunk_list_ = chunk_list_->next;
    free(chunk);
  }
}

allocator_t&
allocator_t::singleton(void)
{
  static allocator_t s;
  return s;
}

void*
allocator_t::alloc(size_t size)
{
  assert(size > 0);

  void* ret;

  if (size > MAX_BYTES)
    ret = malloc(size);
  else {
    size_t index = freelist_index(size);
    if (NULL == free_list_[index]) {
      memory_t* new_chunk = alloc_chunk(index);
      chunk_t*  chunk_node;
      if (freelist_index(sizeof(chunk_t)) == index) {
        chunk_node = (chunk_t*)free_list_[index];
        free_list_[index] = free_list_[index]->next;
      }
      else
        chunk_node = (chunk_t*)alloc(sizeof(chunk_t));

      chunk_node->data = new_chunk;
      chunk_node->next = chunk_list_;
      chunk_list_ = chunk_node;
    }

    ret = free_list_[index];
    free_list_[index] = free_list_[index]->next;
  }

  return ret;
}

void
allocator_t::dealloc(void* ptr, size_t size)
{
  assert(NULL != ptr && size > 0);

  size_t index = freelist_index(size);
  memory_t* free_block = (memory_t*)ptr;
  free_block->next = free_list_[index];
  free_list_[index] = free_block;
}
<commit_msg>fixed bug of allocator in single thread<commit_after>//! Copyright (c) 2013 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "allocator.h"

struct memory_t {
  memory_t* next;
};

struct chunk_t {
  chunk_t*  next;
  memory_t* data;
};

static inline size_t
freelist_index(size_t bytes)
{
  return ((bytes + (allocator_t::ALIGN - 1)) / allocator_t::ALIGN - 1);
}

static inline size_t
min(size_t a, size_t b)
{
  return (a < b ? a : b);
}

memory_t*
allocator_t::alloc_chunk(size_t index)
{
  size_t alloc_size = (index + 1) * ALIGN;
  size_t chunk_size =
    min(MAX_BYTES / alloc_size * alloc_size, alloc_size * MAX_NUMBER);

  if (NULL == free_list_[index]) {
    free_list_[index] = (memory_t*)malloc(chunk_size);
    assert(NULL != free_list_[index]);

    memory_t* node = free_list_[index];
    for (size_t i = 0; i < chunk_size - alloc_size; i += alloc_size)
      node = node->next = node + (index + 1) * ALIGN / sizeof(*node);
    node->next = NULL;
  }

  return free_list_[index];
}

allocator_t::allocator_t(void)
{
  memset(free_list_, 0, sizeof(free_list_));
  chunk_list_ = NULL;
}

allocator_t::~allocator_t(void)
{
  int count = 0;
  chunk_t* chunk = chunk_list_;
  while (NULL != chunk) {
    ++count;
    chunk = chunk->next;
  }

  void** memory_list = (void**)malloc(sizeof(void*) * count);
  assert(NULL != memory_list);

  int i = 0;
  chunk = chunk_list_;
  while (NULL != chunk) {
    memory_list[i] = chunk->data;
    chunk = chunk->next;
  }

  for (i = 0; i < count; ++i)
    free(memory_list[i]);
  free(memory_list);
}

allocator_t&
allocator_t::singleton(void)
{
  static allocator_t s;
  return s;
}

void*
allocator_t::alloc(size_t size)
{
  assert(size > 0);

  void* ret;

  if (size > MAX_BYTES)
    ret = malloc(size);
  else {
    size_t index = freelist_index(size);
    if (NULL == free_list_[index]) {
      memory_t* new_chunk = alloc_chunk(index);
      chunk_t*  chunk_node;
      if (freelist_index(sizeof(chunk_t)) == index) {
        chunk_node = (chunk_t*)free_list_[index];
        free_list_[index] = free_list_[index]->next;
      }
      else
        chunk_node = (chunk_t*)alloc(sizeof(chunk_t));

      chunk_node->data = new_chunk;
      chunk_node->next = chunk_list_;
      chunk_list_ = chunk_node;
    }

    ret = free_list_[index];
    free_list_[index] = free_list_[index]->next;
  }

  return ret;
}

void
allocator_t::dealloc(void* ptr, size_t size)
{
  assert(NULL != ptr && size > 0);

  size_t index = freelist_index(size);
  memory_t* free_block = (memory_t*)ptr;
  free_block->next = free_list_[index];
  free_list_[index] = free_block;
}
<|endoftext|>


<commit_before>// The Art of C++ / Utility
// Copyright (c) 2016 Daniel Frey

#ifndef TAOCPP_INCLUDE_UTILITY_POOL_HPP
#define TAOCPP_INCLUDE_UTILITY_POOL_HPP

#include <list>
#include <memory>
#include <mutex>
#include <cassert>

namespace tao
{
  namespace utility
  {
    template< typename T >
    class pool
      : public std::enable_shared_from_this< pool< T > >
    {
    private:
      std::list< std::shared_ptr< T > > items_;
      std::mutex mutex_;

      struct deleter
      {
        std::weak_ptr< pool > pool_;

        deleter() noexcept = default;

        explicit deleter( const std::shared_ptr< pool >& p ) noexcept
          : pool_( p )
        {
        }

        void operator()( T* item ) const
        {
          std::unique_ptr< T > up( item );
          if( const std::shared_ptr< pool > p = pool_.lock() ) {
            p->push( up );
          }
        }
      };

    protected:
      pool() = default;
      virtual ~pool() = default;

      // create a new T
      virtual std::unique_ptr< T > v_create() const = 0;
      virtual bool v_is_valid( T& ) const { return true; }

      virtual void v_push_before( T& ) const noexcept {}
      virtual void v_push_success( T& ) const noexcept {}
      virtual void v_push_failure( T& ) const noexcept {}

      virtual void v_pull_before( T& ) const noexcept {}
      virtual void v_pull_success( T& ) const noexcept {}
      virtual void v_pull_failure( T& ) const noexcept {}

      void push( std::unique_ptr< T >& up )
      {
        v_push_before( *up );
        if( v_is_valid( *up ) ) {
          std::shared_ptr< T > sp( up.release(), deleter() );
          v_push_success( *sp );
          const std::lock_guard< std::mutex > lock( mutex_ );
          items_.push_back( std::move( sp ) );
        }
        else {
          v_push_failure( *up );
        }
      }

      std::shared_ptr< T > pull() noexcept
      {
        std::shared_ptr< T > nrv;
        const std::lock_guard< std::mutex > lock( mutex_ );
        if( !items_.empty() ) {
          items_.back().swap( nrv );
          items_.pop_back();
        }
        return nrv;
      }

    public:
      pool( const pool& ) = delete;
      void operator=( const pool& ) = delete;

      static void attach( const std::shared_ptr< T >& sp, const std::shared_ptr< pool >& p ) noexcept
      {
        deleter* d = std::get_deleter< deleter >( sp );
        assert( d );
        d->pool_ = p;
      }

      static void detach( const std::shared_ptr< T >& sp ) noexcept
      {
        deleter* d = std::get_deleter< deleter >( sp );
        assert( d );
        d->pool_.reset();
      }

      // create a new T which is put into the pool when no longer used
      std::shared_ptr< T > create()
      {
        return std::shared_ptr< T >( v_create().release(), deleter( this->shared_from_this() ) );
      }

      // get an instance from the pool or create a new one if necessary
      std::shared_ptr< T > get()
      {
        while( const std::shared_ptr< T > sp = pull() ) {
          v_pull_before( *sp );
          if( v_is_valid( *sp ) ) {
            attach( sp, this->shared_from_this() );
            v_pull_success( *sp );
            return sp;
          }
          else {
            v_pull_failure( *sp );
          }
        }
        return create();
      }

      void erase_invalid()
      {
        std::list< std::shared_ptr< T > > deferred_delete;
        const std::lock_guard< std::mutex > lock( mutex_ );
        auto it = items_.begin();
        while( it != items_.end() ) {
          if( !v_is_valid( **it ) ) {
            deferred_delete.push_back( *it );
            it = items_.erase( it );
          }
          else {
            ++it;
          }
        }
      }
    };
  }
}

#endif // TAOCPP_INCLUDE_UTILITY_POOL_HPP
<commit_msg>Simplify<commit_after>// The Art of C++ / Utility
// Copyright (c) 2016 Daniel Frey

#ifndef TAOCPP_INCLUDE_UTILITY_POOL_HPP
#define TAOCPP_INCLUDE_UTILITY_POOL_HPP

#include <list>
#include <memory>
#include <mutex>
#include <cassert>

namespace tao
{
  namespace utility
  {
    template< typename T >
    class pool
      : public std::enable_shared_from_this< pool< T > >
    {
    private:
      std::list< std::shared_ptr< T > > items_;
      std::mutex mutex_;

      struct deleter
      {
        std::weak_ptr< pool > pool_;

        deleter() noexcept = default;

        explicit deleter( const std::shared_ptr< pool >& p ) noexcept
          : pool_( p )
        {
        }

        void operator()( T* item ) const
        {
          std::unique_ptr< T > up( item );
          if( const auto p = pool_.lock() ) {
            p->push( up );
          }
        }
      };

    protected:
      pool() = default;
      virtual ~pool() = default;

      // create a new T
      virtual std::unique_ptr< T > v_create() const = 0;
      virtual bool v_is_valid( T& ) const { return true; }

      virtual void v_push_before( T& ) const noexcept {}
      virtual void v_push_success( T& ) const noexcept {}
      virtual void v_push_failure( T& ) const noexcept {}

      virtual void v_pull_before( T& ) const noexcept {}
      virtual void v_pull_success( T& ) const noexcept {}
      virtual void v_pull_failure( T& ) const noexcept {}

      void push( std::unique_ptr< T >& up )
      {
        v_push_before( *up );
        if( v_is_valid( *up ) ) {
          std::shared_ptr< T > sp( up.release(), deleter() );
          v_push_success( *sp );
          const std::lock_guard< std::mutex > lock( mutex_ );
          items_.push_back( std::move( sp ) );
        }
        else {
          v_push_failure( *up );
        }
      }

      std::shared_ptr< T > pull() noexcept
      {
        std::shared_ptr< T > nrv;
        const std::lock_guard< std::mutex > lock( mutex_ );
        if( !items_.empty() ) {
          items_.back().swap( nrv );
          items_.pop_back();
        }
        return nrv;
      }

    public:
      pool( const pool& ) = delete;
      void operator=( const pool& ) = delete;

      static void attach( const std::shared_ptr< T >& sp, const std::shared_ptr< pool >& p ) noexcept
      {
        deleter* d = std::get_deleter< deleter >( sp );
        assert( d );
        d->pool_ = p;
      }

      static void detach( const std::shared_ptr< T >& sp ) noexcept
      {
        deleter* d = std::get_deleter< deleter >( sp );
        assert( d );
        d->pool_.reset();
      }

      // create a new T which is put into the pool when no longer used
      std::shared_ptr< T > create()
      {
        return { v_create().release(), deleter( this->shared_from_this() ) };
      }

      // get an instance from the pool or create a new one if necessary
      std::shared_ptr< T > get()
      {
        while( const auto sp = pull() ) {
          v_pull_before( *sp );
          if( v_is_valid( *sp ) ) {
            attach( sp, this->shared_from_this() );
            v_pull_success( *sp );
            return sp;
          }
          else {
            v_pull_failure( *sp );
          }
        }
        return create();
      }

      void erase_invalid()
      {
        std::list< std::shared_ptr< T > > deferred_delete;
        const std::lock_guard< std::mutex > lock( mutex_ );
        auto it = items_.begin();
        while( it != items_.end() ) {
          if( !v_is_valid( **it ) ) {
            deferred_delete.push_back( *it );
            it = items_.erase( it );
          }
          else {
            ++it;
          }
        }
      }
    };
  }
}

#endif // TAOCPP_INCLUDE_UTILITY_POOL_HPP
<|endoftext|>


<commit_before>#include "config.h"

Config* Config::getHandle() {
	static Config instance;
	return &instance;
}

void Config::setMainConfigFile(const std::string& configFileName) {
	if (confname.empty())
		confname = configFileName;
}

void Config::readConfig() {
	config = readConfig(confname, std::ifstream(confname));
	for (auto callback : notifyList)
		callback();
}

enum ConfigState { CONFIG_BLOCK, CONFIG_KEY, CONFIG_VALUE, CONFIG_VALUE_NEXT, CONFIG_VALUE_VAR, CONFIG_VALUE_STR, CONFIG_VALUE_STR_ESCAPED };
// This enum is simply an implementation detail for the configuration parser; hence it is placed here instead of the header file.

std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> Config::readConfig(const std::string& filename, std::istream&& configData) {
	ConfigState state = CONFIG_BLOCK;
	unsigned int lineNum = 1;
	LogManager* logger = LogManager::getHandle();
	std::string blockName, key, value, valueVar;
	std::unordered_map<std::string, std::string> blockValues;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> localConfig;
	while (configData.good()) {
		char nextChar = configData.get();
		if (nextChar == std::istream::traits_type::eof())
			break;
		if (nextChar == '\n')
			lineNum++;
		if (state == CONFIG_BLOCK) {
			if (nextChar == '{') {
				if (blockName.empty())
					throw ConfigError (filename, lineNum, "A block without a name was opened.");
				state = CONFIG_KEY;
			} else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A closing brace could not be mached to an open block.");
			else if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				blockName += nextChar;
		} else if (state == CONFIG_KEY) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}') {
				if (blockValues.empty())
					throw ConfigError (filename, lineNum, "An empty block was defined.  What was the point of that?");
				if (!key.empty() || !value.empty())
					throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
				localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (blockName, blockValues));
				blockName.clear();
				blockValues.clear();
				logger->log(LOG_ALL, "config", "Block " + blockName + " read.");
				state = CONFIG_BLOCK;
			} else if (nextChar == ';')
				throw ConfigError (filename, lineNum, "A key was specified without a value.");
			else if (nextChar == '=')
				state = CONFIG_VALUE_NEXT;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				key += nextChar;
		} else if (state == CONFIG_VALUE) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == ';') {
				blockValues.insert(std::pair<std::string, std::string> (key, value));
				key.clear();
				value.clear();
				state = CONFIG_KEY;
			} else if (nextChar == '+')
				state = CONFIG_VALUE_NEXT;
			else
				throw ConfigError (filename, lineNum, "An unexpected character was encountered; expected ';' or '+' (perhaps you forgot to end or properly concatenate your value?).");
		} else if (state == CONFIG_VALUE_NEXT) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '"')
				state = CONFIG_VALUE_STR;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n') {
				valueVar += nextChar;
				state = CONFIG_VALUE_VAR;
			}
		} else if (state == CONFIG_VALUE_VAR) {
			if (nextChar == '"')
				throw ConfigError (filename, lineNum, "A string value was specified in the middle of a variable (perhaps you forgot to properly concatenate with '+'?).");
			else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
			else if (nextChar == ' ' || nextChar == '\t' || nextChar == '\r' || nextChar == '\n' || nextChar == '+' || nextChar == ';') {
				auto keyIter = blockValues.find(valueVar);
				if (keyIter == blockValues.end())
					throw ConfigError (filename, lineNum, "The variable " + valueVar + " was specified, but did not match a variable already specified in the block.");
				value += keyIter->second;
				valueVar.clear();
				if (nextChar == ';') {
					state = CONFIG_KEY;
					blockValues.insert(std::pair<std::string, std::string> (key, value));
					key.clear();
					value.clear();
				} else if (nextChar == '+')
					state = CONFIG_VALUE_NEXT;
				else
					state = CONFIG_VALUE;
			} else
				valueVar += nextChar;
		} else if (state == CONFIG_VALUE_STR) {
			if (nextChar == '\\')
				state = CONFIG_VALUE_STR_ESCAPED;
			else if (nextChar == '"')
				state = CONFIG_VALUE;
			else
				value += nextChar;
		} else if (state == CONFIG_VALUE_STR_ESCAPED) {
			if (nextChar == '\\')
				value += '\\';
			else if (nextChar == 'n')
				value += '\n';
			else if (nextChar == 't')
				value += '\t';
			else if (nextChar == 'r')
				value += '\r';
			else
				value += nextChar;
			state = CONFIG_VALUE_STR;
		}
	}
	if (!blockValues.empty())
		throw ConfigError (filename, lineNum, "A block remained unterminated at the end of the file.");
	std::list<std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>> includedConfigs;
	for (auto block : localConfig) {
		if (block.first == "include") {
			auto inclfIter = block.second.find("file");
			if (inclfIter != block.second.end()) {
				std::string name = inclfIter->second;
				logger->log(LOG_ALL, "config", "Reading included file " + inclfIter->second);
				includedConfigs.push_back(readConfig(inclfIter->second, std::ifstream(name)));
			} else {
				auto incleIter = block.second.find("executable");
				if (incleIter != block.second.end()) {
					std::string cmd = incleIter->second;
					logger->log(LOG_ALL, "config", "Getting configuration data from `" + incleIter->second + "`");
					FILE* pipe = popen(cmd.c_str(), "r");
					if (!pipe)
						raise ConfigError (cmd, 0, "Could not open pipe to read output.");
					char buffer[256];
					std::stringstream output;
					while (!feof(pipe)) {
						if (fgets(buffer, 256, pipe) != NULL)
							output << buffer;
					}
					pclose(pipe);
					includedConfigs.push_back(readConfig(cmd, output));
				} else
					throw ConfigError (filename, lineNum, "An include block was present that contained neither a file nor an executable.");
			}
		}
	}
	for (auto includes : includedConfigs) {
		for (auto conf : includes.second)
			localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (conf));
	}
	return localConfig;
}

void Config::addRehashNotify(std::function<void()> notifyCallback) {
	notifyList.push_back(notifyCallback);
}

size_t Config::blockCount(const std::string& block) const {
	return config.count(block);
}

std::list<std::unordered_map<std::string, std::string>> Config::getBlock(const std::string& block) const {
	std::list<std::unordered_map<std::string, std::string>> blockList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter)
		blockList.push_back(startIter->second);
	return blockList;
}

std::unordered_map<std::string, std::string> Config::getSingleBlock(const std::string& block, const std::unordered_map<std::string, std::string>& conditions) const {
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		for (auto check : conditions) {
			auto blockIter = startIter->second.find(check.first);
			if (blockIter == startIter->second.end())
				continue;
			if (check.second == blockIter->second)
				return startIter->second;
		}
	}
	return std::unordered_map<std::string, std::string> ();
}

std::string Config::getValue(const std::string& block, const std::string& key) const {
	auto blockIter = config.find(block);
	if (blockIter == config.end())
		return "";
	auto dataIter = blockIter->second.find(key);
	if (dataIter == blockIter->second.end())
		return "";
	return dataIter->second;
}

bool Config::getBoolValue(const std::string& block, const std::string& key) const {
	const std::string& value = getValue(block, key);
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

std::list<std::string> Config::getAllValues(const std::string& block, const std::string& key) const {
	std::list<std::string> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back("");
		else
			valueList.push_back(dataIter->second);
	}
	return valueList;
}

std::list<bool> Config::getAllBoolValues(const std::string& block, const std::string& key) const {
	std::list<bool> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (std::string lowerValue; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back(false);
		else {
			lowerValue.clear();
			std::transform(dataIter->second.begin(), dataIter->second.end(), std::back_inserter(lowerValue), ::tolower);
			if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
				valueList.push_back(true);
			else
				valueList.push_back(false);
		}
	}
	return valueList;
}

static bool Config::makeBool(const std::string& value) {
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

Config::Config() {}

ConfigError::ConfigError(const std::string& filename, unsigned int lineNum, const std::string& description) {
	std::ostringstream descStr;
	descStr << "An error occurred reading the configuration from '" << filename << "' on line " << lineNum << ": " << description;
	desc = descStr.str();
}<commit_msg>I got Python in my C++.<commit_after>#include "config.h"

Config* Config::getHandle() {
	static Config instance;
	return &instance;
}

void Config::setMainConfigFile(const std::string& configFileName) {
	if (confname.empty())
		confname = configFileName;
}

void Config::readConfig() {
	config = readConfig(confname, std::ifstream(confname));
	for (auto callback : notifyList)
		callback();
}

enum ConfigState { CONFIG_BLOCK, CONFIG_KEY, CONFIG_VALUE, CONFIG_VALUE_NEXT, CONFIG_VALUE_VAR, CONFIG_VALUE_STR, CONFIG_VALUE_STR_ESCAPED };
// This enum is simply an implementation detail for the configuration parser; hence it is placed here instead of the header file.

std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> Config::readConfig(const std::string& filename, std::istream&& configData) {
	ConfigState state = CONFIG_BLOCK;
	unsigned int lineNum = 1;
	LogManager* logger = LogManager::getHandle();
	std::string blockName, key, value, valueVar;
	std::unordered_map<std::string, std::string> blockValues;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> localConfig;
	while (configData.good()) {
		char nextChar = configData.get();
		if (nextChar == std::istream::traits_type::eof())
			break;
		if (nextChar == '\n')
			lineNum++;
		if (state == CONFIG_BLOCK) {
			if (nextChar == '{') {
				if (blockName.empty())
					throw ConfigError (filename, lineNum, "A block without a name was opened.");
				state = CONFIG_KEY;
			} else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A closing brace could not be mached to an open block.");
			else if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				blockName += nextChar;
		} else if (state == CONFIG_KEY) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}') {
				if (blockValues.empty())
					throw ConfigError (filename, lineNum, "An empty block was defined.  What was the point of that?");
				if (!key.empty() || !value.empty())
					throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
				localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (blockName, blockValues));
				blockName.clear();
				blockValues.clear();
				logger->log(LOG_ALL, "config", "Block " + blockName + " read.");
				state = CONFIG_BLOCK;
			} else if (nextChar == ';')
				throw ConfigError (filename, lineNum, "A key was specified without a value.");
			else if (nextChar == '=')
				state = CONFIG_VALUE_NEXT;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				key += nextChar;
		} else if (state == CONFIG_VALUE) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == ';') {
				blockValues.insert(std::pair<std::string, std::string> (key, value));
				key.clear();
				value.clear();
				state = CONFIG_KEY;
			} else if (nextChar == '+')
				state = CONFIG_VALUE_NEXT;
			else
				throw ConfigError (filename, lineNum, "An unexpected character was encountered; expected ';' or '+' (perhaps you forgot to end or properly concatenate your value?).");
		} else if (state == CONFIG_VALUE_NEXT) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '"')
				state = CONFIG_VALUE_STR;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n') {
				valueVar += nextChar;
				state = CONFIG_VALUE_VAR;
			}
		} else if (state == CONFIG_VALUE_VAR) {
			if (nextChar == '"')
				throw ConfigError (filename, lineNum, "A string value was specified in the middle of a variable (perhaps you forgot to properly concatenate with '+'?).");
			else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
			else if (nextChar == ' ' || nextChar == '\t' || nextChar == '\r' || nextChar == '\n' || nextChar == '+' || nextChar == ';') {
				auto keyIter = blockValues.find(valueVar);
				if (keyIter == blockValues.end())
					throw ConfigError (filename, lineNum, "The variable " + valueVar + " was specified, but did not match a variable already specified in the block.");
				value += keyIter->second;
				valueVar.clear();
				if (nextChar == ';') {
					state = CONFIG_KEY;
					blockValues.insert(std::pair<std::string, std::string> (key, value));
					key.clear();
					value.clear();
				} else if (nextChar == '+')
					state = CONFIG_VALUE_NEXT;
				else
					state = CONFIG_VALUE;
			} else
				valueVar += nextChar;
		} else if (state == CONFIG_VALUE_STR) {
			if (nextChar == '\\')
				state = CONFIG_VALUE_STR_ESCAPED;
			else if (nextChar == '"')
				state = CONFIG_VALUE;
			else
				value += nextChar;
		} else if (state == CONFIG_VALUE_STR_ESCAPED) {
			if (nextChar == '\\')
				value += '\\';
			else if (nextChar == 'n')
				value += '\n';
			else if (nextChar == 't')
				value += '\t';
			else if (nextChar == 'r')
				value += '\r';
			else
				value += nextChar;
			state = CONFIG_VALUE_STR;
		}
	}
	if (!blockValues.empty())
		throw ConfigError (filename, lineNum, "A block remained unterminated at the end of the file.");
	std::list<std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>> includedConfigs;
	for (auto block : localConfig) {
		if (block.first == "include") {
			auto inclfIter = block.second.find("file");
			if (inclfIter != block.second.end()) {
				std::string name = inclfIter->second;
				logger->log(LOG_ALL, "config", "Reading included file " + inclfIter->second);
				includedConfigs.push_back(readConfig(inclfIter->second, std::ifstream(name)));
			} else {
				auto incleIter = block.second.find("executable");
				if (incleIter != block.second.end()) {
					std::string cmd = incleIter->second;
					logger->log(LOG_ALL, "config", "Getting configuration data from `" + incleIter->second + "`");
					FILE* pipe = popen(cmd.c_str(), "r");
					if (!pipe)
						throw ConfigError (cmd, 0, "Could not open pipe to read output.");
					char buffer[256];
					std::stringstream output;
					while (!feof(pipe)) {
						if (fgets(buffer, 256, pipe) != NULL)
							output << buffer;
					}
					pclose(pipe);
					includedConfigs.push_back(readConfig(cmd, output));
				} else
					throw ConfigError (filename, lineNum, "An include block was present that contained neither a file nor an executable.");
			}
		}
	}
	for (auto includes : includedConfigs) {
		for (auto conf : includes.second)
			localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (conf));
	}
	return localConfig;
}

void Config::addRehashNotify(std::function<void()> notifyCallback) {
	notifyList.push_back(notifyCallback);
}

size_t Config::blockCount(const std::string& block) const {
	return config.count(block);
}

std::list<std::unordered_map<std::string, std::string>> Config::getBlock(const std::string& block) const {
	std::list<std::unordered_map<std::string, std::string>> blockList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter)
		blockList.push_back(startIter->second);
	return blockList;
}

std::unordered_map<std::string, std::string> Config::getSingleBlock(const std::string& block, const std::unordered_map<std::string, std::string>& conditions) const {
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		for (auto check : conditions) {
			auto blockIter = startIter->second.find(check.first);
			if (blockIter == startIter->second.end())
				continue;
			if (check.second == blockIter->second)
				return startIter->second;
		}
	}
	return std::unordered_map<std::string, std::string> ();
}

std::string Config::getValue(const std::string& block, const std::string& key) const {
	auto blockIter = config.find(block);
	if (blockIter == config.end())
		return "";
	auto dataIter = blockIter->second.find(key);
	if (dataIter == blockIter->second.end())
		return "";
	return dataIter->second;
}

bool Config::getBoolValue(const std::string& block, const std::string& key) const {
	const std::string& value = getValue(block, key);
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

std::list<std::string> Config::getAllValues(const std::string& block, const std::string& key) const {
	std::list<std::string> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back("");
		else
			valueList.push_back(dataIter->second);
	}
	return valueList;
}

std::list<bool> Config::getAllBoolValues(const std::string& block, const std::string& key) const {
	std::list<bool> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (std::string lowerValue; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back(false);
		else {
			lowerValue.clear();
			std::transform(dataIter->second.begin(), dataIter->second.end(), std::back_inserter(lowerValue), ::tolower);
			if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
				valueList.push_back(true);
			else
				valueList.push_back(false);
		}
	}
	return valueList;
}

static bool Config::makeBool(const std::string& value) {
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

Config::Config() {}

ConfigError::ConfigError(const std::string& filename, unsigned int lineNum, const std::string& description) {
	std::ostringstream descStr;
	descStr << "An error occurred reading the configuration from '" << filename << "' on line " << lineNum << ": " << description;
	desc = descStr.str();
}<|endoftext|>


<commit_before>/**
 * @file lldockcontrol.cpp
 * @brief Creates a panel of a specific kind for a toast
 *
 * $LicenseInfo:firstyear=2000&license=viewergpl$
 *
 * Copyright (c) 2000-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "lldockcontrol.h"
#include "lldockablefloater.h"

LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
		const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) :
		mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue)
{
	mDockAt = dockAt;

	if (dockableFloater->isDocked())
	{
		on();
	}
	else
	{
		off();
	}

	if (!(get_allowed_rect_callback))
	{
		mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1);
	}
	else
	{
		mGetAllowedRectCallback = get_allowed_rect_callback;
	}

	if (dockWidget != NULL)
	{
		repositionDockable();
	}

	if (mDockWidget != NULL)
	{
		mDockWidgetVisible = isDockVisible();
	}
	else
	{
		mDockWidgetVisible = false;
	}
}

LLDockControl::~LLDockControl()
{
}

void LLDockControl::setDock(LLView* dockWidget)
{
	mDockWidget = dockWidget;
	if (mDockWidget != NULL)
	{
		repositionDockable();
		mDockWidgetVisible = isDockVisible();
	}
	else
	{
		mDockWidgetVisible = false;
	}
}

void LLDockControl::getAllowedRect(LLRect& rect)
{
	rect = mDockableFloater->getRootView()->getRect();
}

void LLDockControl::repositionDockable()
{
	LLRect dockRect = mDockWidget->calcScreenRect();
	LLRect rootRect;
	mGetAllowedRectCallback(rootRect);

	// recalculate dockable position if dock position changed, dock visibility changed,
	// root view rect changed or recalculation is forced
	if (mPrevDockRect != dockRect  || mDockWidgetVisible != isDockVisible()
			|| mRootRect != rootRect || mRecalculateDocablePosition)
	{
		// undock dockable and off() if dock not visible
		if (!isDockVisible())
		{
			mDockableFloater->setDocked(false);
			// force off() since dockable may not have dockControll at this time
			off();
			LLDockableFloater* dockable_floater =
					dynamic_cast<LLDockableFloater*> (mDockableFloater);
			if(dockable_floater != NULL)
			{
				dockable_floater->onDockHidden();
			}
		}
		else
		{
			if(mEnabled)
			{
				moveDockable();
			}
			LLDockableFloater* dockable_floater =
					dynamic_cast<LLDockableFloater*> (mDockableFloater);
			if(dockable_floater != NULL)
			{
				dockable_floater->onDockShown();
			}
		}

		mPrevDockRect = dockRect;
		mRootRect = rootRect;
		mRecalculateDocablePosition = false;
		mDockWidgetVisible = isDockVisible();
	}
}

bool LLDockControl::isDockVisible()
{
	bool res = true;

	if (mDockWidget != NULL)
	{
		//we should check all hierarchy
		res = mDockWidget->isInVisibleChain();
		if (res)
		{
			LLRect dockRect = mDockWidget->calcScreenRect();

			switch (mDockAt)
			{
			case LEFT: // to keep compiler happy
				break;
			case TOP:
				// check is dock inside parent rect
				LLRect dockParentRect =
						mDockWidget->getParent()->calcScreenRect();
				if (dockRect.mRight <= dockParentRect.mLeft
						|| dockRect.mLeft >= dockParentRect.mRight)
				{
					res = false;
				}
				break;
			}
		}
	}

	return res;
}

void LLDockControl::moveDockable()
{
	// calculate new dockable position
	LLRect dockRect = mDockWidget->calcScreenRect();
	LLRect rootRect;
	mGetAllowedRectCallback(rootRect);

	LLRect dockableRect = mDockableFloater->calcScreenRect();
	S32 x = 0;
	S32 y = 0;
	LLRect dockParentRect;
	switch (mDockAt)
	{
	case LEFT:
		x = dockRect.mLeft;
		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
		// check is dockable inside root view rect
		if (x < rootRect.mLeft)
		{
			x = rootRect.mLeft;
		}
		if (x + dockableRect.getWidth() > rootRect.mRight)
		{
			x = rootRect.mRight - dockableRect.getWidth();
		}

		mDockTongueX = x + dockableRect.getWidth()/2 - mDockTongue->getWidth() / 2;

		mDockTongueY = dockRect.mTop;
		break;

	case TOP:
		x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
		// check is dockable inside root view rect
		if (x < rootRect.mLeft)
		{
			x = rootRect.mLeft;
		}
		if (x + dockableRect.getWidth() > rootRect.mRight)
		{
			x = rootRect.mRight - dockableRect.getWidth();
		}

		// calculate dock tongue position
		dockParentRect = mDockWidget->getParent()->calcScreenRect();
		if (dockRect.getCenterX() < dockParentRect.mLeft)
		{
			mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
		}
		else if (dockRect.getCenterX() > dockParentRect.mRight)
		{
			mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;;
		}
		else
		{
			mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2;
		}
		mDockTongueY = dockRect.mTop;

		break;
	}

	// move dockable
	dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
			dockableRect.getHeight());
	LLRect localDocableParentRect;
	mDockableFloater->getParent()->screenRectToLocal(dockableRect,
			&localDocableParentRect);
	mDockableFloater->setRect(localDocableParentRect);

	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY,
			&mDockTongueX, &mDockTongueY);

}

void LLDockControl::on()
{
	 if (isDockVisible())
	{
		mDockableFloater->setCanDrag(false);
		mEnabled = true;
		mRecalculateDocablePosition = true;
	}
}

void LLDockControl::off()
{
	mDockableFloater->setCanDrag(true);
	mEnabled = false;
}

void LLDockControl::drawToungue()
{
	if (mEnabled)
	{
		mDockTongue->draw(mDockTongueX, mDockTongueY);
	}
}

<commit_msg>fixed EXT-2353 "IM window should auto-undock when dragged" made all dockable floaters undock on dragging;<commit_after>/**
 * @file lldockcontrol.cpp
 * @brief Creates a panel of a specific kind for a toast
 *
 * $LicenseInfo:firstyear=2000&license=viewergpl$
 *
 * Copyright (c) 2000-2009, Linden Research, Inc.
 *
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 *
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at
 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 *
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 *
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "lldockcontrol.h"
#include "lldockablefloater.h"

LLDockControl::LLDockControl(LLView* dockWidget, LLFloater* dockableFloater,
		const LLUIImagePtr& dockTongue, DocAt dockAt, get_allowed_rect_callback_t get_allowed_rect_callback) :
		mDockWidget(dockWidget), mDockableFloater(dockableFloater), mDockTongue(dockTongue)
{
	mDockAt = dockAt;

	if (dockableFloater->isDocked())
	{
		on();
	}
	else
	{
		off();
	}

	if (!(get_allowed_rect_callback))
	{
		mGetAllowedRectCallback = boost::bind(&LLDockControl::getAllowedRect, this, _1);
	}
	else
	{
		mGetAllowedRectCallback = get_allowed_rect_callback;
	}

	if (dockWidget != NULL)
	{
		repositionDockable();
	}

	if (mDockWidget != NULL)
	{
		mDockWidgetVisible = isDockVisible();
	}
	else
	{
		mDockWidgetVisible = false;
	}
}

LLDockControl::~LLDockControl()
{
}

void LLDockControl::setDock(LLView* dockWidget)
{
	mDockWidget = dockWidget;
	if (mDockWidget != NULL)
	{
		repositionDockable();
		mDockWidgetVisible = isDockVisible();
	}
	else
	{
		mDockWidgetVisible = false;
	}
}

void LLDockControl::getAllowedRect(LLRect& rect)
{
	rect = mDockableFloater->getRootView()->getRect();
}

void LLDockControl::repositionDockable()
{
	LLRect dockRect = mDockWidget->calcScreenRect();
	LLRect rootRect;
	mGetAllowedRectCallback(rootRect);

	// recalculate dockable position if dock position changed, dock visibility changed,
	// root view rect changed or recalculation is forced
	if (mPrevDockRect != dockRect  || mDockWidgetVisible != isDockVisible()
			|| mRootRect != rootRect || mRecalculateDocablePosition)
	{
		// undock dockable and off() if dock not visible
		if (!isDockVisible())
		{
			mDockableFloater->setDocked(false);
			// force off() since dockable may not have dockControll at this time
			off();
			LLDockableFloater* dockable_floater =
					dynamic_cast<LLDockableFloater*> (mDockableFloater);
			if(dockable_floater != NULL)
			{
				dockable_floater->onDockHidden();
			}
		}
		else
		{
			if(mEnabled)
			{
				moveDockable();
			}
			LLDockableFloater* dockable_floater =
					dynamic_cast<LLDockableFloater*> (mDockableFloater);
			if(dockable_floater != NULL)
			{
				dockable_floater->onDockShown();
			}
		}

		mPrevDockRect = dockRect;
		mRootRect = rootRect;
		mRecalculateDocablePosition = false;
		mDockWidgetVisible = isDockVisible();
	}
}

bool LLDockControl::isDockVisible()
{
	bool res = true;

	if (mDockWidget != NULL)
	{
		//we should check all hierarchy
		res = mDockWidget->isInVisibleChain();
		if (res)
		{
			LLRect dockRect = mDockWidget->calcScreenRect();

			switch (mDockAt)
			{
			case LEFT: // to keep compiler happy
				break;
			case TOP:
				// check is dock inside parent rect
				LLRect dockParentRect =
						mDockWidget->getParent()->calcScreenRect();
				if (dockRect.mRight <= dockParentRect.mLeft
						|| dockRect.mLeft >= dockParentRect.mRight)
				{
					res = false;
				}
				break;
			}
		}
	}

	return res;
}

void LLDockControl::moveDockable()
{
	// calculate new dockable position
	LLRect dockRect = mDockWidget->calcScreenRect();
	LLRect rootRect;
	mGetAllowedRectCallback(rootRect);

	LLRect dockableRect = mDockableFloater->calcScreenRect();
	S32 x = 0;
	S32 y = 0;
	LLRect dockParentRect;
	switch (mDockAt)
	{
	case LEFT:
		x = dockRect.mLeft;
		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
		// check is dockable inside root view rect
		if (x < rootRect.mLeft)
		{
			x = rootRect.mLeft;
		}
		if (x + dockableRect.getWidth() > rootRect.mRight)
		{
			x = rootRect.mRight - dockableRect.getWidth();
		}

		mDockTongueX = x + dockableRect.getWidth()/2 - mDockTongue->getWidth() / 2;

		mDockTongueY = dockRect.mTop;
		break;

	case TOP:
		x = dockRect.getCenterX() - dockableRect.getWidth() / 2;
		y = dockRect.mTop + mDockTongue->getHeight() + dockableRect.getHeight();
		// check is dockable inside root view rect
		if (x < rootRect.mLeft)
		{
			x = rootRect.mLeft;
		}
		if (x + dockableRect.getWidth() > rootRect.mRight)
		{
			x = rootRect.mRight - dockableRect.getWidth();
		}

		// calculate dock tongue position
		dockParentRect = mDockWidget->getParent()->calcScreenRect();
		if (dockRect.getCenterX() < dockParentRect.mLeft)
		{
			mDockTongueX = dockParentRect.mLeft - mDockTongue->getWidth() / 2;
		}
		else if (dockRect.getCenterX() > dockParentRect.mRight)
		{
			mDockTongueX = dockParentRect.mRight - mDockTongue->getWidth() / 2;;
		}
		else
		{
			mDockTongueX = dockRect.getCenterX() - mDockTongue->getWidth() / 2;
		}
		mDockTongueY = dockRect.mTop;

		break;
	}

	// move dockable
	dockableRect.setLeftTopAndSize(x, y, dockableRect.getWidth(),
			dockableRect.getHeight());
	LLRect localDocableParentRect;
	mDockableFloater->getParent()->screenRectToLocal(dockableRect,
			&localDocableParentRect);
	mDockableFloater->setRect(localDocableParentRect);

	mDockableFloater->screenPointToLocal(mDockTongueX, mDockTongueY,
			&mDockTongueX, &mDockTongueY);

}

void LLDockControl::on()
{
	 if (isDockVisible())
	{
		mEnabled = true;
		mRecalculateDocablePosition = true;
	}
}

void LLDockControl::off()
{
	mEnabled = false;
}

void LLDockControl::drawToungue()
{
	if (mEnabled)
	{
		mDockTongue->draw(mDockTongueX, mDockTongueY);
	}
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-2018 mvs developers
 *
 * This file is part of metaverse-explorer.
 *
 * metaverse-explorer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <metaverse/explorer/json_helper.hpp>
#include <metaverse/explorer/dispatch.hpp>
#include <metaverse/explorer/extensions/commands/swaptoken.hpp>
#include <metaverse/explorer/extensions/command_extension_func.hpp>
#include <metaverse/explorer/extensions/command_assistant.hpp>
#include <metaverse/explorer/extensions/exception.hpp>
#include <metaverse/explorer/extensions/base_helper.hpp>
#include <metaverse/consensus/libdevcore/SHA3.h>
#include <boost/algorithm/string.hpp>
#include <regex>

namespace libbitcoin {
namespace explorer {
namespace commands {

//Check if address is checksum of ETH address
bool is_ETH_Address(const string& address)
{
    // regex checking
    {
        sregex_iterator end;

        // check if it has the basic requirements of an address
        static const regex reg_common("^0x[0-9a-fA-F]{40}$");
        sregex_iterator it(address.begin(), address.end(), reg_common);
        if (it == end) {
            return false;
        }

        // If it's all small caps, return true
        static const regex reg_alllower("^0x[0-9a-f]{40}$");
        sregex_iterator it1(address.begin(), address.end(), reg_alllower);
        if (it1 != end) {
            return true;
        }

        // If it's all caps, return true
        static const regex reg_allupper("^0x[0-9A-F]{40}$");
        sregex_iterator it2(address.begin(), address.end(), reg_allupper);
        if (it2 != end) {
            return true;
        }
    }

    // Otherwise check each case
    auto addr = address.substr(2); // get rid of prefix "0x"
    auto address_hash = bc::sha3(boost::to_lower_copy(addr)).hex();

    for (size_t i = 0; i < addr.size(); ++i) {
        auto c = addr[i];
        if (std::isdigit(c)) {
            continue;
        }
        // the nth letter should be uppercase if the nth digit of casemap is 1 (89abcdef)
        bool is_less_than_8 = (address_hash[i] >= '0' && address_hash[i] < '8');
        if ((is_less_than_8 && !std::islower(c)) ||
            (!is_less_than_8 && !std::isupper(c))) {
            return false;
        }
    }

    return true;
}

console_result swaptoken::invoke(Json::Value& jv_output,
    libbitcoin::server::server_node& node)
{
    auto& blockchain = node.chain_impl();
    blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
    blockchain.uppercase_symbol(argument_.symbol);

    // check message
    if (argument_.foreign_addr.empty() || argument_.foreign_addr.size() >= 255) {
        throw argument_size_invalid_exception{"message length out of bounds."};
    }

    // check ETH address
    if (!is_ETH_Address(argument_.foreign_addr)) {
        throw argument_legality_exception{argument_.foreign_addr + " is not a valid ETH address."};
    }

    // check asset symbol
    check_asset_symbol(argument_.symbol);

    if (argument_.symbol.compare(0, 4, "ERC.") != 0) {
        throw argument_legality_exception{"Only support assets prefixed by 'ERC.'"};
    }

    attachment attach_asset, attach_fee;
    const std::string&& to_address = get_address(argument_.to, attach_asset, false, blockchain);
    const std::string&& swapfee_address = bc::get_developer_community_address(
        blockchain.chain_settings().use_testnet_rules);

    std::string from_address("");
    if (!option_.from.empty()) {
        from_address = get_address(option_.from, attach_asset, true, blockchain);
                       get_address(option_.from, attach_fee, true, blockchain);
    }

    std::string change_address = get_address(option_.change, blockchain);

    if (!argument_.amount) {
        throw argument_legality_exception{"invalid amount parameter!"};
    }
    if (option_.swapfee < DEFAULT_SWAP_FEE) {
        throw argument_legality_exception{"invalid swapfee parameter! must >= 1 ETP"};
    }

    std::vector<receiver_record> receiver{
        {to_address, argument_.symbol, 0, argument_.amount, utxo_attach_type::asset_transfer, attach_asset},
        {swapfee_address, "", option_.swapfee, 0, utxo_attach_type::etp, attach_fee},
    };

    std::string message("{\"type\":\"ETH\",\"address\":\""+ argument_.foreign_addr + "\"}");

    auto send_helper = sending_asset(
        *this, blockchain,
         std::move(auth_.name), std::move(auth_.auth),
         std::move(from_address), std::move(argument_.symbol),
         "",
         std::move(receiver), option_.fee,
         std::move(message), std::move(change_address));

    send_helper.exec();

    // json output
    auto tx = send_helper.get_transaction();
    jv_output =  config::json_helper(get_api_version()).prop_tree(tx, true);

    return console_result::okay;
}

} // namespace commands
} // namespace explorer
} // namespace libbitcoin

<commit_msg>remove check prefix of token name.<commit_after>/**
 * Copyright (c) 2016-2018 mvs developers
 *
 * This file is part of metaverse-explorer.
 *
 * metaverse-explorer is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <metaverse/explorer/json_helper.hpp>
#include <metaverse/explorer/dispatch.hpp>
#include <metaverse/explorer/extensions/commands/swaptoken.hpp>
#include <metaverse/explorer/extensions/command_extension_func.hpp>
#include <metaverse/explorer/extensions/command_assistant.hpp>
#include <metaverse/explorer/extensions/exception.hpp>
#include <metaverse/explorer/extensions/base_helper.hpp>
#include <metaverse/consensus/libdevcore/SHA3.h>
#include <boost/algorithm/string.hpp>
#include <regex>

namespace libbitcoin {
namespace explorer {
namespace commands {

//Check if address is checksum of ETH address
bool is_ETH_Address(const string& address)
{
    // regex checking
    {
        sregex_iterator end;

        // check if it has the basic requirements of an address
        static const regex reg_common("^0x[0-9a-fA-F]{40}$");
        sregex_iterator it(address.begin(), address.end(), reg_common);
        if (it == end) {
            return false;
        }

        // If it's all small caps, return true
        static const regex reg_alllower("^0x[0-9a-f]{40}$");
        sregex_iterator it1(address.begin(), address.end(), reg_alllower);
        if (it1 != end) {
            return true;
        }

        // If it's all caps, return true
        static const regex reg_allupper("^0x[0-9A-F]{40}$");
        sregex_iterator it2(address.begin(), address.end(), reg_allupper);
        if (it2 != end) {
            return true;
        }
    }

    // Otherwise check each case
    auto addr = address.substr(2); // get rid of prefix "0x"
    auto address_hash = bc::sha3(boost::to_lower_copy(addr)).hex();

    for (size_t i = 0; i < addr.size(); ++i) {
        auto c = addr[i];
        if (std::isdigit(c)) {
            continue;
        }
        // the nth letter should be uppercase if the nth digit of casemap is 1 (89abcdef)
        bool is_less_than_8 = (address_hash[i] >= '0' && address_hash[i] < '8');
        if ((is_less_than_8 && !std::islower(c)) ||
            (!is_less_than_8 && !std::isupper(c))) {
            return false;
        }
    }

    return true;
}

console_result swaptoken::invoke(Json::Value& jv_output,
    libbitcoin::server::server_node& node)
{
    auto& blockchain = node.chain_impl();
    blockchain.is_account_passwd_valid(auth_.name, auth_.auth);
    blockchain.uppercase_symbol(argument_.symbol);

    // check message
    if (argument_.foreign_addr.empty() || argument_.foreign_addr.size() >= 255) {
        throw argument_size_invalid_exception{"message length out of bounds."};
    }

    // check ETH address
    if (!is_ETH_Address(argument_.foreign_addr)) {
        throw argument_legality_exception{argument_.foreign_addr + " is not a valid ETH address."};
    }

    // check asset symbol
    check_asset_symbol(argument_.symbol);

    attachment attach_asset, attach_fee;
    const std::string&& to_address = get_address(argument_.to, attach_asset, false, blockchain);
    const std::string&& swapfee_address = bc::get_developer_community_address(
        blockchain.chain_settings().use_testnet_rules);

    std::string from_address("");
    if (!option_.from.empty()) {
        from_address = get_address(option_.from, attach_asset, true, blockchain);
                       get_address(option_.from, attach_fee, true, blockchain);
    }

    std::string change_address = get_address(option_.change, blockchain);

    if (!argument_.amount) {
        throw argument_legality_exception{"invalid amount parameter!"};
    }
    if (option_.swapfee < DEFAULT_SWAP_FEE) {
        throw argument_legality_exception{"invalid swapfee parameter! must >= 1 ETP"};
    }

    std::vector<receiver_record> receiver{
        {to_address, argument_.symbol, 0, argument_.amount, utxo_attach_type::asset_transfer, attach_asset},
        {swapfee_address, "", option_.swapfee, 0, utxo_attach_type::etp, attach_fee},
    };

    std::string message("{\"type\":\"ETH\",\"address\":\""+ argument_.foreign_addr + "\"}");

    auto send_helper = sending_asset(
        *this, blockchain,
         std::move(auth_.name), std::move(auth_.auth),
         std::move(from_address), std::move(argument_.symbol),
         "",
         std::move(receiver), option_.fee,
         std::move(message), std::move(change_address));

    send_helper.exec();

    // json output
    auto tx = send_helper.get_transaction();
    jv_output =  config::json_helper(get_api_version()).prop_tree(tx, true);

    return console_result::okay;
}

} // namespace commands
} // namespace explorer
} // namespace libbitcoin

<|endoftext|>


<commit_before>/*
 *   Copyright (c) 2009, Mathieu Champlon
 *   All rights reserved.
 *
 *   Redistribution  and use  in source  and binary  forms, with  or without
 *   modification, are permitted provided  that the following conditions are
 *   met :
 *
 *   . Redistributions  of  source  code  must  retain  the  above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   . Redistributions in  binary form  must reproduce  the above  copyright
 *     notice, this list of conditions  and the following disclaimer in  the
 *     documentation and/or other materials provided with the distribution.
 *
 *   . Neither  the name  of  the  copyright  holders  nor the names  of the
 *     contributors may be used to endorse  or promote products derived from
 *     this software without specific prior written permission.
 *
 *   THIS SOFTWARE  IS  PROVIDED  BY THE  COPYRIGHT HOLDERS  AND CONTRIBUTORS
 *   ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,  INCLUDING,  BUT NOT
 *   LIMITED TO, THE IMPLIED  WARRANTIES  OF MERCHANTABILITY AND  FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE THE COPYRIGHT
 *   OWNERS OR CONTRIBUTORS  BE LIABLE FOR ANY  DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL   DAMAGES  (INCLUDING,  BUT  NOT
 *   LIMITED TO,  PROCUREMENT OF SUBSTITUTE  GOODS OR SERVICES;  LOSS OF USE,
 *   DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON  ANY
 *   THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT,  STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY  WAY  OUT OF  THE USE
 *   OF THIS SOFTWARE, EVEN  IF  ADVISED OF  THE POSSIBILITY  OF SUCH DAMAGE.
 */

#ifndef xeumeuleu_xostreamstream_hpp
#define xeumeuleu_xostreamstream_hpp

#include <xeumeuleu/streams/xostream.hpp>
#include <xeumeuleu/streams/encoding.hpp>
#include <xeumeuleu/bridges/xerces/document.hpp>
#include <xeumeuleu/bridges/xerces/output.hpp>
#include <algorithm>
#include <ostream>

#ifdef _MSC_VER
#   pragma warning( push )
#   pragma warning( disable: 4355 )
#endif

namespace xml
{
// =============================================================================
/** @class  xostreamstream
    @brief  Xml stream to adapt a standard onput stream
*/
// Created: MCO 2009-11-12
// =============================================================================
class xostreamstream : private document, private flushable, public xostream
{
public:
    //! @name Constructors/Destructor
    //@{
    explicit xostreamstream( std::basic_ostream< char >& stream, const encoding& encoding = encoding() )
        : xostream( output_ )
        , output_  ( *document_, *document_, *this )
        , stream_  ( stream )
        , encoding_( encoding )
        , flushed_ ( false )
    {}
    virtual ~xostreamstream()
    {
        try
        {
            if( ! flushed_ )
                flush();
        }
        catch( ... )
        {
            // NOTHING
        }
    }
    //@}

private:
    //! @name Operations
    //@{
    virtual void flush()
    {
        std::string data;
        fill( data, encoding_ );
        std::copy( data.begin(), data.end(), std::ostreambuf_iterator< char >( stream_ ) );
        flushed_ = true;
    }
    //@}

private:
    //! @name Member data
    //@{
    output output_;
    std::basic_ostream< char >& stream_;
    const std::string encoding_;
    bool flushed_;
    //@}
};

}

#ifdef _MSC_VER
#   pragma warning( pop )
#endif

#endif // xeumeuleu_xostreamstream_hpp
<commit_msg>Fixed typo in comment<commit_after>/*
 *   Copyright (c) 2009, Mathieu Champlon
 *   All rights reserved.
 *
 *   Redistribution  and use  in source  and binary  forms, with  or without
 *   modification, are permitted provided  that the following conditions are
 *   met :
 *
 *   . Redistributions  of  source  code  must  retain  the  above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   . Redistributions in  binary form  must reproduce  the above  copyright
 *     notice, this list of conditions  and the following disclaimer in  the
 *     documentation and/or other materials provided with the distribution.
 *
 *   . Neither  the name  of  the  copyright  holders  nor the names  of the
 *     contributors may be used to endorse  or promote products derived from
 *     this software without specific prior written permission.
 *
 *   THIS SOFTWARE  IS  PROVIDED  BY THE  COPYRIGHT HOLDERS  AND CONTRIBUTORS
 *   ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,  INCLUDING,  BUT NOT
 *   LIMITED TO, THE IMPLIED  WARRANTIES  OF MERCHANTABILITY AND  FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE THE COPYRIGHT
 *   OWNERS OR CONTRIBUTORS  BE LIABLE FOR ANY  DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL   DAMAGES  (INCLUDING,  BUT  NOT
 *   LIMITED TO,  PROCUREMENT OF SUBSTITUTE  GOODS OR SERVICES;  LOSS OF USE,
 *   DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON  ANY
 *   THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT,  STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY  WAY  OUT OF  THE USE
 *   OF THIS SOFTWARE, EVEN  IF  ADVISED OF  THE POSSIBILITY  OF SUCH DAMAGE.
 */

#ifndef xeumeuleu_xostreamstream_hpp
#define xeumeuleu_xostreamstream_hpp

#include <xeumeuleu/streams/xostream.hpp>
#include <xeumeuleu/streams/encoding.hpp>
#include <xeumeuleu/bridges/xerces/document.hpp>
#include <xeumeuleu/bridges/xerces/output.hpp>
#include <algorithm>
#include <ostream>

#ifdef _MSC_VER
#   pragma warning( push )
#   pragma warning( disable: 4355 )
#endif

namespace xml
{
// =============================================================================
/** @class  xostreamstream
    @brief  Xml stream to adapt a standard output stream
*/
// Created: MCO 2009-11-12
// =============================================================================
class xostreamstream : private document, private flushable, public xostream
{
public:
    //! @name Constructors/Destructor
    //@{
    explicit xostreamstream( std::basic_ostream< char >& stream, const encoding& encoding = encoding() )
        : xostream( output_ )
        , output_  ( *document_, *document_, *this )
        , stream_  ( stream )
        , encoding_( encoding )
        , flushed_ ( false )
    {}
    virtual ~xostreamstream()
    {
        try
        {
            if( ! flushed_ )
                flush();
        }
        catch( ... )
        {
            // NOTHING
        }
    }
    //@}

private:
    //! @name Operations
    //@{
    virtual void flush()
    {
        std::string data;
        fill( data, encoding_ );
        std::copy( data.begin(), data.end(), std::ostreambuf_iterator< char >( stream_ ) );
        flushed_ = true;
    }
    //@}

private:
    //! @name Member data
    //@{
    output output_;
    std::basic_ostream< char >& stream_;
    const std::string encoding_;
    bool flushed_;
    //@}
};

}

#ifdef _MSC_VER
#   pragma warning( pop )
#endif

#endif // xeumeuleu_xostreamstream_hpp
<|endoftext|>