os/ossrv/ossrv_pub/boost_apis/boost/format/parsing.hpp
changeset 0 bde4ae8d615e
     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