<commit_before>#pragma once
/**
	@file
	@brief definition of abstruct exception class
	Copyright (C) 2008 Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <cybozu/itoa.hpp>
#include <errno.h>
#ifdef _WIN32
	#include <winsock2.h>
	#include <windows.h>
#else
	#include <string.h> // for strerror_r
#endif

namespace cybozu {

const bool DontThrow = true;

namespace exception {

/* get max 32 characters to avoid buffer overrun */
inline std::string makeString(const char *p, size_t size = -1)
{
	const size_t maxSize = 32;
	size_t pos = 0;
	if (p) {
		for (pos = 0; pos < std::min(size, maxSize); pos++) {
			if (p[pos] == 0) break;
		}
	}
	return std::string(p, pos);
}
/**
	convert errno to string
	@param err [in] errno
	@note for both windows and linux
*/
inline std::string ConvertErrorNoToString(int err)
{
	char errBuf[256];
#ifdef _WIN32
	strerror_s(errBuf, sizeof(errBuf), err);
	return errBuf;
#elif defined(_GNU_SOURCE)
	return ::strerror_r(err, errBuf, sizeof(errBuf));
#else
	if (strerror_r(err, errBuf, sizeof(errBuf)) == 0) {
		return errBuf;
	} else {
		return "strerror_r error";
	}
#endif
}

} // cybozu::exception

class Exception : public std::exception {
	std::string str_;
public:
	explicit Exception(const char *name)
		: str_(name)
	{
	}
	~Exception() throw () {}
	const char *what() const throw () { return str_.c_str(); }
	const std::string& toString() const { return str_; }
	/**
		append string into str_
	*/
	Exception& operator<<(const std::string& str)
	{
		str_ += ':';
		str_ += str;
		return *this;
	}
	/**
		append C-string into str_
	*/
	Exception& operator<<(const char *str) { return operator<<(cybozu::exception::makeString(str)); }
	/**
		append char into str_
	*/
	Exception& operator<<(char c) { str_ += ':'; str_ += c; return *this; }
	/**
		append integer into str_
	*/
	template<class P>
	Exception& operator<<(P t) { return operator<<(cybozu::itoa(t)); }
};

class ErrorNo {
#ifdef _WIN32
	typedef unsigned int NativeErrorNo;
#else
	typedef int NativeErrorNo;
#endif
	NativeErrorNo err_;
public:
	explicit ErrorNo(NativeErrorNo err)
		: err_(err)
	{
	}
	ErrorNo()
		: err_(getLatestNativeErrorNo())
	{
	}
	NativeErrorNo getLatestNativeErrorNo() const
	{
#ifdef _WIN32
		return ::GetLastError();
#else
		return errno;
#endif
	}
	/**
		convert NativeErrNo to string(maybe UTF8)
		@param err [in] errno
		@note Linux   : same as ConvertErrorNoToString
			  Windows : for Win32 API(use en-us)
	*/
	std::string toString() const
	{
#ifdef _WIN32
		const int msgSize = 256;
		wchar_t msg[msgSize];
		int size = FormatMessageW(
			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			0,
			err_,
			MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
			msg,
			msgSize,
			NULL
		);
		if (size <= 0) return "";
		// remove last "\r\n"
		if (size > 2 && msg[size - 2] == '\r') {
			msg[size - 2] = 0;
			size -= 2;
		}
		std::string ret;
		ret.resize(size);
		// assume ascii only
		for (int i = 0; i < size; i++) {
			ret[i] = (char)msg[i];
		}
		return ret;
#else
		return exception::ConvertErrorNoToString(err_);
#endif
	}
};

} // cybozu
<commit_msg>avoid macro<commit_after>#pragma once
/**
	@file
	@brief definition of abstruct exception class
	Copyright (C) 2008 Cybozu Labs, Inc., all rights reserved.
*/
#include <string>
#include <cybozu/itoa.hpp>
#include <errno.h>
#ifdef _WIN32
	#include <winsock2.h>
	#include <windows.h>
#else
	#include <string.h> // for strerror_r
#endif

namespace cybozu {

const bool DontThrow = true;

namespace exception {

/* get max 32 characters to avoid buffer overrun */
inline std::string makeString(const char *p, size_t size = -1)
{
	const size_t maxSize = 32;
	size_t pos = 0;
	if (p) {
		for (pos = 0; pos < (std::min)(size, maxSize); pos++) {
			if (p[pos] == 0) break;
		}
	}
	return std::string(p, pos);
}
/**
	convert errno to string
	@param err [in] errno
	@note for both windows and linux
*/
inline std::string ConvertErrorNoToString(int err)
{
	char errBuf[256];
#ifdef _WIN32
	strerror_s(errBuf, sizeof(errBuf), err);
	return errBuf;
#elif defined(_GNU_SOURCE)
	return ::strerror_r(err, errBuf, sizeof(errBuf));
#else
	if (strerror_r(err, errBuf, sizeof(errBuf)) == 0) {
		return errBuf;
	} else {
		return "strerror_r error";
	}
#endif
}

} // cybozu::exception

class Exception : public std::exception {
	std::string str_;
public:
	explicit Exception(const char *name)
		: str_(name)
	{
	}
	~Exception() throw () {}
	const char *what() const throw () { return str_.c_str(); }
	const std::string& toString() const { return str_; }
	/**
		append string into str_
	*/
	Exception& operator<<(const std::string& str)
	{
		str_ += ':';
		str_ += str;
		return *this;
	}
	/**
		append C-string into str_
	*/
	Exception& operator<<(const char *str) { return operator<<(cybozu::exception::makeString(str)); }
	/**
		append char into str_
	*/
	Exception& operator<<(char c) { str_ += ':'; str_ += c; return *this; }
	/**
		append integer into str_
	*/
	template<class P>
	Exception& operator<<(P t) { return operator<<(cybozu::itoa(t)); }
};

class ErrorNo {
#ifdef _WIN32
	typedef unsigned int NativeErrorNo;
#else
	typedef int NativeErrorNo;
#endif
	NativeErrorNo err_;
public:
	explicit ErrorNo(NativeErrorNo err)
		: err_(err)
	{
	}
	ErrorNo()
		: err_(getLatestNativeErrorNo())
	{
	}
	NativeErrorNo getLatestNativeErrorNo() const
	{
#ifdef _WIN32
		return ::GetLastError();
#else
		return errno;
#endif
	}
	/**
		convert NativeErrNo to string(maybe UTF8)
		@param err [in] errno
		@note Linux   : same as ConvertErrorNoToString
			  Windows : for Win32 API(use en-us)
	*/
	std::string toString() const
	{
#ifdef _WIN32
		const int msgSize = 256;
		wchar_t msg[msgSize];
		int size = FormatMessageW(
			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
			0,
			err_,
			MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
			msg,
			msgSize,
			NULL
		);
		if (size <= 0) return "";
		// remove last "\r\n"
		if (size > 2 && msg[size - 2] == '\r') {
			msg[size - 2] = 0;
			size -= 2;
		}
		std::string ret;
		ret.resize(size);
		// assume ascii only
		for (int i = 0; i < size; i++) {
			ret[i] = (char)msg[i];
		}
		return ret;
#else
		return exception::ConvertErrorNoToString(err_);
#endif
	}
};

} // cybozu
<|endoftext|>


<commit_before>/*
* Copyright (C) 2008-2013 Communi authors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

#include "usermodel.h"
#include "session.h"
#include <ircmessage.h>
#include <ircsender.h>
#include <irc.h>

UserModel::UserModel(QObject* parent) : QAbstractListModel(parent)
{
    d.session = qobject_cast<Session*>(parent);
}

UserModel::~UserModel()
{
}

Session* UserModel::session() const
{
    return d.session;
}

void UserModel::setSession(Session* session)
{
    d.session = session;
    clearUsers();
}

QString UserModel::channel() const
{
    return d.channel;
}

void UserModel::setChannel(const QString& channel)
{
    d.channel = channel.toLower();
}

QStringList UserModel::users() const
{
    return d.names;
}

bool UserModel::hasUser(const QString& user) const
{
    return d.names.contains(user, Qt::CaseInsensitive);
}

void UserModel::addUser(const QString& user)
{
    addUsers(QStringList() << user);
}

void UserModel::addUsers(const QStringList& users)
{
    QStringList unique;
    QSet<QString> nameSet = d.names.toSet();
    foreach (const QString& user, users) {
        QString name = d.session->unprefixedUser(user);
        if (!nameSet.contains(name))
            unique += user;
    }

    if (!unique.isEmpty()) {
        beginInsertRows(QModelIndex(), 0, unique.count() - 1);
        foreach (const QString& user, unique) {
            QString name = d.session->unprefixedUser(user);
            d.names.prepend(name);
            d.prefixes.insert(name, d.session->userPrefix(user));
        }
        endInsertRows();
    }
}

void UserModel::removeUser(const QString& user)
{
    QString name = d.session->unprefixedUser(user);
    int idx = d.names.indexOf(name);
    if (idx != -1) {
        beginRemoveRows(QModelIndex(), idx, idx);
        d.names.removeAt(idx);
        d.prefixes.remove(name);
        endRemoveRows();
    }
}

void UserModel::clearUsers()
{
    if (!d.names.isEmpty()) {
        beginResetModel();
        d.names.clear();
        endResetModel();
    }
}

void UserModel::renameUser(const QString& from, const QString& to)
{
    int idx = d.names.indexOf(from);
    if (idx != -1) {
        beginRemoveRows(QModelIndex(), idx, idx);
        d.names.removeAt(idx);
        QString prefix = d.prefixes.take(from);
        endRemoveRows();

        beginInsertRows(QModelIndex(), 0, 0);
        d.names.prepend(to);
        d.prefixes[to] = prefix;
        endInsertRows();
    }
}

void UserModel::promoteUser(const QString& user)
{
    QString name = d.session->unprefixedUser(user);
    int idx = d.names.indexOf(name);
    if (idx > 0) {
        // TODO: fix QCompleter to listen QAIM::rowsMoved()
        //beginMoveRows(QModelIndex(), idx, idx, QModelIndex(), 0);
        //d.names.move(idx, 0);
        //endMoveRows();

        beginRemoveRows(QModelIndex(), idx, idx);
        d.names.removeAt(idx);
        endRemoveRows();

        beginInsertRows(QModelIndex(), 0, 0);
        d.names.prepend(name);
        endInsertRows();
    }
}

void UserModel::setUserMode(const QString& user, const QString& mode)
{
    int idx = d.names.indexOf(user);
    if (idx != -1) {
        bool add = true;
        IrcSessionInfo info(d.session);
        QString updated = d.prefixes.value(user);
        for (int i = 0; i < mode.size(); ++i) {
            QChar c = mode.at(i);
            QString p = info.modeToPrefix(c);
            switch (c.unicode()) {
                case '+':
                    add = true;
                    break;
                case '-':
                    add = false;
                    break;
                default:
                    if (add) {
                        if (!updated.contains(p))
                            updated += p;
                    } else {
                        updated.remove(p);
                    }
                    break;
            }
        }
        d.prefixes[user] = updated;
        emit dataChanged(index(idx, 0), index(idx, 0));
    }
}

int UserModel::rowCount(const QModelIndex& parent) const
{
    if (parent.isValid())
        return 0;

    return d.names.count();
}

QVariant UserModel::data(const QModelIndex& index, int role) const
{
    if (index.row() < 0 || index.row() >= d.names.count())
        return QVariant();

    if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
        QString name = d.names.at(index.row());
        if (role == Qt::DisplayRole)
            return d.prefixes.value(name).left(1) + name;
        if (role == Qt::UserRole)
            return d.prefixes.value(name);
        return name;
    }

    return QVariant();
}

void UserModel::processMessage(IrcMessage* message)
{
    if (!d.session) {
        qWarning() << "UserModel::processMessage(): session is null!";
        return;
    }

    if (message->type() == IrcMessage::Nick) {
        QString from = message->sender().name();
        QString to = static_cast<IrcNickMessage*>(message)->nick();
        renameUser(from, to);
    } else if (message->type() == IrcMessage::Join) {
        if (message->flags() & IrcMessage::Own)
            clearUsers();
        else
            addUser(message->sender().name());
    } else if (message->type() == IrcMessage::Part) {
        if (message->flags() & IrcMessage::Own)
            clearUsers();
        else
            removeUser(message->sender().name());
    } else if (message->type() == IrcMessage::Kick) {
        removeUser(static_cast<IrcKickMessage*>(message)->user());
    } else if (message->type() == IrcMessage::Quit) {
        removeUser(message->sender().name());
    } else if (message->type() == IrcMessage::Mode) {
        IrcModeMessage* modeMsg = static_cast<IrcModeMessage*>(message);
        if (modeMsg->sender().name() != modeMsg->target() && !modeMsg->argument().isEmpty())
            setUserMode(modeMsg->argument(), modeMsg->mode());
    } else if (message->type() == IrcMessage::Numeric) {
        if (static_cast<IrcNumericMessage*>(message)->code() == Irc::RPL_NAMREPLY) {
            int count = message->parameters().count();
            if (!d.channel.isNull() && d.channel == message->parameters().value(count - 2).toLower()) {
                QString names = message->parameters().value(count - 1);
                addUsers(names.split(" ", QString::SkipEmptyParts));
            }
        }
    } else {
        promoteUser(message->sender().name());
    }
}
<commit_msg>UserModel: remove unnecessary calls to Session::unprefixedUser()<commit_after>/*
* Copyright (C) 2008-2013 Communi authors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*/

#include "usermodel.h"
#include "session.h"
#include <ircmessage.h>
#include <ircsender.h>
#include <irc.h>

UserModel::UserModel(QObject* parent) : QAbstractListModel(parent)
{
    d.session = qobject_cast<Session*>(parent);
}

UserModel::~UserModel()
{
}

Session* UserModel::session() const
{
    return d.session;
}

void UserModel::setSession(Session* session)
{
    d.session = session;
    clearUsers();
}

QString UserModel::channel() const
{
    return d.channel;
}

void UserModel::setChannel(const QString& channel)
{
    d.channel = channel.toLower();
}

QStringList UserModel::users() const
{
    return d.names;
}

bool UserModel::hasUser(const QString& user) const
{
    return d.names.contains(user, Qt::CaseInsensitive);
}

void UserModel::addUser(const QString& user)
{
    addUsers(QStringList() << user);
}

void UserModel::addUsers(const QStringList& users)
{
    QStringList unique;
    QSet<QString> nameSet = d.names.toSet();
    foreach (const QString& user, users) {
        QString name = d.session->unprefixedUser(user);
        if (!nameSet.contains(name))
            unique += user;
    }

    if (!unique.isEmpty()) {
        beginInsertRows(QModelIndex(), 0, unique.count() - 1);
        foreach (const QString& user, unique) {
            QString name = d.session->unprefixedUser(user);
            d.names.prepend(name);
            d.prefixes.insert(name, d.session->userPrefix(user));
        }
        endInsertRows();
    }
}

void UserModel::removeUser(const QString& user)
{
    int idx = d.names.indexOf(user);
    if (idx != -1) {
        beginRemoveRows(QModelIndex(), idx, idx);
        d.names.removeAt(idx);
        d.prefixes.remove(user);
        endRemoveRows();
    }
}

void UserModel::clearUsers()
{
    if (!d.names.isEmpty()) {
        beginResetModel();
        d.names.clear();
        endResetModel();
    }
}

void UserModel::renameUser(const QString& from, const QString& to)
{
    int idx = d.names.indexOf(from);
    if (idx != -1) {
        beginRemoveRows(QModelIndex(), idx, idx);
        d.names.removeAt(idx);
        QString prefix = d.prefixes.take(from);
        endRemoveRows();

        beginInsertRows(QModelIndex(), 0, 0);
        d.names.prepend(to);
        d.prefixes[to] = prefix;
        endInsertRows();
    }
}

void UserModel::promoteUser(const QString& user)
{
    int idx = d.names.indexOf(user);
    if (idx > 0) {
        // TODO: fix QCompleter to listen QAIM::rowsMoved()
        //beginMoveRows(QModelIndex(), idx, idx, QModelIndex(), 0);
        //d.names.move(idx, 0);
        //endMoveRows();

        beginRemoveRows(QModelIndex(), idx, idx);
        d.names.removeAt(idx);
        endRemoveRows();

        beginInsertRows(QModelIndex(), 0, 0);
        d.names.prepend(user);
        endInsertRows();
    }
}

void UserModel::setUserMode(const QString& user, const QString& mode)
{
    int idx = d.names.indexOf(user);
    if (idx != -1) {
        bool add = true;
        IrcSessionInfo info(d.session);
        QString updated = d.prefixes.value(user);
        for (int i = 0; i < mode.size(); ++i) {
            QChar c = mode.at(i);
            QString p = info.modeToPrefix(c);
            switch (c.unicode()) {
                case '+':
                    add = true;
                    break;
                case '-':
                    add = false;
                    break;
                default:
                    if (add) {
                        if (!updated.contains(p))
                            updated += p;
                    } else {
                        updated.remove(p);
                    }
                    break;
            }
        }
        d.prefixes[user] = updated;
        emit dataChanged(index(idx, 0), index(idx, 0));
    }
}

int UserModel::rowCount(const QModelIndex& parent) const
{
    if (parent.isValid())
        return 0;

    return d.names.count();
}

QVariant UserModel::data(const QModelIndex& index, int role) const
{
    if (index.row() < 0 || index.row() >= d.names.count())
        return QVariant();

    if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
        QString name = d.names.at(index.row());
        if (role == Qt::DisplayRole)
            return d.prefixes.value(name).left(1) + name;
        if (role == Qt::UserRole)
            return d.prefixes.value(name);
        return name;
    }

    return QVariant();
}

void UserModel::processMessage(IrcMessage* message)
{
    if (!d.session) {
        qWarning() << "UserModel::processMessage(): session is null!";
        return;
    }

    if (message->type() == IrcMessage::Nick) {
        QString from = message->sender().name();
        QString to = static_cast<IrcNickMessage*>(message)->nick();
        renameUser(from, to);
    } else if (message->type() == IrcMessage::Join) {
        if (message->flags() & IrcMessage::Own)
            clearUsers();
        else
            addUser(message->sender().name());
    } else if (message->type() == IrcMessage::Part) {
        if (message->flags() & IrcMessage::Own)
            clearUsers();
        else
            removeUser(message->sender().name());
    } else if (message->type() == IrcMessage::Kick) {
        removeUser(static_cast<IrcKickMessage*>(message)->user());
    } else if (message->type() == IrcMessage::Quit) {
        removeUser(message->sender().name());
    } else if (message->type() == IrcMessage::Mode) {
        IrcModeMessage* modeMsg = static_cast<IrcModeMessage*>(message);
        if (modeMsg->sender().name() != modeMsg->target() && !modeMsg->argument().isEmpty())
            setUserMode(modeMsg->argument(), modeMsg->mode());
    } else if (message->type() == IrcMessage::Numeric) {
        if (static_cast<IrcNumericMessage*>(message)->code() == Irc::RPL_NAMREPLY) {
            int count = message->parameters().count();
            if (!d.channel.isNull() && d.channel == message->parameters().value(count - 2).toLower()) {
                QString names = message->parameters().value(count - 1);
                addUsers(names.split(" ", QString::SkipEmptyParts));
            }
        }
    } else {
        promoteUser(message->sender().name());
    }
}
<|endoftext|>


<commit_before>/*
 * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/utils.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef RENDER_UTILS_HPP_
#define RENDER_UTILS_HPP_

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

namespace eos {
	namespace render {

/**
 * Transforms a point from clip space ([-1, 1] x [-1, 1]) to
 * image (screen) coordinates, i.e. the window transform.
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 * No z-division is performed.
 * Note: It should rather be called from NDC to screen space?
 *
 * Exactly conforming to the OpenGL viewport transform, except that
 * we flip y at the end.
 * Qt: Origin top-left. OpenGL: bottom-left. OCV: top-left.
 *
 * @param[in] clip_coordinates A point in clip coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to screen space.
 */
inline cv::Vec2f clip_to_screen_space(const cv::Vec2f& clip_coordinates, int screen_width, int screen_height)
{
	// Window transform:
	const float x_ss = (clip_coordinates[0] + 1.0f) * (screen_width / 2.0f);
	const float y_ss = screen_height - (clip_coordinates[1] + 1.0f) * (screen_height / 2.0f); // also flip y; Qt: Origin top-left. OpenGL: bottom-left.
	return cv::Vec2f(x_ss, y_ss);
	/* Note: What we do here is equivalent to
	   x_w = (x *  vW/2) + vW/2;
	   However, Shirley says we should do:
	   x_w = (x *  vW/2) + (vW-1)/2;
	   (analogous for y)
	   Todo: Check the consequences.
	*/
};

/**
 * Transforms a point from image (screen) coordinates to
 * clip space ([-1, 1] x [-1, 1]).
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 *
 * @param[in] screen_coordinates A point in screen coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to clip space.
 */
inline cv::Vec2f screen_to_clip_space(const cv::Vec2f& screen_coordinates, int screen_width, int screen_height)
{
	const float x_cs = screen_coordinates[0] / (screen_width / 2.0f) - 1.0f;
	float y_cs = screen_coordinates[1] / (screen_height / 2.0f) - 1.0f;
	y_cs *= -1.0f;
	return cv::Vec2f(x_cs, y_cs);
};

/**
 * Calculates the normal of a face (or triangle), i.e. the
 * per-face normal. Return normal will be normalised.
 * Assumes the triangle is given in CCW order, i.e. vertices
 * in counterclockwise order on the screen are front-facing.
 *
 * @param[in] v0 First vertex.
 * @param[in] v1 Second vertex.
 * @param[in] v2 Third vertex.
 * @return The unit-length normal of the given triangle.
 */
cv::Vec3f calculate_face_normal(const cv::Vec3f& v0, const cv::Vec3f& v1, const cv::Vec3f& v2)
{
	cv::Vec3f n = (v1 - v0).cross(v2 - v0); // v0-to-v1 x v0-to-v2
	n /= cv::norm(n);
	return n;
};

/**
 * Draws the texture coordinates (uv-coords) of the given mesh
 * into an image by looping over the triangles and drawing each
 * triangle's texcoords.
 *
 * @param[in] mesh A mesh with texture coordinates.
 * @param[in] image An optional image to draw onto.
 * @return An image with the texture coordinate triangles drawn in it, 512x512 if no image is given.
 */
cv::Mat draw_texcoords(Mesh mesh, cv::Mat image = cv::Mat())
{
	using cv::Point2f;
	using cv::Scalar;
	if (image.empty())
	{
		image = cv::Mat(512, 512, CV_8UC4, Scalar(0.0f, 0.0f, 0.0f, 255.0f));
	}

	for (const auto& triIdx : mesh.tvi) {
		cv::line(image, Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
		cv::line(image, Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
		cv::line(image, Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
	}
	return image;
};

// TODO: Should go to detail:: namespace, or texturing/utils or whatever.
unsigned int get_max_possible_mipmaps_num(unsigned int width, unsigned int height)
{
	unsigned int mipmapsNum = 1;
	unsigned int size = std::max(width, height);

	if (size == 1)
		return 1;

	do {
		size >>= 1;
		mipmapsNum++;
	} while (size != 1);

	return mipmapsNum;
};

inline bool is_power_of_two(int x)
{
	return !(x & (x - 1));
};

class Texture
{
public:
	// Todo: This whole class needs a major overhaul and documentation.

	// throws: ocv exc,  runtime_ex
	void create_mipmapped_texture(cv::Mat image, unsigned int mipmapsNum = 0) {

		this->mipmaps_num = (mipmapsNum == 0 ? get_max_possible_mipmaps_num(image.cols, image.rows) : mipmapsNum);
		/*if (mipmapsNum == 0)
		{
		uchar mmn = render::utils::MatrixUtils::getMaxPossibleMipmapsNum(image.cols, image.rows);
		this->mipmapsNum = mmn;
		} else
		{
		this->mipmapsNum = mipmapsNum;
		}*/

		if (this->mipmaps_num > 1)
		{
			if (!is_power_of_two(image.cols) || !is_power_of_two(image.rows))
			{
				throw std::runtime_error("Error: Couldn't generate mipmaps, width or height not power of two.");
			}
		}
		image.convertTo(image, CV_8UC4);	// Most often, the input img is CV_8UC3. Img is BGR. Add an alpha channel
		cv::cvtColor(image, image, CV_BGR2BGRA);

		int currWidth = image.cols;
		int currHeight = image.rows;
		for (int i = 0; i < this->mipmaps_num; i++)
		{
			if (i == 0) {
				mipmaps.push_back(image);
			}
			else {
				cv::Mat currMipMap(currHeight, currWidth, CV_8UC4);
				cv::resize(mipmaps[i - 1], currMipMap, currMipMap.size());
				mipmaps.push_back(currMipMap);
			}

			if (currWidth > 1)
				currWidth >>= 1;
			if (currHeight > 1)
				currHeight >>= 1;
		}
		this->widthLog = (uchar)(std::log(mipmaps[0].cols) / CV_LOG2 + 0.0001f); // std::epsilon or something? or why 0.0001f here?
		this->heightLog = (uchar)(std::log(mipmaps[0].rows) / CV_LOG2 + 0.0001f); // Changed std::logf to std::log because it doesnt compile in linux (gcc 4.8). CHECK THAT
	};

	std::vector<cv::Mat> mipmaps;	// make Texture a friend class of renderer, then move this to private?
	unsigned char widthLog, heightLog; // log2 of width and height of the base mip-level

private:
	//std::string filename;
	unsigned int mipmaps_num;
};
	} /* namespace render */
} /* namespace eos */

#endif /* RENDER_UTILS_HPP_ */
<commit_msg>Fixed utils.hpp includes<commit_after>/*
 * Eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/render/utils.hpp
 *
 * Copyright 2014, 2015 Patrik Huber
 *
 * 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.
 */
#pragma once

#ifndef RENDER_UTILS_HPP_
#define RENDER_UTILS_HPP_

#include "eos/render/Mesh.hpp"

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"

namespace eos {
	namespace render {

/**
 * Transforms a point from clip space ([-1, 1] x [-1, 1]) to
 * image (screen) coordinates, i.e. the window transform.
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 * No z-division is performed.
 * Note: It should rather be called from NDC to screen space?
 *
 * Exactly conforming to the OpenGL viewport transform, except that
 * we flip y at the end.
 * Qt: Origin top-left. OpenGL: bottom-left. OCV: top-left.
 *
 * @param[in] clip_coordinates A point in clip coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to screen space.
 */
inline cv::Vec2f clip_to_screen_space(const cv::Vec2f& clip_coordinates, int screen_width, int screen_height)
{
	// Window transform:
	const float x_ss = (clip_coordinates[0] + 1.0f) * (screen_width / 2.0f);
	const float y_ss = screen_height - (clip_coordinates[1] + 1.0f) * (screen_height / 2.0f); // also flip y; Qt: Origin top-left. OpenGL: bottom-left.
	return cv::Vec2f(x_ss, y_ss);
	/* Note: What we do here is equivalent to
	   x_w = (x *  vW/2) + vW/2;
	   However, Shirley says we should do:
	   x_w = (x *  vW/2) + (vW-1)/2;
	   (analogous for y)
	   Todo: Check the consequences.
	*/
};

/**
 * Transforms a point from image (screen) coordinates to
 * clip space ([-1, 1] x [-1, 1]).
 * Note that the y-coordinate is flipped because the image origin
 * is top-left while in clip space top is +1 and bottom is -1.
 *
 * @param[in] screen_coordinates A point in screen coordinates.
 * @param[in] screen_width Width of the screen or window.
 * @param[in] screen_height Height of the screen or window.
 * @return A vector with x and y coordinates transformed to clip space.
 */
inline cv::Vec2f screen_to_clip_space(const cv::Vec2f& screen_coordinates, int screen_width, int screen_height)
{
	const float x_cs = screen_coordinates[0] / (screen_width / 2.0f) - 1.0f;
	float y_cs = screen_coordinates[1] / (screen_height / 2.0f) - 1.0f;
	y_cs *= -1.0f;
	return cv::Vec2f(x_cs, y_cs);
};

/**
 * Calculates the normal of a face (or triangle), i.e. the
 * per-face normal. Return normal will be normalised.
 * Assumes the triangle is given in CCW order, i.e. vertices
 * in counterclockwise order on the screen are front-facing.
 *
 * @param[in] v0 First vertex.
 * @param[in] v1 Second vertex.
 * @param[in] v2 Third vertex.
 * @return The unit-length normal of the given triangle.
 */
cv::Vec3f calculate_face_normal(const cv::Vec3f& v0, const cv::Vec3f& v1, const cv::Vec3f& v2)
{
	cv::Vec3f n = (v1 - v0).cross(v2 - v0); // v0-to-v1 x v0-to-v2
	n /= cv::norm(n);
	return n;
};

/**
 * Draws the texture coordinates (uv-coords) of the given mesh
 * into an image by looping over the triangles and drawing each
 * triangle's texcoords.
 *
 * @param[in] mesh A mesh with texture coordinates.
 * @param[in] image An optional image to draw onto.
 * @return An image with the texture coordinate triangles drawn in it, 512x512 if no image is given.
 */
cv::Mat draw_texcoords(Mesh mesh, cv::Mat image = cv::Mat())
{
	using cv::Point2f;
	using cv::Scalar;
	if (image.empty())
	{
		image = cv::Mat(512, 512, CV_8UC4, Scalar(0.0f, 0.0f, 0.0f, 255.0f));
	}

	for (const auto& triIdx : mesh.tvi) {
		cv::line(image, Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
		cv::line(image, Point2f(mesh.texcoords[triIdx[1]][0] * image.cols, mesh.texcoords[triIdx[1]][1] * image.rows), Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
		cv::line(image, Point2f(mesh.texcoords[triIdx[2]][0] * image.cols, mesh.texcoords[triIdx[2]][1] * image.rows), Point2f(mesh.texcoords[triIdx[0]][0] * image.cols, mesh.texcoords[triIdx[0]][1] * image.rows), Scalar(255.0f, 0.0f, 0.0f));
	}
	return image;
};

// TODO: Should go to detail:: namespace, or texturing/utils or whatever.
unsigned int get_max_possible_mipmaps_num(unsigned int width, unsigned int height)
{
	unsigned int mipmapsNum = 1;
	unsigned int size = std::max(width, height);

	if (size == 1)
		return 1;

	do {
		size >>= 1;
		mipmapsNum++;
	} while (size != 1);

	return mipmapsNum;
};

inline bool is_power_of_two(int x)
{
	return !(x & (x - 1));
};

class Texture
{
public:
	// Todo: This whole class needs a major overhaul and documentation.

	// throws: ocv exc,  runtime_ex
	void create_mipmapped_texture(cv::Mat image, unsigned int mipmapsNum = 0) {

		this->mipmaps_num = (mipmapsNum == 0 ? get_max_possible_mipmaps_num(image.cols, image.rows) : mipmapsNum);
		/*if (mipmapsNum == 0)
		{
		uchar mmn = render::utils::MatrixUtils::getMaxPossibleMipmapsNum(image.cols, image.rows);
		this->mipmapsNum = mmn;
		} else
		{
		this->mipmapsNum = mipmapsNum;
		}*/

		if (this->mipmaps_num > 1)
		{
			if (!is_power_of_two(image.cols) || !is_power_of_two(image.rows))
			{
				throw std::runtime_error("Error: Couldn't generate mipmaps, width or height not power of two.");
			}
		}
		image.convertTo(image, CV_8UC4);	// Most often, the input img is CV_8UC3. Img is BGR. Add an alpha channel
		cv::cvtColor(image, image, CV_BGR2BGRA);

		int currWidth = image.cols;
		int currHeight = image.rows;
		for (int i = 0; i < this->mipmaps_num; i++)
		{
			if (i == 0) {
				mipmaps.push_back(image);
			}
			else {
				cv::Mat currMipMap(currHeight, currWidth, CV_8UC4);
				cv::resize(mipmaps[i - 1], currMipMap, currMipMap.size());
				mipmaps.push_back(currMipMap);
			}

			if (currWidth > 1)
				currWidth >>= 1;
			if (currHeight > 1)
				currHeight >>= 1;
		}
		this->widthLog = (uchar)(std::log(mipmaps[0].cols) / CV_LOG2 + 0.0001f); // std::epsilon or something? or why 0.0001f here?
		this->heightLog = (uchar)(std::log(mipmaps[0].rows) / CV_LOG2 + 0.0001f); // Changed std::logf to std::log because it doesnt compile in linux (gcc 4.8). CHECK THAT
	};

	std::vector<cv::Mat> mipmaps;	// make Texture a friend class of renderer, then move this to private?
	unsigned char widthLog, heightLog; // log2 of width and height of the base mip-level

private:
	//std::string filename;
	unsigned int mipmaps_num;
};
	} /* namespace render */
} /* namespace eos */

#endif /* RENDER_UTILS_HPP_ */
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Unified vectorized implementation of the "sum" reduction
 */

#pragma once

namespace etl {

namespace impl {

namespace vec {

template <typename V, typename L>
value_t<L> selected_sum(const L& lhs, size_t first, size_t last) {
    using vec_type = V;
    using T        = value_t<L>;

    static constexpr size_t vec_size = vec_type::template traits<T>::size;

    auto n = last - first;

    size_t i = first;

    auto r1 = vec_type::template zero<T>();
    auto r2 = vec_type::template zero<T>();
    auto r3 = vec_type::template zero<T>();
    auto r4 = vec_type::template zero<T>();
    auto r5 = vec_type::template zero<T>();
    auto r6 = vec_type::template zero<T>();
    auto r7 = vec_type::template zero<T>();
    auto r8 = vec_type::template zero<T>();

    if (n > 1000) {
        for (; i + (vec_size * 8) - 1 < last; i += 8 * vec_size) {
            r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
            r2 = vec_type::add(lhs.template load<vec_type>(i + 1 * vec_size), r2);
            r3 = vec_type::add(lhs.template load<vec_type>(i + 2 * vec_size), r3);
            r4 = vec_type::add(lhs.template load<vec_type>(i + 3 * vec_size), r4);
            r5 = vec_type::add(lhs.template load<vec_type>(i + 4 * vec_size), r5);
            r6 = vec_type::add(lhs.template load<vec_type>(i + 5 * vec_size), r6);
            r7 = vec_type::add(lhs.template load<vec_type>(i + 6 * vec_size), r7);
            r8 = vec_type::add(lhs.template load<vec_type>(i + 7 * vec_size), r8);
        }
    }

    for (; i + (vec_size * 4) - 1 < last; i += 4 * vec_size) {
        r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
        r2 = vec_type::add(lhs.template load<vec_type>(i + 1 * vec_size), r2);
        r3 = vec_type::add(lhs.template load<vec_type>(i + 2 * vec_size), r3);
        r4 = vec_type::add(lhs.template load<vec_type>(i + 3 * vec_size), r4);
    }

    for(; i + (vec_size * 2) - 1 < last; i += 2 * vec_size){
        r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
        r2 = vec_type::add(lhs.template load<vec_type>(i + 1 * vec_size), r2);
    }

    for(; i + vec_size - 1 < last; i += vec_size){
        r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
    }

    auto p1 = vec_type::hadd(r1) + vec_type::hadd(r2) + vec_type::hadd(r3) + vec_type::hadd(r4);
    auto p2 = vec_type::hadd(r5) + vec_type::hadd(r6) + vec_type::hadd(r7) + vec_type::hadd(r8);

    for(; i + 1 < last; i += 2){
        p1 += lhs[i];
        p2 += lhs[i + 1];
    }

    if(i < last){
        p1 += lhs[i];
    }

    return p1 + p2;
}

/*!
 * \brief Compute the sum of lhs
 * \param lhs The lhs expression
 * \return the sum of the elements of lhs
 */
template <typename L>
value_t<L> sum(const L& lhs, size_t first, size_t last) {
    cpp_assert(vec_enabled, "At least one vector mode must be enabled for impl::VEC");

    // The default vectorization scheme should be sufficient
    return selected_sum<default_vec>(lhs, first, last);
}

} //end of namespace standard
} //end of namespace impl
} //end of namespace etl
<commit_msg>Protect when vec::sum cannot be used<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Unified vectorized implementation of the "sum" reduction
 */

#pragma once

namespace etl {

namespace impl {

namespace vec {

template <typename V, typename L>
value_t<L> selected_sum(const L& lhs, size_t first, size_t last) {
    using vec_type = V;
    using T        = value_t<L>;

    static constexpr size_t vec_size = vec_type::template traits<T>::size;

    auto n = last - first;

    size_t i = first;

    auto r1 = vec_type::template zero<T>();
    auto r2 = vec_type::template zero<T>();
    auto r3 = vec_type::template zero<T>();
    auto r4 = vec_type::template zero<T>();
    auto r5 = vec_type::template zero<T>();
    auto r6 = vec_type::template zero<T>();
    auto r7 = vec_type::template zero<T>();
    auto r8 = vec_type::template zero<T>();

    if (n > 1000) {
        for (; i + (vec_size * 8) - 1 < last; i += 8 * vec_size) {
            r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
            r2 = vec_type::add(lhs.template load<vec_type>(i + 1 * vec_size), r2);
            r3 = vec_type::add(lhs.template load<vec_type>(i + 2 * vec_size), r3);
            r4 = vec_type::add(lhs.template load<vec_type>(i + 3 * vec_size), r4);
            r5 = vec_type::add(lhs.template load<vec_type>(i + 4 * vec_size), r5);
            r6 = vec_type::add(lhs.template load<vec_type>(i + 5 * vec_size), r6);
            r7 = vec_type::add(lhs.template load<vec_type>(i + 6 * vec_size), r7);
            r8 = vec_type::add(lhs.template load<vec_type>(i + 7 * vec_size), r8);
        }
    }

    for (; i + (vec_size * 4) - 1 < last; i += 4 * vec_size) {
        r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
        r2 = vec_type::add(lhs.template load<vec_type>(i + 1 * vec_size), r2);
        r3 = vec_type::add(lhs.template load<vec_type>(i + 2 * vec_size), r3);
        r4 = vec_type::add(lhs.template load<vec_type>(i + 3 * vec_size), r4);
    }

    for(; i + (vec_size * 2) - 1 < last; i += 2 * vec_size){
        r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
        r2 = vec_type::add(lhs.template load<vec_type>(i + 1 * vec_size), r2);
    }

    for(; i + vec_size - 1 < last; i += vec_size){
        r1 = vec_type::add(lhs.template load<vec_type>(i + 0 * vec_size), r1);
    }

    auto p1 = vec_type::hadd(r1) + vec_type::hadd(r2) + vec_type::hadd(r3) + vec_type::hadd(r4);
    auto p2 = vec_type::hadd(r5) + vec_type::hadd(r6) + vec_type::hadd(r7) + vec_type::hadd(r8);

    for(; i + 1 < last; i += 2){
        p1 += lhs[i];
        p2 += lhs[i + 1];
    }

    if(i < last){
        p1 += lhs[i];
    }

    return p1 + p2;
}

/*!
 * \brief Compute the sum of lhs
 * \param lhs The lhs expression
 * \return the sum of the elements of lhs
 */
template <typename L, cpp_enable_if((vec_enabled && all_vectorizable<vector_mode, L>::value))>
value_t<L> sum(const L& lhs, size_t first, size_t last) {
    cpp_assert(vec_enabled, "At least one vector mode must be enabled for impl::VEC");

    // The default vectorization scheme should be sufficient
    return selected_sum<default_vec>(lhs, first, last);
}

/*!
 * \brief Compute the sum of lhs
 * \param lhs The lhs expression
 * \return the sum of the elements of lhs
 */
template <typename L, cpp_disable_if((vec_enabled && all_vectorizable<vector_mode, L>::value))>
value_t<L> sum(const L& lhs, size_t first, size_t last) {
    cpp_unused(lhs);
    cpp_unused(first);
    cpp_unused(last);
    cpp_unreachable("vec::sum called with invalid parameters");
}

} //end of namespace standard
} //end of namespace impl
} //end of namespace etl
<|endoftext|>


<commit_before>//  Copyright (C) 2009-2013, Vaclav Haisman. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modifica-
//  tion, 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 ``AS IS'' AND ANY EXPRESSED 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
//  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
//  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
//  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
//  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
//  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
//  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef LOG4CPLUS_CONFIG_HXX
#define LOG4CPLUS_CONFIG_HXX

#if defined (_WIN32)
#  include <log4cplus/config/win32.h>
#elif (defined(__MWERKS__) && defined(__MACOS__))
#  include <log4cplus/config/macosx.h>
#else
#  include <log4cplus/config/defines.hxx>
#endif

#if ! defined (UNICODE) && ! defined (LOG4CPLUS_HAVE_VSNPRINTF_S) \
    && ! defined (LOG4CPLUS_HAVE__VSNPRINTF_S) \
    && ! defined (LOG4CPLUS_HAVE_VSNPRINTF) \
    && ! defined (LOG4CPLUS_HAVE__VSNPRINTF)
#  undef LOG4CPLUS_USE_POOR_MANS_SNPRINTF
#  define LOG4CPLUS_USE_POOR_MANS_SNPRINTF
#endif

# if ! defined (LOG4CPLUS_WORKING_LOCALE) \
  && ! defined (LOG4CPLUS_WORKING_C_LOCALE) \
  && ! defined (LOG4CPLUS_WITH_ICONV)
# define LOG4CPLUS_POOR_MANS_CHCONV
#endif

#ifndef LOG4CPLUS_DECLSPEC_EXPORT
#define LOG4CPLUS_DECLSPEC_EXPORT /* empty */
#endif

#ifndef LOG4CPLUS_DECLSPEC_IMPORT
#define LOG4CPLUS_DECLSPEC_IMPORT /* empty */
#endif

#ifndef LOG4CPLUS_DECLSPEC_PRIVATE
#define LOG4CPLUS_DECLSPEC_PRIVATE /* empty */
#endif

#define LOG4CPLUS_PRIVATE LOG4CPLUS_DECLSPEC_PRIVATE

#if !defined(_WIN32)
#  define LOG4CPLUS_USE_BSD_SOCKETS
#  if !defined(LOG4CPLUS_SINGLE_THREADED)
#    define LOG4CPLUS_USE_PTHREADS
#  endif
#  if defined (INSIDE_LOG4CPLUS)
#    define LOG4CPLUS_EXPORT LOG4CPLUS_DECLSPEC_EXPORT
#  else
#    define LOG4CPLUS_EXPORT LOG4CPLUS_DECLSPEC_IMPORT
#  endif // defined (INSIDE_LOG4CPLUS)

#endif // !_WIN32

#if defined (LOG4CPLUS_INLINES_ARE_EXPORTED) \
    && defined (LOG4CPLUS_BUILD_DLL)
#  define LOG4CPLUS_INLINE_EXPORT inline
#else
#  define LOG4CPLUS_INLINE_EXPORT
#endif

#if defined (UNICODE)
#  if defined (_MSC_VER) && _MSC_VER >= 1400
#    define LOG4CPLUS_FSTREAM_ACCEPTS_WCHAR_T
#  endif
#  if defined (_MSC_VER) && _MSC_VER >= 1600
#    define LOG4CPLUS_HAVE_CODECVT_UTF8_FACET
#    define LOG4CPLUS_HAVE_CODECVT_UTF16_FACET
#  endif
#endif

// C++11 stuff

#if ! defined (__has_feature)
//! __has_feature(X) is Clangs way for testing features.
//! Define it to 0 if it does not exist.
#  define __has_feature(X) 0
#endif

#if (defined (_MSC_VER) && _MSC_VER >= 1600) \
    || defined (__GXX_EXPERIMENTAL_CXX0X__) \
    || __cplusplus >= 201103L
#  define LOG4CPLUS_HAVE_CXX11_SUPPORT
#endif

#if defined (LOG4CPLUS_HAVE_CXX11_SUPPORT) \
    || __has_feature (cxx_rvalue_references)
#  define LOG4CPLUS_HAVE_RVALUE_REFS
#endif

#if ! defined (UNICODE) && defined (__GNUC__) && __GNUC__ >= 3
#  define LOG4CPLUS_FORMAT_ATTRIBUTE(archetype, format_index, first_arg_index) \
    __attribute__ ((format (archetype, format_index, first_arg_index)))
#else
#  define LOG4CPLUS_FORMAT_ATTRIBUTE(archetype, fmt_index, first_arg_index) \
    /* empty */
#endif

#if defined (__GNUC__) \
    && (__GNUC__ >= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
#  define LOG4CPLUS_CALLER_FILE() __builtin_FILE ()
#  define LOG4CPLUS_CALLER_LINE() __builtin_LINE ()
#  define LOG4CPLUS_CALLER_FUNCTION() __builtin_FUNCTION ()
#else
#  define LOG4CPLUS_CALLER_FILE() (NULL)
#  define LOG4CPLUS_CALLER_LINE() (-1)
#  define LOG4CPLUS_CALLER_FUNCTION() (NULL)
#endif

#if defined (__GNUC__) && __GNUC__ >= 3
#  define LOG4CPLUS_ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#  define LOG4CPLUS_ATTRIBUTE_PURE __attribute__ ((__pure__))
#  define LOG4CPLUS_BUILTIN_EXPECT(exp, c) __builtin_expect ((exp), (c))
#else
#  if ! defined (LOG4CPLUS_ATTRIBUTE_NORETURN)
#    define LOG4CPLUS_ATTRIBUTE_NORETURN /* empty */
#  endif
#  define LOG4CPLUS_ATTRIBUTE_PURE /* empty */
#  define LOG4CPLUS_BUILTIN_EXPECT(exp, c) (exp)
#endif

#define LOG4CPLUS_LIKELY(cond) LOG4CPLUS_BUILTIN_EXPECT(!! (cond), 1)
#define LOG4CPLUS_UNLIKELY(cond) LOG4CPLUS_BUILTIN_EXPECT(!! (cond), 0)

#if defined (_MSC_VER)                                             \
    || (defined (__BORLANDC__) && __BORLANDC__ >= 0x0650)          \
    || (defined (__COMO__) && __COMO_VERSION__ >= 400) /* ??? */   \
    || (defined (__DMC__) && __DMC__ >= 0x700) /* ??? */           \
    || (defined (__clang__) && __clang_major__ >= 3)               \
    || (defined (__GNUC__) && (__GNUC__ >= 4                       \
            || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)))
#  define LOG4CPLUS_HAVE_PRAGMA_ONCE
#  pragma once
#endif

#include <log4cplus/helpers/thread-config.h>

#if defined(__cplusplus)
namespace log4cplus
{

//! Per thread cleanup function. Users should call this function before
//! a thread ends its execution. It frees resources allocated in thread local
//! storage. It is important only for multi-threaded static library builds
//! of log4cplus and user threads. In all other cases the clean up is provided
//! automatically by other means.
LOG4CPLUS_EXPORT void threadCleanup ();

//! Initializes log4cplus.
LOG4CPLUS_EXPORT void initialize ();

} // namespace log4cplus

#endif

#endif // LOG4CPLUS_CONFIG_HXX
<commit_msg>config.hxx: Fix check for GCC version providing __builtin_{FILE,LINE,FUNCTION} builtins.<commit_after>//  Copyright (C) 2009-2013, Vaclav Haisman. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modifica-
//  tion, 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 ``AS IS'' AND ANY EXPRESSED 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
//  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
//  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
//  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
//  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
//  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
//  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef LOG4CPLUS_CONFIG_HXX
#define LOG4CPLUS_CONFIG_HXX

#if defined (_WIN32)
#  include <log4cplus/config/win32.h>
#elif (defined(__MWERKS__) && defined(__MACOS__))
#  include <log4cplus/config/macosx.h>
#else
#  include <log4cplus/config/defines.hxx>
#endif

#if ! defined (UNICODE) && ! defined (LOG4CPLUS_HAVE_VSNPRINTF_S) \
    && ! defined (LOG4CPLUS_HAVE__VSNPRINTF_S) \
    && ! defined (LOG4CPLUS_HAVE_VSNPRINTF) \
    && ! defined (LOG4CPLUS_HAVE__VSNPRINTF)
#  undef LOG4CPLUS_USE_POOR_MANS_SNPRINTF
#  define LOG4CPLUS_USE_POOR_MANS_SNPRINTF
#endif

# if ! defined (LOG4CPLUS_WORKING_LOCALE) \
  && ! defined (LOG4CPLUS_WORKING_C_LOCALE) \
  && ! defined (LOG4CPLUS_WITH_ICONV)
# define LOG4CPLUS_POOR_MANS_CHCONV
#endif

#ifndef LOG4CPLUS_DECLSPEC_EXPORT
#define LOG4CPLUS_DECLSPEC_EXPORT /* empty */
#endif

#ifndef LOG4CPLUS_DECLSPEC_IMPORT
#define LOG4CPLUS_DECLSPEC_IMPORT /* empty */
#endif

#ifndef LOG4CPLUS_DECLSPEC_PRIVATE
#define LOG4CPLUS_DECLSPEC_PRIVATE /* empty */
#endif

#define LOG4CPLUS_PRIVATE LOG4CPLUS_DECLSPEC_PRIVATE

#if !defined(_WIN32)
#  define LOG4CPLUS_USE_BSD_SOCKETS
#  if !defined(LOG4CPLUS_SINGLE_THREADED)
#    define LOG4CPLUS_USE_PTHREADS
#  endif
#  if defined (INSIDE_LOG4CPLUS)
#    define LOG4CPLUS_EXPORT LOG4CPLUS_DECLSPEC_EXPORT
#  else
#    define LOG4CPLUS_EXPORT LOG4CPLUS_DECLSPEC_IMPORT
#  endif // defined (INSIDE_LOG4CPLUS)

#endif // !_WIN32

#if defined (LOG4CPLUS_INLINES_ARE_EXPORTED) \
    && defined (LOG4CPLUS_BUILD_DLL)
#  define LOG4CPLUS_INLINE_EXPORT inline
#else
#  define LOG4CPLUS_INLINE_EXPORT
#endif

#if defined (UNICODE)
#  if defined (_MSC_VER) && _MSC_VER >= 1400
#    define LOG4CPLUS_FSTREAM_ACCEPTS_WCHAR_T
#  endif
#  if defined (_MSC_VER) && _MSC_VER >= 1600
#    define LOG4CPLUS_HAVE_CODECVT_UTF8_FACET
#    define LOG4CPLUS_HAVE_CODECVT_UTF16_FACET
#  endif
#endif

// C++11 stuff

#if ! defined (__has_feature)
//! __has_feature(X) is Clangs way for testing features.
//! Define it to 0 if it does not exist.
#  define __has_feature(X) 0
#endif

#if (defined (_MSC_VER) && _MSC_VER >= 1600) \
    || defined (__GXX_EXPERIMENTAL_CXX0X__) \
    || __cplusplus >= 201103L
#  define LOG4CPLUS_HAVE_CXX11_SUPPORT
#endif

#if defined (LOG4CPLUS_HAVE_CXX11_SUPPORT) \
    || __has_feature (cxx_rvalue_references)
#  define LOG4CPLUS_HAVE_RVALUE_REFS
#endif

#if ! defined (UNICODE) && defined (__GNUC__) && __GNUC__ >= 3
#  define LOG4CPLUS_FORMAT_ATTRIBUTE(archetype, format_index, first_arg_index) \
    __attribute__ ((format (archetype, format_index, first_arg_index)))
#else
#  define LOG4CPLUS_FORMAT_ATTRIBUTE(archetype, fmt_index, first_arg_index) \
    /* empty */
#endif

#if defined (__GNUC__) \
    && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
#  define LOG4CPLUS_CALLER_FILE() __builtin_FILE ()
#  define LOG4CPLUS_CALLER_LINE() __builtin_LINE ()
#  define LOG4CPLUS_CALLER_FUNCTION() __builtin_FUNCTION ()
#else
#  define LOG4CPLUS_CALLER_FILE() (NULL)
#  define LOG4CPLUS_CALLER_LINE() (-1)
#  define LOG4CPLUS_CALLER_FUNCTION() (NULL)
#endif

#if defined (__GNUC__) && __GNUC__ >= 3
#  define LOG4CPLUS_ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#  define LOG4CPLUS_ATTRIBUTE_PURE __attribute__ ((__pure__))
#  define LOG4CPLUS_BUILTIN_EXPECT(exp, c) __builtin_expect ((exp), (c))
#else
#  if ! defined (LOG4CPLUS_ATTRIBUTE_NORETURN)
#    define LOG4CPLUS_ATTRIBUTE_NORETURN /* empty */
#  endif
#  define LOG4CPLUS_ATTRIBUTE_PURE /* empty */
#  define LOG4CPLUS_BUILTIN_EXPECT(exp, c) (exp)
#endif

#define LOG4CPLUS_LIKELY(cond) LOG4CPLUS_BUILTIN_EXPECT(!! (cond), 1)
#define LOG4CPLUS_UNLIKELY(cond) LOG4CPLUS_BUILTIN_EXPECT(!! (cond), 0)

#if defined (_MSC_VER)                                             \
    || (defined (__BORLANDC__) && __BORLANDC__ >= 0x0650)          \
    || (defined (__COMO__) && __COMO_VERSION__ >= 400) /* ??? */   \
    || (defined (__DMC__) && __DMC__ >= 0x700) /* ??? */           \
    || (defined (__clang__) && __clang_major__ >= 3)               \
    || (defined (__GNUC__) && (__GNUC__ >= 4                       \
            || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)))
#  define LOG4CPLUS_HAVE_PRAGMA_ONCE
#  pragma once
#endif

#include <log4cplus/helpers/thread-config.h>

#if defined(__cplusplus)
namespace log4cplus
{

//! Per thread cleanup function. Users should call this function before
//! a thread ends its execution. It frees resources allocated in thread local
//! storage. It is important only for multi-threaded static library builds
//! of log4cplus and user threads. In all other cases the clean up is provided
//! automatically by other means.
LOG4CPLUS_EXPORT void threadCleanup ();

//! Initializes log4cplus.
LOG4CPLUS_EXPORT void initialize ();

} // namespace log4cplus

#endif

#endif // LOG4CPLUS_CONFIG_HXX
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_ATTRIBUTE_HPP
#define MAPNIK_ATTRIBUTE_HPP

// mapnik
#include <mapnik/value.hpp>
// stl
#include <string>

namespace mapnik {

static mapnik::value _null_value;

struct attribute
{
    std::string name_;
    explicit attribute(std::string const& name)
        : name_(name) {}

    template <typename V ,typename F>
    V const& value(F const& f) const
    {
        typedef typename F::const_iterator const_iterator;
        const_iterator itr = f.find(name_);
        if (itr != f.end())
        {
            return itr->second;
        }
        return _null_value;
    }
    std::string const& name() const { return name_;}
};
}

#endif // MAPNIK_ATTRIBUTE_HPP
<commit_msg>return by value<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_ATTRIBUTE_HPP
#define MAPNIK_ATTRIBUTE_HPP

// mapnik
#include <mapnik/value.hpp>
// stl
#include <string>

namespace mapnik {

static mapnik::value _null_value;

struct attribute
{
    std::string name_;
    explicit attribute(std::string const& name)
        : name_(name) {}

    template <typename V ,typename F>
    V value(F const& f) const
    {
        typedef typename F::const_iterator const_iterator;
        const_iterator itr = f.find(name_);
        if (itr != f.end())
        {
            return itr->second;
        }
        return _null_value;
    }
    std::string const& name() const { return name_;}
};
}

#endif // MAPNIK_ATTRIBUTE_HPP
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file  test_helper.hpp
//----------------------------------------------------------------------------
/// \brief Unit test helping routines.
//----------------------------------------------------------------------------
// Author:  Serge Aleynikov
// Created: 2010-01-06
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#pragma once

#include <boost/test/unit_test.hpp>

#define BOOST_CURRENT_TEST_NAME \
  boost::unit_test::framework::current_test_case().p_name->c_str()

#define UTXX_REQUIRE_NO_THROW(Expr)     \
    try { Expr; }                       \
    catch (std::exception const& e) {   \
      BOOST_TEST_MESSAGE(e.what());     \
      BOOST_REQUIRE_NO_THROW(Expr);     \
    }

#define UTXX_CHECK_NO_THROW(Expr)       \
    try { Expr; }                       \
    catch (std::exception const& e) {   \
      BOOST_TEST_MESSAGE(e.what());     \
      BOOST_CHECK_NO_THROW(Expr);       \
    }

namespace utxx {

inline long env(const char* a_var, long a_default) {
    const char* p = getenv(a_var);
    return p ? atoi(p) : a_default;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt = "") {
    int    argc = boost::unit_test::framework::master_test_suite().argc;
    char** argv = boost::unit_test::framework::master_test_suite().argv;

    if (a_opt.empty() && a_long_opt.empty()) return false;

    auto same = [=](const std::string& a, int i) {
        return !a.empty() && a == argv[i];
    };

    for (int i=1; i < argc; i++) {
        if (same(a_opt,      i)) return true;
        if (same(a_long_opt, i)) return true;
    }

    return false;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt,
                          std::string& a_value) {
    int    argc = boost::unit_test::framework::master_test_suite().argc;
    char** argv = boost::unit_test::framework::master_test_suite().argv;

    if (a_opt.empty() && a_long_opt.empty()) return false;

    auto same = [=](const std::string& a, int i) {
        return !a.empty() && a == argv[i] &&
               (i < argc-1 && argv[i+1][i] != '-');
    };

    for (int i=1; i < argc; i++) {
        if (same(a_opt,      i)) { a_value = argv[++i]; return true; }
        if (same(a_long_opt, i)) { a_value = argv[++i]; return true; }
    }

    return false;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt,
                          int& a_value) {
    std::string s;
    if (!get_test_argv(a_opt, a_long_opt, s))
        return false;
    a_value = std::stoi(s);
    return true;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt,
                          bool& a_value) {
    std::string s;
    if (!get_test_argv(a_opt, a_long_opt, s))
        return false;
    a_value = s == "true" || s == "1" ||
             (s.length() > 0 && (s[0] == 'y' || s[0] == 'Y'));
    return true;
}

/// Prevent variable optimization by the compiler
#ifdef _MSC_VER
#pragma optimize("", off)
template <class T> void dont_optimize_var(T&& v) { v = v; }
#pragma optimize("", on)
#else
template <class T> void dont_optimize_var(T&& v) { asm volatile("":"+r" (v)); }
#endif

} // namespace utxx::test
<commit_msg>Fix get_test_argv to accept arguments like --arg=value<commit_after>//----------------------------------------------------------------------------
/// \file  test_helper.hpp
//----------------------------------------------------------------------------
/// \brief Unit test helping routines.
//----------------------------------------------------------------------------
// Author:  Serge Aleynikov
// Created: 2010-01-06
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#pragma once

#include <boost/test/unit_test.hpp>

#define BOOST_CURRENT_TEST_NAME \
  boost::unit_test::framework::current_test_case().p_name->c_str()

#define UTXX_REQUIRE_NO_THROW(Expr)     \
    try { Expr; }                       \
    catch (std::exception const& e) {   \
      BOOST_TEST_MESSAGE(e.what());     \
      BOOST_REQUIRE_NO_THROW(Expr);     \
    }

#define UTXX_CHECK_NO_THROW(Expr)       \
    try { Expr; }                       \
    catch (std::exception const& e) {   \
      BOOST_TEST_MESSAGE(e.what());     \
      BOOST_CHECK_NO_THROW(Expr);       \
    }

namespace utxx {

inline long env(const char* a_var, long a_default) {
    const char* p = getenv(a_var);
    return p ? atoi(p) : a_default;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt = "") {
    int    argc = boost::unit_test::framework::master_test_suite().argc;
    char** argv = boost::unit_test::framework::master_test_suite().argv;

    if (a_opt.empty() && a_long_opt.empty()) return false;

    auto same = [=](const std::string& a, int i) {
        size_t n = strlen(argv[i]);
        return !a.empty() &&
               (a == argv[i] || (a.size()+1 <= n &&
                                 strncmp(a.c_str(), argv[i], a.size()) == 0 &&
                                 argv[i][a.size()] == '='));
    };

    for (int i=1; i < argc; i++) {
        if (same(a_opt,      i)) return true;
        if (same(a_long_opt, i)) return true;
    }

    return false;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt,
                          std::string& a_value) {
    int    argc = boost::unit_test::framework::master_test_suite().argc;
    char** argv = boost::unit_test::framework::master_test_suite().argv;

    if (a_opt.empty() && a_long_opt.empty()) return false;

    auto check = [=, &a_value](const std::string& a, int& i) {
        if (a.empty()) return false;
        if (a == argv[i]) { a_value = argv[++i]; return true; }
        size_t n = strlen(argv[i]);
        if (a.size()+1 <= n && strncmp(a.c_str(), argv[i], a.size()) == 0 &&
                               argv[i][a.size()] == '=') {
            a_value = argv[i] + a.size()+1;
            return true;
        }
        return false;
    };

    for (int i=1; i < argc; i++) {
        if (check(a_opt,      i)) return true;
        if (check(a_long_opt, i)) return true;
    }

    return false;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt,
                          int& a_value) {
    std::string s;
    if (!get_test_argv(a_opt, a_long_opt, s))
        return false;
    a_value = std::stoi(s);
    return true;
}

inline bool get_test_argv(const std::string& a_opt,
                          const std::string& a_long_opt,
                          bool& a_value) {
    std::string s;
    if (!get_test_argv(a_opt, a_long_opt, s))
        return false;
    a_value = s == "true" || s == "1" ||
             (s.length() > 0 && (s[0] == 'y' || s[0] == 'Y' || s[0] == 'T'));
    return true;
}

/// Prevent variable optimization by the compiler
#ifdef _MSC_VER
#pragma optimize("", off)
template <class T> void dont_optimize_var(T&& v) { v = v; }
#pragma optimize("", on)
#else
template <class T> void dont_optimize_var(T&& v) { asm volatile("":"+r" (v)); }
#endif

} // namespace utxx::test
<|endoftext|>


<commit_before>/* Brainfuck interpreter using interpreter and composite patterns :) */

#include <exception>
#include <iostream>
#include <list>
#include <vector>
#include <map>
#include <string>
#include <memory>

using namespace std;

struct Data
{
    vector<int> array;
    int ptr;
};

class AbstractExpression
{
    public:
        virtual void add(shared_ptr<AbstractExpression>) {}
        virtual void interpret(Data &) = 0;
};

typedef shared_ptr<AbstractExpression> AbstractExpressionPtr;

class IncrementByte: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.array[data.ptr]++;
        }
};

class DecrementByte: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.array[data.ptr]--;
        }
};

class IncrementPtr: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.ptr++;
            if(data.array.size()==data.ptr) data.array.push_back(0);
        }
};

class DecrementPtr: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.ptr--;
            if(data.ptr<0) throw out_of_range("Negative value of pointer");
        }
};

class Output: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            cout<<char(data.array[data.ptr]);
        }
};

class Input: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            char input;
            cin>>input;
            data.array[data.ptr] = static_cast<char>(input);
        }
};

class CompositeExpression: public AbstractExpression
{
    protected:
        list<AbstractExpressionPtr> expTree;
    public:
        virtual void add(AbstractExpressionPtr exp) {expTree.push_back(exp);}

        virtual void interpret(Data &data) {
            for(list<AbstractExpressionPtr>::iterator it=expTree.begin(); it!=expTree.end(); it++)
                (*it)->interpret(data);
        }
};

class Loop: public CompositeExpression
{
    public:
        virtual void interpret(Data &data) {
            while(data.array[data.ptr]) {
                for(list<AbstractExpressionPtr>::iterator it=expTree.begin(); it!=expTree.end(); it++)
                    (*it)->interpret(data);
            }
        }
};

class AbstractFactory
{
    protected:
        char last;
    public:
        AbstractFactory(char c): last(c) {}
        virtual AbstractExpressionPtr makeExpression() = 0;
        char getClosure() {return last;}
};

typedef shared_ptr<AbstractFactory> AbstractFactoryPtr;

class LoopFactory: public AbstractFactory
{
    public:
        LoopFactory(char c): AbstractFactory(c) {}
        virtual AbstractExpressionPtr makeExpression() {
            return AbstractExpressionPtr(new Loop);
        }
};

class Parser
{
    private:
        map<char, AbstractExpressionPtr> terminalMap;
        map<char, AbstractFactoryPtr> nonTerminalMap;
    public:
        Parser() {
            terminalMap['+'] = AbstractExpressionPtr(new IncrementByte);
            terminalMap['-'] = AbstractExpressionPtr(new DecrementByte);
            terminalMap['>'] = AbstractExpressionPtr(new IncrementPtr);
            terminalMap['<'] = AbstractExpressionPtr(new DecrementPtr);
            terminalMap['.'] = AbstractExpressionPtr(new Output);
            terminalMap[','] = AbstractExpressionPtr(new Input);
            nonTerminalMap['['] = AbstractFactoryPtr(new LoopFactory(']'));
        }

        AbstractExpressionPtr buildTree(const string & code) {
            AbstractExpressionPtr syntaxTreePtr(new CompositeExpression);

            list<AbstractExpressionPtr> listNode(1, syntaxTreePtr);
            list<char> closure;

            for(int i=0; i<code.size(); i++) {
                if(terminalMap.find(code[i]) != terminalMap.end()) {
                    listNode.back()->add(terminalMap[code[i]]);
                }
                else if(nonTerminalMap.find(code[i]) != nonTerminalMap.end()) {
                    AbstractExpressionPtr current = nonTerminalMap[code[i]]->makeExpression();
                    listNode.back()->add(current);
                    listNode.push_back(current);
                    closure.push_back(nonTerminalMap[code[i]]->getClosure());
                }
                else if(code[i] == closure.back()) {
                    listNode.pop_back();
                    closure.pop_back();
                }
            }

            return syntaxTreePtr;
        }
};

int main()
{
    Data data; data.array.assign(1,0); data.ptr = 0;
    string code("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.");
    //string code(",[.[-],]");
    Parser parser;
    AbstractExpressionPtr syntaxTreePtr = parser.buildTree(code);
    syntaxTreePtr->interpret(data);
}
<commit_msg>private on the AbstractFactory's attribute<commit_after>/* Brainfuck interpreter using interpreter and composite patterns :) */

#include <exception>
#include <iostream>
#include <list>
#include <vector>
#include <map>
#include <string>
#include <memory>

using namespace std;

struct Data
{
    vector<int> array;
    int ptr;
};

class AbstractExpression
{
    public:
        virtual void add(shared_ptr<AbstractExpression>) {}
        virtual void interpret(Data &) = 0;
};

typedef shared_ptr<AbstractExpression> AbstractExpressionPtr;

class IncrementByte: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.array[data.ptr]++;
        }
};

class DecrementByte: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.array[data.ptr]--;
        }
};

class IncrementPtr: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.ptr++;
            if(data.array.size()==data.ptr) data.array.push_back(0);
        }
};

class DecrementPtr: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            data.ptr--;
            if(data.ptr<0) throw out_of_range("Negative value of pointer");
        }
};

class Output: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            cout<<char(data.array[data.ptr]);
        }
};

class Input: public AbstractExpression
{
    public:
        virtual void interpret(Data &data) {
            char input;
            cin>>input;
            data.array[data.ptr] = static_cast<char>(input);
        }
};

class CompositeExpression: public AbstractExpression
{
    protected:
        list<AbstractExpressionPtr> expTree;
    public:
        virtual void add(AbstractExpressionPtr exp) {expTree.push_back(exp);}

        virtual void interpret(Data &data) {
            for(list<AbstractExpressionPtr>::iterator it=expTree.begin(); it!=expTree.end(); it++)
                (*it)->interpret(data);
        }
};

class Loop: public CompositeExpression
{
    public:
        virtual void interpret(Data &data) {
            while(data.array[data.ptr]) {
                for(list<AbstractExpressionPtr>::iterator it=expTree.begin(); it!=expTree.end(); it++)
                    (*it)->interpret(data);
            }
        }
};

class AbstractFactory
{
    private:
        char last;
    public:
        AbstractFactory(char c): last(c) {}
        virtual AbstractExpressionPtr makeExpression() = 0;
        char getClosure() {return last;}
};

typedef shared_ptr<AbstractFactory> AbstractFactoryPtr;

class LoopFactory: public AbstractFactory
{
    public:
        LoopFactory(char c): AbstractFactory(c) {}
        virtual AbstractExpressionPtr makeExpression() {
            return AbstractExpressionPtr(new Loop);
        }
};

class Parser
{
    private:
        map<char, AbstractExpressionPtr> terminalMap;
        map<char, AbstractFactoryPtr> nonTerminalMap;
    public:
        Parser() {
            terminalMap['+'] = AbstractExpressionPtr(new IncrementByte);
            terminalMap['-'] = AbstractExpressionPtr(new DecrementByte);
            terminalMap['>'] = AbstractExpressionPtr(new IncrementPtr);
            terminalMap['<'] = AbstractExpressionPtr(new DecrementPtr);
            terminalMap['.'] = AbstractExpressionPtr(new Output);
            terminalMap[','] = AbstractExpressionPtr(new Input);
            nonTerminalMap['['] = AbstractFactoryPtr(new LoopFactory(']'));
        }

        AbstractExpressionPtr buildTree(const string & code) {
            AbstractExpressionPtr syntaxTreePtr(new CompositeExpression);

            list<AbstractExpressionPtr> listNode(1, syntaxTreePtr);
            list<char> closure;

            for(int i=0; i<code.size(); i++) {
                if(terminalMap.find(code[i]) != terminalMap.end()) {
                    listNode.back()->add(terminalMap[code[i]]);
                }
                else if(nonTerminalMap.find(code[i]) != nonTerminalMap.end()) {
                    AbstractExpressionPtr current = nonTerminalMap[code[i]]->makeExpression();
                    listNode.back()->add(current);
                    listNode.push_back(current);
                    closure.push_back(nonTerminalMap[code[i]]->getClosure());
                }
                else if(code[i] == closure.back()) {
                    listNode.pop_back();
                    closure.pop_back();
                }
            }

            return syntaxTreePtr;
        }
};

int main()
{
    Data data; data.array.assign(1,0); data.ptr = 0;
    string code("++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.");
    //string code(",[.[-],]");
    Parser parser;
    AbstractExpressionPtr syntaxTreePtr = parser.buildTree(code);
    syntaxTreePtr->interpret(data);
}
<|endoftext|>


<commit_before>
/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

// Sanity check integration test for logged_in_users
// Spec file: specs/logged_in_users.table

#include <osquery/tests/integration/tables/helper.h>

namespace osquery {
namespace table_tests {

class LoggedInUsersTest : public testing::Test {
  protected:
    void SetUp() override {
      setUpEnvironment();
    }
};

TEST_F(LoggedInUsersTest, sanity) {
  auto const rows = execute_query("select * from logged_in_users");
  auto const row_map = ValidatatioMap{
      {"type", NonEmptyString},
      {"user", NormalType},
      {"tty", NormalType},
      {"host", NormalType},
      {"time", NonNegativeInt},
      {"pid", NonNegativeInt},
  };
  validate_rows(rows, row_map);
}

} // namespace table_tests
} // namespace osquery
<commit_msg>Fix up logged_in_users table integration test for windows: column pid could be -1<commit_after>
/**
 *  Copyright (c) 2014-present, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under both the Apache 2.0 license (found in the
 *  LICENSE file in the root directory of this source tree) and the GPLv2 (found
 *  in the COPYING file in the root directory of this source tree).
 *  You may select, at your option, one of the above-listed licenses.
 */

// Sanity check integration test for logged_in_users
// Spec file: specs/logged_in_users.table

#include <osquery/tests/integration/tables/helper.h>

namespace osquery {
namespace table_tests {

class LoggedInUsersTest : public testing::Test {
  protected:
    void SetUp() override {
      setUpEnvironment();
    }
};

TEST_F(LoggedInUsersTest, sanity) {
  auto const rows = execute_query("select * from logged_in_users");
  auto const row_map = ValidatatioMap{
      {"type", NonEmptyString},
      {"user", NormalType},
      {"tty", NormalType},
      {"host", NormalType},
      {"time", NonNegativeInt},
      {"pid", NonNegativeOrErrorInt},
  };
  validate_rows(rows, row_map);
}

} // namespace table_tests
} // namespace osquery
<|endoftext|>


<commit_before>#ifndef WIN32

#include "native.h"
#include "generic.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <curses.h>
#include <term.h>

/*
 * Marks the given result as failed, using the current value of errno
 */
void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) {
    mark_failed_with_code(env, message, errno, result);
}

/*
 * File functions
 */

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_chmod(JNIEnv *env, jclass target, jstring path, jint mode, jobject result) {
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = chmod(pathUtf8, mode);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not chmod file", result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_stat(JNIEnv *env, jclass target, jstring path, jobject dest, jobject result) {
    struct stat fileInfo;
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = stat(pathUtf8, &fileInfo);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not stat file", result);
        return;
    }
    jclass destClass = env->GetObjectClass(dest);
    jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
    env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
}

/*
 * Process functions
 */

JNIEXPORT jint JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) {
    return getpid();
}

/*
 * Terminal functions
 */

JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_isatty(JNIEnv *env, jclass target, jint output) {
    switch (output) {
    case 0:
    case 1:
        return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
    default:
        return JNI_FALSE;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_getTerminalSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) {
    struct winsize screen_size;
    int retval = ioctl(output+1, TIOCGWINSZ, &screen_size);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not fetch terminal size", result);
        return;
    }
    jclass dimensionClass = env->GetObjectClass(dimension);
    jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I");
    env->SetIntField(dimension, widthField, screen_size.ws_col);
    jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I");
    env->SetIntField(dimension, heightField, screen_size.ws_row);
}

/*
 * Terminfo functions
 */

#define NORMAL_TEXT 0
#define BRIGHT_TEXT 1
#define FOREGROUND_COLOR 2
#define CURSOR_UP 3
#define CURSOR_DOWN 4
#define CURSOR_LEFT 5
#define CURSOR_RIGHT 6
#define CURSOR_START_LINE 7
#define CLEAR_END_OF_LINE 8

#ifdef SOLARIS
#define TERMINAL_CHAR_TYPE char
#else
#define TERMINAL_CHAR_TYPE int
#endif

int current_terminal = -1;
const char* terminal_capabilities[9];

int write_to_terminal(TERMINAL_CHAR_TYPE ch) {
    write(current_terminal, &ch, 1);
}

void write_capability(JNIEnv *env, const char* capability, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }
    if (tputs(capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

void write_param_capability(JNIEnv *env, const char* capability, int count, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }

    capability = tparm((char*)capability, count, 0, 0, 0, 0, 0, 0, 0, 0);
    if (capability == NULL) {
        mark_failed_with_message(env, "could not format terminal capability string", result);
        return;
    }

    if (tputs(capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_initTerminal(JNIEnv *env, jclass target, jint output, jobject result) {
    if (!isatty(output+1)) {
        mark_failed_with_message(env, "not a terminal", result);
        return;
    }
    if (current_terminal < 0) {
        char* termType = getenv("TERM");
        if (termType == NULL) {
            mark_failed_with_message(env, "$TERM not set", result);
            return;
        }
        int retval = tgetent(NULL, termType);
        if (retval != 1) {
            mark_failed_with_message(env, "could not get termcap entry", result);
            return;
        }
        terminal_capabilities[NORMAL_TEXT] = tgetstr((char*)"me", NULL);
        terminal_capabilities[BRIGHT_TEXT] = tgetstr((char*)"md", NULL);
        terminal_capabilities[FOREGROUND_COLOR] = tgetstr((char*)"AF", NULL);
        terminal_capabilities[CURSOR_UP] = tgetstr((char*)"up", NULL);
        terminal_capabilities[CURSOR_DOWN] = tgetstr((char*)"do", NULL);
        terminal_capabilities[CURSOR_LEFT] = tgetstr((char*)"le", NULL);
        terminal_capabilities[CURSOR_RIGHT] = tgetstr((char*)"nd", NULL);
        terminal_capabilities[CURSOR_START_LINE] = tgetstr((char*)"cr", NULL);
        terminal_capabilities[CLEAR_END_OF_LINE] = tgetstr((char*)"ce", NULL);
    }
    current_terminal = output + 1;
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_bold(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[BRIGHT_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_reset(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_foreground(JNIEnv *env, jclass target, jint color, jobject result) {
    write_param_capability(env, terminal_capabilities[FOREGROUND_COLOR], color, result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_UP], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_DOWN], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_LEFT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_RIGHT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_startLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CURSOR_START_LINE], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CLEAR_END_OF_LINE], result);
}

#endif
<commit_msg>Added some diagnostics for missing terminal capability.<commit_after>#ifndef WIN32

#include "native.h"
#include "generic.h"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <curses.h>
#include <term.h>

/*
 * Marks the given result as failed, using the current value of errno
 */
void mark_failed_with_errno(JNIEnv *env, const char* message, jobject result) {
    mark_failed_with_code(env, message, errno, result);
}

/*
 * File functions
 */

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_chmod(JNIEnv *env, jclass target, jstring path, jint mode, jobject result) {
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = chmod(pathUtf8, mode);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not chmod file", result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixFileFunctions_stat(JNIEnv *env, jclass target, jstring path, jobject dest, jobject result) {
    struct stat fileInfo;
    const char* pathUtf8 = env->GetStringUTFChars(path, NULL);
    int retval = stat(pathUtf8, &fileInfo);
    env->ReleaseStringUTFChars(path, pathUtf8);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not stat file", result);
        return;
    }
    jclass destClass = env->GetObjectClass(dest);
    jfieldID modeField = env->GetFieldID(destClass, "mode", "I");
    env->SetIntField(dest, modeField, 0777 & fileInfo.st_mode);
}

/*
 * Process functions
 */

JNIEXPORT jint JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixProcessFunctions_getPid(JNIEnv *env, jclass target) {
    return getpid();
}

/*
 * Terminal functions
 */

JNIEXPORT jboolean JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_isatty(JNIEnv *env, jclass target, jint output) {
    switch (output) {
    case 0:
    case 1:
        return isatty(output+1) ? JNI_TRUE : JNI_FALSE;
    default:
        return JNI_FALSE;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_PosixTerminalFunctions_getTerminalSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) {
    struct winsize screen_size;
    int retval = ioctl(output+1, TIOCGWINSZ, &screen_size);
    if (retval != 0) {
        mark_failed_with_errno(env, "could not fetch terminal size", result);
        return;
    }
    jclass dimensionClass = env->GetObjectClass(dimension);
    jfieldID widthField = env->GetFieldID(dimensionClass, "cols", "I");
    env->SetIntField(dimension, widthField, screen_size.ws_col);
    jfieldID heightField = env->GetFieldID(dimensionClass, "rows", "I");
    env->SetIntField(dimension, heightField, screen_size.ws_row);
}

/*
 * Terminfo functions
 */

#define NORMAL_TEXT 0
#define BRIGHT_TEXT 1
#define FOREGROUND_COLOR 2
#define CURSOR_UP 3
#define CURSOR_DOWN 4
#define CURSOR_LEFT 5
#define CURSOR_RIGHT 6
#define CURSOR_START_LINE 7
#define CLEAR_END_OF_LINE 8

#ifdef SOLARIS
#define TERMINAL_CHAR_TYPE char
#else
#define TERMINAL_CHAR_TYPE int
#endif

int current_terminal = -1;
const char* terminal_capabilities[9];

int write_to_terminal(TERMINAL_CHAR_TYPE ch) {
    write(current_terminal, &ch, 1);
}

const char* getcap(const char* capability) {
    char* cap = tgetstr((char*)capability, NULL);
//    if (cap == NULL) {
//        printf("unknown capability '%s'\n", capability);
//    }
    return cap;
}

void write_capability(JNIEnv *env, const char* capability, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }
    if (tputs(capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

void write_param_capability(JNIEnv *env, const char* capability, int count, jobject result) {
    if (capability == NULL) {
        mark_failed_with_message(env, "unknown terminal capability", result);
        return;
    }

    capability = tparm((char*)capability, count, 0, 0, 0, 0, 0, 0, 0, 0);
    if (capability == NULL) {
        mark_failed_with_message(env, "could not format terminal capability string", result);
        return;
    }

    if (tputs(capability, 1, write_to_terminal) == ERR) {
        mark_failed_with_message(env, "could not write to terminal", result);
        return;
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_initTerminal(JNIEnv *env, jclass target, jint output, jobject result) {
    if (!isatty(output+1)) {
        mark_failed_with_message(env, "not a terminal", result);
        return;
    }
    if (current_terminal < 0) {
        char* termType = getenv("TERM");
        if (termType == NULL) {
            mark_failed_with_message(env, "$TERM not set", result);
            return;
        }
        int retval = tgetent(NULL, termType);
        if (retval != 1) {
            mark_failed_with_message(env, "could not get termcap entry", result);
            return;
        }
        terminal_capabilities[NORMAL_TEXT] = getcap("me");
        terminal_capabilities[BRIGHT_TEXT] = getcap("md");
        terminal_capabilities[FOREGROUND_COLOR] = getcap("AF");
        terminal_capabilities[CURSOR_UP] = getcap("up");
        terminal_capabilities[CURSOR_DOWN] = getcap("do");
        terminal_capabilities[CURSOR_LEFT] = getcap("le");
        terminal_capabilities[CURSOR_RIGHT] = getcap("nd");
        terminal_capabilities[CURSOR_START_LINE] = getcap("cr");
        terminal_capabilities[CLEAR_END_OF_LINE] = getcap("ce");
    }
    current_terminal = output + 1;
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_bold(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[BRIGHT_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_reset(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[NORMAL_TEXT], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_foreground(JNIEnv *env, jclass target, jint color, jobject result) {
    write_param_capability(env, terminal_capabilities[FOREGROUND_COLOR], color, result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_UP], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_DOWN], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_LEFT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) {
    for (jint i = 0; i < count; i++) {
        write_capability(env, terminal_capabilities[CURSOR_RIGHT], result);
    }
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_startLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CURSOR_START_LINE], result);
}

JNIEXPORT void JNICALL
Java_net_rubygrapefruit_platform_internal_jni_TerminfoFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) {
    write_capability(env, terminal_capabilities[CLEAR_END_OF_LINE], result);
}

#endif
<|endoftext|>