<commit_before>/*-
 * Copyright (c) 2012, Achilleas Margaritis
 * Copyright (c) 2014, David T. Chisnall
 * 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.
 *
 * 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.
 */
#ifndef PEGMATITE_AST_HPP
#define PEGMATITE_AST_HPP

#include <cassert>
#include <list>
#include <unordered_map>
#include <memory>
#include "parser.hpp"

namespace pegmatite {

class ASTNode;
template <class T, bool OPT> class ASTPtr;
template <class T> class ASTList;
template <class T> class BindAST;

/** type of AST node stack.
 */
typedef std::vector<std::unique_ptr<ASTNode>> ASTStack;

#ifdef USE_RTTI
#define PARSELIB_RTTI(thisclass, superclass)
#else
/**
 * Define the methods required for pegmatite's lightweight RTTI replacement to
 * work.  This should be used at the end of the class definition and will
 * provide support for safe downcasting.
 */
#define PARSELIB_RTTI(thisclass, superclass)             \
	friend ASTNode;                                      \
protected:                                               \
	virtual char *kind()                                 \
	{                                                    \
		return thisclass::classKind();                   \
	}                                                    \
	static char *classKind()                             \
	{                                                    \
		static char thisclass ## id;                     \
		return &thisclass ## id;                         \
	}                                                    \
public:                                                  \
	virtual bool isa(char *x)                            \
	{                                                    \
		return (x == kind()) ||                          \
				(superclass::isa(x));                    \
	}
#endif

/**
 * Base class for AST nodes.
 */
class ASTNode
{
public:
	/**
	 * Constructs the AST node, with a null parent.
	 */
	ASTNode() : parent_node(0) {}
	/**
	 * Copying AST nodes is not supported.
	 */
	ASTNode(const ASTNode&) = delete;

	/**
	 * Destructor does nothing, virtual for subclasses to use.
	 */
	virtual ~ASTNode() {}

	/**
	 * Returns the parent of this AST node, or `nullptr` if there isn't one
	 * (either if this is the root, or if it is still in the stack waiting to
	 * be added to the tree).
	 */
	ASTNode *parent() const { return parent_node; }

	/**
	 * Interface for constructing the AST node.  The input range `r` is the
	 * range within the source.
	 */
	virtual void construct(const InputRange &r, ASTStack &st) {}

private:
	/**
	 * The parent AST node.
	 */
	ASTNode *parent_node;

	template <class T, bool OPT> friend class ASTPtr;
	template <class T> friend class ASTList;
	template <class T> friend class BindAST;

#ifndef USE_RTTI
protected:
	/**
	 * Returns the kind of object class.  This is a unique pointer that can be
	 * tested against pointers returned by classKind() to determine whether
	 * they can be safely compared.
	 */
	virtual char *kind() { return classKind(); }
	/**
	 * Returns the unique identifier for this class.
	 */
	static char *classKind()
	{
		static char ASTNodeid;
		return &ASTNodeid;
	}
public:
	/**
	 * Root implementation of the RTTI-replacement for builds not wishing to
	 * use RTTI.  This returns true if `x` is the value returned from
	 * `classKind()`, or false otherwise.
	 */
	virtual bool isa(char *x)
	{
		return x == classKind();
	}
	/**
	 * Returns true if this object is an instance of `T`.  Note that this
	 * *only* works with single-inheritance hierarchies.  If you wish to use
	 * multiple inheritance in your AST classes, then you must define
	 * `USE_RTTI` and use the C++ RTTI mechanism.
	 */
	template <class T> bool isa()
	{
		return isa(T::classKind());
	}
	/**
	 * Returns a pointer to this object as a pointer to a child class, or
	 * `nullptr` if the cast would be unsafe.
	 *
	 * Note that AST nodes are intended to be always used as unique pointers
	 * and so the returned object is *only* valid as long as the unique pointer
	 * is valid.
	 */
	template <class T> T* get_as()
	{
		return isa<T>() ? static_cast<T*>(this) : nullptr;
	}
#else
public:
	template <class T> T* get_as()
	{
		return dynamic_cast<T*>(this);
	}
#endif
};

class ASTMember;

/** type of ast member vector.
 */

/**
 * The base class for non-leaf AST nodes.  Subclasses can have instances of
 * `ASTMember` subclasses as fields and will automatically construct them.
 */
class ASTContainer : public ASTNode
{
public:
	/**
	 * Constructs the container, setting a thread-local value to point to it
	 * allowing constructors in fields of the subclass to register themselves
	 * in the members vector.
	 */
	ASTContainer();

	/**
	 * Asks all members to construct themselves from the stack. The members are
	 * asked to construct themselves in reverse order from a node stack (`st`).
	 *
	 * The input range (`r`) is unused, because the leaf nodes have already
	 * constructed themselves at this point.
	 */
	virtual void construct(const InputRange &r, ASTStack &st);

private:
	/**
	 * The type used for tracking the fields of subclasses.
	 */
	typedef std::vector<ASTMember *> ASTMember_vector;
	/**
	 * References to all of the fields of the subclass that will be
	 * automatically constructed.
	 */
	ASTMember_vector members;

	friend class ASTMember;
	PARSELIB_RTTI(ASTContainer, ASTNode)
};

/** Base class for children of ASTContainer.
 */
class ASTMember
{
public:
	/**
	 * On construction, `ASTMember` sets its `container_node` field to the
	 * `ASTContainer` currently under construction and registers itself with
	 * the container, to be notified during the construction phase.
	 */
	ASTMember();

	/**
	 * Returns the container of which this object is a field.
	 */
	ASTContainer *container() const { return container_node; }

	/**
	 * Interface for constructing references to AST objects from the stack.
	 */
	virtual void construct(ASTStack &st) = 0;
private:
	/**
	 * The container that owns this object.
	 */
	ASTContainer *container_node;
};

/**
 * An `ASTPtr` is a wrapper around a pointer to an AST object.  It is intended
 * to be a member of an `ASTContainer` and will automatically pop the top item
 * from the stack and claim it when building the AST..
 */
template <class T, bool OPT = false> class ASTPtr : public ASTMember
{
public:
	/**
	 * Constructs the object in the
	 */
	ASTPtr() : ptr(nullptr) {}

	/** gets the underlying ptr value.
		@return the underlying ptr value.
	 */
	T *get() const
	{
		return ptr.get();
	}

	/** auto conversion to the underlying object ptr.
		@return the underlying ptr value.
	 */
	operator T *() const
	{
		return ptr;
	}

	/** member access.
		@return the underlying ptr value.
	 */
	T *operator ->() const
	{
		assert(ptr);
		return ptr;
	}

	/**
	 * Pops the next matching object from the AST stack `st` and claims it.
	 */
	virtual void construct(ASTStack &st)
	{
		//check the stack node
		//if (st.empty()) throw std::logic_error("empty AST stack");

		//get the node
		ASTNode *node = st.back().get();

		//get the object
		T *obj = node->get_as<T>();

		//if the object is optional, simply return
		if (OPT)
		{
			if (!obj) return;
		}

		//else if the object is mandatory, throw an exception
		else
		{
			//if (!obj) throw std::logic_error("invalid AST node");
		}

		//set the new object
		ptr.reset(obj);
		//pop the node from the stack
		st.back().release();
		st.pop_back();
		_set_parent();
	}

private:
	//ptr
	std::unique_ptr<T> ptr;

	//set parent of object
	void _set_parent()
	{
	}
};

/** A list of objects.
	It pops objects of the given type from the ast stack, until no more objects can be popped.
	It assumes ownership of objects.
	@param T type of object to control.
 */
template <class T> class ASTList : public ASTMember
{
public:
	///list type.
	typedef std::list<std::unique_ptr<T>> container;

	///the default constructor.
	ASTList() {}

	/** duplicates the objects of the given list.
		@param src source object.
	 */
	ASTList(const ASTList<T> &src)
	{
		_dup(src);
	}

	/** returns the container of objects.
		@return the container of objects.
	 */
	const container &objects() const
	{
		return child_objects;
	}

	/**
	 * Pops objects of type T from the stack (`st`) until no more objects can
	 * be popped.
	 */
	virtual void construct(ASTStack &st)
	{
		for(;;)
		{
			//if the stack is empty
			if (st.empty()) break;

			//get the node
			ASTNode *node = st.back().get();

			//get the object
			T *obj = node->get_as<T>();

			//if the object was not not of the appropriate type,
			//end the list parsing
			if (!obj) return;

			//remove the node from the stack
			st.back().release();
			st.pop_back();

			//insert the object in the list, in reverse order
			child_objects.push_front(std::unique_ptr<T>(obj));

			//set the object's parent
			obj->parent_node = ASTMember::container();
		}
	}

private:
	//objects
	container child_objects;

	//duplicate the given list.
	void _dup(const ASTList<T> &src)
	{
		for (auto child : src.child_objects)
		{
			T *obj = new T(child.get());
			child_objects.push_back(obj);
			obj->parent_node = ASTMember::container();
		}
	}
};

/** parses the given input.
	@param i input.
	@param g root rule of grammar.
	@param ws whitespace rule.
	@param el list of errors.
	@param d user data, passed to the parse procedures.
	@return pointer to ast node created, or null if there was an error.
		The return object must be deleted by the caller.
 */
std::unique_ptr<ASTNode> parse(Input &i, Rule &g, Rule &ws, ErrorList &el,
                               const ParserDelegate &d);

/**
 * A parser delegate that is responsible for creating AST nodes from the input.
 *
 * This class manages a mapping from rules in some grammar to AST nodes.
 * Instances of the `BindAST` class that are fields of a subclass of this will
 * automatically register rules on creation.
 *
 * The recommended use for this class is to only register rules on construction
 * (either explicitly in the constructor or implicitly via `BindAST` members).
 * This will give a completely reentrant delegate, which can be used by
 * multiple threads to parse multiple inputs safely.
 */
class ASTParserDelegate : ParserDelegate
{
	/**
	 * BindAST is a friend so that it can call the `set_parse_proc()` function,
	 * which should never be called from anything else.
	 */
	template <class T> friend class BindAST;
	private:
	/**
	 * The map from rules to parsing handlers.
	 */
	std::unordered_map<Rule*, parse_proc> handlers;
	/**
	 * Registers a callback in this delegate.  This should only be called from
	 * the `static` version of this function.
	 */
	void set_parse_proc(Rule &r, parse_proc p);
	/**
	 * Registers a callback for a specific rule in the instance of this class
	 * currently under construction in this thread.  This should only ever be
	 * called by `BindAST` instances.
	 */
	static void bind_parse_proc(Rule &r, parse_proc p);
	public:
	/**
	 * Default constructor, registers this class in thread-local storage so
	 * that it can be referenced by BindAST fields in subclasses when their
	 * constructors are run.
	 */
	ASTParserDelegate();
	virtual parse_proc get_parse_proc(Rule &) const;
	/**
	 * Parse an input `i`, starting from rule `g` in the grammar for which
	 * this is a delegate.  The rule `ws` is used as whitespace.  Errors are
	 * returned via the `el` parameter and the root of the AST via the `ast`
	 * parameter.
	 *
	 * This function returns true on a successful parse, or false otherwise.
	 */
	template <class T> bool parse(Input &i, Rule &g, Rule &ws, ErrorList &el,
	                              std::unique_ptr<T> &ast) const
	{
		std::unique_ptr<ASTNode> node = pegmatite::parse(i, g, ws, el, *this);
		T *n = node->get_as<T>();
		if (n)
		{
			node.release();
			ast.reset(n);
			return true;
		}
		return false;
	}
};

/**
 * The `BindAST` class is responsible for
 */
template <class T> class BindAST
{
public:
	/**
	 * Bind the AST class described in the
	 */
	BindAST(Rule &r)
	{
		ASTParserDelegate::bind_parse_proc(r, [](const ParserPosition &b,
		                                         const ParserPosition &e, void *d)
			{
				ASTStack *st = reinterpret_cast<ASTStack *>(d);
				T *obj = new T();
				obj->construct(InputRange(b, e), *st);
				st->push_back(std::unique_ptr<ASTNode>(obj));
			});
	}
};

} //namespace pegmatite

#endif //PEGMATITE_AST_HPP
<commit_msg>Correctly set the parent from AST pointers.<commit_after>/*-
 * Copyright (c) 2012, Achilleas Margaritis
 * Copyright (c) 2014, David T. Chisnall
 * 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.
 *
 * 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.
 */
#ifndef PEGMATITE_AST_HPP
#define PEGMATITE_AST_HPP

#include <cassert>
#include <list>
#include <unordered_map>
#include <memory>
#include "parser.hpp"

namespace pegmatite {

class ASTNode;
template <class T, bool OPT> class ASTPtr;
template <class T> class ASTList;
template <class T> class BindAST;

/** type of AST node stack.
 */
typedef std::vector<std::unique_ptr<ASTNode>> ASTStack;

#ifdef USE_RTTI
#define PARSELIB_RTTI(thisclass, superclass)
#else
/**
 * Define the methods required for pegmatite's lightweight RTTI replacement to
 * work.  This should be used at the end of the class definition and will
 * provide support for safe downcasting.
 */
#define PARSELIB_RTTI(thisclass, superclass)             \
	friend ASTNode;                                      \
protected:                                               \
	virtual char *kind()                                 \
	{                                                    \
		return thisclass::classKind();                   \
	}                                                    \
	static char *classKind()                             \
	{                                                    \
		static char thisclass ## id;                     \
		return &thisclass ## id;                         \
	}                                                    \
public:                                                  \
	virtual bool isa(char *x)                            \
	{                                                    \
		return (x == kind()) ||                          \
				(superclass::isa(x));                    \
	}
#endif

/**
 * Base class for AST nodes.
 */
class ASTNode
{
public:
	/**
	 * Constructs the AST node, with a null parent.
	 */
	ASTNode() : parent_node(0) {}
	/**
	 * Copying AST nodes is not supported.
	 */
	ASTNode(const ASTNode&) = delete;

	/**
	 * Destructor does nothing, virtual for subclasses to use.
	 */
	virtual ~ASTNode() {}

	/**
	 * Returns the parent of this AST node, or `nullptr` if there isn't one
	 * (either if this is the root, or if it is still in the stack waiting to
	 * be added to the tree).
	 */
	ASTNode *parent() const { return parent_node; }

	/**
	 * Interface for constructing the AST node.  The input range `r` is the
	 * range within the source.
	 */
	virtual void construct(const InputRange &r, ASTStack &st) {}

private:
	/**
	 * The parent AST node.
	 */
	ASTNode *parent_node;

	template <class T, bool OPT> friend class ASTPtr;
	template <class T> friend class ASTList;
	template <class T> friend class BindAST;

#ifndef USE_RTTI
protected:
	/**
	 * Returns the kind of object class.  This is a unique pointer that can be
	 * tested against pointers returned by classKind() to determine whether
	 * they can be safely compared.
	 */
	virtual char *kind() { return classKind(); }
	/**
	 * Returns the unique identifier for this class.
	 */
	static char *classKind()
	{
		static char ASTNodeid;
		return &ASTNodeid;
	}
public:
	/**
	 * Root implementation of the RTTI-replacement for builds not wishing to
	 * use RTTI.  This returns true if `x` is the value returned from
	 * `classKind()`, or false otherwise.
	 */
	virtual bool isa(char *x)
	{
		return x == classKind();
	}
	/**
	 * Returns true if this object is an instance of `T`.  Note that this
	 * *only* works with single-inheritance hierarchies.  If you wish to use
	 * multiple inheritance in your AST classes, then you must define
	 * `USE_RTTI` and use the C++ RTTI mechanism.
	 */
	template <class T> bool isa()
	{
		return isa(T::classKind());
	}
	/**
	 * Returns a pointer to this object as a pointer to a child class, or
	 * `nullptr` if the cast would be unsafe.
	 *
	 * Note that AST nodes are intended to be always used as unique pointers
	 * and so the returned object is *only* valid as long as the unique pointer
	 * is valid.
	 */
	template <class T> T* get_as()
	{
		return isa<T>() ? static_cast<T*>(this) : nullptr;
	}
#else
public:
	template <class T> T* get_as()
	{
		return dynamic_cast<T*>(this);
	}
#endif
};

class ASTMember;

/** type of ast member vector.
 */

/**
 * The base class for non-leaf AST nodes.  Subclasses can have instances of
 * `ASTMember` subclasses as fields and will automatically construct them.
 */
class ASTContainer : public ASTNode
{
public:
	/**
	 * Constructs the container, setting a thread-local value to point to it
	 * allowing constructors in fields of the subclass to register themselves
	 * in the members vector.
	 */
	ASTContainer();

	/**
	 * Asks all members to construct themselves from the stack. The members are
	 * asked to construct themselves in reverse order from a node stack (`st`).
	 *
	 * The input range (`r`) is unused, because the leaf nodes have already
	 * constructed themselves at this point.
	 */
	virtual void construct(const InputRange &r, ASTStack &st);

private:
	/**
	 * The type used for tracking the fields of subclasses.
	 */
	typedef std::vector<ASTMember *> ASTMember_vector;
	/**
	 * References to all of the fields of the subclass that will be
	 * automatically constructed.
	 */
	ASTMember_vector members;

	friend class ASTMember;
	PARSELIB_RTTI(ASTContainer, ASTNode)
};

/** Base class for children of ASTContainer.
 */
class ASTMember
{
public:
	/**
	 * On construction, `ASTMember` sets its `container_node` field to the
	 * `ASTContainer` currently under construction and registers itself with
	 * the container, to be notified during the construction phase.
	 */
	ASTMember();

	/**
	 * Returns the container of which this object is a field.
	 */
	ASTContainer *container() const { return container_node; }

	/**
	 * Interface for constructing references to AST objects from the stack.
	 */
	virtual void construct(ASTStack &st) = 0;
protected:
	/**
	 * The container that owns this object.
	 */
	ASTContainer *container_node;
};

/**
 * An `ASTPtr` is a wrapper around a pointer to an AST object.  It is intended
 * to be a member of an `ASTContainer` and will automatically pop the top item
 * from the stack and claim it when building the AST..
 */
template <class T, bool OPT = false> class ASTPtr : public ASTMember
{
public:
	/**
	 * Constructs the object in the
	 */
	ASTPtr() : ptr(nullptr) {}

	/** gets the underlying ptr value.
		@return the underlying ptr value.
	 */
	T *get() const
	{
		return ptr.get();
	}

	/** auto conversion to the underlying object ptr.
		@return the underlying ptr value.
	 */
	operator T *() const
	{
		return ptr;
	}

	/** member access.
		@return the underlying ptr value.
	 */
	T *operator ->() const
	{
		assert(ptr);
		return ptr;
	}

	/**
	 * Pops the next matching object from the AST stack `st` and claims it.
	 */
	virtual void construct(ASTStack &st)
	{
		//check the stack node
		//if (st.empty()) throw std::logic_error("empty AST stack");

		//get the node
		ASTNode *node = st.back().get();

		//get the object
		T *obj = node->get_as<T>();

		//if the object is optional, simply return
		if (OPT)
		{
			if (!obj) return;
		}

		//else if the object is mandatory, throw an exception
		else
		{
			//if (!obj) throw std::logic_error("invalid AST node");
		}

		//set the new object
		ptr.reset(obj);
		//pop the node from the stack
		st.back().release();
		st.pop_back();
		ptr->parent_node = container_node;
	}

private:
	/**
	 * The node that we are pointing to.
	 */
	std::unique_ptr<T> ptr;
};

/** A list of objects.
	It pops objects of the given type from the ast stack, until no more objects can be popped.
	It assumes ownership of objects.
	@param T type of object to control.
 */
template <class T> class ASTList : public ASTMember
{
public:
	///list type.
	typedef std::list<std::unique_ptr<T>> container;

	///the default constructor.
	ASTList() {}

	/** duplicates the objects of the given list.
		@param src source object.
	 */
	ASTList(const ASTList<T> &src)
	{
		_dup(src);
	}

	/** returns the container of objects.
		@return the container of objects.
	 */
	const container &objects() const
	{
		return child_objects;
	}

	/**
	 * Pops objects of type T from the stack (`st`) until no more objects can
	 * be popped.
	 */
	virtual void construct(ASTStack &st)
	{
		for(;;)
		{
			//if the stack is empty
			if (st.empty()) break;

			//get the node
			ASTNode *node = st.back().get();

			//get the object
			T *obj = node->get_as<T>();

			//if the object was not not of the appropriate type,
			//end the list parsing
			if (!obj) return;

			//remove the node from the stack
			st.back().release();
			st.pop_back();

			//insert the object in the list, in reverse order
			child_objects.push_front(std::unique_ptr<T>(obj));

			//set the object's parent
			obj->parent_node = ASTMember::container();
		}
	}

private:
	//objects
	container child_objects;

	//duplicate the given list.
	void _dup(const ASTList<T> &src)
	{
		for (auto child : src.child_objects)
		{
			T *obj = new T(child.get());
			child_objects.push_back(obj);
			obj->parent_node = ASTMember::container();
		}
	}
};

/** parses the given input.
	@param i input.
	@param g root rule of grammar.
	@param ws whitespace rule.
	@param el list of errors.
	@param d user data, passed to the parse procedures.
	@return pointer to ast node created, or null if there was an error.
		The return object must be deleted by the caller.
 */
std::unique_ptr<ASTNode> parse(Input &i, Rule &g, Rule &ws, ErrorList &el,
                               const ParserDelegate &d);

/**
 * A parser delegate that is responsible for creating AST nodes from the input.
 *
 * This class manages a mapping from rules in some grammar to AST nodes.
 * Instances of the `BindAST` class that are fields of a subclass of this will
 * automatically register rules on creation.
 *
 * The recommended use for this class is to only register rules on construction
 * (either explicitly in the constructor or implicitly via `BindAST` members).
 * This will give a completely reentrant delegate, which can be used by
 * multiple threads to parse multiple inputs safely.
 */
class ASTParserDelegate : ParserDelegate
{
	/**
	 * BindAST is a friend so that it can call the `set_parse_proc()` function,
	 * which should never be called from anything else.
	 */
	template <class T> friend class BindAST;
	private:
	/**
	 * The map from rules to parsing handlers.
	 */
	std::unordered_map<Rule*, parse_proc> handlers;
	/**
	 * Registers a callback in this delegate.  This should only be called from
	 * the `static` version of this function.
	 */
	void set_parse_proc(Rule &r, parse_proc p);
	/**
	 * Registers a callback for a specific rule in the instance of this class
	 * currently under construction in this thread.  This should only ever be
	 * called by `BindAST` instances.
	 */
	static void bind_parse_proc(Rule &r, parse_proc p);
	public:
	/**
	 * Default constructor, registers this class in thread-local storage so
	 * that it can be referenced by BindAST fields in subclasses when their
	 * constructors are run.
	 */
	ASTParserDelegate();
	virtual parse_proc get_parse_proc(Rule &) const;
	/**
	 * Parse an input `i`, starting from rule `g` in the grammar for which
	 * this is a delegate.  The rule `ws` is used as whitespace.  Errors are
	 * returned via the `el` parameter and the root of the AST via the `ast`
	 * parameter.
	 *
	 * This function returns true on a successful parse, or false otherwise.
	 */
	template <class T> bool parse(Input &i, Rule &g, Rule &ws, ErrorList &el,
	                              std::unique_ptr<T> &ast) const
	{
		std::unique_ptr<ASTNode> node = pegmatite::parse(i, g, ws, el, *this);
		T *n = node->get_as<T>();
		if (n)
		{
			node.release();
			ast.reset(n);
			return true;
		}
		return false;
	}
};

/**
 * The `BindAST` class is responsible for
 */
template <class T> class BindAST
{
public:
	/**
	 * Bind the AST class described in the
	 */
	BindAST(Rule &r)
	{
		ASTParserDelegate::bind_parse_proc(r, [](const ParserPosition &b,
		                                         const ParserPosition &e, void *d)
			{
				ASTStack *st = reinterpret_cast<ASTStack *>(d);
				T *obj = new T();
				obj->construct(InputRange(b, e), *st);
				st->push_back(std::unique_ptr<ASTNode>(obj));
			});
	}
};

} //namespace pegmatite

#endif //PEGMATITE_AST_HPP
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tab_contents/native_tab_contents_container_aura.h"

#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
#include "content/browser/tab_contents/interstitial_page.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "ui/aura/window.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "views/views_delegate.h"

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, public:

NativeTabContentsContainerAura::NativeTabContentsContainerAura(
    TabContentsContainer* container)
    : container_(container) {
  set_id(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW);
}

NativeTabContentsContainerAura::~NativeTabContentsContainerAura() {
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, NativeTabContentsContainer overrides:

void NativeTabContentsContainerAura::AttachContents(TabContents* contents) {
  // We need to register the tab contents window with the BrowserContainer so
  // that the BrowserContainer is the focused view when the focus is on the
  // TabContents window (for the TabContents case).
  set_focus_view(this);

  Attach(contents->GetNativeView());
}

void NativeTabContentsContainerAura::DetachContents(TabContents* contents) {
  // Detach the TabContents.  Do this before we unparent the
  // TabContentsViewViews so that the window hierarchy is intact for any
  // cleanup during Detach().
  Detach();
}

void NativeTabContentsContainerAura::SetFastResize(bool fast_resize) {
  set_fast_resize(fast_resize);
}

bool NativeTabContentsContainerAura::GetFastResize() const {
  return fast_resize();
}

bool NativeTabContentsContainerAura::FastResizeAtLastLayout() const {
  return fast_resize_at_last_layout();
}

void NativeTabContentsContainerAura::RenderViewHostChanged(
    RenderViewHost* old_host,
    RenderViewHost* new_host) {
  // If we are focused, we need to pass the focus to the new RenderViewHost.
  if (GetFocusManager()->GetFocusedView() == this)
    OnFocus();
}

views::View* NativeTabContentsContainerAura::GetView() {
  return this;
}

void NativeTabContentsContainerAura::TabContentsFocused(
    TabContents* tab_contents) {
  views::FocusManager* focus_manager = GetFocusManager();
  if (!focus_manager) {
    NOTREACHED();
    return;
  }
  focus_manager->SetFocusedView(this);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, views::View overrides:

bool NativeTabContentsContainerAura::SkipDefaultKeyEventProcessing(
    const views::KeyEvent& e) {
  // Don't look-up accelerators or tab-traversal if we are showing a non-crashed
  // TabContents.
  // We'll first give the page a chance to process the key events.  If it does
  // not process them, they'll be returned to us and we'll treat them as
  // accelerators then.
  return container_->tab_contents() &&
         !container_->tab_contents()->is_crashed();
}

bool NativeTabContentsContainerAura::IsFocusable() const {
  // We need to be focusable when our contents is not a view hierarchy, as
  // clicking on the contents needs to focus us.
  return container_->tab_contents() != NULL;
}

void NativeTabContentsContainerAura::OnFocus() {
  if (container_->tab_contents())
    container_->tab_contents()->Focus();
}

void NativeTabContentsContainerAura::RequestFocus() {
  // This is a hack to circumvent the fact that a the OnFocus() method is not
  // invoked when RequestFocus() is called on an already focused view.
  // The TabContentsContainer is the view focused when the TabContents has
  // focus.  When switching between from one tab that has focus to another tab
  // that should also have focus, RequestFocus() is invoked one the
  // TabContentsContainer.  In order to make sure OnFocus() is invoked we need
  // to clear the focus before hands.
  {
    // Disable notifications.  Clear focus will assign the focus to the main
    // browser window.  Because this change of focus was not user requested,
    // don't send it to listeners.
    views::AutoNativeNotificationDisabler local_notification_disabler;
    GetFocusManager()->ClearFocus();
  }
  View::RequestFocus();
}

void NativeTabContentsContainerAura::AboutToRequestFocusFromTabTraversal(
    bool reverse) {
  container_->tab_contents()->FocusThroughTabTraversal(reverse);
}

void NativeTabContentsContainerAura::GetAccessibleState(
    ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
}

gfx::NativeViewAccessible
    NativeTabContentsContainerAura::GetNativeViewAccessible() {
  // TODO(beng):
  NOTIMPLEMENTED();
  return View::GetNativeViewAccessible();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainer, public:

// static
NativeTabContentsContainer* NativeTabContentsContainer::CreateNativeContainer(
    TabContentsContainer* container) {
  return new NativeTabContentsContainerAura(container);
}
<commit_msg>Revert 110950 - views: Fix the include path for views_delegate.h<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/views/tab_contents/native_tab_contents_container_aura.h"

#include "chrome/browser/ui/view_ids.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
#include "content/browser/tab_contents/interstitial_page.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "ui/aura/window.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/focus/widget_focus_manager.h"
#include "ui/views/views_delegate.h"

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, public:

NativeTabContentsContainerAura::NativeTabContentsContainerAura(
    TabContentsContainer* container)
    : container_(container) {
  set_id(VIEW_ID_TAB_CONTAINER_FOCUS_VIEW);
}

NativeTabContentsContainerAura::~NativeTabContentsContainerAura() {
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, NativeTabContentsContainer overrides:

void NativeTabContentsContainerAura::AttachContents(TabContents* contents) {
  // We need to register the tab contents window with the BrowserContainer so
  // that the BrowserContainer is the focused view when the focus is on the
  // TabContents window (for the TabContents case).
  set_focus_view(this);

  Attach(contents->GetNativeView());
}

void NativeTabContentsContainerAura::DetachContents(TabContents* contents) {
  // Detach the TabContents.  Do this before we unparent the
  // TabContentsViewViews so that the window hierarchy is intact for any
  // cleanup during Detach().
  Detach();
}

void NativeTabContentsContainerAura::SetFastResize(bool fast_resize) {
  set_fast_resize(fast_resize);
}

bool NativeTabContentsContainerAura::GetFastResize() const {
  return fast_resize();
}

bool NativeTabContentsContainerAura::FastResizeAtLastLayout() const {
  return fast_resize_at_last_layout();
}

void NativeTabContentsContainerAura::RenderViewHostChanged(
    RenderViewHost* old_host,
    RenderViewHost* new_host) {
  // If we are focused, we need to pass the focus to the new RenderViewHost.
  if (GetFocusManager()->GetFocusedView() == this)
    OnFocus();
}

views::View* NativeTabContentsContainerAura::GetView() {
  return this;
}

void NativeTabContentsContainerAura::TabContentsFocused(
    TabContents* tab_contents) {
  views::FocusManager* focus_manager = GetFocusManager();
  if (!focus_manager) {
    NOTREACHED();
    return;
  }
  focus_manager->SetFocusedView(this);
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainerAura, views::View overrides:

bool NativeTabContentsContainerAura::SkipDefaultKeyEventProcessing(
    const views::KeyEvent& e) {
  // Don't look-up accelerators or tab-traversal if we are showing a non-crashed
  // TabContents.
  // We'll first give the page a chance to process the key events.  If it does
  // not process them, they'll be returned to us and we'll treat them as
  // accelerators then.
  return container_->tab_contents() &&
         !container_->tab_contents()->is_crashed();
}

bool NativeTabContentsContainerAura::IsFocusable() const {
  // We need to be focusable when our contents is not a view hierarchy, as
  // clicking on the contents needs to focus us.
  return container_->tab_contents() != NULL;
}

void NativeTabContentsContainerAura::OnFocus() {
  if (container_->tab_contents())
    container_->tab_contents()->Focus();
}

void NativeTabContentsContainerAura::RequestFocus() {
  // This is a hack to circumvent the fact that a the OnFocus() method is not
  // invoked when RequestFocus() is called on an already focused view.
  // The TabContentsContainer is the view focused when the TabContents has
  // focus.  When switching between from one tab that has focus to another tab
  // that should also have focus, RequestFocus() is invoked one the
  // TabContentsContainer.  In order to make sure OnFocus() is invoked we need
  // to clear the focus before hands.
  {
    // Disable notifications.  Clear focus will assign the focus to the main
    // browser window.  Because this change of focus was not user requested,
    // don't send it to listeners.
    views::AutoNativeNotificationDisabler local_notification_disabler;
    GetFocusManager()->ClearFocus();
  }
  View::RequestFocus();
}

void NativeTabContentsContainerAura::AboutToRequestFocusFromTabTraversal(
    bool reverse) {
  container_->tab_contents()->FocusThroughTabTraversal(reverse);
}

void NativeTabContentsContainerAura::GetAccessibleState(
    ui::AccessibleViewState* state) {
  state->role = ui::AccessibilityTypes::ROLE_GROUPING;
}

gfx::NativeViewAccessible
    NativeTabContentsContainerAura::GetNativeViewAccessible() {
  // TODO(beng):
  NOTIMPLEMENTED();
  return View::GetNativeViewAccessible();
}

////////////////////////////////////////////////////////////////////////////////
// NativeTabContentsContainer, public:

// static
NativeTabContentsContainer* NativeTabContentsContainer::CreateNativeContainer(
    TabContentsContainer* container) {
  return new NativeTabContentsContainerAura(container);
}
<|endoftext|>


<commit_before>/*
 * Takes an arbitrary number of tuples as input  and calculates the fewest
 * possible groups of sets whose combined Cartesian product contains exactly
 * those tuples.
 *
 * Copyright (c) 2012, Dennis Hedback
 * 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.
 *
 * 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 <algorithm>
#include <iostream>
#include <iterator>

#include "common.hpp"

void read_tuples(Product &prod)
{
    Tuple current_tuple;
    std::string current_elem;

    for (std::istreambuf_iterator<char> it(std::cin), end; it != end; it++)
    {
        char c = *it;

        if (c == ',' || c == '\n')
        {
            current_tuple.push_back(current_elem);
            current_elem.clear();

            if (c == '\n')
            {
                prod.insert(current_tuple);
                current_tuple.clear();
            }
        }
        else
        {
            current_elem += c;
        }
    }
}

void init_generator(Generator &gen, size_t size)
{
    for (unsigned int i = 0; i < size; i++)
        gen.push_back(Set());
}

bool product_contains(Product &prod, Tuple const &tuple)
{
    return prod.find(tuple) != prod.end();
}

void print_generator(Generator &gen)
{
        for (Generator::const_iterator gi = gen.begin(); gi != gen.end(); gi++)
        {
            for (Set::const_iterator si = gi->begin(); si != gi->end(); si++)
            {
                std::cout << *si;

                if (++si != gi->end())
                    std::cout << ',';

                si--;
            }

            std::cout << '\n';
        }

        std::cout << "%%\n";
}

void insert_tuple(Generator &gen, Tuple const &tup)
{
    // FIXME: Handle cases where tup.size() != gen.size()
    Generator::iterator set = gen.begin();
    Tuple::const_iterator elem = tup.begin();

    for (; set != gen.end() && elem != tup.end(); set++, elem++)
    {
        set->insert(*elem);
    }
}

bool is_subset(Product &subset, Product &superset)
{
#ifdef USE_HTAB
    for (Product::const_iterator subit = subset.begin(); subit != subset.end(); subit++)
    {
        if (!product_contains(superset, *subit))
        {
            return false;
        }
    }

    return true;
#else
    return std::includes(superset.begin(), superset.end(), subset.begin(), subset.end());
#endif // USE_HTAB
}

void generating_sets(Product &prod)
{
    Product ref_prod = prod;

    while (prod.size() > 0)
    {
        Generator gen;
        init_generator(gen, prod.begin()->size());

        for (Product::iterator prod_it = prod.begin(); prod_it != prod.end();)
        {
            Generator tmp_gen = gen;
            Product tmp_prod;

            insert_tuple(tmp_gen, *prod_it);
            cartesian_product(tmp_gen, tmp_prod, false);

            if (is_subset(tmp_prod, ref_prod))
            {
                gen = tmp_gen;
                prod.erase(prod_it++);
            }
            else
            {
                ++prod_it;
            }
        }

        print_generator(gen);
    }
}

int main(int argc, char *argv[])
{
    Product prod;
    read_tuples(prod);
    generating_sets(prod);

    return 0;
}
<commit_msg>Added comments<commit_after>/*
 * Takes an arbitrary number of tuples as input  and calculates the fewest
 * possible groups of sets whose combined Cartesian product contains exactly
 * those tuples.
 *
 * Copyright (c) 2012, Dennis Hedback
 * 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.
 *
 * 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 <algorithm>
#include <iostream>
#include <iterator>
#include "common.hpp"

// Reads tuples from input stream and puts them in prod.
void read_tuples(Product &prod)
{
    Tuple tup;
    std::string elem;
    // Read the input stream character by character
    for (std::istreambuf_iterator<char> it(std::cin), end; it != end; it++)
    {
        char c = *it;
        // Tuple elements are delimited by ',' and tuples are delimited by '\n'
        if (c == ',' || c == '\n')
        {
            // This is the end of the current element, push it into the tuple
            // and finalize
            tup.push_back(elem);
            elem.clear();

            if (c == '\n')
            {
                // This is the end of the current tuple, insert it into the
                // product and finalize
                prod.insert(tup);
                tup.clear();
            }
        }
        else
        {
            elem += c; // Append character to the current element
        }
    }
}

// Populates a generator FIXME: This could easily be done in the call to the
// generator's constructor instead
void init_generator(Generator &gen, size_t size)
{
    for (unsigned int i = 0; i < size; i++)
        gen.push_back(Set());
}

// Does product contains Tuple 'tup'?
bool product_contains(Product &prod, Tuple const &tup)
{
    return prod.find(tup) != prod.end();
}

// Prints a generator
void print_generator(Generator &gen)
{
        for (Generator::const_iterator gi = gen.begin(); gi != gen.end(); gi++)
        {
            for (Set::const_iterator si = gi->begin(); si != gi->end(); si++)
            {
                std::cout << *si;
                if (++si != gi->end()) // This is not the last element
                    std::cout << ','; // Delimit elements with ','
                si--;
            }
            std::cout << '\n'; // Sets are delimited with newline
        }
        std::cout << "%%\n"; // Generators are delimited with "%%"
}

// Inserts a tuple into a generator
void insert_tuple(Generator &gen, Tuple const &tup)
{
    // FIXME: Handle cases where tup.size() != gen.size()
    Generator::iterator set = gen.begin();
    Tuple::const_iterator elem = tup.begin();
    // Insert tup[n] into gen[n]
    for (; set != gen.end() && elem != tup.end(); set++, elem++)
    {
        set->insert(*elem);
    }
}

// Is one product a subset of another?
bool is_subset(Product &subset, Product &superset)
{
#ifdef USE_HTAB
// We're using boost::unordered_set so the std::includes algo won't work
    for (Product::const_iterator it = subset.begin(); it != subset.end(); it++)
    {
        if (!product_contains(superset, *it))
        {
            // If superset does not contain any given tuple of subset, then
            // subset is not a subset of superset
            return false;
        }
    }
    return true;
#else
// We're using std::set so let's use the std::includes algo
    return std::includes(superset.begin(), superset.end(), subset.begin(), subset.end());
#endif // USE_HTAB
}

// Calculate, and print, the groups of generating sets whose combined Cartesian
// products contain exactly the tuples in 'prod'
void generating_sets(Product &prod)
{
    Product ref_prod = prod; // Our reference
    // Remove a tuple from prod once it's been inserted into a generator, so
    // we'll continue until all tuples' been inserted
    while (prod.size() > 0)
    {
        Generator gen; // Current generator
        init_generator(gen, prod.begin()->size());
        // Iterate over all tuples in prod and try to insert them into gen
        for (Product::iterator prod_it = prod.begin(); prod_it != prod.end();)
        {
            Generator tmp_gen = gen; // Temporary copy of current generator
            Product tmp_prod; // Cartesian product of temporary generator
            // Insert the tuple into the temporary generator instead of the
            // current generator so we can discard the generator if its product
            // is not a subset of the input product
            insert_tuple(tmp_gen, *prod_it);
            // Calculate the Cartesian product of the current generator and put
            // it in tmp_prod
            cartesian_product(tmp_gen, tmp_prod, false);
            // If the temporary product is a subset of the input product, the
            // generator is kept and the tuple is deleted from the input
            // input product. The goal is that all generators' combined
            // Cartesian products contain exactly the tuples in the input
            // product. If the Cartesian product of one generator is _not_ a
            // subset of the input product, then this is not the case.
            if (is_subset(tmp_prod, ref_prod))
            {
                gen = tmp_gen;
                prod.erase(prod_it++);
            }
            else
            {
                ++prod_it;
            }
        }
        print_generator(gen); // Generator is complete, print it
    }
}

int main(int argc, char *argv[])
{
    Product prod;
    read_tuples(prod);
    generating_sets(prod);
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h"

#include <map>
#include <set>
#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/input_method/input_method_manager.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/user_metrics.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace chromeos {

CrosLanguageOptionsHandler::CrosLanguageOptionsHandler() {
}

CrosLanguageOptionsHandler::~CrosLanguageOptionsHandler() {
}

void CrosLanguageOptionsHandler::GetLocalizedValues(
    DictionaryValue* localized_strings) {
  LanguageOptionsHandlerCommon::GetLocalizedValues(localized_strings);

  RegisterTitle(localized_strings, "languagePage",
                IDS_OPTIONS_SETTINGS_LANGUAGES_AND_INPUT_DIALOG_TITLE);
  localized_strings->SetString("ok_button", l10n_util::GetStringUTF16(IDS_OK));
  localized_strings->SetString("configure",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
  localized_strings->SetString("input_method",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
  localized_strings->SetString("please_add_another_input_method",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD));
  localized_strings->SetString("input_method_instructions",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS));
  localized_strings->SetString("switch_input_methods_hint",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT));
  localized_strings->SetString("select_previous_input_method_hint",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT));
  localized_strings->SetString("restart_button",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_SIGN_OUT_BUTTON));
  localized_strings->SetString("virtual_keyboard_button",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_VIRTUAL_KEYBOARD_BUTTON));

  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::GetInstance();
  // GetSupportedInputMethods() never return NULL.
  scoped_ptr<input_method::InputMethodDescriptors> descriptors(
      manager->GetSupportedInputMethods());
  localized_strings->Set("languageList", GetLanguageList(*descriptors));
  localized_strings->Set("inputMethodList", GetInputMethodList(*descriptors));
}

void CrosLanguageOptionsHandler::RegisterMessages() {
  LanguageOptionsHandlerCommon::RegisterMessages();

  web_ui_->RegisterMessageCallback("inputMethodDisable",
      base::Bind(&CrosLanguageOptionsHandler::InputMethodDisableCallback,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("inputMethodEnable",
      base::Bind(&CrosLanguageOptionsHandler::InputMethodEnableCallback,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("inputMethodOptionsOpen",
      base::Bind(&CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("uiLanguageRestart",
      base::Bind(&CrosLanguageOptionsHandler::RestartCallback,
                 base::Unretained(this)));
}

ListValue* CrosLanguageOptionsHandler::GetInputMethodList(
    const input_method::InputMethodDescriptors& descriptors) {
  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::GetInstance();

  ListValue* input_method_list = new ListValue();

  for (size_t i = 0; i < descriptors.size(); ++i) {
    const input_method::InputMethodDescriptor& descriptor =
        descriptors[i];
    const std::string language_code =
        manager->GetInputMethodUtil()->GetLanguageCodeFromDescriptor(
            descriptor);
    const std::string display_name =
        manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId(
            descriptor.id());

    DictionaryValue* dictionary = new DictionaryValue();
    dictionary->SetString("id", descriptor.id());
    dictionary->SetString("displayName", display_name);

    // One input method can be associated with multiple languages, hence
    // we use a dictionary here.
    DictionaryValue* language_codes = new DictionaryValue();
    language_codes->SetBoolean(language_code, true);
    // Check kExtraLanguages to see if there are languages associated with
    // this input method. If these are present, add these.
    for (size_t j = 0; j < input_method::kExtraLanguagesLength; ++j) {
      const std::string extra_input_method_id =
          input_method::kExtraLanguages[j].input_method_id;
      const std::string extra_language_code =
          input_method::kExtraLanguages[j].language_code;
      if (extra_input_method_id == descriptor.id()) {
        language_codes->SetBoolean(extra_language_code, true);
      }
    }
    dictionary->Set("languageCodeSet", language_codes);

    input_method_list->Append(dictionary);
  }

  return input_method_list;
}

ListValue* CrosLanguageOptionsHandler::GetLanguageList(
    const input_method::InputMethodDescriptors& descriptors) {
  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::GetInstance();

  std::set<std::string> language_codes;
  // Collect the language codes from the supported input methods.
  for (size_t i = 0; i < descriptors.size(); ++i) {
    const input_method::InputMethodDescriptor& descriptor = descriptors[i];
    const std::string language_code =
        manager->GetInputMethodUtil()->GetLanguageCodeFromDescriptor(
            descriptor);
    language_codes.insert(language_code);
  }
  // Collect the language codes from kExtraLanguages.
  for (size_t i = 0; i < input_method::kExtraLanguagesLength; ++i) {
    const char* language_code =
        input_method::kExtraLanguages[i].language_code;
    language_codes.insert(language_code);
  }

  // Map of display name -> {language code, native_display_name}.
  // In theory, we should be able to create a map that is sorted by
  // display names using ICU comparator, but doing it is hard, thus we'll
  // use an auxiliary vector to achieve the same result.
  typedef std::pair<std::string, string16> LanguagePair;
  typedef std::map<string16, LanguagePair> LanguageMap;
  LanguageMap language_map;
  // The auxiliary vector mentioned above.
  std::vector<string16> display_names;

  // Build the list of display names, and build the language map.
  for (std::set<std::string>::const_iterator iter = language_codes.begin();
       iter != language_codes.end(); ++iter) {
    const string16 display_name =
        input_method::InputMethodUtil::GetLanguageDisplayNameFromCode(*iter);
    const string16 native_display_name =
        input_method::InputMethodUtil::GetLanguageNativeDisplayNameFromCode(
            *iter);
    display_names.push_back(display_name);
    language_map[display_name] =
        std::make_pair(*iter, native_display_name);
  }
  DCHECK_EQ(display_names.size(), language_map.size());

  // Sort display names using locale specific sorter.
  l10n_util::SortStrings16(g_browser_process->GetApplicationLocale(),
                           &display_names);

  // Build the language list from the language map.
  ListValue* language_list = new ListValue();
  for (size_t i = 0; i < display_names.size(); ++i) {
    const LanguagePair& pair = language_map[display_names[i]];
    DictionaryValue* dictionary = new DictionaryValue();
    dictionary->SetString("code",  pair.first);
    dictionary->SetString("displayName", display_names[i]);
    dictionary->SetString("nativeDisplayName", pair.second);
    language_list->Append(dictionary);
  }

  return language_list;
}

string16 CrosLanguageOptionsHandler::GetProductName() {
  return l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME);
}

void CrosLanguageOptionsHandler::SetApplicationLocale(
    const std::string& language_code) {
  Profile::FromWebUI(web_ui_)->ChangeAppLocale(
      language_code, Profile::APP_LOCALE_CHANGED_VIA_SETTINGS);
}

void CrosLanguageOptionsHandler::RestartCallback(const ListValue* args) {
  UserMetrics::RecordAction(UserMetricsAction("LanguageOptions_SignOut"));

  Browser* browser = Browser::GetBrowserForController(
      &web_ui_->tab_contents()->controller(), NULL);
  if (browser)
    browser->ExecuteCommand(IDC_EXIT);
}

void CrosLanguageOptionsHandler::InputMethodDisableCallback(
    const ListValue* args) {
  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
  const std::string action = base::StringPrintf(
      "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str());
  UserMetrics::RecordComputedAction(action);
}

void CrosLanguageOptionsHandler::InputMethodEnableCallback(
    const ListValue* args) {
  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
  const std::string action = base::StringPrintf(
      "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str());
  UserMetrics::RecordComputedAction(action);
}

void CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback(
    const ListValue* args) {
  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
  const std::string action = base::StringPrintf(
      "InputMethodOptions_Open_%s", input_method_id.c_str());
  UserMetrics::RecordComputedAction(action);
}

} // namespace chromeos
<commit_msg>Options: Fix CrOS that slipped underneath.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/options2/chromeos/cros_language_options_handler.h"

#include <map>
#include <set>
#include <vector>

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/input_method/input_method_manager.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/public/browser/user_metrics.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

using content::UserMetricsAction;

namespace chromeos {

CrosLanguageOptionsHandler::CrosLanguageOptionsHandler() {
}

CrosLanguageOptionsHandler::~CrosLanguageOptionsHandler() {
}

void CrosLanguageOptionsHandler::GetLocalizedValues(
    DictionaryValue* localized_strings) {
  LanguageOptionsHandlerCommon::GetLocalizedValues(localized_strings);

  RegisterTitle(localized_strings, "languagePage",
                IDS_OPTIONS_SETTINGS_LANGUAGES_AND_INPUT_DIALOG_TITLE);
  localized_strings->SetString("ok_button", l10n_util::GetStringUTF16(IDS_OK));
  localized_strings->SetString("configure",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_CONFIGURE));
  localized_strings->SetString("input_method",
      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD));
  localized_strings->SetString("please_add_another_input_method",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_PLEASE_ADD_ANOTHER_INPUT_METHOD));
  localized_strings->SetString("input_method_instructions",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_INPUT_METHOD_INSTRUCTIONS));
  localized_strings->SetString("switch_input_methods_hint",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_SWITCH_INPUT_METHODS_HINT));
  localized_strings->SetString("select_previous_input_method_hint",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_SELECT_PREVIOUS_INPUT_METHOD_HINT));
  localized_strings->SetString("restart_button",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_SIGN_OUT_BUTTON));
  localized_strings->SetString("virtual_keyboard_button",
      l10n_util::GetStringUTF16(
          IDS_OPTIONS_SETTINGS_LANGUAGES_VIRTUAL_KEYBOARD_BUTTON));

  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::GetInstance();
  // GetSupportedInputMethods() never return NULL.
  scoped_ptr<input_method::InputMethodDescriptors> descriptors(
      manager->GetSupportedInputMethods());
  localized_strings->Set("languageList", GetLanguageList(*descriptors));
  localized_strings->Set("inputMethodList", GetInputMethodList(*descriptors));
}

void CrosLanguageOptionsHandler::RegisterMessages() {
  LanguageOptionsHandlerCommon::RegisterMessages();

  web_ui_->RegisterMessageCallback("inputMethodDisable",
      base::Bind(&CrosLanguageOptionsHandler::InputMethodDisableCallback,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("inputMethodEnable",
      base::Bind(&CrosLanguageOptionsHandler::InputMethodEnableCallback,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("inputMethodOptionsOpen",
      base::Bind(&CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback,
                 base::Unretained(this)));
  web_ui_->RegisterMessageCallback("uiLanguageRestart",
      base::Bind(&CrosLanguageOptionsHandler::RestartCallback,
                 base::Unretained(this)));
}

ListValue* CrosLanguageOptionsHandler::GetInputMethodList(
    const input_method::InputMethodDescriptors& descriptors) {
  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::GetInstance();

  ListValue* input_method_list = new ListValue();

  for (size_t i = 0; i < descriptors.size(); ++i) {
    const input_method::InputMethodDescriptor& descriptor =
        descriptors[i];
    const std::string language_code =
        manager->GetInputMethodUtil()->GetLanguageCodeFromDescriptor(
            descriptor);
    const std::string display_name =
        manager->GetInputMethodUtil()->GetInputMethodDisplayNameFromId(
            descriptor.id());

    DictionaryValue* dictionary = new DictionaryValue();
    dictionary->SetString("id", descriptor.id());
    dictionary->SetString("displayName", display_name);

    // One input method can be associated with multiple languages, hence
    // we use a dictionary here.
    DictionaryValue* language_codes = new DictionaryValue();
    language_codes->SetBoolean(language_code, true);
    // Check kExtraLanguages to see if there are languages associated with
    // this input method. If these are present, add these.
    for (size_t j = 0; j < input_method::kExtraLanguagesLength; ++j) {
      const std::string extra_input_method_id =
          input_method::kExtraLanguages[j].input_method_id;
      const std::string extra_language_code =
          input_method::kExtraLanguages[j].language_code;
      if (extra_input_method_id == descriptor.id()) {
        language_codes->SetBoolean(extra_language_code, true);
      }
    }
    dictionary->Set("languageCodeSet", language_codes);

    input_method_list->Append(dictionary);
  }

  return input_method_list;
}

ListValue* CrosLanguageOptionsHandler::GetLanguageList(
    const input_method::InputMethodDescriptors& descriptors) {
  input_method::InputMethodManager* manager =
      input_method::InputMethodManager::GetInstance();

  std::set<std::string> language_codes;
  // Collect the language codes from the supported input methods.
  for (size_t i = 0; i < descriptors.size(); ++i) {
    const input_method::InputMethodDescriptor& descriptor = descriptors[i];
    const std::string language_code =
        manager->GetInputMethodUtil()->GetLanguageCodeFromDescriptor(
            descriptor);
    language_codes.insert(language_code);
  }
  // Collect the language codes from kExtraLanguages.
  for (size_t i = 0; i < input_method::kExtraLanguagesLength; ++i) {
    const char* language_code =
        input_method::kExtraLanguages[i].language_code;
    language_codes.insert(language_code);
  }

  // Map of display name -> {language code, native_display_name}.
  // In theory, we should be able to create a map that is sorted by
  // display names using ICU comparator, but doing it is hard, thus we'll
  // use an auxiliary vector to achieve the same result.
  typedef std::pair<std::string, string16> LanguagePair;
  typedef std::map<string16, LanguagePair> LanguageMap;
  LanguageMap language_map;
  // The auxiliary vector mentioned above.
  std::vector<string16> display_names;

  // Build the list of display names, and build the language map.
  for (std::set<std::string>::const_iterator iter = language_codes.begin();
       iter != language_codes.end(); ++iter) {
    const string16 display_name =
        input_method::InputMethodUtil::GetLanguageDisplayNameFromCode(*iter);
    const string16 native_display_name =
        input_method::InputMethodUtil::GetLanguageNativeDisplayNameFromCode(
            *iter);
    display_names.push_back(display_name);
    language_map[display_name] =
        std::make_pair(*iter, native_display_name);
  }
  DCHECK_EQ(display_names.size(), language_map.size());

  // Sort display names using locale specific sorter.
  l10n_util::SortStrings16(g_browser_process->GetApplicationLocale(),
                           &display_names);

  // Build the language list from the language map.
  ListValue* language_list = new ListValue();
  for (size_t i = 0; i < display_names.size(); ++i) {
    const LanguagePair& pair = language_map[display_names[i]];
    DictionaryValue* dictionary = new DictionaryValue();
    dictionary->SetString("code",  pair.first);
    dictionary->SetString("displayName", display_names[i]);
    dictionary->SetString("nativeDisplayName", pair.second);
    language_list->Append(dictionary);
  }

  return language_list;
}

string16 CrosLanguageOptionsHandler::GetProductName() {
  return l10n_util::GetStringUTF16(IDS_PRODUCT_OS_NAME);
}

void CrosLanguageOptionsHandler::SetApplicationLocale(
    const std::string& language_code) {
  Profile::FromWebUI(web_ui_)->ChangeAppLocale(
      language_code, Profile::APP_LOCALE_CHANGED_VIA_SETTINGS);
}

void CrosLanguageOptionsHandler::RestartCallback(const ListValue* args) {
  content::RecordAction(UserMetricsAction("LanguageOptions_SignOut"));

  Browser* browser = Browser::GetBrowserForController(
      &web_ui_->tab_contents()->controller(), NULL);
  if (browser)
    browser->ExecuteCommand(IDC_EXIT);
}

void CrosLanguageOptionsHandler::InputMethodDisableCallback(
    const ListValue* args) {
  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
  const std::string action = base::StringPrintf(
      "LanguageOptions_DisableInputMethod_%s", input_method_id.c_str());
  content::RecordComputedAction(action);
}

void CrosLanguageOptionsHandler::InputMethodEnableCallback(
    const ListValue* args) {
  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
  const std::string action = base::StringPrintf(
      "LanguageOptions_EnableInputMethod_%s", input_method_id.c_str());
  content::RecordComputedAction(action);
}

void CrosLanguageOptionsHandler::InputMethodOptionsOpenCallback(
    const ListValue* args) {
  const std::string input_method_id = UTF16ToASCII(ExtractStringValue(args));
  const std::string action = base::StringPrintf(
      "InputMethodOptions_Open_%s", input_method_id.c_str());
  content::RecordComputedAction(action);
}

} // namespace chromeos
<|endoftext|>


<commit_before>/*
 *  Copyright (C) 2014 Hugh Bailey <obs.jim@gmail.com>
 *
 *  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 Street, Fifth Floor, Boston, MA  02110-1301
 *  USA
 */

#include "dshow-base.hpp"
#include "log.hpp"
#include "../dshowcapture.hpp"

namespace DShow {

void *logParam = NULL;
static LogCallback logCallback = NULL;

void SetLogCallback(LogCallback callback, void *param)
{
	logCallback = callback;
	logParam = param;
}

static void Log(LogType type, const wchar_t *format, va_list args)
{
	wchar_t str[4096];
	vswprintf_s(str, 4096, format, args);

	if (logCallback)
		logCallback(type, str, logParam);
}

void Error(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Error, format, args);
	va_end(args);
}

void Warning(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Warning, format, args);
	va_end(args);
}

void Info(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Info, format, args);
	va_end(args);
}

void Debug(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Debug, format, args);
	va_end(args);
}

void ErrorHR(const wchar_t *str, HRESULT hr)
{
	Error(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

void WarningHR(const wchar_t *str, HRESULT hr)
{
	Warning(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

void InfoHR(const wchar_t *str, HRESULT hr)
{
	Info(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

void DebugHR(const wchar_t *str, HRESULT hr)
{
	Info(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

}; /* namespace DShow */
<commit_msg>Fix log level of DebugHR<commit_after>/*
 *  Copyright (C) 2014 Hugh Bailey <obs.jim@gmail.com>
 *
 *  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 Street, Fifth Floor, Boston, MA  02110-1301
 *  USA
 */

#include "dshow-base.hpp"
#include "log.hpp"
#include "../dshowcapture.hpp"

namespace DShow {

void *logParam = NULL;
static LogCallback logCallback = NULL;

void SetLogCallback(LogCallback callback, void *param)
{
	logCallback = callback;
	logParam = param;
}

static void Log(LogType type, const wchar_t *format, va_list args)
{
	wchar_t str[4096];
	vswprintf_s(str, 4096, format, args);

	if (logCallback)
		logCallback(type, str, logParam);
}

void Error(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Error, format, args);
	va_end(args);
}

void Warning(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Warning, format, args);
	va_end(args);
}

void Info(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Info, format, args);
	va_end(args);
}

void Debug(const wchar_t *format, ...)
{
	va_list args;
	va_start(args, format);
	Log(LogType::Debug, format, args);
	va_end(args);
}

void ErrorHR(const wchar_t *str, HRESULT hr)
{
	Error(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

void WarningHR(const wchar_t *str, HRESULT hr)
{
	Warning(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

void InfoHR(const wchar_t *str, HRESULT hr)
{
	Info(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

void DebugHR(const wchar_t *str, HRESULT hr)
{
	Debug(L"%s (0x%08lX): %s", str, hr, ConvertHRToEnglish(hr).c_str());
}

}; /* namespace DShow */
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/lib/io/buffered_inputstream.h"
#include "tensorflow/core/platform/file_system.h"

extern "C" {

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libswscale/swscale.h"
#include <dlfcn.h>

}

#include "kernels/ffmpeg_reader.h"

namespace tensorflow {
namespace data {

static mutex mu(LINKER_INITIALIZED);
static unsigned count(0);
void FFmpegReaderInit() {
  mutex_lock lock(mu);
  count++;
  if (count == 1) {
    // Register all formats and codecs
    av_register_all();
  }
}

static int io_read_packet(void *opaque, uint8_t *buf, int buf_size) {
  FFmpegReader *r = (FFmpegReader *)opaque;
  StringPiece result;
  Status status = r->stream_->Read(r->offset_, buf_size, &result, (char *)buf);
  if (!(status.ok() || errors::IsOutOfRange(status))) {
    return -1;
  }
  r->offset_ += result.size();
  return result.size();
}

static int64_t io_seek(void *opaque, int64_t offset, int whence) {
  FFmpegReader *r = (FFmpegReader *)opaque;
  uint64 file_size = 0;
  Status status = r->stream_->GetFileSize(&file_size);
  if (!status.ok()) {
    return -1;
  }
  switch (whence)
  {
  case SEEK_SET:
    if (offset > file_size) {
      return -1;
    }
    r->offset_ = offset;
    return r->offset_;
  case SEEK_CUR:
    if (r->offset_ + offset > file_size) {
      return -1;
    }
    r->offset_ += offset;
    return r->offset_;
  case SEEK_END:
    if (offset > file_size) {
      return -1;
    }
    r->offset_ = file_size - offset;
    return r->offset_;
  case AVSEEK_SIZE:
    return file_size;
  default:
    break;
  }
  return -1;
}

Status FFmpegReader::InitializeReader()
{
    // Allocate format
    if ((format_context_ = avformat_alloc_context()) == NULL) {
      return errors::InvalidArgument("could not allocate format context");
    }
    // Allocate context
    if ((io_context_ = avio_alloc_context(NULL, 0, 0, this, io_read_packet, NULL, io_seek)) == NULL) {
      return errors::InvalidArgument("could not allocate io context");
    }
    format_context_->pb = io_context_;
    // Open input file, and allocate format context
    if (avformat_open_input(&format_context_, filename_.c_str(), NULL, NULL) < 0) {
      return errors::InvalidArgument("could not open media file: ", filename_);
    }
    // Retrieve stream information
    if (avformat_find_stream_info(format_context_, NULL) < 0) {
      return errors::InvalidArgument("could not find stream information: ", filename_);
    }
    // Find media stream
    if ((stream_index_ = av_find_best_stream(format_context_, MediaType(), -1, -1, NULL, 0)) < 0) {
      return errors::InvalidArgument("could not find media stream: ", filename_);
    }

    AVStream *media_stream = format_context_->streams[stream_index_];
#if LIBAVCODEC_VERSION_MAJOR > 56
    // Find decoder for the stream
    AVCodec *codec = avcodec_find_decoder(media_stream->codecpar->codec_id);
    if (!codec) {
      return errors::Internal("could not find media codec: ", media_stream->codecpar->codec_id);
    }
    // Allocate a codec context for the decoder
    codec_context_ = avcodec_alloc_context3(codec);
    if (!codec_context_) {
      return errors::Internal("could not allocate codec context");
    }
    // Copy codec parameters from input stream to output codec context
    if (avcodec_parameters_to_context(codec_context_, media_stream->codecpar) < 0) {
      return errors::Internal("could not copy codec parameters from input stream to output codec context");
    }
#else
    codec_context_ = media_stream->codec;
    // Find decoder for the stream
    AVCodec *codec = avcodec_find_decoder(codec_context_->codec_id);
    if (!codec) {
      return errors::Internal("could not find media codec: ", codec_context_->codec_id);
    }
#endif
    // Initialize the decoders
    // TODO (yongtang): avcodec_open2 is not thread-safe
    AVDictionary *opts = NULL;
    if (avcodec_open2(codec_context_, codec, &opts) < 0) {
      return errors::Internal("could not open codec");
    }

    // Allocate frame
#if LIBAVCODEC_VERSION_MAJOR > 54
    frame_ = av_frame_alloc();
#else
    frame_ = avcodec_alloc_frame();
#endif
    if (!frame_) {
      return errors::Internal("could not allocate frame");
    }

    // Initialize packet
    av_init_packet(&packet_);
    packet_.data = NULL;
    packet_.size = 0;

    return Status::OK();
}

bool FFmpegReader::ReadAhead(bool first)
{
    while (packet_more_ || frame_more_) {
      while (packet_more_) {
        packet_more_ = false;
	if (packet_.stream_index == stream_index_) {
          int got_frame = 0;
          int decoded = DecodeFrame(&got_frame);
          if (!frame_more_ && got_frame) {
            // This is the cached packet.
            ProcessFrame();
            packet_more_ = true;
            return true;
          }
          if (decoded >= 0 && got_frame) {
            ProcessFrame();
	    if (packet_.data) {
	      packet_.data += decoded;
	      packet_.size -= decoded;
              packet_more_ = (packet_.size > 0);
	    }
            return true;
          }
	}
      }
      if (frame_more_) {
        // If this is not the first time, unref the packet
#if LIBAVCODEC_VERSION_MAJOR > 54
        av_packet_unref(&packet_);
#else
	// NOTE: libav 9.20 does not need unref or free here.
	// av_packet_unref(&packet_);
#endif
	frame_more_ = (av_read_frame(format_context_, &packet_) == 0);
	if (!frame_more_) {
          // Flush out the cached packet
	  packet_more_ = true;
          packet_.data = NULL;
          packet_.size = 0;
	} else {
	  // More packet to process
          packet_more_ = true;
	}
      }
    }
    return false;
}

FFmpegReader::~FFmpegReader() {
#if LIBAVCODEC_VERSION_MAJOR > 54
    av_frame_free(&frame_);
#else
    avcodec_free_frame(&frame_);
#endif
#if LIBAVCODEC_VERSION_MAJOR > 56
    avcodec_free_context(&codec_context_);
#endif
    avformat_close_input(&format_context_);
    av_free(format_context_);
    if (io_context_ != NULL) {
      av_free(io_context_);
    }
}

}  // namespace data
}  // namespace tensorflow
<commit_msg>Add option to set FFmpeg log level through environmental variable (#530)<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/lib/io/buffered_inputstream.h"
#include "tensorflow/core/platform/file_system.h"

extern "C" {

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libavutil/log.h"
#include "libswscale/swscale.h"
#include <dlfcn.h>

}

#include "kernels/ffmpeg_reader.h"

namespace tensorflow {
namespace data {

static mutex mu(LINKER_INITIALIZED);
static unsigned count(0);
void FFmpegReaderInit() {
  mutex_lock lock(mu);
  count++;
  if (count == 1) {
    // Set log level if needed
    static const struct { const char *name; int level; } log_levels[] = {
        { "quiet"  , AV_LOG_QUIET   },
        { "panic"  , AV_LOG_PANIC   },
        { "fatal"  , AV_LOG_FATAL   },
        { "error"  , AV_LOG_ERROR   },
        { "warning", AV_LOG_WARNING },
        { "info"   , AV_LOG_INFO    },
        { "verbose", AV_LOG_VERBOSE },
        { "debug"  , AV_LOG_DEBUG   },
        // { "trace"  , AV_LOG_TRACE   },
    };
    const char* log_level_name = getenv("FFMPEG_LOG_LEVEL");
    if (log_level_name != nullptr) {
      string log_level = log_level_name;
      for (size_t i = 0; i < sizeof(log_levels)/sizeof(log_levels[0]); i++) {
        if (log_level == log_levels[i].name) {
          LOG(INFO) << "FFmpeg log level: " << log_level;
          av_log_set_level(log_levels[i].level);
          break;
        }
      }
    }

    // Register all formats and codecs
    av_register_all();
  }
}

static int io_read_packet(void *opaque, uint8_t *buf, int buf_size) {
  FFmpegReader *r = (FFmpegReader *)opaque;
  StringPiece result;
  Status status = r->stream_->Read(r->offset_, buf_size, &result, (char *)buf);
  if (!(status.ok() || errors::IsOutOfRange(status))) {
    return -1;
  }
  r->offset_ += result.size();
  return result.size();
}

static int64_t io_seek(void *opaque, int64_t offset, int whence) {
  FFmpegReader *r = (FFmpegReader *)opaque;
  uint64 file_size = 0;
  Status status = r->stream_->GetFileSize(&file_size);
  if (!status.ok()) {
    return -1;
  }
  switch (whence)
  {
  case SEEK_SET:
    if (offset > file_size) {
      return -1;
    }
    r->offset_ = offset;
    return r->offset_;
  case SEEK_CUR:
    if (r->offset_ + offset > file_size) {
      return -1;
    }
    r->offset_ += offset;
    return r->offset_;
  case SEEK_END:
    if (offset > file_size) {
      return -1;
    }
    r->offset_ = file_size - offset;
    return r->offset_;
  case AVSEEK_SIZE:
    return file_size;
  default:
    break;
  }
  return -1;
}

Status FFmpegReader::InitializeReader()
{
    // Allocate format
    if ((format_context_ = avformat_alloc_context()) == NULL) {
      return errors::InvalidArgument("could not allocate format context");
    }
    // Allocate context
    if ((io_context_ = avio_alloc_context(NULL, 0, 0, this, io_read_packet, NULL, io_seek)) == NULL) {
      return errors::InvalidArgument("could not allocate io context");
    }
    format_context_->pb = io_context_;
    // Open input file, and allocate format context
    if (avformat_open_input(&format_context_, filename_.c_str(), NULL, NULL) < 0) {
      return errors::InvalidArgument("could not open media file: ", filename_);
    }
    // Retrieve stream information
    if (avformat_find_stream_info(format_context_, NULL) < 0) {
      return errors::InvalidArgument("could not find stream information: ", filename_);
    }
    // Find media stream
    if ((stream_index_ = av_find_best_stream(format_context_, MediaType(), -1, -1, NULL, 0)) < 0) {
      return errors::InvalidArgument("could not find media stream: ", filename_);
    }

    AVStream *media_stream = format_context_->streams[stream_index_];
#if LIBAVCODEC_VERSION_MAJOR > 56
    // Find decoder for the stream
    AVCodec *codec = avcodec_find_decoder(media_stream->codecpar->codec_id);
    if (!codec) {
      return errors::Internal("could not find media codec: ", media_stream->codecpar->codec_id);
    }
    // Allocate a codec context for the decoder
    codec_context_ = avcodec_alloc_context3(codec);
    if (!codec_context_) {
      return errors::Internal("could not allocate codec context");
    }
    // Copy codec parameters from input stream to output codec context
    if (avcodec_parameters_to_context(codec_context_, media_stream->codecpar) < 0) {
      return errors::Internal("could not copy codec parameters from input stream to output codec context");
    }
#else
    codec_context_ = media_stream->codec;
    // Find decoder for the stream
    AVCodec *codec = avcodec_find_decoder(codec_context_->codec_id);
    if (!codec) {
      return errors::Internal("could not find media codec: ", codec_context_->codec_id);
    }
#endif
    // Initialize the decoders
    // TODO (yongtang): avcodec_open2 is not thread-safe
    AVDictionary *opts = NULL;
    if (avcodec_open2(codec_context_, codec, &opts) < 0) {
      return errors::Internal("could not open codec");
    }

    // Allocate frame
#if LIBAVCODEC_VERSION_MAJOR > 54
    frame_ = av_frame_alloc();
#else
    frame_ = avcodec_alloc_frame();
#endif
    if (!frame_) {
      return errors::Internal("could not allocate frame");
    }

    // Initialize packet
    av_init_packet(&packet_);
    packet_.data = NULL;
    packet_.size = 0;

    return Status::OK();
}

bool FFmpegReader::ReadAhead(bool first)
{
    while (packet_more_ || frame_more_) {
      while (packet_more_) {
        packet_more_ = false;
	if (packet_.stream_index == stream_index_) {
          int got_frame = 0;
          int decoded = DecodeFrame(&got_frame);
          if (!frame_more_ && got_frame) {
            // This is the cached packet.
            ProcessFrame();
            packet_more_ = true;
            return true;
          }
          if (decoded >= 0 && got_frame) {
            ProcessFrame();
	    if (packet_.data) {
	      packet_.data += decoded;
	      packet_.size -= decoded;
              packet_more_ = (packet_.size > 0);
	    }
            return true;
          }
	}
      }
      if (frame_more_) {
        // If this is not the first time, unref the packet
#if LIBAVCODEC_VERSION_MAJOR > 54
        av_packet_unref(&packet_);
#else
	// NOTE: libav 9.20 does not need unref or free here.
	// av_packet_unref(&packet_);
#endif
	frame_more_ = (av_read_frame(format_context_, &packet_) == 0);
	if (!frame_more_) {
          // Flush out the cached packet
	  packet_more_ = true;
          packet_.data = NULL;
          packet_.size = 0;
	} else {
	  // More packet to process
          packet_more_ = true;
	}
      }
    }
    return false;
}

FFmpegReader::~FFmpegReader() {
#if LIBAVCODEC_VERSION_MAJOR > 54
    av_frame_free(&frame_);
#else
    avcodec_free_frame(&frame_);
#endif
#if LIBAVCODEC_VERSION_MAJOR > 56
    avcodec_free_context(&codec_context_);
#endif
    avformat_close_input(&format_context_);
    av_free(format_context_);
    if (io_context_ != NULL) {
      av_free(io_context_);
    }
}

}  // namespace data
}  // namespace tensorflow
<|endoftext|>


<commit_before>// Copyright 2016 AUV-IITK
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <sstream>  // for converting the command line parameter to integer
#include <string>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <stdio.h>
#include <dynamic_reconfigure/server.h>
#include <hardware_camera/cameraConfig.h>

/*! \file
* \brief super short description
*
* Long decription
*/

double rotation_error;
bool flag;

std::string exec(const char *cmd)
{
  char buffer[128];
  std::string result = "";
  FILE* pipe = popen(cmd, "r");
  if (!pipe)
    throw std::runtime_error("popen() failed!");
  while (!feof(pipe))
  {
    if (fgets(buffer, 128, pipe) != NULL)
      result += buffer;
  }
  return result;
}

bool checkIfFrontisZero()
{
  std::string serialNumber = "243FA8C0";
  const char *command = "udevadm info -a -p  $(udevadm info -q path -n /dev/video0)";
  std::string video0 = exec(command);
  if (video0.find(serialNumber))
    return true;
  return false;
}

cv::Mat rotate(cv::Mat src, double angle)
{
  // get rotation matrix for rotating the image around its center
  cv::Point2f center(src.cols/2.0, src.rows/2.0);
  cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
  // determine bounding rectangle
  cv::Rect bbox = cv::RotatedRect(center,src.size(), angle).boundingRect();
  // adjust transformation matrix
  rot.at<double>(0,2) += bbox.width/2.0 - center.x;
  rot.at<double>(1,2) += bbox.height/2.0 - center.y;
  cv::Mat dst;
  cv::warpAffine(src, dst, rot, bbox.size());
  return dst;
}

// dynamic reconfig
void callback(hardware_camera::cameraConfig &config, double level)
{
  ROS_INFO("%s Vide_pub: Reconfigure Request: angle= %f flag= %d", ros::this_node::getName().c_str(),
           config.angle, config.flag);
  rotation_error = config.angle;
  flag = config.flag;
}

/*! member description */
int main(int argc, char **argv)
{
  ros::init(argc, argv, "image_publisher");
  ros::NodeHandle nh;

  // register dynamic reconfig server.
  dynamic_reconfigure::Server<hardware_camera::cameraConfig> server;
  dynamic_reconfigure::Server<hardware_camera::cameraConfig>::CallbackType f;
  f = boost::bind(&callback, _1, _2);
  server.setCallback(f);

  // get launch file constants
  double error_angle; int flag_integer;
  nh.getParam("cameras/error_angle", error_angle);
  nh.getParam("cameras/flag", flag_integer);

  // set launch file constants
  hardware_camera::cameraConfig config;
  config.angle = error_angle;
  config.flag = (flag_integer==1) ? true : false;
  callback(config, 0);

  std::string bottom_topic_name, front_topic_name, node_name;
  int front_camera_number, bottom_camera_number;
  front_topic_name = "/varun/sensors/front_camera/image_raw";
  bottom_topic_name = "/varun/sensors/bottom_camera/image_raw";
  image_transport::ImageTransport it(nh);
  image_transport::Publisher front_pub = it.advertise(front_topic_name, 1);
  image_transport::Publisher bottom_pub = it.advertise(bottom_topic_name, 1);

  if (checkIfFrontisZero())
  {
    front_camera_number = 0;
    bottom_camera_number = 1;
  }
  else
  {
    front_camera_number = 1;
    bottom_camera_number = 0;
  }

  cv::VideoCapture front_cap(front_camera_number);
  cv::VideoCapture bottom_cap(bottom_camera_number);
  cv::Mat front_frame, bottom_frame;
  sensor_msgs::ImagePtr front_msg, bottom_msg;
  int loopRate = 10;
  ros::Rate loop_rate(loopRate);
  while (nh.ok())
  {
    if (flag) {
      front_cap >> bottom_frame;
      bottom_cap >> front_frame;
    } else {
      front_cap >> front_frame;
      bottom_cap >> bottom_frame;
    }
    // Check if grabbed frame is actually full with some content
    if (!front_frame.empty())
    {
      cv::Mat final_front_frame = rotate(front_frame, rotation_error);
      front_msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", final_front_frame).toImageMsg();
      front_pub.publish(front_msg);
    }
    // Check if grabbed frame is actually full with some content
    if (!bottom_frame.empty())
    {
      bottom_msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", bottom_frame).toImageMsg();
      bottom_pub.publish(bottom_msg);
    }
    ros::spinOnce();
  }
}
<commit_msg>remove lint errors<commit_after>// Copyright 2016 AUV-IITK
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <sstream>  // for converting the command line parameter to integer
#include <string>
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <stdio.h>
#include <dynamic_reconfigure/server.h>
#include <hardware_camera/cameraConfig.h>

/*! \file
* \brief super short description
*
* Long decription
*/

double rotation_error;
bool flag;

std::string exec(const char *cmd)
{
  char buffer[128];
  std::string result = "";
  FILE *pipe = popen(cmd, "r");
  if (!pipe)
    throw std::runtime_error("popen() failed!");
  while (!feof(pipe))
  {
    if (fgets(buffer, 128, pipe) != NULL)
      result += buffer;
  }
  return result;
}

bool checkIfFrontisZero()
{
  std::string serialNumber = "243FA8C0";
  const char *command = "udevadm info -a -p  $(udevadm info -q path -n /dev/video0)";
  std::string video0 = exec(command);
  if (video0.find(serialNumber))
    return true;
  return false;
}

cv::Mat rotate(cv::Mat src, double angle)
{
  // get rotation matrix for rotating the image around its center
  cv::Point2f center(src.cols / 2.0, src.rows / 2.0);
  cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
  // determine bounding rectangle
  cv::Rect bbox = cv::RotatedRect(center, src.size(), angle).boundingRect();
  // adjust transformation matrix
  rot.at<double>(0, 2) += bbox.width / 2.0 - center.x;
  rot.at<double>(1, 2) += bbox.height / 2.0 - center.y;
  cv::Mat dst;
  cv::warpAffine(src, dst, rot, bbox.size());
  return dst;
}

// dynamic reconfig
void callback(hardware_camera::cameraConfig &config, double level)
{
  ROS_INFO("%s Vide_pub: Reconfigure Request: angle= %f flag= %d", ros::this_node::getName().c_str(), config.angle,
           config.flag);
  rotation_error = config.angle;
  flag = config.flag;
}

/*! member description */
int main(int argc, char **argv)
{
  ros::init(argc, argv, "image_publisher");
  ros::NodeHandle nh;

  // register dynamic reconfig server.
  dynamic_reconfigure::Server<hardware_camera::cameraConfig> server;
  dynamic_reconfigure::Server<hardware_camera::cameraConfig>::CallbackType f;
  f = boost::bind(&callback, _1, _2);
  server.setCallback(f);

  // get launch file constants
  double error_angle;
  int flag_integer;
  nh.getParam("cameras/error_angle", error_angle);
  nh.getParam("cameras/flag", flag_integer);

  // set launch file constants
  hardware_camera::cameraConfig config;
  config.angle = error_angle;
  config.flag = (flag_integer == 1) ? true : false;
  callback(config, 0);

  std::string bottom_topic_name, front_topic_name, node_name;
  int front_camera_number, bottom_camera_number;
  front_topic_name = "/varun/sensors/front_camera/image_raw";
  bottom_topic_name = "/varun/sensors/bottom_camera/image_raw";
  image_transport::ImageTransport it(nh);
  image_transport::Publisher front_pub = it.advertise(front_topic_name, 1);
  image_transport::Publisher bottom_pub = it.advertise(bottom_topic_name, 1);

  if (checkIfFrontisZero())
  {
    front_camera_number = 0;
    bottom_camera_number = 1;
  }
  else
  {
    front_camera_number = 1;
    bottom_camera_number = 0;
  }

  cv::VideoCapture front_cap(front_camera_number);
  cv::VideoCapture bottom_cap(bottom_camera_number);
  cv::Mat front_frame, bottom_frame;
  sensor_msgs::ImagePtr front_msg, bottom_msg;
  int loopRate = 10;
  ros::Rate loop_rate(loopRate);
  while (nh.ok())
  {
    if (flag)
    {
      front_cap >> bottom_frame;
      bottom_cap >> front_frame;
    }
    else
    {
      front_cap >> front_frame;
      bottom_cap >> bottom_frame;
    }
    // Check if grabbed frame is actually full with some content
    if (!front_frame.empty())
    {
      cv::Mat final_front_frame = rotate(front_frame, rotation_error);
      front_msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", final_front_frame).toImageMsg();
      front_pub.publish(front_msg);
    }
    // Check if grabbed frame is actually full with some content
    if (!bottom_frame.empty())
    {
      bottom_msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", bottom_frame).toImageMsg();
      bottom_pub.publish(bottom_msg);
    }
    ros::spinOnce();
  }
}
<|endoftext|>