|
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 m_ostream->flush(); 00146 m_ostream->rdbuf(m_origRdbuf); 00147 00148 // Be sure to remove this from all OStreamTeeStreamBuf's 00149 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00150 00151 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00152 (*it).second->m_teeStreambuf->remove(m_ostream); 00153 00154 delete m_teeStreambuf; 00155 } 00156 00157 } // namespace <empty> 00158 00159 00160 void 00161 create_log_file( 00162 const std::string & name, 00163 const std::string & path) 00164 { 00165 LogStreamMap &file_stream_map = get_file_stream_map(); 00166 00167 close_log_file(name); 00168 00169 std::ofstream *file_stream = new std::ofstream(path.c_str()); 00170 00171 file_stream_map[name] = new LogStream(path, file_stream, file_stream); 00172 } 00173 00174 00175 void 00176 close_log_file( 00177 const std::string & name) 00178 { 00179 LogStreamMap &file_stream_map = get_file_stream_map(); 00180 00181 LogStreamMap::iterator it = file_stream_map.find(name); 00182 00183 if (it != file_stream_map.end()) { 00184 delete (*it).second; 00185 file_stream_map.erase(it); 00186 } 00187 } 00188 00189 00190 void 00191 register_log_ostream( 00192 std::ostream & os, 00193 const std::string & name) 00194 { 00195 LogStreamMap &file_stream_map = get_file_stream_map(); 00196 00197 LogStreamMap::iterator it = file_stream_map.find(name); 00198 00199 if (it != file_stream_map.end()) { 00200 std::ostringstream s; 00201 s << "Log ostream " << name << " has already been registered"; 00202 00203 throw std::runtime_error(s.str()); 00204 } 00205 00206 file_stream_map[name] = new LogStream(name, &os, 0); 00207 } 00208 00209 00210 void 00211 unregister_log_ostream( 00212 std::ostream & os) 00213 { 00214 LogStreamMap &file_stream_map = get_file_stream_map(); 00215 00216 for (LogStreamMap::iterator it = file_stream_map.begin(); it != file_stream_map.end(); ++it) { 00217 if ((*it).second->m_ostream == &os) { 00218 delete (*it).second; 00219 file_stream_map.erase(it); 00220 break; 00221 } 00222 } 00223 00224 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00225 00226 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00227 (*it).second->m_teeStreambuf->remove(&os); 00228 } 00229 00230 00231 const std::string & 00232 get_log_path( 00233 const std::string & name) 00234 { 00235 static std::string not_found = ""; 00236 00237 LogStreamMap &file_stream_map = get_file_stream_map(); 00238 00239 LogStreamMap::iterator it = file_stream_map.find(name); 00240 00241 return it == file_stream_map.end() ? not_found : (*it).second->m_path; 00242 } 00243 00244 00245 std::ostream * 00246 get_log_ostream( 00247 const std::string & name) 00248 { 00249 LogStreamMap &file_stream_map = get_file_stream_map(); 00250 00251 LogStreamMap::iterator it = file_stream_map.find(name); 00252 00253 return it == file_stream_map.end() ? 0 : (*it).second->m_ostream; 00254 } 00255 00256 00257 void 00258 register_ostream( 00259 std::ostream & os, 00260 const std::string & name) 00261 { 00262 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00263 00264 unregister_ostream(os); 00265 00266 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00267 00268 if (it != ostream_tee_streambuf_map.end()) { 00269 // delete (*it).second; 00270 // ostream_tee_streambuf_map.erase(it); 00271 // } 00272 std::ostringstream s; 00273 s << "Output stream " << name << " has already been registered"; 00274 00275 throw std::runtime_error(s.str()); 00276 } 00277 00278 ostream_tee_streambuf_map[name] = new OStreamTeeStreambuf(os); 00279 } 00280 00281 00282 void 00283 unregister_ostream( 00284 std::ostream & os) 00285 { 00286 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00287 00288 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) 00289 (*it).second->m_teeStreambuf->remove(&os); 00290 00291 for (OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.begin(); it != ostream_tee_streambuf_map.end(); ++it) { 00292 if ((*it).second->m_ostream == &os) { 00293 delete (*it).second; 00294 ostream_tee_streambuf_map.erase(it); 00295 break; 00296 } 00297 } 00298 00299 } 00300 00301 00302 std::ostream * 00303 get_ostream_ostream( 00304 const std::string & name) 00305 { 00306 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00307 00308 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00309 00310 return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream; 00311 } 00312 00313 00314 tee_streambuf * 00315 get_ostream_tee_streambuf( 00316 const std::string & name) 00317 { 00318 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00319 00320 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00321 00322 return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_teeStreambuf; 00323 } 00324 00325 00326 std::ostream * 00327 get_ostream_tee_ostream( 00328 const std::string & name) 00329 { 00330 OStreamTeeStreambufMap &ostream_tee_streambuf_map = get_ostream_tee_streambuf_map(); 00331 00332 OStreamTeeStreambufMap::iterator it = ostream_tee_streambuf_map.find(name); 00333 00334 return it == ostream_tee_streambuf_map.end() ? 0 : (*it).second->m_ostream; 00335 } 00336 00337 00338 bool 00339 is_registered_ostream( 00340 const std::string & name) 00341 { 00342 return get_ostream_ostream(name) != 0; 00343 } 00344 00345 00346 namespace { 00347 00348 struct Command 00349 { 00350 virtual ~Command() 00351 {} 00352 00353 virtual void execute() = 0; 00354 }; 00355 00356 #ifdef __INTEL_COMPILER 00357 #pragma warning(push) 00358 #pragma warning(disable: 444) 00359 #endif 00360 struct CommandList : public std::list<Command *> 00361 { 00362 CommandList() 00363 : std::list<Command *>() 00364 {} 00365 00366 ~CommandList() 00367 { 00368 for (std::list<Command *>::iterator it = begin(); it != end(); ++it) 00369 delete (*it); 00370 } 00371 }; 00372 #ifdef __INTEL_COMPILER 00373 #pragma warning(pop) 00374 #endif 00375 00376 namespace { 00377 00378 tee_streambuf & 00379 parse_tee_streambuf( 00380 const std::string & tee_ostream_name) 00381 { 00382 tee_streambuf *osb = get_ostream_tee_streambuf(tee_ostream_name); 00383 00384 if (!osb) { 00385 std::ostringstream s; 00386 00387 s << "Output stream " << tee_ostream_name << " has not been registered for output logging"; 00388 throw std::runtime_error(s.str()); 00389 } 00390 00391 return *osb; 00392 } 00393 00394 00395 std::ostream * 00396 parse_ostream( 00397 const std::string & ostream_name) 00398 { 00399 std::ostream *os = get_log_ostream(ostream_name); 00400 00401 if (!os) 00402 os = get_ostream_tee_ostream(ostream_name); 00403 00404 if (!os) { 00405 std::ostringstream s; 00406 00407 s << "Log file '" << ostream_name << "' has not been registered"; 00408 throw std::runtime_error(s.str()); 00409 } 00410 00411 return os; 00412 } 00413 00414 00415 struct OpenLog : public Command 00416 { 00417 OpenLog( 00418 const std::string &name, 00419 const std::string &path) 00420 : m_name(name), 00421 m_path(path) 00422 {} 00423 00424 virtual ~OpenLog() 00425 {} 00426 00427 virtual void execute() { 00428 create_log_file(m_name, m_path); 00429 } 00430 00431 std::string m_name; 00432 std::string m_path; 00433 }; 00434 00435 00436 struct CloseLog : public Command 00437 { 00438 CloseLog( 00439 const std::string &name) 00440 : m_name(name) 00441 {} 00442 00443 virtual ~CloseLog() 00444 {} 00445 00446 virtual void execute() { 00447 close_log_file(m_name); 00448 } 00449 00450 std::string m_name; 00451 }; 00452 00453 00454 struct ClearTeeOStream : public Command 00455 { 00456 ClearTeeOStream( 00457 const std::string & tee_ostream_name) 00458 : m_teeOStreamName(tee_ostream_name) 00459 {} 00460 00461 virtual ~ClearTeeOStream() 00462 {} 00463 00464 virtual void execute() { 00465 parse_tee_streambuf(m_teeOStreamName).clear(); 00466 } 00467 00468 std::string m_teeOStreamName; 00469 }; 00470 00471 00472 struct AddTeeOStream : public Command 00473 { 00474 AddTeeOStream( 00475 const std::string & tee_ostream_name, 00476 const std::string & ostream_name) 00477 : m_teeOStreamName(tee_ostream_name), 00478 m_ostreamName(ostream_name) 00479 {} 00480 00481 virtual ~AddTeeOStream() 00482 {} 00483 00484 virtual void execute() { 00485 if (m_ostreamName != "null") 00486 parse_tee_streambuf(m_teeOStreamName).add(parse_ostream(m_ostreamName)); 00487 } 00488 00489 std::string m_teeOStreamName; 00490 std::string m_ostreamName; 00491 }; 00492 00493 00494 struct RemoveTeeOStream : public Command 00495 { 00496 RemoveTeeOStream( 00497 const std::string & tee_ostream_name, 00498 const std::string & ostream_name) 00499 : m_teeOStreamName(tee_ostream_name), 00500 m_ostreamName(ostream_name) 00501 {} 00502 00503 virtual ~RemoveTeeOStream() 00504 {} 00505 00506 virtual void execute() { 00507 parse_tee_streambuf(m_teeOStreamName).remove(parse_ostream(m_ostreamName)); 00508 } 00509 00510 std::string m_teeOStreamName; 00511 std::string m_ostreamName; 00512 }; 00513 00514 } // namespace <empty> 00515 00516 00517 /* 00518 * Startup: out > cout pout > cout dout > cout 00519 * Normal: out > log-path+pout pout > null dout > out 00520 * Diagnostic: out > out-path+pout pout > pout-path dout > out 00521 * 00522 * Modify: out > +pout 00523 * out > -pout 00524 */ 00525 void 00526 parse_output_description( 00527 const std::string & output_description, 00528 CommandList & command_list) 00529 { 00530 typedef std::pair<const char *, const char *> Token; 00531 typedef std::list<Token> TokenList; 00532 00533 command_list.clear(); 00534 00535 TokenList tokens; 00536 00537 for (const char *c = output_description.c_str(); *c; ) { 00538 if (std::isspace(*c)) 00539 ++c; 00540 00541 else if (*c == '>' || *c == '+' || *c == '-' || *c == '=') { 00542 tokens.push_back(Token(c, c + 1)); 00543 ++c; 00544 } 00545 00546 else if (*c == '\"') { 00547 const char *d = c + 1; 00548 while (*d && *d != '\"') 00549 ++d; 00550 tokens.push_back(Token(c + 1, d)); 00551 c = d + 1; 00552 } 00553 00554 else { 00555 const char *d = c; 00556 while (std::isgraph(*d) && *d != '+' && *d != '-' &&*d != '=' && *d != '>') 00557 ++d; 00558 tokens.push_back(Token(c, d)); 00559 c = d; 00560 } 00561 } 00562 00563 for (TokenList::iterator it = tokens.begin(); it != tokens.end(); ) { 00564 std::string name((*it).first, (*it).second); 00565 00566 ++it; if (it == tokens.end()) break; 00567 std::string operation((*it).first, (*it).second); 00568 00569 if (operation == "=") { 00570 ++it; if (it == tokens.end()) break; 00571 std::string path((*it).first, (*it).second); 00572 if (!path.empty()) 00573 command_list.push_back(new OpenLog(name, path)); 00574 else 00575 command_list.push_back(new CloseLog(name)); 00576 ++it; if (it == tokens.end()) break; 00577 } 00578 00579 else if (operation == ">") { 00580 parse_tee_streambuf(name); 00581 00582 ++it; if (it == tokens.end()) break; 00583 std::string token(std::string((*it).first, (*it).second)); 00584 if (token != "+" && token != "-") { 00585 std::string ostream_name(std::string((*it).first, (*it).second)); 00586 00587 command_list.push_back(new ClearTeeOStream(name)); 00588 command_list.push_back(new AddTeeOStream(name, ostream_name)); 00589 ++it; if (it == tokens.end()) break; 00590 } 00591 00592 while (it != tokens.end()) { 00593 token = std::string((*it).first, (*it).second); 00594 if (token == "+") { 00595 ++it; if (it == tokens.end()) break; 00596 std::string ostream_name(std::string((*it).first, (*it).second)); 00597 00598 command_list.push_back(new AddTeeOStream(name, ostream_name)); 00599 ++it; if (it == tokens.end()) break; 00600 } 00601 00602 else if (token == "-") { 00603 ++it; if (it == tokens.end()) break; 00604 std::string ostream_name(std::string((*it).first, (*it).second)); 00605 00606 command_list.push_back(new RemoveTeeOStream(name, ostream_name)); 00607 ++it; if (it == tokens.end()) break; 00608 } 00609 else 00610 break; 00611 } 00612 } 00613 } 00614 } 00615 00616 void 00617 execute( 00618 const CommandList & command_list) 00619 { 00620 for (CommandList::const_iterator it = command_list.begin(); it != command_list.end(); ++it) 00621 (*it)->execute(); 00622 } 00623 00624 } // namespace <empty> 00625 00626 void 00627 bind_output_streams( 00628 const std::string & output_description) 00629 { 00630 stk::CommandList command_list; 00631 00632 parse_output_description(output_description, command_list); 00633 execute(command_list); 00634 } 00635 00636 } // namespace stk