<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright (C) 2016 ScyllaDB
 */

#include "prometheus.hh"
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include "proto/metrics2.pb.h"

#include "scollectd_api.hh"
#include "scollectd-impl.hh"
#include "metrics_api.hh"
#include "http/function_handlers.hh"
#include <boost/algorithm/string/replace.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
#include <boost/algorithm/string.hpp>

using namespace seastar;

namespace prometheus {
namespace pm = io::prometheus::client;

/**
 * Taken from an answer in stackoverflow:
 * http://stackoverflow.com/questions/2340730/are-there-c-equivalents-for-the-protocol-buffers-delimited-i-o-functions-in-ja
 */
static bool write_delimited_to(const google::protobuf::MessageLite& message,
        google::protobuf::io::ZeroCopyOutputStream* rawOutput) {
    google::protobuf::io::CodedOutputStream output(rawOutput);

    const int size = message.ByteSize();
    output.WriteVarint32(size);

    uint8_t* buffer = output.GetDirectBufferForNBytesAndAdvance(size);
    if (buffer != nullptr) {
        message.SerializeWithCachedSizesToArray(buffer);
    } else {
        message.SerializeWithCachedSizes(&output);
        if (output.HadError()) {
            return false;
        }
    }

    return true;
}

static std::string safe_name(const sstring& name) {
    auto rep = boost::replace_all_copy(boost::replace_all_copy(name, "-", "_"), " ", "_");
    boost::remove_erase_if(rep, boost::is_any_of("+()"));
    return rep;
}

static sstring collectd_name(const metrics::impl::metric_id & id) {
    return safe_name(id.group_name() + "_" + safe_name(id.name()));
}

static pm::Metric* add_label(pm::Metric* mt, const metrics::impl::metric_id & id, const config& ctx) {
    auto label = mt->add_label();
    label->set_name("instance");
    label->set_value(ctx.hostname);
    for (auto &&i : id.labels()) {
        label = mt->add_label();
        label->set_name(i.first);
        label->set_value(i.second);
    }
    return mt;
}

static void fill_metric(pm::MetricFamily& mf, const metrics::impl::metric_value& c,
        const metrics::impl::metric_id & id, const config& ctx) {
    switch (c.type()) {
    case scollectd::data_type::DERIVE:
        add_label(mf.add_metric(), id, ctx)->mutable_counter()->set_value(c.i());
        mf.set_type(pm::MetricType::COUNTER);
        break;
    case scollectd::data_type::GAUGE:
        add_label(mf.add_metric(), id, ctx)->mutable_gauge()->set_value(c.d());
        mf.set_type(pm::MetricType::GAUGE);
        break;
    case scollectd::data_type::HISTOGRAM:
    {
        auto h = c.get_histogram();
        auto mh = add_label(mf.add_metric(), id,ctx)->mutable_histogram();
        mh->set_sample_count(h.sample_count);
        mh->set_sample_sum(h.sample_sum);
        for (auto b : h.buckets) {
            auto bc = mh->add_bucket();
            bc->set_cumulative_count(b.count);
            bc->set_upper_bound(b.upper_bound);
        }
        mf.set_type(pm::MetricType::HISTOGRAM);
        break;
    }
    default:
        add_label(mf.add_metric(), id, ctx)->mutable_counter()->set_value(c.ui());
        mf.set_type(pm::MetricType::COUNTER);
        break;
    }
}

future<> start(httpd::http_server_control& http_server, config ctx) {
    if (ctx.hostname == "") {
        char hostname[PATH_MAX];
        gethostname(hostname, sizeof(hostname));
        hostname[PATH_MAX-1] = '\0';
        ctx.hostname = hostname;
    }

    return http_server.set_routes([ctx](httpd::routes& r) {
        httpd::future_handler_function f = [ctx](std::unique_ptr<request> req, std::unique_ptr<reply> rep) {
            return do_with(std::vector<metrics::impl::values_copy>(), [rep = std::move(rep), &ctx] (auto& vec) mutable {
                vec.resize(smp::count);
                return parallel_for_each(boost::irange(0u, smp::count), [&vec] (auto cpu) {
                    return smp::submit_to(cpu, [] {
                        return metrics::impl::get_values();
                    }).then([&vec, cpu] (auto res) {
                        vec[cpu] = res;
                    });
                }).then([rep = std::move(rep), &vec, &ctx]() mutable {
                    std::unordered_map<sstring, std::vector<metrics::impl::values_copy::value_type*>> families;
                    for (auto&& shard : vec) {
                        for (auto&& metric : shard) {
                            auto name = ctx.prefix + "_" + collectd_name(metric.first, &shard - vec.data());
                            families[name].push_back(&metric);
                        }
                    }
                    std::string s;
                    google::protobuf::io::StringOutputStream os(&s);
                    for (auto name_metrics : families) {
                        auto&& name = name_metrics.first;
                        auto&& metrics = name_metrics.second;
                        pm::MetricFamily mtf;
                        mtf.set_name(name);
                        for (auto pmetric : metrics) {
                            auto&& id = pmetric->first;
                            auto&& value = pmetric->second;
                            fill_metric(mtf, value, id, ctx);
                        }
                        if (!write_delimited_to(mtf, &os)) {
                            seastar_logger.warn("Failed to write protobuf metrics");
                        }
                    }
                    rep->_content = s;
                    return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
                });
            });
        };
        r.put(GET, "/metrics", new httpd::function_handler(f, "proto"));
    });
}

}
<commit_msg>Fixing the prometheus cleanup patch<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  You may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/*
 * Copyright (C) 2016 ScyllaDB
 */

#include "prometheus.hh"
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include "proto/metrics2.pb.h"

#include "scollectd_api.hh"
#include "scollectd-impl.hh"
#include "metrics_api.hh"
#include "http/function_handlers.hh"
#include <boost/algorithm/string/replace.hpp>
#include <boost/range/algorithm_ext/erase.hpp>
#include <boost/algorithm/string.hpp>

using namespace seastar;

namespace prometheus {
namespace pm = io::prometheus::client;

/**
 * Taken from an answer in stackoverflow:
 * http://stackoverflow.com/questions/2340730/are-there-c-equivalents-for-the-protocol-buffers-delimited-i-o-functions-in-ja
 */
static bool write_delimited_to(const google::protobuf::MessageLite& message,
        google::protobuf::io::ZeroCopyOutputStream* rawOutput) {
    google::protobuf::io::CodedOutputStream output(rawOutput);

    const int size = message.ByteSize();
    output.WriteVarint32(size);

    uint8_t* buffer = output.GetDirectBufferForNBytesAndAdvance(size);
    if (buffer != nullptr) {
        message.SerializeWithCachedSizesToArray(buffer);
    } else {
        message.SerializeWithCachedSizes(&output);
        if (output.HadError()) {
            return false;
        }
    }

    return true;
}

static std::string safe_name(const sstring& name) {
    auto rep = boost::replace_all_copy(boost::replace_all_copy(name, "-", "_"), " ", "_");
    boost::remove_erase_if(rep, boost::is_any_of("+()"));
    return rep;
}

static sstring collectd_name(const metrics::impl::metric_id & id) {
    return safe_name(id.group_name() + "_" + safe_name(id.name()));
}

static pm::Metric* add_label(pm::Metric* mt, const metrics::impl::metric_id & id, const config& ctx) {
    auto label = mt->add_label();
    label->set_name("instance");
    label->set_value(ctx.hostname);
    for (auto &&i : id.labels()) {
        label = mt->add_label();
        label->set_name(i.first);
        label->set_value(i.second);
    }
    return mt;
}

static void fill_metric(pm::MetricFamily& mf, const metrics::impl::metric_value& c,
        const metrics::impl::metric_id & id, const config& ctx) {
    switch (c.type()) {
    case scollectd::data_type::DERIVE:
        add_label(mf.add_metric(), id, ctx)->mutable_counter()->set_value(c.i());
        mf.set_type(pm::MetricType::COUNTER);
        break;
    case scollectd::data_type::GAUGE:
        add_label(mf.add_metric(), id, ctx)->mutable_gauge()->set_value(c.d());
        mf.set_type(pm::MetricType::GAUGE);
        break;
    case scollectd::data_type::HISTOGRAM:
    {
        auto h = c.get_histogram();
        auto mh = add_label(mf.add_metric(), id,ctx)->mutable_histogram();
        mh->set_sample_count(h.sample_count);
        mh->set_sample_sum(h.sample_sum);
        for (auto b : h.buckets) {
            auto bc = mh->add_bucket();
            bc->set_cumulative_count(b.count);
            bc->set_upper_bound(b.upper_bound);
        }
        mf.set_type(pm::MetricType::HISTOGRAM);
        break;
    }
    default:
        add_label(mf.add_metric(), id, ctx)->mutable_counter()->set_value(c.ui());
        mf.set_type(pm::MetricType::COUNTER);
        break;
    }
}

future<> start(httpd::http_server_control& http_server, config ctx) {
    if (ctx.hostname == "") {
        char hostname[PATH_MAX];
        gethostname(hostname, sizeof(hostname));
        hostname[PATH_MAX-1] = '\0';
        ctx.hostname = hostname;
    }

    return http_server.set_routes([ctx](httpd::routes& r) {
        httpd::future_handler_function f = [ctx](std::unique_ptr<request> req, std::unique_ptr<reply> rep) {
            return do_with(std::vector<metrics::impl::values_copy>(), [rep = std::move(rep), &ctx] (auto& vec) mutable {
                vec.resize(smp::count);
                return parallel_for_each(boost::irange(0u, smp::count), [&vec] (auto cpu) {
                    return smp::submit_to(cpu, [] {
                        return metrics::impl::get_values();
                    }).then([&vec, cpu] (auto res) {
                        vec[cpu] = res;
                    });
                }).then([rep = std::move(rep), &vec, &ctx]() mutable {
                    std::unordered_map<sstring, std::vector<metrics::impl::values_copy::value_type*>> families;
                    for (auto&& shard : vec) {
                        for (auto&& metric : shard) {
                            auto name = ctx.prefix + "_" + collectd_name(metric.first);
                            families[name].push_back(&metric);
                        }
                    }
                    std::string s;
                    google::protobuf::io::StringOutputStream os(&s);
                    for (auto name_metrics : families) {
                        auto&& name = name_metrics.first;
                        auto&& metrics = name_metrics.second;
                        pm::MetricFamily mtf;
                        mtf.set_name(name);
                        for (auto pmetric : metrics) {
                            auto&& id = pmetric->first;
                            auto&& value = pmetric->second;
                            fill_metric(mtf, value, id, ctx);
                        }
                        if (!write_delimited_to(mtf, &os)) {
                            seastar_logger.warn("Failed to write protobuf metrics");
                        }
                    }
                    rep->_content = s;
                    return make_ready_future<std::unique_ptr<reply>>(std::move(rep));
                });
            });
        };
        r.put(GET, "/metrics", new httpd::function_handler(f, "proto"));
    });
}

}
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright © 2017-2018 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

/*
 * core::proxy_map
 * An associative proxy interface to an underlying map-like data collection.
 * It is not iterabe because not all associative collections are iterable.
 * It return a proxy_value object that can be assigned to and converts to the underlying value for its key.
 */

#include <functional>
#include <type_traits>

namespace skui::core
{
  template<typename KeyType, typename ValueType>
  class proxy_map
  {
    class proxy_value
    {
    public:
      using setter_type = std::function<void(const KeyType&, ValueType)>;
      using getter_type = std::function<ValueType(const KeyType&)>;

      proxy_value(KeyType key,
                  const getter_type& getter,
                  const setter_type& setter)
        : key{std::move(key)}
        , get{getter}
        , set{setter}
      {}

      proxy_value& operator=(const ValueType& new_value)
      {
        set(key, new_value);
        return *this;
      }

      operator ValueType() const
      {
        return get(key);
      }

      const KeyType key;
      const getter_type& get;
      const setter_type& set;
    };

  public:
    using key_type = std::add_const_t<KeyType>;
    using value_type = ValueType;
    using getter_type = typename proxy_value::getter_type;
    using setter_type = typename proxy_value::setter_type;

    template<typename Getter, typename Setter>
    proxy_map(Getter getter, Setter setter)
      : get{std::move(getter)}
      , set{std::move(setter)}
    {}

    proxy_value operator[](const key_type& key) const
    {
      return {key, get, set};
    }

    void insert(const key_type& key, value_type value)
    {
      set(key, std::move(value));
    }

  private:
    const getter_type get;
    const setter_type set;
  };
}

<commit_msg>Extract core::proxy_value from core::proxy_map to let ADL find its operator<<.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright © 2017-2018 Ruben Van Boxem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 **/

/*
 * core::proxy_map
 * An associative proxy interface to an underlying map-like data collection.
 * It is not iterabe because not all associative collections are iterable.
 * It return a proxy_value object that can be assigned to and converts to the underlying value for its key.
 */

#ifndef SKUI_CORE_PROXY_MAP_H
#define SKUI_CORE_PROXY_MAP_H

#include <functional>
#include <type_traits>

namespace skui::core
{
  template<typename KeyType, typename ValueType>
  class proxy_map;

  template<typename KeyType, typename ValueType>
  class proxy_value
  {
  public:
    using key_type = std::add_const_t<KeyType>;
    using value_type = ValueType;
    using setter_type = std::function<void(const KeyType&, ValueType)>;
    using getter_type = std::function<ValueType(const KeyType&)>;

    proxy_value& operator=(const value_type& new_value)
    {
      set(key, new_value);
      return *this;
    }

    operator value_type() const
    {
      return get(key);
    }

    bool operator==(const value_type& value) const { return static_cast<const value_type&>(*this) == value; }
    bool operator!=(const value_type& value) const { return static_cast<const value_type&>(*this) != value; }
    bool operator< (const value_type& value) const { return static_cast<const value_type&>(*this) <  value; }
    bool operator<=(const value_type& value) const { return static_cast<const value_type&>(*this) <= value; }
    bool operator> (const value_type& value) const { return static_cast<const value_type&>(*this) >  value; }
    bool operator>=(const value_type& value) const { return static_cast<const value_type&>(*this) >= value; }

  private:
    friend class proxy_map<KeyType, ValueType>;
    proxy_value(key_type key,
                const getter_type& getter,
                const setter_type& setter)
      : key{std::move(key)}
      , get{getter}
      , set{setter}
    {}

    const key_type key;
    const getter_type& get;
    const setter_type& set;
  };

  template<typename KeyType, typename ValueType>
  class proxy_map
  {
  public:
    using proxy_value_type = proxy_value<KeyType, ValueType>;
    using key_type = typename proxy_value_type::key_type;
    using value_type = typename proxy_value_type::value_type;
    using getter_type = typename proxy_value_type::getter_type;
    using setter_type = typename proxy_value_type::setter_type;

    template<typename Getter, typename Setter>
    proxy_map(Getter getter, Setter setter)
      : get{std::move(getter)}
      , set{std::move(setter)}
    {}

    proxy_value_type operator[](const key_type& key) const
    {
      return {key, get, set};
    }

    void insert(const key_type& key, value_type value)
    {
      set(key, std::move(value));
    }

  private:
    const getter_type get;
    const setter_type set;
  };

  template<typename KeyType, typename ValueType>
  std::ostream& operator<<(std::ostream& os, const proxy_value<KeyType, ValueType>& value)
  {
    return os << static_cast<const ValueType&>(value);
  }
}

#endif
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/format.hpp"

#include "IECore/ScopedTIFFErrorHandler.h"
#include "IECore/Exception.h"

using namespace IECore;

std::vector< ScopedTIFFErrorHandler * > &ScopedTIFFErrorHandler::handlers()
{
	static std::vector< ScopedTIFFErrorHandler * > g_handlers;
	return g_handlers;
}

ScopedTIFFErrorHandler::ScopedTIFFErrorHandler()
{
	m_previousHandler = TIFFSetErrorHandler( &output );
	handlers().push_back( this );
}

ScopedTIFFErrorHandler::~ScopedTIFFErrorHandler()
{
	assert( handlers().back() == this );
	TIFFSetErrorHandler( m_previousHandler );
	handlers().pop_back();
}

void ScopedTIFFErrorHandler::output(const char* module, const char* fmt, va_list ap)
{
	/// Reconstruct the actual error in a buffer of (arbitrary) maximum length.
	const unsigned int bufSize = 1024;
	char buf[bufSize];
	vsnprintf( &buf[0], bufSize-1, fmt, ap );

	/// Make sure string is null-terminated
	buf[bufSize-1] = '\0';

	std::string context = "libtiff";
	if (module)
	{
		context = std::string( module );
	}

	ScopedTIFFErrorHandler *handler = handlers().back();
	handler->m_errorMessage = ( boost::format( "%s : %s" ) % context % buf ).str() ;
	longjmp( handler->m_jmpBuffer, 1 );
}
<commit_msg>Fixed small memory leak<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "boost/format.hpp"

#include "IECore/ScopedTIFFErrorHandler.h"
#include "IECore/Exception.h"

using namespace IECore;

std::vector< ScopedTIFFErrorHandler * > &ScopedTIFFErrorHandler::handlers()
{
	static std::vector< ScopedTIFFErrorHandler * > g_handlers;
	return g_handlers;
}

ScopedTIFFErrorHandler::ScopedTIFFErrorHandler()
{
	m_previousHandler = TIFFSetErrorHandler( &output );
	handlers().push_back( this );
}

ScopedTIFFErrorHandler::~ScopedTIFFErrorHandler()
{
	assert( handlers().back() == this );
	TIFFSetErrorHandler( m_previousHandler );
	handlers().pop_back();
}

void ScopedTIFFErrorHandler::output(const char* module, const char* fmt, va_list ap)
{
	ScopedTIFFErrorHandler *handler = handlers().back();
	// Ensure that any variables we allocate here don't get lost due to the longjmp call
	{
		/// Reconstruct the actual error in a buffer of (arbitrary) maximum length.
		const unsigned int bufSize = 1024;
		char buf[bufSize];
		vsnprintf( &buf[0], bufSize-1, fmt, ap );

		/// Make sure string is null-terminated
		buf[bufSize-1] = '\0';

		std::string context = "libtiff";
		if (module)
		{
			context = std::string( module );
		}

		handler->m_errorMessage = ( boost::format( "%s : %s" ) % context % buf ).str() ;
	}
	longjmp( handler->m_jmpBuffer, 1 );
}
<|endoftext|>


<commit_before>/** \brief A MARC-21 filter utility that can remove records based on patterns for MARC subfields.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <memory>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "DirectoryEntry.h"
#include "FileUtil.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "MarcXmlWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

void Usage() {
    std::cerr << "usage: " << progname << " [--input-format=(marc-xml|marc-21)] (--drop|--keep|--remove-fields) [--output-format=(marc-xml|marc-21)] marc_input marc_output field_or_subfieldspec1:regex1 "
              << "[field_or_subfieldspec2:regex2 .. field_or_subfieldspecN:regexN]\n"
              << "       where \"field_or_subfieldspec\" must either be a MARC tag or a MARC tag followed by a\n"
              << "       single-character subfield code and \"regex\" is a Perl-compatible regular expression.\n"
              << "       If you don't specify an output format it will be the same as the input format.\n\n";

    std::exit(EXIT_FAILURE);
}

class CompiledPattern {
    std::string tag_;
    char subfield_code_;
    RegexMatcher matcher_;
public:
    static const char NO_SUBFIELD_CODE;
public:
    CompiledPattern(const std::string &tag, const char subfield_code,  const RegexMatcher &matcher)
        : tag_(tag), subfield_code_(subfield_code), matcher_(matcher) {}
    const std::string &getTag() const { return tag_; }
    bool hasSubfieldCode() const { return subfield_code_ != NO_SUBFIELD_CODE; }
    char getSubfieldCode() const { return subfield_code_; }
    bool fieldMatched(const std::string &field_contents) const;
    bool subfieldMatched(const std::string &subfield_contents) const;
};

const char CompiledPattern::NO_SUBFIELD_CODE('\0');

bool CompiledPattern::fieldMatched(const std::string &field_contents) const {
    std::string err_msg;
    const bool retval = matcher_.matched(field_contents, &err_msg);
    if (not retval and not err_msg.empty())
        Error("Unexpected error while trying to match a field in CompiledPattern::fieldMatched(): " + err_msg);

    return retval;
}

bool CompiledPattern::subfieldMatched(const std::string &subfield_contents) const {
    std::string err_msg;
    const bool retval = matcher_.matched(subfield_contents, &err_msg);
    if (not retval and not err_msg.empty())
        Error("Unexpected error while trying to match a subfield in CompiledPattern::subfieldMatched(): " + err_msg);

    return retval;
}

// Expects "patterns" to contain strings that look like TTTS:REGEX where TTT are 3 characters specifying a field,
// S is a subfield code and REGEX is a PCRE-style regex supporting UTF8 that should match subfield contents.
// Alteratively a pattern can look like TTT:REGEX where TTT is a tag and we have no subfield code.
bool CompilePatterns(const std::vector<std::string> &patterns, std::vector<CompiledPattern> * const compiled_patterns,
                     std::string * const err_msg)
{
    compiled_patterns->clear();
    compiled_patterns->reserve(patterns.size());

    for (const auto &pattern : patterns) {
        std::string tag;
        char subfield_code;
        std::string::size_type first_colon_pos = pattern.find(':');
        if (first_colon_pos == std::string::npos) {
            *err_msg = "missing colon!";
            return false;
        } else if (first_colon_pos == DirectoryEntry::TAG_LENGTH) {
            tag = pattern.substr(0, 3);
            subfield_code = CompiledPattern::NO_SUBFIELD_CODE;
        } else if (first_colon_pos == DirectoryEntry::TAG_LENGTH + 1) {
            tag = pattern.substr(0, 3);
            subfield_code = pattern[3];
        } else {
            *err_msg = "colon in wrong position (" + std::to_string(first_colon_pos) + ")! (Tag length must be "
                       + std::to_string(DirectoryEntry::TAG_LENGTH) + ".)";
            return false;
        }

        const std::string regex_string(pattern.substr(first_colon_pos + 1));
        RegexMatcher * const new_matcher(RegexMatcher::RegexMatcherFactory(regex_string, err_msg));
        if (new_matcher == nullptr) {
            *err_msg = "failed to compile regular expression: \"" + regex_string + "\"! (" + *err_msg +")";
            return false;
        }

        compiled_patterns->push_back(CompiledPattern(tag, subfield_code, std::move(*new_matcher)));
        delete new_matcher;
    }

    return true;
}

/** Returns true if we have at least one match. */
bool Matched(const MarcUtil::Record &record, const std::vector<DirectoryEntry> &dir_entries,
             const std::vector<std::string> &fields, const std::vector<CompiledPattern> &compiled_patterns,
             std::vector<size_t> * const matched_field_indices)
{
    matched_field_indices->clear();

    bool matched_at_least_one(false);
    for (const auto &compiled_pattern : compiled_patterns) {
        ssize_t index(record.getFieldIndex(compiled_pattern.getTag()));
        if (index == -1)
            continue;

        for (/* Intentionally empty! */;
             static_cast<size_t>(index) < fields.size() and dir_entries[index].getTag() == compiled_pattern.getTag();
             ++index)
        {
            if (compiled_pattern.hasSubfieldCode()) {
                const Subfields subfields(fields[index]);
                const auto begin_end(subfields.getIterators(compiled_pattern.getSubfieldCode()));
                for (auto subfield_code_and_value(begin_end.first); subfield_code_and_value != begin_end.second;
                     ++subfield_code_and_value)
                {
                    if (compiled_pattern.subfieldMatched(subfield_code_and_value->second)) {
                        matched_field_indices->emplace_back(index);
                        matched_at_least_one = true;
                    }
                }
            } else if (compiled_pattern.fieldMatched(fields[index])) {
                matched_field_indices->emplace_back(index);
                matched_at_least_one = true;
            }
        }
    }

    return matched_at_least_one;
}

namespace {

enum class OutputFormat { MARC_XML, MARC_21, SAME_AS_INPUT };
enum class OperationType { KEEP, DROP, REMOVE_FIELDS };

} // unnamed namespace

void Filter(const bool input_is_xml, const OutputFormat output_format, const std::vector<std::string> &patterns,
            const OperationType operation_type, File * const input, File * const output)
{
    MarcXmlWriter *xml_writer(nullptr);
    if ((output_format == OutputFormat::SAME_AS_INPUT and input_is_xml) or output_format == OutputFormat::MARC_XML)
        xml_writer = new MarcXmlWriter(output);

    std::vector<CompiledPattern> compiled_patterns;
    std::string err_msg;
    if (not CompilePatterns(patterns, &compiled_patterns, &err_msg))
        Error("Error while compiling patterns: " + err_msg);

    unsigned total_count(0), kept_count(0), modified_count(0);
    while (MarcUtil::Record record = input_is_xml ? MarcUtil::Record::XmlFactory(input)
                                                  : MarcUtil::Record::BinaryFactory(input))
    {
        record.setRecordWillBeWrittenAsXml(input_is_xml);
        ++total_count;

        const std::vector<DirectoryEntry> &dir_entries(record.getDirEntries());
        const std::vector<std::string> &fields(record.getFields());
        std::vector<size_t> matched_field_indices;
        if (Matched(record, dir_entries, fields, compiled_patterns, &matched_field_indices)) {
            if (operation_type == OperationType::KEEP) {
                xml_writer != nullptr ? record.write(xml_writer) : record.write(output);
                ++kept_count;
            } else if (operation_type == OperationType::REMOVE_FIELDS) {
                std::sort(matched_field_indices.begin(), matched_field_indices.end(), std::greater<size_t>());
                for (const auto field_index : matched_field_indices)
                    record.deleteField(field_index);
                xml_writer != nullptr ? record.write(xml_writer) : record.write(output);
                ++modified_count;
            }
        } else if (operation_type == OperationType::DROP or operation_type == OperationType::REMOVE_FIELDS) {
            xml_writer != nullptr ? record.write(xml_writer) : record.write(output);
            ++kept_count;
        }
    }

    if (not err_msg.empty())
        Error(err_msg);

    delete xml_writer;

    if (operation_type == OperationType::REMOVE_FIELDS)
        std::cerr << "Modified " << modified_count << " of " << total_count << " record(s).\n";
    else
        std::cerr << "Kept " << kept_count << " of " << total_count << " record(s).\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc < 5)
        Usage();

    OperationType operation_type;
    if (std::strcmp(argv[1], "--keep") == 0)
        operation_type = OperationType::KEEP;
    else if (std::strcmp(argv[1], "--drop") == 0)
        operation_type = OperationType::DROP;
    else if (std::strcmp(argv[1], "--remove-fields") == 0)
        operation_type = OperationType::REMOVE_FIELDS;
    else
        Error("expected --keep, --drop or --remove-field as the first argument!");

    bool input_is_xml(false), already_determined_input_format(false);
    if (std::strcmp("--input-format=marc-xml", argv[2]) == 0) {
        input_is_xml = true;
        argc -= 1;
        argv += 1;
        already_determined_input_format = true;
    } else if (std::strcmp("--input-format=marc-21", argv[2]) == 0) {
        argc -= 1;
        argv += 1;
        already_determined_input_format = true;
    }

    OutputFormat output_format(OutputFormat::SAME_AS_INPUT);
    if (StringUtil::StartsWith(argv[2], "--output-format=")) {
        if (std::strcmp(argv[2] + std::strlen("--output-format="), "marc-xml") == 0)
            output_format = OutputFormat::MARC_XML;
        else if (std::strcmp(argv[2] + std::strlen("--output-format="), "marc-21") == 0)
            output_format = OutputFormat::MARC_21;
        else
            Error("unknown output format \"" + std::string(argv[2] + 16)
                  + "\"!  Must be \"marc-xml\" or \"marc-21\".");
        ++argv, --argc;
    }

    const std::string input_filename(argv[2]);

    // Our input file is possibly a fifo, then avoid reading twice
    if (not already_determined_input_format) {
        const std::string media_type(MediaTypeUtil::GetFileMediaType(input_filename));
        if (unlikely(media_type.empty()))
            Error("can't determine media type of \"" + input_filename + "\"!");
        if (media_type != "application/xml" and media_type != "application/marc")
            Error("\"" + input_filename + "\" is neither XML nor MARC-21 data!");
        input_is_xml = (media_type == "application/xml");
     }

    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(input_filename));
    std::unique_ptr<File> output(FileUtil::OpenOutputFileOrDie(argv[3]));

    std::vector<std::string> patterns;
    for (int arg_no(4); arg_no < argc; ++arg_no)
        patterns.emplace_back(argv[arg_no]);

    try {
        Filter(input_is_xml, output_format, patterns, operation_type, input.get(), output.get());
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Adjusted usage message<commit_after>/** \brief A MARC-21 filter utility that can remove records based on patterns for MARC subfields.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <memory>
#include <unordered_set>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "DirectoryEntry.h"
#include "FileUtil.h"
#include "Leader.h"
#include "MarcUtil.h"
#include "MarcXmlWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

void Usage() {
    std::cerr << "usage: " << progname << " (--drop|--keep|--remove-fields) [--input-format=(marc-xml|marc-21)] [--output-format=(marc-xml|marc-21)] marc_input marc_output field_or_subfieldspec1:regex1 "
              << "[field_or_subfieldspec2:regex2 .. field_or_subfieldspecN:regexN]\n"
              << "       where \"field_or_subfieldspec\" must either be a MARC tag or a MARC tag followed by a\n"
              << "       single-character subfield code and \"regex\" is a Perl-compatible regular expression.\n"
              << "       If you don't specify an output format it will be the same as the input format.\n\n";

    std::exit(EXIT_FAILURE);
}

class CompiledPattern {
    std::string tag_;
    char subfield_code_;
    RegexMatcher matcher_;
public:
    static const char NO_SUBFIELD_CODE;
public:
    CompiledPattern(const std::string &tag, const char subfield_code,  const RegexMatcher &matcher)
        : tag_(tag), subfield_code_(subfield_code), matcher_(matcher) {}
    const std::string &getTag() const { return tag_; }
    bool hasSubfieldCode() const { return subfield_code_ != NO_SUBFIELD_CODE; }
    char getSubfieldCode() const { return subfield_code_; }
    bool fieldMatched(const std::string &field_contents) const;
    bool subfieldMatched(const std::string &subfield_contents) const;
};

const char CompiledPattern::NO_SUBFIELD_CODE('\0');

bool CompiledPattern::fieldMatched(const std::string &field_contents) const {
    std::string err_msg;
    const bool retval = matcher_.matched(field_contents, &err_msg);
    if (not retval and not err_msg.empty())
        Error("Unexpected error while trying to match a field in CompiledPattern::fieldMatched(): " + err_msg);

    return retval;
}

bool CompiledPattern::subfieldMatched(const std::string &subfield_contents) const {
    std::string err_msg;
    const bool retval = matcher_.matched(subfield_contents, &err_msg);
    if (not retval and not err_msg.empty())
        Error("Unexpected error while trying to match a subfield in CompiledPattern::subfieldMatched(): " + err_msg);

    return retval;
}

// Expects "patterns" to contain strings that look like TTTS:REGEX where TTT are 3 characters specifying a field,
// S is a subfield code and REGEX is a PCRE-style regex supporting UTF8 that should match subfield contents.
// Alteratively a pattern can look like TTT:REGEX where TTT is a tag and we have no subfield code.
bool CompilePatterns(const std::vector<std::string> &patterns, std::vector<CompiledPattern> * const compiled_patterns,
                     std::string * const err_msg)
{
    compiled_patterns->clear();
    compiled_patterns->reserve(patterns.size());

    for (const auto &pattern : patterns) {
        std::string tag;
        char subfield_code;
        std::string::size_type first_colon_pos = pattern.find(':');
        if (first_colon_pos == std::string::npos) {
            *err_msg = "missing colon!";
            return false;
        } else if (first_colon_pos == DirectoryEntry::TAG_LENGTH) {
            tag = pattern.substr(0, 3);
            subfield_code = CompiledPattern::NO_SUBFIELD_CODE;
        } else if (first_colon_pos == DirectoryEntry::TAG_LENGTH + 1) {
            tag = pattern.substr(0, 3);
            subfield_code = pattern[3];
        } else {
            *err_msg = "colon in wrong position (" + std::to_string(first_colon_pos) + ")! (Tag length must be "
                       + std::to_string(DirectoryEntry::TAG_LENGTH) + ".)";
            return false;
        }

        const std::string regex_string(pattern.substr(first_colon_pos + 1));
        RegexMatcher * const new_matcher(RegexMatcher::RegexMatcherFactory(regex_string, err_msg));
        if (new_matcher == nullptr) {
            *err_msg = "failed to compile regular expression: \"" + regex_string + "\"! (" + *err_msg +")";
            return false;
        }

        compiled_patterns->push_back(CompiledPattern(tag, subfield_code, std::move(*new_matcher)));
        delete new_matcher;
    }

    return true;
}

/** Returns true if we have at least one match. */
bool Matched(const MarcUtil::Record &record, const std::vector<DirectoryEntry> &dir_entries,
             const std::vector<std::string> &fields, const std::vector<CompiledPattern> &compiled_patterns,
             std::vector<size_t> * const matched_field_indices)
{
    matched_field_indices->clear();

    bool matched_at_least_one(false);
    for (const auto &compiled_pattern : compiled_patterns) {
        ssize_t index(record.getFieldIndex(compiled_pattern.getTag()));
        if (index == -1)
            continue;

        for (/* Intentionally empty! */;
             static_cast<size_t>(index) < fields.size() and dir_entries[index].getTag() == compiled_pattern.getTag();
             ++index)
        {
            if (compiled_pattern.hasSubfieldCode()) {
                const Subfields subfields(fields[index]);
                const auto begin_end(subfields.getIterators(compiled_pattern.getSubfieldCode()));
                for (auto subfield_code_and_value(begin_end.first); subfield_code_and_value != begin_end.second;
                     ++subfield_code_and_value)
                {
                    if (compiled_pattern.subfieldMatched(subfield_code_and_value->second)) {
                        matched_field_indices->emplace_back(index);
                        matched_at_least_one = true;
                    }
                }
            } else if (compiled_pattern.fieldMatched(fields[index])) {
                matched_field_indices->emplace_back(index);
                matched_at_least_one = true;
            }
        }
    }

    return matched_at_least_one;
}

namespace {

enum class OutputFormat { MARC_XML, MARC_21, SAME_AS_INPUT };
enum class OperationType { KEEP, DROP, REMOVE_FIELDS };

} // unnamed namespace

void Filter(const bool input_is_xml, const OutputFormat output_format, const std::vector<std::string> &patterns,
            const OperationType operation_type, File * const input, File * const output)
{
    MarcXmlWriter *xml_writer(nullptr);
    if ((output_format == OutputFormat::SAME_AS_INPUT and input_is_xml) or output_format == OutputFormat::MARC_XML)
        xml_writer = new MarcXmlWriter(output);

    std::vector<CompiledPattern> compiled_patterns;
    std::string err_msg;
    if (not CompilePatterns(patterns, &compiled_patterns, &err_msg))
        Error("Error while compiling patterns: " + err_msg);

    unsigned total_count(0), kept_count(0), modified_count(0);
    while (MarcUtil::Record record = input_is_xml ? MarcUtil::Record::XmlFactory(input)
                                                  : MarcUtil::Record::BinaryFactory(input))
    {
        record.setRecordWillBeWrittenAsXml(input_is_xml);
        ++total_count;

        const std::vector<DirectoryEntry> &dir_entries(record.getDirEntries());
        const std::vector<std::string> &fields(record.getFields());
        std::vector<size_t> matched_field_indices;
        if (Matched(record, dir_entries, fields, compiled_patterns, &matched_field_indices)) {
            if (operation_type == OperationType::KEEP) {
                xml_writer != nullptr ? record.write(xml_writer) : record.write(output);
                ++kept_count;
            } else if (operation_type == OperationType::REMOVE_FIELDS) {
                std::sort(matched_field_indices.begin(), matched_field_indices.end(), std::greater<size_t>());
                for (const auto field_index : matched_field_indices)
                    record.deleteField(field_index);
                xml_writer != nullptr ? record.write(xml_writer) : record.write(output);
                ++modified_count;
            }
        } else if (operation_type == OperationType::DROP or operation_type == OperationType::REMOVE_FIELDS) {
            xml_writer != nullptr ? record.write(xml_writer) : record.write(output);
            ++kept_count;
        }
    }

    if (not err_msg.empty())
        Error(err_msg);

    delete xml_writer;

    if (operation_type == OperationType::REMOVE_FIELDS)
        std::cerr << "Modified " << modified_count << " of " << total_count << " record(s).\n";
    else
        std::cerr << "Kept " << kept_count << " of " << total_count << " record(s).\n";
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc < 5)
        Usage();

    OperationType operation_type;
    if (std::strcmp(argv[1], "--keep") == 0)
        operation_type = OperationType::KEEP;
    else if (std::strcmp(argv[1], "--drop") == 0)
        operation_type = OperationType::DROP;
    else if (std::strcmp(argv[1], "--remove-fields") == 0)
        operation_type = OperationType::REMOVE_FIELDS;
    else
        Error("expected --keep, --drop or --remove-field as the first argument!");

    bool input_is_xml(false), already_determined_input_format(false);
    if (std::strcmp("--input-format=marc-xml", argv[2]) == 0) {
        input_is_xml = true;
        argc -= 1;
        argv += 1;
        already_determined_input_format = true;
    } else if (std::strcmp("--input-format=marc-21", argv[2]) == 0) {
        argc -= 1;
        argv += 1;
        already_determined_input_format = true;
    }

    OutputFormat output_format(OutputFormat::SAME_AS_INPUT);
    if (StringUtil::StartsWith(argv[2], "--output-format=")) {
        if (std::strcmp(argv[2] + std::strlen("--output-format="), "marc-xml") == 0)
            output_format = OutputFormat::MARC_XML;
        else if (std::strcmp(argv[2] + std::strlen("--output-format="), "marc-21") == 0)
            output_format = OutputFormat::MARC_21;
        else
            Error("unknown output format \"" + std::string(argv[2] + 16)
                  + "\"!  Must be \"marc-xml\" or \"marc-21\".");
        ++argv, --argc;
    }

    const std::string input_filename(argv[2]);

    // Our input file is possibly a fifo, then avoid reading twice
    if (not already_determined_input_format) {
        const std::string media_type(MediaTypeUtil::GetFileMediaType(input_filename));
        if (unlikely(media_type.empty()))
            Error("can't determine media type of \"" + input_filename + "\"!");
        if (media_type != "application/xml" and media_type != "application/marc")
            Error("\"" + input_filename + "\" is neither XML nor MARC-21 data!");
        input_is_xml = (media_type == "application/xml");
     }

    std::unique_ptr<File> input(FileUtil::OpenInputFileOrDie(input_filename));
    std::unique_ptr<File> output(FileUtil::OpenOutputFileOrDie(argv[3]));

    std::vector<std::string> patterns;
    for (int arg_no(4); arg_no < argc; ++arg_no)
        patterns.emplace_back(argv[arg_no]);

    try {
        Filter(input_is_xml, output_format, patterns, operation_type, input.get(), output.get());
    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2010 Juergen Riegel <FreeCAD@juergen-riegel.net>        *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRep_Builder.hxx>
# include <BRep_Tool.hxx>
# include <BRepAlgoAPI_Common.hxx>
# include <BRepAlgoAPI_Fuse.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <BRepBndLib.hxx>
# include <BRepBuilderAPI_MakeFace.hxx>
# include <BRepFeat_MakePrism.hxx>
# include <BRepLProp_SLProps.hxx>
# include <BRepPrimAPI_MakeHalfSpace.hxx>
# include <Geom_Surface.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
# include <GeomLib_IsPlanarSurface.hxx>
# include <gp_Pln.hxx>
# include <Precision.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Compound.hxx>
# include <TopoDS_Face.hxx>
# include <TopoDS_Solid.hxx>
# include <TopoDS_Wire.hxx>
# include <TopExp_Explorer.hxx>
#endif

#include <App/Document.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Placement.h>
#include <Base/Reader.h>

#include "FeaturePad.h"

using namespace PartDesign;

const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL};

PROPERTY_SOURCE(PartDesign::Pad, PartDesign::ProfileBased)

Pad::Pad()
{
    addSubType = FeatureAddSub::Additive;

    ADD_PROPERTY_TYPE(Type, (0L), "Pad", App::Prop_None, "Pad type");
    Type.setEnums(TypeEnums);
    ADD_PROPERTY_TYPE(Length, (100.0), "Pad", App::Prop_None,"Pad length");
    ADD_PROPERTY_TYPE(Length2, (100.0), "Pad", App::Prop_None,"Second Pad length");
    ADD_PROPERTY_TYPE(UseCustomVector, (0), "Pad", App::Prop_None, "Use custom vector for pad direction");
    ADD_PROPERTY_TYPE(Direction, (Base::Vector3d(1.0, 1.0, 1.0)), "Pad", App::Prop_None, "Pad direction vector");
    ADD_PROPERTY_TYPE(UpToFace, (0), "Pad", App::Prop_None, "Face where pad will end");
    ADD_PROPERTY_TYPE(Offset, (0.0), "Pad", App::Prop_None, "Offset from face in which pad will end");
    static const App::PropertyQuantityConstraint::Constraints signedLengthConstraint = {-DBL_MAX, DBL_MAX, 1.0};
    Offset.setConstraints(&signedLengthConstraint);
}

short Pad::mustExecute() const
{
    if (Placement.isTouched() ||
        Type.isTouched() ||
        Length.isTouched() ||
        Length2.isTouched() ||
        UseCustomVector.isTouched() ||
        Direction.isTouched() ||
        Offset.isTouched() ||
        UpToFace.isTouched())
        return 1;
    return ProfileBased::mustExecute();
}

App::DocumentObjectExecReturn *Pad::execute(void)
{
    // Validate parameters
    double L = Length.getValue();
    if ((std::string(Type.getValueAsString()) == "Length") && (L < Precision::Confusion()))
        return new App::DocumentObjectExecReturn("Length of pad too small");
    double L2 = Length2.getValue();
    if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion()))
        return new App::DocumentObjectExecReturn("Second length of pad too small");

    Part::Feature* obj = 0;
    TopoDS_Shape sketchshape;
    try {
        obj = getVerifiedObject();
        sketchshape = getVerifiedFace();
    } catch (const Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }

    // if the Base property has a valid shape, fuse the prism into it
    TopoDS_Shape base;
    try {
        base = getBaseShape();
    } catch (const Base::Exception&) {
        base = TopoDS_Shape();
    }

    // get the Sketch plane
    Base::Placement SketchPos = obj->Placement.getValue();
    // get the normal vector of the sketch
    Base::Vector3d SketchVector = getProfileNormal();

    try {
        this->positionByPrevious();
        TopLoc_Location invObjLoc = this->getLocation().Inverted();

        base.Move(invObjLoc);

        Base::Vector3d paddingDirection;

        // use the given vector if necessary
        if (!UseCustomVector.getValue()) {
            paddingDirection = SketchVector;
        }
        else {
            // if null vector, use SketchVector
            if ( (fabs(Direction.getValue().x) < Precision::Confusion())
                && (fabs(Direction.getValue().y) < Precision::Confusion())
                && (fabs(Direction.getValue().z) < Precision::Confusion()) )
            {
                Direction.setValue(SketchVector);
            }

            paddingDirection = Direction.getValue();
        }

        // create vector in padding direction with length 1
        gp_Dir dir(paddingDirection.x, paddingDirection.y, paddingDirection.z);

        // The length of a gp_Dir is 1 so the resulting pad would have
        // the length L in the direction of dir. But we want to have its height in the
        // direction of the normal vector.
        // Therefore we must multiply L by the factor that is necessary
        // to make dir as long that its projection to the SketchVector
        // equals the SketchVector.
        // This is the scalar product of both vectors.
        // Since the pad length cannot be negative, the factor must not be negative.

        double factor = fabs(dir * gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z));

        // factor would be zero if vectors are orthogonal
        if (factor < Precision::Confusion())
            return new App::DocumentObjectExecReturn("Pad: Creation failed because direction is orthogonal to sketch's normal vector");

        // perform the length correction
        L = L / factor;

        dir.Transform(invObjLoc.Transformation());

        if (sketchshape.IsNull())
            return new App::DocumentObjectExecReturn("Pad: Creating a face from sketch failed");
        sketchshape.Move(invObjLoc);

        TopoDS_Shape prism;
        std::string method(Type.getValueAsString());
        if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") {
              // Note: This will return an unlimited planar face if support is a datum plane
            TopoDS_Face supportface = getSupportFace();
            supportface.Move(invObjLoc);

            if (Reversed.getValue())
                dir.Reverse();

            // Find a valid face or datum plane to extrude up to
            TopoDS_Face upToFace;
            if (method == "UpToFace") {
                getUpToFaceFromLinkSub(upToFace, UpToFace);
                upToFace.Move(invObjLoc);
            }
            getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue());

            // TODO: Write our own PrismMaker which does not depend on a solid base shape
            if (base.IsNull()) {
                // This implementation suffers from some problems:
                // * it explicitly checks for planes only but e.g. a B-spline may work too
                // * The extracted surface passed to GeomAPI_ProjectPointOnSurf may lack of
                //   its placement and thus computes a wrong result
                // * the direction computed by base and projection point must not be transformed
#if 0
                // Workaround because BRepFeat_MakePrism requires the base face located on a solid to be able to extrude up to a face
                // Handle special case of extruding up to a face or plane parallel to the base face
                BRepAdaptor_Surface adapt(upToFace);
                if (adapt.GetType() != GeomAbs_Plane)
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face");

                double angle = dir.Angle(adapt.Plane().Axis().Direction());
                if (angle > Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it");

                // Project basepoint of sketch onto the UpToFace to determine distance and direction
                gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z);
                GeomAPI_ProjectPointOnSurf prj(basePoint, adapt.Surface().Surface());
                if (prj.NbPoints() != 1)
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed to find extrusion direction");
                // Distance
                double length = prj.Distance(1) + Offset.getValue();
                if (length < Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height");

                // Direction (the distance is always positive)
                gp_Pnt prjP = prj.NearestPoint();
                dir = gp_Dir(gp_Vec(basePoint, prjP));
                dir.Transform(invObjLoc.Transformation());
#else
                /*TopLoc_Location upToFaceLoc;
                Handle(Geom_Surface) surf = BRep_Tool::Surface(upToFace, upToFaceLoc);
                GeomLib_IsPlanarSurface checkSurface(surf);
                if (surf.IsNull() || !checkSurface.IsPlanar())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face");

                gp_Pln upToPlane = checkSurface.Plan().Transformed(upToFaceLoc);
                gp_Dir planeNorm = upToPlane.Axis().Direction();
                gp_Pnt planeBase = upToPlane.Location();
                double angle = dir.Angle(planeNorm);
                if (angle > Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it");

                // Project basepoint of sketch onto the UpToFace to determine distance and direction
                gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z);
                Standard_Real pn = planeBase.XYZ().Dot(planeNorm.XYZ());
                Standard_Real qn = basePoint.XYZ().Dot(planeNorm.XYZ());
                gp_Pnt projPoint = basePoint.Translated(planeNorm.XYZ().Multiplied(pn-qn));

                // Distance
                double length = projPoint.Distance(basePoint) + Offset.getValue();
                if (length < Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height");

                // Direction (the distance is always positive)
                dir = gp_Dir(gp_Vec(basePoint, projPoint));*/
#endif

                //generatePrism(prism, sketchshape, "Length", dir, length, 0.0, false, false);
                base = sketchshape;
                supportface = TopoDS::Face(sketchshape);
                TopExp_Explorer Ex(supportface,TopAbs_WIRE);
                if (!Ex.More())
                    supportface = TopoDS_Face();

#if 0
                BRepFeat_MakePrism PrismMaker;
                PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1);
                PrismMaker.Perform(upToFace);

                if (!PrismMaker.IsDone())
                    return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!");
                prism = PrismMaker.Shape();
#else
                generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, 2, 1);
#endif
                base.Nullify();
            } else {
                // A support object is always required and we need to use BRepFeat_MakePrism
                // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid
                // because the feature does not add any material. This only happens with the "2" option, though
                // Note: It might be possible to pass a shell or a compound containing multiple faces
                // as the Until parameter of Perform()
                // Note: Multiple independent wires are not supported, we should check for that and
                // warn the user
                // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results
                // Check supportface for limits, otherwise Perform() throws an exception
                TopExp_Explorer Ex(supportface,TopAbs_WIRE);
                if (!Ex.More())
                    supportface = TopoDS_Face();
#if 0
                BRepFeat_MakePrism PrismMaker;
                PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1);
                PrismMaker.Perform(upToFace);

                if (!PrismMaker.IsDone())
                    return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!");
                prism = PrismMaker.Shape();
#else
                generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, 2, 1);
#endif
            }
        } else {
            generatePrism(prism, sketchshape, method, dir, L, L2,
                          Midplane.getValue(), Reversed.getValue());
        }

        if (prism.IsNull())
            return new App::DocumentObjectExecReturn("Pad: Resulting shape is empty");

        // set the additive shape property for later usage in e.g. pattern
        prism = refineShapeIfActive(prism);
        this->AddSubShape.setValue(prism);

        if (!base.IsNull()) {
//             auto obj = getDocument()->addObject("Part::Feature", "prism");
//             static_cast<Part::Feature*>(obj)->Shape.setValue(getSolid(prism));
            // Let's call algorithm computing a fuse operation:
            BRepAlgoAPI_Fuse mkFuse(base, prism);
            // Let's check if the fusion has been successful
            if (!mkFuse.IsDone())
                return new App::DocumentObjectExecReturn("Pad: Fusion with base feature failed");
            TopoDS_Shape result = mkFuse.Shape();
            // we have to get the solids (fuse sometimes creates compounds)
            TopoDS_Shape solRes = this->getSolid(result);
            // lets check if the result is a solid
            if (solRes.IsNull())
                return new App::DocumentObjectExecReturn("Pad: Resulting shape is not a solid");

            int solidCount = countSolids(result);
            if (solidCount > 1) {
                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time.");
            }

            solRes = refineShapeIfActive(solRes);
            this->Shape.setValue(getSolid(solRes));
        } else {
            int solidCount = countSolids(prism);
            if (solidCount > 1) {
                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time.");
            }

           this->Shape.setValue(getSolid(prism));
        }

        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure& e) {

        if (std::string(e.GetMessageString()) == "TopoDS::Face")
            return new App::DocumentObjectExecReturn("Could not create face from sketch.\n"
                "Intersecting sketch entities or multiple faces in a sketch are not allowed.");
        else
            return new App::DocumentObjectExecReturn(e.GetMessageString());
    }
    catch (Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }
}

<commit_msg>PartDesign: [skip ci] fix L2 parameter in pad feature when using custom direction<commit_after>/***************************************************************************
 *   Copyright (c) 2010 Juergen Riegel <FreeCAD@juergen-riegel.net>        *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
# include <BRep_Builder.hxx>
# include <BRep_Tool.hxx>
# include <BRepAlgoAPI_Common.hxx>
# include <BRepAlgoAPI_Fuse.hxx>
# include <BRepAdaptor_Surface.hxx>
# include <BRepBndLib.hxx>
# include <BRepBuilderAPI_MakeFace.hxx>
# include <BRepFeat_MakePrism.hxx>
# include <BRepLProp_SLProps.hxx>
# include <BRepPrimAPI_MakeHalfSpace.hxx>
# include <Geom_Surface.hxx>
# include <GeomAPI_ProjectPointOnSurf.hxx>
# include <GeomLib_IsPlanarSurface.hxx>
# include <gp_Pln.hxx>
# include <Precision.hxx>
# include <TopoDS.hxx>
# include <TopoDS_Compound.hxx>
# include <TopoDS_Face.hxx>
# include <TopoDS_Solid.hxx>
# include <TopoDS_Wire.hxx>
# include <TopExp_Explorer.hxx>
#endif

#include <App/Document.h>
#include <Base/Console.h>
#include <Base/Exception.h>
#include <Base/Placement.h>
#include <Base/Reader.h>

#include "FeaturePad.h"

using namespace PartDesign;

const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL};

PROPERTY_SOURCE(PartDesign::Pad, PartDesign::ProfileBased)

Pad::Pad()
{
    addSubType = FeatureAddSub::Additive;

    ADD_PROPERTY_TYPE(Type, (0L), "Pad", App::Prop_None, "Pad type");
    Type.setEnums(TypeEnums);
    ADD_PROPERTY_TYPE(Length, (100.0), "Pad", App::Prop_None,"Pad length");
    ADD_PROPERTY_TYPE(Length2, (100.0), "Pad", App::Prop_None,"Second Pad length");
    ADD_PROPERTY_TYPE(UseCustomVector, (0), "Pad", App::Prop_None, "Use custom vector for pad direction");
    ADD_PROPERTY_TYPE(Direction, (Base::Vector3d(1.0, 1.0, 1.0)), "Pad", App::Prop_None, "Pad direction vector");
    ADD_PROPERTY_TYPE(UpToFace, (0), "Pad", App::Prop_None, "Face where pad will end");
    ADD_PROPERTY_TYPE(Offset, (0.0), "Pad", App::Prop_None, "Offset from face in which pad will end");
    static const App::PropertyQuantityConstraint::Constraints signedLengthConstraint = {-DBL_MAX, DBL_MAX, 1.0};
    Offset.setConstraints(&signedLengthConstraint);
}

short Pad::mustExecute() const
{
    if (Placement.isTouched() ||
        Type.isTouched() ||
        Length.isTouched() ||
        Length2.isTouched() ||
        UseCustomVector.isTouched() ||
        Direction.isTouched() ||
        Offset.isTouched() ||
        UpToFace.isTouched())
        return 1;
    return ProfileBased::mustExecute();
}

App::DocumentObjectExecReturn *Pad::execute(void)
{
    // Validate parameters
    double L = Length.getValue();
    if ((std::string(Type.getValueAsString()) == "Length") && (L < Precision::Confusion()))
        return new App::DocumentObjectExecReturn("Length of pad too small");
    double L2 = Length2.getValue();
    if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion()))
        return new App::DocumentObjectExecReturn("Second length of pad too small");

    Part::Feature* obj = 0;
    TopoDS_Shape sketchshape;
    try {
        obj = getVerifiedObject();
        sketchshape = getVerifiedFace();
    } catch (const Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }

    // if the Base property has a valid shape, fuse the prism into it
    TopoDS_Shape base;
    try {
        base = getBaseShape();
    } catch (const Base::Exception&) {
        base = TopoDS_Shape();
    }

    // get the Sketch plane
    Base::Placement SketchPos = obj->Placement.getValue();
    // get the normal vector of the sketch
    Base::Vector3d SketchVector = getProfileNormal();

    try {
        this->positionByPrevious();
        TopLoc_Location invObjLoc = this->getLocation().Inverted();

        base.Move(invObjLoc);

        Base::Vector3d paddingDirection;

        // use the given vector if necessary
        if (!UseCustomVector.getValue()) {
            paddingDirection = SketchVector;
        }
        else {
            // if null vector, use SketchVector
            if ( (fabs(Direction.getValue().x) < Precision::Confusion())
                && (fabs(Direction.getValue().y) < Precision::Confusion())
                && (fabs(Direction.getValue().z) < Precision::Confusion()) )
            {
                Direction.setValue(SketchVector);
            }

            paddingDirection = Direction.getValue();
        }

        // create vector in padding direction with length 1
        gp_Dir dir(paddingDirection.x, paddingDirection.y, paddingDirection.z);

        // The length of a gp_Dir is 1 so the resulting pad would have
        // the length L in the direction of dir. But we want to have its height in the
        // direction of the normal vector.
        // Therefore we must multiply L by the factor that is necessary
        // to make dir as long that its projection to the SketchVector
        // equals the SketchVector.
        // This is the scalar product of both vectors.
        // Since the pad length cannot be negative, the factor must not be negative.

        double factor = fabs(dir * gp_Dir(SketchVector.x, SketchVector.y, SketchVector.z));

        // factor would be zero if vectors are orthogonal
        if (factor < Precision::Confusion())
            return new App::DocumentObjectExecReturn("Pad: Creation failed because direction is orthogonal to sketch's normal vector");

        // perform the length correction
        L = L / factor;
        L2 = L2 / factor;

        dir.Transform(invObjLoc.Transformation());

        if (sketchshape.IsNull())
            return new App::DocumentObjectExecReturn("Pad: Creating a face from sketch failed");
        sketchshape.Move(invObjLoc);

        TopoDS_Shape prism;
        std::string method(Type.getValueAsString());
        if (method == "UpToFirst" || method == "UpToLast" || method == "UpToFace") {
              // Note: This will return an unlimited planar face if support is a datum plane
            TopoDS_Face supportface = getSupportFace();
            supportface.Move(invObjLoc);

            if (Reversed.getValue())
                dir.Reverse();

            // Find a valid face or datum plane to extrude up to
            TopoDS_Face upToFace;
            if (method == "UpToFace") {
                getUpToFaceFromLinkSub(upToFace, UpToFace);
                upToFace.Move(invObjLoc);
            }
            getUpToFace(upToFace, base, supportface, sketchshape, method, dir, Offset.getValue());

            // TODO: Write our own PrismMaker which does not depend on a solid base shape
            if (base.IsNull()) {
                // This implementation suffers from some problems:
                // * it explicitly checks for planes only but e.g. a B-spline may work too
                // * The extracted surface passed to GeomAPI_ProjectPointOnSurf may lack of
                //   its placement and thus computes a wrong result
                // * the direction computed by base and projection point must not be transformed
#if 0
                // Workaround because BRepFeat_MakePrism requires the base face located on a solid to be able to extrude up to a face
                // Handle special case of extruding up to a face or plane parallel to the base face
                BRepAdaptor_Surface adapt(upToFace);
                if (adapt.GetType() != GeomAbs_Plane)
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face");

                double angle = dir.Angle(adapt.Plane().Axis().Direction());
                if (angle > Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it");

                // Project basepoint of sketch onto the UpToFace to determine distance and direction
                gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z);
                GeomAPI_ProjectPointOnSurf prj(basePoint, adapt.Surface().Surface());
                if (prj.NbPoints() != 1)
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed to find extrusion direction");
                // Distance
                double length = prj.Distance(1) + Offset.getValue();
                if (length < Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height");

                // Direction (the distance is always positive)
                gp_Pnt prjP = prj.NearestPoint();
                dir = gp_Dir(gp_Vec(basePoint, prjP));
                dir.Transform(invObjLoc.Transformation());
#else
                /*TopLoc_Location upToFaceLoc;
                Handle(Geom_Surface) surf = BRep_Tool::Surface(upToFace, upToFaceLoc);
                GeomLib_IsPlanarSurface checkSurface(surf);
                if (surf.IsNull() || !checkSurface.IsPlanar())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face or plane is only possible if the sketch is located on a face");

                gp_Pln upToPlane = checkSurface.Plan().Transformed(upToFaceLoc);
                gp_Dir planeNorm = upToPlane.Axis().Direction();
                gp_Pnt planeBase = upToPlane.Location();
                double angle = dir.Angle(planeNorm);
                if (angle > Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face is only possible if the sketch plane is parallel to it");

                // Project basepoint of sketch onto the UpToFace to determine distance and direction
                gp_Pnt basePoint(SketchPos.getPosition().x, SketchPos.getPosition().y, SketchPos.getPosition().z);
                Standard_Real pn = planeBase.XYZ().Dot(planeNorm.XYZ());
                Standard_Real qn = basePoint.XYZ().Dot(planeNorm.XYZ());
                gp_Pnt projPoint = basePoint.Translated(planeNorm.XYZ().Multiplied(pn-qn));

                // Distance
                double length = projPoint.Distance(basePoint) + Offset.getValue();
                if (length < Precision::Confusion())
                    return new App::DocumentObjectExecReturn("Pad: Extruding up to a face failed because of zero height");

                // Direction (the distance is always positive)
                dir = gp_Dir(gp_Vec(basePoint, projPoint));*/
#endif

                //generatePrism(prism, sketchshape, "Length", dir, length, 0.0, false, false);
                base = sketchshape;
                supportface = TopoDS::Face(sketchshape);
                TopExp_Explorer Ex(supportface,TopAbs_WIRE);
                if (!Ex.More())
                    supportface = TopoDS_Face();

#if 0
                BRepFeat_MakePrism PrismMaker;
                PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1);
                PrismMaker.Perform(upToFace);

                if (!PrismMaker.IsDone())
                    return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!");
                prism = PrismMaker.Shape();
#else
                generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, 2, 1);
#endif
                base.Nullify();
            } else {
                // A support object is always required and we need to use BRepFeat_MakePrism
                // Problem: For Pocket/UpToFirst (or an equivalent Pocket/UpToFace) the resulting shape is invalid
                // because the feature does not add any material. This only happens with the "2" option, though
                // Note: It might be possible to pass a shell or a compound containing multiple faces
                // as the Until parameter of Perform()
                // Note: Multiple independent wires are not supported, we should check for that and
                // warn the user
                // FIXME: If the support shape is not the previous solid in the tree, then there will be unexpected results
                // Check supportface for limits, otherwise Perform() throws an exception
                TopExp_Explorer Ex(supportface,TopAbs_WIRE);
                if (!Ex.More())
                    supportface = TopoDS_Face();
#if 0
                BRepFeat_MakePrism PrismMaker;
                PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1);
                PrismMaker.Perform(upToFace);

                if (!PrismMaker.IsDone())
                    return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!");
                prism = PrismMaker.Shape();
#else
                generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, 2, 1);
#endif
            }
        } else {
            generatePrism(prism, sketchshape, method, dir, L, L2,
                          Midplane.getValue(), Reversed.getValue());
        }

        if (prism.IsNull())
            return new App::DocumentObjectExecReturn("Pad: Resulting shape is empty");

        // set the additive shape property for later usage in e.g. pattern
        prism = refineShapeIfActive(prism);
        this->AddSubShape.setValue(prism);

        if (!base.IsNull()) {
//             auto obj = getDocument()->addObject("Part::Feature", "prism");
//             static_cast<Part::Feature*>(obj)->Shape.setValue(getSolid(prism));
            // Let's call algorithm computing a fuse operation:
            BRepAlgoAPI_Fuse mkFuse(base, prism);
            // Let's check if the fusion has been successful
            if (!mkFuse.IsDone())
                return new App::DocumentObjectExecReturn("Pad: Fusion with base feature failed");
            TopoDS_Shape result = mkFuse.Shape();
            // we have to get the solids (fuse sometimes creates compounds)
            TopoDS_Shape solRes = this->getSolid(result);
            // lets check if the result is a solid
            if (solRes.IsNull())
                return new App::DocumentObjectExecReturn("Pad: Resulting shape is not a solid");

            int solidCount = countSolids(result);
            if (solidCount > 1) {
                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time.");
            }

            solRes = refineShapeIfActive(solRes);
            this->Shape.setValue(getSolid(solRes));
        } else {
            int solidCount = countSolids(prism);
            if (solidCount > 1) {
                return new App::DocumentObjectExecReturn("Pad: Result has multiple solids. This is not supported at this time.");
            }

           this->Shape.setValue(getSolid(prism));
        }

        return App::DocumentObject::StdReturn;
    }
    catch (Standard_Failure& e) {

        if (std::string(e.GetMessageString()) == "TopoDS::Face")
            return new App::DocumentObjectExecReturn("Could not create face from sketch.\n"
                "Intersecting sketch entities or multiple faces in a sketch are not allowed.");
        else
            return new App::DocumentObjectExecReturn(e.GetMessageString());
    }
    catch (Base::Exception& e) {
        return new App::DocumentObjectExecReturn(e.what());
    }
}

<|endoftext|>


<commit_before>/*!
 * \file Sequence.hpp
 * \brief Class responsible for retrieving images from image sequences - class declaration.
 */

#ifndef CAMERAGIGE_HPP_
#define CAMERAGIGE_HPP_

#include "Component_Aux.hpp"
#include "Component.hpp"
#include "Panel_Empty.hpp"
#include "DataStream.hpp"
#include "Props.hpp"

#include <vector>
#include <string>

#include <cv.h>

#ifdef _WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Winsock2.h>
#endif

//#if defined(_LINUX) || defined(_QNX) || defined(_OSX)
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/times.h>
#include <arpa/inet.h>
//#endif

#define _LINUX
#define _x64

#include <PvApi.h>

/**
 * \defgroup Sequence Sequence
 * \ingroup Sources
 *
 * \brief Image sequence provider.
 *
 * At the moment there is only one type of sequences
 * available, based on image filename pattern (regular expression) and directory,
 * in which files will be searched.
 *
 *
 * \par Data streams:
 *
 * \streamout{out_img,cv::Mat}
 * Output image
 *
 *
 * \par Events:
 *
 * \event{newImage}
 * New image is ready
 * \event{endOfSequence}
 * Sequence has ended
 *
 *
 * \par Event handlers:
 *
 * \handler{onTrigger}
 * Trigger new frame
 *
 *
 * \par Properties:
 *
 * \prop{directory,string,"."}
 * Directory, where fils will be searched
 * \prop{pattern,string,".*\.jpg"}
 * Regex pattern used for searching files
 * \prop{sort,bool,true}
 * If set, then found siles will be sorted in ascending order
 * \prop{prefetch,bool,false}
 * If set, all files will be loaded beforehand, otherwise images are loaded just before they are needed.
 * \prop{triggered,bool,false}
 * If set, new frames will be produced only after onTrigger event
 *
 *
 * \see \ref regex_basics
 *
 *
 * @{
 *
 * @}
 */

namespace Sources {
namespace CameraGigE {

struct Props : public Base::Props {
	// Device
	std::string address;
	uint32_t uid;

	// Controls
	/// Exposure
	std::string 	exposureMode;
	double 			exposureValue;
	/// Gain
	std::string		gainMode;
	int				gainValue;
	/// Iris

	/// WhiteBalance
	std::string		whitebalMode;
	int 			whitebalValueRed;
	int				whitebalValueBlue;

	// ImageFormat
	bool			mirrorX;
	std::string		pixelFormat;
	///ROI
	int 			height;
	int 			width;
	int				regionX;
	int				regionY;

	// ImageMode
	int				binningX;
	int				binningY;

	void load(const ptree & pt) {
		address = pt.get("Address", "");
		uid = pt.get("UID", 0);

		exposureMode = pt.get("Controls.Exposure.Mode", "auto");
		exposureValue = pt.get("Controls.Exposure.Value", 0.05);

		gainMode = pt.get("Controls.Gain.Mode", "auto");
		gainValue = pt.get("Controls.Gain.Value", 0);

		whitebalMode = pt.get("Controls.WhiteBalance.Mode", "auto");
		whitebalValueRed = pt.get("Controls.WhiteBalance.ValueRed", 50);
		whitebalValueBlue = pt.get("Controls.WhiteBalance.ValueBlue", 50);

		mirrorX = pt.get("ImageFormat.MirrorX", false);
		pixelFormat = pt.get("ImageFormat.PixelFormat", "RGB24");
		height = pt.get("ImageFormat.ROI.Height", 480);
		width = pt.get("ImageFormat.ROI.Width", 640);
		regionX = pt.get("ImageFormat.ROI.RegionX", 0);
		regionY = pt.get("ImageFormat.ROI.RegionY", 0);

		binningX = pt.get("ImageMode.BinningX", 1);
		binningY = pt.get("ImageMode.BinningY", 1);

	}

	void save(ptree & pt) {
		pt.put("Address", address);
		pt.put("UID", uid);

		pt.put("Controls.Exposure.Mode", exposureMode);
		pt.put("Controls.Exposure.Value", exposureValue);

		pt.put("Controls.Gain.Mode", gainMode);
		pt.put("Controls.Gain.Value", gainValue);

		pt.put("Controls.WhiteBalance.Mode", whitebalMode);
		pt.put("Controls.WhiteBalance.ValueRed", whitebalValueRed);
		pt.put("Controls.WhiteBalance.ValueBlue", whitebalValueBlue);

		pt.put("ImageFormat.MirrorX", mirrorX);
		pt.put("ImageFormat.PixelFormat", pixelFormat);
		pt.put("ImageFormat.ROI.Height", height);
		pt.put("ImageFormat.ROI.Width", width);
		pt.put("ImageFormat.ROI.RegionX", regionX);
		pt.put("ImageFormat.ROI.RegionY", regionY);

		pt.put("ImageMode.BinningX", binningX);
		pt.put("ImageMode.BinningY", binningY);
	}
};

/*!
 * \class Sequence
 * \brief Class responsible for retrieving images from image sequences.
 */
class CameraGigE : public Base::Component {

public:
	/*!
	 * Constructor. Sets ID and startup variables.
	 */
	CameraGigE(const std::string & name = "");

	/*!
	 * Destructor.
	 */
	virtual ~CameraGigE();

	/*!
	 * Return sequence properties
	 */
	Base::Props * getProperties() {
		return &props;
	}

protected:

	/*!
	 * Connects source to given device.
	 */
	bool onInit();

	/*!
	 * Disconnect source from device, closes streams, etc.
	 */
	bool onFinish();

	/*!
	 * Retrieves data from device.
	 */
	bool onStep();

	/*!
	 * Start component
	 */
	bool onStart();

	/*!
	 * Stop component
	 */
	bool onStop();

	/// Event signaling that new image was retrieved.
	Base::Event * newImage;

	/// Sequence has ended
	Base::Event * endOfSequence;

	/// Output data stream
	Base::DataStreamOut<cv::Mat> out_img;

	/*!
	 * Event handler function.
	 */
	void onTrigger();

	/// Event handler.
	Base::EventHandler<CameraGigE> h_onTrigger;

private:
	/// Camera handle
	tPvHandle 	cHandle;
	tPvFrame	frame;

	/// current frame
	cv::Mat img;

	/// sequence properties
	Props props;

};

}//: namespace Sequence
}//: namespace Sources

/*
 * Register source component.
 */
REGISTER_SOURCE_COMPONENT("CameraGigE", Sources::CameraGigE::CameraGigE, Common::Panel_Empty)

#endif /* CAMERAGIGE_HPP_ */
<commit_msg>CameraGigE some documentation.<commit_after>/*!
 * \file Sequence.hpp
 * \brief Class responsible for retrieving images from image sequences - class declaration.
 */

#ifndef CAMERAGIGE_HPP_
#define CAMERAGIGE_HPP_

#include "Component_Aux.hpp"
#include "Component.hpp"
#include "Panel_Empty.hpp"
#include "DataStream.hpp"
#include "Props.hpp"

#include <vector>
#include <string>

#include <cv.h>

#ifdef _WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Winsock2.h>
#endif

//#if defined(_LINUX) || defined(_QNX) || defined(_OSX)
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <sys/times.h>
#include <arpa/inet.h>
//#endif

#define _LINUX
#define _x64

#include <PvApi.h>

/**
 * \defgroup CameraGigE CameraGigE
 * \ingroup Sources
 *
 * \brief ATV GigE camera driver.
 *
 * Provide access to GieE Vision cameras.
 *
 *
 * \par Data streams:
 *
 * \streamout{out_img,cv::Mat}
 * Output image
 *
 *
 * \par Events:
 *
 * \event{newImage}
 * New image is ready
 *
 *
 * \par Event handlers:
 *
 * \handler{onTrigger}
 * Trigger new frame in SoftTrigger mode
 *
 *
 * \par Properties:
 *
 * \prop{Adress,string,"192.168.1.2"}
 * IP address of camera.
 * \prop{UID,int,"0"}
 * UID of camera.
 *
 * \prop{Exposure.Mode,string,"Auto"}
 * Control exposure mode, available modes : Manual, Auto, AutoOnce, External.
 * \prop{Exposure.Value,double,0.01}
 * Exposure time in seconds used in Manual mode.
 *
 * \prop{Gain.Mode,string,"Auto"}
 * Control gain mode, available modes : Manual, Auto, AutoOnce.
 * \prop{Gain.Value,int,0}
 * Sensor gain in dB used in Manual mode.
 *
 * \prop{Whitebal.Mode,string,"Auto"}
 * Control White Balance mode, available modes : Manual, Auto, AutoOnce.
 * \prop{Whitebal.ValueRed,int,50}
 * Red gain expressed as a percentage of the camera default setting.
 * \prop{Whitebal.ValueBlue,int,50}
 * Blue gain expressed as a percentage of the camera default setting.
 *
 * \prop{ImageFormat.PixelFormat,string,"RGB24"}
 * Pixel format, available formats : mono8, RGB24.
 *
 * \prop{ImageFormat.MirrorX,bool,false}
 * Enable horizontal mirroring of the image.
 * \prop{ImageFormat.ROI.Height,int,480}
 * The vertical size of the rectangle that defines the ROI.
 * \prop{ImageFormat.ROI.Width,int,640}
 * The horizontal size of the rectangle that defines the ROI.
 * \prop{ImageFormat.ROI.RegionX,int,0}
 * The X position of the top-left corner of the ROI.
 * \prop{ImageFormat.ROI.RegionY,int,0}
 * The Y position of the top-left corner of the ROI.
 *
 * \prop{ImageMode.BinningX,int,0}
 * The horizontal binning factor.
 * Binning is the summing of charge of adjacent pixels on a sensor, to give a lower resolution but more sensitive image.
 * \prop{ImageMode.BinningY,int,0}
 * The vertical binning factor.
 *
 * @{
 *
 * @}
 */

namespace Sources {
namespace CameraGigE {

struct Props : public Base::Props {
	// Device
	std::string address;
	uint32_t uid;

	// Controls
	/// Exposure
	std::string 	exposureMode;
	double 			exposureValue;
	/// Gain
	std::string		gainMode;
	int				gainValue;
	/// Iris

	/// WhiteBalance
	std::string		whitebalMode;
	int 			whitebalValueRed;
	int				whitebalValueBlue;

	// ImageFormat
	bool			mirrorX;
	std::string		pixelFormat;
	///ROI
	int 			height;
	int 			width;
	int				regionX;
	int				regionY;

	// ImageMode
	int				binningX;
	int				binningY;

	void load(const ptree & pt) {
		address = pt.get("Address", "");
		uid = pt.get("UID", 0);

		exposureMode = pt.get("Controls.Exposure.Mode", "auto");
		exposureValue = pt.get("Controls.Exposure.Value", 0.05);

		gainMode = pt.get("Controls.Gain.Mode", "auto");
		gainValue = pt.get("Controls.Gain.Value", 0);

		whitebalMode = pt.get("Controls.WhiteBalance.Mode", "auto");
		whitebalValueRed = pt.get("Controls.WhiteBalance.ValueRed", 50);
		whitebalValueBlue = pt.get("Controls.WhiteBalance.ValueBlue", 50);

		mirrorX = pt.get("ImageFormat.MirrorX", false);
		pixelFormat = pt.get("ImageFormat.PixelFormat", "RGB24");
		height = pt.get("ImageFormat.ROI.Height", 480);
		width = pt.get("ImageFormat.ROI.Width", 640);
		regionX = pt.get("ImageFormat.ROI.RegionX", 0);
		regionY = pt.get("ImageFormat.ROI.RegionY", 0);

		binningX = pt.get("ImageMode.BinningX", 0);
		binningY = pt.get("ImageMode.BinningY", 0);

	}

	void save(ptree & pt) {
		pt.put("Address", address);
		pt.put("UID", uid);

		pt.put("Controls.Exposure.Mode", exposureMode);
		pt.put("Controls.Exposure.Value", exposureValue);

		pt.put("Controls.Gain.Mode", gainMode);
		pt.put("Controls.Gain.Value", gainValue);

		pt.put("Controls.WhiteBalance.Mode", whitebalMode);
		pt.put("Controls.WhiteBalance.ValueRed", whitebalValueRed);
		pt.put("Controls.WhiteBalance.ValueBlue", whitebalValueBlue);

		pt.put("ImageFormat.MirrorX", mirrorX);
		pt.put("ImageFormat.PixelFormat", pixelFormat);
		pt.put("ImageFormat.ROI.Height", height);
		pt.put("ImageFormat.ROI.Width", width);
		pt.put("ImageFormat.ROI.RegionX", regionX);
		pt.put("ImageFormat.ROI.RegionY", regionY);

		pt.put("ImageMode.BinningX", binningX);
		pt.put("ImageMode.BinningY", binningY);
	}
};

/*!
 * \class Sequence
 * \brief Class responsible for retrieving images from image sequences.
 */
class CameraGigE : public Base::Component {

public:
	/*!
	 * Constructor. Sets ID and startup variables.
	 */
	CameraGigE(const std::string & name = "");

	/*!
	 * Destructor.
	 */
	virtual ~CameraGigE();

	/*!
	 * Return sequence properties
	 */
	Base::Props * getProperties() {
		return &props;
	}

protected:

	/*!
	 * Connects source to given device.
	 */
	bool onInit();

	/*!
	 * Disconnect source from device, closes streams, etc.
	 */
	bool onFinish();

	/*!
	 * Retrieves data from device.
	 */
	bool onStep();

	/*!
	 * Start component
	 */
	bool onStart();

	/*!
	 * Stop component
	 */
	bool onStop();

	/// Event signaling that new image was retrieved.
	Base::Event * newImage;

	/// Sequence has ended
	Base::Event * endOfSequence;

	/// Output data stream
	Base::DataStreamOut<cv::Mat> out_img;

	/*!
	 * Event handler function.
	 */
	void onTrigger();

	/// Event handler.
	Base::EventHandler<CameraGigE> h_onTrigger;

private:
	/// Camera handle
	tPvHandle 	cHandle;
	tPvFrame	frame;

	/// current frame
	cv::Mat img;

	/// sequence properties
	Props props;

};

}//: namespace Sequence
}//: namespace Sources

/*
 * Register source component.
 */
REGISTER_SOURCE_COMPONENT("CameraGigE", Sources::CameraGigE::CameraGigE, Common::Panel_Empty)

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


<commit_before>#include "fdsb/nid.hpp"
#include <atomic>

using namespace fdsb;

std::atomic<unsigned long long> last_nid(0);

static Nid Nid::unique()
{
	return {Nid::Type::allocated,last_nid++};
}
<commit_msg>Removed static<commit_after>#include "fdsb/nid.hpp"
#include <atomic>

using namespace fdsb;

std::atomic<unsigned long long> last_nid(0);

Nid Nid::unique()
{
	return {Nid::Type::allocated,last_nid++};
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2014 Arduino.  All right reserved.

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

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

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <chip.h>

#include "watchdog.h"

void watchdogEnable (uint32_t timeout)
{
	/* this assumes the slow clock is running at 32.768 kHz
	   watchdog frequency is therefore 32768 / 128 = 256 Hz */
	timeout = timeout * 256 / 1000;
	if (timeout == 0)
		timeout = 1;
	else if (timeout > 0xFFF)
		timeout = 0xFFF;
	timeout = WDT_MR_WDRSTEN | WDT_MR_WDRPROC | WDT_MR_WDV(timeout) | WDT_MR_WDD(timeout);
	WDT_Enable (WDT, timeout);
}

void watchdogDisable(void)
{
	WDT_Disable (WDT);
}

void watchdogReset(void)
{
	WDT_Restart (WDT);
}

extern "C"
void _watchdogDefaultSetup (void)
{
	WDT_Disable (WDT);
}
void watchdogSetup (void) __attribute__ ((weak, alias("_watchdogDefaultSetup")));

<commit_msg>Due watchdog: change flags to effectively reset board<commit_after>/*
  Copyright (c) 2014 Arduino.  All right reserved.

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

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

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <chip.h>

#include "watchdog.h"

void watchdogEnable (uint32_t timeout)
{
	/* this assumes the slow clock is running at 32.768 kHz
	   watchdog frequency is therefore 32768 / 128 = 256 Hz */
	timeout = timeout * 256 / 1000;
	if (timeout == 0)
		timeout = 1;
	else if (timeout > 0xFFF)
		timeout = 0xFFF;
	timeout = WDT_MR_WDRSTEN | WDT_MR_WDV(timeout) | WDT_MR_WDD(timeout);
	WDT_Enable (WDT, timeout);
}

void watchdogDisable(void)
{
	WDT_Disable (WDT);
}

void watchdogReset(void)
{
	WDT_Restart (WDT);
}

extern "C"
void _watchdogDefaultSetup (void)
{
	WDT_Disable (WDT);
}
void watchdogSetup (void) __attribute__ ((weak, alias("_watchdogDefaultSetup")));

<|endoftext|>