Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

locale.cc

Go to the documentation of this file.
00001 // Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
00002 //
00003 // This file is part of the GNU ISO C++ Library.  This library is free
00004 // software; you can redistribute it and/or modify it under the
00005 // terms of the GNU General Public License as published by the
00006 // Free Software Foundation; either version 2, or (at your option)
00007 // any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 
00014 // You should have received a copy of the GNU General Public License along
00015 // with this library; see the file COPYING.  If not, write to the Free
00016 // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
00017 // USA.
00018 
00019 // As a special exception, you may use this file as part of a free software
00020 // library without restriction.  Specifically, if other files instantiate
00021 // templates or use macros or inline functions from this file, or you compile
00022 // this file and link it with other files to produce an executable, this
00023 // file does not by itself cause the resulting executable to be covered by
00024 // the GNU General Public License.  This exception does not however
00025 // invalidate any other reasons why the executable file might be covered by
00026 // the GNU General Public License.
00027 
00028 #include <bits/std_clocale.h>
00029 #include <bits/std_cstring.h>
00030 #include <bits/std_cassert.h>
00031 #include <bits/std_cctype.h>
00032 #include <bits/std_limits.h>
00033 #include <exception>
00034 #include <bits/std_stdexcept.h>
00035 #include <bits/std_locale.h>
00036 #include <bits/std_istream.h>
00037 #include <bits/std_ostream.h>
00038 #include <bits/std_vector.h>
00039 #include <bits/std_memory.h>      // for auto_ptr
00040 #ifdef _GLIBCPP_USE_WCHAR_T  
00041 # include <bits/std_cwctype.h>     // for towupper, etc.
00042 #endif
00043 
00044 namespace std 
00045 {
00046   // Definitions for static const data members of locale.
00047   const locale::category    locale::none;
00048   const locale::category    locale::ctype;
00049   const locale::category    locale::numeric;
00050   const locale::category    locale::collate;
00051   const locale::category    locale::time;
00052   const locale::category    locale::monetary;
00053   const locale::category    locale::messages;
00054   const locale::category    locale::all;
00055 
00056   locale::_Impl*        locale::_S_classic;
00057   locale::_Impl*        locale::_S_global; 
00058   const size_t          locale::_S_num_categories;
00059   const size_t          locale::_S_num_facets;
00060 
00061   // Definitions for locale::id of standard facets. 
00062   locale::id ctype<char>::id;
00063   locale::id codecvt<char, char, mbstate_t>::id;
00064 
00065 #ifdef _GLIBCPP_USE_WCHAR_T  
00066   locale::id ctype<wchar_t>::id;
00067   locale::id codecvt<wchar_t, char, mbstate_t>::id;
00068 #endif
00069 
00070   // Definitions for static const data members of locale::id
00071   size_t locale::id::_S_highwater;  // init'd to 0 by linker
00072 
00073   // Definitions for static const data members of locale::_Impl
00074   const locale::id* const
00075   locale::_Impl::_S_id_ctype[] =
00076   {
00077     &std::ctype<char>::id, 
00078     &codecvt<char, char, mbstate_t>::id,
00079 #ifdef _GLIBCPP_USE_WCHAR_T
00080     &std::ctype<wchar_t>::id,
00081     &codecvt<wchar_t, char, mbstate_t>::id,
00082 #endif
00083     0
00084   };
00085 
00086   const locale::id* const
00087   locale::_Impl::_S_id_numeric[] =
00088   {
00089     &num_get<char>::id,  
00090     &num_put<char>::id,  
00091     &numpunct<char>::id, 
00092 #ifdef _GLIBCPP_USE_WCHAR_T
00093     &num_get<wchar_t>::id,
00094     &num_put<wchar_t>::id,
00095     &numpunct<wchar_t>::id,
00096 #endif
00097     0
00098   };
00099   
00100   const locale::id* const
00101   locale::_Impl::_S_id_collate[] =
00102   {
00103     &std::collate<char>::id,
00104 #ifdef _GLIBCPP_USE_WCHAR_T
00105     &std::collate<wchar_t>::id,
00106 #endif
00107     0
00108   };
00109 
00110   const locale::id* const
00111   locale::_Impl::_S_id_time[] =
00112   {
00113     &time_get<char>::id, 
00114     &time_put<char>::id, 
00115 #ifdef _GLIBCPP_USE_WCHAR_T
00116     &time_get<wchar_t>::id,
00117     &time_put<wchar_t>::id,
00118 #endif
00119     0
00120   };
00121   
00122   const locale::id* const
00123   locale::_Impl::_S_id_monetary[] =
00124   {
00125     &money_get<char>::id,        
00126     &money_put<char>::id,        
00127     &moneypunct<char, false>::id, 
00128     &moneypunct<char, true >::id, 
00129 #ifdef _GLIBCPP_USE_WCHAR_T
00130     &money_get<wchar_t>::id,
00131     &money_put<wchar_t>::id,
00132     &moneypunct<wchar_t, false>::id,
00133     &moneypunct<wchar_t, true >::id,
00134 #endif
00135     0
00136   };
00137 
00138   const locale::id* const
00139   locale::_Impl::_S_id_messages[] =
00140   {
00141     &std::messages<char>::id, 
00142 #ifdef _GLIBCPP_USE_WCHAR_T
00143     &std::messages<wchar_t>::id,
00144 #endif
00145     0
00146   };
00147   
00148   const locale::id* const* const
00149   locale::_Impl::_S_facet_categories[] =
00150   {
00151     // Order must match the decl order in class locale.
00152     locale::_Impl::_S_id_ctype,
00153     locale::_Impl::_S_id_numeric,
00154     locale::_Impl::_S_id_collate,
00155     locale::_Impl::_S_id_time,
00156     locale::_Impl::_S_id_monetary,
00157     locale::_Impl::_S_id_messages,
00158     0
00159   };
00160 
00161   // Construct and return valid pattern consisting of some combination of:
00162   // space none symbol sign value
00163   money_base::pattern
00164   money_base::_S_construct_pattern(char __preceeds, char __space, char __posn)
00165   { 
00166     pattern __ret;
00167 
00168     // This insanely complicated routine attempts to construct a valid
00169     // pattern for use with monyepunct. A couple of invariants:
00170 
00171     // if (__preceeds) symbol -> value
00172     // else value -> symbol
00173     
00174     // if (__space) space
00175     // else none
00176 
00177     // none == never first
00178     // space never first or last
00179 
00180     // Any elegant implementations of this are welcome.
00181     switch (__posn)
00182       {
00183       case 1:
00184     // 1 The sign precedes the value and symbol.
00185     if (__space)
00186       {
00187         // Pattern starts with sign.
00188         if (__preceeds)
00189           {
00190         __ret.field[1] = symbol;
00191         __ret.field[2] = space;
00192         __ret.field[3] = value;
00193           }
00194         else
00195           {
00196         __ret.field[1] = value;
00197         __ret.field[2] = space;
00198         __ret.field[3] = symbol;
00199           }
00200         __ret.field[0] = sign;
00201       }
00202     else
00203       {
00204         // Pattern starts with sign and ends with none.
00205         if (__preceeds)
00206           {
00207         __ret.field[1] = symbol;
00208         __ret.field[2] = value;
00209           }
00210         else
00211           {
00212         __ret.field[1] = value;
00213         __ret.field[2] = symbol;
00214           }
00215         __ret.field[0] = sign;
00216         __ret.field[3] = none;
00217       }
00218     break;
00219       case 2:
00220     // 2 The sign follows the value and symbol.
00221     if (__space)
00222       {
00223         // Pattern either ends with sign.
00224         if (__preceeds)
00225           {
00226         __ret.field[0] = symbol;
00227         __ret.field[1] = space;
00228         __ret.field[2] = value;
00229           }
00230         else
00231           {
00232         __ret.field[0] = value;
00233         __ret.field[1] = space;
00234         __ret.field[2] = symbol;
00235           }
00236         __ret.field[3] = sign;
00237       }
00238     else
00239       {
00240         // Pattern ends with sign then none.
00241         if (__preceeds)
00242           {
00243         __ret.field[0] = symbol;
00244         __ret.field[1] = value;
00245           }
00246         else
00247           {
00248         __ret.field[0] = value;
00249         __ret.field[1] = symbol;
00250           }
00251         __ret.field[2] = sign;
00252         __ret.field[3] = none;
00253       }
00254     break;
00255       case 3:
00256     // 3 The sign immediately precedes the symbol.
00257     if (__space)
00258       {
00259         // Have space.
00260         if (__preceeds)
00261           {
00262         __ret.field[0] = sign;
00263         __ret.field[1] = symbol;
00264         __ret.field[2] = space;
00265         __ret.field[3] = value;
00266           }
00267         else
00268           {
00269         __ret.field[0] = value;
00270         __ret.field[1] = space;
00271         __ret.field[2] = sign;
00272         __ret.field[3] = symbol;
00273           }
00274       }
00275     else
00276       {
00277         // Have none.
00278         if (__preceeds)
00279           {
00280         __ret.field[0] = sign;
00281         __ret.field[1] = symbol;
00282         __ret.field[2] = value;
00283           }
00284         else
00285           {
00286         __ret.field[0] = value;
00287         __ret.field[1] = sign;
00288         __ret.field[2] = symbol;
00289           }
00290         __ret.field[3] = none;
00291       }
00292     break;
00293       case 4:
00294     // 4 The sign immediately follows the symbol. 
00295     if (__space)
00296       {
00297         // Have space.
00298         if (__preceeds)
00299           {
00300         __ret.field[0] = symbol;
00301         __ret.field[1] = sign;
00302         __ret.field[2] = space;
00303         __ret.field[3] = value;
00304           }
00305         else
00306           {
00307         __ret.field[0] = value;
00308         __ret.field[1] = space;
00309         __ret.field[2] = symbol;
00310         __ret.field[3] = sign;
00311           }
00312       }
00313     else
00314       {
00315         // Have none.
00316         if (__preceeds)
00317           {
00318         __ret.field[0] = symbol;
00319         __ret.field[1] = sign;
00320         __ret.field[2] = value;
00321           }
00322         else
00323           {
00324         __ret.field[0] = value;
00325         __ret.field[1] = symbol;
00326         __ret.field[2] = sign;
00327           }
00328         __ret.field[3] = none;
00329       }
00330     break;
00331       default:
00332     ;
00333       }
00334     return __ret;
00335   }
00336 
00337   locale::~locale() throw()
00338   { _M_impl->_M_remove_reference(); }
00339 
00340   void
00341   locale::_M_coalesce(const locale& __base, const locale& __add, 
00342               category __cat)
00343   {
00344     __cat = _S_normalize_category(__cat);  
00345     _M_impl = new _Impl(*__base._M_impl, 1);  
00346 
00347     try 
00348       { _M_impl->_M_replace_categories(__add._M_impl, __cat); }
00349     catch (...) 
00350       { 
00351     _M_impl->_M_remove_reference(); 
00352     __throw_exception_again;
00353       }
00354   }
00355 
00356   locale::locale() throw()
00357   { 
00358     _S_initialize(); 
00359     (_M_impl = _S_global)->_M_add_reference(); 
00360   } // XXX MT
00361 
00362   locale::locale(const locale& __other) throw()
00363   { (_M_impl = __other._M_impl)->_M_add_reference(); }
00364 
00365   locale::locale(_Impl* __ip) throw()
00366   : _M_impl(__ip)
00367   { __ip->_M_add_reference(); }
00368 
00369   locale::locale(const char* __s)
00370   {
00371     if (__s)
00372       {
00373     if (strcmp(__s, "C") == 0 || strcmp(__s, "POSIX") == 0)
00374       (_M_impl = _S_classic)->_M_add_reference();
00375     else
00376       _M_impl = new _Impl(__s, 1);
00377       }
00378     else
00379       __throw_runtime_error("attempt to create locale from NULL name");
00380   }
00381 
00382   locale::locale(const locale& __base, const char* __s, category __cat)
00383   { 
00384     // NB: There are complicated, yet more efficient ways to do
00385     // this. Building up locales on a per-category way is tedious, so
00386     // let's do it this way until people complain.
00387     locale __add(__s);
00388     _M_coalesce(__base, __add, __cat);
00389   }
00390 
00391   locale::locale(const locale& __base, const locale& __add, category __cat)
00392   { _M_coalesce(__base, __add, __cat); }
00393 
00394   bool
00395   locale::operator==(const locale& __rhs) const throw()
00396   {
00397     string __name = this->name();
00398     return (_M_impl == __rhs._M_impl 
00399         || (__name != "*" && __name == __rhs.name()));
00400   }
00401 
00402   const locale&
00403   locale::operator=(const locale& __other) throw()
00404   {
00405     __other._M_impl->_M_add_reference();
00406     _M_impl->_M_remove_reference();
00407     _M_impl = __other._M_impl;
00408     return *this;
00409   }
00410 
00411   locale
00412   locale::global(const locale& __other)
00413   {
00414     // XXX MT
00415     _S_initialize();
00416     locale __old(_S_global);
00417     __other._M_impl->_M_add_reference();
00418     _S_global->_M_remove_reference();
00419     _S_global = __other._M_impl; 
00420     if (_S_global->_M_check_same_name() && _S_global->_M_names[0] != "*")
00421       setlocale(LC_ALL, __other.name().c_str());
00422     return __old;
00423   }
00424 
00425   string
00426   locale::name() const
00427   {
00428     string __ret;
00429     // Need some kind of separator character. This one was pretty much
00430     // arbitrarily chosen as to not conflict with glibc locales: the
00431     // exact formatting is not set in stone.
00432     const char __separator = '|';
00433 
00434     if (_M_impl->_M_check_same_name())
00435       __ret = _M_impl->_M_names[0];
00436     else
00437       {
00438     for (size_t i = 0; i < _S_num_categories; ++i)
00439       __ret += __separator + _M_impl->_M_names[i];
00440       }
00441     return __ret;
00442   }
00443 
00444   locale const&
00445   locale::classic()
00446   {
00447     static locale* __classic_locale;
00448     // XXX MT
00449     if (!_S_classic)
00450       {
00451     try 
00452       {
00453         // 26 Standard facets, 2 references.
00454         // One reference for _M_classic, one for _M_global
00455         _S_classic = new _Impl("C", 2);
00456         _S_global = _S_classic;         
00457 
00458         // Finesse static init order hassles
00459         __classic_locale = new locale(_S_classic);
00460       }
00461     catch(...) 
00462       {
00463         delete __classic_locale;
00464         if (_S_classic)
00465           {
00466         _S_classic->_M_remove_reference();
00467         _S_global->_M_remove_reference();
00468           }
00469         _S_classic = _S_global = 0;
00470         // XXX MT
00471         __throw_exception_again;
00472       }
00473       }
00474     return *__classic_locale;
00475   }
00476 
00477   locale::category
00478   locale::_S_normalize_category(category __cat) 
00479   {
00480     int __ret = 0;
00481     if (__cat == none || (__cat & all) && !(__cat & ~all))
00482       __ret = __cat;
00483     else
00484       {
00485     // NB: May be a C-style "LC_ALL" category; convert.
00486     switch (__cat)
00487       {
00488       case LC_COLLATE:  
00489         __ret = collate; 
00490         break;
00491       case LC_CTYPE:    
00492         __ret = ctype;
00493         break;
00494       case LC_MONETARY: 
00495         __ret = monetary;
00496         break;
00497       case LC_NUMERIC:  
00498         __ret = numeric;
00499         break;
00500       case LC_TIME:     
00501         __ret = time; 
00502         break;
00503 #ifdef _GLIBCPP_HAVE_LC_MESSAGES
00504       case LC_MESSAGES: 
00505         __ret = messages;
00506         break;
00507 #endif  
00508       case LC_ALL:      
00509         __ret = all;
00510         break;
00511       default:
00512         __throw_runtime_error("bad locale category");
00513       }
00514       }
00515     return __ret;
00516   }
00517 
00518   locale::facet::
00519   facet(size_t __refs) throw()
00520   : _M_references(__refs) 
00521   { }
00522 
00523   void  
00524   locale::facet::
00525   _M_add_reference() throw()
00526   { ++_M_references; }                     // XXX MT
00527 
00528   void  
00529   locale::facet::
00530   _M_remove_reference() throw()
00531   {
00532     if (_M_references)
00533       --_M_references;
00534     else
00535       {
00536         try 
00537       { delete this; }  // XXX MT
00538     catch (...) 
00539       { }
00540       }
00541   }
00542   
00543   // Definitions for static const data members of ctype_base.
00544   const ctype_base::mask ctype_base::space;
00545   const ctype_base::mask ctype_base::print;
00546   const ctype_base::mask ctype_base::cntrl;
00547   const ctype_base::mask ctype_base::upper;
00548   const ctype_base::mask ctype_base::lower;
00549   const ctype_base::mask ctype_base::alpha;
00550   const ctype_base::mask ctype_base::digit;
00551   const ctype_base::mask ctype_base::punct;
00552   const ctype_base::mask ctype_base::xdigit;
00553   const ctype_base::mask ctype_base::alnum;
00554   const ctype_base::mask ctype_base::graph;
00555 
00556   // Platform-specific initialization code for ctype tables.
00557   #include <bits/ctype_noninline.h>
00558 
00559   const size_t ctype<char>::table_size;
00560 
00561   ctype<char>::~ctype()
00562   { if (_M_del) delete[] this->table(); }
00563 
00564   // These are dummy placeholders as these virtual functions are never called.
00565   bool 
00566   ctype<char>::do_is(mask, char_type) const 
00567   { return false; }
00568   
00569   const char*
00570   ctype<char>::do_is(const char_type* __c, const char_type*, mask*) const 
00571   { return __c; }
00572   
00573   const char*
00574   ctype<char>::do_scan_is(mask, const char_type* __c, const char_type*) const 
00575   { return __c; }
00576 
00577   const char* 
00578   ctype<char>::do_scan_not(mask, const char_type* __c, const char_type*) const
00579   { return __c; }
00580 
00581   char
00582   ctype<char>::do_widen(char __c) const
00583   { return __c; }
00584   
00585   const char* 
00586   ctype<char>::do_widen(const char* __low, const char* __high, 
00587             char* __dest) const
00588   {
00589     memcpy(__dest, __low, __high - __low);
00590     return __high;
00591   }
00592   
00593   char
00594   ctype<char>::do_narrow(char __c, char /*__dfault*/) const
00595   { return __c; }
00596   
00597   const char* 
00598   ctype<char>::do_narrow(const char* __low, const char* __high, 
00599              char /*__dfault*/, char* __dest) const
00600   {
00601     memcpy(__dest, __low, __high - __low);
00602     return __high;
00603   }
00604 
00605   ctype_byname<char>::ctype_byname(const char* /*__s*/, size_t __refs)
00606   : ctype<char>(new mask[table_size], true, __refs)
00607   { }
00608 
00609   // Definitions for static const data members of money_base
00610   const money_base::pattern 
00611   money_base::_S_default_pattern =  {{symbol, sign, none, value}};
00612 
00613   template<>
00614     _Format_cache<char>::_Format_cache()
00615     : _M_valid(true),
00616     _M_decimal_point('.'), _M_thousands_sep(','),
00617     _M_truename("true"), _M_falsename("false"), _M_use_grouping(false)
00618     { }
00619 
00620 #ifdef _GLIBCPP_USE_WCHAR_T
00621   template<>
00622     _Format_cache<wchar_t>::_Format_cache()
00623     : _M_valid(true),
00624     _M_decimal_point(L'.'), _M_thousands_sep(L','),
00625     _M_truename(L"true"), _M_falsename(L"false"), _M_use_grouping(false)
00626     { }
00627 #endif
00628 
00629   template<>
00630     const ctype<char>&
00631     use_facet<ctype<char> >(const locale& __loc)
00632     {
00633       size_t __i = ctype<char>::id._M_index;
00634       const locale::_Impl* __tmp = __loc._M_impl;
00635       return static_cast<const ctype<char>&>(* (*(__tmp->_M_facets))[__i]);
00636     }
00637 
00638 #ifdef _GLIBCPP_USE_WCHAR_T
00639   template<>
00640     const ctype<wchar_t>&
00641     use_facet<ctype<wchar_t> >(const locale& __loc)
00642     {
00643       size_t __i = ctype<wchar_t>::id._M_index;
00644       const locale::_Impl* __tmp = __loc._M_impl;
00645       return static_cast<const ctype<wchar_t>&>(* (*(__tmp->_M_facets))[__i]);
00646     }
00647 #endif
00648 
00649   template<>
00650     void
00651     num_get<char, istreambuf_iterator<char> >::
00652     _M_extract(istreambuf_iterator<char> __beg, 
00653            istreambuf_iterator<char> __end, ios_base& __io, 
00654            ios_base::iostate& __err, char* __xtrc, int& __base, 
00655            bool __fp) const
00656     {
00657       typedef _Format_cache<char> __cache_type; 
00658 
00659       // Prepare for possible failure
00660       __xtrc[0] = '\0';
00661 
00662       // Stage 1: determine a conversion specifier.
00663       ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield;
00664       if (__basefield == ios_base::dec)
00665         __base = 10;
00666       else if (__basefield == ios_base::oct)
00667         __base = 8;
00668       else if (__basefield == ios_base::hex)
00669         __base = 16;
00670       else
00671         __base = 0;
00672       // As far as I can tell, bases other than 10 are not available for
00673       // floating point types
00674       if (__fp)
00675         __base = 10;
00676 
00677       // Stage 2: extract characters.
00678       __cache_type const* __fmt = __cache_type::_S_get(__io);
00679       bool __valid = __beg != __end;
00680       // Fail quickly if !__valid
00681       if (!__valid)
00682         {
00683           __err |= (ios_base::eofbit | ios_base::failbit);
00684           return;
00685         }
00686 
00687       // Acceptable formats for numbers here are based on 22.2.3.1
00688       string __grp;
00689       int __sep_pos = 0;
00690       int __pos = 0;
00691       const char* __lits = __fmt->_S_literals;
00692       char __c = *__beg;
00693 
00694       // Check first for sign
00695       bool __testsign = false;
00696       if ((__c == __lits[__cache_type::_S_minus])
00697           || (__c == __lits[__cache_type::_S_plus]))
00698         {
00699           __xtrc[__pos++] = __c;
00700           ++__beg;
00701           __testsign = true;
00702           // whitespace may follow a sign
00703           while ((__beg != __end) && (isspace(*__beg)))
00704             ++__beg;
00705 
00706           // There had better be more to come...
00707           if (__beg == __end)
00708             {
00709               __xtrc[__pos] = '\0';
00710               __err |= (ios_base::eofbit | ios_base::failbit);
00711               return;
00712             }
00713         }
00714 
00715       bool __testzero = false;    // Has there been a leading zero?
00716 
00717       // Now check if first character is a zero
00718       __c = *__beg;
00719       if (__c == __lits[__cache_type::_S_digits])
00720         {
00721            __testzero = true;
00722            ++__beg;
00723 
00724            // We have to check for __beg == __end here. If so,
00725            // a plain '0' (possibly with a sign) can be got rid of now
00726            if (__beg == __end)
00727              {
00728                __xtrc[__pos++] = __c;
00729                __xtrc[__pos] = '\0';
00730                __err |= ios_base::eofbit;
00731                return;
00732              }
00733 
00734           // Figure out base for integer types only
00735           // Based on Table 55 of 22.2.2.1.2
00736           if (!__fp && __base != 10 && __base != 8)
00737             {
00738               // Here, __base == 0 or 16
00739               __c = *__beg;
00740               if ((__c == __lits[__cache_type::_S_x])
00741                  || (__c == __lits[__cache_type::_S_X]))
00742                 {
00743                   ++__beg;
00744                   __base = 16;
00745                   __testzero = false; // "0x" is not a leading zero
00746                 }
00747               else if (__base == 0)
00748                 __base = 8;
00749             }
00750 
00751           // Remove any more leading zeros
00752           while (__beg != __end)
00753             {
00754               if (*__beg == __lits[__cache_type::_S_digits])
00755                 {
00756                   ++__beg;
00757                   __testzero = true;
00758                 }
00759               else
00760                 break;
00761             }
00762         }
00763       else if (__base == 0) // 1st character is not zero
00764         __base = 10;
00765 
00766       // We now seek "units", i.e. digits and thousands separators.
00767       // We may need to know if anything is found here. A leading zero
00768       // (removed by now) would count.
00769       bool __testunits = __testzero;
00770       while (__valid && __beg != __end)
00771         {
00772           __valid = false;
00773           __c = *__beg;
00774           const char* __p = strchr(__fmt->_S_literals, __c);
00775 
00776           // NB: strchr returns true for __c == 0x0
00777           if (__p && __c)
00778             {
00779               // Try first for acceptable digit; record it if found
00780               if ((__p >= &__lits[__cache_type::_S_digits]
00781                     && __p < &__lits[__cache_type::_S_digits + __base])
00782                    || (__p >= &__lits[__cache_type::_S_udigits]
00783                        && __p < &__lits[__cache_type::_S_udigits + __base]))
00784                 {
00785                   __xtrc[__pos++] = __c;
00786                   ++__sep_pos;
00787                   __valid = true;
00788                   __testunits = true;
00789                 }
00790             }
00791           else if (__c == __fmt->_M_thousands_sep
00792                    && __fmt->_M_use_grouping)
00793             {
00794               // NB: Thousands separator at the beginning of a string
00795               // is a no-no, as is two consecutive thousands
00796               // separators
00797               if (__sep_pos)
00798                 {
00799                   __grp += static_cast<char>(__sep_pos);
00800                   __sep_pos = 0;
00801                   __valid = true;
00802                 }
00803               else
00804                 __err |= ios_base::failbit;
00805             }
00806           if (__valid)
00807             ++__beg;
00808         }
00809 
00810       // Digit grouping is checked. If _M_groupings() doesn't
00811       // match, then get very very upset, and set failbit.
00812       if (__fmt->_M_use_grouping && !__grp.empty())
00813         {
00814           // Add the ending grouping
00815           __grp += static_cast<char>(__sep_pos);
00816 
00817           // __grp is parsed L to R
00818           // 1,222,444 == __grp of "/1/3/3"
00819           // __fmt->_M_grouping is parsed R to L
00820           // 1,222,444 == __fmt->_M_grouping of "/3" == "/3/3/3"
00821           int __i = 0;
00822           int __j = 0;
00823           const int __len = __fmt->_M_grouping.size();
00824           int __n = __grp.size();
00825           bool __test = true;
00826 
00827           // Parsed number groupings have to match the
00828           // numpunct::grouping string exactly, starting at the
00829           // right-most point of the parsed sequence of elements ...
00830           while (__test && __i < __n - 1)
00831             for (__j = 0; __test && __j < __len && __i < __n - 1; ++__j,++__i)
00832               __test &= __fmt->_M_grouping[__j] == __grp[__n - __i - 1];
00833           // ... but the last parsed grouping can be <= numpunct
00834           // grouping.
00835           __j == __len ? __j = 0 : __j;
00836           __test &= __fmt->_M_grouping[__j] >= __grp[__n - __i - 1];
00837 
00838           if (!__test)
00839             {
00840               __err |= ios_base::failbit;
00841               __xtrc[__pos] = '\0';
00842               if (__beg == __end)
00843                 __err |= ios_base::eofbit;
00844               return;
00845             }
00846         }
00847 
00848       // If there was nothing but zeros, put one in the output string
00849       if (__testzero && (__pos == 0 || (__pos == 1 && __testsign)))
00850         __xtrc[__pos++] = __lits[__cache_type::_S_digits];
00851 
00852       // That's it for integer types. Remaining code is for floating point
00853       if (__fp && __beg != __end)
00854         {
00855           __c = *__beg;
00856           // Check first for decimal point. There MUST be one if
00857           // __testunits is false.
00858           bool __testdec = false;    // Is there a decimal point
00859                                      // with digits following it?
00860           if (__c == __fmt->_M_decimal_point)
00861             {
00862               __xtrc[__pos++] = '.';
00863               ++__beg;
00864               // Now we get any digits after the decimal point
00865               // There MUST be some if __testunits is false.
00866               while (__beg != __end)
00867                 {
00868                   __c = *__beg;
00869                   const char* __p = strchr(__fmt->_S_literals, __c);
00870                   if ((__p >= &__lits[__cache_type::_S_digits]
00871                         && __p < &__lits[__cache_type::_S_digits + __base])
00872                        || (__p >= &__lits[__cache_type::_S_udigits]
00873                            && __p < &__lits[__cache_type::_S_udigits + __base]))
00874                     {
00875                       __xtrc[__pos++] = __c;
00876                       ++__beg;
00877                       __testdec = true;
00878                     }
00879                   else
00880                     break;
00881                 }
00882             }
00883           if (!__testunits && !__testdec) // Ill formed
00884             {
00885               __err |= ios_base::failbit;
00886               __xtrc[__pos] = '\0';
00887               if (__beg == __end)
00888                 __err |= ios_base::eofbit;
00889               return;
00890             }
00891 
00892           // Now we may find an exponent
00893           if (__beg != __end)
00894             {
00895               __c = *__beg;
00896               if ((__c == __lits[__cache_type::_S_ee])
00897                    || (__c == __lits[__cache_type::_S_Ee]))
00898                 {
00899                   __xtrc[__pos++] = __c;
00900                   ++__beg;
00901                   // Now there may be a sign
00902                   if (__beg != __end)
00903                     {
00904                       __c = *__beg;
00905                       if ((__c == __lits[__cache_type::_S_minus])
00906                           || (__c == __lits[__cache_type::_S_plus]))
00907                         {
00908                           __xtrc[__pos++] = __c;
00909                           ++__beg;
00910                           // whitespace may follow a sign
00911                           while ((__beg != __end) && (isspace(*__beg)))
00912                             ++__beg;
00913 
00914                         }
00915                     }
00916                   // And now there must be some digits
00917                   if (__beg == __end)
00918                     {
00919                       __xtrc[__pos] = '\0';
00920                       __err |= (ios_base::eofbit | ios_base::failbit);
00921                       return;
00922                     }
00923                   while (__beg != __end)
00924                     {
00925                       __c = *__beg;
00926                       const char* __p = strchr(__fmt->_S_literals, __c);
00927                       if ((__p >= &__lits[__cache_type::_S_digits]
00928                             && __p < &__lits[__cache_type::_S_digits + __base])
00929                            || (__p >= &__lits[__cache_type::_S_udigits]
00930                                && __p < &__lits[__cache_type::_S_udigits + __base]))
00931                         {
00932                           __xtrc[__pos++] = __c;
00933                           ++__beg;
00934                         }
00935                       else
00936                         break;
00937                     }
00938                 }
00939             }
00940           // Finally, that's it for floating point
00941         }
00942 
00943       // Finish up
00944       __xtrc[__pos] = '\0';
00945       if (__beg == __end)
00946         __err |= ios_base::eofbit;
00947     }
00948 
00949   // The following code uses sprintf() to convert floating point
00950   // values for insertion into a stream. The current implementation
00951   // replicates the code in _S_pad_numeric() (in _S_output_float()) in
00952   // order to prevent having to create a "wide" buffer in addition to
00953   // the "narrow" buffer passed to sprintf(). An optimization would be
00954   // to replace sprintf() with code that works directly on a wide
00955   // buffer and then use _S_pad_numeric() to do the padding. It would
00956   // be good to replace sprintf() anyway to avoid accidental buffer
00957   // overruns and to gain back the efficiency that C++ provides by
00958   // knowing up front the type of the values to insert. This
00959   // implementation follows the C++ standard fairly directly as
00960   // outlined in 22.2.2.2 [lib.locale.num.put]
00961   bool
00962   __build_float_format(ios_base& __io, char* __fptr, char __modifier,
00963                streamsize __prec)
00964   {
00965     bool __incl_prec = false;
00966     ios_base::fmtflags __flags = __io.flags();
00967     *__fptr++ = '%';
00968     // [22.2.2.2.2] Table 60
00969     if (__flags & ios_base::showpos)
00970       *__fptr++ = '+';
00971     if (__flags & ios_base::showpoint)
00972       *__fptr++ = '#';
00973     // As per [22.2.2.2.2.11]
00974     if (__flags & ios_base::fixed || __prec > 0)
00975       {
00976         *__fptr++ = '.';
00977         *__fptr++ = '*';
00978         __incl_prec = true;
00979       }
00980     if (__modifier)
00981       *__fptr++ = __modifier;
00982     ios_base::fmtflags __fltfield = __flags & ios_base::floatfield;
00983     // [22.2.2.2.2] Table 58
00984     if (__fltfield == ios_base::fixed)
00985       *__fptr++ = 'f';
00986     else if (__fltfield == ios_base::scientific)
00987       *__fptr++ = (__flags & ios_base::uppercase) ? 'E' : 'e';
00988     else
00989       *__fptr++ = (__flags & ios_base::uppercase) ? 'G' : 'g';
00990     *__fptr = '\0';
00991     return __incl_prec;
00992   }
00993 
00994   collate<char>::collate(size_t __refs)
00995   : locale::facet(__refs) { }
00996   
00997   collate<char>::~collate() { }
00998   
00999   int 
01000   collate<char>::do_compare(const char* __lo1, const char* __hi1, 
01001                 const char* __lo2, const char* __hi2) const
01002   {
01003     for (; __lo1 < __hi1 && __lo2 < __hi2; ++__lo1, ++__lo2) 
01004       if (*__lo1 != *__lo2) 
01005     return (*__lo1 < *__lo2) ? -1 : 1;
01006     if (__lo1 < __hi1) 
01007       return 1;
01008     else if (__lo2 < __hi2) 
01009       return -1;
01010     else 
01011       return 0;
01012   }
01013   
01014   string
01015   collate<char>::
01016   do_transform(const char* __lo, const char* __hi) const
01017   { return string(__lo, __hi - __lo); }
01018   
01019   long
01020   collate<char>::
01021   do_hash(const char* __lo, const char* __hi) const
01022   {
01023     unsigned long __val = 0xdeadbeef;
01024     for (; __lo < __hi; ++__lo)
01025       __val = *__lo ^ ((__val << 7) & 
01026            (__val >> (numeric_limits<unsigned long>::digits - 1)));
01027     return __val;
01028   }
01029   
01030   collate_byname<char>::collate_byname(const char* /*__s*/, size_t __refs)
01031   : collate<char>(__refs) { }
01032 
01033   moneypunct_byname<char, false>::moneypunct_byname(const char* /*__s*/, 
01034                             size_t __refs)
01035   : moneypunct<char, false>(__refs) { }
01036   
01037   moneypunct_byname<char, true>::moneypunct_byname(const char* /*__s*/, 
01038                            size_t __refs)
01039   : moneypunct<char, true>(__refs) { }
01040   
01041   messages_byname<char>::
01042   messages_byname(const char* /*__s*/, size_t __refs)
01043   : messages<char>(__refs) { }
01044 
01045 #ifdef _GLIBCPP_USE_WCHAR_T  
01046   ctype<wchar_t>::__wmask_type
01047   ctype<wchar_t>::_M_convert_to_wmask(const mask __m) const
01048   {
01049     __wmask_type __ret;
01050     switch (__m)
01051       {
01052       case space:
01053     __ret = wctype("space");
01054     break;
01055       case print:
01056     __ret = wctype("print");
01057     break;
01058       case cntrl:
01059     __ret = wctype("cntrl");
01060     break;
01061       case upper:
01062     __ret = wctype("upper");
01063     break;
01064       case lower:
01065     __ret = wctype("lower");
01066     break;
01067       case alpha:
01068     __ret = wctype("alpha");
01069     break;
01070       case digit:
01071     __ret = wctype("digit");
01072     break;
01073       case punct:
01074     __ret = wctype("punct");
01075     break;
01076       case xdigit:
01077     __ret = wctype("xdigit");
01078     break;
01079       case alnum:
01080     __ret = wctype("alnum");
01081     break;
01082       case graph:
01083     __ret = wctype("graph");
01084     break;
01085       default:
01086     __ret = 0;
01087       }
01088     return __ret;
01089   };
01090   
01091   ctype<wchar_t>::~ctype() { }
01092 
01093   // NB: These ctype<wchar_t> methods are not configuration-specific,
01094   // unlike the ctype<char> bits.
01095   ctype<wchar_t>::ctype(size_t __refs) : __ctype_abstract_base<wchar_t>(__refs)
01096   { }
01097 
01098   wchar_t
01099   ctype<wchar_t>::do_toupper(wchar_t __c) const
01100   { return towupper(__c); }
01101 
01102   const wchar_t*
01103   ctype<wchar_t>::do_toupper(wchar_t* __low, const wchar_t* __high) const
01104   {
01105     while (__low < __high)
01106       {
01107         *__low = towupper(*__low);
01108         ++__low;
01109       }
01110     return __high;
01111   }
01112   
01113   wchar_t
01114   ctype<wchar_t>::do_tolower(wchar_t __c) const
01115   { return towlower(__c); }
01116   
01117   const wchar_t*
01118   ctype<wchar_t>::do_tolower(wchar_t* __low, const wchar_t* __high) const
01119   {
01120     while (__low < __high)
01121       {
01122         *__low = towlower(*__low);
01123         ++__low;
01124       }
01125     return __high;
01126   }
01127 
01128   bool
01129   ctype<wchar_t>::
01130   do_is(mask __m, char_type __c) const
01131   { return static_cast<bool>(iswctype(__c, _M_convert_to_wmask(__m))); }
01132   
01133   const wchar_t* 
01134   ctype<wchar_t>::
01135   do_is(const wchar_t* __low, const wchar_t* __high, mask* __m) const
01136   {
01137     while (__low < __high && !this->is(*__m, *__low))
01138       ++__low;
01139     return __low;
01140   }
01141   
01142   const wchar_t* 
01143   ctype<wchar_t>::
01144   do_scan_is(mask __m, const wchar_t* __low, const wchar_t* __high) const
01145   {
01146     while (__low < __high && !this->is(__m, *__low))
01147       ++__low;
01148     return __low;
01149   }
01150 
01151   const wchar_t*
01152   ctype<wchar_t>::
01153   do_scan_not(mask __m, const char_type* __low, const char_type* __high) const
01154   {
01155     while (__low < __high && this->is(__m, *__low) != 0)
01156       ++__low;
01157     return __low;
01158   }
01159 
01160   wchar_t
01161   ctype<wchar_t>::
01162   do_widen(char __c) const
01163   { return btowc(__c); }
01164   
01165   const char* 
01166   ctype<wchar_t>::
01167   do_widen(const char* __low, const char* __high, wchar_t* __dest) const
01168   {
01169     mbstate_t __state;
01170     memset(static_cast<void*>(&__state), 0, sizeof(mbstate_t));
01171     mbsrtowcs(__dest, &__low, __high - __low, &__state);
01172     return __high;
01173   }
01174 
01175   char
01176   ctype<wchar_t>::
01177   do_narrow(wchar_t __wc, char __dfault) const
01178   { 
01179     int __c = wctob(__wc);
01180     return (__c == EOF ? __dfault : static_cast<char>(__c)); 
01181   }
01182 
01183   const wchar_t*
01184   ctype<wchar_t>::
01185   do_narrow(const wchar_t* __low, const wchar_t* __high, char __dfault, 
01186         char* __dest) const
01187   {
01188     mbstate_t __state;
01189     memset(static_cast<void*>(&__state), 0, sizeof(mbstate_t));
01190     size_t __len = __high - __low;
01191     size_t __conv = wcsrtombs(__dest, &__low, __len, &__state);
01192     if (__conv == __len)
01193       *__dest = __dfault;
01194     return __high;
01195   }
01196 
01197   ctype_byname<wchar_t>::
01198   ctype_byname(const char* /*__s*/, size_t __refs)
01199   : ctype<wchar_t>(__refs) { }
01200 
01201   collate<wchar_t>::
01202   collate(size_t __refs): locale::facet(__refs) { }
01203   
01204   collate<wchar_t>::
01205   ~collate() { }
01206 
01207   int 
01208   collate<wchar_t>::
01209   do_compare(const wchar_t* /*__lo1*/, const wchar_t* /*__hi1*/,
01210          const wchar_t* /*__lo2*/, const wchar_t* /*__hi2*/) const
01211   {
01212     return 0; // XXX not done
01213   }
01214   
01215   wstring collate<wchar_t>::
01216   do_transform(const wchar_t* /*__lo*/, const wchar_t* /*__hi*/) const
01217   {
01218     return wstring(); // XXX not done
01219   }
01220   
01221   long collate<wchar_t>::
01222   do_hash(const wchar_t* /*__lo*/, const wchar_t* /*__hi*/) const
01223   {
01224     return 0; // XXX not done
01225   }
01226 
01227   collate_byname<wchar_t>::
01228   collate_byname(const char* /*__s*/, size_t __refs)
01229   : collate<wchar_t> (__refs) { }
01230   
01231   messages_byname<wchar_t>::
01232   messages_byname(const char* /*__s*/, size_t __refs)
01233   : messages<wchar_t> (__refs) { }
01234 #endif //  _GLIBCPP_USE_WCHAR_T
01235 } // namespace std
01236 

Generated at Tue May 1 16:28:38 2001 for libstdc++-v3 by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001