Boost logo

Boost :

From: Alisdair Meredith (alisdair.meredith_at_[hidden])
Date: 2002-12-20 07:40:03


Ok, now I have access to BCB6 I have tracked down the failures to some
problems with std::isdigit.

For some reason isdigit is trying to instantiate the ctype facet for
const char, ctype<const char>. I haven't worked out the reason this
instantiation is required, but by replacing all calls to isdigit in
parsing.hpp with the 'equivalent' code below ( borrowed straight from
Josutti's The Standard C++ Library ) CBuilder6 passes all format tests
(with compiler warnings for binding non-const references to temporaries)

#if defined( __BORLANDC__ )
  while ( i1 < buf.size()
        && std::use_facet<std::ctype<Ch> >( oss_.rdbuf()->getloc() ).is(
std::ctype_base::digit, buf[i1] )
        )
#else
  while(i1 < buf.size() && isdigit(buf[i1],oss_.rdbuf()->getloc()))
#endif
    ++i1;

Attached is the fully updated parsing.hpp file

-- 
AlisdairM

// -*- C++ -*-
// Boost general library 'format' ---------------------------
// See http://www.boost.org for updates, documentation, and revision history.

// (C) Samuel Krempp 2001
// krempp_at_[hidden]
// 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

#ifdef BOOST_MSVC
#ifdef isdigit
#undef isdigit
#endif
#endif // MSVC workaround

#include "boost/format/format_class.hpp"
#include "boost/throw_exception.hpp"

namespace boost {
namespace io {
namespace detail {

  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
    // Returns : n
  {
    using namespace std; // isdigit is better without 'std::' for borland 0x560
    Res n = 0;
#if defined( __BORLANDC__ )
    while ( start<s.size()
          && std::use_facet<std::ctype<Ch> >( os.rdbuf()->getloc() ).is( std::ctype_base::digit, s[start] )
          )
#else
    while(start<s.size() && isdigit(s[start], os.rdbuf()->getloc() ) )
#endif
    {
      char cur_ch = os.narrow( s[start], 0);
      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;
  }

  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.
    // Effects : advance *pos_p by skipping printf's asterisk fields.
    // Returns : nothing
  {
    using namespace std; // isdigit is better without 'std::' for borland 0x560
    assert( pos_p != 0);
    if(*pos_p >= buf.size() ) return;
    if(buf[ *pos_p]==os.widen('*')) {
      ++ (*pos_p);
#if defined( __BORLANDC__ )
      while ( *pos_p < buf.size()
            && std::use_facet<std::ctype<Ch> >( os.rdbuf()->getloc() ).is( std::ctype_base::digit, buf[*pos_p] )
            )
#else
      while (*pos_p < buf.size() && isdigit(buf[*pos_p],os.rdbuf()->getloc()))
#endif
        ++(*pos_p);
      if(buf[*pos_p]==os.widen('$')) ++(*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());
  }
    

  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
  {
    using namespace std; // isdigit is better without 'std::' for borland 0x560
    typedef format_item<Ch, Tr> format_item_t;
    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(buf[i1]==os.widen('0'))
      goto parse_flags;

    // handle argument order (%2$d) or possibly width specification: %2d
    i0 = i1; // save position before digits
#if defined( __BORLANDC__ )
    while ( i1 < buf.size()
          && std::use_facet<std::ctype<Ch> >( os.rdbuf()->getloc() ).is( std::ctype_base::digit, buf[i1] )
          )
#else
    while (i1 < buf.size() && isdigit(buf[i1], os.rdbuf()->getloc()))
#endif
      ++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] == 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;
            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_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->ref_state_.flags_ |= std::ios_base::showpoint | std::ios_base::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
#if defined( __BORLANDC__ )
    while ( i1 < buf.size()
          && std::use_facet<std::ctype<Ch> >( os.rdbuf()->getloc() ).is( std::ctype_base::digit, buf[i1] )
          )
#else
    while (i1<buf.size() && isdigit(buf[i1], os.rdbuf()->getloc()))
#endif
      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]==os.widen('.'))
      {
        ++i1;
        skip_asterisk(buf, &i1, os);
        i0 = i1; // save position before digits
#if defined( __BORLANDC__ )
        while ( i1 < buf.size()
              && std::use_facet<std::ctype<Ch> >( os.rdbuf()->getloc() ).is( std::ctype_base::digit, buf[i1] )
              )
#else
        while (i1<buf.size() && isdigit(buf[i1], os.rdbuf()->getloc()))
#endif
          ++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;
    }
    
    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..) :
#if defined( __BORLANDC__ )
      while ( i1 < buf.size()
            && std::use_facet<std::ctype<Ch> >( oss_.rdbuf()->getloc() ).is( std::ctype_base::digit, buf[i1] )
            )
#else
      while(i1 < buf.size() && isdigit(buf[i1],oss_.rdbuf()->getloc()))
#endif
        ++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;
      }
      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
    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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk