Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:54

0001 // ----------------------------------------------------------------------------
0002 // parsing.hpp :  implementation of the parsing member functions
0003 //                      ( parse, parse_printf_directive)
0004 // ----------------------------------------------------------------------------
0005 
0006 //  Copyright Samuel Krempp 2003. Use, modification, and distribution are
0007 //  subject to the Boost Software License, Version 1.0. (See accompanying
0008 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 // see http://www.boost.org/libs/format for library home page
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     // streams will be used for narrow / widen. but these methods are not const
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     // Input : [start, last) iterators range and a
0067     //          a Facet to use its widen/narrow member function
0068     // Effects : read sequence and convert digits into integral n, of type Res
0069     // Returns : n
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); // cant fail.
0079             res *= 10;
0080             res += cur_ch - '0'; // 22.2.1.1.2.13 of the C++ standard
0081         }
0082         return it;
0083     }
0084 
0085     // auxiliary func called by parse_printf_directive
0086     // for centralising error handling
0087     // it either throws if user sets the corresponding flag, or does nothing.
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     // Input: the position of a printf-directive in the format-string
0097     //    a basic_ios& merely to use its widen/narrow member function
0098     //    a bitset'exceptions' telling whether to throw exceptions on errors.
0099     // Returns:
0100     //  true if parse succeeded (ignore some errors if exceptions disabled)
0101     //  false if it failed so bad that the directive should be printed verbatim
0102     // Effects:
0103     //  start is incremented so that *start is the first char after
0104     //     this directive
0105     //  *fpar is set with the parameters read in the directive
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;  // if no positional-directive
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) { // empty directive : this is a trailing %
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         // the flag '0' would be picked as a digit for argument order, but here it's a flag :
0135         if(*start== const_or_not(fac).widen( '0'))
0136             goto parse_flags;
0137 
0138         // handle argument order (%2$d)  or possibly width specification: %2d
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             // %N% case : this is already the end of the directive
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                 // non-positional directive
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         // handle flags
0170         while (start != last) { // as long as char is one of + - = _ # 0 or ' '
0171             switch ( wrap_narrow(fac, *start, 0)) {
0172                 case '\'':
0173                     break; // no effect yet. (painful to implement)
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                     // need to know alignment before really setting flags,
0192                     // so just add 'zeropad' flag for now, it will be processed later.
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         } // loop on flag.
0202 
0203         if( start>=last) {
0204             maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
0205             return true;
0206         }
0207 
0208       // first skip 'asterisk fields' : * or num (length)
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         // handle precision spec
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       // argument type modifiers
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                     // boost::format ignores argument type modifiers as it relies on
0242                     // the type of the argument fed into it by operator %
0243                     break;
0244 
0245                 // Note that the ptrdiff_t argument type 't' from C++11 is not honored
0246                 // because it was already in use as the tabulation specifier in boost::format
0247                 // case 't':
0248 
0249                 // Microsoft extensions:
0250                 // https://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx
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         } // loop on argument type modifiers to pick up 'hh', 'll', and the more complex microsoft ones
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         // The default flags are "dec" and "skipws"
0306         // so if changing the base, need to unset basefield first
0307 
0308         switch (wrap_narrow(fac, *start, 0))
0309         {
0310             // Boolean
0311             case 'b':
0312                 fpar->fmtstate_.flags_ |= std::ios_base::boolalpha;
0313                 break;
0314 
0315             // Decimal
0316             case 'u':
0317             case 'd':
0318             case 'i':
0319                 // Defaults are sufficient
0320                 break;
0321 
0322             // Hex
0323             case 'X':
0324                 fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
0325                 BOOST_FALLTHROUGH;
0326             case 'x':
0327             case 'p': // pointer => set hex.
0328                 fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
0329                 fpar->fmtstate_.flags_ |= std::ios_base::hex;
0330                 break;
0331 
0332             // Octal
0333             case 'o':
0334                 fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
0335                 fpar->fmtstate_.flags_ |= std::ios_base::oct;
0336                 break;
0337 
0338             // Floating
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                 // default flags are correct here
0364                 break;
0365 
0366             // Tabulation (a boost::format extension)
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             // Character
0385             case 'C':
0386             case 'c':
0387                 fpar->truncate_ = 1;
0388                 break;
0389 
0390             // String
0391             case 'S':
0392             case 's':
0393                 if(precision_set) // handle truncation manually, with own parameter.
0394                     fpar->truncate_ = fpar->fmtstate_.precision_;
0395                 fpar->fmtstate_.precision_ = 6; // default stream precision.
0396                 break;
0397 
0398             // %n is insecure and ignored by boost::format
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     // -end parse_printf_directive()
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         // quick-parsing of the format-string to count arguments mark (arg_mark, '%')
0426         // returns : upper bound on the number of format items in the format strings
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() )); // must not end in ".. %"
0434                 else {
0435                   ++num_items;
0436                   break;
0437                 }
0438             }
0439             if(buf[i1+1] == buf[i1] ) {// escaped "%%"
0440                 i1+=2; continue;
0441             }
0442 
0443             ++i1;
0444             // in case of %N% directives, dont count it double (wastes allocations..) :
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 } // detail namespace
0460 } // io namespace
0461 
0462 
0463 
0464 // -----------------------------------------------
0465 //  format :: parse(..)
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         // parse the format-string
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         //has widen and narrow even on compilers without locale
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         // A: find upper_bound on num_items and allocates arrays
0484         int num_items = io::detail::upper_bound_from_fstring(buf, arg_mark, fac, exceptions());
0485         make_or_reuse_data(num_items);
0486 
0487         // B: Now the real parsing of the format string :
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] ) { // escaped mark, '%%'
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 ) // the directive will be printed verbatim
0512                 continue;
0513             i0=i1;
0514             items_[cur_item].compute_states(); // process complex options, like zeropad, into params
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         } // loop on %'s
0526         BOOST_ASSERT(cur_item == num_items);
0527 
0528         // store the final piece of string
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 ) {  // dont mix positional with non-positionnal directives
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                 // else do nothing. => positionnal arguments are processed as non-positionnal
0540             }
0541             // set things like it would have been with positional directives :
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         // C: set some member data :
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 } // namespace boost
0562 
0563 
0564 #endif //  BOOST_FORMAT_PARSING_HPP