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