diff --git a/Socket/ServerSocketHandle.cti b/Socket/ServerSocketHandle.cti index 4044b1ee269e19eab611b926bb99bf613e992003..132625d789786bec3248d05e9fca5d9d5d2a2e29 100644 --- a/Socket/ServerSocketHandle.cti +++ b/Socket/ServerSocketHandle.cti @@ -114,8 +114,8 @@ template <class SPolicy> prefix_ typename senf::ServerSocketHandle<SPolicy>::ClientHandle senf::ServerSocketHandle<SPolicy>::acceptfrom(Address & addr) { - return ClienttHandle(this->protocol().clone(), - SPolicy::CommunicationPolicy::accept(*this,addr)); + return ClientHandle(this->body().clone( + SPolicy::CommunicationPolicy::accept(*this,addr), false)); } /////////////////////////////////////////////////////////////////////////// diff --git a/Utils/Console/Parse.test.cc b/Utils/Console/Parse.test.cc index 5a2295f3fe633125c164107af354b137f44d011d..4570fb0e61c706b49ee4a55d9cce22c90f563c5c 100644 --- a/Utils/Console/Parse.test.cc +++ b/Utils/Console/Parse.test.cc @@ -227,28 +227,28 @@ BOOST_AUTO_UNIT_TEST(commandParser) ++ args; BOOST_REQUIRE( args != info.arguments().end() ); - BOOST_REQUIRE_EQUAL( args->size(), 1 ); + BOOST_REQUIRE_EQUAL( args->size(), 1u ); BOOST_CHECK_EQUAL( args->begin()->value(), tokens[1] ); ++ args; BOOST_REQUIRE( args != info.arguments().end() ); - BOOST_REQUIRE_EQUAL( args->size(), 1 ); + BOOST_REQUIRE_EQUAL( args->size(), 1u ); BOOST_CHECK_EQUAL( args->begin()->value(), tokens[2] ); ++ args; BOOST_REQUIRE( args != info.arguments().end() ); - BOOST_REQUIRE_EQUAL( args->size(), 8 ); + BOOST_REQUIRE_EQUAL( args->size(), 8u ); for (unsigned i (0); i<8; ++i) BOOST_CHECK_EQUAL( args->begin()[i].value(), tokens[4+i] ); ++ args; BOOST_REQUIRE( args != info.arguments().end() ); - BOOST_REQUIRE_EQUAL( args->size(), 1 ); + BOOST_REQUIRE_EQUAL( args->size(), 1u ); BOOST_CHECK_EQUAL( args->begin()->value(), tokens[13] ); ++ args; BOOST_REQUIRE( args != info.arguments().end() ); - BOOST_REQUIRE_EQUAL( args->size(), 1 ); + BOOST_REQUIRE_EQUAL( args->size(), 1u ); BOOST_CHECK_EQUAL( args->begin()->value(), tokens[14] ); ++ args; diff --git a/Utils/Console/Server.cc b/Utils/Console/Server.cc index 719f527b4fea6f1c9cec588e18cad1f8f18d0c84..41475c29ec35c3d2ec59f902eea12791d342e751 100644 --- a/Utils/Console/Server.cc +++ b/Utils/Console/Server.cc @@ -106,12 +106,12 @@ prefix_ void senf::console::Server::newClient(int event) ServerHandle::ClientHandle client (handle_.accept()); boost::intrusive_ptr<Client> p (new Client(*this, client)); clients_.insert( p ); - SENF_LOG(( "Registered new client " << p.get() )); + SENF_LOG(( "Registered new client " << client.peer() )); } prefix_ void senf::console::Server::removeClient(Client & client) { - SENF_LOG(( "Disposing client " << & client )); + SENF_LOG(( "Disposing client " << client.handle().peer() )); // THIS DELETES THE CLIENT INSTANCE !! clients_.erase(boost::intrusive_ptr<Client>(&client)); } @@ -224,8 +224,9 @@ senf::console::detail::NoninteractiveClientReader::newData(int event) // senf::console::Client prefix_ senf::console::Client::Client(Server & server, ClientHandle handle) - : out_t(boost::ref(*this)), senf::log::IOStreamTarget(out_t::member), server_ (server), - handle_ (handle), + : out_t(boost::ref(*this)), + senf::log::IOStreamTarget("client-" + senf::str(handle.peer()), out_t::member), + server_ (server), handle_ (handle), readevent_ ("senf::console::Client::interactive_check", boost::bind(&Client::setNoninteractive,this), handle, scheduler::FdEvent::EV_READ, false), @@ -322,33 +323,6 @@ prefix_ void senf::console::Client::v_write(senf::log::time_type timestamp, reader_->enablePrompt(); } -prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Client const & client) -{ - typedef ClientSocketHandle< MakeSocketPolicy< - INet4AddressingPolicy,ConnectedCommunicationPolicy>::policy > V4Socket; - typedef ClientSocketHandle< MakeSocketPolicy< - INet6AddressingPolicy,ConnectedCommunicationPolicy>::policy > V6Socket; - - try { - if (check_socket_cast<V4Socket>(client.handle())) - os << dynamic_socket_cast<V4Socket>(client.handle()).peer(); - else if (check_socket_cast<V6Socket>(client.handle())) - os << dynamic_socket_cast<V6Socket>(client.handle()).peer(); - else - os << static_cast<void const *>(&client); - } - catch (SystemException &) { - os << "0.0.0.0:0"; - } - - return os; -} - -prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Client * client) -{ - return os << *client; -} - /////////////////////////////////////////////////////////////////////////// // senf::console::Client::SysBacktrace diff --git a/Utils/Console/Server.ih b/Utils/Console/Server.ih index d7b73e7e76ffdeb2d834f22e92c9d0b7a57654ef..5e110faaab2516430b21671454b1f59cf3e9465d 100644 --- a/Utils/Console/Server.ih +++ b/Utils/Console/Server.ih @@ -88,7 +88,7 @@ namespace detail { typedef senf::ServerSocketHandle< senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy, - senf::UnspecifiedAddressingPolicy>::policy > ServerHandle; + senf::BSDAddressingPolicy>::policy > ServerHandle; /** \brief Internal: Generic client interface diff --git a/Utils/Logger/ConsoleTarget.cci b/Utils/Logger/ConsoleTarget.cci index d1ff8e52554fa8455dc5bf5bd13000a21ecea6e1..5fc13c1e87c4119458f1f13dcd655b4865e3f52c 100644 --- a/Utils/Logger/ConsoleTarget.cci +++ b/Utils/Logger/ConsoleTarget.cci @@ -40,7 +40,7 @@ prefix_ senf::log::ConsoleTarget & senf::log::ConsoleTarget::instance() } prefix_ senf::log::ConsoleTarget::ConsoleTarget() - : IOStreamTarget(std::cout) + : IOStreamTarget("console", std::cout) {} ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/Utils/Logger/FileTarget.cc b/Utils/Logger/FileTarget.cc index 04675739602e84f4cc558c7c890ac345d970fe1b..2baff33daf6f5202e0371762606f314e329cf3b1 100644 --- a/Utils/Logger/FileTarget.cc +++ b/Utils/Logger/FileTarget.cc @@ -33,7 +33,8 @@ ///////////////////////////////cc.p//////////////////////////////////////// prefix_ senf::log::FileTarget::FileTarget(std::string file) - : ofstream_t(file.c_str(), std::ofstream::app), IOStreamTarget(ofstream_t::member), file_(file) + : ofstream_t(file.c_str(), std::ofstream::app), IOStreamTarget(file, ofstream_t::member), + file_(file) {} prefix_ void senf::log::FileTarget::reopen() diff --git a/Utils/Logger/IOStreamTarget.cci b/Utils/Logger/IOStreamTarget.cci index 8e55b7448327bf06870d49d788ec5580fca176c1..e4f7968012d59bad08e526d9dcfd40fe10c6ecfa 100644 --- a/Utils/Logger/IOStreamTarget.cci +++ b/Utils/Logger/IOStreamTarget.cci @@ -30,8 +30,8 @@ #define prefix_ inline ///////////////////////////////cci.p/////////////////////////////////////// -prefix_ senf::log::IOStreamTarget::IOStreamTarget(std::ostream & os) - : stream_ (os) +prefix_ senf::log::IOStreamTarget::IOStreamTarget(std::string const & name, std::ostream & os) + : Target(name), stream_ (os) {} ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/Utils/Logger/IOStreamTarget.hh b/Utils/Logger/IOStreamTarget.hh index bb1c0d57c36014982245ba6a106581129039508d..229ab6309c4614537327adbf81aa4bb8d2880c6b 100644 --- a/Utils/Logger/IOStreamTarget.hh +++ b/Utils/Logger/IOStreamTarget.hh @@ -57,7 +57,7 @@ namespace log { ///\name Structors and default members ///@{ - explicit IOStreamTarget(std::ostream & os); + IOStreamTarget(std::string const & name, std::ostream & os); ///@} /////////////////////////////////////////////////////////////////////////// diff --git a/Utils/Logger/StringTarget.cti b/Utils/Logger/StringTarget.cti index 11572060bf8abcec5704945369074077b076c8d1..a1e6a372f791e12a3da3a7093d3354b7afe3e7a5 100644 --- a/Utils/Logger/StringTarget.cti +++ b/Utils/Logger/StringTarget.cti @@ -34,7 +34,7 @@ // senf::log::StringTarget prefix_ senf::log::StringTarget::StringTarget() - : IOStreamTarget(stream_base::member) + : IOStreamTarget("membuffer", stream_base::member) {} prefix_ std::string senf::log::StringTarget::str() diff --git a/Utils/Logger/SyslogTarget.cci b/Utils/Logger/SyslogTarget.cci index fe71ce3c7c7879cc278842fbefd4f0bea401df25..f9c62710b5eff51df911ea44cf4048dadc945d98 100644 --- a/Utils/Logger/SyslogTarget.cci +++ b/Utils/Logger/SyslogTarget.cci @@ -31,7 +31,7 @@ ///////////////////////////////cci.p/////////////////////////////////////// prefix_ senf::log::SyslogTarget::SyslogTarget(int facility) - : facility_ (facility) + : Target("syslog"), facility_ (facility) {} ///////////////////////////////cci.e/////////////////////////////////////// diff --git a/Utils/Logger/SyslogUDPTarget.cc b/Utils/Logger/SyslogUDPTarget.cc index 0538fe070aae4a34b564264aea72b56c54d7864d..03a055f8928eeb15b8f86a9bf5aef950f490c71b 100644 --- a/Utils/Logger/SyslogUDPTarget.cc +++ b/Utils/Logger/SyslogUDPTarget.cc @@ -44,6 +44,9 @@ prefix_ void senf::log::SyslogUDPTarget::v_write(time_type timestamp, std::strin detail::quoteNonPrintable(m); std::stringstream prfstream; + // The space after the '>' is there on purpose: It ensures, that the prefix (which may be empty) + // or message will not inadvertently be interpreted as date or hostname by a receiving syslog + // daemon or proxy prfstream << '<' << (facility_ | senf::log::SyslogTarget::LEVELMAP[level]) << "> " << prefix(timestamp, stream, area, level); std::string const & prf (prfstream.str()); diff --git a/Utils/Logger/SyslogUDPTarget.cci b/Utils/Logger/SyslogUDPTarget.cci index 4078e3d35989a6cb9be740bffd38bc2eb291bf54..52a505551e9db3ef22cb768d62732b5b498e9f6b 100644 --- a/Utils/Logger/SyslogUDPTarget.cci +++ b/Utils/Logger/SyslogUDPTarget.cci @@ -27,31 +27,32 @@ // Custom includes #include "../../Socket/Protocols/INet/ConnectedUDPSocketHandle.hh" +#include "../String.hh" #define prefix_ inline ///////////////////////////////cci.p/////////////////////////////////////// prefix_ senf::log::SyslogUDPTarget::SyslogUDPTarget(senf::INet4Address const & target, int facility) - : facility_ (facility), + : Target("udp-" + senf::str(target)), facility_ (facility), handle_ ( senf::ConnectedUDPv4ClientSocketHandle(senf::INet4SocketAddress(target, 514u)) ) {} prefix_ senf::log::SyslogUDPTarget::SyslogUDPTarget(senf::INet4SocketAddress const & target, int facility) - : facility_ (facility), + : Target("udp-" + senf::str(target)), facility_ (facility), handle_ ( senf::ConnectedUDPv4ClientSocketHandle(target) ) {} prefix_ senf::log::SyslogUDPTarget::SyslogUDPTarget(senf::INet6Address const & target, int facility) - : facility_ (facility), + : Target("udp-" + senf::str(target)), facility_ (facility), handle_ ( senf::ConnectedUDPv6ClientSocketHandle(senf::INet6SocketAddress(target, 514u)) ) {} prefix_ senf::log::SyslogUDPTarget::SyslogUDPTarget(senf::INet6SocketAddress const & target, int facility) - : facility_ (facility), + : Target("udp-" + senf::str(target)), facility_ (facility), handle_ ( senf::ConnectedUDPv6ClientSocketHandle(target) ) {} diff --git a/Utils/Logger/Target.cc b/Utils/Logger/Target.cc index 068631c7df3e5cbbd7d4778d33c7441f422437f2..22d5823d400f58bf7b5b9ce88fb6b1e452508961 100644 --- a/Utils/Logger/Target.cc +++ b/Utils/Logger/Target.cc @@ -28,7 +28,11 @@ // Custom includes #include <algorithm> +#include <boost/format.hpp> #include "ConsoleTarget.hh" +#include "../Console/Console.hh" +#include "../Console/Sysdir.hh" +#include "../membind.hh" //#include "Target.mpp" #define prefix_ @@ -37,9 +41,106 @@ /////////////////////////////////////////////////////////////////////////// // senf::log::Target -prefix_ senf::log::Target::Target() +namespace senf { +namespace log { + + SENF_CONSOLE_REGISTER_ENUM_MEMBER( Target, action_t, (ACCEPT)(REJECT) ); + +}} + +namespace { +namespace local { + + enum Level { + VERBOSE = senf::log::VERBOSE::value, + NOTICE = senf::log::NOTICE::value, + MESSAGE = senf::log::MESSAGE::value, + IMPORTANT = senf::log::IMPORTANT::value, + CRITICAL = senf::log::CRITICAL::value, + FATAL = senf::log::FATAL::value + }; + SENF_CONSOLE_REGISTER_ENUM( Level, + (VERBOSE)(NOTICE)(MESSAGE)(IMPORTANT)(CRITICAL)(FATAL) ); + +}} + +prefix_ senf::log::Target::Target(std::string const & name) { - detail::TargetRegistry::instance().registerTarget(this); + namespace kw = senf::console::kw; + + detail::TargetRegistry::instance().registerTarget(this, name); + consoleDir_().add("list", senf::membind(&Target::consoleList, this)) + .doc("Show routing table\n" + "\n" + "Columns:\n" + " # rule index\n" + " STREAM stream to match, empty to match all streams\n" + " AREA area to match, empty to match all targets\n" + " LEVEL match messages with level above this. Log levels in increasing order\n" + " are:\n" + " verbose, notice, message, important, critical, fatal\n" + " ACTION action to take: accept or reject"); + consoleDir_().add("route", + boost::function<void (std::string const &, std::string const &, + local::Level, action_t, int)>( + senf::membind( + static_cast<void (Target::*)( + std::string const &, std::string const &, + unsigned, action_t, int)>(&Target::route), + this))) + .arg("stream", "stream to match or empty to match any stream", + kw::default_value="") + .arg("area", "area to match or empty to match any area", + kw::default_value="") + .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL", + kw::default_value=local::VERBOSE) + .arg("action", "routing action, one of: ACCEPT, REJECT", + kw::default_value=ACCEPT) + .arg("index", "index at which to insert new rule", + kw::default_value=-1) + .doc("Add routing entry. Log messages are matched against the routing table beginning\n" + "with the first entry. The action of the first matching entry determines the\n" + "handling of the message.\n" + "\n" + "Examples:\n" + "\n" + " route\n" + " route all messages to this target.\n" + "\n" + " route \"\" my::Class\n" + " route all messages which are in the my::Class area.\n" + "\n" + " route senf::log::Debug \"\" VERBOSE REJECT\n" + " route \"\" \"\" VERBOSE\n" + " route all messages not in the senf::log::Debug stream to the current area.\n" + "\n" + "The additional optional index argument identifies the position in the routing table\n" + "where the new routing entry will be added. Positive numbers count from the\n" + "beginning, 0 being the first routing entry. Negative values count from the end.\n"); + consoleDir_().add("unroute", + senf::membind(static_cast<void (Target::*)(int)>(&Target::unroute), this)) + .arg("index", "index of routing entry to remove") + .overloadDoc("Remove routing entry with the given index"); + consoleDir_().add("unroute", + boost::function<void (std::string const &, std::string const &, + local::Level, action_t)>( + senf::membind( + static_cast<void (Target::*)( + std::string const &, std::string const &, + unsigned, action_t)>(&Target::unroute), + this))) + .arg("stream", "stream to match or empty to match any stream", + kw::default_value="") + .arg("area", "area to match or empty to match any area", + kw::default_value="") + .arg("level", "log level, one of: VERBOSE, NOTICE, MESSAGE, IMPORTANT, CRITICAL, FATAL", + kw::default_value=local::VERBOSE) + .arg("action", "routing action, one of: ACCEPT, REJECT", + kw::default_value=ACCEPT) + .overloadDoc("Remove the routing entry matching the specified arguments."); + consoleDir_().add("flush", senf::membind(&Target::flush, this)) + .doc("Remove all routing entries clearing the routing table. This will disable all\n" + "logging output on this target."); } prefix_ senf::log::Target::~Target() @@ -56,9 +157,12 @@ prefix_ senf::log::Target::~Target() prefix_ void senf::log::Target::route(std::string const & stream, std::string const & area, unsigned level, action_t action, int index) { - detail::StreamBase const * s (StreamRegistry::instance().lookup(stream)); - if (!s) - throw InvalidStreamException(); + detail::StreamBase const * s (0); + if (! stream.empty()) { + s = StreamRegistry::instance().lookup(stream); + if (!s) + throw InvalidStreamException(); + } detail::AreaBase const * a (0); if (! area.empty()) { a = AreaRegistry::instance().lookup(area); @@ -71,9 +175,12 @@ prefix_ void senf::log::Target::route(std::string const & stream, std::string co prefix_ void senf::log::Target::unroute(std::string const & stream, std::string const & area, unsigned level, action_t action) { - detail::StreamBase const * s (StreamRegistry::instance().lookup(stream)); - if (!s) - throw InvalidStreamException(); + detail::StreamBase const * s (0); + if (! stream.empty()) { + s = StreamRegistry::instance().lookup(stream); + if (!s) + throw InvalidStreamException(); + } detail::AreaBase const * a (0); if (! area.empty()) { a = AreaRegistry::instance().lookup(area); @@ -123,6 +230,15 @@ prefix_ void senf::log::Target::flush() updateRoutingCache(i->stream_, i->area_); } +//////////////////////////////////////// +// protected members + +prefix_ senf::log::detail::TargetRegistry::TargetRegistry() + : fallbackRouting_(true) +{ + console::sysdir().add("log", consoleDir_()); +} + //////////////////////////////////////// // private members @@ -214,9 +330,44 @@ prefix_ void senf::log::Target::write(time_type timestamp, } } +namespace { + std::string formatLabel(std::string const & l) + { + if (l.empty()) + return "-"; + if (l.size() > 29) + return l.substr(l.size()-29); + return l; + } +} + +prefix_ void senf::log::Target::consoleList(std::ostream & os) +{ + static char const * levels[] = { + "none", "verbose", "notice", "message", "important", "critical", "fatal", "disabled" }; + + boost::format fmt ("%2d %-29s %-29s %-9s %-6s\n"); + os << fmt % "#" % "STREAM" % "AREA" % "LEVEL" % "ACTION"; + unsigned n (0); + for (iterator i (begin()); i != end(); ++i, ++n) + os << fmt + % n + % formatLabel(i->stream()) + % formatLabel(i->area()) + % levels[i->level()] + % (i->action() == ACCEPT ? "accept" : "reject"); +} + /////////////////////////////////////////////////////////////////////////// // senf::log::detail::TargetRegistry +prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target, + std::string const & name) +{ + targets_.insert(target); + consoleDir_().add(name, target->consoleDir_()); +} + prefix_ void senf::log::detail::TargetRegistry::write(StreamBase const & stream, AreaBase const & area, unsigned level, std::string const & msg) diff --git a/Utils/Logger/Target.cci b/Utils/Logger/Target.cci index 10e58ab352e51a503f66171eb8e144e6fff629fc..09c570669525dc4432fe545937374a3c82f275ec 100644 --- a/Utils/Logger/Target.cci +++ b/Utils/Logger/Target.cci @@ -137,15 +137,6 @@ prefix_ bool senf::log::detail::TargetRegistry::fallbackRouting() //////////////////////////////////////// // private members -prefix_ senf::log::detail::TargetRegistry::TargetRegistry() - : fallbackRouting_(true) -{} - -prefix_ void senf::log::detail::TargetRegistry::registerTarget(Target * target) -{ - targets_.insert(target); -} - prefix_ void senf::log::detail::TargetRegistry::unregisterTarget(Target * target) { targets_.erase(target); diff --git a/Utils/Logger/Target.hh b/Utils/Logger/Target.hh index 9065ef4c4075a511344665c906ab4478700702f4..69fd1d123115c7987da35c61c92ddea75c8279c1 100644 --- a/Utils/Logger/Target.hh +++ b/Utils/Logger/Target.hh @@ -36,6 +36,7 @@ #include "StreamRegistry.hh" #include "../Exception.hh" #include "TimeSource.hh" +#include "../Console/LazyDirectory.hh" //#include "Target.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -185,7 +186,7 @@ namespace log { ///\name Structors and default members ///@{ - Target(); + explicit Target(std::string const & name); virtual ~Target(); ///@} @@ -351,6 +352,8 @@ namespace log { void write(time_type timestamp, detail::StreamBase const & stream, detail::AreaBase const & area, unsigned level, std::string const & message); + void consoleList(std::ostream & os); + # ifdef DOXYGEN protected: # endif @@ -382,6 +385,8 @@ namespace log { RIB rib_; + console::LazyDirectory consoleDir_; + friend class detail::AreaBase; friend class detail::TargetRegistry; }; diff --git a/Utils/Logger/Target.ih b/Utils/Logger/Target.ih index a0838719b46757d5f7f93247aa1e9af738c34bc7..c6d4efb7fa11030081418748d1707fd47ed97fd4 100644 --- a/Utils/Logger/Target.ih +++ b/Utils/Logger/Target.ih @@ -30,6 +30,7 @@ #include <memory> #include <boost/type_traits/is_same.hpp> #include <boost/static_assert.hpp> +#include "../Console/LazyDirectory.hh" ///////////////////////////////ih.p//////////////////////////////////////// @@ -53,13 +54,15 @@ namespace detail { private: TargetRegistry(); - void registerTarget(Target * target); + void registerTarget(Target * target, std::string const & name); void unregisterTarget(Target * target); typedef std::set<Target *> Targets; Targets targets_; bool fallbackRouting_; + + console::LazyDirectory consoleDir_; friend class senf::log::Target; friend class senf::singleton<TargetRegistry>; diff --git a/Utils/String.cti b/Utils/String.cti new file mode 100644 index 0000000000000000000000000000000000000000..8d39ba9159393dc79f33910dfafa56cbf3146a26 --- /dev/null +++ b/Utils/String.cti @@ -0,0 +1,52 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund <g0dil@berlios.de> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the +// Free Software Foundation, Inc., +// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +/** \file + \brief String inline template implementation */ + +//#include "String.ih" + +// Custom includes +#include <boost/lexical_cast.hpp> + +#define prefix_ inline +///////////////////////////////cti.p/////////////////////////////////////// + +template <class T> +prefix_ std::string senf::str(T const & t) +{ + return boost::lexical_cast<std::string>(t); +} + +///////////////////////////////cti.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "senf" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -u test" +// End: diff --git a/Utils/String.hh b/Utils/String.hh index 10f523e6787e33c5af3aebad942e694635cfbe73..623068b652c24c67cee01d3810ae69830476751d 100644 --- a/Utils/String.hh +++ b/Utils/String.hh @@ -42,12 +42,15 @@ namespace senf { template <class ForwardReadableRange> std::string stringJoin(ForwardReadableRange const & range, std::string sep); + template <class T> + std::string str(T const & t); + } ///////////////////////////////hh.e//////////////////////////////////////// //#include "String.cci" #include "String.ct" -//#include "String.cti" +#include "String.cti" #endif