From 1c7d6bf5fcddae13b6226d61fe60cfccb8d2c359 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 11 Sep 2003 10:23:55 +0000 Subject: * Removed references to char_traits so that boost/format also works on GCC 2.95. --- boost/Makefile.am | 1 + boost/format.hpp | 9 +- boost/format/Makefile.am | 3 + boost/format/feed_args.hpp | 69 +++-- boost/format/format_class.hpp | 43 ++-- boost/format/format_fwd.hpp | 16 +- boost/format/format_implementation.cc | 256 ++++++++++++++++++ boost/format/format_implementation.hpp | 268 ------------------- boost/format/free_funcs.cc | 71 +++++ boost/format/free_funcs.hpp | 72 ------ boost/format/group.hpp | 44 ++-- boost/format/internals.hpp | 48 ++-- boost/format/internals_fwd.hpp | 24 +- boost/format/parsing.cc | 454 ++++++++++++++++++++++++++++++++ boost/format/parsing.hpp | 457 --------------------------------- 15 files changed, 906 insertions(+), 929 deletions(-) create mode 100644 boost/Makefile.am create mode 100644 boost/format/Makefile.am create mode 100644 boost/format/format_implementation.cc delete mode 100644 boost/format/format_implementation.hpp create mode 100644 boost/format/free_funcs.cc delete mode 100644 boost/format/free_funcs.hpp create mode 100644 boost/format/parsing.cc delete mode 100644 boost/format/parsing.hpp (limited to 'boost') diff --git a/boost/Makefile.am b/boost/Makefile.am new file mode 100644 index 000000000..fad59a1b9 --- /dev/null +++ b/boost/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = format diff --git a/boost/format.hpp b/boost/format.hpp index f5bdada05..a287048ed 100644 --- a/boost/format.hpp +++ b/boost/format.hpp @@ -25,6 +25,9 @@ #include #include +//#define BOOST_NO_STD_LOCALE +//#define BOOST_NO_LOCALE_ISIDIGIT +//#include #include @@ -54,15 +57,15 @@ namespace boost #include // **** Implementation ------------------------------------------- -#include // member functions +//#include // member functions #include // class for grouping arguments #include // argument-feeding functions -#include // format-string parsing (member-)functions +//#include // format-string parsing (member-)functions // **** Implementation of the free functions ---------------------- -#include +//#include #endif // BOOST_FORMAT_HPP diff --git a/boost/format/Makefile.am b/boost/format/Makefile.am new file mode 100644 index 000000000..43a44a216 --- /dev/null +++ b/boost/format/Makefile.am @@ -0,0 +1,3 @@ +noinst_LIBRARIES = libformat.a + +libformat_a_SOURCES = format_implementation.cc free_funcs.cc parsing.cc diff --git a/boost/format/feed_args.hpp b/boost/format/feed_args.hpp index 2e678ca3b..ba107dce6 100644 --- a/boost/format/feed_args.hpp +++ b/boost/format/feed_args.hpp @@ -31,17 +31,16 @@ namespace io { namespace detail { namespace { - template inline - void empty_buf(BOOST_IO_STD basic_ostringstream & os) { - static const std::basic_string emptyStr; + inline + void empty_buf(BOOST_IO_STD ostringstream & os) { + static const std::string emptyStr; os.str(emptyStr); } - template - void do_pad( std::basic_string & s, + void do_pad( std::string & s, std::streamsize w, - const Ch c, - std::ios_base::fmtflags f, + const char c, + std::ios::fmtflags f, bool center) // applies centered / left / right padding to the string s. // Effects : string s is padded. @@ -59,7 +58,7 @@ namespace { } else { - if(f & std::ios_base::left) { + if(f & std::ios::left) { s.append(n, c); } else { @@ -69,32 +68,32 @@ namespace { } // -do_pad(..) - template< class Ch, class Tr, class T> inline - void put_head(BOOST_IO_STD basic_ostream& , const T& ) { + template inline + void put_head(BOOST_IO_STD ostream& , const T& ) { } - template< class Ch, class Tr, class T> inline - void put_head( BOOST_IO_STD basic_ostream& os, const group1& x ) { + template inline + void put_head( BOOST_IO_STD ostream& os, const group1& x ) { os << group_head(x.a1_); // send the first N-1 items, not the last } - template< class Ch, class Tr, class T> inline - void put_last( BOOST_IO_STD basic_ostream& os, const T& x ) { + template inline + void put_last( BOOST_IO_STD ostream& os, const T& x ) { os << x ; } - template< class Ch, class Tr, class T> inline - void put_last( BOOST_IO_STD basic_ostream& os, const group1& x ) { + template inline + void put_last( BOOST_IO_STD ostream& os, const group1& x ) { os << group_last(x.a1_); // this selects the last element } #ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST - template< class Ch, class Tr, class T> inline - void put_head( BOOST_IO_STD basic_ostream& , T& ) { + template inline + void put_head( BOOST_IO_STD ostream& , T& ) { } - template< class Ch, class Tr, class T> inline - void put_last( BOOST_IO_STD basic_ostream& os, T& x ) { + template inline + void put_last( BOOST_IO_STD ostream& os, T& x ) { os << x ; } #endif @@ -102,19 +101,19 @@ namespace { -template< class Ch, class Tr, class T> +template void put( T x, - const format_item& specs, - std::basic_string & res, - BOOST_IO_STD basic_ostringstream& oss_ ) + const format_item& specs, + std::string & res, + BOOST_IO_STD ostringstream& oss_ ) { // does the actual conversion of x, with given params, into a string // using the *supplied* strinstream. (the stream state is important) - typedef std::basic_string string_t; - typedef format_item format_item_t; + typedef std::string string_t; + typedef format_item format_item_t; - stream_format_state prev_state(oss_); + stream_format_state prev_state(oss_); specs.state_.apply_on(oss_); @@ -124,8 +123,8 @@ void put( T x, empty_buf( oss_); const std::streamsize w=oss_.width(); - const std::ios_base::fmtflags fl=oss_.flags(); - const bool internal = (fl & std::ios_base::internal) != 0; + const std::ios::fmtflags fl=oss_.flags(); + const bool internal = (fl & std::ios::internal) != 0; const bool two_stepped_padding = internal && ! ( specs.pad_scheme_ & format_item_t::spacepad ) && specs.truncate_ < 0 ; @@ -203,8 +202,8 @@ void put( T x, -template< class Ch, class Tr, class T> -void distribute(basic_format& self, T x) +template +void distribute(basic_format& self, T x) // call put(x, ..) on every occurence of the current argument : { if(self.cur_arg_ >= self.num_args_) @@ -217,16 +216,16 @@ void distribute(basic_format& self, T x) { if(self.items_[i].argN_ == self.cur_arg_) { - put (x, self.items_[i], self.items_[i].res_, self.oss_ ); + put (x, self.items_[i], self.items_[i].res_, self.oss_ ); } } } -template -basic_format& feed(basic_format& self, T x) +template +basic_format& feed(basic_format& self, T x) { if(self.dumped_) self.clear(); - distribute (self, x); + distribute (self, x); ++self.cur_arg_; if(self.bound_.size() != 0) { diff --git a/boost/format/format_class.hpp b/boost/format/format_class.hpp index 9126bfad3..6875623ac 100644 --- a/boost/format/format_class.hpp +++ b/boost/format/format_class.hpp @@ -30,26 +30,21 @@ namespace boost { -template class basic_format { public: - typedef Ch CharT; // those 2 are necessary for borland compatibilty, - typedef Tr Traits; // in the body of the operator% template. - - - typedef std::basic_string string_t; - typedef BOOST_IO_STD basic_ostringstream internal_stream_t; + typedef std::string string_t; + typedef BOOST_IO_STD ostringstream internal_stream_t; private: - typedef BOOST_IO_STD basic_ostream stream_t; - typedef io::detail::stream_format_state stream_format_state; - typedef io::detail::format_item format_item_t; + typedef BOOST_IO_STD ostream stream_t; + typedef io::detail::stream_format_state stream_format_state; + typedef io::detail::format_item format_item_t; public: - basic_format(const Ch* str); + basic_format(const char* str); basic_format(const string_t& s); #ifndef BOOST_NO_STD_LOCALE - basic_format(const Ch* str, const std::locale & loc); + basic_format(const char* str, const std::locale & loc); basic_format(const string_t& s, const std::locale & loc); #endif // no locale basic_format(const basic_format& x); @@ -60,13 +55,13 @@ public: // pass arguments through those operators : template basic_format& operator%(const T& x) { - return io::detail::feed(*this,x); + return io::detail::feed(*this,x); } #ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST template basic_format& operator%(T& x) { - return io::detail::feed(*this,x); + return io::detail::feed(*this,x); } #endif @@ -93,21 +88,21 @@ public: // final output string_t str() const; - friend BOOST_IO_STD basic_ostream& - operator<< ( BOOST_IO_STD basic_ostream& , const basic_format& ); + friend BOOST_IO_STD ostream& + operator<< ( BOOST_IO_STD ostream& , const basic_format& ); - template friend basic_format& - io::detail::feed(basic_format&, T); + template friend basic_format& + io::detail::feed(basic_format&, T); - template friend - void io::detail::distribute(basic_format&, T); + template friend + void io::detail::distribute(basic_format&, T); - template friend - basic_format& io::detail::modify_item_body(basic_format&, int, const T&); + template friend + basic_format& io::detail::modify_item_body(basic_format&, int, const T&); - template friend - basic_format& io::detail::bind_arg_body(basic_format&, int, const T&); + template friend + basic_format& io::detail::bind_arg_body(basic_format&, int, const T&); // make the members private only if the friend templates are supported private: diff --git a/boost/format/format_fwd.hpp b/boost/format/format_fwd.hpp index bad2f7238..97c55f668 100644 --- a/boost/format/format_fwd.hpp +++ b/boost/format/format_fwd.hpp @@ -24,13 +24,9 @@ namespace boost { -template > class basic_format; +class basic_format; -typedef basic_format format; - -#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_STD_WSTREAMBUF) -typedef basic_format wformat; -#endif +typedef basic_format format; namespace io { enum format_error_bits { bad_format_string_bit = 1, @@ -39,15 +35,13 @@ enum format_error_bits { bad_format_string_bit = 1, all_error_bits = 255, no_error_bits=0 }; // Convertion: format to string -template -std::basic_string str(const basic_format& ) ; +std::string str(const basic_format& ) ; } // namespace io -template< class Ch, class Tr> -BOOST_IO_STD basic_ostream& -operator<<( BOOST_IO_STD basic_ostream&, const basic_format&); +BOOST_IO_STD ostream& +operator<<( BOOST_IO_STD ostream&, const basic_format&); } // namespace boost diff --git a/boost/format/format_implementation.cc b/boost/format/format_implementation.cc new file mode 100644 index 000000000..41cb5fc9f --- /dev/null +++ b/boost/format/format_implementation.cc @@ -0,0 +1,256 @@ +// -*- C++ -*- +// Boost general library format --------------------------- +// See http://www.boost.org for updates, documentation, and revision history. + +// (C) Samuel Krempp 2001 +// krempp@crans.ens-cachan.fr +// Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + +// ideas taken from Rüdiger Loos's format class +// and Karl Nelson's ofstream + +// ---------------------------------------------------------------------------- +// format_implementation.hpp Implementation of the basic_format class +// ---------------------------------------------------------------------------- + + +#ifndef BOOST_FORMAT_IMPLEMENTATION_HPP +#define BOOST_FORMAT_IMPLEMENTATION_HPP + +//#include +//#include +#include + +namespace boost { + +// -------- format:: ------------------------------------------- +basic_format::basic_format(const char* str) + : style_(0), cur_arg_(0), num_args_(0), dumped_(false), + items_(), oss_(), exceptions_(io::all_error_bits) +{ + state0_.set_by_stream(oss_); + string_t emptyStr; + if( !str) str = emptyStr.c_str(); + parse( str ); +} + +#ifndef BOOST_NO_STD_LOCALE +basic_format::basic_format(const char* str, const std::locale & loc) + : style_(0), cur_arg_(0), num_args_(0), dumped_(false), + items_(), oss_(), exceptions_(io::all_error_bits) +{ + oss_.imbue( loc ); + state0_.set_by_stream(oss_); + string_t emptyStr; + if( !str) str = emptyStr.c_str(); + parse( str ); +} + +basic_format::basic_format(const string_t& s, const std::locale & loc) + : style_(0), cur_arg_(0), num_args_(0), dumped_(false), + items_(), oss_(), exceptions_(io::all_error_bits) +{ + oss_.imbue( loc ); + state0_.set_by_stream(oss_); + parse(s); +} +#endif //BOOST_NO_STD_LOCALE + +basic_format::basic_format(const string_t& s) + : style_(0), cur_arg_(0), num_args_(0), dumped_(false), + items_(), oss_(), exceptions_(io::all_error_bits) +{ + state0_.set_by_stream(oss_); + parse(s); +} + +basic_format:: basic_format(const basic_format& x) + : style_(x.style_), cur_arg_(x.cur_arg_), num_args_(x.num_args_), dumped_(false), + items_(x.items_), prefix_(x.prefix_), bound_(x.bound_), + oss_(), // <- we obviously can't copy x.oss_ + state0_(x.state0_), exceptions_(x.exceptions_) +{ + state0_.apply_on(oss_); +} + +basic_format& basic_format::operator= (const basic_format& x) +{ + if(this == &x) + return *this; + state0_ = x.state0_; + state0_.apply_on(oss_); + + // plus all the other (trivial) assignments : + exceptions_ = x.exceptions_; + items_ = x.items_; + prefix_ = x.prefix_; + bound_=x.bound_; + style_=x.style_; + cur_arg_=x.cur_arg_; + num_args_=x.num_args_; + dumped_=x.dumped_; + return *this; +} + + +unsigned char basic_format::exceptions() const +{ + return exceptions_; +} + +unsigned char basic_format::exceptions(unsigned char newexcept) +{ + unsigned char swp = exceptions_; + exceptions_ = newexcept; + return swp; +} + + +basic_format& basic_format ::clear() + // empty the string buffers (except bound arguments, see clear_binds() ) + // and make the format object ready for formatting a new set of arguments +{ + BOOST_ASSERT( bound_.size()==0 || num_args_ == static_cast(bound_.size()) ); + + for(unsigned long i=0; i num_args_ || bound_.size()==0 || !bound_[argN-1] ) + { + if( exceptions() & io::out_of_range_bit ) + boost::throw_exception(io::out_of_range()); // arg not in range. + else return *this; + } + bound_[argN-1]=false; + clear(); + return *this; +} + + + +std::string basic_format::str() const +{ + dumped_=true; + if(items_.size()==0) + return prefix_; + if( cur_arg_ < num_args_) + if( exceptions() & io::too_few_args_bit ) + boost::throw_exception(io::too_few_args()); // not enough variables have been supplied ! + + unsigned long sz = prefix_.size(); + unsigned long i; + for(i=0; i < items_.size(); ++i) + sz += items_[i].res_.size() + items_[i].appendix_.size(); + string_t res; + res.reserve(sz); + + res += prefix_; + for(i=0; i < items_.size(); ++i) + { + const format_item_t& item = items_[i]; + res += item.res_; + if( item.argN_ == format_item_t::argN_tabulation) + { + BOOST_ASSERT( item.pad_scheme_ & format_item_t::tabulation); + std::streamsize n = item.state_.width_ - res.size(); + if( n > 0 ) + res.append( n, item.state_.fill_ ); + } + res += item.appendix_; + } + return res; +} + +namespace io { +namespace detail { + +template +basic_format& bind_arg_body( basic_format& self, + int argN, + const T& val) + // bind one argument to a fixed value + // this is persistent over clear() calls, thus also over str() and << +{ + if(self.dumped_) self.clear(); // needed, because we will modify cur_arg_.. + if(argN<1 || argN > self.num_args_) + { + if( self.exceptions() & io::out_of_range_bit ) + boost::throw_exception(io::out_of_range()); // arg not in range. + else return self; + } + if(self.bound_.size()==0) + self.bound_.assign(self.num_args_,false); + else + BOOST_ASSERT( self.num_args_ == static_cast(self.bound_.size()) ); + int o_cur_arg = self.cur_arg_; + self.cur_arg_ = argN-1; // arrays begin at 0 + + self.bound_[self.cur_arg_]=false; // if already set, we unset and re-sets.. + self.operator%(val); // put val at the right place, because cur_arg is set + + + // Now re-position cur_arg before leaving : + self.cur_arg_ = o_cur_arg; + self.bound_[argN-1]=true; + if(self.cur_arg_ == argN-1 ) + // hum, now this arg is bound, so move to next free arg + { + while(self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_]) ++self.cur_arg_; + } + // In any case, we either have all args, or are on a non-binded arg : + BOOST_ASSERT( self.cur_arg_ >= self.num_args_ || ! self.bound_[self.cur_arg_]); + return self; +} + +template +basic_format& modify_item_body( basic_format& self, + int itemN, + const T& manipulator) + // applies a manipulator to the format_item describing a given directive. + // this is a permanent change, clear or clear_binds won't cancel that. +{ + if(itemN<1 || itemN >= static_cast(self.items_.size() )) + { + if( self.exceptions() & io::out_of_range_bit ) + boost::throw_exception(io::out_of_range()); // item not in range. + else return self; + } + self.items_[itemN-1].ref_state_.apply_manip( manipulator ); + self.items_[itemN-1].state_ = self.items_[itemN-1].ref_state_; + return self; +} + +} // namespace detail + +} // namespace io + +} // namespace boost + + + +#endif // BOOST_FORMAT_IMPLEMENTATION_HPP diff --git a/boost/format/format_implementation.hpp b/boost/format/format_implementation.hpp deleted file mode 100644 index 58372bb13..000000000 --- a/boost/format/format_implementation.hpp +++ /dev/null @@ -1,268 +0,0 @@ -// -*- C++ -*- -// Boost general library format --------------------------- -// See http://www.boost.org for updates, documentation, and revision history. - -// (C) Samuel Krempp 2001 -// krempp@crans.ens-cachan.fr -// Permission to copy, use, modify, sell and -// distribute this software is granted provided this copyright notice appears -// in all copies. This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. - -// ideas taken from Rüdiger Loos's format class -// and Karl Nelson's ofstream - -// ---------------------------------------------------------------------------- -// format_implementation.hpp Implementation of the basic_format class -// ---------------------------------------------------------------------------- - - -#ifndef BOOST_FORMAT_IMPLEMENTATION_HPP -#define BOOST_FORMAT_IMPLEMENTATION_HPP - -//#include -//#include -#include - -namespace boost { - -// -------- format:: ------------------------------------------- -template< class Ch, class Tr> -basic_format ::basic_format(const Ch* str) - : style_(0), cur_arg_(0), num_args_(0), dumped_(false), - items_(), oss_(), exceptions_(io::all_error_bits) -{ - state0_.set_by_stream(oss_); - string_t emptyStr; - if( !str) str = emptyStr.c_str(); - parse( str ); -} - -#ifndef BOOST_NO_STD_LOCALE -template< class Ch, class Tr> -basic_format ::basic_format(const Ch* str, const std::locale & loc) - : style_(0), cur_arg_(0), num_args_(0), dumped_(false), - items_(), oss_(), exceptions_(io::all_error_bits) -{ - oss_.imbue( loc ); - state0_.set_by_stream(oss_); - string_t emptyStr; - if( !str) str = emptyStr.c_str(); - parse( str ); -} - -template< class Ch, class Tr> -basic_format ::basic_format(const string_t& s, const std::locale & loc) - : style_(0), cur_arg_(0), num_args_(0), dumped_(false), - items_(), oss_(), exceptions_(io::all_error_bits) -{ - oss_.imbue( loc ); - state0_.set_by_stream(oss_); - parse(s); -} -#endif //BOOST_NO_STD_LOCALE - -template< class Ch, class Tr> -basic_format ::basic_format(const string_t& s) - : style_(0), cur_arg_(0), num_args_(0), dumped_(false), - items_(), oss_(), exceptions_(io::all_error_bits) -{ - state0_.set_by_stream(oss_); - parse(s); -} - -template< class Ch, class Tr> -basic_format :: basic_format(const basic_format& x) - : style_(x.style_), cur_arg_(x.cur_arg_), num_args_(x.num_args_), dumped_(false), - items_(x.items_), prefix_(x.prefix_), bound_(x.bound_), - oss_(), // <- we obviously can't copy x.oss_ - state0_(x.state0_), exceptions_(x.exceptions_) -{ - state0_.apply_on(oss_); -} - -template< class Ch, class Tr> -basic_format& basic_format ::operator= (const basic_format& x) -{ - if(this == &x) - return *this; - state0_ = x.state0_; - state0_.apply_on(oss_); - - // plus all the other (trivial) assignments : - exceptions_ = x.exceptions_; - items_ = x.items_; - prefix_ = x.prefix_; - bound_=x.bound_; - style_=x.style_; - cur_arg_=x.cur_arg_; - num_args_=x.num_args_; - dumped_=x.dumped_; - return *this; -} - - -template< class Ch, class Tr> -unsigned char basic_format ::exceptions() const -{ - return exceptions_; -} - -template< class Ch, class Tr> -unsigned char basic_format ::exceptions(unsigned char newexcept) -{ - unsigned char swp = exceptions_; - exceptions_ = newexcept; - return swp; -} - - -template< class Ch, class Tr> -basic_format& basic_format ::clear() - // empty the string buffers (except bound arguments, see clear_binds() ) - // and make the format object ready for formatting a new set of arguments -{ - BOOST_ASSERT( bound_.size()==0 || num_args_ == static_cast(bound_.size()) ); - - for(unsigned long i=0; i -basic_format& basic_format ::clear_binds() - // cancel all bindings, and clear() -{ - bound_.resize(0); - clear(); - return *this; -} - -template< class Ch, class Tr> -basic_format& basic_format ::clear_bind(int argN) - // cancel the binding of ONE argument, and clear() -{ - if(argN<1 || argN > num_args_ || bound_.size()==0 || !bound_[argN-1] ) - { - if( exceptions() & io::out_of_range_bit ) - boost::throw_exception(io::out_of_range()); // arg not in range. - else return *this; - } - bound_[argN-1]=false; - clear(); - return *this; -} - - - -template< class Ch, class Tr> -std::basic_string basic_format ::str() const -{ - dumped_=true; - if(items_.size()==0) - return prefix_; - if( cur_arg_ < num_args_) - if( exceptions() & io::too_few_args_bit ) - boost::throw_exception(io::too_few_args()); // not enough variables have been supplied ! - - unsigned long sz = prefix_.size(); - unsigned long i; - for(i=0; i < items_.size(); ++i) - sz += items_[i].res_.size() + items_[i].appendix_.size(); - string_t res; - res.reserve(sz); - - res += prefix_; - for(i=0; i < items_.size(); ++i) - { - const format_item_t& item = items_[i]; - res += item.res_; - if( item.argN_ == format_item_t::argN_tabulation) - { - BOOST_ASSERT( item.pad_scheme_ & format_item_t::tabulation); - std::streamsize n = item.state_.width_ - res.size(); - if( n > 0 ) - res.append( n, item.state_.fill_ ); - } - res += item.appendix_; - } - return res; -} - -namespace io { -namespace detail { - -template -basic_format& bind_arg_body( basic_format& self, - int argN, - const T& val) - // bind one argument to a fixed value - // this is persistent over clear() calls, thus also over str() and << -{ - if(self.dumped_) self.clear(); // needed, because we will modify cur_arg_.. - if(argN<1 || argN > self.num_args_) - { - if( self.exceptions() & io::out_of_range_bit ) - boost::throw_exception(io::out_of_range()); // arg not in range. - else return self; - } - if(self.bound_.size()==0) - self.bound_.assign(self.num_args_,false); - else - BOOST_ASSERT( self.num_args_ == static_cast(self.bound_.size()) ); - int o_cur_arg = self.cur_arg_; - self.cur_arg_ = argN-1; // arrays begin at 0 - - self.bound_[self.cur_arg_]=false; // if already set, we unset and re-sets.. - self.operator%(val); // put val at the right place, because cur_arg is set - - - // Now re-position cur_arg before leaving : - self.cur_arg_ = o_cur_arg; - self.bound_[argN-1]=true; - if(self.cur_arg_ == argN-1 ) - // hum, now this arg is bound, so move to next free arg - { - while(self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_]) ++self.cur_arg_; - } - // In any case, we either have all args, or are on a non-binded arg : - BOOST_ASSERT( self.cur_arg_ >= self.num_args_ || ! self.bound_[self.cur_arg_]); - return self; -} - -template -basic_format& modify_item_body( basic_format& self, - int itemN, - const T& manipulator) - // applies a manipulator to the format_item describing a given directive. - // this is a permanent change, clear or clear_binds won't cancel that. -{ - if(itemN<1 || itemN >= static_cast(self.items_.size() )) - { - if( self.exceptions() & io::out_of_range_bit ) - boost::throw_exception(io::out_of_range()); // item not in range. - else return self; - } - self.items_[itemN-1].ref_state_.apply_manip( manipulator ); - self.items_[itemN-1].state_ = self.items_[itemN-1].ref_state_; - return self; -} - -} // namespace detail - -} // namespace io - -} // namespace boost - - - -#endif // BOOST_FORMAT_IMPLEMENTATION_HPP diff --git a/boost/format/free_funcs.cc b/boost/format/free_funcs.cc new file mode 100644 index 000000000..b2ac01774 --- /dev/null +++ b/boost/format/free_funcs.cc @@ -0,0 +1,71 @@ +// -*- C++ -*- +// Boost general library 'format' --------------------------- +// See http://www.boost.org for updates, documentation, and revision history. + +// (C) Samuel Krempp 2001 +// krempp@crans.ens-cachan.fr +// Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + +// ideas taken from Rüdiger Loos's format class +// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing) + +// ------------------------------------------------------------------------------ +// free_funcs.hpp : implementation of the free functions declared in namespace format +// ------------------------------------------------------------------------------ + +#ifndef BOOST_FORMAT_FUNCS_HPP +#define BOOST_FORMAT_FUNCS_HPP + +#include "boost/format.hpp" +//#include "boost/throw_exception.hpp" + +namespace boost { + +namespace io { + inline + std::string str(const basic_format& f) + // adds up all pieces of strings and converted items, and return the formatted string + { + return f.str(); + } +} // - namespace io + +BOOST_IO_STD ostream& +operator<<( BOOST_IO_STD ostream& os, + const boost::basic_format& f) + // effect: "return os << str(f);" but we can try to do it faster +{ + typedef boost::basic_format format_t; + if(f.items_.size()==0) + os << f.prefix_; + else { + if(f.cur_arg_ < f.num_args_) + if( f.exceptions() & io::too_few_args_bit ) + boost::throw_exception(io::too_few_args()); // not enough variables have been supplied ! + if(f.style_ & format_t::special_needs) + os << f.str(); + else { + // else we dont have to count chars output, so we dump directly to os : + os << f.prefix_; + for(unsigned long i=0; i inline - std::basic_string str(const basic_format& f) - // adds up all pieces of strings and converted items, and return the formatted string - { - return f.str(); - } -} // - namespace io - -template< class Ch, class Tr> -BOOST_IO_STD basic_ostream& -operator<<( BOOST_IO_STD basic_ostream& os, - const boost::basic_format& f) - // effect: "return os << str(f);" but we can try to do it faster -{ - typedef boost::basic_format format_t; - if(f.items_.size()==0) - os << f.prefix_; - else { - if(f.cur_arg_ < f.num_args_) - if( f.exceptions() & io::too_few_args_bit ) - boost::throw_exception(io::too_few_args()); // not enough variables have been supplied ! - if(f.style_ & format_t::special_needs) - os << f.str(); - else { - // else we dont have to count chars output, so we dump directly to os : - os << f.prefix_; - for(unsigned long i=0; i inline -BOOST_IO_STD basic_ostream& -operator << ( BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << ( BOOST_IO_STD ostream& os, const group0& ) { return os; @@ -63,8 +63,8 @@ struct group1 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group1& x) { os << x.a1_; @@ -86,8 +86,8 @@ struct group2 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group2& x) { os << x.a1_<< x.a2_; @@ -107,8 +107,8 @@ struct group3 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group3& x) { os << x.a1_<< x.a2_<< x.a3_; @@ -129,8 +129,8 @@ struct group4 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group4& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_; @@ -152,8 +152,8 @@ struct group5 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group5& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_; @@ -176,8 +176,8 @@ struct group6 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group6& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_; @@ -201,8 +201,8 @@ struct group7 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group7& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_; @@ -227,8 +227,8 @@ struct group8 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group8& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_<< x.a8_; @@ -254,8 +254,8 @@ struct group9 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group9& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_<< x.a8_<< x.a9_; @@ -282,8 +282,8 @@ struct group10 template inline -BOOST_IO_STD basic_ostream& -operator << (BOOST_IO_STD basic_ostream& os, +BOOST_IO_STD ostream& +operator << (BOOST_IO_STD ostream& os, const group10& x) { os << x.a1_<< x.a2_<< x.a3_<< x.a4_<< x.a5_<< x.a6_<< x.a7_<< x.a8_<< x.a9_<< x.a10_; diff --git a/boost/format/internals.hpp b/boost/format/internals.hpp index 52448b731..d25eb4c86 100644 --- a/boost/format/internals.hpp +++ b/boost/format/internals.hpp @@ -33,22 +33,21 @@ namespace detail { // -------------- // set of params that define the format state of a stream -template struct stream_format_state { - typedef BOOST_IO_STD basic_ios basic_ios; + typedef std::ios basic_ios; std::streamsize width_; std::streamsize precision_; - Ch fill_; - std::ios_base::fmtflags flags_; + char fill_; + std::ios::fmtflags flags_; - stream_format_state() : width_(-1), precision_(-1), fill_(0), flags_(std::ios_base::dec) {} + stream_format_state() : width_(-1), precision_(-1), fill_(0), flags_(std::ios::dec) {} stream_format_state(basic_ios& os) {set_by_stream(os); } void apply_on(basic_ios & os) const; //- applies format_state to the stream template void apply_manip(T manipulator) //- modifies state by applying manipulator. - { apply_manip_body( *this, manipulator) ; } + { apply_manip_body( *this, manipulator) ; } void reset(); //- sets to default state. void set_by_stream(const basic_ios& os); //- sets to os's state. }; @@ -58,7 +57,6 @@ struct stream_format_state // -------------- // format_item : stores all parameters that can be defined by directives in the format-string -template struct format_item { enum pad_values { zeropad = 1, spacepad =2, centered=4, tabulation = 8 }; @@ -67,10 +65,10 @@ struct format_item argN_tabulation = -2, // tabulation directive. (no argument read) argN_ignored = -3 // ignored directive. (no argument read) }; - typedef BOOST_IO_STD basic_ios basic_ios; - typedef detail::stream_format_state stream_format_state; - typedef std::basic_string string_t; - typedef BOOST_IO_STD basic_ostringstream internal_stream_t; + typedef BOOST_IO_STD ios basic_ios; + typedef detail::stream_format_state stream_format_state; + typedef std::string string_t; + typedef BOOST_IO_STD ostringstream internal_stream_t; int argN_; //- argument number (starts at 0, eg : %1 => argN=0) @@ -98,8 +96,8 @@ struct format_item // ----------------------------------------------------------- // --- stream_format_state:: ------------------------------------------- -template inline -void stream_format_state ::apply_on(basic_ios & os) const +inline +void stream_format_state::apply_on(basic_ios & os) const // set the state of this stream according to our params { if(width_ != -1) @@ -111,8 +109,8 @@ void stream_format_state ::apply_on(basic_ios & os) const os.flags(flags_); } -template inline -void stream_format_state ::set_by_stream(const basic_ios& os) +inline +void stream_format_state::set_by_stream(const basic_ios& os) // set our params according to the state of this stream { flags_ = os.flags(); @@ -121,42 +119,42 @@ void stream_format_state ::set_by_stream(const basic_ios& os) fill_ = os.fill(); } -template inline -void apply_manip_body( stream_format_state& self, +template inline +void apply_manip_body( stream_format_state& self, T manipulator) // modify our params according to the manipulator { - BOOST_IO_STD basic_stringstream ss; + BOOST_IO_STD stringstream ss; self.apply_on( ss ); ss << manipulator; self.set_by_stream( ss ); } -template inline -void stream_format_state ::reset() +inline +void stream_format_state::reset() // set our params to standard's default state { width_=-1; precision_=-1; fill_=0; - flags_ = std::ios_base::dec; + flags_ = std::ios::dec; } // --- format_items:: ------------------------------------------- -template inline -void format_item ::compute_states() +inline +void format_item::compute_states() // reflect pad_scheme_ on state_ and ref_state_ // because some pad_schemes has complex consequences on several state params. { if(pad_scheme_ & zeropad) { - if(ref_state_.flags_ & std::ios_base::left) + if(ref_state_.flags_ & std::ios::left) { pad_scheme_ = pad_scheme_ & (~zeropad); // ignore zeropad in left alignment } else { ref_state_.fill_='0'; - ref_state_.flags_ |= std::ios_base::internal; + ref_state_.flags_ |= std::ios::internal; } } state_ = ref_state_; diff --git a/boost/format/internals_fwd.hpp b/boost/format/internals_fwd.hpp index f260e6dec..a8ebf7c3a 100644 --- a/boost/format/internals_fwd.hpp +++ b/boost/format/internals_fwd.hpp @@ -26,8 +26,8 @@ namespace boost { namespace io { namespace detail { - template struct stream_format_state; - template struct format_item; + struct stream_format_state; + struct format_item; } @@ -37,24 +37,24 @@ namespace detail { // but MSVC have problems with template member functions : // defined in format_implementation.hpp : - template - basic_format& modify_item_body( basic_format& self, + template + basic_format& modify_item_body( basic_format& self, int itemN, const T& manipulator); - template - basic_format& bind_arg_body( basic_format& self, + template + basic_format& bind_arg_body( basic_format& self, int argN, const T& val); - template - void apply_manip_body( stream_format_state& self, + template + void apply_manip_body( stream_format_state& self, T manipulator); // argument feeding (defined in feed_args.hpp ) : - template - void distribute(basic_format& self, T x); + template + void distribute(basic_format& self, T x); - template - basic_format& feed(basic_format& self, T x); + template + basic_format& feed(basic_format& self, T x); } // namespace detail diff --git a/boost/format/parsing.cc b/boost/format/parsing.cc new file mode 100644 index 000000000..1e12dea9b --- /dev/null +++ b/boost/format/parsing.cc @@ -0,0 +1,454 @@ +// -*- C++ -*- +// Boost general library 'format' --------------------------- +// See http://www.boost.org for updates, documentation, and revision history. + +// (C) Samuel Krempp 2001 +// krempp@crans.ens-cachan.fr +// Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + +// ideas taken from Rudiger Loos's format class +// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing) + +// ------------------------------------------------------------------------------ +// parsing.hpp : implementation of the parsing member functions +// ( parse, parse_printf_directive) +// ------------------------------------------------------------------------------ + + +#ifndef BOOST_FORMAT_PARSING_HPP +#define BOOST_FORMAT_PARSING_HPP + + +#include +//#include +//#include + + +namespace boost { +namespace io { +namespace detail { + + template inline + bool wrap_isdigit(char c, Stream &os) + { +#ifndef BOOST_NO_LOCALE_ISIDIGIT + return std::isdigit(c, os.rdbuf()->getloc() ); +# else + using namespace std; + return isdigit(c); +#endif + } //end- wrap_isdigit(..) + + template inline + Res str2int(const std::string& s, + std::string::size_type start, + BOOST_IO_STD ios &os, + const Res = Res(0) ) + // Input : char string, with starting index + // a basic_ios& merely to call its widen/narrow member function in the desired locale. + // Effects : reads s[start:] and converts digits into an integral n, of type Res + // Returns : n + { + Res n = 0; + while(start= buf.size() ) return; + if(buf[ *pos_p]=='*') { + ++ (*pos_p); + while (*pos_p < buf.size() && wrap_isdigit(buf[*pos_p],os)) ++(*pos_p); + if(buf[*pos_p]=='$') ++(*pos_p); + } + } + + + inline void maybe_throw_exception( unsigned char exceptions) + // auxiliary func called by parse_printf_directive + // for centralising error handling + // it either throws if user sets the corresponding flag, or does nothing. + { + if(exceptions & io::bad_format_string_bit) + boost::throw_exception(io::bad_format_string()); + } + + + + bool parse_printf_directive(const std::string & buf, + std::string::size_type * pos_p, + detail::format_item * fpar, + BOOST_IO_STD ios &os, + unsigned char exceptions) + // Input : a 'printf-directive' in the format-string, starting at buf[ *pos_p ] + // a basic_ios& merely to call its widen/narrow member function in the desired locale. + // a bitset'excpetions' telling whether to throw exceptions on errors. + // Returns : true if parse somehow succeeded (possibly ignoring errors if exceptions disabled) + // false if it failed so bad that the directive should be printed verbatim + // Effects : - *pos_p is incremented so that buf[*pos_p] is the first char after the directive + // - *fpar is set with the parameters read in the directive + { + typedef format_item format_item_t; + BOOST_ASSERT( pos_p != 0); + std::string::size_type &i1 = *pos_p, + i0; + fpar->argN_ = format_item_t::argN_no_posit; // if no positional-directive + + bool in_brackets=false; + if(buf[i1]=='|') + { + in_brackets=true; + if( ++i1 >= buf.size() ) { + maybe_throw_exception(exceptions); + return false; + } + } + + // the flag '0' would be picked as a digit for argument order, but here it's a flag : + if(buf[i1]=='0') + goto parse_flags; + + // handle argument order (%2$d) or possibly width specification: %2d + i0 = i1; // save position before digits + while (i1 < buf.size() && wrap_isdigit(buf[i1], os)) + ++i1; + if (i1!=i0) + { + if( i1 >= buf.size() ) { + maybe_throw_exception(exceptions); + return false; + } + int n=str2int(buf,i0, os, int(0) ); + + // %N% case : this is already the end of the directive + if( buf[i1] == '%' ) + { + fpar->argN_ = n-1; + ++i1; + if( in_brackets) + maybe_throw_exception(exceptions); + // but don't return. maybe "%" was used in lieu of '$', so we go on. + else return true; + } + + if ( buf[i1]=='$' ) + { + fpar->argN_ = n-1; + ++i1; + } + else + { + // non-positionnal directive + fpar->ref_state_.width_ = n; + fpar->argN_ = format_item_t::argN_no_posit; + goto parse_precision; + } + } + + parse_flags: + // handle flags + while ( i1 ref_state_.flags_ |= std::ios::left; + break; + case '=': + fpar->pad_scheme_ |= format_item_t::centered; + break; + case ' ': + fpar->pad_scheme_ |= format_item_t::spacepad; + break; + case '+': + fpar->ref_state_.flags_ |= std::ios::showpos; + break; + case '0': + fpar->pad_scheme_ |= format_item_t::zeropad; + // need to know alignment before really setting flags, + // so just add 'zeropad' flag for now, it will be processed later. + break; + case '#': + fpar->ref_state_.flags_ |= std::ios::showpoint | std::ios::showbase; + break; + default: + goto parse_width; + } + ++i1; + } // loop on flag. + if( i1>=buf.size()) { + maybe_throw_exception(exceptions); + return true; + } + + parse_width: + // handle width spec + skip_asterisk(buf, &i1, os); // skips 'asterisk fields' : *, or *N$ + i0 = i1; // save position before digits + while (i1ref_state_.width_ = str2int( buf,i0, os, std::streamsize(0) ); } + + parse_precision: + if( i1>=buf.size()) { + maybe_throw_exception(exceptions); + return true; + } + // handle precision spec + if (buf[i1]=='.') + { + ++i1; + skip_asterisk(buf, &i1, os); + i0 = i1; // save position before digits + while (i1ref_state_.precision_ = 0; + else + fpar->ref_state_.precision_ = str2int(buf,i0, os, std::streamsize(0) ); + } + + // handle formatting-type flags : + while( i1=buf.size()) { + maybe_throw_exception(exceptions); + return true; + } + + if( in_brackets && buf[i1]=='|' ) + { + ++i1; + return true; + } + switch (buf[i1]) + { + case 'X': + fpar->ref_state_.flags_ |= std::ios::uppercase; + case 'p': // pointer => set hex. + case 'x': + fpar->ref_state_.flags_ &= ~std::ios::basefield; + fpar->ref_state_.flags_ |= std::ios::hex; + break; + + case 'o': + fpar->ref_state_.flags_ &= ~std::ios::basefield; + fpar->ref_state_.flags_ |= std::ios::oct; + break; + + case 'E': + fpar->ref_state_.flags_ |= std::ios::uppercase; + case 'e': + fpar->ref_state_.flags_ &= ~std::ios::floatfield; + fpar->ref_state_.flags_ |= std::ios::scientific; + + fpar->ref_state_.flags_ &= ~std::ios::basefield; + fpar->ref_state_.flags_ |= std::ios::dec; + break; + + case 'f': + fpar->ref_state_.flags_ &= ~std::ios::floatfield; + fpar->ref_state_.flags_ |= std::ios::fixed; + case 'u': + case 'd': + case 'i': + fpar->ref_state_.flags_ &= ~std::ios::basefield; + fpar->ref_state_.flags_ |= std::ios::dec; + break; + + case 'T': + ++i1; + if( i1 >= buf.size()) + maybe_throw_exception(exceptions); + else + fpar->ref_state_.fill_ = buf[i1]; + fpar->pad_scheme_ |= format_item_t::tabulation; + fpar->argN_ = format_item_t::argN_tabulation; + break; + case 't': + fpar->ref_state_.fill_ = ' '; + fpar->pad_scheme_ |= format_item_t::tabulation; + fpar->argN_ = format_item_t::argN_tabulation; + break; + + case 'G': + fpar->ref_state_.flags_ |= std::ios::uppercase; + break; + case 'g': // 'g' conversion is default for floats. + fpar->ref_state_.flags_ &= ~std::ios::basefield; + fpar->ref_state_.flags_ |= std::ios::dec; + + // CLEAR all floatield flags, so stream will CHOOSE + fpar->ref_state_.flags_ &= ~std::ios::floatfield; + break; + + case 'C': + case 'c': + fpar->truncate_ = 1; + break; + case 'S': + case 's': + fpar->truncate_ = fpar->ref_state_.precision_; + fpar->ref_state_.precision_ = -1; + break; + case 'n' : + fpar->argN_ = format_item_t::argN_ignored; + break; + default: + maybe_throw_exception(exceptions); + } + ++i1; + + if( in_brackets ) + { + if( i1= buf.size() ) { + if(exceptions() & io::bad_format_string_bit) + boost::throw_exception(io::bad_format_string()); // must not end in "bla bla %" + else break; // stop there, ignore last '%' + } + if(buf[i1+1] == buf[i1] ) { i1+=2; continue; } // escaped "%%" / "##" + ++i1; + + // in case of %N% directives, dont count it double (wastes allocations..) : + while(i1 < buf.size() && io::detail::wrap_isdigit(buf[i1],oss_)) ++i1; + if( i1 < buf.size() && buf[i1] == arg_mark ) ++ i1; + + ++num_items; + } + items_.assign( num_items, format_item_t() ); + + // B: Now the real parsing of the format string : + num_items=0; + i1 = 0; + string_t::size_type i0 = i1; + bool special_things=false; + int cur_it=0; + while( (i1=buf.find(arg_mark,i1)) != string::npos ) + { + string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_; + + if( buf[i1+1] == buf[i1] ) // escaped mark, '%%' + { + piece += buf.substr(i0, i1-i0) + buf[i1]; + i1+=2; i0=i1; + continue; + } + BOOST_ASSERT( static_cast(cur_it) < items_.size() || cur_it==0); + + if(i1!=i0) piece += buf.substr(i0, i1-i0); + ++i1; + + bool parse_ok; + parse_ok = io::detail::parse_printf_directive(buf, &i1, &items_[cur_it], oss_, exceptions()); + if( ! parse_ok ) continue; // the directive will be printed verbatim + + i0=i1; + items_[cur_it].compute_states(); // process complex options, like zeropad, into stream params. + + int argN=items_[cur_it].argN_; + if(argN == format_item_t::argN_ignored) + continue; + if(argN ==format_item_t::argN_no_posit) + ordered_args=false; + else if(argN == format_item_t::argN_tabulation) special_things=true; + else if(argN > max_argN) max_argN = argN; + ++num_items; + ++cur_it; + } // loop on %'s + BOOST_ASSERT(cur_it == num_items); + + // store the final piece of string + string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_; + piece += buf.substr(i0); + + if( !ordered_args) + { + if(max_argN >= 0 ) // dont mix positional with non-positionnal directives + { + if(exceptions() & io::bad_format_string_bit) + boost::throw_exception(io::bad_format_string()); + // else do nothing. => positionnal arguments are processed as non-positionnal + } + // set things like it would have been with positional directives : + int non_ordered_items = 0; + for(int i=0; i< num_items; ++i) + if(items_[i].argN_ == format_item_t::argN_no_posit) + { + items_[i].argN_ = non_ordered_items; + ++non_ordered_items; + } + max_argN = non_ordered_items-1; + } + + // C: set some member data : + items_.resize(num_items); + + if(special_things) style_ |= special_needs; + num_args_ = max_argN + 1; + if(ordered_args) style_ |= ordered; + else style_ &= ~ordered; +} + +} // namespace boost + + +#endif // BOOST_FORMAT_PARSING_HPP diff --git a/boost/format/parsing.hpp b/boost/format/parsing.hpp deleted file mode 100644 index a461314f9..000000000 --- a/boost/format/parsing.hpp +++ /dev/null @@ -1,457 +0,0 @@ -// -*- C++ -*- -// Boost general library 'format' --------------------------- -// See http://www.boost.org for updates, documentation, and revision history. - -// (C) Samuel Krempp 2001 -// krempp@crans.ens-cachan.fr -// Permission to copy, use, modify, sell and -// distribute this software is granted provided this copyright notice appears -// in all copies. This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. - -// ideas taken from Rudiger Loos's format class -// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing) - -// ------------------------------------------------------------------------------ -// parsing.hpp : implementation of the parsing member functions -// ( parse, parse_printf_directive) -// ------------------------------------------------------------------------------ - - -#ifndef BOOST_FORMAT_PARSING_HPP -#define BOOST_FORMAT_PARSING_HPP - - -#include -//#include -//#include - - -namespace boost { -namespace io { -namespace detail { - - template inline - bool wrap_isdigit(Ch c, Stream &os) - { -#ifndef BOOST_NO_LOCALE_ISIDIGIT - return std::isdigit(c, os.rdbuf()->getloc() ); -# else - using namespace std; - return isdigit(c); -#endif - } //end- wrap_isdigit(..) - - template inline - Res str2int(const std::basic_string& s, - typename std::basic_string::size_type start, - BOOST_IO_STD basic_ios &os, - const Res = Res(0) ) - // Input : char string, with starting index - // a basic_ios& merely to call its widen/narrow member function in the desired locale. - // Effects : reads s[start:] and converts digits into an integral n, of type Res - // Returns : n - { - Res n = 0; - while(start - void skip_asterisk(const std::basic_string & buf, - typename std::basic_string::size_type * pos_p, - BOOST_IO_STD basic_ios &os) - // skip printf's "asterisk-fields" directives in the format-string buf - // Input : char string, with starting index *pos_p - // a basic_ios& merely to call its widen/narrow member function in the desired locale. - // Effects : advance *pos_p by skipping printf's asterisk fields. - // Returns : nothing - { - using namespace std; - BOOST_ASSERT( pos_p != 0); - if(*pos_p >= buf.size() ) return; - if(buf[ *pos_p]==os.widen('*')) { - ++ (*pos_p); - while (*pos_p < buf.size() && wrap_isdigit(buf[*pos_p],os)) ++(*pos_p); - if(buf[*pos_p]==os.widen('$')) ++(*pos_p); - } - } - - - inline void maybe_throw_exception( unsigned char exceptions) - // auxiliary func called by parse_printf_directive - // for centralising error handling - // it either throws if user sets the corresponding flag, or does nothing. - { - if(exceptions & io::bad_format_string_bit) - boost::throw_exception(io::bad_format_string()); - } - - - - template - bool parse_printf_directive(const std::basic_string & buf, - typename std::basic_string::size_type * pos_p, - detail::format_item * fpar, - BOOST_IO_STD basic_ios &os, - unsigned char exceptions) - // Input : a 'printf-directive' in the format-string, starting at buf[ *pos_p ] - // a basic_ios& merely to call its widen/narrow member function in the desired locale. - // a bitset'excpetions' telling whether to throw exceptions on errors. - // Returns : true if parse somehow succeeded (possibly ignoring errors if exceptions disabled) - // false if it failed so bad that the directive should be printed verbatim - // Effects : - *pos_p is incremented so that buf[*pos_p] is the first char after the directive - // - *fpar is set with the parameters read in the directive - { - typedef format_item format_item_t; - BOOST_ASSERT( pos_p != 0); - typename std::basic_string::size_type &i1 = *pos_p, - i0; - fpar->argN_ = format_item_t::argN_no_posit; // if no positional-directive - - bool in_brackets=false; - if(buf[i1]==os.widen('|')) - { - in_brackets=true; - if( ++i1 >= buf.size() ) { - maybe_throw_exception(exceptions); - return false; - } - } - - // the flag '0' would be picked as a digit for argument order, but here it's a flag : - if(buf[i1]==os.widen('0')) - goto parse_flags; - - // handle argument order (%2$d) or possibly width specification: %2d - i0 = i1; // save position before digits - while (i1 < buf.size() && wrap_isdigit(buf[i1], os)) - ++i1; - if (i1!=i0) - { - if( i1 >= buf.size() ) { - maybe_throw_exception(exceptions); - return false; - } - int n=str2int(buf,i0, os, int(0) ); - - // %N% case : this is already the end of the directive - if( buf[i1] == os.widen('%') ) - { - fpar->argN_ = n-1; - ++i1; - if( in_brackets) - maybe_throw_exception(exceptions); - // but don't return. maybe "%" was used in lieu of '$', so we go on. - else return true; - } - - if ( buf[i1]==os.widen('$') ) - { - fpar->argN_ = n-1; - ++i1; - } - else - { - // non-positionnal directive - fpar->ref_state_.width_ = n; - fpar->argN_ = format_item_t::argN_no_posit; - goto parse_precision; - } - } - - parse_flags: - // handle flags - while ( i1 ref_state_.flags_ |= std::ios_base::left; - break; - case '=': - fpar->pad_scheme_ |= format_item_t::centered; - break; - case ' ': - fpar->pad_scheme_ |= format_item_t::spacepad; - break; - case '+': - fpar->ref_state_.flags_ |= std::ios_base::showpos; - break; - case '0': - fpar->pad_scheme_ |= format_item_t::zeropad; - // need to know alignment before really setting flags, - // so just add 'zeropad' flag for now, it will be processed later. - break; - case '#': - fpar->ref_state_.flags_ |= std::ios_base::showpoint | std::ios_base::showbase; - break; - default: - goto parse_width; - } - ++i1; - } // loop on flag. - if( i1>=buf.size()) { - maybe_throw_exception(exceptions); - return true; - } - - parse_width: - // handle width spec - skip_asterisk(buf, &i1, os); // skips 'asterisk fields' : *, or *N$ - i0 = i1; // save position before digits - while (i1ref_state_.width_ = str2int( buf,i0, os, std::streamsize(0) ); } - - parse_precision: - if( i1>=buf.size()) { - maybe_throw_exception(exceptions); - return true; - } - // handle precision spec - if (buf[i1]==os.widen('.')) - { - ++i1; - skip_asterisk(buf, &i1, os); - i0 = i1; // save position before digits - while (i1ref_state_.precision_ = 0; - else - fpar->ref_state_.precision_ = str2int(buf,i0, os, std::streamsize(0) ); - } - - // handle formatting-type flags : - while( i1=buf.size()) { - maybe_throw_exception(exceptions); - return true; - } - - if( in_brackets && buf[i1]==os.widen('|') ) - { - ++i1; - return true; - } - switch (os.narrow(buf[i1], 0) ) - { - case 'X': - fpar->ref_state_.flags_ |= std::ios_base::uppercase; - case 'p': // pointer => set hex. - case 'x': - fpar->ref_state_.flags_ &= ~std::ios_base::basefield; - fpar->ref_state_.flags_ |= std::ios_base::hex; - break; - - case 'o': - fpar->ref_state_.flags_ &= ~std::ios_base::basefield; - fpar->ref_state_.flags_ |= std::ios_base::oct; - break; - - case 'E': - fpar->ref_state_.flags_ |= std::ios_base::uppercase; - case 'e': - fpar->ref_state_.flags_ &= ~std::ios_base::floatfield; - fpar->ref_state_.flags_ |= std::ios_base::scientific; - - fpar->ref_state_.flags_ &= ~std::ios_base::basefield; - fpar->ref_state_.flags_ |= std::ios_base::dec; - break; - - case 'f': - fpar->ref_state_.flags_ &= ~std::ios_base::floatfield; - fpar->ref_state_.flags_ |= std::ios_base::fixed; - case 'u': - case 'd': - case 'i': - fpar->ref_state_.flags_ &= ~std::ios_base::basefield; - fpar->ref_state_.flags_ |= std::ios_base::dec; - break; - - case 'T': - ++i1; - if( i1 >= buf.size()) - maybe_throw_exception(exceptions); - else - fpar->ref_state_.fill_ = buf[i1]; - fpar->pad_scheme_ |= format_item_t::tabulation; - fpar->argN_ = format_item_t::argN_tabulation; - break; - case 't': - fpar->ref_state_.fill_ = os.widen(' '); - fpar->pad_scheme_ |= format_item_t::tabulation; - fpar->argN_ = format_item_t::argN_tabulation; - break; - - case 'G': - fpar->ref_state_.flags_ |= std::ios_base::uppercase; - break; - case 'g': // 'g' conversion is default for floats. - fpar->ref_state_.flags_ &= ~std::ios_base::basefield; - fpar->ref_state_.flags_ |= std::ios_base::dec; - - // CLEAR all floatield flags, so stream will CHOOSE - fpar->ref_state_.flags_ &= ~std::ios_base::floatfield; - break; - - case 'C': - case 'c': - fpar->truncate_ = 1; - break; - case 'S': - case 's': - fpar->truncate_ = fpar->ref_state_.precision_; - fpar->ref_state_.precision_ = -1; - break; - case 'n' : - fpar->argN_ = format_item_t::argN_ignored; - break; - default: - maybe_throw_exception(exceptions); - } - ++i1; - - if( in_brackets ) - { - if( i1 -void basic_format ::parse(const string_t & buf) - // parse the format-string -{ - using namespace std; - const Ch arg_mark = oss_.widen('%'); - bool ordered_args=true; - int max_argN=-1; - typename string_t::size_type i1=0; - int num_items=0; - - // A: find upper_bound on num_items and allocates arrays - i1=0; - while( (i1=buf.find(arg_mark,i1)) != string::npos ) - { - if( i1+1 >= buf.size() ) { - if(exceptions() & io::bad_format_string_bit) - boost::throw_exception(io::bad_format_string()); // must not end in "bla bla %" - else break; // stop there, ignore last '%' - } - if(buf[i1+1] == buf[i1] ) { i1+=2; continue; } // escaped "%%" / "##" - ++i1; - - // in case of %N% directives, dont count it double (wastes allocations..) : - while(i1 < buf.size() && io::detail::wrap_isdigit(buf[i1],oss_)) ++i1; - if( i1 < buf.size() && buf[i1] == arg_mark ) ++ i1; - - ++num_items; - } - items_.assign( num_items, format_item_t() ); - - // B: Now the real parsing of the format string : - num_items=0; - i1 = 0; - typename string_t::size_type i0 = i1; - bool special_things=false; - int cur_it=0; - while( (i1=buf.find(arg_mark,i1)) != string::npos ) - { - string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_; - - if( buf[i1+1] == buf[i1] ) // escaped mark, '%%' - { - piece += buf.substr(i0, i1-i0) + buf[i1]; - i1+=2; i0=i1; - continue; - } - BOOST_ASSERT( static_cast(cur_it) < items_.size() || cur_it==0); - - if(i1!=i0) piece += buf.substr(i0, i1-i0); - ++i1; - - bool parse_ok; - parse_ok = io::detail::parse_printf_directive(buf, &i1, &items_[cur_it], oss_, exceptions()); - if( ! parse_ok ) continue; // the directive will be printed verbatim - - i0=i1; - items_[cur_it].compute_states(); // process complex options, like zeropad, into stream params. - - int argN=items_[cur_it].argN_; - if(argN == format_item_t::argN_ignored) - continue; - if(argN ==format_item_t::argN_no_posit) - ordered_args=false; - else if(argN == format_item_t::argN_tabulation) special_things=true; - else if(argN > max_argN) max_argN = argN; - ++num_items; - ++cur_it; - } // loop on %'s - BOOST_ASSERT(cur_it == num_items); - - // store the final piece of string - string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_; - piece += buf.substr(i0); - - if( !ordered_args) - { - if(max_argN >= 0 ) // dont mix positional with non-positionnal directives - { - if(exceptions() & io::bad_format_string_bit) - boost::throw_exception(io::bad_format_string()); - // else do nothing. => positionnal arguments are processed as non-positionnal - } - // set things like it would have been with positional directives : - int non_ordered_items = 0; - for(int i=0; i< num_items; ++i) - if(items_[i].argN_ == format_item_t::argN_no_posit) - { - items_[i].argN_ = non_ordered_items; - ++non_ordered_items; - } - max_argN = non_ordered_items-1; - } - - // C: set some member data : - items_.resize(num_items); - - if(special_things) style_ |= special_needs; - num_args_ = max_argN + 1; - if(ordered_args) style_ |= ordered; - else style_ &= ~ordered; -} - -} // namespace boost - - -#endif // BOOST_FORMAT_PARSING_HPP -- cgit v1.2.3