|
Sierra Toolkit
Version of the Day
|
00001 /*------------------------------------------------------------------------*/ 00002 /* Copyright 2010 Sandia Corporation. */ 00003 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */ 00004 /* license for use of this work by or on behalf of the U.S. Government. */ 00005 /* Export of this program may require a license from the */ 00006 /* United States Government. */ 00007 /*------------------------------------------------------------------------*/ 00008 00009 #include <iostream> 00010 #include <stk_util/environment/OutputLog.hpp> 00011 #include <stk_util/util/TeeStreambuf.hpp> 00012 #include <stk_util/util/IndentStreambuf.hpp> 00013 00014 00015 #include <map> 00016 #include <list> 00017 #include <string> 00018 #include <iostream> 00019 #include <sstream> 00020 #include <fstream> 00021 #include <stdexcept> 00022 #include <cctype> 00023 00024 namespace stk_classic { 00025 00026 namespace { 00027 00028 struct LogStream 00029 { 00030 LogStream(const std::string &path, std::ostream *output_stream, std::ofstream *file_stream) 00031 : m_path(path), 00032 m_ostream(output_stream), 00033 m_ofstream(file_stream) 00034 {} 00035 00036 ~LogStream(); 00037 00038 std::string m_path; 00039 std::ostream * m_ostream; 00040 std::ofstream * m_ofstream; 00041 00042 private: 00043 LogStream(const LogStream &); 00044 void operator = (const LogStream &); 00045 }; 00046 00047 #ifdef __INTEL_COMPILER 00048 #pragma warning(push) 00049 #pragma warning(disable: 444) 00050 #endif 00051 struct LogStreamMap : public std::map<std::string, LogStream *> 00052 { 00053 LogStreamMap() 00054 {} 00055 00056 ~LogStreamMap() { 00057 while (!empty()) { 00058 LogStream *log_stream = (*begin()).second; 00059 erase(begin()); 00060 delete log_stream; 00061 } 00062 } 00063 }; 00064 #ifdef __INTEL_COMPILER 00065 #pragma warning(pop) 00066 #endif 00067 00068 struct OStreamTeeStreambuf 00069 { 00070 OStreamTeeStreambuf(std::ostream &output_stream) 00071 : m_ostream(&output_stream), 00072 m_origRdbuf(output_stream.rdbuf()), 00073 m_teeStreambuf(new tee_streambuf(&output_stream)) 00074 { 00075 m_ostream->rdbuf(m_teeStreambuf); 00076 } 00077 00078 ~OStreamTeeStreambuf(); 00079 00080 std::ostream * m_ostream; 00081 std::streambuf * m_origRdbuf; 00082 tee_streambuf * m_teeStreambuf; 00083 00084 private: 00085 OStreamTeeStreambuf(const OStreamTeeStreambuf &); 00086 void operator = (const OStreamTeeStreambuf &); 00087 }; 00088 00089 #ifdef __INTEL_COMPILER 00090 #pragma warning(push) 00091 #pragma warning(disable: 444) 00092 #endif 00093 struct OStreamTeeStreambufMap : public std::map<std::string, OStreamTeeStreambuf *> 00094 { 00095 OStreamTeeStreambufMap() 00096 {} 00097 00098 ~OStreamTeeStreambufMap() { 00099 while (!empty()) { 00100 OStreamTeeStreambuf *tee_streambuf = (*begin()).second; 00101 erase(begin()); 00102 delete tee_streambuf; 00103 } 00104 } 00105 }; 00106 #ifdef __INTEL_COMPILER 00107 #pragma warning(pop) 00108 #endif 00109 00110 LogStreamMap & 00111 get_file_stream_map() 00112 { 00113 static LogStreamMap s_logFileStreamMap; 00114 00115 return s_logFileStreamMap; 00116 } 00117 00118 00119 OStreamTeeStreambufMap & 00120 get_ostream_tee_streambuf_map() 00121 { 00122 static OStreamTeeStreambufMap s_ostreamTeeStreambufMap; 00123 00124 return s_ostreamTeeStreambufMap; 00125 } 00126 00127 00128 LogStream::~LogStream() 00129 { 00130 m_ostream->flush(); 00131 00132 // If the output stream was created internally (via bind_output_stream), be sure to remove it from 00133 // all OStreamTeeStreamBuf's 00134 if (m_ofstream) { 00135 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00136 00137 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00138 (*it).second->m_teeStreambuf->remove(m_ofstream); 00139 00140 delete m_ofstream; 00141 } 00142 } 00143 00144 00145 OStreamTeeStreambuf::~OStreamTeeStreambuf() 00146 { 00147 if (m_ostream) { 00148 m_ostream->flush(); 00149 m_ostream->rdbuf(m_origRdbuf); 00150 } 00151 00152 // Be sure to remove this from all OStreamTeeStreamBuf's 00153 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00154 00155 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00156 (*it).second->m_teeStreambuf->remove(m_ostream); 00157 00158 delete m_teeStreambuf; 00159 } 00160 00161 } // namespace <empty> 00162 00163 00164 void 00165 create_log_file( 00166 const std::string & name, 00167 const std::string & path) 00168 { 00169 LogStreamMap &file_stream_map = get_file_stream_map(); 00170 00171 close_log_file(name); 00172 00173 std::ofstream *file_stream = new std::ofstream(path.c_str()); 00174 00175 if(!file_stream->good()) { 00176 00177 std::ostringstream s; 00178 s << "Cannot open output log file '" << path << "' directory does not exist or is write protected."; 00179 00180 throw std::runtime_error(s.str()); 00181 00182 } 00183 00184 00185 file_stream_map[name] = new LogStream(path, file_stream, file_stream); 00186 } 00187 00188 00189 void 00190 close_log_file( 00191 const std::string & name) 00192 { 00193 LogStreamMap &file_stream_map = get_file_stream_map(); 00194 00195 LogStreamMap::iterator it = file_stream_map.find(name); 00196 00197 if (it != file_stream_map.end()) { 00198 delete (*it).second; 00199 file_stream_map.erase(it); 00200 } 00201 } 00202 00203 00204 void 00205 register_log_ostream( 00206 std::ostream & os, 00207 const std::string & name) 00208 { 00209 LogStreamMap &file_stream_map = get_file_stream_map(); 00210 00211 LogStreamMap::iterator it = file_stream_map.find(name); 00212 00213 if (it != file_stream_map.end()) { 00214 std::ostringstream s; 00215 s << "Log ostream " << name << " has already been registered"; 00216 00217 //Do we really want to throw if a stream is registered multiple times? 00218 //I don't think so... commenting this out. 00219 //throw std::runtime_error(s.str()); 00220 } 00221 else { 00222 file_stream_map[name] = new LogStream(name, &os, 0); 00223 } 00224 } 00225 00226 00227 void 00228 unregister_log_ostream( 00229 std::ostream & os) 00230 { 00231 LogStreamMap &file_stream_map = get_file_stream_map(); 00232 00233 for (LogStreamMap::iterator it = file_stream_map.begin(); it != file_stream_map.end(); ++it) { 00234 if ((*it).second->m_ostream == &os) { 00235 delete (*it).second; 00236 file_stream_map.erase(it); 00237 break; 00238 } 00239 } 00240 00241 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00242 00243 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00244 (*it).second->m_teeStreambuf->remove(&os); 00245 } 00246 00247 00248 const std::string & 00249 get_log_path( 00250 const std::string & name) 00251 { 00252 static std::string not_found = ""; 00253 00254 LogStreamMap &file_stream_map = get_file_stream_map(); 00255 00256 LogStreamMap::iterator it = file_stream_map.find(name); 00257 00258 return it == file_stream_map.end() ? not_found : (*it).second->m_path; 00259 } 00260 00261 00262 std::ostream * 00263 get_log_ostream( 00264 const std::string & name) 00265 { 00266 LogStreamMap &file_stream_map = get_file_stream_map(); 00267 00268 LogStreamMap::iterator it = file_stream_map.find(name); 00269 00270 return it == file_stream_map.end() ? 0 : (*it).second->m_ostream; 00271 } 00272 00273 00274 void 00275 register_ostream( 00276 std::ostream & os, 00277 const std::string & name) 00278 { 00279 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00280 00281 unregister_ostream(os); 00282 00283 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00284 00285 if (it != ostream_tee_streambuf_map.end()) { 00286 // delete (*it).second; 00287 // ostream_tee_streambuf_map.erase(it); 00288 // } 00289 std::ostringstream s; 00290 s << "Output stream " << name << " has already been registered"; 00291 00292 throw std::runtime_error(s.str()); 00293 } 00294 00295 ostream_tee_streambuf_map[name] = new OStreamTeeStreambuf(os); 00296 } 00297 00298 00299 void 00300 unregister_ostream( 00301 std::ostream & os) 00302 { 00303 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00304 00305 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00306 (*it).second->m_teeStreambuf->remove(&os); 00307 00308 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) { 00309 if ((*it).second->m_ostream == &os) { 00310 delete (*it).second; 00311 ostream_tee_streambuf_map.erase(it); 00312 break; 00313 } 00314 } 00315 00316 } 00317 00318 00319 std::ostream * 00320 get_ostream_ostream( 00321 const std::string & name) 00322 { 00323 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00324 00325 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00326 00327 return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream; 00328 } 00329 00330 00331 tee_streambuf * 00332 get_ostream_tee_streambuf( 00333 const std::string & name) 00334 { 00335 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00336 00337 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00338 00339 return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_teeStreambuf; 00340 } 00341 00342 00343 std::ostream * 00344 get_ostream_tee_ostream( 00345 const std::string & name) 00346 { 00347 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00348 00349 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00350 00351 return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream; 00352 } 00353 00354 00355 bool 00356 is_registered_ostream( 00357 const std::string & name) 00358 { 00359 return get_ostream_ostream(name) != 0; 00360 } 00361 00362 00363 namespace { 00364 00365 struct Command 00366 { 00367 virtual ~Command() 00368 {} 00369 00370 virtual void execute() = 0; 00371 }; 00372 00373 #ifdef __INTEL_COMPILER 00374 #pragma warning(push) 00375 #pragma warning(disable: 444) 00376 #endif 00377 struct CommandList : public std::list<Command *> 00378 { 00379 CommandList() 00380 : std::list<Command *>() 00381 {} 00382 00383 ~CommandList() 00384 { 00385 for (std::list<Command *>::iterator it = begin(); it != end(); ++it) 00386 delete (*it); 00387 } 00388 }; 00389 #ifdef __INTEL_COMPILER 00390 #pragma warning(pop) 00391 #endif 00392 00393 namespace { 00394 00395 tee_streambuf & 00396 parse_tee_streambuf( 00397 const std::string & tee_ostream_name) 00398 { 00399 tee_streambuf *osb = get_ostream_tee_streambuf(tee_ostream_name); 00400 00401 if (!osb) { 00402 std::ostringstream s; 00403 00404 s << "Output stream " << tee_ostream_name << " has not been registered for output logging"; 00405 throw std::runtime_error(s.str()); 00406 } 00407 00408 return *osb; 00409 } 00410 00411 00412 std::ostream * 00413 parse_ostream( 00414 const std::string & ostream_name) 00415 { 00416 std::ostream *os = get_log_ostream(ostream_name); 00417 00418 if (!os) 00419 os = get_ostream_tee_ostream(ostream_name); 00420 00421 if (!os) { 00422 std::ostringstream s; 00423 00424 s << "Log file '" << ostream_name << "' has not been registered"; 00425 throw std::runtime_error(s.str()); 00426 } 00427 00428 return os; 00429 } 00430 00431 00432 struct OpenLog : public Command 00433 { 00434 OpenLog( 00435 const std::string &name, 00436 const std::string &path) 00437 : m_name(name), 00438 m_path(path) 00439 {} 00440 00441 virtual ~OpenLog() 00442 {} 00443 00444 virtual void execute() { 00445 create_log_file(m_name, m_path); 00446 } 00447 00448 std::string m_name; 00449 std::string m_path; 00450 }; 00451 00452 00453 struct CloseLog : public Command 00454 { 00455 CloseLog( 00456 const std::string &name) 00457 : m_name(name) 00458 {} 00459 00460 virtual ~CloseLog() 00461 {} 00462 00463 virtual void execute() { 00464 close_log_file(m_name); 00465 } 00466 00467 std::string m_name; 00468 }; 00469 00470 00471 struct ClearTeeOStream : public Command 00472 { 00473 ClearTeeOStream( 00474 const std::string & tee_ostream_name) 00475 : m_teeOStreamName(tee_ostream_name) 00476 {} 00477 00478 virtual ~ClearTeeOStream() 00479 {} 00480 00481 virtual void execute() { 00482 parse_tee_streambuf(m_teeOStreamName).clear(); 00483 } 00484 00485 std::string m_teeOStreamName; 00486 }; 00487 00488 00489 struct AddTeeOStream : public Command 00490 { 00491 AddTeeOStream( 00492 const std::string & tee_ostream_name, 00493 const std::string & ostream_name) 00494 : m_teeOStreamName(tee_ostream_name), 00495 m_ostreamName(ostream_name) 00496 {} 00497 00498 virtual ~AddTeeOStream() 00499 {} 00500 00501 virtual void execute() { 00502 if (m_ostreamName != "null") 00503 parse_tee_streambuf(m_teeOStreamName).add(parse_ostream(m_ostreamName)); 00504 } 00505 00506 std::string m_teeOStreamName; 00507 std::string m_ostreamName; 00508 }; 00509 00510 00511 struct RemoveTeeOStream : public Command 00512 { 00513 RemoveTeeOStream( 00514 const std::string & tee_ostream_name, 00515 const std::string & ostream_name) 00516 : m_teeOStreamName(tee_ostream_name), 00517 m_ostreamName(ostream_name) 00518 {} 00519 00520 virtual ~RemoveTeeOStream() 00521 {} 00522 00523 virtual void execute() { 00524 parse_tee_streambuf(m_teeOStreamName).remove(parse_ostream(m_ostreamName)); 00525 } 00526 00527 std::string m_teeOStreamName; 00528 std::string m_ostreamName; 00529 }; 00530 00531 } // namespace <empty> 00532 00533 00534 /* 00535 * Startup: out > cout pout > cout dout > cout 00536 * Normal: out > log-path+pout pout > null dout > out 00537 * Diagnostic: out > out-path+pout pout > pout-path dout > out 00538 * 00539 * Modify: out > +pout 00540 * out > -pout 00541 */ 00542 void 00543 parse_output_description( 00544 const std::string & output_description, 00545 CommandList & command_list) 00546 { 00547 typedef std::pair<const char *, const char *> Token; 00548 typedef std::list<Token> TokenList; 00549 00550 command_list.clear(); 00551 00552 TokenList tokens; 00553 00554 for (const char *c = output_description.c_str(); *c; ) { 00555 if (std::isspace(*c)) 00556 ++c; 00557 00558 else if (*c == '>' || *c == '+' || *c == '-' || *c == '=') { 00559 tokens.push_back(Token(c, c + 1)); 00560 ++c; 00561 } 00562 00563 else if (*c == '\"') { 00564 const char *d = c + 1; 00565 while (*d && *d != '\"') 00566 ++d; 00567 tokens.push_back(Token(c + 1, d)); 00568 c = d + 1; 00569 } 00570 00571 else { 00572 const char *d = c; 00573 while (std::isgraph(*d) && *d != '+' && *d != '-' &&*d != '=' && *d != '>') 00574 ++d; 00575 tokens.push_back(Token(c, d)); 00576 c = d; 00577 } 00578 } 00579 00580 for (TokenList::iterator it = tokens.begin(); it != tokens.end(); ) { 00581 std::string name((*it).first, (*it).second); 00582 00583 ++it; if (it == tokens.end()) break; 00584 std::string operation((*it).first, (*it).second); 00585 00586 if (operation == "=") { 00587 ++it; if (it == tokens.end()) break; 00588 std::string path((*it).first, (*it).second); 00589 if (!path.empty()) 00590 command_list.push_back(new OpenLog(name, path)); 00591 else 00592 command_list.push_back(new CloseLog(name)); 00593 ++it; if (it == tokens.end()) break; 00594 } 00595 00596 else if (operation == ">") { 00597 parse_tee_streambuf(name); 00598 00599 ++it; if (it == tokens.end()) break; 00600 std::string token(std::string((*it).first, (*it).second)); 00601 if (token != "+" && token != "-") { 00602 std::string ostream_name(std::string((*it).first, (*it).second)); 00603 00604 command_list.push_back(new ClearTeeOStream(name)); 00605 command_list.push_back(new AddTeeOStream(name, ostream_name)); 00606 ++it; if (it == tokens.end()) break; 00607 } 00608 00609 while (it != tokens.end()) { 00610 token = std::string((*it).first, (*it).second); 00611 if (token == "+") { 00612 ++it; if (it == tokens.end()) break; 00613 std::string ostream_name(std::string((*it).first, (*it).second)); 00614 00615 command_list.push_back(new AddTeeOStream(name, ostream_name)); 00616 ++it; if (it == tokens.end()) break; 00617 } 00618 00619 else if (token == "-") { 00620 ++it; if (it == tokens.end()) break; 00621 std::string ostream_name(std::string((*it).first, (*it).second)); 00622 00623 command_list.push_back(new RemoveTeeOStream(name, ostream_name)); 00624 ++it; if (it == tokens.end()) break; 00625 } 00626 else 00627 break; 00628 } 00629 } 00630 } 00631 } 00632 00633 void 00634 execute( 00635 const CommandList & command_list) 00636 { 00637 for (CommandList::const_iterator it = command_list.begin(); it != command_list.end(); ++it) 00638 (*it)->execute(); 00639 } 00640 00641 } // namespace <empty> 00642 00643 void 00644 bind_output_streams( 00645 const std::string & output_description) 00646 { 00647 stk_classic::CommandList command_list; 00648 00649 parse_output_description(output_description, command_list); 00650 execute(command_list); 00651 } 00652 00653 } // namespace stk_classic 00654 00655 namespace sierra { 00656 00657 std::ostream & 00658 out() { 00659 static std::ostream s_out(std::cout.rdbuf()); 00660 00661 return s_out; 00662 } 00663 00664 00665 std::ostream & 00666 pout() { 00667 static std::ostream s_pout(std::cout.rdbuf()); 00668 00669 return s_pout; 00670 } 00671 00672 00673 std::ostream & 00674 dout() { 00675 static std::ostream s_dout(std::cout.rdbuf()); 00676 00677 return s_dout; 00678 } 00679 00680 00681 std::ostream & 00682 tout() { 00683 static std::ostream s_tout(std::cout.rdbuf()); 00684 00685 return s_tout; 00686 } 00687 00688 00689 std::ostream & 00690 dwout() { 00691 static stk_classic::indent_streambuf s_dwoutStreambuf(std::cout.rdbuf()); 00692 static std::ostream s_dwout(&s_dwoutStreambuf); 00693 00694 return s_dwout; 00695 } 00696 00697 } // namespace sierra 00698 00699 00700