From: g0dil Date: Fri, 15 May 2009 22:12:29 +0000 (+0000) Subject: Socket/Protocols/Raw: Add EUI64 data type X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=895dffdf82bb7360b61dc561e6beb1b69fa16ada;p=senf.git Socket/Protocols/Raw: Add EUI64 data type git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1210 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Socket/Protocols/Raw/EUI64.cc b/Socket/Protocols/Raw/EUI64.cc new file mode 100644 index 0000000..b69191b --- /dev/null +++ b/Socket/Protocols/Raw/EUI64.cc @@ -0,0 +1,87 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EUI64 non-inline non-template implementation */ + +#include "EUI64.hh" +//#include "EUI64.ih" + +// Custom includes +#include +#include +#include "ParseString.hh" + +//#include "EUI64.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +prefix_ senf::EUI64 senf::EUI64::from_string(std::string const & s) +{ + EUI64 eui (senf::noinit); + detail::parseHexString(s, ":-", eui.begin(), eui.end()); + return eui; +} + +prefix_ std::ostream & senf::operator<<(std::ostream & os, EUI64 const & eui) +{ + boost::io::ios_all_saver ias(os); + os << std::hex << std::setfill('0') + << std::setw(2) << unsigned(eui[0]) << ":" + << std::setw(2) << unsigned(eui[1]) << ":" + << std::setw(2) << unsigned(eui[2]) << ":" + << std::setw(2) << unsigned(eui[3]) << "-" + << std::setw(2) << unsigned(eui[4]) << ":" + << std::setw(2) << unsigned(eui[5]) << ":" + << std::setw(2) << unsigned(eui[6]) << ":" + << std::setw(2) << unsigned(eui[7]); + return os; +} + +prefix_ std::istream & senf::operator>>(std::istream & is, EUI64 & eui) +{ + std::string s; + if (!(is >> s)) + return is; + try { + eui = EUI64::from_string(s); + } + catch (AddressException &) { + is.setstate(std::ios::failbit); + } + return is; +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "EUI64.mpp" + + +// 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/Socket/Protocols/Raw/EUI64.cci b/Socket/Protocols/Raw/EUI64.cci new file mode 100644 index 0000000..6b40b7f --- /dev/null +++ b/Socket/Protocols/Raw/EUI64.cci @@ -0,0 +1,103 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EUI64 inline non-template implementation */ + +//#include "EUI64.ih" + +// Custom includes +#include +#include +#include "MACAddress.hh" + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +prefix_ senf::EUI64::EUI64(boost::uint64_t v) +{ + (*this)[0] = (v>>56) & 0xffu; + (*this)[1] = (v>>48) & 0xffu; + (*this)[2] = (v>>40) & 0xffu; + (*this)[3] = (v>>32) & 0xffu; + (*this)[4] = (v>>24) & 0xffu; + (*this)[5] = (v>>16) & 0xffu; + (*this)[6] = (v>> 8) & 0xffu; + (*this)[7] = (v ) & 0xffu; +} + +prefix_ senf::EUI64::EUI64(senf::NoInit_t) +{} + +prefix_ senf::EUI64 senf::EUI64::from_mac(MACAddress const & mac) +{ + EUI64 eui (senf::noinit); + eui[0] = mac[0]; + eui[1] = mac[1]; + eui[2] = mac[2]; + eui[3] = 0xffu; + eui[4] = 0xfeu; + eui[5] = mac[3]; + eui[6] = mac[4]; + eui[7] = mac[5]; + return eui; +} + +prefix_ bool senf::EUI64::isMACCompatible() + const +{ + return (*this)[3] == 0xffu && (*this)[4] == 0xfeu; +} + +prefix_ bool senf::EUI64::boolean_test() + const +{ + using boost::lambda::_1; + return std::find_if(begin(),end(), _1 != 0x00u) != end(); +} + +prefix_ boost::uint64_t senf::EUI64::uint64() + const +{ + return (boost::uint64_t((*this)[0])<<56) + | (boost::uint64_t((*this)[1])<<48) + | (boost::uint64_t((*this)[2])<<40) + | (boost::uint64_t((*this)[3])<<32) + | (boost::uint64_t((*this)[4])<<24) + | (boost::uint64_t((*this)[5])<<16) + | (boost::uint64_t((*this)[6])<< 8) + | (boost::uint64_t((*this)[7]) ); +} + +///////////////////////////////cci.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/Socket/Protocols/Raw/EUI64.cti b/Socket/Protocols/Raw/EUI64.cti new file mode 100644 index 0000000..6f15591 --- /dev/null +++ b/Socket/Protocols/Raw/EUI64.cti @@ -0,0 +1,54 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EUI64 inline template implementation */ + +//#include "EUI64.ih" + +// Custom includes +#include "../../../config.hh" + +#define prefix_ inline +///////////////////////////////cti.p/////////////////////////////////////// + +template +prefix_ senf::EUI64 senf::EUI64::from_data(InputIterator i) +{ + EUI64 eui (senf::noinit); + SENF_copy_n(i, 8, eui.begin()); + return eui; +} + +///////////////////////////////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/Socket/Protocols/Raw/EUI64.hh b/Socket/Protocols/Raw/EUI64.hh new file mode 100644 index 0000000..e125c02 --- /dev/null +++ b/Socket/Protocols/Raw/EUI64.hh @@ -0,0 +1,97 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EUI64 public header */ + +#ifndef HH_SENF_Socket_Protocols_Raw_EUI64_ +#define HH_SENF_Socket_Protocols_Raw_EUI64_ 1 + +// Custom includes +#include +#include +#include +#include "../../../Utils/Tags.hh" +#include "../../../Utils/safe_bool.hh" + +//#include "EUI64.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { + + class MACAddress; + + /** \brief EUI-64 data type + + An EUI-64 is a 64 bit (8 octet) id. + */ + class EUI64 + : public boost::array, + public senf::comparable_safe_bool + { + public: + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + // default copy constructor + // default copy assignment + // default destructor + // no conversion constructors + + explicit EUI64(boost::uint64_t v=0u); + explicit EUI64(senf::NoInit_t); + + static EUI64 from_mac(MACAddress const & mac); + static EUI64 from_string(std::string const & s); + template + static EUI64 from_data(InputIterator i); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + bool isMACCompatible() const; + bool boolean_test() const; + boost::uint64_t uint64() const; + }; + + std::ostream & operator<<(std::ostream & os, EUI64 const & v); + std::istream & operator>>(std::istream & is, EUI64 & v); + +} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "EUI64.cci" +//#include "EUI64.ct" +#include "EUI64.cti" +#endif + + +// 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/Socket/Protocols/Raw/EUI64.test.cc b/Socket/Protocols/Raw/EUI64.test.cc new file mode 100644 index 0000000..3c53281 --- /dev/null +++ b/Socket/Protocols/Raw/EUI64.test.cc @@ -0,0 +1,95 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 EUI64.test unit tests */ + +//#include "EUI64.test.hh" +//#include "EUI64.test.ih" + +// Custom includes +#include "EUI64.hh" + +#include "../../../Utils/auto_unit_test.hh" +#include + +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +BOOST_AUTO_UNIT_TEST(eui64) +{ + senf::EUI64 eui; + BOOST_CHECK( !eui ); + BOOST_CHECK( !eui.isMACCompatible() ); + + eui = senf::EUI64::from_mac(senf::MACAddress(0x102030405060ull)); + boost::uint8_t data[] = { 0x10u, 0x20u, 0x30u, 0xffu, 0xfeu, 0x40u, 0x50u, 0x60u }; + BOOST_CHECK_EQUAL_COLLECTIONS( eui.begin(), eui.end(), data, data+sizeof(data)/sizeof(data[0]) ); + BOOST_CHECK( eui ); + BOOST_CHECK( eui.isMACCompatible() ); + BOOST_CHECK_EQUAL( eui.uint64(), 0x102030fffe405060ull ); + + BOOST_CHECK_EQUAL( eui, senf::EUI64::from_data(data) ); + BOOST_CHECK_EQUAL( eui, senf::EUI64::from_string("10:20:30:ff-FE:40:50:60") ); + + BOOST_CHECK_THROW( senf::EUI64::from_string("123:20:30:40:50:60:70:80"), + senf::AddressSyntaxException ); + BOOST_CHECK_THROW( senf::EUI64::from_string("12:20:30:40:50:60:70"), + senf::AddressSyntaxException ); + BOOST_CHECK_THROW( senf::EUI64::from_string("12:20:30:40:50:60:70:8g"), + senf::AddressSyntaxException ); + BOOST_CHECK_THROW( senf::EUI64::from_string("12:20:30:40:50:60:70:80:90"), + senf::AddressSyntaxException ); + + { + std::stringstream ss; + ss << std::uppercase << eui; + BOOST_CHECK_EQUAL( ss.str(), "10:20:30:FF-FE:40:50:60" ); + eui = senf::EUI64(); + BOOST_CHECK( !eui ); + ss >> eui; + BOOST_CHECK_EQUAL( eui, senf::EUI64(0x102030fffe405060ull) ); + + BOOST_CHECK( (ss >> eui).fail() ); + } + + { + std::stringstream ss; + ss << "01:02:03:04-05:06:07:108"; + BOOST_CHECK( (ss >> eui).fail() ); + } + +} + +///////////////////////////////cc.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/Socket/Protocols/Raw/MACAddress.cc b/Socket/Protocols/Raw/MACAddress.cc index e8fb19b..43a2882 100644 --- a/Socket/Protocols/Raw/MACAddress.cc +++ b/Socket/Protocols/Raw/MACAddress.cc @@ -30,63 +30,20 @@ #include #include #include -#include #include -#include +#include "ParseString.hh" //#include "MACAddress.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -namespace { - - boost::uint8_t hexToNibble(char c) - { - if (c<'0') - throw senf::AddressSyntaxException(); - else if (c<='9') - return c-'0'; - else if (c<'A') - throw senf::AddressSyntaxException(); - else if (c<='F') - return c-'A'+10; - else if (c<'a') - throw senf::AddressSyntaxException(); - else if (c<='f') - return c-'a'+10; - else - throw senf::AddressSyntaxException(); - } - - template - boost::uint8_t hexToByte(Range const & range) - { - if (boost::size(range) != 2) - throw senf::AddressSyntaxException(); - typename boost::range_const_iterator::type i (boost::begin(range)); - return hexToNibble(i[0])*16+hexToNibble(i[1]); - } - -} - /////////////////////////////////////////////////////////////////////////// // senf::MACAddress prefix_ senf::MACAddress::MACAddress senf::MACAddress::from_string(std::string const & s) { MACAddress mac (senf::noinit); - typedef boost::char_separator separator; - typedef boost::tokenizer tokenizer; - separator sep (":-"); - tokenizer tok (s,sep); - tokenizer::iterator i (tok.begin()); - tokenizer::iterator const i_end (tok.end()); - iterator j (mac.begin()); - iterator const j_end (mac.end()); - for (; i!=i_end && j!=j_end; ++i, ++j) - *j = hexToByte(*i); - if (i!=i_end || j!=j_end) - throw AddressSyntaxException(); + detail::parseHexString(s, ":-", mac.begin(), mac.end()); return mac; } @@ -113,7 +70,7 @@ senf::MACAddress const senf::MACAddress::None; prefix_ std::ostream & senf::operator<<(std::ostream & os, MACAddress const & mac) { - boost::io::ios_all_saver ias(os); + boost::io::ios_all_saver ias (os); os << std::hex << std::setfill('0'); for (MACAddress::const_iterator i (mac.begin()); i != mac.end(); ++i) { if (i != mac.begin()) diff --git a/Socket/Protocols/Raw/MACAddress.ct b/Socket/Protocols/Raw/MACAddress.ct index 2f87896..e0b4ef3 100644 --- a/Socket/Protocols/Raw/MACAddress.ct +++ b/Socket/Protocols/Raw/MACAddress.ct @@ -26,6 +26,7 @@ //#include "MACAddress.ih" // Custom includes +#include "../../../config.hh" #define prefix_ ///////////////////////////////ct.p//////////////////////////////////////// @@ -37,10 +38,7 @@ template prefix_ senf::MACAddress::MACAddress senf::MACAddress::from_data(InputIterator i) { MACAddress mac (senf::noinit); - iterator j (mac.begin()); - iterator const j_end (mac.end()); - for (;j!=j_end;++j,++i) - *j = *i; + SENF_copy_n(i, 6, mac.begin()); return mac; } diff --git a/Socket/Protocols/Raw/MACAddress.test.cc b/Socket/Protocols/Raw/MACAddress.test.cc index 87d0686..5dd8691 100644 --- a/Socket/Protocols/Raw/MACAddress.test.cc +++ b/Socket/Protocols/Raw/MACAddress.test.cc @@ -60,14 +60,14 @@ BOOST_AUTO_UNIT_TEST(macAddress) { std::stringstream str ( "invalid_mac_address"); str >> mac; - BOOST_CHECK( str.fail()); + BOOST_CHECK( str.fail() ); } { std::stringstream str; str << mac; BOOST_CHECK_EQUAL( str.str(), "a1:b2:c3:d4:e5:f6" ); str >> mac; - BOOST_CHECK( ! str.fail()); + BOOST_CHECK( ! str.fail() ); } BOOST_CHECK_EQUAL(mac, MACAddress::from_string(test)); @@ -92,7 +92,7 @@ BOOST_AUTO_UNIT_TEST(macAddress) BOOST_CHECK( mac == mac2 ); BOOST_CHECK_EQUAL( senf::str(mac2), "a1:b2:c3:d4:e5:f6" ); - BOOST_CHECK_THROW( MACAddress::from_string("1:2:3:4:5:6"), AddressSyntaxException ); + BOOST_CHECK_THROW( MACAddress::from_string("123:2:3:4:5:6"), AddressSyntaxException ); BOOST_CHECK_THROW( MACAddress::from_string("01:02:03:04:05"), AddressSyntaxException ); // test all invalid ascii ranges BOOST_CHECK_THROW( MACAddress::from_string("01:02:03:04:05:z6"), AddressSyntaxException ); diff --git a/Socket/Protocols/Raw/ParseString.ct b/Socket/Protocols/Raw/ParseString.ct new file mode 100644 index 0000000..94eeeac --- /dev/null +++ b/Socket/Protocols/Raw/ParseString.ct @@ -0,0 +1,73 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 ParseString non-inline template implementation */ + +//#include "ParseString.ih" + +// Custom includes +#include +#include +#include +#include "../../../Utils/String.hh" + +#define prefix_ +///////////////////////////////ct.p//////////////////////////////////////// + +template +prefix_ void senf::detail::parseHexString(std::string const & value, + char const * separator, ForwardIterator f, + ForwardIterator l) +{ + typedef boost::char_separator Separator; + typedef boost::tokenizer Tokenizer; + Separator sep (separator); + Tokenizer tok (value, sep); + Tokenizer::iterator i (tok.begin()); + Tokenizer::iterator const i_end (tok.end()); + try { + for (; i!=i_end && f!=l; ++i, ++f) + *f = boost::numeric_cast::value_type>( + senf::lexical_cast()[std::hex]( + std::string(boost::begin(*i),boost::end(*i)))); + } + catch (std::bad_cast &) { + throw AddressSyntaxException(); + } + if (i!=i_end || f!=l) + throw AddressSyntaxException(); +} + +///////////////////////////////ct.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/Socket/Protocols/Raw/ParseString.hh b/Socket/Protocols/Raw/ParseString.hh new file mode 100644 index 0000000..a59c0f5 --- /dev/null +++ b/Socket/Protocols/Raw/ParseString.hh @@ -0,0 +1,58 @@ +// $Id$ +// +// Copyright (C) 2009 +// Fraunhofer Institute for Open Communication Systems (FOKUS) +// Competence Center NETwork research (NET), St. Augustin, GERMANY +// Stefan Bund +// +// 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 ParseString public header */ + +#ifndef HH_SENF_Socket_Protocols_Raw_ParseString_ +#define HH_SENF_Socket_Protocols_Raw_ParseString_ 1 + +// Custom includes + +//#include "ParseString.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace senf { +namespace detail { + + template + void parseHexString(std::string const & value, char const * separator, + ForwardIterator f, ForwardIterator l); + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +//#include "ParseString.cci" +#include "ParseString.ct" +//#include "ParseString.cti" +#endif + + +// 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: