<commit_before>/*
 * Copyright (c) 2009 Steven Noonan <steven@uplinklabs.net>
 *                and Miah Clayton <miah@ferrousmoon.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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 AUTHOR ``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 AUTHOR 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 "universal_include.h"

#if defined ( TARGET_COMPILER_VC ) || defined ( TARGET_COMPILER_ICC )
#   pragma comment (lib, "unrar.lib")
#endif

#include "App/app.h"
#include "App/file_utils.h"
#include "App/resource.h"

#ifndef TARGET_OS_WINDOWS
inline static void strlwr ( char *_string )
{
    for ( char *p = _string; p && *p != '\0'; p++ )
        *p = tolower(*p);
}
#endif

Resource::Resource()
{
}

Resource::~Resource()
{
    Data::DArray<MemMappedFile *> *files = m_resourceFiles.ConvertToDArray();
    for ( size_t i = 0; i < files->size(); i++ )
    {
        if ( !files->valid ( i ) ) continue;
        delete files->get ( i );
    }
    delete files;
}

void Resource::ParseArchive ( const char *_dataFile, const char *_password )
{
    if (!FileExists( _dataFile))
        return;

    UncompressedArchive    *mainData = NULL;

    try
    {
        mainData = new UncompressedArchive(_dataFile, _password);
    }
    catch( ... )
    {
        return;
    }

    for (size_t i = 0; i < mainData->m_numFiles; ++i)
    {
        MemMappedFile *file = mainData->m_files[i];
        if (file->m_size > 0)
        {
            strlwr(file->m_filename);

            // Subsequent archives may override existing resources

            MemMappedFile *oldFile = m_resourceFiles.find(file->m_filename, NULL);
            if (oldFile) {
                m_resourceFiles.erase(file->m_filename);
                delete oldFile;
            }

            m_resourceFiles.insert(file->m_filename, file);
        }
    }

    delete mainData;
}

BinaryReader *Resource::GetBinaryReader ( char const *_filename )
{
    BinaryReader *reader = NULL;
    char fullFilename[256];

    // TODO: Implement moddability and themes, etc.
#if 0
    if ( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }
#endif

    if ( !reader )
    {
        sprintf( fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }

    if ( !reader )
    {
        if ( FileExists ( _filename ) ) reader = new BinaryFileReader(_filename);
    }

    if ( !reader )
    {
        MemMappedFile *mmfile = GetUncompressedFile(_filename);
        if (mmfile) reader = new BinaryDataReader(mmfile->m_data, mmfile->m_size, _filename);
    }

    return reader;
}

SDL_Surface *Resource::GetImage ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    SDL_Surface *surf = NULL;

    if ( !surf )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        surf = IMG_Load ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !surf && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        surf = IMG_Load_RW ( data, 0 );
        CrbReleaseAssert ( surf );
    }

    return surf;
}

#ifdef USE_SDLMIXER
Mix_Chunk *Resource::GetSound ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    Mix_Chunk *chunk = NULL;

    if ( !chunk )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        chunk = Mix_LoadWAV ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !chunk && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        chunk = Mix_LoadWAV_RW ( data, 0 );
    }

    return chunk;
}
#endif

TextReader *Resource::GetTextReader(char const *_filename)
{
    TextReader *reader = NULL;
    char fullFilename[256];

    fullFilename[0] = 0;

#if 0
    if( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if( DoesFileExist(fullFilename) )
            reader = new TextFileReader(fullFilename);

#ifdef TARGET_OS_VISTA
        // The Oberon build bundles the Perdition mod
        if( !reader )
        {
            sprintf( fullFilename, "mods/%s/%s", m_modName, _filename );
            if( DoesFileExist(fullFilename) )
                reader = new TextFileReader(fullFilename);
        }
#endif
    }
#endif

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        if ( FileExists ( fullFilename ) )
            reader = new TextFileReader(fullFilename);
    }

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        MemMappedFile *mmfile = GetUncompressedFile(fullFilename);
        if ( mmfile )
            reader = new TextDataReader((char*)mmfile->m_data, mmfile->m_size, fullFilename);
    }

    return reader;
}

MemMappedFile *Resource::GetUncompressedFile(char const *_filename)
{
	char           fullFilename[2048];

	MemMappedFile *file = NULL;

	if (!file) {
		sprintf(fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	if (!file) {
		file = m_resourceFiles.find(_filename, NULL);
	}

	return file;
}
<commit_msg>resource.cpp: fix font loader<commit_after>/*
 * Copyright (c) 2009 Steven Noonan <steven@uplinklabs.net>
 *                and Miah Clayton <miah@ferrousmoon.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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 AUTHOR ``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 AUTHOR 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 "universal_include.h"

#if defined ( TARGET_COMPILER_VC ) || defined ( TARGET_COMPILER_ICC )
#   pragma comment (lib, "unrar.lib")
#endif

#include "App/app.h"
#include "App/file_utils.h"
#include "App/resource.h"

#ifndef TARGET_OS_WINDOWS
inline static void strlwr ( char *_string )
{
    for ( char *p = _string; p && *p != '\0'; p++ )
        *p = tolower(*p);
}
#endif

Resource::Resource()
{
}

Resource::~Resource()
{
    Data::DArray<MemMappedFile *> *files = m_resourceFiles.ConvertToDArray();
    for ( size_t i = 0; i < files->size(); i++ )
    {
        if ( !files->valid ( i ) ) continue;
        delete files->get ( i );
    }
    delete files;
}

void Resource::ParseArchive ( const char *_dataFile, const char *_password )
{
    if (!FileExists( _dataFile))
        return;

    UncompressedArchive    *mainData = NULL;

    try
    {
        mainData = new UncompressedArchive(_dataFile, _password);
    }
    catch( ... )
    {
        return;
    }

    for (size_t i = 0; i < mainData->m_numFiles; ++i)
    {
        MemMappedFile *file = mainData->m_files[i];
        if (file->m_size > 0)
        {
            strlwr(file->m_filename);

            // Subsequent archives may override existing resources

            MemMappedFile *oldFile = m_resourceFiles.find(file->m_filename, NULL);
            if (oldFile) {
                m_resourceFiles.erase(file->m_filename);
                delete oldFile;
            }

            m_resourceFiles.insert(file->m_filename, file);
        }
    }

    delete mainData;
}

BinaryReader *Resource::GetBinaryReader ( char const *_filename )
{
    BinaryReader *reader = NULL;
    char fullFilename[256];

    // TODO: Implement moddability and themes, etc.
#if 0
    if ( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }
#endif

    if ( !reader )
    {
        sprintf( fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }

    if ( !reader )
    {
        if ( FileExists ( _filename ) ) reader = new BinaryFileReader(_filename);
    }

    if ( !reader )
    {
        MemMappedFile *mmfile = GetUncompressedFile(_filename);
        if (mmfile) reader = new BinaryDataReader(mmfile->m_data, mmfile->m_size, _filename);
    }

    return reader;
}

SDL_Surface *Resource::GetImage ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    SDL_Surface *surf = NULL;

    if ( !surf )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        surf = IMG_Load ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !surf && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        surf = IMG_Load_RW ( data, 0 );
        CrbReleaseAssert ( surf );
    }

    return surf;
}

#ifdef USE_SDLMIXER
Mix_Chunk *Resource::GetSound ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    Mix_Chunk *chunk = NULL;

    if ( !chunk )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        chunk = Mix_LoadWAV ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !chunk && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        chunk = Mix_LoadWAV_RW ( data, 0 );
    }

    return chunk;
}
#endif

TextReader *Resource::GetTextReader(char const *_filename)
{
    TextReader *reader = NULL;
    char fullFilename[256];

    fullFilename[0] = 0;

#if 0
    if( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if( DoesFileExist(fullFilename) )
            reader = new TextFileReader(fullFilename);

#ifdef TARGET_OS_VISTA
        // The Oberon build bundles the Perdition mod
        if( !reader )
        {
            sprintf( fullFilename, "mods/%s/%s", m_modName, _filename );
            if( DoesFileExist(fullFilename) )
                reader = new TextFileReader(fullFilename);
        }
#endif
    }
#endif

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        if ( FileExists ( fullFilename ) )
            reader = new TextFileReader(fullFilename);
    }

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        MemMappedFile *mmfile = GetUncompressedFile(fullFilename);
        if ( mmfile )
            reader = new TextDataReader((char*)mmfile->m_data, mmfile->m_size, fullFilename);
    }

    return reader;
}

MemMappedFile *Resource::GetUncompressedFile(char const *_filename)
{
	char           fullFilename[2048];

	MemMappedFile *file = NULL;

	if (!file) {
		file = m_resourceFiles.find(_filename, NULL);
	}

	if (!file) {
		sprintf(fullFilename, "%s", _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			m_resourceFiles.insert(_filename, file);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	if (!file) {
		sprintf(fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			m_resourceFiles.insert(_filename, file);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	return file;
}
<|endoftext|>


<commit_before>#include <memory>

#include <possumwood_sdk/node_implementation.h>
#include <possumwood_sdk/source_editor.h>

#include <QPainter>
#include <QPushButton>
#include <QMenu>

#include <lualib.h>
#include <luabind/luabind.hpp>
#include <luabind/class_info.hpp>

#include "datatypes/state.h"
#include "datatypes/context.h"

namespace {

dependency_graph::InAttr<std::string> a_src;
dependency_graph::InAttr<possumwood::lua::Context> a_context;
dependency_graph::OutAttr<std::shared_ptr<const possumwood::lua::State>> a_state;

class Editor : public possumwood::SourceEditor {
	public:
		Editor() : SourceEditor(a_src), m_popup(nullptr) {
			m_varsButton = new QPushButton("Globals");
			buttonsLayout()->insertWidget(0, m_varsButton);

			widget()->connect(m_varsButton, &QPushButton::pressed, [this]() {
				// lazily populate variable list on first click
				if(m_popup == nullptr)
					populateVariableList();

				// if the populating succeeded, show the menu
				if(m_popup)
					m_popup->popup(
						m_varsButton->mapToGlobal(QPoint(0,-m_popup->sizeHint().height()))
					);
			});
		}

	protected:
		virtual void valueChanged(const dependency_graph::Attr& attr) override {
			// update the menu on each change of the "state" attribute (i.e., evaluation)
			if(attr == a_state && values().get(a_state) != nullptr) {
				if(m_popup) {
					m_popup->deleteLater();
					m_popup = nullptr;
				}
			}

			else
				SourceEditor::valueChanged(attr);
		}

		std::string luaType(const luabind::object& o) {
			int type = luabind::type(o);

			switch(type) {
				case LUA_TNONE: return "none";
				case LUA_TNIL: return "nil";
				case LUA_TBOOLEAN: return "bool";
				case LUA_TLIGHTUSERDATA: return "light object";
				case LUA_TNUMBER: return "number";
				case LUA_TSTRING: return "string";
				case LUA_TTABLE: return "table";
				case LUA_TFUNCTION: return "function";
				case LUA_TTHREAD: return "thread";
				case LUA_TUSERDATA:
					if(isClassInstance(o))
						return "object";
					else if(isClass(o))
						return "class";
					else
						return "lua class";
			}

			return "unknown";
		}

		// add one item to the menu
		// TODO: extend to add values as well
		void addItem(QMenu* menu, const luabind::object& o, const std::string& name) {
			menu->addAction((name + "\t" + luaType(o)).c_str());
		}

		// add a submenu to the popup
		QMenu* addMenu(QMenu* menu, const luabind::object& o, const std::string& name) {
			return menu->addMenu((name + "\t" + luaType(o)).c_str());
		}

		void parseClass(QMenu* menu, const luabind::object& o, int recurse) {
			o.push(o.interpreter());
			luabind::detail::object_rep* obj = luabind::detail::get_instance(o.interpreter(), -1);
			if(obj && obj->crep()) {
				obj->crep()->get_table(o.interpreter());
				luabind::object ooo(luabind::from_stack(o.interpreter(), -1));

				if(recurse > 0)
					parseGlobals(menu, ooo, recurse-1);

				lua_settop(o.interpreter(), 0);
			}
		}

		bool isClass(const luabind::object& o) {
			if(o.is_valid()) {
				auto meta = luabind::getmetatable(o);

				if(meta.is_valid() && luabind::type(meta) == LUA_TTABLE) {
					for(luabind::iterator j(meta); j != luabind::iterator(); ++j) {
						auto key = luabind::object_cast_nothrow<std::string>(j.key());
						if(key && *key == "__luabind_classrep")
							return true;
					}
				}
			}

			return false;
		}

		bool isClassInstance(const luabind::object& o) {
			auto meta = luabind::getmetatable(o);

			if(luabind::type(meta) == LUA_TTABLE) {
				for(luabind::iterator j(meta); j != luabind::iterator(); ++j) {
					auto key = luabind::object_cast_nothrow<std::string>(j.key());
					if(key && *key == "__luabind_class")
						return true;
				}
			}

			return false;
		}

		// parses the metadata table
		void parseMeta(QMenu* menu, const luabind::object& o, int recurse = 10) {
			if(o.is_valid()) {
				assert(!isClass(o));

				// adds all members for this instance
				if(isClassInstance(o))
					parseClass(menu, o, recurse-1);

				// just descends recursively
				else {
					auto meta = luabind::getmetatable(o);

					if(meta.is_valid() && luabind::type(meta) == LUA_TTABLE)
						parseGlobals(menu, meta, recurse-1);
				}
			}
		}

		// parse a table and add its content to the menu - first explicitly on globals, then recurse
		void parseGlobals(QMenu* menu, const luabind::object& o, int recurse = 10) {
			assert(o.is_valid());
			assert(luabind::type(o) == LUA_TTABLE);

			// iterate over the items of this table
			for(luabind::iterator j(o), end; j != end; ++j) {
				luabind::object obj = *j;

				if(obj.is_valid()) {
					// try to obtain a key as a string - this might be a number of an array, so treat that appropriately
					auto key = luabind::object_cast_nothrow<std::string>(j.key());
					if(key) {
						// the current object is a table - add a submenu and proceed recursively
						if(luabind::type(obj) == LUA_TTABLE) {
							QMenu* m = addMenu(menu, obj, *key);

							if(recurse > 0)
								parseGlobals(m, obj, recurse - 1);
						}

						// a luabind class - only show it as a single item
						else if(luabind::type(obj) == LUA_TUSERDATA && isClass(obj))
							addItem(menu, obj, *key);

						// a userdata object - either an inbuilt class or a luabind instance
						else if(luabind::type(obj) == LUA_TUSERDATA) {
							if(recurse > 0) {
								QMenu* m = addMenu(menu, obj, *key);
								parseMeta(m, obj, recurse - 1);
							}
						}

						// functions, numbers, strings ... just add them to the menu
						else
							addItem(menu, obj, *key);
					}
				}
			}
		}

		void populateVariableList() {
			if(m_popup)
				m_popup->deleteLater();

			m_popup = new QMenu(m_varsButton);

			m_popup->connect(m_popup, &QMenu::triggered, [this](QAction* action) {
				QString text = action->text();
				while(!text.isEmpty() && !QChar(text[0]).isLetterOrNumber())
					text = text.mid(1, text.length()-1);
				if(text.indexOf('\t') >= 0)
					text = text.mid(0, text.indexOf('\t'));

				editorWidget()->insertPlainText(text);
			});

			// parse the global variables of the state from the output (includes injected vars and modules)
			std::shared_ptr<const possumwood::lua::State> state = values().get(a_state);
			if(state)
				parseGlobals(m_popup, state->globals());
		}

	private:
		QPushButton* m_varsButton;

		QMenu* m_popup;
};

dependency_graph::State compute(dependency_graph::Values& data) {
	dependency_graph::State result;

	const std::string& src = data.get(a_src);

	// Create a new lua state
	std::shared_ptr<possumwood::lua::State> state(new possumwood::lua::State(data.get(a_context)));

	try {
		// load all standard Lua libraries
		// luaL_openlibs(*state);

		// luabind class info function - allows introspection of luabind classes
		luabind::bind_class_info(*state);

		// evaluate our script
		int err = luaL_dostring(*state, src.c_str());
		if(err)
			throw std::runtime_error(lua_tostring(*state, -1));

		// and return the resulting state
		data.set(a_state, std::shared_ptr<const possumwood::lua::State>(state));
	}
	catch(const luabind::error& err) {
		throw std::runtime_error(lua_tostring(err.state(), -1));
	}

	return result;
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_src, "source", std::string("variable = 10\n"));
	meta.addAttribute(a_context, "context", possumwood::lua::Context(), possumwood::Metadata::kVertical);
	meta.addAttribute(a_state, "state");

	meta.addInfluence(a_src, a_state);
	meta.addInfluence(a_context, a_state);

	meta.setCompute(&compute);
	meta.setEditor<Editor>();
}

possumwood::NodeImplementation s_impl("lua/script", init);

}
<commit_msg>Globals menu is now sorted alphabetically<commit_after>#include <memory>

#include <possumwood_sdk/node_implementation.h>
#include <possumwood_sdk/source_editor.h>

#include <QPainter>
#include <QPushButton>
#include <QMenu>

#include <lualib.h>
#include <luabind/luabind.hpp>
#include <luabind/class_info.hpp>

#include "datatypes/state.h"
#include "datatypes/context.h"

namespace {

dependency_graph::InAttr<std::string> a_src;
dependency_graph::InAttr<possumwood::lua::Context> a_context;
dependency_graph::OutAttr<std::shared_ptr<const possumwood::lua::State>> a_state;

class Editor : public possumwood::SourceEditor {
	public:
		Editor() : SourceEditor(a_src), m_popup(nullptr) {
			m_varsButton = new QPushButton("Globals");
			buttonsLayout()->insertWidget(0, m_varsButton);

			widget()->connect(m_varsButton, &QPushButton::pressed, [this]() {
				// lazily populate variable list on first click
				if(m_popup == nullptr)
					populateVariableList();

				// if the populating succeeded, show the menu
				if(m_popup)
					m_popup->popup(
						m_varsButton->mapToGlobal(QPoint(0,-m_popup->sizeHint().height()))
					);
			});
		}

	protected:
		virtual void valueChanged(const dependency_graph::Attr& attr) override {
			// update the menu on each change of the "state" attribute (i.e., evaluation)
			if(attr == a_state && values().get(a_state) != nullptr) {
				if(m_popup) {
					m_popup->deleteLater();
					m_popup = nullptr;
				}
			}

			else
				SourceEditor::valueChanged(attr);
		}

		std::string luaType(const luabind::object& o) {
			int type = luabind::type(o);

			switch(type) {
				case LUA_TNONE: return "none";
				case LUA_TNIL: return "nil";
				case LUA_TBOOLEAN: return "bool";
				case LUA_TLIGHTUSERDATA: return "light object";
				case LUA_TNUMBER: return "number";
				case LUA_TSTRING: return "string";
				case LUA_TTABLE: return "table";
				case LUA_TFUNCTION: return "function";
				case LUA_TTHREAD: return "thread";
				case LUA_TUSERDATA:
					if(isClassInstance(o))
						return "object";
					else if(isClass(o))
						return "class";
					else
						return "lua class";
			}

			return "unknown";
		}

		// sorting mechanism for new items
		QAction* findPosition(QMenu* menu, const QString& name) {
			QList<QAction*> actions = menu->actions();

			// find the item
			auto it = std::lower_bound(actions.begin(), actions.end(), name, [](QAction* a, const QString& n) {
				if(a != nullptr)
					return a->text().mid(0, a->text().indexOf('\t')) < n;
				return true;
			});

			// return the value if valid, null otherwise
			if(it != actions.end())
				return *it;
			return nullptr;
		}

		// add one item to the menu
		// TODO: extend to add values as well
		void addItem(QMenu* menu, const luabind::object& o, const std::string& name) {
			QAction* newAction = new QAction(QString::fromStdString(name + "\t" + luaType(o)));

			menu->insertAction(findPosition(menu, name.c_str()), newAction);
		}

		// add a submenu to the popup
		QMenu* addMenu(QMenu* menu, const luabind::object& o, const std::string& name) {
			QMenu* newMenu = new QMenu(QString::fromStdString(name + "\t" + luaType(o)));

			menu->insertMenu(findPosition(menu, name.c_str()), newMenu);

			return newMenu;
		}

		void parseClass(QMenu* menu, const luabind::object& o, int recurse) {
			o.push(o.interpreter());
			luabind::detail::object_rep* obj = luabind::detail::get_instance(o.interpreter(), -1);
			if(obj && obj->crep()) {
				obj->crep()->get_table(o.interpreter());
				luabind::object ooo(luabind::from_stack(o.interpreter(), -1));

				if(recurse > 0)
					parseGlobals(menu, ooo, recurse-1);

				lua_settop(o.interpreter(), 0);
			}
		}

		bool isClass(const luabind::object& o) {
			if(o.is_valid()) {
				auto meta = luabind::getmetatable(o);

				if(meta.is_valid() && luabind::type(meta) == LUA_TTABLE) {
					for(luabind::iterator j(meta); j != luabind::iterator(); ++j) {
						auto key = luabind::object_cast_nothrow<std::string>(j.key());
						if(key && *key == "__luabind_classrep")
							return true;
					}
				}
			}

			return false;
		}

		bool isClassInstance(const luabind::object& o) {
			auto meta = luabind::getmetatable(o);

			if(luabind::type(meta) == LUA_TTABLE) {
				for(luabind::iterator j(meta); j != luabind::iterator(); ++j) {
					auto key = luabind::object_cast_nothrow<std::string>(j.key());
					if(key && *key == "__luabind_class")
						return true;
				}
			}

			return false;
		}

		// parses the metadata table
		void parseMeta(QMenu* menu, const luabind::object& o, int recurse = 10) {
			if(o.is_valid()) {
				assert(!isClass(o));

				// adds all members for this instance
				if(isClassInstance(o))
					parseClass(menu, o, recurse-1);

				// just descends recursively
				else {
					auto meta = luabind::getmetatable(o);

					if(meta.is_valid() && luabind::type(meta) == LUA_TTABLE)
						parseGlobals(menu, meta, recurse-1);
				}
			}
		}

		// parse a table and add its content to the menu - first explicitly on globals, then recurse
		void parseGlobals(QMenu* menu, const luabind::object& o, int recurse = 10) {
			assert(o.is_valid());
			assert(luabind::type(o) == LUA_TTABLE);

			// iterate over the items of this table
			for(luabind::iterator j(o), end; j != end; ++j) {
				luabind::object obj = *j;

				if(obj.is_valid()) {
					// try to obtain a key as a string - this might be a number of an array, so treat that appropriately
					auto key = luabind::object_cast_nothrow<std::string>(j.key());
					if(key) {
						// the current object is a table - add a submenu and proceed recursively
						if(luabind::type(obj) == LUA_TTABLE) {
							QMenu* m = addMenu(menu, obj, *key);

							if(recurse > 0)
								parseGlobals(m, obj, recurse - 1);
						}

						// a luabind class - only show it as a single item
						else if(luabind::type(obj) == LUA_TUSERDATA && isClass(obj))
							addItem(menu, obj, *key);

						// a userdata object - either an inbuilt class or a luabind instance
						else if(luabind::type(obj) == LUA_TUSERDATA) {
							if(recurse > 0) {
								QMenu* m = addMenu(menu, obj, *key);
								parseMeta(m, obj, recurse - 1);
							}
						}

						// functions, numbers, strings ... just add them to the menu
						else
							addItem(menu, obj, *key);
					}
				}
			}
		}

		void populateVariableList() {
			if(m_popup)
				m_popup->deleteLater();

			m_popup = new QMenu(m_varsButton);

			m_popup->connect(m_popup, &QMenu::triggered, [this](QAction* action) {
				QString text = action->text();
				while(!text.isEmpty() && !QChar(text[0]).isLetterOrNumber())
					text = text.mid(1, text.length()-1);
				if(text.indexOf('\t') >= 0)
					text = text.mid(0, text.indexOf('\t'));

				editorWidget()->insertPlainText(text);
			});

			// parse the global variables of the state from the output (includes injected vars and modules)
			std::shared_ptr<const possumwood::lua::State> state = values().get(a_state);
			if(state)
				parseGlobals(m_popup, state->globals());
		}

	private:
		QPushButton* m_varsButton;

		QMenu* m_popup;
};

dependency_graph::State compute(dependency_graph::Values& data) {
	dependency_graph::State result;

	const std::string& src = data.get(a_src);

	// Create a new lua state
	std::shared_ptr<possumwood::lua::State> state(new possumwood::lua::State(data.get(a_context)));

	try {
		// load all standard Lua libraries
		// luaL_openlibs(*state);

		// luabind class info function - allows introspection of luabind classes
		luabind::bind_class_info(*state);

		// evaluate our script
		int err = luaL_dostring(*state, src.c_str());
		if(err)
			throw std::runtime_error(lua_tostring(*state, -1));

		// and return the resulting state
		data.set(a_state, std::shared_ptr<const possumwood::lua::State>(state));
	}
	catch(const luabind::error& err) {
		throw std::runtime_error(lua_tostring(err.state(), -1));
	}

	return result;
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_src, "source", std::string("variable = 10\n"));
	meta.addAttribute(a_context, "context", possumwood::lua::Context(), possumwood::Metadata::kVertical);
	meta.addAttribute(a_state, "state");

	meta.addInfluence(a_src, a_state);
	meta.addInfluence(a_context, a_state);

	meta.setCompute(&compute);
	meta.setEditor<Editor>();
}

possumwood::NodeImplementation s_impl("lua/script", init);

}
<|endoftext|>


<commit_before>// Copyright 2010-2013 Google
// 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 <string>
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/hash.h"
#include "base/map_util.h"
#include "flatzinc2/model.h"
#include "flatzinc2/solver.h"
#include "constraint_solver/constraint_solver.h"
#include "util/string_array.h"

namespace operations_research {
IntExpr* FzSolver::GetExpression(const FzArgument& arg) {
  switch (arg.type) {
    case FzArgument::INT_VALUE: {
      return solver_.MakeIntConst(arg.integer_value);
    }
    case FzArgument::INT_VAR_REF: { return Extract(arg.variable); }
    default: {
      LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable";
      return nullptr;
    }
  }
}

std::vector<IntVar*> FzSolver::GetVariableArray(const FzArgument& arg) {
  std::vector<IntVar*> result;
  if (arg.type == FzArgument::INT_VAR_REF_ARRAY) {
    result.resize(arg.variables.size());
    for (int i = 0; i < arg.variables.size(); ++i) {
      result[i] = Extract(arg.variables[i])->Var();
    }
  } else {
    LOG(FATAL) << "Cannot extract " << arg.DebugString()
               << " as a variable array";
  }
  return result;
}

IntExpr* FzSolver::Extract(FzIntegerVariable* const var) {
  IntExpr* result = FindPtrOrNull(extrated_map_, var);
  if (result != nullptr) {
    return result;
  }
  if (var->domain.values.size() == 1) {
    result = solver_.MakeIntConst(var->domain.values.back());
  } else if (var->domain.is_interval) {
    result = solver_.MakeIntVar(var->domain.values[0], var->domain.values[1],
                                var->name);
  } else {
    result = solver_.MakeIntVar(var->domain.values, var->name);
  }
  extrated_map_[var] = result;
  return nullptr;
}

// The format is fixed in the flatzinc specification.
std::string FzSolver::SolutionString(const FzOnSolutionOutput& output) {
  if (output.variable != nullptr) {
    return StringPrintf("%s = %" GG_LL_FORMAT "d;", output.name.c_str(),
                        Extract(output.variable)->Var()->Value());
  } else {
    const int bound_size = output.bounds.size();
    std::string result =
        StringPrintf("%s = array%dd(", output.name.c_str(), bound_size);
    for (int i = 0; i < bound_size; ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d..%" GG_LL_FORMAT "d, ",
                       output.bounds[i].min_value, output.bounds[i].max_value));
    }
    result.append("[");
    for (int i = 0; i < output.flat_variables.size(); ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d",
                       Extract(output.flat_variables[i])->Var()->Value()));
      if (i != output.flat_variables.size() - 1) {
        result.append(", ");
      }
    }
    result.append("]);");
    return result;
  }
  return "";
}

namespace {
struct ConstraintWithIo {
  FzConstraint* ct;
  int index;
  hash_set<FzIntegerVariable*> required;

  ConstraintWithIo(FzConstraint* cte, int i,
                   const hash_set<FzIntegerVariable*> & defined)
      : ct(cte), index(i) {
    hash_set<FzIntegerVariable*> marked;
    for (const FzArgument& arg : ct->arguments) {
      if (arg.variable != nullptr && ContainsKey(defined, arg.variable)) {
        required.insert(arg.variable);
      }
      for (FzIntegerVariable* const var : arg.variables) {
        if (ContainsKey(defined, var)) {
          required.insert(var);
        }
      }
    }
    if (ct->target_variable != nullptr) {
      required.erase(ct->target_variable);
    }
  }
};

struct ConstraintWithIoComparator {
  bool operator()(const ConstraintWithIo& a, const ConstraintWithIo& b) const {
    if (a.ct->target_variable != nullptr &&
        ContainsKey(b.required, a.ct->target_variable)) {
      return true;
    }
    if (b.ct->target_variable != nullptr &&
        ContainsKey(a.required, b.ct->target_variable)) {
      return false;
    }
    return a.index < b.index;
  }
};
}  // namespace

bool FzSolver::Extract() {
  statistics_.BuildStatistics();
  hash_set<FzIntegerVariable*> defined_variables;
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint == nullptr) {
      Extract(var);
    } else {
      defined_variables.insert(var);
    }
  }
  int index = 0;
  std::vector<ConstraintWithIo> to_sort;
  for (FzConstraint* ct : model_.constraints()) {
    if (ct != nullptr && !ct->is_trivially_true) {
      to_sort.push_back(ConstraintWithIo(ct, index++, defined_variables));
    }
  }
  std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
  for (const ConstraintWithIo& ctio : to_sort) {
    ExtractConstraint(ctio.ct);
  }
  return true;
}
}  // namespace operations_research
<commit_msg>first pass at constraint sorting<commit_after>// Copyright 2010-2013 Google
// 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 <string>
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/hash.h"
#include "base/map_util.h"
#include "flatzinc2/model.h"
#include "flatzinc2/solver.h"
#include "constraint_solver/constraint_solver.h"
#include "util/string_array.h"

namespace operations_research {
IntExpr* FzSolver::GetExpression(const FzArgument& arg) {
  switch (arg.type) {
    case FzArgument::INT_VALUE: {
      return solver_.MakeIntConst(arg.integer_value);
    }
    case FzArgument::INT_VAR_REF: { return Extract(arg.variable); }
    default: {
      LOG(FATAL) << "Cannot extract " << arg.DebugString() << " as a variable";
      return nullptr;
    }
  }
}

std::vector<IntVar*> FzSolver::GetVariableArray(const FzArgument& arg) {
  std::vector<IntVar*> result;
  if (arg.type == FzArgument::INT_VAR_REF_ARRAY) {
    result.resize(arg.variables.size());
    for (int i = 0; i < arg.variables.size(); ++i) {
      result[i] = Extract(arg.variables[i])->Var();
    }
  } else {
    LOG(FATAL) << "Cannot extract " << arg.DebugString()
               << " as a variable array";
  }
  return result;
}

IntExpr* FzSolver::Extract(FzIntegerVariable* const var) {
  IntExpr* result = FindPtrOrNull(extrated_map_, var);
  if (result != nullptr) {
    return result;
  }
  if (var->domain.values.size() == 1) {
    result = solver_.MakeIntConst(var->domain.values.back());
  } else if (var->domain.is_interval) {
    result = solver_.MakeIntVar(var->domain.values[0], var->domain.values[1],
                                var->name);
  } else {
    result = solver_.MakeIntVar(var->domain.values, var->name);
  }
  extrated_map_[var] = result;
  return nullptr;
}

// The format is fixed in the flatzinc specification.
std::string FzSolver::SolutionString(const FzOnSolutionOutput& output) {
  if (output.variable != nullptr) {
    return StringPrintf("%s = %" GG_LL_FORMAT "d;", output.name.c_str(),
                        Extract(output.variable)->Var()->Value());
  } else {
    const int bound_size = output.bounds.size();
    std::string result =
        StringPrintf("%s = array%dd(", output.name.c_str(), bound_size);
    for (int i = 0; i < bound_size; ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d..%" GG_LL_FORMAT "d, ",
                       output.bounds[i].min_value, output.bounds[i].max_value));
    }
    result.append("[");
    for (int i = 0; i < output.flat_variables.size(); ++i) {
      result.append(
          StringPrintf("%" GG_LL_FORMAT "d",
                       Extract(output.flat_variables[i])->Var()->Value()));
      if (i != output.flat_variables.size() - 1) {
        result.append(", ");
      }
    }
    result.append("]);");
    return result;
  }
  return "";
}

namespace {
struct ConstraintWithIo {
  FzConstraint* ct;
  int index;
  hash_set<FzIntegerVariable*> required;

  ConstraintWithIo(FzConstraint* cte, int i,
                   const hash_set<FzIntegerVariable*>& defined)
      : ct(cte), index(i) {
    hash_set<FzIntegerVariable*> marked;
    for (const FzArgument& arg : ct->arguments) {
      if (arg.variable != nullptr && ContainsKey(defined, arg.variable)) {
        required.insert(arg.variable);
      }
      for (FzIntegerVariable* const var : arg.variables) {
        if (ContainsKey(defined, var)) {
          required.insert(var);
        }
      }
    }
    if (ct->target_variable != nullptr) {
      required.erase(ct->target_variable);
    }
  }
};

struct ConstraintWithIoComparator {
  bool operator()(const ConstraintWithIo& a, const ConstraintWithIo& b) const {
    if (a.ct->target_variable != nullptr &&
        ContainsKey(b.required, a.ct->target_variable)) {
      return true;
    }
    if (b.ct->target_variable != nullptr &&
        ContainsKey(a.required, b.ct->target_variable)) {
      return false;
    }
    return a.index < b.index;
  }
};
}  // namespace

bool FzSolver::Extract() {
  statistics_.BuildStatistics();
  hash_set<FzIntegerVariable*> defined_variables;
  for (FzIntegerVariable* const var : model_.variables()) {
    if (var->defining_constraint == nullptr) {
      Extract(var);
    } else {
      defined_variables.insert(var);
    }
  }
  // Sort constraints such that defined variables are created before the
  // extraction of the constraints that use them.
  int index = 0;
  std::vector<ConstraintWithIo> to_sort;
  for (FzConstraint* ct : model_.constraints()) {
    if (ct != nullptr && !ct->is_trivially_true) {
      to_sort.push_back(ConstraintWithIo(ct, index++, defined_variables));
    }
  }
  std::sort(to_sort.begin(), to_sort.end(), ConstraintWithIoComparator());
  for (const ConstraintWithIo& ctio : to_sort) {
    ExtractConstraint(ctio.ct);
  }
  return true;
}
}  // namespace operations_research
<|endoftext|>


<commit_before>/**
 * @file
 *
 * @brief This file specifies a lexer that scans a subset of YAML.
 *
 * The lexer uses the same idea as the scanner of `libyaml` (and various other
 * YAML libs) to detect simple keys (keys with no `?` prefix).
 *
 * For a detailed explanation of the algorithm, I recommend to take a look at
 * the scanner of
 *
 * - SnakeYAML Engine:
 *   https://bitbucket.org/asomov/snakeyaml-engine
 * - or LLVM’s YAML library:
 *   https://github.com/llvm-mirror/llvm/blob/master/lib/Support/YAMLParser.cpp
 *
 * .
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

// -- Imports ------------------------------------------------------------------

#include <antlr4-runtime.h>

#include <kdblogger.h>

using std::deque;
using std::pair;
using std::shared_ptr;
using std::stack;
using std::string;
using std::unique_ptr;

using antlr4::CharStream;
using antlr4::CommonToken;
using antlr4::CommonTokenFactory;
using antlr4::Token;
using antlr4::TokenFactory;
using antlr4::TokenSource;

// -- Class --------------------------------------------------------------------

class YAMLLexer : public TokenSource
{
	/** This variable stores the input that this lexer scans. */
	CharStream * input;

	/** This queue stores the list of tokens produced by the lexer. */
	deque<unique_ptr<CommonToken>> tokens;

	/** The lexer uses this factory to produce tokens. */
	Ref<TokenFactory<CommonToken>> factory = CommonTokenFactory::DEFAULT;

	/** This pair stores the token source (this lexer) and the current `input`. */
	pair<TokenSource *, CharStream *> source;

	/**
	 * This variable saves the current line position of the lexer inside
	 * `input`.
	 */
	size_t line = 1;

	/**
	 * This number stores the current character position of the lexer inside of
	 * `line`.
	 */
	size_t column = 1;

	/**
	 * This counter stores the number of tokens already emitted by the lexer.
	 * The lexer needs this variable, to keep track of the insertion point of
	 * `KEY` tokens in the token queue.
	 */
	size_t tokensEmitted = 0;

	/**
	 * This stack stores the indentation (in number of characters) for each
	 * block collection.
	 */
	stack<size_t> indents{ deque<size_t>{ 0 } };

	/**
	 * This boolean specifies if the lexer has already scanned the whole input or
	 * not.
	 */
	bool done = false;

	/**
	 * This pair stores a simple key candidate token (first part) and its
	 * position in the token queue (second part).
	 *
	 * Since the lexer only supports block syntax for mappings and sequences we
	 * use a single token here. If we need support for flow collections we have
	 * to store a candidate for each flow level (block context = flow level 0).
	 */
	pair<unique_ptr<CommonToken>, size_t> simpleKey;

	/**
	 * @brief This function creates a new token with the specified parameters.
	 *
	 * @param type This parameter specifies the type of the token this function
	 *             should create.
	 * @param start This number specifies the start index of the returned token
	 *              inside the character stream `input`.
	 * @param stop This number specifies the stop index of the returned token
	 *             inside the character stream `input`.
	 * @param text This string specifies the text of the returned token.
	 *
	 * @return A token with the specified parameters
	 */
	unique_ptr<CommonToken> commonToken (size_t type, size_t start, size_t stop, string text);

	/**
	 * @brief This function creates a new token with the specified parameters.
	 *
	 * @param type This parameter specifies the type of the token this function
	 *             should create.
	 * @param start This number specifies the start index of the returned token
	 *              inside the character stream `input`.
	 * @param stop This number specifies the stop index of the returned token
	 *             inside the character stream `input`.
	 *
	 * @return A token with the specified parameters
	 */
	unique_ptr<CommonToken> commonToken (size_t type, size_t start, size_t stop);

	/**
	 * @brief This function adds an indentation value if the given value is
	 * smaller than the current indentation.
	 *
	 * @param lineIndex This parameter specifies the indentation value that this
	 *                  function compares to the current indentation.
	 *
	 * @retval true If the function added an indentation value
	 *         false Otherwise
	 */
	bool addIndentation (size_t const column);

	/**
	 * @brief This function checks if the lexer needs to scan additional tokens.
	 *
	 * @retval true If the lexer should fetch additional tokens
	 *         false Otherwise
	 */
	bool needMoreTokens () const;

	/**
	 * @brief This method adds new tokens to the token stream.
	 */
	void fetchTokens ();

	/**
	 * @brief This method consumes characters from the input stream keeping
	 *        track of line and column numbers.
	 *
	 * @param characters This parameter specifies the number of characters the
	 *                   the function should consume.
	 */
	void forward (size_t const characters);

	/**
	 * @brief This method removes uninteresting characters from the input.
	 */
	void scanToNextToken ();

	/**
	 * @brief This method checks if the input at the specified offset starts a key
	 *        value token.
	 *
	 * @param offset This parameter specifies an offset to the current position,
	 *               where this function will look for a key value token.
	 *
	 * @retval true If the input matches a key value token
	 *         false Otherwise
	 */
	bool isValue (size_t const offset = 1) const;

	/**
	 * @brief This method checks if the current input starts a list element.
	 *
	 * @retval true If the input matches a list element token
	 *         false Otherwise
	 */
	bool isElement () const;

	/**
	 * @brief This method checks if the input at the specified offset starts a
	 *        line comment.
	 *
	 * @param offset This parameter specifies an offset to the current position,
	 *               where this function will look for a comment token.
	 *
	 * @retval true If the input matches a comment token
	 *         false Otherwise
	 */
	bool isComment (size_t const offset) const;

	/**
	 * @brief This method saves a token for a simple key candidate located at the
	 *        current input position.
	 */
	void addSimpleKeyCandidate ();

	/**
	 * @brief This method adds block closing tokens to the token queue, if the
	 *        indentation decreased.
	 *
	 * @param lineIndex This parameter specifies the column (indentation in number
	 *                  of spaces) for which this method should add block end
	 *                  tokens.
	 */
	void addBlockEnd (size_t const lineIndex);

	/**
	 * @brief This method adds the token for the start of the YAML stream to
	 *        `tokens`.
	 */
	void scanStart ();

	/**
	 * @brief This method adds the end markers to the token queue.
	 */
	void scanEnd ();

	/**
	 * @brief This method scans a single quoted scalar and adds it to the token
	 *        queue.
	 */
	void scanSingleQuotedScalar ();

	/**
	 * @brief This method scans a plain scalar and adds it to the token queue.
	 */
	void scanPlainScalar ();

	/**
	 * @brief This method counts the number of non space characters that can be
	 *        part of a plain scalar at position `offset`.
	 *
	 * @param offset This parameter specifies an offset to the current input
	 *               position, where this function searches for non space
	 *               characters.
	 *
	 * @return The number of non-space characters at the input position `offset`
	 */
	size_t countPlainNonSpace (size_t const offset) const;

	/**
	 * @brief This method counts the number of space characters that can be part
	 *        of a plain scalar at the current input position.
	 *
	 * @return The number of space characters at the current input position
	 */
	size_t countPlainSpace () const;

	/**
	 * @brief This method scans a comment and adds it to the token queue.
	 */
	void scanComment ();

	/**
	 * @brief This method scans a double quoted scalar and adds it to the token
	 *        queue.
	 */
	void scanDoubleQuotedScalar ();

	/**
	 * @brief This method scans a mapping value token and adds it to the token
	 *        queue.
	 */
	void scanValue ();

	/**
	 * @brief This method scans a list element token and adds it to the token
	 *        queue.
	 */
	void scanElement ();

public:
	/** This token type starts the YAML stream. */
	static const size_t STREAM_START = 1;
	/** This token type ends the YAML stream. */
	static const size_t STREAM_END = 2;
	/** This token type specifies that the token stores a plain scalar. */
	static const size_t PLAIN_SCALAR = 3;
	/** This token type indicates the start of a mapping key. */
	static const size_t KEY = 4;
	/** This token type indicates the start of a mapping value. */
	static const size_t VALUE = 5;
	/** This token type indicates the start of a mapping. */
	static const size_t MAPPING_START = 6;
	/** This token type indicates the end of a block collection. */
	static const size_t BLOCK_END = 7;
	/** This token type indicates a list element. */
	static const size_t ELEMENT = 8;
	/** This token type indicates the start of a sequence. */
	static const size_t SEQUENCE_START = 9;
	/** This token type specifies that the token stores a double quoted scalar. */
	static const size_t DOUBLE_QUOTED_SCALAR = 10;
	/** This token type specifies that the token stores a (line) comment. */
	static const size_t COMMENT = 11;
	/** This token type specifies that the token stores a single quoted scalar. */
	static const size_t SINGLE_QUOTED_SCALAR = 12;

	/**
	 * @brief This constructor creates a new YAML lexer for the given input.
	 *
	 * @param input This character stream stores the data this lexer scans.
	 */
	YAMLLexer (CharStream * input);

	/**
	 * @brief This method retrieves the current (not already emitted) token
	 *        produced by the lexer.
	 *
	 * @return A token of the token stream produced by the lexer
	 */
	unique_ptr<Token> nextToken () override;

	/**
	 * @brief This method retrieves the current line index.
	 *
	 * @return The index of the line the lexer is currently scanning
	 */
	size_t getLine () const override;

	/**
	 * @brief This method returns the position in the current line.
	 *
	 * @return The character index in the line the lexer is scanning
	 */
	size_t getCharPositionInLine () override;

	/**
	 * @brief This method returns the source the lexer is scanning.
	 *
	 * @return The input of the lexer
	 */
	CharStream * getInputStream () override;

	/**
	 * @brief This method retrieves the name of the source the lexer is
	 * currently scanning.
	 *
	 * @return The name of the current input source
	 */
	std::string getSourceName () override;

	/**
	 * @brief This setter changes the token factory of the lexer.
	 *
	 * @param tokenFactory This parameter specifies the factory that the scanner
	 *                     should use to create tokens.
	 */
	template <typename T1>
	void setTokenFactory (TokenFactory<T1> * tokenFactory);

	/**
	 * @brief Retrieve the current token factory.
	 *
	 * @return The factory the scanner uses to create tokens
	 */
	Ref<TokenFactory<CommonToken>> getTokenFactory () override;
};
<commit_msg>Yan LR: Add class to store type of YAML block node<commit_after>/**
 * @file
 *
 * @brief This file specifies a lexer that scans a subset of YAML.
 *
 * The lexer uses the same idea as the scanner of `libyaml` (and various other
 * YAML libs) to detect simple keys (keys with no `?` prefix).
 *
 * For a detailed explanation of the algorithm, I recommend to take a look at
 * the scanner of
 *
 * - SnakeYAML Engine:
 *   https://bitbucket.org/asomov/snakeyaml-engine
 * - or LLVM’s YAML library:
 *   https://github.com/llvm-mirror/llvm/blob/master/lib/Support/YAMLParser.cpp
 *
 * .
 *
 * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
 */

// -- Imports ------------------------------------------------------------------

#include <antlr4-runtime.h>

#include <kdblogger.h>

using std::deque;
using std::pair;
using std::shared_ptr;
using std::stack;
using std::string;
using std::unique_ptr;

using antlr4::CharStream;
using antlr4::CommonToken;
using antlr4::CommonTokenFactory;
using antlr4::Token;
using antlr4::TokenFactory;
using antlr4::TokenSource;

// -- Class --------------------------------------------------------------------

class YAMLLexer : public TokenSource
{
	class Level
	{
	public:
		enum class Type
		{
			MAP,
			SEQUENCE,
			OTHER
		};
		size_t indent = 0;
		Type type = Level::Type::OTHER;

		Level (size_t indentation, Level::Type levelType = Level::Type::OTHER) : indent{ indentation }, type{ levelType }
		{
		}
	};

	/** This variable stores the input that this lexer scans. */
	CharStream * input;

	/** This queue stores the list of tokens produced by the lexer. */
	deque<unique_ptr<CommonToken>> tokens;

	/** The lexer uses this factory to produce tokens. */
	Ref<TokenFactory<CommonToken>> factory = CommonTokenFactory::DEFAULT;

	/** This pair stores the token source (this lexer) and the current `input`. */
	pair<TokenSource *, CharStream *> source;

	/**
	 * This variable saves the current line position of the lexer inside
	 * `input`.
	 */
	size_t line = 1;

	/**
	 * This number stores the current character position of the lexer inside of
	 * `line`.
	 */
	size_t column = 1;

	/**
	 * This counter stores the number of tokens already emitted by the lexer.
	 * The lexer needs this variable, to keep track of the insertion point of
	 * `KEY` tokens in the token queue.
	 */
	size_t tokensEmitted = 0;

	/**
	 * This stack stores the indentation (in number of characters) for each
	 * block collection.
	 */
	stack<size_t> indents{ deque<size_t>{ 0 } };

	/**
	 * This boolean specifies if the lexer has already scanned the whole input or
	 * not.
	 */
	bool done = false;

	/**
	 * This pair stores a simple key candidate token (first part) and its
	 * position in the token queue (second part).
	 *
	 * Since the lexer only supports block syntax for mappings and sequences we
	 * use a single token here. If we need support for flow collections we have
	 * to store a candidate for each flow level (block context = flow level 0).
	 */
	pair<unique_ptr<CommonToken>, size_t> simpleKey;

	/**
	 * @brief This function creates a new token with the specified parameters.
	 *
	 * @param type This parameter specifies the type of the token this function
	 *             should create.
	 * @param start This number specifies the start index of the returned token
	 *              inside the character stream `input`.
	 * @param stop This number specifies the stop index of the returned token
	 *             inside the character stream `input`.
	 * @param text This string specifies the text of the returned token.
	 *
	 * @return A token with the specified parameters
	 */
	unique_ptr<CommonToken> commonToken (size_t type, size_t start, size_t stop, string text);

	/**
	 * @brief This function creates a new token with the specified parameters.
	 *
	 * @param type This parameter specifies the type of the token this function
	 *             should create.
	 * @param start This number specifies the start index of the returned token
	 *              inside the character stream `input`.
	 * @param stop This number specifies the stop index of the returned token
	 *             inside the character stream `input`.
	 *
	 * @return A token with the specified parameters
	 */
	unique_ptr<CommonToken> commonToken (size_t type, size_t start, size_t stop);

	/**
	 * @brief This function adds an indentation value if the given value is
	 * smaller than the current indentation.
	 *
	 * @param lineIndex This parameter specifies the indentation value that this
	 *                  function compares to the current indentation.
	 *
	 * @retval true If the function added an indentation value
	 *         false Otherwise
	 */
	bool addIndentation (size_t const column);

	/**
	 * @brief This function checks if the lexer needs to scan additional tokens.
	 *
	 * @retval true If the lexer should fetch additional tokens
	 *         false Otherwise
	 */
	bool needMoreTokens () const;

	/**
	 * @brief This method adds new tokens to the token stream.
	 */
	void fetchTokens ();

	/**
	 * @brief This method consumes characters from the input stream keeping
	 *        track of line and column numbers.
	 *
	 * @param characters This parameter specifies the number of characters the
	 *                   the function should consume.
	 */
	void forward (size_t const characters);

	/**
	 * @brief This method removes uninteresting characters from the input.
	 */
	void scanToNextToken ();

	/**
	 * @brief This method checks if the input at the specified offset starts a key
	 *        value token.
	 *
	 * @param offset This parameter specifies an offset to the current position,
	 *               where this function will look for a key value token.
	 *
	 * @retval true If the input matches a key value token
	 *         false Otherwise
	 */
	bool isValue (size_t const offset = 1) const;

	/**
	 * @brief This method checks if the current input starts a list element.
	 *
	 * @retval true If the input matches a list element token
	 *         false Otherwise
	 */
	bool isElement () const;

	/**
	 * @brief This method checks if the input at the specified offset starts a
	 *        line comment.
	 *
	 * @param offset This parameter specifies an offset to the current position,
	 *               where this function will look for a comment token.
	 *
	 * @retval true If the input matches a comment token
	 *         false Otherwise
	 */
	bool isComment (size_t const offset) const;

	/**
	 * @brief This method saves a token for a simple key candidate located at the
	 *        current input position.
	 */
	void addSimpleKeyCandidate ();

	/**
	 * @brief This method adds block closing tokens to the token queue, if the
	 *        indentation decreased.
	 *
	 * @param lineIndex This parameter specifies the column (indentation in number
	 *                  of spaces) for which this method should add block end
	 *                  tokens.
	 */
	void addBlockEnd (size_t const lineIndex);

	/**
	 * @brief This method adds the token for the start of the YAML stream to
	 *        `tokens`.
	 */
	void scanStart ();

	/**
	 * @brief This method adds the end markers to the token queue.
	 */
	void scanEnd ();

	/**
	 * @brief This method scans a single quoted scalar and adds it to the token
	 *        queue.
	 */
	void scanSingleQuotedScalar ();

	/**
	 * @brief This method scans a plain scalar and adds it to the token queue.
	 */
	void scanPlainScalar ();

	/**
	 * @brief This method counts the number of non space characters that can be
	 *        part of a plain scalar at position `offset`.
	 *
	 * @param offset This parameter specifies an offset to the current input
	 *               position, where this function searches for non space
	 *               characters.
	 *
	 * @return The number of non-space characters at the input position `offset`
	 */
	size_t countPlainNonSpace (size_t const offset) const;

	/**
	 * @brief This method counts the number of space characters that can be part
	 *        of a plain scalar at the current input position.
	 *
	 * @return The number of space characters at the current input position
	 */
	size_t countPlainSpace () const;

	/**
	 * @brief This method scans a comment and adds it to the token queue.
	 */
	void scanComment ();

	/**
	 * @brief This method scans a double quoted scalar and adds it to the token
	 *        queue.
	 */
	void scanDoubleQuotedScalar ();

	/**
	 * @brief This method scans a mapping value token and adds it to the token
	 *        queue.
	 */
	void scanValue ();

	/**
	 * @brief This method scans a list element token and adds it to the token
	 *        queue.
	 */
	void scanElement ();

public:
	/** This token type starts the YAML stream. */
	static const size_t STREAM_START = 1;
	/** This token type ends the YAML stream. */
	static const size_t STREAM_END = 2;
	/** This token type specifies that the token stores a plain scalar. */
	static const size_t PLAIN_SCALAR = 3;
	/** This token type indicates the start of a mapping key. */
	static const size_t KEY = 4;
	/** This token type indicates the start of a mapping value. */
	static const size_t VALUE = 5;
	/** This token type indicates the start of a mapping. */
	static const size_t MAPPING_START = 6;
	/** This token type indicates the end of a block collection. */
	static const size_t BLOCK_END = 7;
	/** This token type indicates a list element. */
	static const size_t ELEMENT = 8;
	/** This token type indicates the start of a sequence. */
	static const size_t SEQUENCE_START = 9;
	/** This token type specifies that the token stores a double quoted scalar. */
	static const size_t DOUBLE_QUOTED_SCALAR = 10;
	/** This token type specifies that the token stores a (line) comment. */
	static const size_t COMMENT = 11;
	/** This token type specifies that the token stores a single quoted scalar. */
	static const size_t SINGLE_QUOTED_SCALAR = 12;

	/**
	 * @brief This constructor creates a new YAML lexer for the given input.
	 *
	 * @param input This character stream stores the data this lexer scans.
	 */
	YAMLLexer (CharStream * input);

	/**
	 * @brief This method retrieves the current (not already emitted) token
	 *        produced by the lexer.
	 *
	 * @return A token of the token stream produced by the lexer
	 */
	unique_ptr<Token> nextToken () override;

	/**
	 * @brief This method retrieves the current line index.
	 *
	 * @return The index of the line the lexer is currently scanning
	 */
	size_t getLine () const override;

	/**
	 * @brief This method returns the position in the current line.
	 *
	 * @return The character index in the line the lexer is scanning
	 */
	size_t getCharPositionInLine () override;

	/**
	 * @brief This method returns the source the lexer is scanning.
	 *
	 * @return The input of the lexer
	 */
	CharStream * getInputStream () override;

	/**
	 * @brief This method retrieves the name of the source the lexer is
	 * currently scanning.
	 *
	 * @return The name of the current input source
	 */
	std::string getSourceName () override;

	/**
	 * @brief This setter changes the token factory of the lexer.
	 *
	 * @param tokenFactory This parameter specifies the factory that the scanner
	 *                     should use to create tokens.
	 */
	template <typename T1>
	void setTokenFactory (TokenFactory<T1> * tokenFactory);

	/**
	 * @brief Retrieve the current token factory.
	 *
	 * @return The factory the scanner uses to create tokens
	 */
	Ref<TokenFactory<CommonToken>> getTokenFactory () override;
};
<|endoftext|>


<commit_before>// DXGL
// Copyright (C) 2012-2013 William Feely

// 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 "common.h"
#include "texture.h"
#include "glRenderer.h"
#include "glDirectDraw.h"
#include "glDirectDrawSurface.h"
#include "glDirect3DTexture.h"
#include "glDirect3DDevice.h"

glDirect3DTexture2::glDirect3DTexture2(glDirectDrawSurface7 *glDDS7)
{
	this->glDDS7 = glDDS7;
	refcount = 1;
}

glDirect3DTexture2::~glDirect3DTexture2()
{
	glDDS7->d3dt2 = NULL;
	glDDS7->Release();
}

HRESULT WINAPI glDirect3DTexture2::QueryInterface(REFIID riid, void** ppvObj)
{
	if(!this) return DDERR_INVALIDPARAMS;
	if(riid == IID_IUnknown)
	{
		this->AddRef();
		*ppvObj = this;
		return DD_OK;
	}
	return glDDS7->QueryInterface(riid,ppvObj);
}

ULONG WINAPI glDirect3DTexture2::AddRef()
{
	if(!this) return 0;
	refcount++;
	return refcount;
}

ULONG WINAPI glDirect3DTexture2::Release()
{
	if(!this) return 0;
	ULONG ret;
	refcount--;
	ret = refcount;
	if(refcount == 0) delete this;
	return ret;
}

HRESULT WINAPI glDirect3DTexture2::GetHandle(LPDIRECT3DDEVICE2 lpDirect3DDevice2, LPD3DTEXTUREHANDLE lpHandle)
{
	if(!this) return DDERR_INVALIDOBJECT;
	if(!lpDirect3DDevice2) return DDERR_INVALIDPARAMS;
	glDirect3DDevice7 *glD3DDev7;
	lpDirect3DDevice2->QueryInterface(IID_IDirect3DDevice7,(void**)&glD3DDev7);
	HRESULT ret = glDDS7->GetHandle(glD3DDev7,lpHandle);
	glD3DDev7->Release();
	return ret;
}
HRESULT WINAPI glDirect3DTexture2::Load(LPDIRECT3DTEXTURE2 lpD3DTexture2)
{
	if(!this) return DDERR_INVALIDOBJECT;
	if(!lpD3DTexture2) return DDERR_INVALIDPARAMS;
	return glDDS7->Load(((glDirect3DTexture2*)lpD3DTexture2)->GetDDS7());
}
HRESULT WINAPI glDirect3DTexture2::PaletteChanged(DWORD dwStart, DWORD dwCount)
{
	if(!this) return DDERR_INVALIDOBJECT;
	FIXME("glDirect3DTexture2::PaletteChanged: stub");
	return DDERR_GENERIC;
}

glDirect3DTexture1::glDirect3DTexture1(glDirectDrawSurface7 *glDDS7)
{
	this->glDDS7 = glDDS7;
	refcount = 1;
}
glDirect3DTexture1::~glDirect3DTexture1()
{
	glDDS7->d3dt1 = NULL;
	glDDS7->Release();
}
HRESULT WINAPI glDirect3DTexture1::QueryInterface(REFIID riid, void** ppvObj)
{
	if(!this) return DDERR_INVALIDPARAMS;
	if(riid == IID_IUnknown)
	{
		this->AddRef();
		*ppvObj = this;
		return DD_OK;
	}
	return glDDS7->QueryInterface(riid,ppvObj);
}
ULONG WINAPI glDirect3DTexture1::AddRef()
{
	if(!this) return 0;
	refcount++;
	return refcount;
}
ULONG WINAPI glDirect3DTexture1::Release()
{
	if(!this) return 0;
	ULONG ret;
	refcount--;
	ret = refcount;
	if(refcount == 0) delete this;
	return ret;
}

HRESULT WINAPI glDirect3DTexture1::GetHandle(LPDIRECT3DDEVICE lpDirect3DDevice, LPD3DTEXTUREHANDLE lpHandle)
{
	if(!this) return DDERR_INVALIDOBJECT;
	if(!lpDirect3DDevice) return DDERR_INVALIDPARAMS;
	glDirect3DDevice7 *glD3DDev7;
	lpDirect3DDevice->QueryInterface(IID_IDirect3DDevice7,(void**)&glD3DDev7);
	HRESULT ret = glDDS7->GetHandle(glD3DDev7,lpHandle);
	glD3DDev7->Release();
	return ret;
}
HRESULT WINAPI glDirect3DTexture1::Initialize(LPDIRECT3DDEVICE lpD3DDevice, LPDIRECTDRAWSURFACE lpDDSurface)
{
	if(!this) return DDERR_INVALIDOBJECT;
	return DDERR_ALREADYINITIALIZED;
}
HRESULT WINAPI glDirect3DTexture1::Load(LPDIRECT3DTEXTURE lpD3DTexture)
{
	if(!this) return DDERR_INVALIDOBJECT;
	if(!lpD3DTexture) return DDERR_INVALIDPARAMS;
	return glDDS7->Load(((glDirect3DTexture1*)lpD3DTexture)->GetDDS7());
}
HRESULT WINAPI glDirect3DTexture1::PaletteChanged(DWORD dwStart, DWORD dwCount)
{
	if(!this) return DDERR_INVALIDOBJECT;
	FIXME("glDirect3DTexture1::PaletteChanged: stub");
	return DDERR_GENERIC;
}
HRESULT WINAPI glDirect3DTexture1::Unload()
{
	if(!this) return DDERR_INVALIDOBJECT;
	return DDERR_UNSUPPORTED;
}
<commit_msg>Trace glDurect3DTexture.cpp and fix a couple invalid object return values.<commit_after>// DXGL
// Copyright (C) 2012-2013 William Feely

// 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 "common.h"
#include "texture.h"
#include "glRenderer.h"
#include "glDirectDraw.h"
#include "glDirectDrawSurface.h"
#include "glDirect3DTexture.h"
#include "glDirect3DDevice.h"

glDirect3DTexture2::glDirect3DTexture2(glDirectDrawSurface7 *glDDS7)
{
	TRACE_ENTER(2,14,this,14,glDDS7);
	this->glDDS7 = glDDS7;
	refcount = 1;
	TRACE_EXIT(-1,0);
}

glDirect3DTexture2::~glDirect3DTexture2()
{
	TRACE_ENTER(1,14,this);
	glDDS7->d3dt2 = NULL;
	glDDS7->Release();
	TRACE_EXIT(-1,0);
}

HRESULT WINAPI glDirect3DTexture2::QueryInterface(REFIID riid, void** ppvObj)
{
	TRACE_ENTER(3,14,this,24,&riid,14,ppvObj);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	if(riid == IID_IUnknown)
	{
		this->AddRef();
		*ppvObj = this;
		TRACE_VAR("*ppvObj",14,*ppvObj);
		TRACE_EXIT(23,DD_OK);
		return DD_OK;
	}
	TRACE_RET(23,glDDS7->QueryInterface(riid,ppvObj));
}

ULONG WINAPI glDirect3DTexture2::AddRef()
{
	TRACE_ENTER(1,14,this);
	if(!this) TRACE_RET(8,0);
	refcount++;
	TRACE_EXIT(8,refcount);
	return refcount;
}

ULONG WINAPI glDirect3DTexture2::Release()
{
	TRACE_ENTER(1,14,this);
	if(!this) TRACE_RET(8,0);
	ULONG ret;
	refcount--;
	ret = refcount;
	if(refcount == 0) delete this;
	TRACE_EXIT(8,ret);
	return ret;
}

HRESULT WINAPI glDirect3DTexture2::GetHandle(LPDIRECT3DDEVICE2 lpDirect3DDevice2, LPD3DTEXTUREHANDLE lpHandle)
{
	TRACE_ENTER(3,14,this,14,lpDirect3DDevice2,14,lpHandle);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	if(!lpDirect3DDevice2) TRACE_RET(23,DDERR_INVALIDPARAMS);
	glDirect3DDevice7 *glD3DDev7;
	lpDirect3DDevice2->QueryInterface(IID_IDirect3DDevice7,(void**)&glD3DDev7);
	HRESULT ret = glDDS7->GetHandle(glD3DDev7,lpHandle);
	glD3DDev7->Release();
	TRACE_EXIT(23,ret);
	return ret;
}
HRESULT WINAPI glDirect3DTexture2::Load(LPDIRECT3DTEXTURE2 lpD3DTexture2)
{
	TRACE_ENTER(2,14,this,14,lpD3DTexture2);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	if(!lpD3DTexture2) TRACE_RET(23,DDERR_INVALIDPARAMS);
	TRACE_RET(23,glDDS7->Load(((glDirect3DTexture2*)lpD3DTexture2)->GetDDS7()));
}
HRESULT WINAPI glDirect3DTexture2::PaletteChanged(DWORD dwStart, DWORD dwCount)
{
	TRACE_ENTER(3,14,this,8,dwStart,8,dwCount);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	FIXME("glDirect3DTexture2::PaletteChanged: stub");
	TRACE_EXIT(23,DDERR_GENERIC);
	return DDERR_GENERIC;
}

glDirect3DTexture1::glDirect3DTexture1(glDirectDrawSurface7 *glDDS7)
{
	TRACE_ENTER(2,14,this,14,glDDS7);
	this->glDDS7 = glDDS7;
	refcount = 1;
	TRACE_EXIT(-1,0);
}
glDirect3DTexture1::~glDirect3DTexture1()
{
	TRACE_ENTER(1,14,this);
	glDDS7->d3dt1 = NULL;
	glDDS7->Release();
	TRACE_EXIT(-1,0);
}
HRESULT WINAPI glDirect3DTexture1::QueryInterface(REFIID riid, void** ppvObj)
{
	TRACE_ENTER(3,14,this,24,&riid,14,ppvObj);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	if(riid == IID_IUnknown)
	{
		this->AddRef();
		*ppvObj = this;
		TRACE_VAR("*ppvObj",14,*ppvObj);
		TRACE_EXIT(23,DD_OK);
		return DD_OK;
	}
	TRACE_RET(23,glDDS7->QueryInterface(riid,ppvObj));
}
ULONG WINAPI glDirect3DTexture1::AddRef()
{
	TRACE_ENTER(1,14,this);
	if(!this) TRACE_RET(8,0);
	refcount++;
	TRACE_EXIT(8,refcount);
	return refcount;
}
ULONG WINAPI glDirect3DTexture1::Release()
{
	TRACE_ENTER(1,14,this);
	if(!this) TRACE_RET(8,0);
	ULONG ret;
	refcount--;
	ret = refcount;
	if(refcount == 0) delete this;
	TRACE_EXIT(8,ret);
	return ret;
}

HRESULT WINAPI glDirect3DTexture1::GetHandle(LPDIRECT3DDEVICE lpDirect3DDevice, LPD3DTEXTUREHANDLE lpHandle)
{
	TRACE_ENTER(3,14,this,14,lpDirect3DDevice,14,lpHandle);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	if(!lpDirect3DDevice) TRACE_RET(23,DDERR_INVALIDPARAMS);
	glDirect3DDevice7 *glD3DDev7;
	lpDirect3DDevice->QueryInterface(IID_IDirect3DDevice7,(void**)&glD3DDev7);
	HRESULT ret = glDDS7->GetHandle(glD3DDev7,lpHandle);
	glD3DDev7->Release();
	TRACE_EXIT(23,ret);
	return ret;
}
HRESULT WINAPI glDirect3DTexture1::Initialize(LPDIRECT3DDEVICE lpD3DDevice, LPDIRECTDRAWSURFACE lpDDSurface)
{
	TRACE_ENTER(3,14,this,14,lpD3DDevice,14,lpDDSurface);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	TRACE_EXIT(23,DDERR_ALREADYINITIALIZED);
	return DDERR_ALREADYINITIALIZED;
}
HRESULT WINAPI glDirect3DTexture1::Load(LPDIRECT3DTEXTURE lpD3DTexture)
{
	TRACE_ENTER(2,14,this,14,lpD3DTexture);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	if(!lpD3DTexture) TRACE_RET(23,DDERR_INVALIDPARAMS);
	TRACE_RET(23,glDDS7->Load(((glDirect3DTexture1*)lpD3DTexture)->GetDDS7()));
}
HRESULT WINAPI glDirect3DTexture1::PaletteChanged(DWORD dwStart, DWORD dwCount)
{
	TRACE_ENTER(3,14,this,8,dwStart,8,dwCount);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	FIXME("glDirect3DTexture1::PaletteChanged: stub");
	TRACE_EXIT(23,DDERR_GENERIC);
	return DDERR_GENERIC;
}
HRESULT WINAPI glDirect3DTexture1::Unload()
{
	TRACE_ENTER(1,14,this);
	if(!this) TRACE_RET(23,DDERR_INVALIDOBJECT);
	TRACE_EXIT(23,DDERR_UNSUPPORTED);
	return DDERR_UNSUPPORTED;
}
<|endoftext|>


<commit_before>#include "gt/program/inner_common.hpp"

namespace Options = boost::program_options;
namespace Program = GT::Program;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void validate(
    boost::any&                     value,
    const std::vector<std::string>& values,
    GT::Model::ResultBuilderMode*,
    int
) {
    // make sure no previous assignment to value was made
    Options::validators::check_first_occurrence(value);

    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const std::string&           stringValue = Options::validators::get_single_string(values);
    std::istringstream           streamValue(stringValue);
    GT::Model::ResultBuilderMode parsedValue;
    streamValue >> parsedValue;

    value = boost::any( parsedValue );
}

void validate(
    boost::any&                     value,
    const std::vector<std::string>& values,
    GT::Model::ResultIndentationMode*,
    int
) {
    // make sure no previous assignment to value was made
    Options::validators::check_first_occurrence(value);

    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const std::string&               stringValue = Options::validators::get_single_string(values);
    std::istringstream               streamValue(stringValue);
    GT::Model::ResultIndentationMode parsedValue;
    streamValue >> parsedValue;

    value = boost::any( parsedValue );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main(
    const int   argumentsNumber,
    const char* arguments[]
) {
    // Options declaration section

    const char helpOption[]         = "help,H";
    const char helpDescription[]    = "produce this message";

    int  debugValue                 = 0;
    const int  debugDefault         = 0;
    const char debugOption[]        = "debug-level,D";
    const char debugDescription[]   = "0 if no parser debugging, non 0 for debug allowed";

    std::string inputValue          = "";
    const std::string inputDefault  = "";
    const char inputOption[]        = "input-file,I";
    const char inputDescription[]   = "input file to be parsed - if no one given reads from standard input";

    std::string outputValue         = "";
    const std::string outputDefault = "";
    const char outputOption[]       = "output-file,O";
    const char outputDescription[]  = "output target - if no one given reads from standard output";

    std::string errorValue          = "";
    const std::string errorDefault  = "";
    const char errorOption[]        = "error-file,E";
    const char errorDescription[]   = "error target - if no one given reads from standard error";

    GT::Model::ResultBuilderMode
               resultValue             = GT::Model::ResultBuilderMode::PLAIN;
    const GT::Model::ResultBuilderMode
               resultDefault           = GT::Model::ResultBuilderMode::PLAIN;
    const char resultOption[]          = "result,R";
    const char resultDescription[]     = "result type - PLAIN, JSON and XML allowed";

    GT::Model::ResultIndentationMode
               indentationValue            = GT::Model::ResultIndentationMode::TABS;
    const GT::Model::ResultIndentationMode
               indentationDefault          = GT::Model::ResultIndentationMode::TABS;
    const char indentationOption[]         = "indent,T";
    const char indentationDescription[]    = "indentation used - TABS, SPACES and NONE allowed";

    // Options setup

    Options::options_description description("Available options");
    description.add_options()
    (helpOption,                                                helpDescription)
    (debugOption,       Options::value<int>(
                            &debugValue
                        )->default_value(debugDefault),         debugDescription)
    (inputOption,       Options::value<std::string>(
                            &inputValue
                        )->default_value(inputDefault),         inputDescription)
    (outputOption,      Options::value<std::string>(
                            &outputValue
                        )->default_value(outputDefault),        outputDescription)
    (errorOption,      Options::value<std::string>(
                            &errorValue
                        )->default_value(errorDefault),         errorDescription)
    (resultOption,      Options::value<GT::Model::ResultBuilderMode>(
                            &resultValue
                        )->default_value(resultDefault),        resultDescription)
    (indentationOption, Options::value<GT::Model::ResultIndentationMode>(
                            &indentationValue
                        )->default_value(indentationDefault),   indentationDescription)
    ;

    try {
        // Parsing variables from arguments

        Options::variables_map variables;
        Options::store(
            Options::parse_command_line(argumentsNumber, arguments, description),
            variables
        );
        Options::notify(variables);

        // Display help if requested

        if (variables.count("help") || variables.count("H")) {
            std::cout << description << std::endl;
            return 0;
        }

        // Execute program otherwise

        Program::ProgramController controller;

        if (variables.count(debugOption))
            controller.setDebugLevel(debugValue);

        if (!inputValue.empty())
            controller.setInputStream(inputValue);
        else
            controller.setDefaultInputStream();

        if (!outputValue.empty())
            controller.setOutputStream(outputValue);
        else
            controller.setDefaultOutputStream();

        if (!errorValue.empty())
            controller.setErrorStream(errorValue);
        else
            controller.setDefaultErrorStream();

        return controller.setResultBuilderMode(resultValue)
                         .setResultIndentationMode(indentationValue)
                         .run();
    } catch (const boost::program_options::unknown_option& exception) {
        // uknown option error
        std::cerr << "Uknown option, use one of listed instead." << std::endl;
        std::cout << std::endl << description << std::endl;
        return -1;
    } catch (const std::exception& exception) {
        // last resort error handling
        std::cerr << exception.what() << std::endl;
        return -1;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>* Added documentation to program.cpp.<commit_after>#include "gt/program/inner_common.hpp"

namespace Options = boost::program_options;
namespace Program = GT::Program;

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * @brief Validator for boost::program_options to parse GT::Model::ResultBuilderMode.
 *
 * @param value  target value handler
 * @param values values all values that match validator
 */
void validate(
    boost::any&                     value,
    const std::vector<std::string>& values,
    GT::Model::ResultBuilderMode*,
    int
) {
    // make sure no previous assignment to value was made
    Options::validators::check_first_occurrence(value);

    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const std::string&           stringValue = Options::validators::get_single_string(values);
    std::istringstream           streamValue(stringValue);
    GT::Model::ResultBuilderMode parsedValue;
    streamValue >> parsedValue;

    value = boost::any( parsedValue );
}

/**
 * @brief Validator for boost::program_options to parse GT::Model::ResultIndentationMode.
 *
 * @param value  target value handler
 * @param values values all values that match validator
 */
void validate(
    boost::any&                     value,
    const std::vector<std::string>& values,
    GT::Model::ResultIndentationMode*,
    int
) {
    // make sure no previous assignment to value was made
    Options::validators::check_first_occurrence(value);

    // Extract the first string from 'values'. If there is more than
    // one string, it's an error, and exception will be thrown.
    const std::string&               stringValue = Options::validators::get_single_string(values);
    std::istringstream               streamValue(stringValue);
    GT::Model::ResultIndentationMode parsedValue;
    streamValue >> parsedValue;

    value = boost::any( parsedValue );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * @brief Parses arguments and runs program accordingly.
 *
 * @param argumentNumber number of arguments passed into program
 * @param arguments      actual arguments passed into program (arguments[0] being the executable's name)
 * @return               program exit code
 */
int main(
    const int   argumentsNumber,
    const char* arguments[]
) {
    // Options declaration section

    const char helpOption[]         = "help,H";
    const char helpDescription[]    = "produce this message";

    int  debugValue                 = 0;
    const int  debugDefault         = 0;
    const char debugOption[]        = "debug-level,D";
    const char debugDescription[]   = "0 if no parser debugging, non 0 for debug allowed";

    std::string inputValue          = "";
    const std::string inputDefault  = "";
    const char inputOption[]        = "input-file,I";
    const char inputDescription[]   = "input file to be parsed - if no one given reads from standard input";

    std::string outputValue         = "";
    const std::string outputDefault = "";
    const char outputOption[]       = "output-file,O";
    const char outputDescription[]  = "output target - if no one given reads from standard output";

    std::string errorValue          = "";
    const std::string errorDefault  = "";
    const char errorOption[]        = "error-file,E";
    const char errorDescription[]   = "error target - if no one given reads from standard error";

    GT::Model::ResultBuilderMode
               resultValue             = GT::Model::ResultBuilderMode::PLAIN;
    const GT::Model::ResultBuilderMode
               resultDefault           = GT::Model::ResultBuilderMode::PLAIN;
    const char resultOption[]          = "result,R";
    const char resultDescription[]     = "result type - PLAIN, JSON and XML allowed";

    GT::Model::ResultIndentationMode
               indentationValue            = GT::Model::ResultIndentationMode::TABS;
    const GT::Model::ResultIndentationMode
               indentationDefault          = GT::Model::ResultIndentationMode::TABS;
    const char indentationOption[]         = "indent,T";
    const char indentationDescription[]    = "indentation used - TABS, SPACES and NONE allowed";

    // Options setup

    Options::options_description description("Available options");
    description.add_options()
    (helpOption,                                                helpDescription)
    (debugOption,       Options::value<int>(
                            &debugValue
                        )->default_value(debugDefault),         debugDescription)
    (inputOption,       Options::value<std::string>(
                            &inputValue
                        )->default_value(inputDefault),         inputDescription)
    (outputOption,      Options::value<std::string>(
                            &outputValue
                        )->default_value(outputDefault),        outputDescription)
    (errorOption,      Options::value<std::string>(
                            &errorValue
                        )->default_value(errorDefault),         errorDescription)
    (resultOption,      Options::value<GT::Model::ResultBuilderMode>(
                            &resultValue
                        )->default_value(resultDefault),        resultDescription)
    (indentationOption, Options::value<GT::Model::ResultIndentationMode>(
                            &indentationValue
                        )->default_value(indentationDefault),   indentationDescription)
    ;

    try {
        // Parsing variables from arguments

        Options::variables_map variables;
        Options::store(
            Options::parse_command_line(argumentsNumber, arguments, description),
            variables
        );
        Options::notify(variables);

        // Display help if requested

        if (variables.count("help") || variables.count("H")) {
            std::cout << description << std::endl;
            return 0;
        }

        // Execute program otherwise

        Program::ProgramController controller;

        if (variables.count(debugOption))
            controller.setDebugLevel(debugValue);

        if (!inputValue.empty())
            controller.setInputStream(inputValue);
        else
            controller.setDefaultInputStream();

        if (!outputValue.empty())
            controller.setOutputStream(outputValue);
        else
            controller.setDefaultOutputStream();

        if (!errorValue.empty())
            controller.setErrorStream(errorValue);
        else
            controller.setDefaultErrorStream();

        return controller.setResultBuilderMode(resultValue)
                         .setResultIndentationMode(indentationValue)
                         .run();
    } catch (const boost::program_options::unknown_option& exception) {
        // uknown option error
        std::cerr << "Uknown option, use one of listed instead." << std::endl;
        std::cout << std::endl << description << std::endl;
        return -1;
    } catch (const std::exception& exception) {
        // last resort error handling
        std::cerr << exception.what() << std::endl;
        return -1;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/
#include "qxtlineedit.h"
#include <QStyleOptionFrameV2>
#include <QPainter>
#include <QStyle>

// copied from qlineedit.cpp:
#define vMargin 1
#define hMargin 2

struct QxtLineEditPrivate : public QxtPrivate<QxtLineEdit>
{
    QString sampleText;
};

/*!
    \class QxtLineEdit QxtLineEdit
    \ingroup QxtGui
    \brief A line edit that is able to show a sample text.

    QxtLineEdit is a line edit that is able to show a sample text.
    The sample text is shown when the line edit is empty and has
    no focus.

    \image html qxtlineedit.png "Two empty QxtLineEdits: non-focused and focused."
 */

/*!
    Constructs a new QxtLineEdit with \a parent.
 */
QxtLineEdit::QxtLineEdit(QWidget* parent) : QLineEdit(parent)
{
}

/*!
    Constructs a new QxtLineEdit with \a text and \a parent.
 */
QxtLineEdit::QxtLineEdit(const QString& text, QWidget* parent) : QLineEdit(text, parent)
{
}

/*!
    Destructs the line edit.
 */
QxtLineEdit::~QxtLineEdit()
{
}

/*!
    \property QxtLineEdit::sampleText
    \brief This property holds the sample text of the line edit

    The sample text is shown when the line edit is empty and has
    no focus.
 */
QString QxtLineEdit::sampleText() const
{
    return qxt_d().sampleText;
}

void QxtLineEdit::setSampleText(const QString& text)
{
    if (qxt_d().sampleText != text)
    {
        qxt_d().sampleText = text;
        if (displayText().isEmpty() && !hasFocus())
            update();
    }
}

/*!
    \reimp
*/
void QxtLineEdit::paintEvent(QPaintEvent* event)
{
    QLineEdit::paintEvent(event);
    if (displayText().isEmpty() && !hasFocus())
    {
        QStyleOptionFrameV2 option;
        initStyleOption(&option);

        QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &option, this);
#if QT_VERSION >= 0x040500
        // TODO: sort out prior Qt 4.5
        int left, top, right, bottom;
        getTextMargins(&left, &top, &right, &bottom);
        r.adjust(left, top, -right, -bottom);
#endif // QT_VERSION >= 0x040500
        r.adjust(hMargin, vMargin, -hMargin, -vMargin);

        QPainter painter(this);
        QPalette pal = palette();
        pal.setCurrentColorGroup(QPalette::Disabled);
        style()->drawItemText(&painter, r, alignment(), pal, false, qxt_d().sampleText, QPalette::Text);
    }
}
<commit_msg>Fixed a compilation warning in QxtLineEdit.<commit_after>/****************************************************************************
 **
 ** Copyright (C) Qxt Foundation. Some rights reserved.
 **
 ** This file is part of the QxtGui module of the Qxt library.
 **
 ** This library is free software; you can redistribute it and/or modify it
 ** under the terms of the Common Public License, version 1.0, as published
 ** by IBM, and/or under the terms of the GNU Lesser General Public License,
 ** version 2.1, as published by the Free Software Foundation.
 **
 ** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY
 ** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
 ** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR
 ** FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** You should have received a copy of the CPL and the LGPL along with this
 ** file. See the LICENSE file and the cpl1.0.txt/lgpl-2.1.txt files
 ** included with the source distribution for more information.
 ** If you did not receive a copy of the licenses, contact the Qxt Foundation.
 **
 ** <http://libqxt.org>  <foundation@libqxt.org>
 **
 ****************************************************************************/
#include "qxtlineedit.h"
#include <QStyleOptionFrameV2>
#include <QPainter>
#include <QStyle>

// copied from qlineedit.cpp:
#define vMargin 1
#define hMargin 2

class QxtLineEditPrivate : public QxtPrivate<QxtLineEdit>
{
public:
    QString sampleText;
};

/*!
    \class QxtLineEdit QxtLineEdit
    \ingroup QxtGui
    \brief A line edit that is able to show a sample text.

    QxtLineEdit is a line edit that is able to show a sample text.
    The sample text is shown when the line edit is empty and has
    no focus.

    \image html qxtlineedit.png "Two empty QxtLineEdits: non-focused and focused."
 */

/*!
    Constructs a new QxtLineEdit with \a parent.
 */
QxtLineEdit::QxtLineEdit(QWidget* parent) : QLineEdit(parent)
{
}

/*!
    Constructs a new QxtLineEdit with \a text and \a parent.
 */
QxtLineEdit::QxtLineEdit(const QString& text, QWidget* parent) : QLineEdit(text, parent)
{
}

/*!
    Destructs the line edit.
 */
QxtLineEdit::~QxtLineEdit()
{
}

/*!
    \property QxtLineEdit::sampleText
    \brief This property holds the sample text of the line edit

    The sample text is shown when the line edit is empty and has
    no focus.
 */
QString QxtLineEdit::sampleText() const
{
    return qxt_d().sampleText;
}

void QxtLineEdit::setSampleText(const QString& text)
{
    if (qxt_d().sampleText != text)
    {
        qxt_d().sampleText = text;
        if (displayText().isEmpty() && !hasFocus())
            update();
    }
}

/*!
    \reimp
*/
void QxtLineEdit::paintEvent(QPaintEvent* event)
{
    QLineEdit::paintEvent(event);
    if (displayText().isEmpty() && !hasFocus())
    {
        QStyleOptionFrameV2 option;
        initStyleOption(&option);

        QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &option, this);
#if QT_VERSION >= 0x040500
        // TODO: sort out prior Qt 4.5
        int left, top, right, bottom;
        getTextMargins(&left, &top, &right, &bottom);
        r.adjust(left, top, -right, -bottom);
#endif // QT_VERSION >= 0x040500
        r.adjust(hMargin, vMargin, -hMargin, -vMargin);

        QPainter painter(this);
        QPalette pal = palette();
        pal.setCurrentColorGroup(QPalette::Disabled);
        style()->drawItemText(&painter, r, alignment(), pal, false, qxt_d().sampleText, QPalette::Text);
    }
}
<|endoftext|>


<commit_before>#include "hext/match-tree.h"

namespace hext {

match_tree::match_tree()
: children(),
  matches()
{
}

match_tree * match_tree::append_child_and_own(std::unique_ptr<match_tree> m)
{
  this->children.push_back(std::move(m));
  return this->children.back().get();
}

void match_tree::append_match(const name_value_pair& p)
{
  this->matches.push_back(p);
}

void match_tree::to_json(std::ostream& out) const
{
  if( !this->matches.empty() )
  {
    out << "{";
    assert(this->matches.size() > 0);
    std::vector<match_tree::name_value_pair>::const_iterator
      it_last = this->matches.end() - 1;
    for(auto it = this->matches.begin(); it != this->matches.end(); ++it)
    {
      out << it->first << ": \""
          << util::escape_quotes(it->second)
          << ( it == it_last ? "\"" : "\", " );
    }
    out << "}\n";
  }

  for(const auto& c : this->children)
  {
    c->to_json(out);
  }
}

void match_tree::print(std::ostream& out) const
{
  out << "digraph match_tree {\n";
  this->print_dot(out);
  out << "}\n";
}

void match_tree::print_dot(std::ostream& out, int parent_id) const
{
  static int node_index = 0;
  int this_node = ++node_index;

  std::string label;
  if( this->matches.empty() )
  {
    label.append("[rule]");
  }
  else
  {
    for(const auto& m : this->matches)
    {
      label.append(m.first);
      label.append(" ");
    }
  }

  out << "    node_" << this_node << " [label=\"" << label << "\"];\n";
  if( parent_id )
    out << "    node_" << parent_id << " -> node_" << this_node << ";\n";

  for(const auto& c : this->children)
    c->print_dot(out, this_node);
}

} // namespace hext

<commit_msg>use font arial in DOT output (smaller graph size)<commit_after>#include "hext/match-tree.h"

namespace hext {

match_tree::match_tree()
: children(),
  matches()
{
}

match_tree * match_tree::append_child_and_own(std::unique_ptr<match_tree> m)
{
  this->children.push_back(std::move(m));
  return this->children.back().get();
}

void match_tree::append_match(const name_value_pair& p)
{
  this->matches.push_back(p);
}

void match_tree::to_json(std::ostream& out) const
{
  if( !this->matches.empty() )
  {
    out << "{";
    assert(this->matches.size() > 0);
    std::vector<match_tree::name_value_pair>::const_iterator
      it_last = this->matches.end() - 1;
    for(auto it = this->matches.begin(); it != this->matches.end(); ++it)
    {
      out << it->first << ": \""
          << util::escape_quotes(it->second)
          << ( it == it_last ? "\"" : "\", " );
    }
    out << "}\n";
  }

  for(const auto& c : this->children)
  {
    c->to_json(out);
  }
}

void match_tree::print(std::ostream& out) const
{
  out << "digraph match_tree {\n"
      << "    node [fontname=\"Arial\"];\n";
  this->print_dot(out);
  out << "}\n";
}

void match_tree::print_dot(std::ostream& out, int parent_id) const
{
  static int node_index = 0;
  int this_node = ++node_index;

  std::string label;
  if( this->matches.empty() )
  {
    label.append("[rule]");
  }
  else
  {
    for(const auto& m : this->matches)
    {
      label.append(m.first);
      label.append(" ");
    }
  }

  out << "    node_" << this_node << " [label=\"" << label << "\"];\n";
  if( parent_id )
    out << "    node_" << parent_id << " -> node_" << this_node << ";\n";

  for(const auto& c : this->children)
    c->print_dot(out, this_node);
}

} // namespace hext

<|endoftext|>