/* * * Copyright (C) 2000-2021, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: ofstd * * Author: Marco Eichelberg * * Purpose: Define alias for cout, cerr and clog * */ #include "dcmtk/config/osconfig.h" #include "dcmtk/ofstd/ofconsol.h" #include "dcmtk/ofstd/ofthread.h" #include #ifdef HAVE_UNISTD_H BEGIN_EXTERN_C #include END_EXTERN_C #endif BEGIN_EXTERN_C #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_IO_H #include #endif END_EXTERN_C #ifdef DCMTK_GUI OFOStringStream COUT; OFOStringStream CERR; #endif OFConsole::OFConsole() #ifdef DCMTK_GUI : currentCout(&COUT) , currentCerr(&CERR) #else : currentCout(&STD_NAMESPACE cout) , currentCerr(&STD_NAMESPACE cerr) #endif , joined(0) #ifdef WITH_THREADS , coutMutex() , cerrMutex() #endif { } STD_NAMESPACE ostream *OFConsole::setCout(STD_NAMESPACE ostream *newCout) { lockCout(); STD_NAMESPACE ostream *tmpCout = currentCout; #ifdef DCMTK_GUI if (newCout) currentCout = newCout; else currentCout = &COUT; #else if (newCout) currentCout = newCout; else currentCout = &STD_NAMESPACE cout; #endif unlockCout(); return tmpCout; } STD_NAMESPACE ostream *OFConsole::setCerr(STD_NAMESPACE ostream *newCerr) { lockCerr(); STD_NAMESPACE ostream *tmpCerr = currentCerr; #ifdef DCMTK_GUI if (newCerr) currentCerr = newCerr; else currentCerr = &CERR; #else if (newCerr) currentCerr = newCerr; else currentCerr = &STD_NAMESPACE cerr; #endif unlockCerr(); return tmpCerr; } void OFConsole::join() { lockCerr(); if (!joined) { // changing the state of "joined" requires that both mutexes are locked. // Mutexes must always be locked in the same order to avoid deadlocks. lockCout(); joined = 1; } // now status is joined, so unlockCerr implicitly unlocks both mutexes unlockCerr(); return; } void OFConsole::split() { lockCerr(); if (joined) { // since status is joined, lockCerr() has locked both mutexes joined = 0; // now status is unjoined, we have to unlock both mutexes manually unlockCout(); } unlockCerr(); return; } OFBool OFConsole::isJoined() { lockCerr(); // nobody will change "joined" if we have locked either mutex int result = joined; unlockCerr(); if (result) return OFTrue; else return OFFalse; } OFConsole& OFConsole::instance() { static OFConsole instance_; return instance_; } int OFConsole::old_stderr = -1; void OFConsole::mergeStderrStdout() { fflush(stderr); if (fileno(stderr) != fileno(stdout)) { /* duplicate the stderr file descriptor to be the same as stdout */ if (old_stderr < 0) old_stderr = dup(fileno(stderr)); /* now duplicate the file descriptor of stdout into the file descriptor of stderr. * This will silently close the previous file descriptor of stderr. */ if (0 != dup2(fileno(stdout), fileno(stderr))) { OFConsole::instance().lockCerr() << "Unable to redirect stderr to stdout" << OFendl; OFConsole::instance().unlockCerr(); } } #ifndef __BORLANDC__ /* setvbuf on stdout/stderr does not work with Borland C++ */ /* set stdout and stderr to unbuffered mode */ if (setvbuf(stdout, NULL, _IONBF, 0 ) != 0 ) { OFConsole::instance().lockCerr() << "Unable to switch stdout to unbuffered mode" << OFendl; OFConsole::instance().unlockCerr(); } if (setvbuf(stderr, NULL, _IONBF, 0 ) != 0 ) { OFConsole::instance().lockCerr() << "Unable to switch stderr to unbuffered mode" << OFendl; OFConsole::instance().unlockCerr(); } #endif /* __BORLANDC__ */ } void OFConsole::unmergeStderrStdout() { /* only execute this code if stderr was actually redirected before */ if (old_stderr > 0) { if (0 != dup2(old_stderr, fileno(stderr))) { OFConsole::instance().lockCerr() << "Error: Unable to release redirection of stderr to stdout" << OFendl; OFConsole::instance().unlockCerr(); } #ifndef __BORLANDC__ /* switch stdout to buffered mode */ if (setvbuf(stdout, NULL, _IOFBF, BUFSIZ ) != 0 ) { OFConsole::instance().lockCerr() << "Error: Unable to switch stdout to buffered mode" << OFendl; OFConsole::instance().unlockCerr(); } #endif /* __BORLANDC__ */ } } class OFConsoleInitializer { public: OFConsoleInitializer() { OFConsole::instance(); } }; /* the constructor of this global object makes sure * that ofConsole is initialized before main starts. * Required to make ofConsole thread-safe. */ OFConsoleInitializer ofConsoleInitializer;