247 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// -*- 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
 | 
						|
 | 
						|
// ----------------------------------------------------------------------------
 | 
						|
// feed_args.hpp :  functions for processing each argument 
 | 
						|
//                      (feed, feed_manip, and distribute)
 | 
						|
// ----------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
#ifndef BOOST_FORMAT_FEED_ARGS_HPP
 | 
						|
#define BOOST_FORMAT_FEED_ARGS_HPP
 | 
						|
 | 
						|
#include "boost/format/format_class.hpp"
 | 
						|
#include "boost/format/group.hpp"
 | 
						|
 | 
						|
#include "boost/throw_exception.hpp"
 | 
						|
 | 
						|
namespace boost {
 | 
						|
namespace io {
 | 
						|
namespace detail {
 | 
						|
namespace  { 
 | 
						|
 | 
						|
  inline
 | 
						|
  void empty_buf(BOOST_IO_STD ostringstream & os) { 
 | 
						|
    static const std::string emptyStr;
 | 
						|
    os.str(emptyStr); 
 | 
						|
  }
 | 
						|
 | 
						|
  void do_pad( std::string & s, 
 | 
						|
                std::streamsize w, 
 | 
						|
                const char c, 
 | 
						|
                std::ios::fmtflags f, 
 | 
						|
                bool center) 
 | 
						|
    // applies centered / left / right  padding  to the string s.
 | 
						|
    // Effects : string s is padded.
 | 
						|
  {
 | 
						|
    std::streamsize n=w-s.size();
 | 
						|
    if(n<=0) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if(center) 
 | 
						|
      {
 | 
						|
        s.reserve(w); // allocate once for the 2 inserts
 | 
						|
        const std::streamsize n1 = n /2, n0 = n - n1; 
 | 
						|
        s.insert(s.begin(), n0, c);
 | 
						|
        s.append(n1, c);
 | 
						|
      } 
 | 
						|
    else 
 | 
						|
      {
 | 
						|
        if(f & std::ios::left) {
 | 
						|
          s.append(n, c);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          s.insert(s.begin(), n, c);
 | 
						|
        }
 | 
						|
      }
 | 
						|
  } // -do_pad(..) 
 | 
						|
 | 
						|
 | 
						|
  template<class T> inline
 | 
						|
  void put_head(BOOST_IO_STD ostream& , const T& ) {
 | 
						|
  }
 | 
						|
 | 
						|
  template<class T> inline
 | 
						|
  void put_head( BOOST_IO_STD ostream& os, const group1<T>& x ) {
 | 
						|
    os << group_head(x.a1_); // send the first N-1 items, not the last
 | 
						|
  }
 | 
						|
 | 
						|
  template<class T> inline
 | 
						|
  void put_last( BOOST_IO_STD ostream& os, const T& x ) {
 | 
						|
    os << x ;
 | 
						|
  }
 | 
						|
 | 
						|
  template<class T> inline
 | 
						|
  void put_last( BOOST_IO_STD ostream& os, const group1<T>& x ) {
 | 
						|
    os << group_last(x.a1_); // this selects the last element
 | 
						|
  }
 | 
						|
 | 
						|
#ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST 
 | 
						|
  template<class T> inline
 | 
						|
  void put_head( BOOST_IO_STD ostream& , T& ) {
 | 
						|
  }
 | 
						|
 | 
						|
  template<class T> inline
 | 
						|
  void put_last( BOOST_IO_STD ostream& os, T& x ) {
 | 
						|
    os << x ;
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
 | 
						|
  
 | 
						|
template<class T> 
 | 
						|
void put( T x, 
 | 
						|
          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::string string_t;
 | 
						|
  typedef format_item  format_item_t;
 | 
						|
 | 
						|
  stream_format_state   prev_state(oss_);
 | 
						|
    
 | 
						|
  specs.state_.apply_on(oss_);
 | 
						|
 | 
						|
  // in case x is a group, apply the manip part of it, 
 | 
						|
  // in order to find width
 | 
						|
  put_head( oss_, x );
 | 
						|
  empty_buf( oss_);
 | 
						|
 | 
						|
  const std::streamsize w=oss_.width();
 | 
						|
  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 ;
 | 
						|
      
 | 
						|
 | 
						|
  if(! two_stepped_padding) 
 | 
						|
    {
 | 
						|
      if(w>0) // handle simple padding via do_pad, not natively in stream 
 | 
						|
        oss_.width(0);
 | 
						|
      put_last( oss_, x);
 | 
						|
      res = oss_.str();
 | 
						|
 | 
						|
      if (specs.truncate_ >= 0)
 | 
						|
        res.erase(specs.truncate_);
 | 
						|
 | 
						|
      // complex pads :
 | 
						|
      if(specs.pad_scheme_ & format_item_t::spacepad)
 | 
						|
        {
 | 
						|
          if( res.size()==0 ||   ( res[0]!='+' && res[0]!='-'  ))
 | 
						|
            {
 | 
						|
              res.insert(res.begin(), 1, ' '); // insert 1 space at  pos 0
 | 
						|
            }
 | 
						|
        }
 | 
						|
      if(w > 0) // need do_pad
 | 
						|
        {
 | 
						|
          do_pad(res,w,oss_.fill(), fl, (specs.pad_scheme_ & format_item_t::centered) !=0 );
 | 
						|
        }
 | 
						|
    } 
 | 
						|
  else  // 2-stepped padding
 | 
						|
    {
 | 
						|
      put_last( oss_, x); // oss_.width() may result in padding.
 | 
						|
      res = oss_.str();
 | 
						|
      
 | 
						|
      if (specs.truncate_ >= 0)
 | 
						|
        res.erase(specs.truncate_);
 | 
						|
 | 
						|
      if( res.size() - w > 0)
 | 
						|
        { //   length w exceeded
 | 
						|
          // either it was multi-output with first output padding up all width..
 | 
						|
          // either it was one big arg and we are fine.
 | 
						|
          empty_buf( oss_);
 | 
						|
          oss_.width(0);
 | 
						|
          put_last(oss_, x );
 | 
						|
          string_t tmp = oss_.str();  // minimal-length output
 | 
						|
          std::streamsize d;
 | 
						|
          if( (d=w - tmp.size()) <=0 ) 
 | 
						|
            {
 | 
						|
              // minimal length is already >= w, so no padding  (cool!)
 | 
						|
              res.swap(tmp);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            { // hum..  we need to pad (it was necessarily multi-output)
 | 
						|
              typedef typename string_t::size_type size_type;
 | 
						|
              size_type i = 0;
 | 
						|
              while( i<tmp.size() && tmp[i] == res[i] ) // find where we should pad.
 | 
						|
                ++i;
 | 
						|
              tmp.insert(i, static_cast<size_type>( d ), oss_.fill());
 | 
						|
              res.swap( tmp );
 | 
						|
            }
 | 
						|
        }
 | 
						|
      else 
 | 
						|
        { // okay, only one thing was printed and padded, so res is fine.
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  prev_state.apply_on(oss_);
 | 
						|
  empty_buf( oss_);
 | 
						|
  oss_.clear();
 | 
						|
} // end- put(..)
 | 
						|
 | 
						|
 | 
						|
}  // local namespace
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
template<class T> 
 | 
						|
void distribute(basic_format& self, T x) 
 | 
						|
  // call put(x, ..) on every occurence of the current argument :
 | 
						|
{
 | 
						|
  if(self.cur_arg_ >= self.num_args_)
 | 
						|
    {
 | 
						|
      if( self.exceptions() & too_many_args_bit )
 | 
						|
        boost::throw_exception(too_many_args()); // too many variables have been supplied !
 | 
						|
      else return;
 | 
						|
    }
 | 
						|
  for(unsigned long i=0; i < self.items_.size(); ++i)
 | 
						|
    {
 | 
						|
      if(self.items_[i].argN_ == self.cur_arg_)
 | 
						|
        {
 | 
						|
          put<T> (x, self.items_[i], self.items_[i].res_, self.oss_ );
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
template<class T> 
 | 
						|
basic_format&  feed(basic_format& self, T x) 
 | 
						|
{
 | 
						|
  if(self.dumped_) self.clear();
 | 
						|
  distribute<T> (self, x);
 | 
						|
  ++self.cur_arg_;
 | 
						|
  if(self.bound_.size() != 0)
 | 
						|
    {
 | 
						|
      while( self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_] )
 | 
						|
        ++self.cur_arg_;
 | 
						|
    }
 | 
						|
 | 
						|
  // this arg is finished, reset the stream's format state
 | 
						|
  self.state0_.apply_on(self.oss_);
 | 
						|
  return self;
 | 
						|
}
 | 
						|
    
 | 
						|
 | 
						|
} // namespace detail
 | 
						|
} // namespace io
 | 
						|
} // namespace boost
 | 
						|
 | 
						|
 | 
						|
#endif //  BOOST_FORMAT_FEED_ARGS_HPP
 |