00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00023
00042
00043
00044 #ifndef _CTTL_XTL_TRACE_H_INCLUDED_
00045 #define _CTTL_XTL_TRACE_H_INCLUDED_
00046
00047 #include <iostream>
00048 #include <string>
00049
00050 #define CTTL_QUOTED_EXPRESSION_HELPER( x ) #x
00051 #define CTTL_QUOTED_EXPRESSION( x ) CTTL_QUOTED_EXPRESSION_HELPER( x )
00052
00053
00054
00055 #define CTTL_TRACE_VARIABLE_2( xprefix, xsuffix ) xprefix ## xsuffix
00056 #define CTTL_TRACE_VARIABLE_1( xprefix, xsuffix ) CTTL_TRACE_VARIABLE_2( xprefix, xsuffix )
00057 #define CTTL_TRACE_VARIABLE( xprefix ) CTTL_TRACE_VARIABLE_1( xprefix, __LINE__ )
00058
00059
00060 #ifdef CTTL_TRACE_EVERYTHING
00061
00062 # ifdef CTTL_TRACE_EXPRESSION_TYPEID
00063 # define CTTL_TRACE_TYPEID( p ) ( typeid( *p ).name() )
00064 # else
00065 # ifdef CTTL_TRACE_EXPRESSION_IMPL
00066 # define CTTL_TRACE_TYPEID( p ) __FILE__ ";" CTTL_QUOTED_EXPRESSION( __LINE__ )
00067 # else
00068 # define CTTL_TRACE_TYPEID( p ) ""
00069 # endif // CTTL_TRACE_EXPRESSION_IMPL
00070 # endif // CTTL_TRACE_EXPRESSION_TYPEID
00071
00072 # define CTTL_TRACE_LEVEL_MATCH( xchar ) xtl_trace_grammar tlv( CTTL_TRACE_TYPEID( this ), edge_, xchar, xtl_trace_grammar::trace_grammar_mode_match )
00073 # define CTTL_TRACE_LEVEL_FIND( xchar ) xtl_trace_grammar tlv( CTTL_TRACE_TYPEID( this ), edge_, xchar, xtl_trace_grammar::trace_grammar_mode_find )
00074 # define CTTL_TRACE_LEVEL_BANG( xchar ) xtl_trace_grammar tlv( CTTL_TRACE_TYPEID( this ), edge_, xchar, xtl_trace_grammar::trace_grammar_mode_bang )
00075
00076 # define CTTL_TRACE_STATIC_LEVEL_MATCH( xchar, callbackid ) xtl_trace_grammar tlv( callbackid, edge_, xchar, xtl_trace_grammar::trace_grammar_mode_match )
00077 # define CTTL_TRACE_STATIC_LEVEL_FIND( xchar, callbackid ) xtl_trace_grammar tlv( callbackid, edge_, xchar, xtl_trace_grammar::trace_grammar_mode_find )
00078 # define CTTL_TRACE_STATIC_LEVEL_BANG( xchar, callbackid ) xtl_trace_grammar tlv( callbackid, edge_, xchar, xtl_trace_grammar::trace_grammar_mode_bang )
00079
00080 # define CTTL_TRACE_RESULT( RESULT_, xchar ) xtl_trace_grammar::trace_fragment< RESULT_ >( CTTL_TRACE_TYPEID( this ), edge_, xchar, NULL, -1 )
00081 # define CTTL_TRACE_STATIC_RESULT( RESULT_, xchar, xtext ) xtl_trace_grammar::trace_fragment< RESULT_ >( xtext, edge_, xchar, NULL, -1 )
00082
00083 # define CTTL_TRACE_EDGE_RESULT_TRUE( xchar ) xtl_trace_grammar::trace_edge< true >( CTTL_TRACE_TYPEID( this ), m_edge, xchar, NULL )
00084 # define CTTL_TRACE_NODE_RESULT_TRUE( xchar, xedge ) xtl_trace_grammar::trace_edge< true >( CTTL_TRACE_TYPEID( this ), xedge, xchar, NULL )
00085
00086 # define CTTL_TRACE_EDGE_RESULT_FALSE( xchar, xidentity ) xtl_trace_grammar::trace_fragment< false >( CTTL_TRACE_TYPEID( this ), edge_, xchar, NULL, xidentity )
00087 # define CTTL_TRACE_NODE_RESULT_FALSE( xchar, xidentity ) CTTL_TRACE_EDGE_RESULT_FALSE( xchar, xidentity )
00088
00089 # define CTTL_TRACE_TEXT_RESULT( RESULT_, xchar, xtext ) xtl_trace_grammar::trace_fragment< RESULT_ >( CTTL_TRACE_TYPEID( this ), edge_, xchar, xtext, -1 )
00090 # define CTTL_TRACE_TEXT( xchar, xtext ) xtl_trace_grammar::trace_fragment< true >( xtext, edge_, xchar, NULL, -1 )
00091 # define CTTL_TRACE_MESSAGE( xtext ) xtl_trace_grammar::trace_message( xtext )
00092 # define CTTL_TRACE_JUSTIFY() xtl_trace_grammar::trace_justify()
00093 # define CTTL_RULE( xrule ) xtl_traced_rule( __LINE__, CTTL_QUOTED_EXPRESSION( xrule ), *this, &xrule )
00094 # define CTTL_MEMBER_RULE( xobject, xrule ) xtl_traced_rule( __LINE__, CTTL_QUOTED_EXPRESSION( xrule ), xobject, xrule )
00095 # define CTTL_STATIC_RULE( xrule ) xtl_traced_rule( __LINE__, CTTL_QUOTED_EXPRESSION( xrule ), xrule )
00096 # define CTTL_TRACE_SILENT( xbool ) xtl_trace_silencer< xbool > CTTL_TRACE_VARIABLE( xtl_trace_silencer_ ); if ( sizeof( CTTL_TRACE_VARIABLE( xtl_trace_silencer_ ) ) ){}
00097
00098 #else
00099
00100 # define CTTL_TRACE_TYPEID( p )
00101
00102 # define CTTL_TRACE_LEVEL_MATCH( xchar )
00103 # define CTTL_TRACE_LEVEL_FIND( xchar )
00104 # define CTTL_TRACE_LEVEL_BANG( xchar )
00105
00106 # define CTTL_TRACE_STATIC_LEVEL_MATCH( xchar, callbackid )
00107 # define CTTL_TRACE_STATIC_LEVEL_FIND( xchar, callbackid )
00108 # define CTTL_TRACE_STATIC_LEVEL_BANG( xchar, callbackid )
00109
00110 # define CTTL_TRACE_RESULT( RESULT_, xchar )
00111 # define CTTL_TRACE_STATIC_RESULT( RESULT_, xchar, xtext )
00112 # define CTTL_TRACE_EDGE_RESULT_TRUE( xchar )
00113 # define CTTL_TRACE_NODE_RESULT_TRUE( xchar, xedge )
00114 # define CTTL_TRACE_EDGE_RESULT_FALSE( xchar, xidentity )
00115 # define CTTL_TRACE_NODE_RESULT_FALSE( xchar, xidentity )
00116 # define CTTL_TRACE_TEXT_RESULT( RESULT_, xchar, xtext )
00117 # define CTTL_TRACE_TEXT( xchar, xtext )
00118 # define CTTL_TRACE_JUSTIFY()
00119 # ifdef CTTL_TRACE_RULES
00120 # define CTTL_TRACE_MESSAGE( xtext ) xtl_trace_grammar::trace_message( xtext )
00121 # define CTTL_RULE( xrule ) xtl_traced_rule( __LINE__, CTTL_QUOTED_EXPRESSION( xrule ), *this, &xrule )
00122 # define CTTL_MEMBER_RULE( xobject, xrule ) xtl_traced_rule( __LINE__, CTTL_QUOTED_EXPRESSION( xrule ), xobject, xrule )
00123 # define CTTL_STATIC_RULE( xrule ) xtl_traced_rule( __LINE__, CTTL_QUOTED_EXPRESSION( xrule ), xrule )
00124 # define CTTL_TRACE_SILENT( xbool ) xtl_trace_silencer< xbool > CTTL_TRACE_VARIABLE( xtl_trace_silencer_ ); if ( sizeof( CTTL_TRACE_VARIABLE( xtl_trace_silencer_ ) ) ){}
00125 # else
00126 # ifdef CTTL_TRACE_TRIVIAL
00127 # define CTTL_TRACE_MESSAGE( xtext ) xtl_trace_grammar::trace_message( xtext )
00128 # else
00129 # define CTTL_TRACE_MESSAGE( xtext )
00130 # endif // CTTL_TRACE_TRIVIAL
00131 # define CTTL_RULE( xrule ) rule( *this, &xrule )
00132 # define CTTL_MEMBER_RULE( xobject, xrule ) rule( xobject, xrule )
00133 # define CTTL_STATIC_RULE( xrule ) rule( xrule )
00134 # define CTTL_TRACE_SILENT( xbool )
00135 # endif // CTTL_TRACE_RULES
00136
00137 #endif // CTTL_TRACE_EVERYTHING
00138
00139
00140 namespace cttl_impl {
00141
00142 struct xtl_trace_grammar {
00143
00144 static const size_t fragment_length = 25;
00145
00146 enum trace_grammar_mode {
00147 trace_grammar_mode_match,
00148 trace_grammar_mode_find,
00149 trace_grammar_mode_bang
00150 };
00151
00152 template< typename EdgeT >
00153 xtl_trace_grammar( CTTL_STD_CHAR const* object_name_, EdgeT const& edge_, CTTL_STD_CHAR char_, trace_grammar_mode mode_ )
00154 {
00155 std::cout
00156 << exact_edge2text( edge_, true ).c_str()
00157 << '?'
00158 ;
00159
00160 build_skyline();
00161
00162 std::cout
00163 << '{'
00164 << char_
00165 << ( mode_ == trace_grammar_mode_match ? "" : ( mode_ == trace_grammar_mode_find ? "!" : "!!" ) )
00166 << "\t\t"
00167 << edge_.first.offset()
00168 << '-'
00169 << edge_.second.offset()
00170
00171 << '\t'
00172 << object_name_
00173 << std::endl
00174 ;
00175
00176 depth( 1 );
00177 }
00178
00179 template< typename EdgeT >
00180 xtl_trace_grammar( int object_callback_id_, EdgeT const& edge_, CTTL_STD_CHAR char_, trace_grammar_mode mode_ )
00181 {
00182 std::cout
00183 << exact_edge2text( edge_, true )
00184 << '?'
00185 ;
00186
00187 build_skyline();
00188
00189 std::cout
00190 << '{'
00191 << char_
00192 << object_callback_id_
00193 << ( mode_ == trace_grammar_mode_match ? "" : ( mode_ == trace_grammar_mode_find ? "!" : "!!" ) )
00194 << "\t\t"
00195 << edge_.first.offset()
00196 << '-'
00197 << edge_.second.offset()
00198
00199 << std::endl
00200 ;
00201
00202 depth( 1 );
00203 }
00204
00205 ~xtl_trace_grammar()
00206 {
00207 depth( -1 );
00208 trace_message( "}" );
00209 }
00210
00211 static int depth( int change_ )
00212 {
00213 static int depth_ = 0;
00214 depth_ += change_;
00215 return depth_;
00216 }
00217
00218 template< typename EdgeT >
00219 static typename EdgeT::string_T edge2text( EdgeT const& edge_, bool result_ )
00220 {
00221
00222 std::string text_extract;
00223
00224 if ( edge_.length() < 0 ) {
00225 text_extract = "***INVALID***";
00226 padtext( text_extract, result_ );
00227 return text_extract;
00228 }
00229
00230 size_t end_offset = edge_.first.offset();
00231 int begin_offset = end_offset - fragment_length + 1;
00232 if ( begin_offset < 0 )
00233 begin_offset = 0;
00234 text_extract = edge_.parent().container().text_absolute_substring( begin_offset, end_offset ).c_str();
00235 text_extract += '@';
00236
00237 padtext( text_extract, result_ );
00238 return text_extract;
00239 }
00240
00241 template< typename EdgeT >
00242 static typename EdgeT::string_T exact_edge2text( EdgeT const& edge_, bool result_ )
00243 {
00244
00245
00246 std::string text_extract;
00247
00248 if ( edge_.length() < 0 ) {
00249 text_extract = "***INVALID***";
00250 padtext( text_extract, result_ );
00251 return text_extract;
00252 }
00253
00254 size_t begin_offset = edge_.first.offset();
00255 size_t end_offset = edge_.second.offset();
00256 if ( ( end_offset - begin_offset ) > fragment_length - 1 )
00257 end_offset = begin_offset + fragment_length - 1;
00258
00259 text_extract = '@';
00260 text_extract += edge_.parent().container().text_absolute_substring( begin_offset, end_offset ).c_str();
00261
00262 padtext( text_extract, result_ );
00263 return text_extract;
00264 }
00265
00266 static std::string& whitespace2monospace( std::string& text_extract_ )
00267 {
00268 std::string::size_type pos = text_extract_.length();
00269 while ( pos )
00270 if ( text_extract_[ --pos ] < ' ' )
00271 text_extract_[ pos ] = '.';
00272
00273 return text_extract_;
00274 }
00275
00276 static void padtext( std::string& text_extract_, bool result_ )
00277 {
00278 whitespace2monospace( text_extract_ );
00279
00280 if ( text_extract_.length() < fragment_length )
00281 if ( result_ )
00282 for ( size_t pad = 0; pad < fragment_length - text_extract_.length(); ++ pad )
00283 std::cout << '-';
00284
00285 else
00286 for ( size_t pad = 0; pad < fragment_length - text_extract_.length(); ++ pad )
00287 std::cout << '~';
00288
00289 }
00290
00291 static void output_monospace_text( CTTL_STD_CHAR const* text_ )
00292 {
00293 while( *text_ ) {
00294 std::cout << ( isprint( *text_ ) ? *text_ : '.' );
00295 text_++;
00296 }
00297 }
00298
00299 template< bool result_, typename EdgeT >
00300 static void trace_fragment( CTTL_STD_CHAR const* object_name_, EdgeT const& edge_, CTTL_STD_CHAR char_, CTTL_STD_CHAR const* text_, int identity_ )
00301 {
00302
00303
00304 std::cout
00305 << edge2text( edge_, result_ ).c_str()
00306 << ( result_ ? '|' : '~' )
00307 ;
00308
00309 build_skyline();
00310
00311 std::cout
00312 << char_;
00313
00314 if ( identity_ != -1 )
00315 std::cout << identity_;
00316
00317 std::cout
00318 << '\t'
00319 << '\t'
00320 << edge_.first.offset()
00321 << '-'
00322 << edge_.second.offset()
00323
00324 << '\t'
00325 << ( result_ ? "" : "FAIL " )
00326 ;
00327 if ( text_ )
00328 output_monospace_text( text_ );
00329 else
00330 std::cout << object_name_;
00331
00332 std::cout << std::endl;
00333 }
00334
00335 template< bool result_, typename EdgeT >
00336 static void trace_edge( CTTL_STD_CHAR const* object_name_, EdgeT const& edge_, CTTL_STD_CHAR char_, CTTL_STD_CHAR const* text_ )
00337 {
00338
00339 std::cout
00340 << exact_edge2text( edge_, result_ ).c_str()
00341 << ( result_ ? '|' : '~' )
00342 ;
00343
00344 build_skyline();
00345
00346 std::cout
00347 << char_
00348 << edge_.first.identity()
00349 << "\t\t"
00350 << edge_.first.offset()
00351 << '-'
00352 << edge_.second.offset()
00353
00354 << '\t'
00355 ;
00356 if ( text_ )
00357 output_monospace_text( text_ );
00358 else
00359 std::cout << object_name_;
00360
00361 std::cout << std::endl;
00362 }
00363
00364 static void trace_message( CTTL_STD_CHAR const* text_ )
00365 {
00366 trace_justify();
00367 std::cout << text_ << std::endl;
00368 }
00369
00370 static void trace_message( std::string const& text_ )
00371 {
00372 trace_justify();
00373 std::cout << text_ << std::endl;
00374 }
00375
00376 static void trace_justify( CTTL_STD_CHAR pad_char_ = ' ' )
00377 {
00378 for ( size_t pad = 0; pad <= fragment_length; ++pad )
00379 std::cout << pad_char_;
00380
00381 build_skyline( pad_char_ );
00382 }
00383
00384 static void build_skyline( CTTL_STD_CHAR pad_char_ = ' ' )
00385 {
00386 for ( int dp = 0; dp < depth( 0 ); ++dp )
00387 std::cout << pad_char_;
00388 }
00389
00390 };
00391
00392 template< bool MakeSilentT >
00393 struct xtl_trace_silencer {
00394 xtl_trace_silencer()
00395 :
00396 m_badbit( ( std::cout.rdstate() & std::ios_base::badbit ) != 0 )
00397 {
00398 if ( !m_badbit ) {
00399
00400 std::cout.flush();
00401 std::cout.setstate( std::ios_base::badbit );
00402 }
00403 }
00404 ~xtl_trace_silencer()
00405 {
00406 if ( !m_badbit ) {
00407
00408 std::cout.clear();
00409 }
00410 }
00411 private:
00412
00413 bool m_badbit;
00414
00415 };
00416
00417
00418 template<>
00419 struct xtl_trace_silencer< false > {
00420 xtl_trace_silencer()
00421 :
00422 m_badbit( ( std::cout.rdstate() & std::ios_base::badbit ) != 0 )
00423 {
00424 if ( m_badbit ) {
00425
00426 std::cout.clear();
00427 }
00428 }
00429 ~xtl_trace_silencer()
00430 {
00431 if ( m_badbit ) {
00432
00433 std::cout.flush();
00434 std::cout.setstate( std::ios_base::badbit );
00435 }
00436 }
00437 private:
00438
00439 bool m_badbit;
00440
00441 };
00442
00443 }
00444
00445
00446 #endif // _CTTL_XTL_TRACE_H_INCLUDED_