#include "config.h"

// Implementation
#include "Cap.hpp"

// Local
#include "Sys.hpp"

namespace UI {
namespace Util {

Cap::Cap(InitType const & initType)
#ifdef __linux__
	:cap_(initType == Clear_ ? Sys::cap_init() : Sys::cap_get_proc())
#endif
{}

Cap::Cap(std::string const & s, InitType const & initType)
#ifdef __linux__
	:cap_(Sys::cap_from_text((Cap(initType).get() + " " + s).c_str()))
#endif
{}

Cap::Cap(Cap const & cap)
#ifdef __linux__
	:cap_(Sys::cap_dup(cap.cap_))
#endif
{}

Cap::~Cap()
{
#ifdef __linux__
	// Never throw in destructor
	try { Sys::cap_free(cap_); }
	catch (...) {}
#endif
}

Cap & Cap::apply()
{
#ifdef __linux__
	Sys::cap_set_proc(cap_);
	return *this;
#else
	return *this;
#endif
}

#ifdef HAVE_CAP_COMPARE
bool Cap::operator==(Cap const & cap) const
{
	return Sys::cap_compare(cap.cap_, cap_) == 0;
}
#endif

std::string const Cap::get() const
{
#ifdef __linux__
	// Helper class needed to ensure exception safety
	class Helper
	{
	public:
		char * s_;
		Helper( cap_t c): s_(Sys::cap_to_text(c, 0)) {};
		~Helper() { try {    Sys::cap_free(s_); } catch (...) {}; }
	};
	return Helper(cap_).s_;
#else
	return "";
#endif
}


CapScope::CapScope(std::string const & capabilities)
	:capabilities_(capabilities)
{
#ifdef __linux__
	Cap(capabilities_ + "+e").apply();
#endif
}

CapScope::~CapScope()
{
#ifdef __linux__
	// Avoid exception in destructor
	try { Cap(capabilities_ + "-e").apply(); } catch (...) {};
#endif
}

}}
