From 8aeb85f04ee68b960a6d326aca1a17dec2f6d019 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 9 Dec 2019 01:26:58 -0800 Subject: 5806 --- html/003trace.cc.html | 656 +++++++++++++++++++++++++------------------------- 1 file changed, 329 insertions(+), 327 deletions(-) (limited to 'html/003trace.cc.html') diff --git a/html/003trace.cc.html b/html/003trace.cc.html index 66f007fd..2b5fba00 100644 --- a/html/003trace.cc.html +++ b/html/003trace.cc.html @@ -14,9 +14,9 @@ pre { white-space: pre-wrap; font-family: monospace; color: #000000; background- body { font-size:12pt; font-family: monospace; color: #000000; background-color: #c6c6c6; } a { color:inherit; } * { font-size:12pt; font-size: 1em; } +.cSpecial { color: #008000; } .LineNr { } .Normal { color: #000000; background-color: #c6c6c6; padding-bottom: 1px; } -.cSpecial { color: #008000; } .Comment { color: #005faf; } .Delimiter { color: #c000c0; } .Special { color: #d70000; } @@ -192,7 +192,7 @@ if ('onhashchange' in window) { 131 132 string unescape_newline(string& s) { 133 std::stringstream ss; -134 for (int i = 0; i < SIZE(s); ++i) { +134 for (int i = 0; i < SIZE(s); ++i) { 135 if (s.at(i) == '\n') 136 ss << "\\n"; 137 else @@ -245,340 +245,342 @@ if ('onhashchange' in window) { 184 if (!curr_stream) return; 185 string curr_contents = curr_stream->str(); 186 if (!curr_contents.empty()) { -187 past_lines.push_back(trace_line(curr_contents, trim(curr_label), curr_depth)); // preserve indent in contents +187 past_lines.push_back(trace_line(curr_contents, trim(curr_label), curr_depth)); // preserve indent in contents 188 // maybe incrementally dump trace 189 trace_line& t = past_lines.back(); -190 if (should_incrementally_print_trace()) { +190 if (should_incrementally_print_trace()) { 191 dump_trace_line(cerr, t); 192 } -193 // End trace Commit -194 } -195 -196 // clean up -197 delete curr_stream; -198 curr_stream = NULL; -199 curr_label.clear(); -200 curr_depth = Max_depth; -201 } -202 -203 //:: == Initializing the trace in tests +193 // Hack: on 'subx --trace --dump', emit only to stderr, not 'last_run'. +194 if (Dump_trace) past_lines.pop_back(); // economize on memory +195 // End trace Commit +196 } +197 +198 // clean up +199 delete curr_stream; +200 curr_stream = NULL; +201 curr_label.clear(); +202 curr_depth = Max_depth; +203 } 204 -205 :(before "End Includes") -206 #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; -207 :(before "End Test Setup") -208 START_TRACING_UNTIL_END_OF_SCOPE -209 -210 //: Trace_stream is a resource, lease_tracer uses RAII to manage it. -211 :(before "End Types") -212 struct lease_tracer { -213 lease_tracer(); -214 ~lease_tracer(); -215 }; -216 :(code) -217 lease_tracer::lease_tracer() { Trace_stream = new trace_stream; } -218 lease_tracer::~lease_tracer() { -219 delete Trace_stream; -220 Trace_stream = NULL; -221 } -222 -223 //:: == Errors and warnings using traces +205 //:: == Initializing the trace in tests +206 +207 :(before "End Includes") +208 #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; +209 :(before "End Test Setup") +210 START_TRACING_UNTIL_END_OF_SCOPE +211 +212 //: Trace_stream is a resource, lease_tracer uses RAII to manage it. +213 :(before "End Types") +214 struct lease_tracer { +215 lease_tracer(); +216 ~lease_tracer(); +217 }; +218 :(code) +219 lease_tracer::lease_tracer() { Trace_stream = new trace_stream; } +220 lease_tracer::~lease_tracer() { +221 delete Trace_stream; +222 Trace_stream = NULL; +223 } 224 -225 :(before "End Includes") -226 #define raise (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Error_depth, "error")) -227 #define warn (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Warn_depth, "warn")) -228 -229 //: Print errors and warnings to the screen by default. -230 :(before "struct trace_stream") // include constants in all cleaved compilation units -231 const int Error_depth = 0; -232 const int Warn_depth = 1; -233 :(before "End Globals") -234 int Hide_errors = false; // if set, don't print errors or warnings to screen -235 int Hide_warnings = false; // if set, don't print warnings to screen -236 :(before "End Reset") -237 Hide_errors = false; -238 Hide_warnings = false; -239 //: Never dump warnings in tests -240 :(before "End Test Setup") -241 Hide_warnings = true; -242 :(code) -243 bool trace_stream::should_incrementally_print_trace() { -244 if (!Hide_errors && curr_depth == Error_depth) return true; -245 if (!Hide_warnings && !Hide_errors && curr_depth == Warn_depth) return true; -246 // End Incremental Trace Print Conditions -247 return false; -248 } -249 :(before "End trace_stream Methods") -250 bool should_incrementally_print_trace(); -251 -252 :(before "End Globals") -253 int Trace_errors = 0; // used only when Trace_stream is NULL -254 -255 // Fail tests that displayed (unexpected) errors. -256 // Expected errors should always be hidden and silently checked for. -257 :(before "End Test Teardown") -258 if (Passed && !Hide_errors && trace_contains_errors()) { -259 Passed = false; -260 } -261 :(code) -262 bool trace_contains_errors() { -263 return Trace_errors > 0 || trace_count("error") > 0; -264 } -265 -266 :(before "End Includes") -267 // If we aren't yet sure how to deal with some corner case, use assert_for_now -268 // to indicate that it isn't an inviolable invariant. -269 #define assert_for_now assert -270 #define raise_for_now raise -271 -272 //:: == Other assertions on traces -273 //: Primitives: -274 //: - CHECK_TRACE_CONTENTS(lines) -275 //: Assert that the trace contains the given lines (separated by newlines) -276 //: in order. There can be other intervening lines between them. -277 //: - CHECK_TRACE_DOESNT_CONTAIN(line) -278 //: - CHECK_TRACE_DOESNT_CONTAIN(label, contents) -279 //: Assert that the trace doesn't contain the given (single) line. -280 //: - CHECK_TRACE_COUNT(label, count) -281 //: Assert that the trace contains exactly 'count' lines with the given -282 //: 'label'. -283 //: - CHECK_TRACE_CONTAINS_ERRORS() -284 //: - CHECK_TRACE_DOESNT_CONTAIN_ERRORS() -285 //: - trace_count_prefix(label, prefix) -286 //: Count the number of trace lines with the given 'label' that start with -287 //: the given 'prefix'. -288 -289 :(before "End Includes") -290 #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) -291 -292 #define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) +225 //:: == Errors and warnings using traces +226 +227 :(before "End Includes") +228 #define raise (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Error_depth, "error")) +229 #define warn (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Warn_depth, "warn")) +230 +231 //: Print errors and warnings to the screen by default. +232 :(before "struct trace_stream") // include constants in all cleaved compilation units +233 const int Error_depth = 0; +234 const int Warn_depth = 1; +235 :(before "End Globals") +236 int Hide_errors = false; // if set, don't print errors or warnings to screen +237 int Hide_warnings = false; // if set, don't print warnings to screen +238 :(before "End Reset") +239 Hide_errors = false; +240 Hide_warnings = false; +241 //: Never dump warnings in tests +242 :(before "End Test Setup") +243 Hide_warnings = true; +244 :(code) +245 bool trace_stream::should_incrementally_print_trace() { +246 if (!Hide_errors && curr_depth == Error_depth) return true; +247 if (!Hide_warnings && !Hide_errors && curr_depth == Warn_depth) return true; +248 // End Incremental Trace Print Conditions +249 return false; +250 } +251 :(before "End trace_stream Methods") +252 bool should_incrementally_print_trace(); +253 +254 :(before "End Globals") +255 int Trace_errors = 0; // used only when Trace_stream is NULL +256 +257 // Fail tests that displayed (unexpected) errors. +258 // Expected errors should always be hidden and silently checked for. +259 :(before "End Test Teardown") +260 if (Passed && !Hide_errors && trace_contains_errors()) { +261 Passed = false; +262 } +263 :(code) +264 bool trace_contains_errors() { +265 return Trace_errors > 0 || trace_count("error") > 0; +266 } +267 +268 :(before "End Includes") +269 // If we aren't yet sure how to deal with some corner case, use assert_for_now +270 // to indicate that it isn't an inviolable invariant. +271 #define assert_for_now assert +272 #define raise_for_now raise +273 +274 //:: == Other assertions on traces +275 //: Primitives: +276 //: - CHECK_TRACE_CONTENTS(lines) +277 //: Assert that the trace contains the given lines (separated by newlines) +278 //: in order. There can be other intervening lines between them. +279 //: - CHECK_TRACE_DOESNT_CONTAIN(line) +280 //: - CHECK_TRACE_DOESNT_CONTAIN(label, contents) +281 //: Assert that the trace doesn't contain the given (single) line. +282 //: - CHECK_TRACE_COUNT(label, count) +283 //: Assert that the trace contains exactly 'count' lines with the given +284 //: 'label'. +285 //: - CHECK_TRACE_CONTAINS_ERRORS() +286 //: - CHECK_TRACE_DOESNT_CONTAIN_ERRORS() +287 //: - trace_count_prefix(label, prefix) +288 //: Count the number of trace lines with the given 'label' that start with +289 //: the given 'prefix'. +290 +291 :(before "End Includes") +292 #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) 293 -294 #define CHECK_TRACE_COUNT(label, count) \ -295 if (Passed && trace_count(label) != (count)) { \ -296 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): trace_count of " << label << " should be " << count << '\n'; \ -297 cerr << " got " << trace_count(label) << '\n'; /* multiple eval */ \ -298 DUMP(label); \ -299 Passed = false; \ -300 return; /* Currently we stop at the very first failure. */ \ -301 } -302 -303 #define CHECK_TRACE_CONTAINS_ERRORS() CHECK(trace_contains_errors()) -304 #define CHECK_TRACE_DOESNT_CONTAIN_ERRORS() \ -305 if (Passed && trace_contains_errors()) { \ -306 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected errors\n"; \ -307 DUMP("error"); \ -308 Passed = false; \ -309 return; \ -310 } -311 -312 // Allow tests to ignore trace lines generated during setup. -313 #define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream -314 -315 :(code) -316 bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { -317 if (!Passed) return false; -318 if (!Trace_stream) return false; -319 vector<string> expected_lines = split(expected, "\n"); -320 int curr_expected_line = 0; -321 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) -322 ++curr_expected_line; -323 if (curr_expected_line == SIZE(expected_lines)) return true; -324 string label, contents; -325 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); -326 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -327 if (label != p->label) continue; -328 string t = trim(p->contents); -329 if (contents != unescape_newline(t)) continue; -330 ++curr_expected_line; -331 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) -332 ++curr_expected_line; -333 if (curr_expected_line == SIZE(expected_lines)) return true; -334 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); -335 } -336 -337 if (line_exists_anywhere(label, contents)) { -338 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; -339 DUMP(""); -340 } -341 else { -342 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; -343 DUMP(label); -344 } -345 Passed = false; -346 return false; -347 } -348 -349 bool trace_doesnt_contain(string expected) { -350 vector<string> tmp = split_first(expected, ": "); -351 if (SIZE(tmp) == 1) { -352 raise << expected << ": missing label or contents in trace line\n" << end(); -353 assert(false); -354 } -355 return trace_count(tmp.at(0), tmp.at(1)) == 0; -356 } -357 -358 int trace_count(string label) { -359 return trace_count(label, ""); -360 } -361 -362 int trace_count(string label, string line) { -363 if (!Trace_stream) return 0; -364 long result = 0; -365 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -366 if (label == p->label) { -367 if (line == "" || trim(line) == trim(p->contents)) -368 ++result; -369 } -370 } -371 return result; -372 } -373 -374 int trace_count_prefix(string label, string prefix) { -375 if (!Trace_stream) return 0; -376 long result = 0; -377 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -378 if (label == p->label) { -379 if (starts_with(trim(p->contents), trim(prefix))) -380 ++result; -381 } -382 } -383 return result; -384 } -385 -386 void split_label_contents(const string& s, string* label, string* contents) { -387 static const string delim(": "); -388 size_t pos = s.find(delim); -389 if (pos == string::npos) { -390 *label = ""; -391 *contents = trim(s); -392 } -393 else { -394 *label = trim(s.substr(0, pos)); -395 *contents = trim(s.substr(pos+SIZE(delim))); -396 } -397 } -398 -399 bool line_exists_anywhere(const string& label, const string& contents) { -400 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -401 if (label != p->label) continue; -402 if (contents == trim(p->contents)) return true; -403 } -404 return false; -405 } -406 -407 vector<string> split(string s, string delim) { -408 vector<string> result; -409 size_t begin=0, end=s.find(delim); -410 while (true) { -411 if (end == string::npos) { -412 result.push_back(string(s, begin, string::npos)); -413 break; -414 } -415 result.push_back(string(s, begin, end-begin)); -416 begin = end+SIZE(delim); -417 end = s.find(delim, begin); -418 } -419 return result; -420 } -421 -422 vector<string> split_first(string s, string delim) { -423 vector<string> result; -424 size_t end=s.find(delim); -425 result.push_back(string(s, 0, end)); -426 if (end != string::npos) -427 result.push_back(string(s, end+SIZE(delim), string::npos)); -428 return result; -429 } -430 -431 //:: == Helpers for debugging using traces +294 #define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) +295 +296 #define CHECK_TRACE_COUNT(label, count) \ +297 if (Passed && trace_count(label) != (count)) { \ +298 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): trace_count of " << label << " should be " << count << '\n'; \ +299 cerr << " got " << trace_count(label) << '\n'; /* multiple eval */ \ +300 DUMP(label); \ +301 Passed = false; \ +302 return; /* Currently we stop at the very first failure. */ \ +303 } +304 +305 #define CHECK_TRACE_CONTAINS_ERRORS() CHECK(trace_contains_errors()) +306 #define CHECK_TRACE_DOESNT_CONTAIN_ERRORS() \ +307 if (Passed && trace_contains_errors()) { \ +308 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected errors\n"; \ +309 DUMP("error"); \ +310 Passed = false; \ +311 return; \ +312 } +313 +314 // Allow tests to ignore trace lines generated during setup. +315 #define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream +316 +317 :(code) +318 bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { +319 if (!Passed) return false; +320 if (!Trace_stream) return false; +321 vector<string> expected_lines = split(expected, "\n"); +322 int curr_expected_line = 0; +323 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) +324 ++curr_expected_line; +325 if (curr_expected_line == SIZE(expected_lines)) return true; +326 string label, contents; +327 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); +328 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +329 if (label != p->label) continue; +330 string t = trim(p->contents); +331 if (contents != unescape_newline(t)) continue; +332 ++curr_expected_line; +333 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) +334 ++curr_expected_line; +335 if (curr_expected_line == SIZE(expected_lines)) return true; +336 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); +337 } +338 +339 if (line_exists_anywhere(label, contents)) { +340 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; +341 DUMP(""); +342 } +343 else { +344 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; +345 DUMP(label); +346 } +347 Passed = false; +348 return false; +349 } +350 +351 bool trace_doesnt_contain(string expected) { +352 vector<string> tmp = split_first(expected, ": "); +353 if (SIZE(tmp) == 1) { +354 raise << expected << ": missing label or contents in trace line\n" << end(); +355 assert(false); +356 } +357 return trace_count(tmp.at(0), tmp.at(1)) == 0; +358 } +359 +360 int trace_count(string label) { +361 return trace_count(label, ""); +362 } +363 +364 int trace_count(string label, string line) { +365 if (!Trace_stream) return 0; +366 long result = 0; +367 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +368 if (label == p->label) { +369 if (line == "" || trim(line) == trim(p->contents)) +370 ++result; +371 } +372 } +373 return result; +374 } +375 +376 int trace_count_prefix(string label, string prefix) { +377 if (!Trace_stream) return 0; +378 long result = 0; +379 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +380 if (label == p->label) { +381 if (starts_with(trim(p->contents), trim(prefix))) +382 ++result; +383 } +384 } +385 return result; +386 } +387 +388 void split_label_contents(const string& s, string* label, string* contents) { +389 static const string delim(": "); +390 size_t pos = s.find(delim); +391 if (pos == string::npos) { +392 *label = ""; +393 *contents = trim(s); +394 } +395 else { +396 *label = trim(s.substr(0, pos)); +397 *contents = trim(s.substr(pos+SIZE(delim))); +398 } +399 } +400 +401 bool line_exists_anywhere(const string& label, const string& contents) { +402 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +403 if (label != p->label) continue; +404 if (contents == trim(p->contents)) return true; +405 } +406 return false; +407 } +408 +409 vector<string> split(string s, string delim) { +410 vector<string> result; +411 size_t begin=0, end=s.find(delim); +412 while (true) { +413 if (end == string::npos) { +414 result.push_back(string(s, begin, string::npos)); +415 break; +416 } +417 result.push_back(string(s, begin, end-begin)); +418 begin = end+SIZE(delim); +419 end = s.find(delim, begin); +420 } +421 return result; +422 } +423 +424 vector<string> split_first(string s, string delim) { +425 vector<string> result; +426 size_t end=s.find(delim); +427 result.push_back(string(s, 0, end)); +428 if (end != string::npos) +429 result.push_back(string(s, end+SIZE(delim), string::npos)); +430 return result; +431 } 432 -433 :(before "End Includes") -434 // To debug why a test is failing, dump its trace using '?'. -435 #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); -436 -437 // To add temporary prints to the trace, use 'dbg'. -438 // `git log` should never show any calls to 'dbg'. -439 #define dbg trace(0, "a") -440 -441 //: Dump the entire trace to file where it can be browsed offline. -442 //: Dump the trace as it happens; that way you get something even if the -443 //: program crashes. -444 -445 :(before "End Globals") -446 ofstream Trace_file; -447 :(before "End Commandline Options(*arg)") -448 else if (is_equal(*arg, "--trace")) { -449 cerr << "saving trace to 'last_run'\n"; -450 Trace_file.open("last_run"); -451 // Add a dummy line up top; otherwise the `browse_trace` tool currently has -452 // no way to expand any lines above an error. -453 Trace_file << " 0 dummy: start\n"; -454 } -455 :(before "End trace Commit") -456 if (Trace_file) { -457 dump_trace_line(Trace_file, t); -458 } -459 :(before "End One-time Setup") -460 atexit(cleanup_main); -461 :(code) -462 void cleanup_main() { -463 if (Trace_file) Trace_file.close(); -464 // End cleanup_main -465 } -466 -467 :(before "End trace_stream Methods") -468 string readable_contents(string label) { -469 string trim(const string& s); // prototype -470 ostringstream output; -471 label = trim(label); -472 for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) -473 if (label.empty() || label == p->label) -474 dump_trace_line(output, *p); -475 return output.str(); -476 } -477 -478 //: Print traces to the screen as they happen. -479 //: Particularly useful when juggling multiple trace streams, like when -480 //: debugging sandboxes. -481 :(before "End Globals") -482 bool Dump_trace = false; -483 :(before "End Commandline Options(*arg)") -484 else if (is_equal(*arg, "--dump")) { -485 Dump_trace = true; -486 } -487 :(before "End Incremental Trace Print Conditions") -488 if (Dump_trace) return true; -489 -490 //: Miscellaneous helpers. +433 //:: == Helpers for debugging using traces +434 +435 :(before "End Includes") +436 // To debug why a test is failing, dump its trace using '?'. +437 #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); +438 +439 // To add temporary prints to the trace, use 'dbg'. +440 // `git log` should never show any calls to 'dbg'. +441 #define dbg trace(0, "a") +442 +443 //: Dump the entire trace to file where it can be browsed offline. +444 //: Dump the trace as it happens; that way you get something even if the +445 //: program crashes. +446 +447 :(before "End Globals") +448 ofstream Trace_file; +449 :(before "End Commandline Options(*arg)") +450 else if (is_equal(*arg, "--trace")) { +451 cerr << "saving trace to 'last_run'\n"; +452 Trace_file.open("last_run"); +453 // Add a dummy line up top; otherwise the `browse_trace` tool currently has +454 // no way to expand any lines above an error. +455 Trace_file << " 0 dummy: start\n"; +456 } +457 :(before "End trace Commit") +458 if (Trace_file) { +459 dump_trace_line(Trace_file, t); +460 } +461 :(before "End One-time Setup") +462 atexit(cleanup_main); +463 :(code) +464 void cleanup_main() { +465 if (Trace_file) Trace_file.close(); +466 // End cleanup_main +467 } +468 +469 :(before "End trace_stream Methods") +470 string readable_contents(string label) { +471 string trim(const string& s); // prototype +472 ostringstream output; +473 label = trim(label); +474 for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) +475 if (label.empty() || label == p->label) +476 dump_trace_line(output, *p); +477 return output.str(); +478 } +479 +480 //: Print traces to the screen as they happen. +481 //: Particularly useful when juggling multiple trace streams, like when +482 //: debugging sandboxes. +483 :(before "End Globals") +484 bool Dump_trace = false; +485 :(before "End Commandline Options(*arg)") +486 else if (is_equal(*arg, "--dump")) { +487 Dump_trace = true; +488 } +489 :(before "End Incremental Trace Print Conditions") +490 if (Dump_trace) return true; 491 -492 :(code) -493 string trim(const string& s) { -494 string::const_iterator first = s.begin(); -495 while (first != s.end() && isspace(*first)) -496 ++first; -497 if (first == s.end()) return ""; -498 -499 string::const_iterator last = --s.end(); -500 while (last != s.begin() && isspace(*last)) -501 --last; -502 ++last; -503 return string(first, last); -504 } -505 -506 :(before "End Includes") -507 #include <vector> -508 using std::vector; -509 #include <list> -510 using std::list; -511 #include <set> -512 using std::set; -513 -514 #include <sstream> -515 using std::istringstream; -516 using std::ostringstream; -517 -518 #include <fstream> -519 using std::ifstream; -520 using std::ofstream; +492 //: Miscellaneous helpers. +493 +494 :(code) +495 string trim(const string& s) { +496 string::const_iterator first = s.begin(); +497 while (first != s.end() && isspace(*first)) +498 ++first; +499 if (first == s.end()) return ""; +500 +501 string::const_iterator last = --s.end(); +502 while (last != s.begin() && isspace(*last)) +503 --last; +504 ++last; +505 return string(first, last); +506 } +507 +508 :(before "End Includes") +509 #include <vector> +510 using std::vector; +511 #include <list> +512 using std::list; +513 #include <set> +514 using std::set; +515 +516 #include <sstream> +517 using std::istringstream; +518 using std::ostringstream; +519 +520 #include <fstream> +521 using std::ifstream; +522 using std::ofstream; -- cgit 1.4.1-2-gfad0