]> git.lyx.org Git - lyx.git/blobdiff - boost/boost/format/parsing.hpp
Don't allow newline characters in document settings.
[lyx.git] / boost / boost / format / parsing.hpp
index 1e8bd904c38ccc427ba7c688301fa311f57a677d..b14ca82c984699c12fa0dcdb4a8285609aedc85c 100644 (file)
@@ -1,28 +1,22 @@
-// -*- C++ -*-
-//  Boost general library 'format'   ---------------------------
-//  See http://www.boost.org for updates, documentation, and revision history.
-
-//  (C) Samuel Krempp 2001
-//                  krempp@crans.ens-cachan.fr
-//  Permission to copy, use, modify, sell and
-//  distribute this software is granted provided this copyright notice appears
-//  in all copies. This software is provided "as is" without express or implied
-//  warranty, and with no claim as to its suitability for any purpose.
-
-// ideas taken from Rudiger Loos's format class
-// and Karl Nelson's ofstream (also took its parsing code as basis for printf parsing)
-
-// ------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
 // parsing.hpp :  implementation of the parsing member functions
 //                      ( parse, parse_printf_directive)
-// ------------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+
+//  Copyright Samuel Krempp 2003. Use, modification, and distribution are
+//  subject to the Boost Software License, Version 1.0. (See accompanying
+//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// see http://www.boost.org/libs/format for library home page
 
+// ----------------------------------------------------------------------------
 
 #ifndef BOOST_FORMAT_PARSING_HPP
 #define BOOST_FORMAT_PARSING_HPP
 
 
 #include <boost/format/format_class.hpp>
+#include <boost/format/exceptions.hpp>
 #include <boost/throw_exception.hpp>
 #include <boost/assert.hpp>
 
@@ -31,425 +25,478 @@ namespace boost {
 namespace io {
 namespace detail {
 
-  template<class Ch, class Stream> inline
-  bool wrap_isdigit(Ch c, Stream &os) 
-  {
-#ifndef BOOST_NO_LOCALE_ISIDIGIT
-    return std::isdigit(c, os.rdbuf()->getloc() );
+#if defined(BOOST_NO_STD_LOCALE)
+    // streams will be used for narrow / widen. but these methods are not const
+    template<class T>
+    T& const_or_not(const T& x) { 
+        return const_cast<T&> (x);
+    }
+#else
+    template<class T>
+    const T& const_or_not(const T& x) { 
+        return x;
+    }
+#endif
+
+    template<class Ch, class Facet> inline
+    char wrap_narrow(const Facet& fac, Ch c, char deflt) {
+        return const_or_not(fac).narrow(c, deflt);
+    }
+
+    template<class Ch, class Facet> inline
+    bool wrap_isdigit(const Facet& fac, Ch c) {
+#if ! defined( BOOST_NO_LOCALE_ISDIGIT )
+        return fac.is(std::ctype<Ch>::digit, c);
 # else
-    using namespace std;
-    return isdigit(c); 
+        (void) fac;     // remove "unused parameter" warning
+        using namespace std;
+        return isdigit(c); 
 #endif 
-  } //end- wrap_isdigit(..)
-
-  template<class Res, class Ch, class Tr> inline
-  Res str2int(const std::basic_string<Ch, Tr>& s, 
-              typename std::basic_string<Ch, Tr>::size_type start, 
-              BOOST_IO_STD basic_ios<Ch,Tr> &os,
-              const Res = Res(0)  ) 
-    // Input : char string, with starting index
-    //         a basic_ios& merely to call its widen/narrow member function in the desired locale.
-    // Effects : reads s[start:] and converts digits into an integral n, of type Res
+    }
+    template<class Iter, class Facet> 
+    Iter wrap_scan_notdigit(const Facet & fac, Iter beg, Iter end) {
+        using namespace std;
+        for( ; beg!=end && wrap_isdigit(fac, *beg); ++beg) ;
+        return beg;
+    }
+
+
+    // Input : [start, last) iterators range and a
+    //          a Facet to use its widen/narrow member function
+    // Effects : read sequence and convert digits into integral n, of type Res
     // Returns : n
-  {
-    Res n = 0;
-    while(start<s.size() && wrap_isdigit(s[start], os) ) {
-      char cur_ch = os.narrow( s[start], 0);
-      BOOST_ASSERT(cur_ch != 0 ); // since we called isdigit, this should not happen.
-      n *= 10;
-      n += cur_ch - '0'; // 22.2.1.1.2 of the C++ standard
-      ++start;
+    template<class Res, class Iter, class Facet>
+    Iter str2int (const Iter & start, const Iter & last, Res & res, 
+                 const Facet& fac) 
+    {
+        using namespace std;
+        Iter it;
+        res=0;
+        for(it=start; it != last && wrap_isdigit(fac, *it); ++it ) {
+            char cur_ch = wrap_narrow(fac, *it, 0); // cant fail.
+            res *= 10;
+            res += cur_ch - '0'; // 22.2.1.1.2.13 of the C++ standard
+        }
+        return it;
     }
-    return n;
-  }
 
-  template<class Ch, class Tr>
-  void skip_asterisk(const std::basic_string<Ch,Tr> & buf, 
-                     typename std::basic_string<Ch,Tr>::size_type * pos_p,
-                     BOOST_IO_STD basic_ios<Ch, Tr> &os)
     // skip printf's "asterisk-fields" directives in the format-string buf
     // Input : char string, with starting index *pos_p
-    //         a basic_ios& merely to call its widen/narrow member function in the desired locale.
+    //         a Facet merely to use its widen/narrow member function
     // Effects : advance *pos_p by skipping printf's asterisk fields.
     // Returns : nothing
-  {
-    using namespace std;
-    BOOST_ASSERT( pos_p != 0);
-    if(*pos_p >= buf.size() ) return;
-    if(buf[ *pos_p]==os.widen('*')) {
-      ++ (*pos_p);
-      while (*pos_p < buf.size() && wrap_isdigit(buf[*pos_p],os)) ++(*pos_p);
-      if(buf[*pos_p]==os.widen('$')) ++(*pos_p);
+    template<class Iter, class Facet>
+    Iter skip_asterisk(Iter start, Iter last, const Facet& fac) 
+    {
+        using namespace std;
+        ++ start;
+        start = wrap_scan_notdigit(fac, start, last);
+        if(start!=last && *start== const_or_not(fac).widen( '$') )
+            ++start;
+        return start;
     }
-  }
 
 
-  inline void maybe_throw_exception( unsigned char exceptions)
     // auxiliary func called by parse_printf_directive
     // for centralising error handling
     // it either throws if user sets the corresponding flag, or does nothing.
-  {
-    if(exceptions & io::bad_format_string_bit)
-          boost::throw_exception(io::bad_format_string());
-  }
+    inline void maybe_throw_exception(unsigned char exceptions, 
+                                      std::size_t pos, std::size_t size)
+    {
+        if(exceptions & io::bad_format_string_bit)
+            boost::throw_exception(io::bad_format_string(pos, size) );
+    }
     
 
+    // 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;
+            }
+        }
 
-  template<class Ch, class Tr>
-  bool parse_printf_directive(const std::basic_string<Ch, Tr> & buf,
-                              typename std::basic_string<Ch, Tr>::size_type * pos_p,
-                              detail::format_item<Ch, Tr> * fpar,
-                              BOOST_IO_STD basic_ios<Ch,Tr> &os,
-                              unsigned char exceptions)
-    // Input   : a 'printf-directive' in the format-string, starting at buf[ *pos_p ]
-    //           a basic_ios& merely to call its widen/narrow member function in the desired locale.
-    //           a bitset'excpetions' telling whether to throw exceptions on errors.
-    // Returns : true if parse somehow succeeded (possibly ignoring errors if exceptions disabled) 
-    //           false if it failed so bad that the directive should be printed verbatim
-    // Effects : - *pos_p is incremented so that buf[*pos_p] is the first char after the directive
-    //           - *fpar is set with the parameters read in the directive
-  {
-    typedef format_item<Ch, Tr>  format_item_t;
-    BOOST_ASSERT( pos_p != 0);
-    typename std::basic_string<Ch, Tr>::size_type       &i1 = *pos_p,      
-                                                        i0; 
-    fpar->argN_ = format_item_t::argN_no_posit;  // if no positional-directive
-
-    bool in_brackets=false;
-    if(buf[i1]==os.widen('|'))
-      {
-        in_brackets=true;
-        if( ++i1 >= buf.size() ) {
-          maybe_throw_exception(exceptions);
-          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;
+            }
         }
-      }
-
-    // the flag '0' would be picked as a digit for argument order, but here it's a flag :
-    if(buf[i1]==os.widen('0')) 
-      goto parse_flags;
-
-    // handle argument order (%2$d)  or possibly width specification: %2d
-    i0 = i1;  // save position before digits
-    while (i1 < buf.size() && wrap_isdigit(buf[i1], os))
-      ++i1;
-    if (i1!=i0) 
-      {
-        if( i1 >= buf.size() ) {
-          maybe_throw_exception(exceptions);
-          return false;
+    
+      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;
         }
-        int n=str2int(buf,i0, os, int(0) );
-        
-        // %N% case : this is already the end of the directive
-        if( buf[i1] == os.widen('%') ) 
-          {
-            fpar->argN_ = n-1;
-            ++i1;
-            if( in_brackets) 
-              maybe_throw_exception(exceptions); 
-              // but don't return.  maybe "%" was used in lieu of '$', so we go on.
-            else return true;
-          }
-
-        if ( buf[i1]==os.widen('$') ) 
-          {
-            fpar->argN_ = n-1;
-            ++i1;
-          } 
-        else  
-          {
-            // non-positionnal directive
-            fpar->ref_state_.width_ = n;
-            fpar->argN_  = format_item_t::argN_no_posit;
-            goto parse_precision;
-          }
-      }
     
-  parse_flags: 
-    // handle flags
-    while ( i1 <buf.size()) // as long as char is one of + - = # 0 l h   or ' '
-      {  
-        // misc switches
-        switch (os.narrow(buf[i1], 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->ref_state_.flags_ |= std::ios_base::left;
+        // 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 '=':
-            fpar->pad_scheme_ |= format_item_t::centered;
+
+        case 'o':
+            fpar->fmtstate_.flags_ &= ~std::ios_base::basefield;
+            fpar->fmtstate_.flags_ |=  std::ios_base::oct;
             break;
-          case ' ':
-            fpar->pad_scheme_ |= format_item_t::spacepad;
+
+        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 '+':
-            fpar->ref_state_.flags_ |= std::ios_base::showpos;
+      
+        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 '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.
+
+        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 '#':
-            fpar->ref_state_.flags_ |= std::ios_base::showpoint | std::ios_base::showbase;
+        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;
-          default:
-            goto parse_width;
-          }
-        ++i1;
-      } // loop on flag.
-    if( i1>=buf.size()) {
-      maybe_throw_exception(exceptions);
-      return true; 
+
+        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()
 
-  parse_width:
-    // handle width spec
-    skip_asterisk(buf, &i1, os); // skips 'asterisk fields' :  *, or *N$
-    i0 = i1;  // save position before digits
-    while (i1<buf.size() && wrap_isdigit(buf[i1], os))
-      i1++;
-    
-    if (i1!=i0) 
-      { fpar->ref_state_.width_ = str2int( buf,i0, os, std::streamsize(0) ); }
+    template<class String, class Facet>
+    int upper_bound_from_fstring(const String& buf, 
+                                 const typename String::value_type arg_mark,
+                                 const Facet& fac, 
+                                 unsigned char exceptions) 
+    {
+        // quick-parsing of the format-string to count arguments mark (arg_mark, '%')
+        // returns : upper bound on the number of format items in the format strings
+        using namespace boost::io;
+        typename String::size_type i1=0;
+        int num_items=0;
+        while( (i1=buf.find(arg_mark,i1)) != String::npos ) {
+            if( i1+1 >= buf.size() ) {
+                if(exceptions & bad_format_string_bit)
+                    boost::throw_exception(bad_format_string(i1, buf.size() )); // must not end in ".. %"
+                else {
+                  ++num_items;
+                  break;
+                }
+            }
+            if(buf[i1+1] == buf[i1] ) {// escaped "%%"
+                i1+=2; continue; 
+            }
 
-  parse_precision:
-    if( i1>=buf.size()) { 
-      maybe_throw_exception(exceptions);
-      return true;
+            ++i1;
+            // in case of %N% directives, dont count it double (wastes allocations..) :
+            i1 = detail::wrap_scan_notdigit(fac, buf.begin()+i1, buf.end()) - buf.begin();
+            if( i1 < buf.size() && buf[i1] == arg_mark )
+                ++i1;
+            ++num_items;
+        }
+        return num_items;
     }
-    // handle precision spec
-    if (buf[i1]==os.widen('.'))  
-      {
-        ++i1;
-        skip_asterisk(buf, &i1, os);
-        i0 = i1;  // save position before digits
-        while (i1<buf.size() && wrap_isdigit(buf[i1], os))
-          ++i1;
-
-        if(i1==i0)
-          fpar->ref_state_.precision_ = 0;
-        else 
-          fpar->ref_state_.precision_ = str2int(buf,i0, os, std::streamsize(0) );
-      }
-    
-    // handle  formatting-type flags :
-    while( i1<buf.size() && 
-           ( buf[i1]==os.widen('l') || buf[i1]==os.widen('L') || buf[i1]==os.widen('h')) )
-      ++i1;
-    if( i1>=buf.size()) {
-      maybe_throw_exception(exceptions);
-      return true;
+    template<class String> inline
+    void append_string(String& dst, const String& src, 
+                       const typename String::size_type beg, 
+                       const typename String::size_type end) {
+#if !defined(BOOST_NO_STRING_APPEND)
+        dst.append(src.begin()+beg, src.begin()+end);
+#else
+        dst += src.substr(beg, end-beg);
+#endif
     }
-    
-    if( in_brackets && buf[i1]==os.widen('|') ) 
-      {
-        ++i1;
-        return true;
-      }
-    switch (os.narrow(buf[i1], 0) )  
-      {
-      case 'X':
-        fpar->ref_state_.flags_ |= std::ios_base::uppercase;
-      case 'p': // pointer => set hex.
-      case 'x':
-        fpar->ref_state_.flags_ &= ~std::ios_base::basefield;
-        fpar->ref_state_.flags_ |= std::ios_base::hex;
-        break;
-      
-      case 'o':
-        fpar->ref_state_.flags_ &= ~std::ios_base::basefield;
-        fpar->ref_state_.flags_ |=  std::ios_base::oct;
-        break;
-
-      case 'E':
-        fpar->ref_state_.flags_ |=  std::ios_base::uppercase;
-      case 'e':
-        fpar->ref_state_.flags_ &= ~std::ios_base::floatfield;
-        fpar->ref_state_.flags_ |=  std::ios_base::scientific;
-
-        fpar->ref_state_.flags_ &= ~std::ios_base::basefield;
-        fpar->ref_state_.flags_ |=  std::ios_base::dec;
-        break;
-      
-      case 'f':
-        fpar->ref_state_.flags_ &= ~std::ios_base::floatfield;
-        fpar->ref_state_.flags_ |=  std::ios_base::fixed;
-      case 'u':
-      case 'd':
-      case 'i':
-        fpar->ref_state_.flags_ &= ~std::ios_base::basefield;
-        fpar->ref_state_.flags_ |=  std::ios_base::dec;
-        break;
-
-      case 'T':
-        ++i1;
-        if( i1 >= buf.size())
-          maybe_throw_exception(exceptions);
-        else
-          fpar->ref_state_.fill_ = buf[i1];
-        fpar->pad_scheme_ |= format_item_t::tabulation;
-        fpar->argN_ = format_item_t::argN_tabulation; 
-        break;
-      case 't': 
-        fpar->ref_state_.fill_ = os.widen(' ');
-        fpar->pad_scheme_ |= format_item_t::tabulation;
-        fpar->argN_ = format_item_t::argN_tabulation; 
-        break;
-
-      case 'G':
-        fpar->ref_state_.flags_ |= std::ios_base::uppercase;
-        break;
-      case 'g': // 'g' conversion is default for floats.
-        fpar->ref_state_.flags_ &= ~std::ios_base::basefield;
-        fpar->ref_state_.flags_ |=  std::ios_base::dec;
-
-        // CLEAR all floatield flags, so stream will CHOOSE
-        fpar->ref_state_.flags_ &= ~std::ios_base::floatfield; 
-        break;
-
-      case 'C':
-      case 'c': 
-        fpar->truncate_ = 1;
-        break;
-      case 'S':
-      case 's': 
-        fpar->truncate_ = fpar->ref_state_.precision_;
-        fpar->ref_state_.precision_ = -1;
-        break;
-      case 'n' :  
-        fpar->argN_ = format_item_t::argN_ignored;
-        break;
-      default: 
-        maybe_throw_exception(exceptions);
-      }
-    ++i1;
-
-    if( in_brackets )
-      {
-        if( i1<buf.size() && buf[i1]==os.widen('|') ) 
-          {
-            ++i1;
-            return true;
-          }
-        else  maybe_throw_exception(exceptions);
-      }
-    return true;
-  }
 
 } // detail namespace
 } // io namespace
 
 
+
 // -----------------------------------------------
 //  format :: parse(..)
 
-template<class Ch, class Traits>
-void basic_format<Ch, Traits> ::parse(const string_t & buf) 
-  // parse the format-string
-{
-    using namespace std;
-    const Ch arg_mark = oss_.widen('%');
-    bool ordered_args=true; 
-    int max_argN=-1;
-    typename string_t::size_type i1=0;
-    int num_items=0;
-    
-    // A: find upper_bound on num_items and allocates arrays
-    i1=0; 
-    while( (i1=buf.find(arg_mark,i1)) != string::npos ) 
-    {
-      if( i1+1 >= buf.size() ) {
-        if(exceptions() & io::bad_format_string_bit)
-          boost::throw_exception(io::bad_format_string()); // must not end in "bla bla %"
-        else break; // stop there, ignore last '%'
-      }
-      if(buf[i1+1] == buf[i1] ) { i1+=2; continue; } // escaped "%%" / "##"
-      ++i1;
-      
-      // in case of %N% directives, dont count it double (wastes allocations..) :
-      while(i1 < buf.size() && io::detail::wrap_isdigit(buf[i1],oss_)) ++i1;
-      if( i1 < buf.size() && buf[i1] == arg_mark ) ++ i1;
-
-      ++num_items;
-    }
-    items_.assign( num_items, format_item_t() );
-    
-    // B: Now the real parsing of the format string :
-    num_items=0;
-    i1 = 0;
-    typename string_t::size_type i0 = i1;
-    bool special_things=false;
-    int cur_it=0;
-    while( (i1=buf.find(arg_mark,i1)) != string::npos ) 
-    {
-      string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_;
-
-      if( buf[i1+1] == buf[i1] ) // escaped mark, '%%'
-      {
-        piece += buf.substr(i0, i1-i0) + buf[i1]; 
-        i1+=2; i0=i1;
-        continue; 
-      }
-      BOOST_ASSERT(  static_cast<unsigned int>(cur_it) < items_.size() || cur_it==0);
-
-      if(i1!=i0) piece += buf.substr(i0, i1-i0);
-      ++i1;
-      
-      bool parse_ok;
-      parse_ok = io::detail::parse_printf_directive(buf, &i1, &items_[cur_it], oss_, exceptions());
-      if( ! parse_ok ) continue; // the directive will be printed verbatim
-
-      i0=i1;
-      items_[cur_it].compute_states(); // process complex options, like zeropad, into stream params.
-
-      int argN=items_[cur_it].argN_;
-      if(argN == format_item_t::argN_ignored)
-        continue;
-      if(argN ==format_item_t::argN_no_posit)
-        ordered_args=false;
-      else if(argN == format_item_t::argN_tabulation) special_things=true;
-      else if(argN > max_argN) max_argN = argN;
-      ++num_items;
-      ++cur_it;
-    } // loop on %'s
-    BOOST_ASSERT(cur_it == num_items);
-    
-    // store the final piece of string
-    string_t & piece = (cur_it==0) ? prefix_ : items_[cur_it-1].appendix_;
-    piece += buf.substr(i0);
+    template<class Ch, class Tr, class Alloc>
+    basic_format<Ch, Tr, Alloc>& basic_format<Ch, Tr, Alloc>:: 
+    parse (const string_type& buf) {
+        // parse the format-string 
+        using namespace std;
+#if !defined(BOOST_NO_STD_LOCALE)
+        const std::ctype<Ch> & fac = BOOST_USE_FACET( std::ctype<Ch>, getloc());
+#else
+        io::basic_oaltstringstream<Ch, Tr, Alloc> fac; 
+        //has widen and narrow even on compilers without locale
+#endif
+
+        const Ch arg_mark = io::detail::const_or_not(fac).widen( '%');
+        bool ordered_args=true; 
+        int max_argN=-1;
+
+        // A: find upper_bound on num_items and allocates arrays
+        int num_items = io::detail::upper_bound_from_fstring(buf, arg_mark, fac, exceptions());
+        make_or_reuse_data(num_items);
+
+        // B: Now the real parsing of the format string :
+        num_items=0;
+        typename string_type::size_type i0=0, i1=0;
+        typename string_type::const_iterator it;
+        bool special_things=false;
+        int cur_item=0;
+        while( (i1=buf.find(arg_mark,i1)) != string_type::npos ) {
+            string_type & piece = (cur_item==0) ? prefix_ : items_[cur_item-1].appendix_;
+            if( buf[i1+1] == buf[i1] ) { // escaped mark, '%%' 
+                io::detail::append_string(piece, buf, i0, i1+1);
+                i1+=2; i0=i1;
+                continue; 
+            }
+            BOOST_ASSERT(  static_cast<unsigned int>(cur_item) < items_.size() || cur_item==0);
+
+            if(i1!=i0) {
+                io::detail::append_string(piece, buf, i0, i1);
+                i0=i1;
+            }
+            ++i1;
+            it = buf.begin()+i1;
+            bool parse_ok = io::detail::parse_printf_directive(
+                it, buf.end(), &items_[cur_item], fac, i1, exceptions());
+            i1 = it - buf.begin();
+            if( ! parse_ok ) // the directive will be printed verbatim
+                continue; 
+            i0=i1;
+            items_[cur_item].compute_states(); // process complex options, like zeropad, into params
+
+            int argN=items_[cur_item].argN_;
+            if(argN == format_item_t::argN_ignored)
+                continue;
+            if(argN ==format_item_t::argN_no_posit)
+                ordered_args=false;
+            else if(argN == format_item_t::argN_tabulation) special_things=true;
+            else if(argN > max_argN) max_argN = argN;
+            ++num_items;
+            ++cur_item;
+        } // loop on %'s
+        BOOST_ASSERT(cur_item == num_items);
     
-    if( !ordered_args) 
-    {
-      if(max_argN >= 0 )  // dont mix positional with non-positionnal directives
+        // store the final piece of string
         {
-          if(exceptions() & io::bad_format_string_bit)
-            boost::throw_exception(io::bad_format_string());
-          // else do nothing. => positionnal arguments are processed as non-positionnal
+            string_type & piece = (cur_item==0) ? prefix_ : items_[cur_item-1].appendix_;
+            io::detail::append_string(piece, buf, i0, buf.size());
+        }
+    
+        if( !ordered_args) {
+            if(max_argN >= 0 ) {  // dont mix positional with non-positionnal directives
+                if(exceptions() & io::bad_format_string_bit)
+                    boost::throw_exception(io::bad_format_string(max_argN, 0));
+                // else do nothing. => positionnal arguments are processed as non-positionnal
+            }
+            // set things like it would have been with positional directives :
+            int non_ordered_items = 0;
+            for(int i=0; i< num_items; ++i)
+                if(items_[i].argN_ == format_item_t::argN_no_posit) {
+                    items_[i].argN_ = non_ordered_items;
+                    ++non_ordered_items;
+                }
+            max_argN = non_ordered_items-1;
         }
-      // set things like it would have been with positional directives :
-      int non_ordered_items = 0;
-      for(int i=0; i< num_items; ++i)
-        if(items_[i].argN_ == format_item_t::argN_no_posit) 
-          {
-            items_[i].argN_ = non_ordered_items;
-            ++non_ordered_items;
-          }
-      max_argN = non_ordered_items-1;
-    }
     
-    // C: set some member data :
-    items_.resize(num_items);
-
-    if(special_things) style_ |= special_needs;
-    num_args_ = max_argN + 1;
-    if(ordered_args) style_ |=  ordered;
-    else style_ &= ~ordered;
-}
+        // C: set some member data :
+        items_.resize(num_items, format_item_t(io::detail::const_or_not(fac).widen( ' ')) );
+
+        if(special_things) style_ |= special_needs;
+        num_args_ = max_argN + 1;
+        if(ordered_args) style_ |=  ordered;
+        else style_ &= ~ordered;
+        return *this;
+    }
 
 } // namespace boost