<commit_before>/*
 * Copyright (c) [2016-2017] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact Novell, Inc.
 *
 * To contact Novell about this file by physical or electronic mail, you may
 * find current contact information at www.novell.com.
 */

#include <iostream>

#include "storage/Utils/XmlFile.h"
#include "storage/Prober.h"
#include "storage/Utils/StorageTmpl.h"
#include "storage/Utils/StorageDefines.h"
#include "storage/Utils/SystemCmd.h"
#include "storage/SystemInfo/SystemInfo.h"
#include "storage/Holders/User.h"
#include "storage/Holders/Subdevice.h"
#include "storage/Devices/LvmPvImpl.h"
#include "storage/Devices/LvmVgImpl.h"
#include "storage/Devices/BlkDeviceImpl.h"
#include "storage/FindBy.h"
#include "storage/FreeInfo.h"
#include "storage/UsedFeatures.h"

namespace storage
{

    using namespace std;

    const char* DeviceTraits<LvmPv>::classname = "LvmPv";

    LvmPv::Impl::Impl(const xmlNode* node)
	: Device::Impl(node), uuid()
    {
	getChildValue(node, "uuid", uuid);
    }

    void
    LvmPv::Impl::save(xmlNode* node) const
    {
	Device::Impl::save(node);

	setChildValue(node, "uuid", uuid);
    }

    void
    LvmPv::Impl::check(const CheckCallbacks* check_callbacks) const
    {
	Device::Impl::check(check_callbacks);

	if (!has_single_parent_of_type<const BlkDevice>())
	    ST_THROW(Exception("LvmPv has no BlkDevice parent"));
    }

    bool
    LvmPv::Impl::has_blk_device() const
    {
	return has_single_parent_of_type<const BlkDevice>();
    }

    BlkDevice*
    LvmPv::Impl::get_blk_device()
    {
	return get_single_parent_of_type<BlkDevice>();
    }

    const BlkDevice*
    LvmPv::Impl::get_blk_device() const
    {
	return get_single_parent_of_type<const BlkDevice>();
    }

    bool
    LvmPv::Impl::has_lvm_vg() const
    {
	return has_single_child_of_type<const LvmVg>();
    }

    LvmVg*
    LvmPv::Impl::get_lvm_vg()
    {
	return get_single_child_of_type<LvmVg>();
    }

    const LvmVg*
    LvmPv::Impl::get_lvm_vg() const
    {
	return get_single_child_of_type<const LvmVg>();
    }

    void
    LvmPv::Impl::probe_lvm_pvs(Prober& prober)
    {
	for (const CmdPvs::Pv& pv : prober.get_system_info().getCmdPvs().get_pvs())
	{
	    LvmPv* lvm_pv = LvmPv::create(prober.get_probed());
	    lvm_pv->get_impl().set_uuid(pv.pv_uuid);

	    if (!pv.vg_uuid.empty())
	    {
		LvmVg* lvm_vg = LvmVg::Impl::find_by_uuid(prober.get_probed(), pv.vg_uuid);
		Subdevice::create(prober.get_probed(), lvm_pv, lvm_vg);
	    }
	}
    }

    void
    LvmPv::Impl::probe_pass_1b(Prober& prober)
    {
	const CmdPvs& cmd_pvs = prober.get_system_info().getCmdPvs();
	const CmdPvs::Pv& pv = cmd_pvs.find_by_pv_uuid(uuid);

	prober.add_holder(pv.pv_name, get_non_impl(), [](Devicegraph* probed, Device* a, Device* b) {
	    User::create(probed, a, b);
	});
    }

    ResizeInfo
    LvmPv::Impl::detect_resize_info() const
    {
	ResizeInfo resize_info(true);

	// A physical volume must have at least one extent and space for
	// metadata.

	// TODO 1 MiB due to metadata and physical extent alignment, needs
	// more research.

	resize_info.min_size = 1 * MiB;

	if (has_lvm_vg())
	{
	    const LvmVg* lvm_vg = get_lvm_vg();

	    resize_info.min_size += lvm_vg->get_extent_size();
	}

	// Currently we only support growing if the physical volume is already
	// on disk - shrinking is more complicated.

	if (exists_in_probed())
	{
	    resize_info.min_size = get_blk_device()->get_size();
	}

	return resize_info;
    }

    uint64_t
    LvmPv::Impl::used_features() const
    {
	return UF_LVM | Device::Impl::used_features();
    }

    void
    LvmPv::Impl::parent_has_new_region(const Device* parent)
    {
	if (has_lvm_vg())
	{
	    LvmVg* lvm_vg = get_lvm_vg();
	    lvm_vg->get_impl().parent_has_new_region(get_non_impl());
	}
    }

    LvmPv*
    LvmPv::Impl::find_by_uuid(Devicegraph* devicegraph, const string& uuid)
    {
	return storage::find_by_uuid<LvmPv>(devicegraph, uuid);
    }

    const LvmPv*
    LvmPv::Impl::find_by_uuid(const Devicegraph* devicegraph, const string& uuid)
    {
	return storage::find_by_uuid<const LvmPv>(devicegraph, uuid);
    }

    bool
    LvmPv::Impl::equal(const Device::Impl& rhs_base) const
    {
	const Impl& rhs = dynamic_cast<const Impl&>(rhs_base);

	if (!Device::Impl::equal(rhs))
	    return false;

	return uuid == rhs.uuid;
    }

    void
    LvmPv::Impl::log_diff(std::ostream& log, const Device::Impl& rhs_base) const
    {
	const Impl& rhs = dynamic_cast<const Impl&>(rhs_base);

	Device::Impl::log_diff(log, rhs);

	storage::log_diff(log, "uuid", uuid, rhs.uuid);
    }

    void
    LvmPv::Impl::print(std::ostream& out) const
    {
	Device::Impl::print(out);

	out << " uuid:" << uuid;
    }

    Text
    LvmPv::Impl::do_create_text(Tense tense) const
    {
	const BlkDevice* blk_device = get_blk_device();

	Text text = tenser(tense,
			   // TRANSLATORS: displayed before action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Create physical volume on %1$s"),
			   // TRANSLATORS: displayed during action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Creating physical volume on %1$s"));

	return sformat(text, blk_device->get_name().c_str());
    }

    void
    LvmPv::Impl::do_create()
    {
	const BlkDevice* blk_device = get_blk_device();

	string cmd_line = PVCREATEBIN " --force " + quote(blk_device->get_name());
	cout << cmd_line << endl;

	SystemCmd cmd(cmd_line);
	if (cmd.retcode() != 0)
	    ST_THROW(Exception("create LvmPv failed"));
    }

    Text
    LvmPv::Impl::do_resize_text(ResizeMode resize_mode, const Device* lhs, const Device* rhs,
				Tense tense) const
    {
	const BlkDevice* blk_device = get_blk_device();

	const BlkDevice* blk_device_lhs = to_lvm_pv(lhs)->get_impl().get_blk_device();
	const BlkDevice* blk_device_rhs = to_lvm_pv(rhs)->get_impl().get_blk_device();

	Text text;

	switch (resize_mode)
	{
	    case ResizeMode::SHRINK:
		text = tenser(tense,
			      // TRANSLATORS: displayed before action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 2GiB),
			      // %3$s is replaced by new size (e.g. 1GiB)
			      _("Shrink physical volume on %1$s from %2$s to %3$s"),
			      // TRANSLATORS: displayed during action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 2GiB),
			      // %3$s is replaced by new size (e.g. 1GiB)
			      _("Shrinking physical volume on %1$s from %2$s to %3$s"));
		break;

	    case ResizeMode::GROW:
		text = tenser(tense,
			      // TRANSLATORS: displayed before action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 1GiB),
			      // %3$s is replaced by new size (e.g. 2GiB)
			      _("Grow physical volume on %1$s from %2$s to %3$s"),
			      // TRANSLATORS: displayed during action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 1GiB),
			      // %3$s is replaced by new size (e.g. 2GiB)
			      _("Growing physical volume on %1$s from %2$s to %3$s"));
		break;

	    default:
		ST_THROW(LogicException("invalid value for resize_mode"));
	}

	return sformat(text, blk_device->get_name().c_str(),
		       blk_device_lhs->get_size_string().c_str(),
		       blk_device_rhs->get_size_string().c_str());
    }

    void
    LvmPv::Impl::do_resize(ResizeMode resize_mode, const Device* rhs) const
    {
	const BlkDevice* blk_device = get_blk_device();
	const BlkDevice* blk_device_rhs = to_lvm_pv(rhs)->get_impl().get_blk_device();

	string cmd_line = PVRESIZEBIN " " + quote(blk_device->get_name());
	if (resize_mode == ResizeMode::SHRINK)
	    cmd_line += " --yes --setphysicalvolumesize " + to_string(blk_device_rhs->get_size()) + "b";

	cout << cmd_line << endl;

	wait_for_devices({ blk_device->get_name() });

	SystemCmd cmd(cmd_line);
	if (cmd.retcode() != 0)
	    ST_THROW(Exception("resize LvmPv failed"));
    }

    Text
    LvmPv::Impl::do_delete_text(Tense tense) const
    {
	const BlkDevice* blk_device = get_blk_device();

	Text text = tenser(tense,
			   // TRANSLATORS: displayed before action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Delete physical volume on %1$s"),
			   // TRANSLATORS: displayed during action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Deleting physical volume on %1$s"));

	return sformat(text, blk_device->get_name().c_str());
    }

    void
    LvmPv::Impl::do_delete() const
    {
	const BlkDevice* blk_device = get_blk_device();

	string cmd_line = PVREMOVEBIN " " + quote(blk_device->get_name());
	cout << cmd_line << endl;

	SystemCmd cmd(cmd_line);
	if (cmd.retcode() != 0)
	    ST_THROW(Exception("delete LvmPv failed"));
    }

}
<commit_msg>- wait for devices before pvcreate<commit_after>/*
 * Copyright (c) [2016-2017] SUSE LLC
 *
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as published
 * by the Free Software Foundation.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, contact Novell, Inc.
 *
 * To contact Novell about this file by physical or electronic mail, you may
 * find current contact information at www.novell.com.
 */

#include <iostream>

#include "storage/Utils/XmlFile.h"
#include "storage/Prober.h"
#include "storage/Utils/StorageTmpl.h"
#include "storage/Utils/StorageDefines.h"
#include "storage/Utils/SystemCmd.h"
#include "storage/SystemInfo/SystemInfo.h"
#include "storage/Holders/User.h"
#include "storage/Holders/Subdevice.h"
#include "storage/Devices/LvmPvImpl.h"
#include "storage/Devices/LvmVgImpl.h"
#include "storage/Devices/BlkDeviceImpl.h"
#include "storage/FindBy.h"
#include "storage/FreeInfo.h"
#include "storage/UsedFeatures.h"

namespace storage
{

    using namespace std;

    const char* DeviceTraits<LvmPv>::classname = "LvmPv";

    LvmPv::Impl::Impl(const xmlNode* node)
	: Device::Impl(node), uuid()
    {
	getChildValue(node, "uuid", uuid);
    }

    void
    LvmPv::Impl::save(xmlNode* node) const
    {
	Device::Impl::save(node);

	setChildValue(node, "uuid", uuid);
    }

    void
    LvmPv::Impl::check(const CheckCallbacks* check_callbacks) const
    {
	Device::Impl::check(check_callbacks);

	if (!has_single_parent_of_type<const BlkDevice>())
	    ST_THROW(Exception("LvmPv has no BlkDevice parent"));
    }

    bool
    LvmPv::Impl::has_blk_device() const
    {
	return has_single_parent_of_type<const BlkDevice>();
    }

    BlkDevice*
    LvmPv::Impl::get_blk_device()
    {
	return get_single_parent_of_type<BlkDevice>();
    }

    const BlkDevice*
    LvmPv::Impl::get_blk_device() const
    {
	return get_single_parent_of_type<const BlkDevice>();
    }

    bool
    LvmPv::Impl::has_lvm_vg() const
    {
	return has_single_child_of_type<const LvmVg>();
    }

    LvmVg*
    LvmPv::Impl::get_lvm_vg()
    {
	return get_single_child_of_type<LvmVg>();
    }

    const LvmVg*
    LvmPv::Impl::get_lvm_vg() const
    {
	return get_single_child_of_type<const LvmVg>();
    }

    void
    LvmPv::Impl::probe_lvm_pvs(Prober& prober)
    {
	for (const CmdPvs::Pv& pv : prober.get_system_info().getCmdPvs().get_pvs())
	{
	    LvmPv* lvm_pv = LvmPv::create(prober.get_probed());
	    lvm_pv->get_impl().set_uuid(pv.pv_uuid);

	    if (!pv.vg_uuid.empty())
	    {
		LvmVg* lvm_vg = LvmVg::Impl::find_by_uuid(prober.get_probed(), pv.vg_uuid);
		Subdevice::create(prober.get_probed(), lvm_pv, lvm_vg);
	    }
	}
    }

    void
    LvmPv::Impl::probe_pass_1b(Prober& prober)
    {
	const CmdPvs& cmd_pvs = prober.get_system_info().getCmdPvs();
	const CmdPvs::Pv& pv = cmd_pvs.find_by_pv_uuid(uuid);

	prober.add_holder(pv.pv_name, get_non_impl(), [](Devicegraph* probed, Device* a, Device* b) {
	    User::create(probed, a, b);
	});
    }

    ResizeInfo
    LvmPv::Impl::detect_resize_info() const
    {
	ResizeInfo resize_info(true);

	// A physical volume must have at least one extent and space for
	// metadata.

	// TODO 1 MiB due to metadata and physical extent alignment, needs
	// more research.

	resize_info.min_size = 1 * MiB;

	if (has_lvm_vg())
	{
	    const LvmVg* lvm_vg = get_lvm_vg();

	    resize_info.min_size += lvm_vg->get_extent_size();
	}

	// Currently we only support growing if the physical volume is already
	// on disk - shrinking is more complicated.

	if (exists_in_probed())
	{
	    resize_info.min_size = get_blk_device()->get_size();
	}

	return resize_info;
    }

    uint64_t
    LvmPv::Impl::used_features() const
    {
	return UF_LVM | Device::Impl::used_features();
    }

    void
    LvmPv::Impl::parent_has_new_region(const Device* parent)
    {
	if (has_lvm_vg())
	{
	    LvmVg* lvm_vg = get_lvm_vg();
	    lvm_vg->get_impl().parent_has_new_region(get_non_impl());
	}
    }

    LvmPv*
    LvmPv::Impl::find_by_uuid(Devicegraph* devicegraph, const string& uuid)
    {
	return storage::find_by_uuid<LvmPv>(devicegraph, uuid);
    }

    const LvmPv*
    LvmPv::Impl::find_by_uuid(const Devicegraph* devicegraph, const string& uuid)
    {
	return storage::find_by_uuid<const LvmPv>(devicegraph, uuid);
    }

    bool
    LvmPv::Impl::equal(const Device::Impl& rhs_base) const
    {
	const Impl& rhs = dynamic_cast<const Impl&>(rhs_base);

	if (!Device::Impl::equal(rhs))
	    return false;

	return uuid == rhs.uuid;
    }

    void
    LvmPv::Impl::log_diff(std::ostream& log, const Device::Impl& rhs_base) const
    {
	const Impl& rhs = dynamic_cast<const Impl&>(rhs_base);

	Device::Impl::log_diff(log, rhs);

	storage::log_diff(log, "uuid", uuid, rhs.uuid);
    }

    void
    LvmPv::Impl::print(std::ostream& out) const
    {
	Device::Impl::print(out);

	out << " uuid:" << uuid;
    }

    Text
    LvmPv::Impl::do_create_text(Tense tense) const
    {
	const BlkDevice* blk_device = get_blk_device();

	Text text = tenser(tense,
			   // TRANSLATORS: displayed before action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Create physical volume on %1$s"),
			   // TRANSLATORS: displayed during action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Creating physical volume on %1$s"));

	return sformat(text, blk_device->get_name().c_str());
    }

    void
    LvmPv::Impl::do_create()
    {
	const BlkDevice* blk_device = get_blk_device();

	string cmd_line = PVCREATEBIN " --force " + quote(blk_device->get_name());
	cout << cmd_line << endl;

	wait_for_devices({ blk_device->get_name() });

	SystemCmd cmd(cmd_line);
	if (cmd.retcode() != 0)
	    ST_THROW(Exception("create LvmPv failed"));
    }

    Text
    LvmPv::Impl::do_resize_text(ResizeMode resize_mode, const Device* lhs, const Device* rhs,
				Tense tense) const
    {
	const BlkDevice* blk_device = get_blk_device();

	const BlkDevice* blk_device_lhs = to_lvm_pv(lhs)->get_impl().get_blk_device();
	const BlkDevice* blk_device_rhs = to_lvm_pv(rhs)->get_impl().get_blk_device();

	Text text;

	switch (resize_mode)
	{
	    case ResizeMode::SHRINK:
		text = tenser(tense,
			      // TRANSLATORS: displayed before action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 2GiB),
			      // %3$s is replaced by new size (e.g. 1GiB)
			      _("Shrink physical volume on %1$s from %2$s to %3$s"),
			      // TRANSLATORS: displayed during action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 2GiB),
			      // %3$s is replaced by new size (e.g. 1GiB)
			      _("Shrinking physical volume on %1$s from %2$s to %3$s"));
		break;

	    case ResizeMode::GROW:
		text = tenser(tense,
			      // TRANSLATORS: displayed before action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 1GiB),
			      // %3$s is replaced by new size (e.g. 2GiB)
			      _("Grow physical volume on %1$s from %2$s to %3$s"),
			      // TRANSLATORS: displayed during action,
			      // %1$s is replaced by device name (e.g. /dev/sdb1),
			      // %2$s is replaced by old size (e.g. 1GiB),
			      // %3$s is replaced by new size (e.g. 2GiB)
			      _("Growing physical volume on %1$s from %2$s to %3$s"));
		break;

	    default:
		ST_THROW(LogicException("invalid value for resize_mode"));
	}

	return sformat(text, blk_device->get_name().c_str(),
		       blk_device_lhs->get_size_string().c_str(),
		       blk_device_rhs->get_size_string().c_str());
    }

    void
    LvmPv::Impl::do_resize(ResizeMode resize_mode, const Device* rhs) const
    {
	const BlkDevice* blk_device = get_blk_device();
	const BlkDevice* blk_device_rhs = to_lvm_pv(rhs)->get_impl().get_blk_device();

	string cmd_line = PVRESIZEBIN " " + quote(blk_device->get_name());
	if (resize_mode == ResizeMode::SHRINK)
	    cmd_line += " --yes --setphysicalvolumesize " + to_string(blk_device_rhs->get_size()) + "b";

	cout << cmd_line << endl;

	wait_for_devices({ blk_device->get_name() });

	SystemCmd cmd(cmd_line);
	if (cmd.retcode() != 0)
	    ST_THROW(Exception("resize LvmPv failed"));
    }

    Text
    LvmPv::Impl::do_delete_text(Tense tense) const
    {
	const BlkDevice* blk_device = get_blk_device();

	Text text = tenser(tense,
			   // TRANSLATORS: displayed before action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Delete physical volume on %1$s"),
			   // TRANSLATORS: displayed during action,
			   // %1$s is replaced by device name (e.g. /dev/sda1)
			   _("Deleting physical volume on %1$s"));

	return sformat(text, blk_device->get_name().c_str());
    }

    void
    LvmPv::Impl::do_delete() const
    {
	const BlkDevice* blk_device = get_blk_device();

	string cmd_line = PVREMOVEBIN " " + quote(blk_device->get_name());
	cout << cmd_line << endl;

	SystemCmd cmd(cmd_line);
	if (cmd.retcode() != 0)
	    ST_THROW(Exception("delete LvmPv failed"));
    }

}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdint.h>
#include <time.h>

#include "nan.h"

using namespace node;
using namespace v8;

class Time {
  public:
  static void Init(Handle<Object> target) {
    Nan::HandleScope scope;

    // time(3)
    Nan::SetMethod(target, "time", Time_);

    // tzset(3)
    Nan::SetMethod(target, "tzset", Tzset);

    // localtime
    Nan::SetMethod(target, "localtime", Localtime);

    // mktime
    Nan::SetMethod(target, "mktime", Mktime);
  }

  static NAN_METHOD(Time_) {
    Nan::EscapableHandleScope scope;
    info.GetReturnValue().Set(scope.Escape(Nan::New<v8::Number>(time(NULL))));
  }

  static NAN_METHOD(Tzset) {
    Nan::EscapableHandleScope scope;

    // Set up the timezone info from the current TZ environ variable
    tzset();

    // Set up a return object that will hold the results of the timezone change
    Local<Object> obj = Nan::New<v8::Object>();

    // The 'tzname' char * [] gets put into a JS Array
    int tznameLength = 2;
    Local<Array> tznameArray = Nan::New<v8::Array>( tznameLength );
#if _MSC_VER >= 1900
	char szTzName[128];

	for (int i = 0; i < tznameLength; i++) {
		_get_tzname(nullptr, szTzName, 128, i);
		Nan::Set(tznameArray, i, Nan::New<v8::String>(szTzName).ToLocalChecked());
	}

	Nan::Set(obj, Nan::New("tzname").ToLocalChecked(), tznameArray);

	// The 'timezone' long is the "seconds West of UTC"
	long timezone;
	_get_timezone(&timezone);
	Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New<v8::Number>(timezone));

	// The 'daylight' int is obselete actually, but I'll include it here for
	// curiosity's sake. See the "Notes" section of "man tzset"
	int daylight;
	_get_daylight(&daylight);
	Nan::Set(obj, Nan::New("daylight").ToLocalChecked(), Nan::New<v8::Number>(daylight));
#else
    for (int i=0; i < tznameLength; i++) {
      Nan::Set(tznameArray, i, Nan::New<v8::String>(tzname[i]).ToLocalChecked());
    }

    Nan::Set(obj, Nan::New("tzname").ToLocalChecked(), tznameArray);

    // The 'timezone' long is the "seconds West of UTC"
    Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New<v8::Number>( timezone ));

    // The 'daylight' int is obselete actually, but I'll include it here for
    // curiosity's sake. See the "Notes" section of "man tzset"
    Nan::Set(obj, Nan::New("daylight").ToLocalChecked(), Nan::New<v8::Number>( daylight ));
#endif
    info.GetReturnValue().Set(scope.Escape(obj));
  }

  static NAN_METHOD(Localtime) {
    Nan::EscapableHandleScope scope;

    // Construct the 'tm' struct
    time_t rawtime = static_cast<time_t>(info[0]->IntegerValue());
    struct tm *timeinfo = localtime( &rawtime );

    // Create the return "Object"
    Local<Object> obj = Nan::New<v8::Object>();

    if (timeinfo) {
      Nan::Set(obj, Nan::New("seconds").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_sec) );
      Nan::Set(obj, Nan::New("minutes").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_min) );
      Nan::Set(obj, Nan::New("hours").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_hour) );
      Nan::Set(obj, Nan::New("dayOfMonth").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_mday) );
      Nan::Set(obj, Nan::New("month").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_mon) );
      Nan::Set(obj, Nan::New("year").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_year) );
      Nan::Set(obj, Nan::New("dayOfWeek").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_wday) );
      Nan::Set(obj, Nan::New("dayOfYear").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_yday) );
      Nan::Set(obj, Nan::New("isDaylightSavings").ToLocalChecked(), Nan::New<v8::Boolean>(timeinfo->tm_isdst > 0) );

#if defined HAVE_TM_GMTOFF
      // Only available with glibc's "tm" struct. Most Linuxes, Mac OS X...
      Nan::Set(obj, Nan::New("gmtOffset").ToLocalChecked(), Nan::New<v8::Number>(timeinfo->tm_gmtoff) );
      Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New(timeinfo->tm_zone).ToLocalChecked() );

#elif defined HAVE_TIMEZONE
      // Compatibility for Cygwin, Solaris, probably others...
      long scd;
      if (timeinfo->tm_isdst > 0) {
  #ifdef HAVE_ALTZONE
        scd = -altzone;
  #else
        scd = -timezone + 3600;
  #endif // HAVE_ALTZONE
      } else {
        scd = -timezone;
      }
      Nan::Set(obj, Nan::New("gmtOffset").ToLocalChecked(), Nan::New<v8::Integer>(scd));
      Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New<v8::String>(tzname[timeinfo->tm_isdst]));
#endif // HAVE_TM_GMTOFF
    } else {
      Nan::Set(obj, Nan::New("invalid").ToLocalChecked(), Nan::New<v8::Boolean>(true));
    }

    info.GetReturnValue().Set(scope.Escape(obj));
  }

  static NAN_METHOD(Mktime) {
    Nan::EscapableHandleScope scope;

    if (info.Length() < 1) {
      return Nan::ThrowTypeError("localtime() Object expected");
    }

    Local<Object> arg = info[0].As<v8::Object>();

    struct tm tmstr;
    tmstr.tm_sec   = Nan::Get(arg, Nan::New("seconds").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_min   = Nan::Get(arg, Nan::New("minutes").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_hour  = Nan::Get(arg, Nan::New("hours").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_mday  = Nan::Get(arg, Nan::New("dayOfMonth").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_mon   = Nan::Get(arg, Nan::New("month").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_year  = Nan::Get(arg, Nan::New("year").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_isdst = Nan::Get(arg, Nan::New("isDaylightSavings").ToLocalChecked()).ToLocalChecked()->Int32Value();
    // tm_wday and tm_yday are ignored for input, but properly set after 'mktime' is called

    info.GetReturnValue().Set(scope.Escape(Nan::New<v8::Number>(static_cast<double>(mktime( &tmstr )))));
  }

};

extern "C" {
  static void init (Handle<Object> target) {
    Time::Init(target);
  }
  NODE_MODULE(time, init)
}
<commit_msg>fix bug<commit_after>#include <stdio.h>
#include <stdint.h>
#include <time.h>

#include "nan.h"

using namespace node;
using namespace v8;

class Time {
  public:
  static void Init(Handle<Object> target) {
    Nan::HandleScope scope;

    // time(3)
    Nan::SetMethod(target, "time", Time_);

    // tzset(3)
    Nan::SetMethod(target, "tzset", Tzset);

    // localtime
    Nan::SetMethod(target, "localtime", Localtime);

    // mktime
    Nan::SetMethod(target, "mktime", Mktime);
  }

  static NAN_METHOD(Time_) {
    Nan::EscapableHandleScope scope;
    info.GetReturnValue().Set(scope.Escape(Nan::New<v8::Number>(time(NULL))));
  }

  static NAN_METHOD(Tzset) {
    Nan::EscapableHandleScope scope;

    // Set up the timezone info from the current TZ environ variable
    tzset();

    // Set up a return object that will hold the results of the timezone change
    Local<Object> obj = Nan::New<v8::Object>();

    // The 'tzname' char * [] gets put into a JS Array
    int tznameLength = 2;
    Local<Array> tznameArray = Nan::New<v8::Array>( tznameLength );
#if _MSC_VER >= 1900
	char szTzName[128];

	for (int i = 0; i < tznameLength; i++) {
		size_t strLength;
		_get_tzname(&strLength, szTzName, 128, i);
		Nan::Set(tznameArray, i, Nan::New<v8::String>(szTzName).ToLocalChecked());
	}

	Nan::Set(obj, Nan::New("tzname").ToLocalChecked(), tznameArray);

	// The 'timezone' long is the "seconds West of UTC"
	long timezone;
	_get_timezone(&timezone);
	Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New<v8::Number>(timezone));

	// The 'daylight' int is obselete actually, but I'll include it here for
	// curiosity's sake. See the "Notes" section of "man tzset"
	int daylight;
	_get_daylight(&daylight);
	Nan::Set(obj, Nan::New("daylight").ToLocalChecked(), Nan::New<v8::Number>(daylight));
#else
    for (int i=0; i < tznameLength; i++) {
      Nan::Set(tznameArray, i, Nan::New<v8::String>(tzname[i]).ToLocalChecked());
    }

    Nan::Set(obj, Nan::New("tzname").ToLocalChecked(), tznameArray);

    // The 'timezone' long is the "seconds West of UTC"
    Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New<v8::Number>( timezone ));

    // The 'daylight' int is obselete actually, but I'll include it here for
    // curiosity's sake. See the "Notes" section of "man tzset"
    Nan::Set(obj, Nan::New("daylight").ToLocalChecked(), Nan::New<v8::Number>( daylight ));
#endif
    info.GetReturnValue().Set(scope.Escape(obj));
  }

  static NAN_METHOD(Localtime) {
    Nan::EscapableHandleScope scope;

    // Construct the 'tm' struct
    time_t rawtime = static_cast<time_t>(info[0]->IntegerValue());
    struct tm *timeinfo = localtime( &rawtime );

    // Create the return "Object"
    Local<Object> obj = Nan::New<v8::Object>();

    if (timeinfo) {
      Nan::Set(obj, Nan::New("seconds").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_sec) );
      Nan::Set(obj, Nan::New("minutes").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_min) );
      Nan::Set(obj, Nan::New("hours").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_hour) );
      Nan::Set(obj, Nan::New("dayOfMonth").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_mday) );
      Nan::Set(obj, Nan::New("month").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_mon) );
      Nan::Set(obj, Nan::New("year").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_year) );
      Nan::Set(obj, Nan::New("dayOfWeek").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_wday) );
      Nan::Set(obj, Nan::New("dayOfYear").ToLocalChecked(), Nan::New<v8::Integer>(timeinfo->tm_yday) );
      Nan::Set(obj, Nan::New("isDaylightSavings").ToLocalChecked(), Nan::New<v8::Boolean>(timeinfo->tm_isdst > 0) );

#if defined HAVE_TM_GMTOFF
      // Only available with glibc's "tm" struct. Most Linuxes, Mac OS X...
      Nan::Set(obj, Nan::New("gmtOffset").ToLocalChecked(), Nan::New<v8::Number>(timeinfo->tm_gmtoff) );
      Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New(timeinfo->tm_zone).ToLocalChecked() );

#elif defined HAVE_TIMEZONE
      // Compatibility for Cygwin, Solaris, probably others...
      long scd;
      if (timeinfo->tm_isdst > 0) {
  #ifdef HAVE_ALTZONE
        scd = -altzone;
  #else
        scd = -timezone + 3600;
  #endif // HAVE_ALTZONE
      } else {
        scd = -timezone;
      }
      Nan::Set(obj, Nan::New("gmtOffset").ToLocalChecked(), Nan::New<v8::Integer>(scd));
      Nan::Set(obj, Nan::New("timezone").ToLocalChecked(), Nan::New<v8::String>(tzname[timeinfo->tm_isdst]));
#endif // HAVE_TM_GMTOFF
    } else {
      Nan::Set(obj, Nan::New("invalid").ToLocalChecked(), Nan::New<v8::Boolean>(true));
    }

    info.GetReturnValue().Set(scope.Escape(obj));
  }

  static NAN_METHOD(Mktime) {
    Nan::EscapableHandleScope scope;

    if (info.Length() < 1) {
      return Nan::ThrowTypeError("localtime() Object expected");
    }

    Local<Object> arg = info[0].As<v8::Object>();

    struct tm tmstr;
    tmstr.tm_sec   = Nan::Get(arg, Nan::New("seconds").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_min   = Nan::Get(arg, Nan::New("minutes").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_hour  = Nan::Get(arg, Nan::New("hours").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_mday  = Nan::Get(arg, Nan::New("dayOfMonth").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_mon   = Nan::Get(arg, Nan::New("month").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_year  = Nan::Get(arg, Nan::New("year").ToLocalChecked()).ToLocalChecked()->Int32Value();
    tmstr.tm_isdst = Nan::Get(arg, Nan::New("isDaylightSavings").ToLocalChecked()).ToLocalChecked()->Int32Value();
    // tm_wday and tm_yday are ignored for input, but properly set after 'mktime' is called

    info.GetReturnValue().Set(scope.Escape(Nan::New<v8::Number>(static_cast<double>(mktime( &tmstr )))));
  }

};

extern "C" {
  static void init (Handle<Object> target) {
    Time::Init(target);
  }
  NODE_MODULE(time, init)
}
<|endoftext|>


<commit_before>/* Copyright (c) 2009, Sebastien Mirolo
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
     * Neither the name of fortylines nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY Sebastien Mirolo ''AS IS'' AND ANY
   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL Sebastien Mirolo BE LIABLE FOR ANY
   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include <cstdlib>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include "todo.hh"
#include "aws.hh"

boost::uuids::uuid todouuid( const boost::filesystem::path& p ) {
    return asuuid(boost::filesystem::basename(p.filename()));
}

const boost::regex todoFilter::viewPat(".*todos/.+");
const boost::filesystem::path todoFilter::active("/contrib/todos/active/");

std::string todoFilter::asPath( const std::string& tag ) {
    std::stringstream s;
    s << active << tag << ".todo";
    return s.str();
}

std::string todoFilter::asPath( boost::uuids::uuid tag ) {
    std::stringstream s;
    s << active << tag << ".todo";
    return s.str();
}

class todoliner : public todoFilter {
public:

    virtual void filters( const post& );
};

class byScore : public postFilter {
protected:
    typedef std::vector<post> indexSet;

    indexSet indexes;

public:
    explicit byScore( postFilter &n ) : postFilter(&n) {}

    virtual void filters( const post& );
    virtual void flush();
};

class todoCreateFeedback : public postFilter {
public:
    virtual void filters( const post& );
};

class todocreator : public todoFilter {
protected:
    const session *s;

public:
    todocreator( const session& v, postFilter* n  )
	: todoFilter(n), s(&v) {}

    virtual void filters( const post& );
};

class todocommentor : public postFilter {
protected:
    const session *s;

public:
    todocommentor( const session& v, postFilter* n  )
	: postFilter(n), s(&v) {}

    virtual void filters( const post& );
};

void todoCreateFeedback::filters( const post& p ) {
    std::cout << htmlContent;
    std::cout << html::p() << "item " << p.tag << " has been created."
	      <srcDir(asPath(p.tag)));

    blogwriter writer(file);
    writer.filters(p);
    file.flush();
    file.close();
    next->filters(p);
#else
    throw std::runtime_error("Todo item could not be created"
	" because you do not have permissions to do so on this server."
	" Sorry for the inconvienience.");
#endif

}

void todocommentor::filters( const post& v ) {

}

void todoliner::filters( const post& p ) {
    std::cout << html::tr()
	      << "" << std::endl
	      << html::td() << p.time.date() << html::td::end
	      << html::td() << p.authorEmail << html::td::end
	      << html::td() << html::a().href(asPath(p.tag))
	      << p.title
	      << html::a::end << html::td::end;
    std::cout << html::td()
	      << p.score
	      << html::td::end;
    std::cout << html::tr::end;
}

void byScore::filters( const post& p )
{
    indexes.push_back(p);
}

void byScore::flush()
{
    if( indexes.empty() ) {
	std::cout << html::tr()
		  << html::td().colspan("4")
		  << "no todo items present"
		  << html::td::end
		  <filters(*idx);
	}
	next->flush();
    }
}

void todoAppendPost::fetch( session& s,
			    const boost::filesystem::path& pathname )
{
}

void todoCreate::fetch( session& s, const boost::filesystem::path& pathname )
{
    post p;
    p.score = 0;
    p.title = s.valueOf("title");
    p.authorEmail = s.valueOf("author");
    p.descr = s.valueOf("descr");

    todoCreateFeedback fb;
    todocreator create(s,&fb);
    if( p.valid() ) {
	create.filters(p);

    } else {
	mailParser parser(create);
	parser.walk(s,*istr);
    }
}

void todoComment::fetch( session& s, const boost::filesystem::path& pathname )
{
    using namespace boost::system;
    using namespace boost::filesystem;

    boost::filesystem::path postname(boost::filesystem::exists(pathname) ?
				     pathname
				     : s.abspath(s.valueOf("href")));

    post p;
    p.authorEmail = s.valueOf("author");
    p.descr = s.valueOf("descr");
    p.time = boost::posix_time::second_clock::local_time();
    p.tag = todouuid(postname);
    p.score = 0;

#if 0
    if( p.valid() ) {
	comment.filters(p);
    } else {
	mailParser parser(comment);
	parser.walk(s,*istr);
    }
#endif

#ifndef READONLY
    boost::interprocess::file_lock f_lock(postname.string().c_str());
    boost::filesystem::ofstream file;

    f_lock.lock();
    file.open(postname,std::ios_base::out | std::ios_base::app);
    if( file.fail() ) {
	f_lock.unlock();
	boost::throw_exception(basic_filesystem_error<path>(
	   std::string("unable to open file"),
	   postname,
	   error_code()));
    }

    blogwriter writer(file);
    writer.filters(p);
    file.flush();

    file.close();
    f_lock.unlock();

#if 0
    std::cout << redirect(s.asUrl(postname).string())
	      << htmlContent << std::endl;
#else
    /* \todo clean-up. We use this code such that the browser displays
       the correct url. If we use a redirect, it only works with static pages (index.html). */
    std::cout << htmlContent << std::endl << "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=" << s.asUrl(postname).string() << "\">" << std::endl;
#endif

#else
    std::cout << htmlContent << std::endl;
    std::cout << html::p() << "comment could not be created"
	" because you do not have permissions to do so on this server."
	" Sorry for the inconvienience."
	      << html::p::end;
#endif

}

void todoIndexWriteHtml::fetch( session& s,
				const boost::filesystem::path& pathname )
{
    todoliner shortline;
    byScore order(shortline);
    mailParser parser(order,true);
    parser.fetch(s,pathname);
}

void todoVoteAbandon::fetch( session& s,
			     const boost::filesystem::path& pathname ) {
	std::cout << htmlContent;
	std::cout << html::p() << "You have abandon the transaction and thus"
		  << " your vote has not been registered."
		  << " Thank you for your interest."
		  << html::p::end;
}

void todoVoteSuccess::fetch( session& s,
			     const boost::filesystem::path& pathname )
{
    awsStandardButton button(s.valueOf("awsAccessKey"),
			     s.valueOf("awsSecretKey"),
			     s.valueOf("awsCertificate"));
    if( !button.checkReturn(s,"/todoVoteSuccess") ) {
	std::cout << "error wrong request signature" << std::endl;
	return;
    }

    /* The pathname is set to the *todoVote* action name when we get here
       so we derive the document name from *href*. */
    boost::filesystem::path postname(boost::filesystem::exists(pathname) ?
				     pathname
			      : todoFilter::asPath(s.valueOf("referenceId")));

    if( !boost::filesystem::is_regular_file(postname) ) {
	/* If *postname* does not point to a regular file,
	   the inputs were incorrect somehome.
	 */
	std::cout << htmlContent;
	std::cout << html::p() << postname
		  << " does not appear to be a regular file on the server"
		  << " and thus your vote for it cannot be registered."
	    " Please " << html::a().href("info@fortylines.com") << "contact us"
		  << html::a::end << " about the issue."
		  << " Sorry for the inconvienience."
		  << html::p::end;
	return;
    }

    boost::uuids::uuid tag = asuuid(boost::filesystem::basename(postname));

    /* make temporary file */
    char tmpname[FILENAME_MAX] = "vote-XXXXXX";
    int fildes = mkstemp(tmpname);

    /* read/copy with score update */
    uint32_t score = 0;
    boost::interprocess::file_lock f_lock(postname.string().c_str());
    f_lock.lock();
    boost::filesystem::ifstream infile(postname);
    while( !infile.eof() ) {
	std::string line;
	std::getline(infile,line);
	line += '\n';
	if( line.compare(0,7,"Score: ") == 0 ) {
	    std::stringstream s;
	    score = atoi(line.substr(7).c_str()) + 1;
	    s << "Score: " << score << std::endl;
	    write(fildes,s.str().c_str(),s.str().size());
	} else {
	    write(fildes,line.c_str(),line.size());
	}
    }
    infile.close();
    close(fildes);

    /* move temporary back to original */
    if( score > 0 ) {
	boost::filesystem::remove(postname);
	boost::filesystem::rename(tmpname,postname);

	std::cout << htmlContent;
	std::cout << html::p() << "Your vote for item "
		  << tag << " has been registered. Thank you."
		  << html::p::end;
    } else {
	std::cout << htmlContent;
	std::cout << html::p() << "There does not appear to have any"
	    " score associated with item " << tag << " thus your"
	    " vote cannot be registered. Sorry for the inconvienience."
		  << html::p::end;
    }
    f_lock.unlock();
}

void todoWriteHtml::meta( session& s,
			  const boost::filesystem::path& pathname ) {
    using namespace boost::filesystem;
    static const boost::regex valueEx("^(Subject):\\s+(.*)");

    std::stringstream title;
    title << '[' << todouuid(pathname) << ']';
    ifstream strm;
    open(strm,pathname);
    while( !strm.eof() ) {
	boost::smatch m;
	std::string line;
	std::getline(strm,line);
	if( boost::regex_search(line,m,valueEx) ) {
	    title << ' ' << m.str(2);
	    break;
	}
    }
    strm.close();
    s.vars["Subject"] = title.str();
    document::meta(s,pathname);
}

void
todoWriteHtml::fetch( session& s, const boost::filesystem::path& pathname )
{
    htmlwriter writer(std::cout);
    mailParser parser(writer);
    parser.fetch(s,pathname);
}
<commit_msg>extend to absolute path<commit_after>/* Copyright (c) 2009, Sebastien Mirolo
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.
     * Neither the name of fortylines nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY Sebastien Mirolo ''AS IS'' AND ANY
   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   DISCLAIMED. IN NO EVENT SHALL Sebastien Mirolo BE LIABLE FOR ANY
   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */

#include <cstdlib>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include "todo.hh"
#include "aws.hh"

boost::uuids::uuid todouuid( const boost::filesystem::path& p ) {
    return asuuid(boost::filesystem::basename(p.filename()));
}

const boost::regex todoFilter::viewPat(".*todos/.+");
const boost::filesystem::path todoFilter::active("/contrib/todos/active/");

std::string todoFilter::asPath( const std::string& tag ) {
    std::stringstream s;
    s << active << tag << ".todo";
    return s.str();
}

std::string todoFilter::asPath( boost::uuids::uuid tag ) {
    std::stringstream s;
    s << active << tag << ".todo";
    return s.str();
}

class todoliner : public todoFilter {
public:

    virtual void filters( const post& );
};

class byScore : public postFilter {
protected:
    typedef std::vector<post> indexSet;

    indexSet indexes;

public:
    explicit byScore( postFilter &n ) : postFilter(&n) {}

    virtual void filters( const post& );
    virtual void flush();
};

class todoCreateFeedback : public postFilter {
public:
    virtual void filters( const post& );
};

class todocreator : public todoFilter {
protected:
    const session *s;

public:
    todocreator( const session& v, postFilter* n  )
	: todoFilter(n), s(&v) {}

    virtual void filters( const post& );
};

class todocommentor : public postFilter {
protected:
    const session *s;

public:
    todocommentor( const session& v, postFilter* n  )
	: postFilter(n), s(&v) {}

    virtual void filters( const post& );
};

void todoCreateFeedback::filters( const post& p ) {
    std::cout << htmlContent;
    std::cout << html::p() << "item " << p.tag << " has been created."
	      <srcDir(asPath(p.tag)));

    blogwriter writer(file);
    writer.filters(p);
    file.flush();
    file.close();
    next->filters(p);
#else
    throw std::runtime_error("Todo item could not be created"
	" because you do not have permissions to do so on this server."
	" Sorry for the inconvienience.");
#endif

}

void todocommentor::filters( const post& v ) {

}

void todoliner::filters( const post& p ) {
    std::cout << html::tr()
	      << "" << std::endl
	      << html::td() << p.time.date() << html::td::end
	      << html::td() << p.authorEmail << html::td::end
	      << html::td() << html::a().href(asPath(p.tag))
	      << p.title
	      << html::a::end << html::td::end;
    std::cout << html::td()
	      << p.score
	      << html::td::end;
    std::cout << html::tr::end;
}

void byScore::filters( const post& p )
{
    indexes.push_back(p);
}

void byScore::flush()
{
    if( indexes.empty() ) {
	std::cout << html::tr()
		  << html::td().colspan("4")
		  << "no todo items present"
		  << html::td::end
		  <filters(*idx);
	}
	next->flush();
    }
}

void todoAppendPost::fetch( session& s,
			    const boost::filesystem::path& pathname )
{
}

void todoCreate::fetch( session& s, const boost::filesystem::path& pathname )
{
    post p;
    p.score = 0;
    p.title = s.valueOf("title");
    p.authorEmail = s.valueOf("author");
    p.descr = s.valueOf("descr");

    todoCreateFeedback fb;
    todocreator create(s,&fb);
    if( p.valid() ) {
	create.filters(p);

    } else {
	mailParser parser(create);
	parser.walk(s,*istr);
    }
}

void todoComment::fetch( session& s, const boost::filesystem::path& pathname )
{
    using namespace boost::system;
    using namespace boost::filesystem;

    boost::filesystem::path postname(boost::filesystem::exists(pathname) ?
				     pathname
				     : s.abspath(s.valueOf("href")));

    post p;
    p.authorEmail = s.valueOf("author");
    p.descr = s.valueOf("descr");
    p.time = boost::posix_time::second_clock::local_time();
    p.tag = todouuid(postname);
    p.score = 0;

#if 0
    if( p.valid() ) {
	comment.filters(p);
    } else {
	mailParser parser(comment);
	parser.walk(s,*istr);
    }
#endif

#ifndef READONLY
    boost::interprocess::file_lock f_lock(postname.string().c_str());
    boost::filesystem::ofstream file;

    f_lock.lock();
    file.open(postname,std::ios_base::out | std::ios_base::app);
    if( file.fail() ) {
	f_lock.unlock();
	boost::throw_exception(basic_filesystem_error<path>(
	   std::string("unable to open file"),
	   postname,
	   error_code()));
    }

    blogwriter writer(file);
    writer.filters(p);
    file.flush();

    file.close();
    f_lock.unlock();

#if 0
    std::cout << redirect(s.asUrl(postname).string())
	      << htmlContent << std::endl;
#else
    /* \todo clean-up. We use this code such that the browser displays
       the correct url. If we use a redirect, it only works with static pages (index.html). */
    std::cout << htmlContent << std::endl << "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=" << s.asUrl(postname).string() << "\">" << std::endl;
#endif

#else
    std::cout << htmlContent << std::endl;
    std::cout << html::p() << "comment could not be created"
	" because you do not have permissions to do so on this server."
	" Sorry for the inconvienience."
	      << html::p::end;
#endif

}

void todoIndexWriteHtml::fetch( session& s,
				const boost::filesystem::path& pathname )
{
    todoliner shortline;
    byScore order(shortline);
    mailParser parser(order,true);
    parser.fetch(s,pathname);
}

void todoVoteAbandon::fetch( session& s,
			     const boost::filesystem::path& pathname ) {
	std::cout << htmlContent;
	std::cout << html::p() << "You have abandon the transaction and thus"
		  << " your vote has not been registered."
		  << " Thank you for your interest."
		  << html::p::end;
}

void todoVoteSuccess::fetch( session& s,
			     const boost::filesystem::path& pathname )
{
    awsStandardButton button(s.valueOf("awsAccessKey"),
			     s.valueOf("awsSecretKey"),
			     s.valueOf("awsCertificate"));
    if( !button.checkReturn(s,"/todoVoteSuccess") ) {
	std::cout << "error wrong request signature" << std::endl;
	return;
    }

    /* The pathname is set to the *todoVote* action name when we get here
       so we derive the document name from *href*. */
    boost::filesystem::path postname(boost::filesystem::exists(pathname) ?
				     pathname
		: s.srcDir(todoFilter::asPath(s.valueOf("referenceId"))));

    if( !boost::filesystem::is_regular_file(postname) ) {
	/* If *postname* does not point to a regular file,
	   the inputs were incorrect somehome.
	 */
	std::cout << htmlContent;
	std::cout << html::p() << postname
		  << " does not appear to be a regular file on the server"
		  << " and thus your vote for it cannot be registered."
	    " Please " << html::a().href("info@fortylines.com") << "contact us"
		  << html::a::end << " about the issue."
		  << " Sorry for the inconvienience."
		  << html::p::end;
	return;
    }

    boost::uuids::uuid tag = asuuid(boost::filesystem::basename(postname));

    /* make temporary file */
    char tmpname[FILENAME_MAX] = "vote-XXXXXX";
    int fildes = mkstemp(tmpname);

    /* read/copy with score update */
    uint32_t score = 0;
    boost::interprocess::file_lock f_lock(postname.string().c_str());
    f_lock.lock();
    boost::filesystem::ifstream infile(postname);
    while( !infile.eof() ) {
	std::string line;
	std::getline(infile,line);
	line += '\n';
	if( line.compare(0,7,"Score: ") == 0 ) {
	    std::stringstream s;
	    score = atoi(line.substr(7).c_str()) + 1;
	    s << "Score: " << score << std::endl;
	    write(fildes,s.str().c_str(),s.str().size());
	} else {
	    write(fildes,line.c_str(),line.size());
	}
    }
    infile.close();
    close(fildes);

    /* move temporary back to original */
    if( score > 0 ) {
	boost::filesystem::remove(postname);
	boost::filesystem::rename(tmpname,postname);

	std::cout << htmlContent;
	std::cout << html::p() << "Your vote for item "
		  << tag << " has been registered. Thank you."
		  << html::p::end;
    } else {
	std::cout << htmlContent;
	std::cout << html::p() << "There does not appear to have any"
	    " score associated with item " << tag << " thus your"
	    " vote cannot be registered. Sorry for the inconvienience."
		  << html::p::end;
    }
    f_lock.unlock();
}

void todoWriteHtml::meta( session& s,
			  const boost::filesystem::path& pathname ) {
    using namespace boost::filesystem;
    static const boost::regex valueEx("^(Subject):\\s+(.*)");

    std::stringstream title;
    title << '[' << todouuid(pathname) << ']';
    ifstream strm;
    open(strm,pathname);
    while( !strm.eof() ) {
	boost::smatch m;
	std::string line;
	std::getline(strm,line);
	if( boost::regex_search(line,m,valueEx) ) {
	    title << ' ' << m.str(2);
	    break;
	}
    }
    strm.close();
    s.vars["Subject"] = title.str();
    document::meta(s,pathname);
}

void
todoWriteHtml::fetch( session& s, const boost::filesystem::path& pathname )
{
    htmlwriter writer(std::cout);
    mailParser parser(writer);
    parser.fetch(s,pathname);
}
<|endoftext|>


<commit_before>#include "service.h"
#include <string>
#include <fstream>
#include <locale>
#include <iostream>

typedef std::string string;
typedef std::string::iterator string_iterator;

// Utility function to skip white space. Returns an iterator at the
// first non-white-space position (or at end).
static string_iterator skipws(string_iterator i, string_iterator end)
{
    using std::locale;
    using std::isspace;

    while (i != end) {
      if (! isspace(*i, locale::classic())) {
        break;
      }
      ++i;
    }
    return i;
}

// Read a setting name.
static string read_setting_name(string_iterator & i, string_iterator end)
{
    using std::locale;
    using std::ctype;
    using std::use_facet;

    const ctype<char> & facet = use_facet<ctype<char> >(locale::classic());

    string rval;
    // Allow alphabetical characters, and dash (-) in setting name
    while (i != end && (*i == '-' || facet.is(ctype<char>::alpha, *i))) {
        rval += *i;
        ++i;
    }
    return rval;
}

// Read a setting value
//
// In general a setting value is a single-line string. It may contain multiple parts
// separated by white space (which is normally collapsed). A hash mark - # - denotes
// the end of the value and the beginning of a comment (it should be preceded by
// whitespace).
//
// Part of a value may be quoted using double quote marks, which prevents collapse
// of whitespace and interpretation of most special characters (the quote marks will
// not be considered part of the value). A backslash can precede a character (such
// as '#' or '"' or another backslash) to remove its special meaning. Newline
// characters are not allowed in values and cannot be quoted.
//
// This function expects the string to be in an ASCII-compatible, single byte
// encoding (the "classic" locale).
static string read_setting_value(string_iterator & i, string_iterator end,
        std::list<std::pair<int,int>> * part_positions = nullptr)
{
    using std::locale;
    using std::isspace;

    i = skipws(i, end);

    string rval;
    bool new_part = true;
    int part_start;

    while (i != end) {
        char c = *i;
        if (c == '\"') {
            if (new_part) {
                part_start = rval.length();
                new_part = false;
            }
            // quoted string
            ++i;
            while (i != end) {
                c = *i;
                if (c == '\"') break;
                if (c == '\n') {
                    // TODO error here.
                }
                else if (c == '\\') {
                    // A backslash escapes the following character.
                    ++i;
                    if (i != end) {
                        c = *i;
                        if (c == '\n') {
                            // TODO error here.
                        }
                        rval += c;
                    }
                }
                else {
                    rval += c;
                }
                ++i;
            }
            if (i == end) {
                // String wasn't terminated
                // TODO error here
                break;
            }
        }
        else if (c == '\\') {
            if (new_part) {
                part_start = rval.length();
                new_part = false;
            }
            // A backslash escapes the next character
            ++i;
            if (i != end) {
                rval += *i;
            }
            else {
                // TODO error here
            }
        }
        else if (isspace(c, locale::classic())) {
            if (! new_part && part_positions != nullptr) {
                part_positions->emplace_back(part_start, rval.length());
                new_part = true;
            }
            i = skipws(i, end);
            if (i == end) break;
            if (*i == '#') break; // comment
            rval += ' ';  // collapse ws to a single space
            continue;
        }
        else if (c == '#') {
            // hmm... comment? Probably, though they should have put a space
            // before it really. TODO throw an exception, and document
            // that '#' for comments must be preceded by space, and in values
            // must be quoted.
            break;
        }
        else {
            if (new_part) {
                part_start = rval.length();
                new_part = false;
            }
            rval += c;
        }
        ++i;
    }

    return rval;
}

// Find a service record, or load it from file. If the service has
// dependencies, load those also.
//
// Might throw a ServiceLoadExc exception if a dependency cycle is found or if another
// problem occurs (I/O error, service description not found etc).
ServiceRecord * ServiceSet::loadServiceRecord(const char * name)
{
    using std::string;
    using std::ifstream;
    using std::ios;
    using std::ios_base;
    using std::locale;
    using std::isspace;

    // First try and find an existing record...
    ServiceRecord * rval = findService(string(name));
    if (rval != 0) {
        if (rval->isDummy()) {
            throw ServiceCyclicDependency(name);
        }
        return rval;
    }

    // Couldn't find one. Have to load it.
    string service_filename = service_dir;
    if (*(service_filename.rbegin()) != '/') {
        service_filename += '/';
    }
    service_filename += name;

    string command;
    int service_type = SVC_PROCESS;
    std::list<ServiceRecord *> depends_on;
    std::list<ServiceRecord *> depends_soft;
    string logfile;

    // TODO catch I/O exceptions, wrap & re-throw?
    string line;
    bool auto_restart = false;
    ifstream service_file;
    service_file.exceptions(ios::badbit | ios::failbit);

    try {
        service_file.open(service_filename.c_str(), ios::in);
    }
    catch (std::ios_base::failure &exc) {
        throw ServiceNotFound(name);
    }

    // Add a dummy service record now to prevent cyclic dependencies
    rval = new ServiceRecord(this, string(name));
    records.push_back(rval);

    // getline can set failbit if it reaches end-of-file, we don't want an exception in that case:
    service_file.exceptions(ios::badbit);

    while (! (service_file.rdstate() & ios::eofbit)) {
        getline(service_file, line);
        string::iterator i = line.begin();
        string::iterator end = line.end();

        i = skipws(i, end);
        if (i != end) {
            if (*i == '#') {
                continue;  // comment line
            }
            string setting = read_setting_name(i, end);
            i = skipws(i, end);
            if (i == end || (*i != '=' && *i != ':')) {
                throw ServiceDescriptionExc(name, "Badly formed line.");
            }
            i = skipws(++i, end);

            if (setting == "command") {
                command = read_setting_value(i, end);
            }
            else if (setting == "depends-on") {
                string dependency_name = read_setting_value(i, end);
                depends_on.push_back(loadServiceRecord(dependency_name.c_str()));
            }
            else if (setting == "waits-for") {
                string dependency_name = read_setting_value(i, end);
                depends_soft.push_back(loadServiceRecord(dependency_name.c_str()));
            }
            else if (setting == "logfile") {
                logfile = read_setting_value(i, end);
            }
            else if (setting == "restart") {
                string restart = read_setting_value(i, end);
                auto_restart = (restart == "yes" || restart == "true");
            }
            else if (setting == "type") {
                string type_str = read_setting_value(i, end);
                if (type_str == "scripted") {
                    service_type = SVC_SCRIPTED;
                }
                else if (type_str == "process") {
                    service_type = SVC_PROCESS;
                }
                else if (type_str == "internal") {
                    service_type = SVC_INTERNAL;
                }
                else {
                    throw ServiceDescriptionExc(name, "Service type must be \"scripted\""
                        " or \"process\" or \"internal\"");
                }
            }
            else {
                throw ServiceDescriptionExc(name, "Unknown setting: " + setting);
            }
        }
    }

    service_file.close();
    // TODO check we actually have all the settings - type, command

    // Now replace the dummy service record with a real record:
    for (auto iter = records.begin(); iter != records.end(); iter++) {
        if (*iter == rval) {
            // We've found the dummy record
            delete rval;
            rval = new ServiceRecord(this, string(name), service_type, command,
                    & depends_on, & depends_soft);
            rval->setLogfile(logfile);
            rval->setAutoRestart(auto_restart);
            *iter = rval;
            break;
        }
    }

    return rval;
}
<commit_msg>Add parameter documentation for read_setting_value<commit_after>#include "service.h"
#include <string>
#include <fstream>
#include <locale>
#include <iostream>

typedef std::string string;
typedef std::string::iterator string_iterator;

// Utility function to skip white space. Returns an iterator at the
// first non-white-space position (or at end).
static string_iterator skipws(string_iterator i, string_iterator end)
{
    using std::locale;
    using std::isspace;

    while (i != end) {
      if (! isspace(*i, locale::classic())) {
        break;
      }
      ++i;
    }
    return i;
}

// Read a setting name.
static string read_setting_name(string_iterator & i, string_iterator end)
{
    using std::locale;
    using std::ctype;
    using std::use_facet;

    const ctype<char> & facet = use_facet<ctype<char> >(locale::classic());

    string rval;
    // Allow alphabetical characters, and dash (-) in setting name
    while (i != end && (*i == '-' || facet.is(ctype<char>::alpha, *i))) {
        rval += *i;
        ++i;
    }
    return rval;
}

// Read a setting value
//
// In general a setting value is a single-line string. It may contain multiple parts
// separated by white space (which is normally collapsed). A hash mark - # - denotes
// the end of the value and the beginning of a comment (it should be preceded by
// whitespace).
//
// Part of a value may be quoted using double quote marks, which prevents collapse
// of whitespace and interpretation of most special characters (the quote marks will
// not be considered part of the value). A backslash can precede a character (such
// as '#' or '"' or another backslash) to remove its special meaning. Newline
// characters are not allowed in values and cannot be quoted.
//
// This function expects the string to be in an ASCII-compatible, single byte
// encoding (the "classic" locale).
//
// Params:
//    i  -  reference to string iterator through the line
//    end -   iterator at end of line
//    part_positions -  list of <int,int> to which the position of each setting value
//                      part will be added as [start,end). May be null.
static string read_setting_value(string_iterator & i, string_iterator end,
        std::list<std::pair<int,int>> * part_positions = nullptr)
{
    using std::locale;
    using std::isspace;

    i = skipws(i, end);

    string rval;
    bool new_part = true;
    int part_start;

    while (i != end) {
        char c = *i;
        if (c == '\"') {
            if (new_part) {
                part_start = rval.length();
                new_part = false;
            }
            // quoted string
            ++i;
            while (i != end) {
                c = *i;
                if (c == '\"') break;
                if (c == '\n') {
                    // TODO error here.
                }
                else if (c == '\\') {
                    // A backslash escapes the following character.
                    ++i;
                    if (i != end) {
                        c = *i;
                        if (c == '\n') {
                            // TODO error here.
                        }
                        rval += c;
                    }
                }
                else {
                    rval += c;
                }
                ++i;
            }
            if (i == end) {
                // String wasn't terminated
                // TODO error here
                break;
            }
        }
        else if (c == '\\') {
            if (new_part) {
                part_start = rval.length();
                new_part = false;
            }
            // A backslash escapes the next character
            ++i;
            if (i != end) {
                rval += *i;
            }
            else {
                // TODO error here
            }
        }
        else if (isspace(c, locale::classic())) {
            if (! new_part && part_positions != nullptr) {
                part_positions->emplace_back(part_start, rval.length());
                new_part = true;
            }
            i = skipws(i, end);
            if (i == end) break;
            if (*i == '#') break; // comment
            rval += ' ';  // collapse ws to a single space
            continue;
        }
        else if (c == '#') {
            // hmm... comment? Probably, though they should have put a space
            // before it really. TODO throw an exception, and document
            // that '#' for comments must be preceded by space, and in values
            // must be quoted.
            break;
        }
        else {
            if (new_part) {
                part_start = rval.length();
                new_part = false;
            }
            rval += c;
        }
        ++i;
    }

    return rval;
}

// Find a service record, or load it from file. If the service has
// dependencies, load those also.
//
// Might throw a ServiceLoadExc exception if a dependency cycle is found or if another
// problem occurs (I/O error, service description not found etc).
ServiceRecord * ServiceSet::loadServiceRecord(const char * name)
{
    using std::string;
    using std::ifstream;
    using std::ios;
    using std::ios_base;
    using std::locale;
    using std::isspace;

    // First try and find an existing record...
    ServiceRecord * rval = findService(string(name));
    if (rval != 0) {
        if (rval->isDummy()) {
            throw ServiceCyclicDependency(name);
        }
        return rval;
    }

    // Couldn't find one. Have to load it.
    string service_filename = service_dir;
    if (*(service_filename.rbegin()) != '/') {
        service_filename += '/';
    }
    service_filename += name;

    string command;
    int service_type = SVC_PROCESS;
    std::list<ServiceRecord *> depends_on;
    std::list<ServiceRecord *> depends_soft;
    string logfile;

    // TODO catch I/O exceptions, wrap & re-throw?
    string line;
    bool auto_restart = false;
    ifstream service_file;
    service_file.exceptions(ios::badbit | ios::failbit);

    try {
        service_file.open(service_filename.c_str(), ios::in);
    }
    catch (std::ios_base::failure &exc) {
        throw ServiceNotFound(name);
    }

    // Add a dummy service record now to prevent cyclic dependencies
    rval = new ServiceRecord(this, string(name));
    records.push_back(rval);

    // getline can set failbit if it reaches end-of-file, we don't want an exception in that case:
    service_file.exceptions(ios::badbit);

    while (! (service_file.rdstate() & ios::eofbit)) {
        getline(service_file, line);
        string::iterator i = line.begin();
        string::iterator end = line.end();

        i = skipws(i, end);
        if (i != end) {
            if (*i == '#') {
                continue;  // comment line
            }
            string setting = read_setting_name(i, end);
            i = skipws(i, end);
            if (i == end || (*i != '=' && *i != ':')) {
                throw ServiceDescriptionExc(name, "Badly formed line.");
            }
            i = skipws(++i, end);

            if (setting == "command") {
                command = read_setting_value(i, end);
            }
            else if (setting == "depends-on") {
                string dependency_name = read_setting_value(i, end);
                depends_on.push_back(loadServiceRecord(dependency_name.c_str()));
            }
            else if (setting == "waits-for") {
                string dependency_name = read_setting_value(i, end);
                depends_soft.push_back(loadServiceRecord(dependency_name.c_str()));
            }
            else if (setting == "logfile") {
                logfile = read_setting_value(i, end);
            }
            else if (setting == "restart") {
                string restart = read_setting_value(i, end);
                auto_restart = (restart == "yes" || restart == "true");
            }
            else if (setting == "type") {
                string type_str = read_setting_value(i, end);
                if (type_str == "scripted") {
                    service_type = SVC_SCRIPTED;
                }
                else if (type_str == "process") {
                    service_type = SVC_PROCESS;
                }
                else if (type_str == "internal") {
                    service_type = SVC_INTERNAL;
                }
                else {
                    throw ServiceDescriptionExc(name, "Service type must be \"scripted\""
                        " or \"process\" or \"internal\"");
                }
            }
            else {
                throw ServiceDescriptionExc(name, "Unknown setting: " + setting);
            }
        }
    }

    service_file.close();
    // TODO check we actually have all the settings - type, command

    // Now replace the dummy service record with a real record:
    for (auto iter = records.begin(); iter != records.end(); iter++) {
        if (*iter == rval) {
            // We've found the dummy record
            delete rval;
            rval = new ServiceRecord(this, string(name), service_type, command,
                    & depends_on, & depends_soft);
            rval->setLogfile(logfile);
            rval->setAutoRestart(auto_restart);
            *iter = rval;
            break;
        }
    }

    return rval;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b3dpolypolygon.cxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basegfx.hxx"
#include <osl/diagnose.h>
#include <basegfx/polygon/b3dpolypolygon.hxx>
#include <basegfx/polygon/b3dpolygon.hxx>
#include <rtl/instance.hxx>
#include <basegfx/matrix/b3dhommatrix.hxx>

#include <functional>
#include <vector>
#include <algorithm>

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

class ImplB3DPolyPolygon
{
    typedef ::std::vector< ::basegfx::B3DPolygon >  PolygonVector;

    PolygonVector                                   maPolygons;

public:
    ImplB3DPolyPolygon() : maPolygons()
    {
    }

    ImplB3DPolyPolygon(const ::basegfx::B3DPolygon& rToBeCopied) :
        maPolygons(1,rToBeCopied)
    {
    }

    bool operator==(const ImplB3DPolyPolygon& rPolygonList) const
    {
        // same polygon count?
        if(maPolygons.size() != rPolygonList.maPolygons.size())
            return false;

        // compare polygon content
        if(maPolygons != rPolygonList.maPolygons)
            return false;

        return true;
    }

    const ::basegfx::B3DPolygon& getB3DPolygon(sal_uInt32 nIndex) const
    {
        return maPolygons[nIndex];
    }

    void setB3DPolygon(sal_uInt32 nIndex, const ::basegfx::B3DPolygon& rPolygon)
    {
        maPolygons[nIndex] = rPolygon;
    }

    void insert(sal_uInt32 nIndex, const ::basegfx::B3DPolygon& rPolygon, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // add nCount copies of rPolygon
            PolygonVector::iterator aIndex(maPolygons.begin());
            aIndex += nIndex;
            maPolygons.insert(aIndex, nCount, rPolygon);
        }
    }

    void insert(sal_uInt32 nIndex, const ::basegfx::B3DPolyPolygon& rPolyPolygon)
    {
        const sal_uInt32 nCount = rPolyPolygon.count();

        if(nCount)
        {
            // add nCount polygons from rPolyPolygon
            maPolygons.reserve(maPolygons.size() + nCount);
            PolygonVector::iterator aIndex(maPolygons.begin());
            aIndex += nIndex;

            for(sal_uInt32 a(0L); a < nCount; a++)
            {
                maPolygons.insert(aIndex, rPolyPolygon.getB3DPolygon(a));
                aIndex++;
            }
        }
    }

    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // remove polygon data
            PolygonVector::iterator aStart(maPolygons.begin());
            aStart += nIndex;
            const PolygonVector::iterator aEnd(aStart + nCount);

            maPolygons.erase(aStart, aEnd);
        }
    }

    sal_uInt32 count() const
    {
        return maPolygons.size();
    }

    void setClosed(bool bNew)
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].setClosed(bNew);
        }
    }

    void flip()
    {
        std::for_each( maPolygons.begin(),
                       maPolygons.end(),
                       std::mem_fun_ref( &::basegfx::B3DPolygon::flip ));
    }

    void removeDoublePoints()
    {
        std::for_each( maPolygons.begin(),
                       maPolygons.end(),
                       std::mem_fun_ref( &::basegfx::B3DPolygon::removeDoublePoints ));
    }

    void transform(const ::basegfx::B3DHomMatrix& rMatrix)
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].transform(rMatrix);
        }
    }

    void makeUnique()
    {
        std::for_each( maPolygons.begin(),
                       maPolygons.end(),
                       std::mem_fun_ref( &::basegfx::B3DPolygon::makeUnique ));
    }
};

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

namespace basegfx
{
    namespace { struct DefaultPolyPolygon : public rtl::Static<B3DPolyPolygon::ImplType,
                                                               DefaultPolyPolygon> {}; }

    B3DPolyPolygon::B3DPolyPolygon() :
        mpPolyPolygon(DefaultPolyPolygon::get())
    {
    }

    B3DPolyPolygon::B3DPolyPolygon(const B3DPolyPolygon& rPolyPolygon) :
        mpPolyPolygon(rPolyPolygon.mpPolyPolygon)
    {
    }

    B3DPolyPolygon::B3DPolyPolygon(const B3DPolygon& rPolygon) :
        mpPolyPolygon( ImplB3DPolyPolygon(rPolygon) )
    {
    }

    B3DPolyPolygon::~B3DPolyPolygon()
    {
    }

    B3DPolyPolygon& B3DPolyPolygon::operator=(const B3DPolyPolygon& rPolyPolygon)
    {
        mpPolyPolygon = rPolyPolygon.mpPolyPolygon;
        return *this;
    }

    void B3DPolyPolygon::makeUnique()
    {
        mpPolyPolygon.make_unique();
        mpPolyPolygon->makeUnique();
    }

    bool B3DPolyPolygon::operator==(const B3DPolyPolygon& rPolyPolygon) const
    {
        if(mpPolyPolygon.same_object(rPolyPolygon.mpPolyPolygon))
            return true;

        return ((*mpPolyPolygon) == (*rPolyPolygon.mpPolyPolygon));
    }

    bool B3DPolyPolygon::operator!=(const B3DPolyPolygon& rPolyPolygon) const
    {
        return !(*this == rPolyPolygon);
    }

    sal_uInt32 B3DPolyPolygon::count() const
    {
        return mpPolyPolygon->count();
    }

    B3DPolygon B3DPolyPolygon::getB3DPolygon(sal_uInt32 nIndex) const
    {
        OSL_ENSURE(nIndex < mpPolyPolygon->count(), "B3DPolyPolygon access outside range (!)");

        return mpPolyPolygon->getB3DPolygon(nIndex);
    }

    void B3DPolyPolygon::setB3DPolygon(sal_uInt32 nIndex, const B3DPolygon& rPolygon)
    {
        OSL_ENSURE(nIndex < mpPolyPolygon->count(), "B3DPolyPolygon access outside range (!)");

        if(getB3DPolygon(nIndex) != rPolygon)
            mpPolyPolygon->setB3DPolygon(nIndex, rPolygon);
    }

    void B3DPolyPolygon::insert(sal_uInt32 nIndex, const B3DPolygon& rPolygon, sal_uInt32 nCount)
    {
        OSL_ENSURE(nIndex <= mpPolyPolygon->count(), "B3DPolyPolygon Insert outside range (!)");

        if(nCount)
            mpPolyPolygon->insert(nIndex, rPolygon, nCount);
    }

    void B3DPolyPolygon::append(const B3DPolygon& rPolygon, sal_uInt32 nCount)
    {
        if(nCount)
            mpPolyPolygon->insert(mpPolyPolygon->count(), rPolygon, nCount);
    }

    void B3DPolyPolygon::insert(sal_uInt32 nIndex, const B3DPolyPolygon& rPolyPolygon)
    {
        OSL_ENSURE(nIndex <= mpPolyPolygon->count(), "B3DPolyPolygon Insert outside range (!)");

        if(rPolyPolygon.count())
            mpPolyPolygon->insert(nIndex, rPolyPolygon);
    }

    void B3DPolyPolygon::append(const B3DPolyPolygon& rPolyPolygon)
    {
        if(rPolyPolygon.count())
            mpPolyPolygon->insert(mpPolyPolygon->count(), rPolyPolygon);
    }

    void B3DPolyPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
    {
        OSL_ENSURE(nIndex + nCount <= mpPolyPolygon->count(), "B3DPolyPolygon Remove outside range (!)");

        if(nCount)
            mpPolyPolygon->remove(nIndex, nCount);
    }

    void B3DPolyPolygon::clear()
    {
        mpPolyPolygon = DefaultPolyPolygon::get();
    }

    bool B3DPolyPolygon::isClosed() const
    {
        bool bRetval(true);

        // PolyPOlygon is closed when all contained Polygons are closed or
        // no Polygon exists.
        for(sal_uInt32 a(0L); bRetval && a < mpPolyPolygon->count(); a++)
        {
            if(!(mpPolyPolygon->getB3DPolygon(a)).isClosed())
            {
                bRetval = false;
            }
        }

        return bRetval;
    }

    void B3DPolyPolygon::setClosed(bool bNew)
    {
        if(bNew != isClosed())
            mpPolyPolygon->setClosed(bNew);
    }

    void B3DPolyPolygon::flip()
    {
        mpPolyPolygon->flip();
    }

    bool B3DPolyPolygon::hasDoublePoints() const
    {
        bool bRetval(false);

        for(sal_uInt32 a(0L); !bRetval && a < mpPolyPolygon->count(); a++)
        {
            if((mpPolyPolygon->getB3DPolygon(a)).hasDoublePoints())
            {
                bRetval = true;
            }
        }

        return bRetval;
    }

    void B3DPolyPolygon::removeDoublePoints()
    {
        if(hasDoublePoints())
            mpPolyPolygon->removeDoublePoints();
    }

    void B3DPolyPolygon::transform(const ::basegfx::B3DHomMatrix& rMatrix)
    {
        if(mpPolyPolygon->count() && !rMatrix.isIdentity())
        {
            mpPolyPolygon->transform(rMatrix);
        }
    }
} // end of namespace basegfx

// eof
<commit_msg>INTEGRATION: CWS aw033 (1.5.2); FILE MERGED 2008/05/14 14:40:33 aw 1.5.2.6: RESYNC: (1.9-1.11); FILE MERGED 2006/11/28 16:13:34 aw 1.5.2.5: RESYNC: (1.8-1.9); FILE MERGED 2006/09/27 16:29:23 aw 1.5.2.4: #i39532# changes after resync to m185 2006/09/26 14:51:00 aw 1.5.2.3: RESYNC: (1.6-1.8); FILE MERGED 2006/05/12 11:36:07 aw 1.5.2.2: code changes for primitive support 2005/10/28 11:24:15 aw 1.5.2.1: #i39532#<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: b3dpolypolygon.cxx,v $
 * $Revision: 1.12 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basegfx.hxx"
#include <osl/diagnose.h>
#include <basegfx/polygon/b3dpolypolygon.hxx>
#include <basegfx/polygon/b3dpolygon.hxx>
#include <rtl/instance.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b3dhommatrix.hxx>
#include <functional>
#include <vector>
#include <algorithm>

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

class ImplB3DPolyPolygon
{
    typedef ::std::vector< ::basegfx::B3DPolygon >  PolygonVector;

    PolygonVector                                   maPolygons;

public:
    ImplB3DPolyPolygon() : maPolygons()
    {
    }

    ImplB3DPolyPolygon(const ::basegfx::B3DPolygon& rToBeCopied) :
        maPolygons(1,rToBeCopied)
    {
    }

    bool operator==(const ImplB3DPolyPolygon& rPolygonList) const
    {
        // same polygon count?
        if(maPolygons.size() != rPolygonList.maPolygons.size())
            return false;

        // compare polygon content
        if(maPolygons != rPolygonList.maPolygons)
            return false;

        return true;
    }

    const ::basegfx::B3DPolygon& getB3DPolygon(sal_uInt32 nIndex) const
    {
        return maPolygons[nIndex];
    }

    void setB3DPolygon(sal_uInt32 nIndex, const ::basegfx::B3DPolygon& rPolygon)
    {
        maPolygons[nIndex] = rPolygon;
    }

    void insert(sal_uInt32 nIndex, const ::basegfx::B3DPolygon& rPolygon, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // add nCount copies of rPolygon
            PolygonVector::iterator aIndex(maPolygons.begin());
            aIndex += nIndex;
            maPolygons.insert(aIndex, nCount, rPolygon);
        }
    }

    void insert(sal_uInt32 nIndex, const ::basegfx::B3DPolyPolygon& rPolyPolygon)
    {
        const sal_uInt32 nCount = rPolyPolygon.count();

        if(nCount)
        {
            // add nCount polygons from rPolyPolygon
            maPolygons.reserve(maPolygons.size() + nCount);
            PolygonVector::iterator aIndex(maPolygons.begin());
            aIndex += nIndex;

            for(sal_uInt32 a(0L); a < nCount; a++)
            {
                maPolygons.insert(aIndex, rPolyPolygon.getB3DPolygon(a));
                aIndex++;
            }
        }
    }

    void remove(sal_uInt32 nIndex, sal_uInt32 nCount)
    {
        if(nCount)
        {
            // remove polygon data
            PolygonVector::iterator aStart(maPolygons.begin());
            aStart += nIndex;
            const PolygonVector::iterator aEnd(aStart + nCount);

            maPolygons.erase(aStart, aEnd);
        }
    }

    sal_uInt32 count() const
    {
        return maPolygons.size();
    }

    void setClosed(bool bNew)
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].setClosed(bNew);
        }
    }

    void flip()
    {
        std::for_each( maPolygons.begin(),
                       maPolygons.end(),
                       std::mem_fun_ref( &::basegfx::B3DPolygon::flip ));
    }

    void removeDoublePoints()
    {
        std::for_each( maPolygons.begin(),
                       maPolygons.end(),
                       std::mem_fun_ref( &::basegfx::B3DPolygon::removeDoublePoints ));
    }

    void transform(const ::basegfx::B3DHomMatrix& rMatrix)
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].transform(rMatrix);
        }
    }

    void clearBColors()
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].clearBColors();
        }
    }

    void transformNormals(const ::basegfx::B3DHomMatrix& rMatrix)
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].transformNormals(rMatrix);
        }
    }

    void clearNormals()
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].clearNormals();
        }
    }

    void transformTextureCoordiantes(const ::basegfx::B2DHomMatrix& rMatrix)
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].transformTextureCoordiantes(rMatrix);
        }
    }

    void clearTextureCoordinates()
    {
        for(sal_uInt32 a(0L); a < maPolygons.size(); a++)
        {
            maPolygons[a].clearTextureCoordinates();
        }
    }

    void makeUnique()
    {
        std::for_each( maPolygons.begin(),
                       maPolygons.end(),
                       std::mem_fun_ref( &::basegfx::B3DPolygon::makeUnique ));
    }
};

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

namespace basegfx
{
    namespace { struct DefaultPolyPolygon : public rtl::Static<B3DPolyPolygon::ImplType,
                                                               DefaultPolyPolygon> {}; }

    B3DPolyPolygon::B3DPolyPolygon() :
        mpPolyPolygon(DefaultPolyPolygon::get())
    {
    }

    B3DPolyPolygon::B3DPolyPolygon(const B3DPolyPolygon& rPolyPolygon) :
        mpPolyPolygon(rPolyPolygon.mpPolyPolygon)
    {
    }

    B3DPolyPolygon::B3DPolyPolygon(const B3DPolygon& rPolygon) :
        mpPolyPolygon( ImplB3DPolyPolygon(rPolygon) )
    {
    }

    B3DPolyPolygon::~B3DPolyPolygon()
    {
    }

    B3DPolyPolygon& B3DPolyPolygon::operator=(const B3DPolyPolygon& rPolyPolygon)
    {
        mpPolyPolygon = rPolyPolygon.mpPolyPolygon;
        return *this;
    }

    void B3DPolyPolygon::makeUnique()
    {
        mpPolyPolygon.make_unique();
        mpPolyPolygon->makeUnique();
    }

    bool B3DPolyPolygon::operator==(const B3DPolyPolygon& rPolyPolygon) const
    {
        if(mpPolyPolygon.same_object(rPolyPolygon.mpPolyPolygon))
            return true;

        return ((*mpPolyPolygon) == (*rPolyPolygon.mpPolyPolygon));
    }

    bool B3DPolyPolygon::operator!=(const B3DPolyPolygon& rPolyPolygon) const
    {
        return !(*this == rPolyPolygon);
    }

    sal_uInt32 B3DPolyPolygon::count() const
    {
        return mpPolyPolygon->count();
    }

    B3DPolygon B3DPolyPolygon::getB3DPolygon(sal_uInt32 nIndex) const
    {
        OSL_ENSURE(nIndex < mpPolyPolygon->count(), "B3DPolyPolygon access outside range (!)");

        return mpPolyPolygon->getB3DPolygon(nIndex);
    }

    void B3DPolyPolygon::setB3DPolygon(sal_uInt32 nIndex, const B3DPolygon& rPolygon)
    {
        OSL_ENSURE(nIndex < mpPolyPolygon->count(), "B3DPolyPolygon access outside range (!)");

        if(getB3DPolygon(nIndex) != rPolygon)
            mpPolyPolygon->setB3DPolygon(nIndex, rPolygon);
    }

    bool B3DPolyPolygon::areBColorsUsed() const
    {
        for(sal_uInt32 a(0L); a < mpPolyPolygon->count(); a++)
        {
            if((mpPolyPolygon->getB3DPolygon(a)).areBColorsUsed())
            {
                return true;
            }
        }

        return false;
    }

    void B3DPolyPolygon::clearBColors()
    {
        if(areBColorsUsed())
            mpPolyPolygon->clearBColors();
    }

    void B3DPolyPolygon::transformNormals(const B3DHomMatrix& rMatrix)
    {
        if(!rMatrix.isIdentity())
            mpPolyPolygon->transformNormals(rMatrix);
    }

    bool B3DPolyPolygon::areNormalsUsed() const
    {
        for(sal_uInt32 a(0L); a < mpPolyPolygon->count(); a++)
        {
            if((mpPolyPolygon->getB3DPolygon(a)).areNormalsUsed())
            {
                return true;
            }
        }

        return false;
    }

    void B3DPolyPolygon::clearNormals()
    {
        if(areNormalsUsed())
            mpPolyPolygon->clearNormals();
    }

    void B3DPolyPolygon::transformTextureCoordiantes(const B2DHomMatrix& rMatrix)
    {
        if(!rMatrix.isIdentity())
            mpPolyPolygon->transformTextureCoordiantes(rMatrix);
    }

    bool B3DPolyPolygon::areTextureCoordinatesUsed() const
    {
        for(sal_uInt32 a(0L); a < mpPolyPolygon->count(); a++)
        {
            if((mpPolyPolygon->getB3DPolygon(a)).areTextureCoordinatesUsed())
            {
                return true;
            }
        }

        return false;
    }

    void B3DPolyPolygon::clearTextureCoordinates()
    {
        if(areTextureCoordinatesUsed())
            mpPolyPolygon->clearTextureCoordinates();
    }

    void B3DPolyPolygon::insert(sal_uInt32 nIndex, const B3DPolygon& rPolygon, sal_uInt32 nCount)
    {
        OSL_ENSURE(nIndex <= mpPolyPolygon->count(), "B3DPolyPolygon Insert outside range (!)");

        if(nCount)
            mpPolyPolygon->insert(nIndex, rPolygon, nCount);
    }

    void B3DPolyPolygon::append(const B3DPolygon& rPolygon, sal_uInt32 nCount)
    {
        if(nCount)
            mpPolyPolygon->insert(mpPolyPolygon->count(), rPolygon, nCount);
    }

    void B3DPolyPolygon::insert(sal_uInt32 nIndex, const B3DPolyPolygon& rPolyPolygon)
    {
        OSL_ENSURE(nIndex <= mpPolyPolygon->count(), "B3DPolyPolygon Insert outside range (!)");

        if(rPolyPolygon.count())
            mpPolyPolygon->insert(nIndex, rPolyPolygon);
    }

    void B3DPolyPolygon::append(const B3DPolyPolygon& rPolyPolygon)
    {
        if(rPolyPolygon.count())
            mpPolyPolygon->insert(mpPolyPolygon->count(), rPolyPolygon);
    }

    void B3DPolyPolygon::remove(sal_uInt32 nIndex, sal_uInt32 nCount)
    {
        OSL_ENSURE(nIndex + nCount <= mpPolyPolygon->count(), "B3DPolyPolygon Remove outside range (!)");

        if(nCount)
            mpPolyPolygon->remove(nIndex, nCount);
    }

    void B3DPolyPolygon::clear()
    {
        mpPolyPolygon = DefaultPolyPolygon::get();
    }

    bool B3DPolyPolygon::isClosed() const
    {
        bool bRetval(true);

        // PolyPOlygon is closed when all contained Polygons are closed or
        // no Polygon exists.
        for(sal_uInt32 a(0L); bRetval && a < mpPolyPolygon->count(); a++)
        {
            if(!(mpPolyPolygon->getB3DPolygon(a)).isClosed())
            {
                bRetval = false;
            }
        }

        return bRetval;
    }

    void B3DPolyPolygon::setClosed(bool bNew)
    {
        if(bNew != isClosed())
            mpPolyPolygon->setClosed(bNew);
    }

    void B3DPolyPolygon::flip()
    {
        mpPolyPolygon->flip();
    }

    bool B3DPolyPolygon::hasDoublePoints() const
    {
        bool bRetval(false);

        for(sal_uInt32 a(0L); !bRetval && a < mpPolyPolygon->count(); a++)
        {
            if((mpPolyPolygon->getB3DPolygon(a)).hasDoublePoints())
            {
                bRetval = true;
            }
        }

        return bRetval;
    }

    void B3DPolyPolygon::removeDoublePoints()
    {
        if(hasDoublePoints())
            mpPolyPolygon->removeDoublePoints();
    }

    void B3DPolyPolygon::transform(const B3DHomMatrix& rMatrix)
    {
        if(mpPolyPolygon->count() && !rMatrix.isIdentity())
        {
            mpPolyPolygon->transform(rMatrix);
        }
    }
} // end of namespace basegfx

// eof
<|endoftext|>


<commit_before>// Copyright Steinwurf ApS 2014.
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#pragma once

#include "parameter.hpp"
#include "copy.hpp"

#include <type_traits>

namespace kw
{
    template<class Value>
    struct arg
    {
        arg()
        {}

        template<class Arg>
        parameter<Value> operator=(const Arg& argument) const
        {
            return {this, argument};
        }
    };

    template<class Key, class Value, class Parameter, class... Args>
    void get(
        const arg<Key>& key,
        Value& value,
        const parameter<Parameter>& param,
        const Args&... args)
    {
        if (&key == param.key)
            copy<Parameter, Value>()(param.value, value);
        get(key, value, args...);
    }

    template<class Key, class Value, class... Args>
    void get(
        const arg<Key>& key,
        Value& value,
        const arg<bool>& param,
        const Args&... args)
    {
        get(key, value, param = true, args...);
    }

    template <class Key, class Value>
    void get(const arg<Key>&, Value&)
    { }
}
<commit_msg>conforming to style guide<commit_after>// Copyright Steinwurf ApS 2014.
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#pragma once

#include "parameter.hpp"
#include "copy.hpp"

#include <type_traits>

namespace kw
{
    template<class Value>
    struct arg
    {
        arg()
        { }

        template<class Arg>
        parameter<Value> operator=(const Arg& argument) const
        {
            return {this, argument};
        }
    };

    template<class Key, class Value, class Parameter, class... Args>
    void get(
        const arg<Key>& key,
        Value& value,
        const parameter<Parameter>& param,
        const Args&... args)
    {
        if (&key == param.key)
            copy<Parameter, Value>()(param.value, value);
        get(key, value, args...);
    }

    template<class Key, class Value, class... Args>
    void get(
        const arg<Key>& key,
        Value& value,
        const arg<bool>& param,
        const Args&... args)
    {
        get(key, value, param = true, args...);
    }

    template <class Key, class Value>
    void get(const arg<Key>&, Value&)
    { }
}
<|endoftext|>