File indexing completed on 2025-01-18 09:30:54
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef BOOST_FORMAT_PARSING_HPP
0015 #define BOOST_FORMAT_PARSING_HPP
0016
0017
0018 #include <boost/format/format_class.hpp>
0019 #include <boost/format/exceptions.hpp>
0020 #include <boost/throw_exception.hpp>
0021 #include <boost/assert.hpp>
0022 #include <boost/config.hpp>
0023 #include <boost/core/ignore_unused.hpp>
0024
0025 namespace boost {
0026 namespace io {
0027 namespace detail {
0028
0029 #if defined(BOOST_NO_STD_LOCALE)
0030
0031 template<class T>
0032 T& const_or_not(const T& x) {
0033 return const_cast<T&> (x);
0034 }
0035 #else
0036 template<class T>
0037 const T& const_or_not(const T& x) {
0038 return x;
0039 }
0040 #endif
0041
0042 template<class Ch, class Facet> inline
0043 char wrap_narrow(const Facet& fac, Ch c, char deflt) {
0044 return const_or_not(fac).narrow(c, deflt);
0045 }
0046
0047 template<class Ch, class Facet> inline
0048 bool wrap_isdigit(const Facet& fac, Ch c) {
0049 #if ! defined( BOOST_NO_LOCALE_ISDIGIT )
0050 return fac.is(std::ctype<Ch>::digit, c);
0051 # else
0052 ignore_unused(fac);
0053 using namespace std;
0054 return isdigit(c) != 0;
0055 #endif
0056 }
0057
0058 template<class Iter, class Facet>
0059 Iter wrap_scan_notdigit(const Facet & fac, Iter beg, Iter end) {
0060 using namespace std;
0061 for( ; beg!=end && wrap_isdigit(fac, *beg); ++beg) ;
0062 return beg;
0063 }
0064
0065
0066
0067
0068
0069
0070 template<class Res, class Iter, class Facet>
0071 Iter str2int (const Iter & start, const Iter & last, Res & res,
0072 const Facet& fac)
0073 {
0074 using namespace std;
0075 Iter it;
0076 res=0;
0077 for(it=start; it != last && wrap_isdigit(fac, *it); ++it ) {
0078 char cur_ch = wrap_narrow(fac, *it, 0);
0079 res *= 10;
0080 res += cur_ch - '0';
0081 }
0082 return it;
0083 }
0084
0085
0086
0087
0088 inline void maybe_throw_exception(unsigned char exceptions,
0089 std::size_t pos, std::size_t size)
0090 {
0091 if(exceptions & io::bad_format_string_bit)
0092 boost::throw_exception(io::bad_format_string(pos, size) );
0093 }
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106 template<class Ch, class Tr, class Alloc, class Iter, class Facet>
0107 bool parse_printf_directive(Iter & start, const Iter& last,
0108 detail::format_item<Ch, Tr, Alloc> * fpar,
0109 const Facet& fac,
0110 std::size_t offset, unsigned char exceptions)
0111 {
0112 typedef typename basic_format<Ch, Tr, Alloc>::format_item_t format_item_t;
0113
0114 fpar->argN_ = format_item_t::argN_no_posit;
0115 bool precision_set = false;
0116 bool in_brackets=false;
0117 Iter start0 = start;
0118 std::size_t fstring_size = last-start0+offset;
0119 char mssiz = 0;
0120
0121 if(start>= last) {
0122 maybe_throw_exception(exceptions, start-start0 + offset, fstring_size);
0123 return false;
0124 }
0125
0126 if(*start== const_or_not(fac).widen( '|')) {
0127 in_brackets=true;
0128 if( ++start >= last ) {
0129 maybe_throw_exception(exceptions, start-start0 + offset, fstring_size);
0130 return false;
0131 }
0132 }
0133
0134
0135 if(*start== const_or_not(fac).widen( '0'))
0136 goto parse_flags;
0137
0138
0139 if(wrap_isdigit(fac, *start)) {
0140 int n;
0141 start = str2int(start, last, n, fac);
0142 if( start >= last ) {
0143 maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0144 return false;
0145 }
0146
0147
0148 if( *start == const_or_not(fac).widen( '%') ) {
0149 fpar->argN_ = n-1;
0150 ++start;
0151 if( in_brackets)
0152 maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0153 return true;
0154 }
0155
0156 if ( *start== const_or_not(fac).widen( '$') ) {
0157 fpar->argN_ = n-1;
0158 ++start;
0159 }
0160 else {
0161
0162 fpar->fmtstate_.width_ = n;
0163 fpar->argN_ = format_item_t::argN_no_posit;
0164 goto parse_precision;
0165 }
0166 }
0167
0168 parse_flags:
0169
0170 while (start != last) {
0171 switch ( wrap_narrow(fac, *start, 0)) {
0172 case '\'':
0173 break;
0174 case '-':
0175 fpar->fmtstate_.flags_ |= std::ios_base::left;
0176 break;
0177 case '=':
0178 fpar->pad_scheme_ |= format_item_t::centered;
0179 break;
0180 case '_':
0181 fpar->fmtstate_.flags_ |= std::ios_base::internal;
0182 break;
0183 case ' ':
0184 fpar->pad_scheme_ |= format_item_t::spacepad;
0185 break;
0186 case '+':
0187 fpar->fmtstate_.flags_ |= std::ios_base::showpos;
0188 break;
0189 case '0':
0190 fpar->pad_scheme_ |= format_item_t::zeropad;
0191
0192
0193 break;
0194 case '#':
0195 fpar->fmtstate_.flags_ |= std::ios_base::showpoint | std::ios_base::showbase;
0196 break;
0197 default:
0198 goto parse_width;
0199 }
0200 ++start;
0201 }
0202
0203 if( start>=last) {
0204 maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0205 return true;
0206 }
0207
0208
0209 parse_width:
0210 if(*start == const_or_not(fac).widen( '*') )
0211 ++start;
0212 else if(start!=last && wrap_isdigit(fac, *start))
0213 start = str2int(start, last, fpar->fmtstate_.width_, fac);
0214
0215 parse_precision:
0216 if( start>= last) {
0217 maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0218 return true;
0219 }
0220
0221 if (*start== const_or_not(fac).widen( '.')) {
0222 ++start;
0223 if(start != last && *start == const_or_not(fac).widen( '*') )
0224 ++start;
0225 else if(start != last && wrap_isdigit(fac, *start)) {
0226 start = str2int(start, last, fpar->fmtstate_.precision_, fac);
0227 precision_set = true;
0228 }
0229 else
0230 fpar->fmtstate_.precision_ =0;
0231 }
0232
0233
0234 while (start != last) {
0235 switch (wrap_narrow(fac, *start, 0)) {
0236 case 'h':
0237 case 'l':
0238 case 'j':
0239 case 'z':
0240 case 'L':
0241
0242
0243 break;
0244
0245
0246
0247
0248
0249
0250
0251
0252 case 'w':
0253 break;
0254 case 'I':
0255 mssiz = 'I';
0256 break;
0257 case '3':
0258 if (mssiz != 'I') {
0259 maybe_throw_exception(exceptions, start - start0 + offset, fstring_size);
0260 return true;
0261 }
0262 mssiz = '3';
0263 break;
0264 case '2':
0265 if (mssiz != '3') {
0266 maybe_throw_exception(exceptions, start - start0 + offset, fstring_size);
0267 return true;
0268 }
0269 mssiz = 0x00;
0270 break;
0271 case '6':
0272 if (mssiz != 'I') {
0273 maybe_throw_exception(exceptions, start - start0 + offset, fstring_size);
0274 return true;
0275 }
0276 mssiz = '6';
0277 break;
0278 case '4':
0279 if (mssiz != '6') {
0280 maybe_throw_exception(exceptions, start - start0 + offset, fstring_size);
0281 return true;
0282 }
0283 mssiz = 0x00;
0284 break;
0285 default:
0286 if (mssiz && mssiz == 'I') {
0287 mssiz = 0;
0288 }
0289 goto parse_conversion_specification;
0290 }
0291 ++start;
0292 }
0293
0294 parse_conversion_specification:
0295 if (start >= last || mssiz) {
0296 maybe_throw_exception(exceptions, start - start0 + offset, fstring_size);
0297 return true;
0298 }
0299
0300 if( in_brackets && *start== const_or_not(fac).widen( '|') ) {
0301 ++start;
0302 return true;
0303 }
0304
0305
0306
0307
0308 switch (wrap_narrow(fac, *start, 0))
0309 {
0310
0311 case 'b':
0312 fpar->fmtstate_.flags_ |= std::ios_base::boolalpha;
0313 break;
0314
0315
0316 case 'u':
0317 case 'd':
0318 case 'i':
0319
0320 break;
0321
0322
0323 case 'X':
0324 fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
0325 BOOST_FALLTHROUGH;
0326 case 'x':
0327 case 'p':
0328 fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
0329 fpar->fmtstate_.flags_ |= std::ios_base::hex;
0330 break;
0331
0332
0333 case 'o':
0334 fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
0335 fpar->fmtstate_.flags_ |= std::ios_base::oct;
0336 break;
0337
0338
0339 case 'A':
0340 fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
0341 BOOST_FALLTHROUGH;
0342 case 'a':
0343 fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
0344 fpar->fmtstate_.flags_ |= std::ios_base::fixed;
0345 fpar->fmtstate_.flags_ |= std::ios_base::scientific;
0346 break;
0347 case 'E':
0348 fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
0349 BOOST_FALLTHROUGH;
0350 case 'e':
0351 fpar->fmtstate_.flags_ |= std::ios_base::scientific;
0352 break;
0353 case 'F':
0354 fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
0355 BOOST_FALLTHROUGH;
0356 case 'f':
0357 fpar->fmtstate_.flags_ |= std::ios_base::fixed;
0358 break;
0359 case 'G':
0360 fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
0361 BOOST_FALLTHROUGH;
0362 case 'g':
0363
0364 break;
0365
0366
0367 case 'T':
0368 ++start;
0369 if( start >= last) {
0370 maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0371 return false;
0372 } else {
0373 fpar->fmtstate_.fill_ = *start;
0374 }
0375 fpar->pad_scheme_ |= format_item_t::tabulation;
0376 fpar->argN_ = format_item_t::argN_tabulation;
0377 break;
0378 case 't':
0379 fpar->fmtstate_.fill_ = const_or_not(fac).widen( ' ');
0380 fpar->pad_scheme_ |= format_item_t::tabulation;
0381 fpar->argN_ = format_item_t::argN_tabulation;
0382 break;
0383
0384
0385 case 'C':
0386 case 'c':
0387 fpar->truncate_ = 1;
0388 break;
0389
0390
0391 case 'S':
0392 case 's':
0393 if(precision_set)
0394 fpar->truncate_ = fpar->fmtstate_.precision_;
0395 fpar->fmtstate_.precision_ = 6;
0396 break;
0397
0398
0399 case 'n' :
0400 fpar->argN_ = format_item_t::argN_ignored;
0401 break;
0402
0403 default:
0404 maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0405 }
0406 ++start;
0407
0408 if( in_brackets ) {
0409 if( start != last && *start== const_or_not(fac).widen( '|') ) {
0410 ++start;
0411 return true;
0412 }
0413 else maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0414 }
0415 return true;
0416 }
0417
0418
0419 template<class String, class Facet>
0420 int upper_bound_from_fstring(const String& buf,
0421 const typename String::value_type arg_mark,
0422 const Facet& fac,
0423 unsigned char exceptions)
0424 {
0425
0426
0427 using namespace boost::io;
0428 typename String::size_type i1=0;
0429 int num_items=0;
0430 while( (i1=buf.find(arg_mark,i1)) != String::npos ) {
0431 if( i1+1 >= buf.size() ) {
0432 if(exceptions & bad_format_string_bit)
0433 boost::throw_exception(bad_format_string(i1, buf.size() ));
0434 else {
0435 ++num_items;
0436 break;
0437 }
0438 }
0439 if(buf[i1+1] == buf[i1] ) {
0440 i1+=2; continue;
0441 }
0442
0443 ++i1;
0444
0445 i1 = detail::wrap_scan_notdigit(fac, buf.begin()+i1, buf.end()) - buf.begin();
0446 if( i1 < buf.size() && buf[i1] == arg_mark )
0447 ++i1;
0448 ++num_items;
0449 }
0450 return num_items;
0451 }
0452 template<class String> inline
0453 void append_string(String& dst, const String& src,
0454 const typename String::size_type beg,
0455 const typename String::size_type end) {
0456 dst.append(src.begin()+beg, src.begin()+end);
0457 }
0458
0459 }
0460 }
0461
0462
0463
0464
0465
0466
0467 template<class Ch, class Tr, class Alloc>
0468 basic_format<Ch, Tr, Alloc>& basic_format<Ch, Tr, Alloc>::
0469 parse (const string_type& buf) {
0470
0471 using namespace std;
0472 #if !defined(BOOST_NO_STD_LOCALE)
0473 const std::ctype<Ch> & fac = BOOST_USE_FACET( std::ctype<Ch>, getloc());
0474 #else
0475 io::basic_oaltstringstream<Ch, Tr, Alloc> fac;
0476
0477 #endif
0478
0479 const Ch arg_mark = io::detail::const_or_not(fac).widen( '%');
0480 bool ordered_args=true;
0481 int max_argN=-1;
0482
0483
0484 int num_items = io::detail::upper_bound_from_fstring(buf, arg_mark, fac, exceptions());
0485 make_or_reuse_data(num_items);
0486
0487
0488 num_items=0;
0489 typename string_type::size_type i0=0, i1=0;
0490 typename string_type::const_iterator it;
0491 bool special_things=false;
0492 int cur_item=0;
0493 while( (i1=buf.find(arg_mark,i1)) != string_type::npos ) {
0494 string_type & piece = (cur_item==0) ? prefix_ : items_[cur_item-1].appendix_;
0495 if( buf[i1+1] == buf[i1] ) {
0496 io::detail::append_string(piece, buf, i0, i1+1);
0497 i1+=2; i0=i1;
0498 continue;
0499 }
0500 BOOST_ASSERT( static_cast<unsigned int>(cur_item) < items_.size() || cur_item==0);
0501
0502 if(i1!=i0) {
0503 io::detail::append_string(piece, buf, i0, i1);
0504 i0=i1;
0505 }
0506 ++i1;
0507 it = buf.begin()+i1;
0508 bool parse_ok = io::detail::parse_printf_directive(
0509 it, buf.end(), &items_[cur_item], fac, i1, exceptions());
0510 i1 = it - buf.begin();
0511 if( ! parse_ok )
0512 continue;
0513 i0=i1;
0514 items_[cur_item].compute_states();
0515
0516 int argN=items_[cur_item].argN_;
0517 if(argN == format_item_t::argN_ignored)
0518 continue;
0519 if(argN ==format_item_t::argN_no_posit)
0520 ordered_args=false;
0521 else if(argN == format_item_t::argN_tabulation) special_things=true;
0522 else if(argN > max_argN) max_argN = argN;
0523 ++num_items;
0524 ++cur_item;
0525 }
0526 BOOST_ASSERT(cur_item == num_items);
0527
0528
0529 {
0530 string_type & piece = (cur_item==0) ? prefix_ : items_[cur_item-1].appendix_;
0531 io::detail::append_string(piece, buf, i0, buf.size());
0532 }
0533
0534 if( !ordered_args) {
0535 if(max_argN >= 0 ) {
0536 if(exceptions() & io::bad_format_string_bit)
0537 boost::throw_exception(
0538 io::bad_format_string(static_cast<std::size_t>(max_argN), 0));
0539
0540 }
0541
0542 int non_ordered_items = 0;
0543 for(int i=0; i< num_items; ++i)
0544 if(items_[i].argN_ == format_item_t::argN_no_posit) {
0545 items_[i].argN_ = non_ordered_items;
0546 ++non_ordered_items;
0547 }
0548 max_argN = non_ordered_items-1;
0549 }
0550
0551
0552 items_.resize(num_items, format_item_t(io::detail::const_or_not(fac).widen( ' ')) );
0553
0554 if(special_things) style_ |= special_needs;
0555 num_args_ = max_argN + 1;
0556 if(ordered_args) style_ |= ordered;
0557 else style_ &= ~ordered;
0558 return *this;
0559 }
0560
0561 }
0562
0563
0564 #endif