1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/ossrv_pub/boost_apis/boost/format/parsing.hpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,491 @@
1.4 +// ----------------------------------------------------------------------------
1.5 +// parsing.hpp : implementation of the parsing member functions
1.6 +// ( parse, parse_printf_directive)
1.7 +// ----------------------------------------------------------------------------
1.8 +
1.9 +// Copyright Samuel Krempp 2003. Use, modification, and distribution are
1.10 +// subject to the Boost Software License, Version 1.0. (See accompanying
1.11 +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
1.12 +
1.13 +// see http://www.boost.org/libs/format for library home page
1.14 +
1.15 +// ----------------------------------------------------------------------------
1.16 +
1.17 +#ifndef BOOST_FORMAT_PARSING_HPP
1.18 +#define BOOST_FORMAT_PARSING_HPP
1.19 +
1.20 +
1.21 +#include <boost/format/format_class.hpp>
1.22 +#include <boost/throw_exception.hpp>
1.23 +#include <boost/assert.hpp>
1.24 +
1.25 +
1.26 +namespace boost {
1.27 +namespace io {
1.28 +namespace detail {
1.29 +
1.30 +#if defined(BOOST_NO_STD_LOCALE)
1.31 + // streams will be used for narrow / widen. but these methods are not const
1.32 + template<class T>
1.33 + T& const_or_not(const T& x) {
1.34 + return const_cast<T&> (x);
1.35 + }
1.36 +#else
1.37 + template<class T>
1.38 + const T& const_or_not(const T& x) {
1.39 + return x;
1.40 + }
1.41 +#endif
1.42 +
1.43 + template<class Ch, class Facet> inline
1.44 + char wrap_narrow(const Facet& fac, Ch c, char deflt) {
1.45 + return const_or_not(fac).narrow(c, deflt);
1.46 + }
1.47 +
1.48 + template<class Ch, class Facet> inline
1.49 + bool wrap_isdigit(const Facet& fac, Ch c) {
1.50 +#if ! defined( BOOST_NO_LOCALE_ISDIGIT )
1.51 + return fac.is(std::ctype<Ch>::digit, c);
1.52 +# else
1.53 + using namespace std;
1.54 + return isdigit(c);
1.55 +#endif
1.56 + }
1.57 +
1.58 + template<class Iter, class Facet>
1.59 + Iter wrap_scan_notdigit(const Facet & fac, Iter beg, Iter end) {
1.60 + using namespace std;
1.61 + for( ; beg!=end && wrap_isdigit(fac, *beg); ++beg) ;
1.62 + return beg;
1.63 + }
1.64 +
1.65 +
1.66 + // Input : [start, last) iterators range and a
1.67 + // a Facet to use its widen/narrow member function
1.68 + // Effects : read sequence and convert digits into integral n, of type Res
1.69 + // Returns : n
1.70 + template<class Res, class Iter, class Facet>
1.71 + Iter str2int (const Iter & start, const Iter & last, Res & res,
1.72 + const Facet& fac)
1.73 + {
1.74 + using namespace std;
1.75 + Iter it;
1.76 + res=0;
1.77 + for(it=start; it != last && wrap_isdigit(fac, *it); ++it ) {
1.78 + char cur_ch = wrap_narrow(fac, *it, 0); // cant fail.
1.79 + res *= 10;
1.80 + res += cur_ch - '0'; // 22.2.1.1.2.13 of the C++ standard
1.81 + }
1.82 + return it;
1.83 + }
1.84 +
1.85 + // skip printf's "asterisk-fields" directives in the format-string buf
1.86 + // Input : char string, with starting index *pos_p
1.87 + // a Facet merely to use its widen/narrow member function
1.88 + // Effects : advance *pos_p by skipping printf's asterisk fields.
1.89 + // Returns : nothing
1.90 + template<class Iter, class Facet>
1.91 + Iter skip_asterisk(Iter start, Iter last, const Facet& fac)
1.92 + {
1.93 + using namespace std;
1.94 + ++ start;
1.95 + start = wrap_scan_notdigit(fac, start, last);
1.96 + if(start!=last && *start== const_or_not(fac).widen( '$') )
1.97 + ++start;
1.98 + return start;
1.99 + }
1.100 +
1.101 +
1.102 + // auxiliary func called by parse_printf_directive
1.103 + // for centralising error handling
1.104 + // it either throws if user sets the corresponding flag, or does nothing.
1.105 + inline void maybe_throw_exception(unsigned char exceptions,
1.106 + std::size_t pos, std::size_t size)
1.107 + {
1.108 + if(exceptions & io::bad_format_string_bit)
1.109 + boost::throw_exception(io::bad_format_string(pos, size) );
1.110 + }
1.111 +
1.112 +
1.113 + // Input: the position of a printf-directive in the format-string
1.114 + // a basic_ios& merely to use its widen/narrow member function
1.115 + // a bitset'exceptions' telling whether to throw exceptions on errors.
1.116 + // Returns:
1.117 + // true if parse succeeded (ignore some errors if exceptions disabled)
1.118 + // false if it failed so bad that the directive should be printed verbatim
1.119 + // Effects:
1.120 + // start is incremented so that *start is the first char after
1.121 + // this directive
1.122 + // *fpar is set with the parameters read in the directive
1.123 + template<class Ch, class Tr, class Alloc, class Iter, class Facet>
1.124 + bool parse_printf_directive(Iter & start, const Iter& last,
1.125 + detail::format_item<Ch, Tr, Alloc> * fpar,
1.126 + const Facet& fac,
1.127 + std::size_t offset, unsigned char exceptions)
1.128 + {
1.129 + typedef typename basic_format<Ch, Tr, Alloc>::format_item_t format_item_t;
1.130 +
1.131 + fpar->argN_ = format_item_t::argN_no_posit; // if no positional-directive
1.132 + bool precision_set = false;
1.133 + bool in_brackets=false;
1.134 + Iter start0 = start;
1.135 + std::size_t fstring_size = last-start0+offset;
1.136 + if(*start== const_or_not(fac).widen( '|')) {
1.137 + in_brackets=true;
1.138 + if( ++start >= last ) {
1.139 + maybe_throw_exception(exceptions, start-start0 + offset, fstring_size);
1.140 + return false;
1.141 + }
1.142 + }
1.143 +
1.144 + // the flag '0' would be picked as a digit for argument order, but here it's a flag :
1.145 + if(*start== const_or_not(fac).widen( '0'))
1.146 + goto parse_flags;
1.147 +
1.148 + // handle argument order (%2$d) or possibly width specification: %2d
1.149 + if(wrap_isdigit(fac, *start)) {
1.150 + int n;
1.151 + start = str2int(start, last, n, fac);
1.152 + if( start >= last ) {
1.153 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.154 + return false;
1.155 + }
1.156 +
1.157 + // %N% case : this is already the end of the directive
1.158 + if( *start == const_or_not(fac).widen( '%') ) {
1.159 + fpar->argN_ = n-1;
1.160 + ++start;
1.161 + if( in_brackets)
1.162 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.163 + // but don't return. maybe "%" was used in lieu of '$', so we go on.
1.164 + else
1.165 + return true;
1.166 + }
1.167 +
1.168 + if ( *start== const_or_not(fac).widen( '$') ) {
1.169 + fpar->argN_ = n-1;
1.170 + ++start;
1.171 + }
1.172 + else {
1.173 + // non-positionnal directive
1.174 + fpar->fmtstate_.width_ = n;
1.175 + fpar->argN_ = format_item_t::argN_no_posit;
1.176 + goto parse_precision;
1.177 + }
1.178 + }
1.179 +
1.180 + parse_flags:
1.181 + // handle flags
1.182 + while ( start != last) { // as long as char is one of + - = _ # 0 l h or ' '
1.183 + // misc switches
1.184 + switch ( wrap_narrow(fac, *start, 0)) {
1.185 + case '\'' : break; // no effect yet. (painful to implement)
1.186 + case 'l':
1.187 + case 'h': // short/long modifier : for printf-comaptibility (no action needed)
1.188 + break;
1.189 + case '-':
1.190 + fpar->fmtstate_.flags_ |= std::ios_base::left;
1.191 + break;
1.192 + case '=':
1.193 + fpar->pad_scheme_ |= format_item_t::centered;
1.194 + break;
1.195 + case '_':
1.196 + fpar->fmtstate_.flags_ |= std::ios_base::internal;
1.197 + break;
1.198 + case ' ':
1.199 + fpar->pad_scheme_ |= format_item_t::spacepad;
1.200 + break;
1.201 + case '+':
1.202 + fpar->fmtstate_.flags_ |= std::ios_base::showpos;
1.203 + break;
1.204 + case '0':
1.205 + fpar->pad_scheme_ |= format_item_t::zeropad;
1.206 + // need to know alignment before really setting flags,
1.207 + // so just add 'zeropad' flag for now, it will be processed later.
1.208 + break;
1.209 + case '#':
1.210 + fpar->fmtstate_.flags_ |= std::ios_base::showpoint | std::ios_base::showbase;
1.211 + break;
1.212 + default:
1.213 + goto parse_width;
1.214 + }
1.215 + ++start;
1.216 + } // loop on flag.
1.217 +
1.218 + if( start>=last) {
1.219 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.220 + return true;
1.221 + }
1.222 + parse_width:
1.223 + // handle width spec
1.224 + // first skip 'asterisk fields' : *, or *N$
1.225 + if(*start == const_or_not(fac).widen( '*') )
1.226 + start = skip_asterisk(start, last, fac);
1.227 + if(start!=last && wrap_isdigit(fac, *start))
1.228 + start = str2int(start, last, fpar->fmtstate_.width_, fac);
1.229 +
1.230 + parse_precision:
1.231 + if( start>= last) {
1.232 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.233 + return true;
1.234 + }
1.235 + // handle precision spec
1.236 + if (*start== const_or_not(fac).widen( '.')) {
1.237 + ++start;
1.238 + if(start != last && *start == const_or_not(fac).widen( '*') )
1.239 + start = skip_asterisk(start, last, fac);
1.240 + if(start != last && wrap_isdigit(fac, *start)) {
1.241 + start = str2int(start, last, fpar->fmtstate_.precision_, fac);
1.242 + precision_set = true;
1.243 + }
1.244 + else
1.245 + fpar->fmtstate_.precision_ =0;
1.246 + }
1.247 +
1.248 + // handle formatting-type flags :
1.249 + while( start != last && ( *start== const_or_not(fac).widen( 'l')
1.250 + || *start== const_or_not(fac).widen( 'L')
1.251 + || *start== const_or_not(fac).widen( 'h')) )
1.252 + ++start;
1.253 + if( start>=last) {
1.254 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.255 + return true;
1.256 + }
1.257 +
1.258 + if( in_brackets && *start== const_or_not(fac).widen( '|') ) {
1.259 + ++start;
1.260 + return true;
1.261 + }
1.262 + switch ( wrap_narrow(fac, *start, 0) ) {
1.263 + case 'X':
1.264 + fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
1.265 + case 'p': // pointer => set hex.
1.266 + case 'x':
1.267 + fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
1.268 + fpar->fmtstate_.flags_ |= std::ios_base::hex;
1.269 + break;
1.270 +
1.271 + case 'o':
1.272 + fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
1.273 + fpar->fmtstate_.flags_ |= std::ios_base::oct;
1.274 + break;
1.275 +
1.276 + case 'E':
1.277 + fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
1.278 + case 'e':
1.279 + fpar->fmtstate_.flags_ &= ~std::ios_base::floatfield;
1.280 + fpar->fmtstate_.flags_ |= std::ios_base::scientific;
1.281 +
1.282 + fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
1.283 + fpar->fmtstate_.flags_ |= std::ios_base::dec;
1.284 + break;
1.285 +
1.286 + case 'f':
1.287 + fpar->fmtstate_.flags_ &= ~std::ios_base::floatfield;
1.288 + fpar->fmtstate_.flags_ |= std::ios_base::fixed;
1.289 + case 'u':
1.290 + case 'd':
1.291 + case 'i':
1.292 + fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
1.293 + fpar->fmtstate_.flags_ |= std::ios_base::dec;
1.294 + break;
1.295 +
1.296 + case 'T':
1.297 + ++start;
1.298 + if( start >= last)
1.299 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.300 + else
1.301 + fpar->fmtstate_.fill_ = *start;
1.302 + fpar->pad_scheme_ |= format_item_t::tabulation;
1.303 + fpar->argN_ = format_item_t::argN_tabulation;
1.304 + break;
1.305 + case 't':
1.306 + fpar->fmtstate_.fill_ = const_or_not(fac).widen( ' ');
1.307 + fpar->pad_scheme_ |= format_item_t::tabulation;
1.308 + fpar->argN_ = format_item_t::argN_tabulation;
1.309 + break;
1.310 +
1.311 + case 'G':
1.312 + fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
1.313 + break;
1.314 + case 'g': // 'g' conversion is default for floats.
1.315 + fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
1.316 + fpar->fmtstate_.flags_ |= std::ios_base::dec;
1.317 +
1.318 + // CLEAR all floatield flags, so stream will CHOOSE
1.319 + fpar->fmtstate_.flags_ &= ~std::ios_base::floatfield;
1.320 + break;
1.321 +
1.322 + case 'C':
1.323 + case 'c':
1.324 + fpar->truncate_ = 1;
1.325 + break;
1.326 + case 'S':
1.327 + case 's':
1.328 + if(precision_set) // handle truncation manually, with own parameter.
1.329 + fpar->truncate_ = fpar->fmtstate_.precision_;
1.330 + fpar->fmtstate_.precision_ = 6; // default stream precision.
1.331 + break;
1.332 + case 'n' :
1.333 + fpar->argN_ = format_item_t::argN_ignored;
1.334 + break;
1.335 + default:
1.336 + maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.337 + }
1.338 + ++start;
1.339 +
1.340 + if( in_brackets ) {
1.341 + if( start != last && *start== const_or_not(fac).widen( '|') ) {
1.342 + ++start;
1.343 + return true;
1.344 + }
1.345 + else maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
1.346 + }
1.347 + return true;
1.348 + }
1.349 + // -end parse_printf_directive()
1.350 +
1.351 + template<class String, class Facet>
1.352 + int upper_bound_from_fstring(const String& buf,
1.353 + const typename String::value_type arg_mark,
1.354 + const Facet& fac,
1.355 + unsigned char exceptions)
1.356 + {
1.357 + // quick-parsing of the format-string to count arguments mark (arg_mark, '%')
1.358 + // returns : upper bound on the number of format items in the format strings
1.359 + using namespace boost::io;
1.360 + typename String::size_type i1=0;
1.361 + int num_items=0;
1.362 + while( (i1=buf.find(arg_mark,i1)) != String::npos ) {
1.363 + if( i1+1 >= buf.size() ) {
1.364 + if(exceptions & bad_format_string_bit)
1.365 + boost::throw_exception(bad_format_string(i1, buf.size() )); // must not end in ".. %"
1.366 + else break; // stop there, ignore last '%'
1.367 + }
1.368 + if(buf[i1+1] == buf[i1] ) {// escaped "%%"
1.369 + i1+=2; continue;
1.370 + }
1.371 +
1.372 + ++i1;
1.373 + // in case of %N% directives, dont count it double (wastes allocations..) :
1.374 + i1 = detail::wrap_scan_notdigit(fac, buf.begin()+i1, buf.end()) - buf.begin();
1.375 + if( i1 < buf.size() && buf[i1] == arg_mark )
1.376 + ++i1;
1.377 + ++num_items;
1.378 + }
1.379 + return num_items;
1.380 + }
1.381 + template<class String> inline
1.382 + void append_string(String& dst, const String& src,
1.383 + const typename String::size_type beg,
1.384 + const typename String::size_type end) {
1.385 +#if !defined(BOOST_NO_STRING_APPEND)
1.386 + dst.append(src.begin()+beg, src.begin()+end);
1.387 +#else
1.388 + dst += src.substr(beg, end-beg);
1.389 +#endif
1.390 + }
1.391 +
1.392 +} // detail namespace
1.393 +} // io namespace
1.394 +
1.395 +
1.396 +
1.397 +// -----------------------------------------------
1.398 +// format :: parse(..)
1.399 +
1.400 + template<class Ch, class Tr, class Alloc>
1.401 + basic_format<Ch, Tr, Alloc>& basic_format<Ch, Tr, Alloc>::
1.402 + parse (const string_type& buf) {
1.403 + // parse the format-string
1.404 + using namespace std;
1.405 +#if !defined(BOOST_NO_STD_LOCALE)
1.406 + const std::ctype<Ch> & fac = BOOST_USE_FACET( std::ctype<Ch>, getloc());
1.407 +#else
1.408 + io::basic_oaltstringstream<Ch, Tr, Alloc> fac;
1.409 + //has widen and narrow even on compilers without locale
1.410 +#endif
1.411 +
1.412 + const Ch arg_mark = io::detail::const_or_not(fac).widen( '%');
1.413 + bool ordered_args=true;
1.414 + int max_argN=-1;
1.415 +
1.416 + // A: find upper_bound on num_items and allocates arrays
1.417 + int num_items = io::detail::upper_bound_from_fstring(buf, arg_mark, fac, exceptions());
1.418 + make_or_reuse_data(num_items);
1.419 +
1.420 + // B: Now the real parsing of the format string :
1.421 + num_items=0;
1.422 + typename string_type::size_type i0=0, i1=0;
1.423 + typename string_type::const_iterator it;
1.424 + bool special_things=false;
1.425 + int cur_item=0;
1.426 + while( (i1=buf.find(arg_mark,i1)) != string_type::npos ) {
1.427 + string_type & piece = (cur_item==0) ? prefix_ : items_[cur_item-1].appendix_;
1.428 + if( buf[i1+1] == buf[i1] ) { // escaped mark, '%%'
1.429 + io::detail::append_string(piece, buf, i0, i1+1);
1.430 + i1+=2; i0=i1;
1.431 + continue;
1.432 + }
1.433 + BOOST_ASSERT( static_cast<unsigned int>(cur_item) < items_.size() || cur_item==0);
1.434 +
1.435 + if(i1!=i0)
1.436 + io::detail::append_string(piece, buf, i0, i1);
1.437 + ++i1;
1.438 + it = buf.begin()+i1;
1.439 + bool parse_ok = io::detail::parse_printf_directive(
1.440 + it, buf.end(), &items_[cur_item], fac, i1, exceptions());
1.441 + i1 = it - buf.begin();
1.442 + if( ! parse_ok ) // the directive will be printed verbatim
1.443 + continue;
1.444 + i0=i1;
1.445 + items_[cur_item].compute_states(); // process complex options, like zeropad, into params
1.446 +
1.447 + int argN=items_[cur_item].argN_;
1.448 + if(argN == format_item_t::argN_ignored)
1.449 + continue;
1.450 + if(argN ==format_item_t::argN_no_posit)
1.451 + ordered_args=false;
1.452 + else if(argN == format_item_t::argN_tabulation) special_things=true;
1.453 + else if(argN > max_argN) max_argN = argN;
1.454 + ++num_items;
1.455 + ++cur_item;
1.456 + } // loop on %'s
1.457 + BOOST_ASSERT(cur_item == num_items);
1.458 +
1.459 + // store the final piece of string
1.460 + {
1.461 + string_type & piece = (cur_item==0) ? prefix_ : items_[cur_item-1].appendix_;
1.462 + io::detail::append_string(piece, buf, i0, buf.size());
1.463 + }
1.464 +
1.465 + if( !ordered_args) {
1.466 + if(max_argN >= 0 ) { // dont mix positional with non-positionnal directives
1.467 + if(exceptions() & io::bad_format_string_bit)
1.468 + boost::throw_exception(io::bad_format_string(max_argN, 0));
1.469 + // else do nothing. => positionnal arguments are processed as non-positionnal
1.470 + }
1.471 + // set things like it would have been with positional directives :
1.472 + int non_ordered_items = 0;
1.473 + for(int i=0; i< num_items; ++i)
1.474 + if(items_[i].argN_ == format_item_t::argN_no_posit) {
1.475 + items_[i].argN_ = non_ordered_items;
1.476 + ++non_ordered_items;
1.477 + }
1.478 + max_argN = non_ordered_items-1;
1.479 + }
1.480 +
1.481 + // C: set some member data :
1.482 + items_.resize(num_items, format_item_t(io::detail::const_or_not(fac).widen( ' ')) );
1.483 +
1.484 + if(special_things) style_ |= special_needs;
1.485 + num_args_ = max_argN + 1;
1.486 + if(ordered_args) style_ |= ordered;
1.487 + else style_ &= ~ordered;
1.488 + return *this;
1.489 + }
1.490 +
1.491 +} // namespace boost
1.492 +
1.493 +
1.494 +#endif // BOOST_FORMAT_PARSING_HPP