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
00027
00028 #include <lestes/std/dumper.hh>
00029 #include <lestes/std/reflect.hh>
00030 #include <lestes/std/objectize.hh>
00031 #include <lestes/std/objectize_macros.hh>
00032 #include <lestes/std/map.hh>
00033 #include <lestes/std/set.hh>
00034 #include <lestes/std/list.hh>
00035 #include <lestes/std/pair.hh>
00036 #include <lestes/std/vector.hh>
00037
00038 package(lestes);
00039 package(std);
00040
00041 using ::std::endl;
00042
00043 ::std::ostream & dumper::dump( ::std::ostream & output_to,
00044 ptr<object> start_at, bool respect_barriers )
00045 {
00046 ptr<dumper> instance = new dumper( output_to, respect_barriers );
00047 instance->the_dump(start_at);
00048 return output_to;
00049 }
00050
00051 void dumper::visit_object( ptr<object> o )
00052 {
00053 lassert(o);
00054 was_simple = false;
00055 }
00056
00057 void dumper::visit_nodump()
00058 {
00059 stream << "<nondumpable />";
00060 was_simple = true;
00061 }
00062
00063 void dumper::visit_lint( lint i )
00064 {
00065 stream << "<simple type=\"lint\" value=\"" << i << "\" />";
00066 was_simple = true;
00067 }
00068
00069 void dumper::visit_ulint( ulint i )
00070 {
00071 stream << "<simple type=\"ulint\" value=\"" << i << "\" />";
00072 was_simple = true;
00073 }
00074
00075 void dumper::visit_bool( bool i )
00076 {
00077
00078 stream << "<simple type=\"bool\" value=\"" << (i ? "true" : "false") << "\" />";
00079 was_simple = true;
00080 }
00081
00082 void dumper::visit_lstring( const lstring &i )
00083 {
00084 lstring tmp(i);
00085 lstring sought("<>&");
00086 lstring lt("<");
00087 lstring gt(">");
00088 lstring amp("&");
00089 lstring::size_type mark = tmp.find_first_of(sought);
00090 if (mark != lstring::npos)
00091 do {
00092 switch (tmp[mark]) {
00093 case '<':
00094 tmp.replace(mark, 1, lt);
00095 break;
00096 case '>':
00097 tmp.replace(mark, 1, gt);
00098 break;
00099 case '&':
00100 tmp.replace(mark, 1, amp);
00101 break;
00102 }
00103 } while ((mark = tmp.find_first_of(sought, mark+1)) != lstring::npos);
00104 stream << "<simple type=\"lstring\" value=\"" << tmp << "\" />";
00105 was_simple = true;
00106 }
00107
00108 void dumper::visit_ucn_string( const ucn_string &i )
00109 {
00110 ucn_string tmp(i);
00111 ucn_string sought("\x3c\x3e\x26");
00112 ucn_string lt("\x26\x6c\x74\x3b");
00113 ucn_string gt("\x26\x67\x74\x3b");
00114 ucn_string amp("\x26\x61\x6d\x70\x3b");
00115 ucn_string::size_type mark = tmp.find_first_of(sought);
00116 if (mark != ucn_string::npos)
00117 do {
00118 switch (tmp[mark]) {
00119 case 0x3c:
00120 tmp.replace(mark, 1, lt);
00121 break;
00122 case 0x3e:
00123 tmp.replace(mark, 1, gt);
00124 break;
00125 case 0x26:
00126 tmp.replace(mark, 1, amp);
00127 break;
00128 }
00129 } while ((mark = tmp.find_first_of(sought, mark+1)) != ucn_string::npos);
00130 stream << "<simple type=\"ucn_string\" value=\"" << tmp << "\" />";
00131 was_simple = true;
00132 }
00133
00134 void dumper::try_enqueue( ptr<object> o, ptr<queue_type> queue, ptr<set_type> visited )
00135 {
00136 bool not_yet_visited = visited->insert(o).second;
00137 if (not_yet_visited)
00138 queue->push_back(o);
00139 }
00140
00141 void dumper::gc_mark()
00142 {
00143 dumper_visitor::gc_mark();
00144 }
00145
00146 dumper::dumper( ::std::ostream &a_stream, bool a_respect_barriers )
00147 : dumper_visitor(), stream(a_stream), respect_barriers(a_respect_barriers)
00148 {}
00149
00150 void dumper::the_dump( ptr<object> start_at )
00151 {
00152 ptr<queue_type> queue = queue_type::create();
00153 ptr<set_type> visited = set_type::create();
00154
00155 stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
00156 "<dump xmlns=\"http://lestes.jikos.cz/schemas/dump\">" << endl;
00157 if (start_at) {
00158
00159 start_at->accept_dumper_visitor(this);
00160 if (!was_simple) {
00161 try_enqueue( start_at, queue, visited );
00162 }
00163 } else {
00164 stream << "<null />" << endl;
00165 }
00166 while ( !queue->empty() ) {
00167 ptr<object> current = queue->front();
00168 queue->pop_front();
00169
00170 lassert(current);
00171
00172 bool at_barrier = current->dump_barrier_get();
00173
00174 ptr<reflection_list> refls = current->reflection_get();
00175 lassert( refls );
00176
00177 stream << "<instance type=\"" << refls->back()->name_get() << "\""
00178 " id=\"i_" << current->uid_get() << "\">" << endl;
00179 ptr<field_list_list> fields = current->field_values_get();
00180 field_list_list::iterator field_it = fields->begin();
00181 for ( reflection_list::iterator refl_it = refls->begin();
00182 refl_it != refls->end(); ++refl_it ) {
00183
00184 ptr<class_reflection::field_metadata_list> metadata =
00185 (*refl_it)->field_metadata_get();
00186
00187 for (class_reflection::field_metadata_list::iterator
00188 meta_it = metadata->begin();
00189 meta_it != metadata->end();
00190 ++meta_it, ++field_it ) {
00191
00192
00193 lassert( field_it != fields->end() );
00194
00195 ulint item_no = 0;
00196 bool do_append_no = (*field_it)->size() > 1;
00197 for (value_list::iterator val_it = (*field_it)->begin();
00198 val_it != (*field_it)->end();
00199 ++val_it, ++item_no ) {
00200
00201 stream << "<field name=\"" << (*meta_it)->first;
00202 if (do_append_no)
00203 stream << item_no;
00204 stream << "\" type=\"" << (*meta_it)->second << "\""
00205 " origin=\"" << (*refl_it)->name_get() << "\">";
00206 if (*val_it) {
00207 (*val_it)->accept_dumper_visitor(this);
00208 if (!was_simple) {
00209 if (respect_barriers && at_barrier)
00210 stream << "<after-barrier />";
00211 else {
00212 try_enqueue( *val_it, queue, visited );
00213 stream << "<pointer idref=\"i_" <<
00214 (*val_it)->uid_get() << "\" />";
00215 }
00216 }
00217 } else
00218 stream << "<null />";
00219 stream << "</field>" << endl;
00220 }
00221 }
00222 }
00223
00224
00225 lassert( field_it == fields->end() );
00226 stream << "</instance>" << endl;
00227 };
00228 stream << "</dump>" << endl;
00229 }
00230
00231 ::std::ostream & readable_dumper::dump( ::std::ostream & output_to,
00232 ptr<object> start_at, bool respect_barriers )
00233 {
00234 ptr<readable_dumper> instance =
00235 new readable_dumper( output_to, respect_barriers );
00236 instance->visited = set_type::create();
00237 instance->after_barrier = false;
00238 if (start_at) {
00239 output_to << "<dump>" << endl;
00240 start_at->accept_dumper_visitor(instance);
00241 output_to << "</dump>" << endl;
00242 } else
00243 output_to << "<null />" << endl;
00244 return output_to;
00245 }
00246
00247 void readable_dumper::gc_mark()
00248 {
00249 visited.gc_mark();
00250 dumper_visitor::gc_mark();
00251 }
00252
00253 void readable_dumper::follow( ptr<object> o )
00254 {
00255 ptr<reflection_list> refls = o->reflection_get();
00256 lassert( refls );
00257
00258 bool already_visited = !(visited->insert(o).second);
00259 if (already_visited) {
00260 stream << '<' << refls->back()->name_get() <<
00261 " idref=\"i_" << o->uid_get() << "\" />" << endl;
00262 return;
00263 }
00264 stream << '<' << refls->back()->name_get() << " id=\"i_" << o->uid_get() << "\">" << endl;
00265
00266 bool at_barrier = o->dump_barrier_get();
00267
00268 ptr<field_list_list> fields = o->field_values_get();
00269 field_list_list::iterator field_it = fields->begin();
00270 for ( reflection_list::iterator refl_it = refls->begin();
00271 refl_it != refls->end(); ++refl_it ) {
00272
00273 ptr<class_reflection::field_metadata_list> metadata =
00274 (*refl_it)->field_metadata_get();
00275
00276 for (class_reflection::field_metadata_list::iterator
00277 meta_it = metadata->begin();
00278 meta_it != metadata->end();
00279 ++meta_it, ++field_it ) {
00280
00281
00282 lassert( field_it != fields->end() );
00283
00284 ulint item_no = 0;
00285 bool do_append_no = (*field_it)->size() > 1;
00286 for (value_list::iterator val_it = (*field_it)->begin();
00287 val_it != (*field_it)->end(); ++val_it, ++item_no ) {
00288 stream << '<' << (*meta_it)->first;
00289 if (do_append_no)
00290 stream << item_no;
00291 stream << " type=\"" << (*meta_it)->second << "\""
00292 " origin=\"" << (*refl_it)->name_get() << "\">" <<
00293 endl;
00294 if (*val_it) {
00295 if (respect_barriers && at_barrier)
00296 after_barrier = true;
00297 (*val_it)->accept_dumper_visitor(this);
00298 after_barrier = false;
00299 } else
00300 stream << "<null />" << endl;
00301 stream << "</" << (*meta_it)->first;
00302 if (do_append_no)
00303 stream << item_no;
00304 stream << '>' << endl;
00305 }
00306 }
00307 }
00308
00309
00310 lassert( field_it == fields->end() );
00311
00312 stream << "</" << refls->back()->name_get() << '>' << endl;
00313 }
00314
00315 readable_dumper::readable_dumper( ::std::ostream &a_stream, bool a_respect_barriers )
00316 : dumper_visitor(), stream(a_stream), respect_barriers(a_respect_barriers)
00317 {}
00318
00319 void readable_dumper::visit_object( ptr<object> o )
00320 {
00321 if (after_barrier)
00322 stream << "<after-barrier />" << endl;
00323 else
00324 follow(o);
00325 }
00326
00327 void readable_dumper::visit_nodump()
00328 {
00329 stream << "<nondumpable />" << endl;
00330 }
00331
00332 void readable_dumper::visit_lint( lint i )
00333 {
00334 stream << "<lint>" << i << "</lint>" << endl;
00335 }
00336
00337 void readable_dumper::visit_ulint( ulint i )
00338 {
00339 stream << "<ulint>" << i << "</ulint>" << endl;
00340 }
00341
00342 void readable_dumper::visit_bool( bool i )
00343 {
00344
00345 stream << "<bool>" << (i ? "true" : "false") << "</bool>" << endl;
00346 }
00347
00348 void readable_dumper::visit_lstring( const lstring &i )
00349 {
00350 lstring tmp(i);
00351 lstring sought("<>&");
00352 lstring lt("<");
00353 lstring gt(">");
00354 lstring amp("&");
00355 lstring::size_type mark = tmp.find_first_of(sought);
00356 if (mark != lstring::npos)
00357 do {
00358 switch (tmp[mark]) {
00359 case '<':
00360 tmp.replace(mark, 1, lt);
00361 break;
00362 case '>':
00363 tmp.replace(mark, 1, gt);
00364 break;
00365 case '&':
00366 tmp.replace(mark, 1, amp);
00367 break;
00368 }
00369 } while ((mark = tmp.find_first_of(sought, mark+1)) != lstring::npos);
00370 stream << "<lstring>" << tmp << "</lstring>" << endl;
00371 }
00372
00373 void readable_dumper::visit_ucn_string( const ucn_string &i )
00374 {
00375 ucn_string tmp(i);
00376 ucn_string sought("\x3c\x3e\x26");
00377 ucn_string lt("\x26\x6c\x74\x3b");
00378 ucn_string gt("\x26\x67\x74\x3b");
00379 ucn_string amp("\x26\x61\x6d\x70\x3b");
00380 ucn_string::size_type mark = tmp.find_first_of(sought);
00381 if (mark != ucn_string::npos)
00382 do {
00383 switch (tmp[mark]) {
00384 case 0x3c:
00385 tmp.replace(mark, 1, lt);
00386 break;
00387 case 0x3e:
00388 tmp.replace(mark, 1, gt);
00389 break;
00390 case 0x26:
00391 tmp.replace(mark, 1, amp);
00392 break;
00393 }
00394 } while ((mark = tmp.find_first_of(sought, mark+1)) != ucn_string::npos);
00395 stream << "<ucn_string>" << tmp << "</ucn_string>" << endl;
00396 }
00397
00398 end_package(std);
00399 end_package(lestes);