00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <cstdarg>
00027 #include <cstdio>
00028 #include <mpcl/text/string.hh>
00029
00030 #ifdef HAVE_VSNPRINTF
00031
00032
00033
00034
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 }
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
00066
00067
00068
00069
00070
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
00081
00082
00083
00084
00085
00086 if ( iChars <= -1 )
00087 {
00088
00089
00090
00091 zSize *= 2;
00092 pcReallocatedBuffer = (char*) realloc (pcBuffer, zSize);
00093 }
00094 else if ( ((size_t) iChars) >= zSize )
00095 {
00096
00097
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 }
00119
00120
00121 #else
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
00176
00177
00179 TDirectiveDFA (void);
00180
00181
00182 public:
00183
00184
00185
00186
00187
00196 bool next ( TState tSOURCE_STATE ,
00197 TEvent tSOURCE_EVENT ,
00198 TState& rtTARGET_STATE ) const;
00199
00200 };
00201
00202
00203
00204
00205
00206
00207 static const char* _TranslateDirective ( const char* pkcDIRECTIVE ,
00208 std::va_list& rtSOURCE_VA_LIST ,
00209 TString& ryTARGET_STRING );
00210
00211 }
00212
00213 }
00214
00215
00216
00217
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 }
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 }
00279
00280
00281
00282
00283
00284
00290 static const mpcl::text::TDirectiveDFA<int, int> _ktDirectiveDFA;
00291
00292
00293
00294
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
00314
00315 while ( !gFinalState )
00316 {
00317
00318
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
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 }
00422
00423
00424
00425
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
00444
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 }
00457
00458
00459 #endif // not HAVE_VSNPRINTF