LCOV - code coverage report
Current view: top level - src/utils/iodevices - OutputDevice.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 88 112 78.6 %
Date: 2024-05-05 15:31:14 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2004-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    OutputDevice.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Jakob Erdmann
      17             : /// @author  Michael Behrisch
      18             : /// @date    2004
      19             : ///
      20             : // Static storage of an output device and its base (abstract) implementation
      21             : /****************************************************************************/
      22             : #include <config.h>
      23             : 
      24             : #include <map>
      25             : #include <fstream>
      26             : #include <sstream>
      27             : #include <string>
      28             : #include <iomanip>
      29             : #ifdef WIN32
      30             : #define NOMINMAX
      31             : #include <windows.h>
      32             : #undef NOMINMAX
      33             : #endif
      34             : #include "OutputDevice.h"
      35             : #include "OutputDevice_File.h"
      36             : #include "OutputDevice_COUT.h"
      37             : #include "OutputDevice_CERR.h"
      38             : #include "OutputDevice_Network.h"
      39             : #include "PlainXMLFormatter.h"
      40             : #include <utils/common/StringUtils.h>
      41             : #include <utils/common/UtilExceptions.h>
      42             : #include <utils/common/FileHelpers.h>
      43             : #include <utils/common/ToString.h>
      44             : #include <utils/common/MsgHandler.h>
      45             : #include <utils/options/OptionsCont.h>
      46             : #include <utils/options/OptionsIO.h>
      47             : 
      48             : 
      49             : // ===========================================================================
      50             : // static member definitions
      51             : // ===========================================================================
      52             : std::map<std::string, OutputDevice*> OutputDevice::myOutputDevices;
      53             : int OutputDevice::myPrevConsoleCP = -1;
      54             : 
      55             : 
      56             : // ===========================================================================
      57             : // static method definitions
      58             : // ===========================================================================
      59             : OutputDevice&
      60    17610623 : OutputDevice::getDevice(const std::string& name, bool usePrefix) {
      61             : #ifdef WIN32
      62             :     // fix the windows console output on first call
      63             :     if (myPrevConsoleCP == -1) {
      64             :         myPrevConsoleCP = GetConsoleOutputCP();
      65             :         SetConsoleOutputCP(CP_UTF8);
      66             :     }
      67             : #endif
      68             :     // check whether the device has already been aqcuired
      69    17610623 :     if (myOutputDevices.find(name) != myOutputDevices.end()) {
      70    17383915 :         return *myOutputDevices[name];
      71             :     }
      72             :     // build the device
      73             :     OutputDevice* dev = nullptr;
      74             :     // check whether the device shall print to stdout
      75      226708 :     if (name == "stdout") {
      76       72001 :         dev = OutputDevice_COUT::getDevice();
      77      154707 :     } else if (name == "stderr") {
      78      110354 :         dev = OutputDevice_CERR::getDevice();
      79       44353 :     } else if (FileHelpers::isSocket(name)) {
      80             :         try {
      81          12 :             int port = StringUtils::toInt(name.substr(name.find(":") + 1));
      82          12 :             dev = new OutputDevice_Network(name.substr(0, name.find(":")), port);
      83           0 :         } catch (NumberFormatException&) {
      84           0 :             throw IOError("Given port number '" + name.substr(name.find(":") + 1) + "' is not numeric.");
      85           0 :         } catch (EmptyData&) {
      86           0 :             throw IOError(TL("No port number given."));
      87           0 :         }
      88             :     } else {
      89       88694 :         std::string name2 = (name == "nul" || name == "NUL") ? "/dev/null" : name;
      90       90024 :         if (usePrefix && OptionsCont::getOptions().isSet("output-prefix") && name2 != "/dev/null") {
      91        2636 :             std::string prefix = OptionsCont::getOptions().getString("output-prefix");
      92             :             const std::string::size_type metaTimeIndex = prefix.find("TIME");
      93        1318 :             if (metaTimeIndex != std::string::npos) {
      94           0 :                 const time_t rawtime = std::chrono::system_clock::to_time_t(OptionsIO::getLoadTime());
      95             :                 char buffer [80];
      96           0 :                 struct tm* timeinfo = localtime(&rawtime);
      97           0 :                 strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S", timeinfo);
      98           0 :                 prefix.replace(metaTimeIndex, 4, buffer);
      99             :             }
     100        2636 :             name2 = FileHelpers::prependToLastPathComponent(prefix, name);
     101             :         }
     102       88694 :         name2 = StringUtils::substituteEnvironment(name2, &OptionsIO::getLoadTime());
     103       44347 :         const int len = (int)name.length();
     104      177225 :         dev = new OutputDevice_File(name2, len > 3 && name.substr(len - 3) == ".gz");
     105             :     }
     106      226624 :     dev->setPrecision();
     107      226624 :     dev->getOStream() << std::setiosflags(std::ios::fixed);
     108      226624 :     myOutputDevices[name] = dev;
     109      226624 :     return *dev;
     110             : }
     111             : 
     112             : 
     113             : bool
     114      709037 : OutputDevice::createDeviceByOption(const std::string& optionName,
     115             :                                    const std::string& rootElement,
     116             :                                    const std::string& schemaFile) {
     117      709037 :     if (!OptionsCont::getOptions().isSet(optionName)) {
     118             :         return false;
     119             :     }
     120       44232 :     OutputDevice& dev = OutputDevice::getDevice(OptionsCont::getOptions().getString(optionName));
     121       22094 :     if (rootElement != "") {
     122       44186 :         dev.writeXMLHeader(rootElement, schemaFile);
     123             :     }
     124             :     return true;
     125             : }
     126             : 
     127             : 
     128             : OutputDevice&
     129    17100061 : OutputDevice::getDeviceByOption(const std::string& optionName) {
     130    17100061 :     std::string devName = OptionsCont::getOptions().getString(optionName);
     131    17100061 :     if (myOutputDevices.find(devName) == myOutputDevices.end()) {
     132           0 :         throw InvalidArgument("Device '" + devName + "' has not been created.");
     133             :     }
     134    34200122 :     return OutputDevice::getDevice(devName);
     135             : }
     136             : 
     137             : 
     138             : void
     139           0 : OutputDevice::flushAll() {
     140           0 :     for (auto item : myOutputDevices) {
     141             :         item.second->flush();
     142             :     }
     143           0 : }
     144             : 
     145             : 
     146             : void
     147      145531 : OutputDevice::closeAll(bool keepErrorRetrievers) {
     148             :     std::vector<OutputDevice*> errorDevices;
     149             :     std::vector<OutputDevice*> nonErrorDevices;
     150      398481 :     for (std::map<std::string, OutputDevice*>::iterator i = myOutputDevices.begin(); i != myOutputDevices.end(); ++i) {
     151      252950 :         if (MsgHandler::getErrorInstance()->isRetriever(i->second)) {
     152      146083 :             errorDevices.push_back(i->second);
     153             :         } else {
     154      106867 :             nonErrorDevices.push_back(i->second);
     155             :         }
     156             :     }
     157      252398 :     for (OutputDevice* const dev : nonErrorDevices) {
     158             :         try {
     159      106867 :             dev->close();
     160           0 :         } catch (const IOError& e) {
     161           0 :             WRITE_ERROR(TL("Error on closing output devices."));
     162           0 :             WRITE_ERROR(e.what());
     163           0 :         }
     164             :     }
     165      145531 :     if (!keepErrorRetrievers) {
     166      220971 :         for (OutputDevice* const dev : errorDevices) {
     167             :             try {
     168      110628 :                 dev->close();
     169           0 :             } catch (const IOError& e) {
     170             :                 std::cerr << "Error on closing error output devices." << std::endl;
     171           0 :                 std::cerr << e.what() << std::endl;
     172           0 :             }
     173             :         }
     174             : #ifdef WIN32
     175             :         if (myPrevConsoleCP != -1) {
     176             :             SetConsoleOutputCP(myPrevConsoleCP);
     177             :         }
     178             : #endif
     179             :     }
     180      145531 : }
     181             : 
     182             : 
     183             : std::string
     184     2246532 : OutputDevice::realString(const double v, const int precision) {
     185     2246532 :     std::ostringstream oss;
     186     2246532 :     if (v == 0) {
     187      476833 :         return "0";
     188             :     }
     189     1769699 :     if (v < pow(10., -precision)) {
     190             :         oss.setf(std::ios::scientific, std::ios::floatfield);
     191             :     } else {
     192             :         oss.setf(std::ios::fixed, std::ios::floatfield);     // use decimal format
     193             :         oss.setf(std::ios::showpoint);    // print decimal point
     194             :         oss << std::setprecision(precision);
     195             :     }
     196             :     oss << v;
     197             :     return oss.str();
     198     2246532 : }
     199             : 
     200             : 
     201             : // ===========================================================================
     202             : // member method definitions
     203             : // ===========================================================================
     204     1368257 : OutputDevice::OutputDevice(const int defaultIndentation, const std::string& filename) :
     205     1368257 :     myFilename(filename), myFormatter(new PlainXMLFormatter(defaultIndentation)) {
     206     1368257 : }
     207             : 
     208             : 
     209     1368129 : OutputDevice::~OutputDevice() {
     210     1368129 :     delete myFormatter;
     211     1368129 : }
     212             : 
     213             : 
     214             : bool
     215           0 : OutputDevice::ok() {
     216           0 :     return getOStream().good();
     217             : }
     218             : 
     219             : 
     220             : const std::string&
     221           0 : OutputDevice::getFilename() {
     222           0 :     return myFilename;
     223             : }
     224             : 
     225             : void
     226      226596 : OutputDevice::close() {
     227      496339 :     while (closeTag()) {}
     228      316359 :     for (std::map<std::string, OutputDevice*>::iterator i = myOutputDevices.begin(); i != myOutputDevices.end(); ++i) {
     229      316359 :         if (i->second == this) {
     230             :             myOutputDevices.erase(i);
     231             :             break;
     232             :         }
     233             :     }
     234      226596 :     MsgHandler::removeRetrieverFromAllInstances(this);
     235      226596 :     delete this;
     236      226596 : }
     237             : 
     238             : 
     239             : void
     240     4020941 : OutputDevice::setPrecision(int precision) {
     241     4020941 :     getOStream() << std::setprecision(precision);
     242     4020941 : }
     243             : 
     244             : 
     245             : int
     246       51785 : OutputDevice::precision() {
     247       51785 :     return (int)getOStream().precision();
     248             : }
     249             : 
     250             : 
     251             : bool
     252       48440 : OutputDevice::writeXMLHeader(const std::string& rootElement,
     253             :                              const std::string& schemaFile,
     254             :                              std::map<SumoXMLAttr, std::string> attrs,
     255             :                              bool includeConfig) {
     256       48440 :     if (schemaFile != "") {
     257       45338 :         attrs[SUMO_ATTR_XMLNS] = "http://www.w3.org/2001/XMLSchema-instance";
     258       45338 :         attrs[SUMO_ATTR_SCHEMA_LOCATION] = "http://sumo.dlr.de/xsd/" + schemaFile;
     259             :     }
     260       48440 :     return myFormatter->writeXMLHeader(getOStream(), rootElement, attrs, includeConfig);
     261             : }
     262             : 
     263             : 
     264             : OutputDevice&
     265    13323632 : OutputDevice::openTag(const std::string& xmlElement) {
     266    13323632 :     myFormatter->openTag(getOStream(), xmlElement);
     267    13323632 :     return *this;
     268             : }
     269             : 
     270             : 
     271             : OutputDevice&
     272     7291208 : OutputDevice::openTag(const SumoXMLTag& xmlElement) {
     273     7291208 :     myFormatter->openTag(getOStream(), xmlElement);
     274     7291208 :     return *this;
     275             : }
     276             : 
     277             : 
     278             : bool
     279    20885138 : OutputDevice::closeTag(const std::string& comment) {
     280    20885138 :     if (myFormatter->closeTag(getOStream(), comment)) {
     281    20658542 :         postWriteHook();
     282    20658541 :         return true;
     283             :     }
     284             :     return false;
     285             : }
     286             : 
     287             : 
     288             : void
     289    86216717 : OutputDevice::postWriteHook() {}
     290             : 
     291             : 
     292             : void
     293      488616 : OutputDevice::inform(const std::string& msg, const char progress) {
     294      488616 :     if (progress != 0) {
     295       58784 :         getOStream() << msg << progress;
     296             :     } else {
     297      918448 :         getOStream() << msg << '\n';
     298             :     }
     299      488616 :     postWriteHook();
     300      488616 : }
     301             : 
     302             : 
     303             : /****************************************************************************/

Generated by: LCOV version 1.14