+
+
+ // Input: the position of a printf-directive in the format-string
+ // a basic_ios& merely to use its widen/narrow member function
+ // a bitset'exceptions' telling whether to throw exceptions on errors.
+ // Returns:
+ // true if parse succeeded (ignore some errors if exceptions disabled)
+ // false if it failed so bad that the directive should be printed verbatim
+ // Effects:
+ // start is incremented so that *start is the first char after
+ // this directive
+ // *fpar is set with the parameters read in the directive
+ template<class Ch, class Tr, class Alloc, class Iter, class Facet>
+ bool parse_printf_directive(Iter & start, const Iter& last,
+ detail::format_item<Ch, Tr, Alloc> * fpar,
+ const Facet& fac,
+ std::size_t offset, unsigned char exceptions)
+ {
+ typedef typename basic_format<Ch, Tr, Alloc>::format_item_t format_item_t;
+
+ fpar->argN_ = format_item_t::argN_no_posit; // if no positional-directive
+ bool precision_set = false;
+ bool in_brackets=false;
+ Iter start0 = start;
+ std::size_t fstring_size = last-start0+offset;
+
+ if(start>= last) { // empty directive : this is a trailing %
+ maybe_throw_exception(exceptions, start-start0 + offset, fstring_size);
+ return false;
+ }
+
+ if(*start== const_or_not(fac).widen( '|')) {
+ in_brackets=true;
+ if( ++start >= last ) {
+ maybe_throw_exception(exceptions, start-start0 + offset, fstring_size);
+ return false;
+ }
+ }
+
+ // the flag '0' would be picked as a digit for argument order, but here it's a flag :
+ if(*start== const_or_not(fac).widen( '0'))
+ goto parse_flags;
+
+ // handle argument order (%2$d) or possibly width specification: %2d
+ if(wrap_isdigit(fac, *start)) {
+ int n;
+ start = str2int(start, last, n, fac);
+ if( start >= last ) {
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ return false;
+ }
+
+ // %N% case : this is already the end of the directive
+ if( *start == const_or_not(fac).widen( '%') ) {
+ fpar->argN_ = n-1;
+ ++start;
+ if( in_brackets)
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ // but don't return. maybe "%" was used in lieu of '$', so we go on.
+ else
+ return true;
+ }
+
+ if ( *start== const_or_not(fac).widen( '$') ) {
+ fpar->argN_ = n-1;
+ ++start;
+ }
+ else {
+ // non-positionnal directive
+ fpar->fmtstate_.width_ = n;
+ fpar->argN_ = format_item_t::argN_no_posit;
+ goto parse_precision;
+ }
+ }
+
+ parse_flags:
+ // handle flags
+ while ( start != last) { // as long as char is one of + - = _ # 0 l h or ' '
+ // misc switches
+ switch ( wrap_narrow(fac, *start, 0)) {
+ case '\'' : break; // no effect yet. (painful to implement)
+ case 'l':
+ case 'h': // short/long modifier : for printf-comaptibility (no action needed)
+ break;
+ case '-':
+ fpar->fmtstate_.flags_ |= std::ios_base::left;
+ break;
+ case '=':
+ fpar->pad_scheme_ |= format_item_t::centered;
+ break;
+ case '_':
+ fpar->fmtstate_.flags_ |= std::ios_base::internal;
+ break;
+ case ' ':
+ fpar->pad_scheme_ |= format_item_t::spacepad;
+ break;
+ case '+':
+ fpar->fmtstate_.flags_ |= std::ios_base::showpos;
+ break;
+ case '0':
+ fpar->pad_scheme_ |= format_item_t::zeropad;
+ // need to know alignment before really setting flags,
+ // so just add 'zeropad' flag for now, it will be processed later.
+ break;
+ case '#':
+ fpar->fmtstate_.flags_ |= std::ios_base::showpoint | std::ios_base::showbase;
+ break;
+ default:
+ goto parse_width;
+ }
+ ++start;
+ } // loop on flag.
+
+ if( start>=last) {
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ return true;
+ }
+ parse_width:
+ // handle width spec
+ // first skip 'asterisk fields' : *, or *N$
+ if(*start == const_or_not(fac).widen( '*') )
+ start = skip_asterisk(start, last, fac);
+ if(start!=last && wrap_isdigit(fac, *start))
+ start = str2int(start, last, fpar->fmtstate_.width_, fac);
+
+ parse_precision:
+ if( start>= last) {
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ return true;
+ }
+ // handle precision spec
+ if (*start== const_or_not(fac).widen( '.')) {
+ ++start;
+ if(start != last && *start == const_or_not(fac).widen( '*') )
+ start = skip_asterisk(start, last, fac);
+ if(start != last && wrap_isdigit(fac, *start)) {
+ start = str2int(start, last, fpar->fmtstate_.precision_, fac);
+ precision_set = true;
+ }
+ else
+ fpar->fmtstate_.precision_ =0;
+ }
+
+ // handle formatting-type flags :
+ while( start != last && ( *start== const_or_not(fac).widen( 'l')
+ || *start== const_or_not(fac).widen( 'L')
+ || *start== const_or_not(fac).widen( 'h')) )
+ ++start;
+ if( start>=last) {
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ return true;
+ }
+
+ if( in_brackets && *start== const_or_not(fac).widen( '|') ) {
+ ++start;
+ return true;
+ }
+ switch ( wrap_narrow(fac, *start, 0) ) {
+ case 'X':
+ fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
+ case 'p': // pointer => set hex.
+ case 'x':
+ fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
+ fpar->fmtstate_.flags_ |= std::ios_base::hex;
+ break;
+
+ case 'o':
+ fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
+ fpar->fmtstate_.flags_ |= std::ios_base::oct;
+ break;
+
+ case 'E':
+ fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
+ case 'e':
+ fpar->fmtstate_.flags_ &= ~std::ios_base::floatfield;
+ fpar->fmtstate_.flags_ |= std::ios_base::scientific;
+
+ fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
+ fpar->fmtstate_.flags_ |= std::ios_base::dec;
+ break;
+
+ case 'f':
+ fpar->fmtstate_.flags_ &= ~std::ios_base::floatfield;
+ fpar->fmtstate_.flags_ |= std::ios_base::fixed;
+ case 'u':
+ case 'd':
+ case 'i':
+ fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
+ fpar->fmtstate_.flags_ |= std::ios_base::dec;
+ break;
+
+ case 'T':
+ ++start;
+ if( start >= last)
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ else
+ fpar->fmtstate_.fill_ = *start;
+ fpar->pad_scheme_ |= format_item_t::tabulation;
+ fpar->argN_ = format_item_t::argN_tabulation;
+ break;
+ case 't':
+ fpar->fmtstate_.fill_ = const_or_not(fac).widen( ' ');
+ fpar->pad_scheme_ |= format_item_t::tabulation;
+ fpar->argN_ = format_item_t::argN_tabulation;
+ break;
+
+ case 'G':
+ fpar->fmtstate_.flags_ |= std::ios_base::uppercase;
+ break;
+ case 'g': // 'g' conversion is default for floats.
+ fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
+ fpar->fmtstate_.flags_ |= std::ios_base::dec;
+
+ // CLEAR all floatield flags, so stream will CHOOSE
+ fpar->fmtstate_.flags_ &= ~std::ios_base::floatfield;
+ break;
+
+ case 'C':
+ case 'c':
+ fpar->truncate_ = 1;
+ break;
+ case 'S':
+ case 's':
+ if(precision_set) // handle truncation manually, with own parameter.
+ fpar->truncate_ = fpar->fmtstate_.precision_;
+ fpar->fmtstate_.precision_ = 6; // default stream precision.
+ break;
+ case 'n' :
+ fpar->argN_ = format_item_t::argN_ignored;
+ break;
+ default:
+ maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ }
+ ++start;
+
+ if( in_brackets ) {
+ if( start != last && *start== const_or_not(fac).widen( '|') ) {
+ ++start;
+ return true;
+ }
+ else maybe_throw_exception(exceptions, start-start0+offset, fstring_size);
+ }
+ return true;
+ }
+ // -end parse_printf_directive()