* Removed references to char_traits so that boost/format also works on
GCC 2.95.
This commit is contained in:
		
							parent
							
								
									d930a9bc5a
								
							
						
					
					
						commit
						1c7d6bf5fc
					
				
					 15 changed files with 222 additions and 239 deletions
				
			
		
							
								
								
									
										454
									
								
								boost/format/parsing.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										454
									
								
								boost/format/parsing.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,454 @@ | |||
| // -*- 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)
 | ||||
| // ------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| 
 | ||||
| #ifndef BOOST_FORMAT_PARSING_HPP | ||||
| #define BOOST_FORMAT_PARSING_HPP | ||||
| 
 | ||||
| 
 | ||||
| #include <boost/format.hpp> | ||||
| //#include <boost/throw_exception.hpp>
 | ||||
| //#include <boost/assert.hpp>
 | ||||
| 
 | ||||
| 
 | ||||
| namespace boost { | ||||
| namespace io { | ||||
| namespace detail { | ||||
| 
 | ||||
|   template<class Stream> inline | ||||
|   bool wrap_isdigit(char c, Stream &os)  | ||||
|   { | ||||
| #ifndef BOOST_NO_LOCALE_ISIDIGIT | ||||
|     return std::isdigit(c, os.rdbuf()->getloc() ); | ||||
| # else | ||||
|     using namespace std; | ||||
|     return isdigit(c);  | ||||
| #endif  | ||||
|   } //end- wrap_isdigit(..)
 | ||||
| 
 | ||||
|   template<class Res> inline | ||||
|   Res str2int(const std::string& s,  | ||||
|               std::string::size_type start,  | ||||
|               BOOST_IO_STD ios &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
 | ||||
|     // Returns : n
 | ||||
|   { | ||||
|     Res n = 0; | ||||
|     while(start<s.size() && wrap_isdigit(s[start], os) ) { | ||||
|       char cur_ch = s[start]; | ||||
|       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; | ||||
|     } | ||||
|     return n; | ||||
|   } | ||||
| 
 | ||||
|   void skip_asterisk(const std::string & buf,  | ||||
|                      std::string::size_type * pos_p, | ||||
|                      BOOST_IO_STD ios &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.
 | ||||
|     // 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]=='*') { | ||||
|       ++ (*pos_p); | ||||
|       while (*pos_p < buf.size() && wrap_isdigit(buf[*pos_p],os)) ++(*pos_p); | ||||
|       if(buf[*pos_p]=='$') ++(*pos_p); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   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()); | ||||
|   } | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
|   bool parse_printf_directive(const std::string & buf, | ||||
|                               std::string::size_type * pos_p, | ||||
|                               detail::format_item * fpar, | ||||
|                               BOOST_IO_STD ios &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  format_item_t; | ||||
|     BOOST_ASSERT( pos_p != 0); | ||||
|     std::string::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]=='|') | ||||
|       { | ||||
|         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(buf[i1]=='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; | ||||
|         } | ||||
|         int n=str2int(buf,i0, os, int(0) ); | ||||
|          | ||||
|         // %N% case : this is already the end of the directive
 | ||||
|         if( buf[i1] == '%' )  | ||||
|           { | ||||
|             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]=='$' )  | ||||
|           { | ||||
|             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 (buf[i1])  | ||||
|           { | ||||
|           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::left; | ||||
|             break; | ||||
|           case '=': | ||||
|             fpar->pad_scheme_ |= format_item_t::centered; | ||||
|             break; | ||||
|           case ' ': | ||||
|             fpar->pad_scheme_ |= format_item_t::spacepad; | ||||
|             break; | ||||
|           case '+': | ||||
|             fpar->ref_state_.flags_ |= std::ios::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->ref_state_.flags_ |= std::ios::showpoint | std::ios::showbase; | ||||
|             break; | ||||
|           default: | ||||
|             goto parse_width; | ||||
|           } | ||||
|         ++i1; | ||||
|       } // loop on flag.
 | ||||
|     if( i1>=buf.size()) { | ||||
|       maybe_throw_exception(exceptions); | ||||
|       return true;  | ||||
|     } | ||||
| 
 | ||||
|   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) ); } | ||||
| 
 | ||||
|   parse_precision: | ||||
|     if( i1>=buf.size()) {  | ||||
|       maybe_throw_exception(exceptions); | ||||
|       return true; | ||||
|     } | ||||
|     // handle precision spec
 | ||||
|     if (buf[i1]=='.')   | ||||
|       { | ||||
|         ++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]=='l' || buf[i1]=='L' || buf[i1]=='h') ) | ||||
|       ++i1; | ||||
|     if( i1>=buf.size()) { | ||||
|       maybe_throw_exception(exceptions); | ||||
|       return true; | ||||
|     } | ||||
|      | ||||
|     if( in_brackets && buf[i1]=='|' )  | ||||
|       { | ||||
|         ++i1; | ||||
|         return true; | ||||
|       } | ||||
|     switch (buf[i1])   | ||||
|       { | ||||
|       case 'X': | ||||
|         fpar->ref_state_.flags_ |= std::ios::uppercase; | ||||
|       case 'p': // pointer => set hex.
 | ||||
|       case 'x': | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::basefield; | ||||
|         fpar->ref_state_.flags_ |= std::ios::hex; | ||||
|         break; | ||||
|        | ||||
|       case 'o': | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::basefield; | ||||
|         fpar->ref_state_.flags_ |=  std::ios::oct; | ||||
|         break; | ||||
| 
 | ||||
|       case 'E': | ||||
|         fpar->ref_state_.flags_ |=  std::ios::uppercase; | ||||
|       case 'e': | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::floatfield; | ||||
|         fpar->ref_state_.flags_ |=  std::ios::scientific; | ||||
| 
 | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::basefield; | ||||
|         fpar->ref_state_.flags_ |=  std::ios::dec; | ||||
|         break; | ||||
|        | ||||
|       case 'f': | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::floatfield; | ||||
|         fpar->ref_state_.flags_ |=  std::ios::fixed; | ||||
|       case 'u': | ||||
|       case 'd': | ||||
|       case 'i': | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::basefield; | ||||
|         fpar->ref_state_.flags_ |=  std::ios::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_ = ' '; | ||||
|         fpar->pad_scheme_ |= format_item_t::tabulation; | ||||
|         fpar->argN_ = format_item_t::argN_tabulation;  | ||||
|         break; | ||||
| 
 | ||||
|       case 'G': | ||||
|         fpar->ref_state_.flags_ |= std::ios::uppercase; | ||||
|         break; | ||||
|       case 'g': // 'g' conversion is default for floats.
 | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::basefield; | ||||
|         fpar->ref_state_.flags_ |=  std::ios::dec; | ||||
| 
 | ||||
|         // CLEAR all floatield flags, so stream will CHOOSE
 | ||||
|         fpar->ref_state_.flags_ &= ~std::ios::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]=='|' )  | ||||
|           { | ||||
|             ++i1; | ||||
|             return true; | ||||
|           } | ||||
|         else  maybe_throw_exception(exceptions); | ||||
|       } | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
| } // detail namespace
 | ||||
| } // io namespace
 | ||||
| 
 | ||||
| 
 | ||||
| // -----------------------------------------------
 | ||||
| //  format :: parse(..)
 | ||||
| 
 | ||||
| void basic_format::parse(const string_t & buf)  | ||||
|   // parse the format-string
 | ||||
| { | ||||
|     using namespace std; | ||||
|     const char arg_mark = '%'; | ||||
|     bool ordered_args=true;  | ||||
|     int max_argN=-1; | ||||
|     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; | ||||
|     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); | ||||
|      | ||||
|     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()); | ||||
|           // 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; | ||||
|     } | ||||
|      | ||||
|     // 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; | ||||
| } | ||||
| 
 | ||||
| } // namespace boost
 | ||||
| 
 | ||||
| 
 | ||||
| #endif //  BOOST_FORMAT_PARSING_HPP
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue