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

string.cc

00001 /*
00002 *  Name:      string.cc
00003 *  Author:    Rafael Jesus Alcantara Perez
00004 *  Summary:   String
00005 *  Date:      $Date: 2003/04/14 00:18:35 $
00006 *  Revision:  $Revision: 1.1 $
00007 *
00008 *  Copyright (C) 1994-2002  Rafael Jesus Alcantara Perez <rafa@dedalo-ing.com>
00009 *
00010 *  This program is free software; you can redistribute it and/or modify
00011 *  it under the terms of the GNU General Public License as published by
00012 *  the Free Software Foundation; either version 2 of the License, or
00013 *  (at your option) any later version.
00014 *
00015 *  This program is distributed in the hope that it will be useful,
00016 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 *  GNU General Public License for more details.
00019 *
00020 *  You should have received a copy of the GNU General Public License
00021 *  along with this program; if not, write to the Free Software
00022 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00023 *  MA 02111-1307, USA.
00024 */
00025 
00026 #include <cstdarg>
00027 #include <cstdio>
00028 #include <mpcl/text/string.hh>
00029 
00030 #ifdef HAVE_VSNPRINTF
00031 
00032 
00033 //
00034 //  E X P O R T E D   F U N C T I O N S
00035 //
00036 
00037 const char* mpcl::text::
00038 BoolToString (bool gTRUTH, const char* pkcTRUE, const char* pkcFALSE)
00039 {
00040 
00041   return ( gTRUTH ) ? pkcTRUE : pkcFALSE;
00042 
00043 }  // BoolToString()
00044 
00045 
00046 mpcl::text::TString mpcl::text::
00047 Format (const char* pkcFORMAT...)
00048 {
00049 
00050   using std::free;
00051   using std::malloc;
00052   using std::realloc;
00053   
00054   TString   yTarget;
00055   
00056   if ( pkcFORMAT )
00057   {
00058     va_list           tVa_list;
00059     register int      iChars              = -1;
00060     register size_t   zSize               = 1024;
00061     register char*    pcBuffer            = NULL;
00062     register char*    pcReallocatedBuffer = (char*) malloc (zSize);
00063     
00064     //
00065     //  Initializes the variable argument list.
00066     //  While the reserved buffer  doesn't  have the minimum size tries to hold
00067     //  the whole string, continues trying.
00068     //  
00069     //  Warning:  It  should  be  used  a boolean variable to  check  the  exit
00070     //            condition,  but for performance reasons it has  been removed.
00071     //
00072     while ( pcReallocatedBuffer )
00073     {
00074       va_start (tVa_list, pkcFORMAT);
00075       pcBuffer = pcReallocatedBuffer;
00076       iChars   = vsnprintf (pcBuffer, zSize, pkcFORMAT, tVa_list);
00077       va_end (tVa_list);
00078 
00079       //
00080       //  In GLIBC 2.0 it returns -1 if  there isn't space, but in GLIBC 2.1 it
00081       //  returns the characters that it would needed.
00082       //  Standard  function  'std::realloc()' doesn't free the  buffer  if  it
00083       //  can't reallocate the space, so it is needed to free that buffer, even
00084       //  if the last 'std::realloc()' has failed.
00085       //
00086       if ( iChars <= -1 )
00087       {
00088         //
00089         //  GLIBC 2.0.x version of function 'std::vsnprintf()'.
00090         //
00091         zSize               *= 2;
00092         pcReallocatedBuffer  = (char*) realloc (pcBuffer, zSize);
00093       }
00094       else if ( ((size_t) iChars) >= zSize )
00095       {
00096         //
00097         //  GLIBC 2.1.x (ISO C9X) version of function 'std::vsnprintf()'.
00098         //
00099         zSize               = iChars + 1;
00100         pcReallocatedBuffer = (char*) realloc (pcBuffer, zSize);
00101       }
00102       else
00103       {
00104         break;
00105       }
00106     }
00107     if ( pcBuffer )
00108     {
00109       if ( pcReallocatedBuffer )
00110       {
00111         yTarget = pcReallocatedBuffer;
00112       }
00113       free (pcBuffer);
00114     }
00115   }
00116   return yTarget;
00117   
00118 }  // Format()
00119 
00120 
00121 #else  // not HAVE_VSNPRINTF
00122 
00123 #include <mpcl/automaton/deterministic_finite_automaton.hh>
00124 
00125 
00127 namespace mpcl
00128 {
00129 
00131   namespace text
00132   {
00133 
00135     enum ESpecialSymbol
00136     {
00137       any_char              = -1 ,
00138       digit                 = -2 ,
00139       other_convertors      = -3 ,
00140       other_convertors_real = -4
00141     };
00142 
00144     enum EState
00145     {
00146       initial_state              ,
00147       prepoint_number_state      ,
00148       point_number_state         ,
00149       postpoint_number_state     ,
00150       conversion_specifier_state ,
00151       final_percent_symbol_state ,
00152       final_string_state         ,
00153       final_state                ,
00154       l_state                    ,
00155       L_state
00156     };
00157 
00158 
00168     template <typename TState, typename TEvent>
00169     class TDirectiveDFA : public automaton::TDeterministicFiniteAutomaton<TState, TEvent>
00170     {
00171 
00172       public:
00173 
00174         //
00175         //  C O N S T R U C T O R S
00176         //
00177 
00179         TDirectiveDFA (void);
00180 
00181 
00182       public:
00183 
00184         //
00185         //  S E L E C T O R S
00186         //
00187 
00196         bool next ( TState  tSOURCE_STATE  ,
00197                     TEvent  tSOURCE_EVENT  ,
00198                     TState& rtTARGET_STATE ) const;
00199 
00200     };  // class TDirectiveDFA
00201 
00202 
00203     //
00204     //  L O C A L   F U N C T I O N S
00205     //
00206 
00207     static const char* _TranslateDirective ( const char*   pkcDIRECTIVE     ,
00208                                              std::va_list& rtSOURCE_VA_LIST ,
00209                                              TString&      ryTARGET_STRING  );
00210 
00211   }  // namespace text
00212 
00213 }  // namespace mpcl
00214 
00215 
00216 //
00217 //  C O N S T R U C T O R S
00218 //
00219 
00220 template <typename TState, typename TEvent>
00221 mpcl::text::TDirectiveDFA<TState, TEvent>::TDirectiveDFA (void) :
00222   mpcl::text::TDeterministicFiniteAutomaton<TState, TEvent> ()
00223 {
00224   
00225 # define ADD_TRANS(iSTATE, iEVENT, iNEXT_STATE) \
00226     tTransitionMap.bind (make_pair (iSTATE, iEVENT), iNEXT_STATE)
00227 
00228   tCurrentState = initial_state;
00229   tInitialState = initial_state;
00230   ADD_TRANS (initial_state, digit,    prepoint_number_state);
00231   ADD_TRANS (initial_state, '.',      point_number_state);
00232   ADD_TRANS (initial_state, '%',      final_percent_symbol_state);
00233   ADD_TRANS (initial_state, any_char, conversion_specifier_state);
00234   
00235   ADD_TRANS (conversion_specifier_state, 's',                   final_string_state);
00236   ADD_TRANS (conversion_specifier_state, 'c',                   final_state);
00237   ADD_TRANS (conversion_specifier_state, other_convertors,      final_state);
00238   ADD_TRANS (conversion_specifier_state, other_convertors_real, final_state);
00239   ADD_TRANS (conversion_specifier_state, 'l',                   l_state);
00240   ADD_TRANS (conversion_specifier_state, 'L',                   L_state);
00241   
00242   ADD_TRANS (prepoint_number_state, digit,    prepoint_number_state);
00243   ADD_TRANS (prepoint_number_state, '.',      point_number_state);
00244   ADD_TRANS (prepoint_number_state, any_char, conversion_specifier_state);
00245   
00246   ADD_TRANS (point_number_state, digit,    postpoint_number_state);
00247   ADD_TRANS (point_number_state, any_char, conversion_specifier_state);
00248   
00249   ADD_TRANS (postpoint_number_state, digit,    postpoint_number_state);
00250   ADD_TRANS (postpoint_number_state, any_char, conversion_specifier_state);
00251   
00252   ADD_TRANS (l_state, other_convertors,      final_state);
00253   ADD_TRANS (L_state, other_convertors_real, final_state);
00254 
00255 # undef ADD_TRANS
00256   
00257 }  // TDirectiveDFA()
00258 
00259 
00260 template <typename TState, typename TEvent>
00261 bool mpcl::text::TDirectiveDFA<TState, TEvent>::
00262 next ( TState  tSOURCE_STATE  ,
00263        TEvent  tSOURCE_EVENT  ,
00264        TState& rtTARGET_STATE ) const
00265 {
00266 
00267   typename TTransitionMap::const_iterator   I;
00268   bool                                      gSuccess;
00269   
00270   I        = tTransitionMap.find (make_pair (tSOURCE_STATE, tSOURCE_EVENT));
00271   gSuccess = ( I != tTransitionMap.end() );
00272   if ( gSuccess )
00273   {
00274     rtTARGET_STATE = I->second;
00275   }
00276   return gSuccess;
00277 
00278 }  // next()
00279 
00280 
00281 //
00282 //  L O C A L   V A R I A B L E S
00283 //
00284 
00290 static const mpcl::text::TDirectiveDFA<int, int>   _ktDirectiveDFA;
00291 
00292 
00293 //
00294 //  L O C A L   F U N C T I O N S
00295 //
00296 
00297 static const char* mpcl::text::text::
00298 _TranslateDirective ( const char*   pkcDIRECTIVE     ,
00299                       std::va_list& rtSOURCE_VA_LIST ,
00300                       TString&      ryTARGET_STRING  )
00301 {
00302 
00303   char            acBuffer [1024];
00304   register bool   gFound;
00305   register bool   gEatChar;
00306   register int    iNextState;
00307   register int    iEvent;
00308   register bool   gFinalState   = false;
00309   register int    iCurrentState = initial_state;
00310   TString         yDirective    = "%";
00311 
00312   //
00313   //  Steps over introducer character ('%') and initializes map.
00314   //
00315   while ( !gFinalState )
00316   {
00317     //
00318     //  Groups input chars on special symbols (if any).
00319     //
00320     switch (*pkcDIRECTIVE)
00321     {
00322       case '0':
00323       case '1':
00324       case '2':
00325       case '3':
00326       case '4':
00327       case '5':
00328       case '6':
00329       case '7':
00330       case '8':
00331       case '9':
00332       {
00333         iEvent = (int) digit;
00334         break;
00335       }
00336       case 'd':
00337       case 'i':
00338       case 'u':
00339       case 'x':
00340       {
00341         iEvent = (int) other_convertors;
00342         break;
00343       }
00344       case 'f':
00345       case 'e':
00346       {
00347         iEvent = (int) other_convertors_real;
00348         break;
00349       }
00350       default:
00351       {
00352         iEvent = *pkcDIRECTIVE;
00353       }
00354     }
00355     
00356     //
00357     //  Find next state (if any).
00358     //
00359     gFound = _ktDirectiveDFA.next (iCurrentState, iEvent, iNextState);
00360     if ( gFound )
00361     {
00362       gEatChar = true;
00363     }
00364     else
00365     {
00366       gFound   = _ktDirectiveDFA.next (iCurrentState, any_char, iNextState);
00367       gEatChar = !gFound;
00368     }
00369     switch (iCurrentState)
00370     {
00371       case conversion_specifier_state:
00372       case initial_state:
00373       case point_number_state:
00374       case prepoint_number_state:
00375       case postpoint_number_state:
00376       case l_state:
00377       case L_state:
00378       {
00379         if ( gEatChar )
00380         {
00381           yDirective.append (1, *pkcDIRECTIVE);
00382           ++pkcDIRECTIVE;
00383         }
00384         break;
00385       }
00386       case final_string_state:
00387       {
00388         ryTARGET_STRING.append (va_arg (rtSOURCE_VA_LIST, const char*));
00389         gFinalState = true;
00390         break;
00391       }
00392       case final_state:
00393       {
00394         vsprintf (acBuffer, yDirective.c_str(), rtSOURCE_VA_LIST);
00395         ryTARGET_STRING.append (acBuffer);
00396         gFinalState = true;
00397         break;
00398       }
00399       case final_percent_symbol_state:
00400       {
00401         ryTARGET_STRING.append (1, '%');
00402         gFinalState = true;
00403         break;
00404       }
00405     }
00406     if ( gFound )
00407     {
00408       iCurrentState = iNextState;
00409     }
00410     else if ( gFinalState )
00411     {
00412       break;
00413     }
00414     else
00415     {
00416       throw TConstraintException ("unrecognized directive", __FILE__, __LINE__);
00417     }
00418   }
00419   return pkcDIRECTIVE;
00420   
00421 }  // _TranslateDirective()
00422 
00423 
00424 //
00425 //  E X P O R T E D   F U N C T I O N S
00426 //
00427 
00428 mpcl::text::TString mpcl::text::
00429 Format (const char* pkcFORMAT...)
00430 {
00431   
00432   TString   yTarget;
00433   
00434   if ( pkcFORMAT )
00435   {
00436     register const char*   pkcIter;
00437     va_list                tVa_list;
00438     register const char*   pkcChunkBegin = pkcFORMAT;
00439 
00440     va_start (tVa_list, pkcFORMAT);
00441 
00442     //
00443     //  While it founds directive intruducer, append plain chunks
00444     //  and translates directives.
00445     //
00446     while ( NULL != (pkcIter = strchr (pkcChunkBegin, '%')) )
00447     {
00448       yTarget.append (pkcChunkBegin, pkcIter - pkcChunkBegin);
00449       pkcChunkBegin = _TranslateDirective (pkcIter + 1, tVa_list, yTarget);
00450     }
00451     yTarget.append (pkcChunkBegin);
00452     va_end (tVa_list);
00453   }
00454   return yTarget;
00455   
00456 }  // Format()
00457 
00458 
00459 #endif  // not HAVE_VSNPRINTF

Generated on Mon Oct 13 02:35:24 2003 for MPCL by doxygen1.2.18