LCOV - code coverage report
Current view: top level - src/utils/iodevices - OutputDevice.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 82.5 % 114 94
Test Date: 2024-11-22 15:46:21 Functions: 80.0 % 20 16

            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     17843096 : 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     17843096 :     if (myOutputDevices.find(name) != myOutputDevices.end()) {
      70     17565601 :         return *myOutputDevices[name];
      71              :     }
      72              :     // build the device
      73              :     OutputDevice* dev = nullptr;
      74              :     // check whether the device shall print to stdout
      75       277495 :     if (name == "stdout") {
      76        85108 :         dev = OutputDevice_COUT::getDevice();
      77       192387 :     } else if (name == "stderr") {
      78       126348 :         dev = OutputDevice_CERR::getDevice();
      79        66039 :     } else if (FileHelpers::isSocket(name)) {
      80              :         try {
      81            4 :             const bool ipv6 = name[0] == '[';  // IPv6 adresses may be written like '[::1]:8000'
      82            4 :             const size_t sepIndex = name.find(":", ipv6 ? name.find("]") : 0);
      83            4 :             const int port = StringUtils::toInt(name.substr(sepIndex + 1));
      84            8 :             dev = new OutputDevice_Network(ipv6 ? name.substr(1, sepIndex - 2) : name.substr(0, sepIndex), port);
      85            0 :         } catch (NumberFormatException&) {
      86            0 :             throw IOError("Given port number '" + name.substr(name.find(":") + 1) + "' is not numeric.");
      87            0 :         } catch (EmptyData&) {
      88            0 :             throw IOError(TL("No port number given."));
      89            0 :         }
      90              :     } else {
      91        66035 :         std::string name2 = (name == "nul" || name == "NUL") ? "/dev/null" : name;
      92       132076 :         if (usePrefix && OptionsCont::getOptions().isSet("output-prefix") && name2 != "/dev/null") {
      93         1348 :             std::string prefix = OptionsCont::getOptions().getString("output-prefix");
      94              :             const std::string::size_type metaTimeIndex = prefix.find("TIME");
      95          674 :             if (metaTimeIndex != std::string::npos) {
      96            0 :                 const time_t rawtime = std::chrono::system_clock::to_time_t(OptionsIO::getLoadTime());
      97              :                 char buffer [80];
      98            0 :                 struct tm* timeinfo = localtime(&rawtime);
      99            0 :                 strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S", timeinfo);
     100            0 :                 prefix.replace(metaTimeIndex, 4, buffer);
     101              :             }
     102         1348 :             name2 = FileHelpers::prependToLastPathComponent(prefix, name);
     103              :         }
     104       132154 :         name2 = StringUtils::substituteEnvironment(name2, &OptionsIO::getLoadTime());
     105        66035 :         const int len = (int)name.length();
     106       132034 :         dev = new OutputDevice_File(name2, len > 3 && name.substr(len - 3) == ".gz");
     107              :     }
     108       277411 :     dev->setPrecision();
     109       277411 :     dev->getOStream() << std::setiosflags(std::ios::fixed);
     110       277411 :     myOutputDevices[name] = dev;
     111       277411 :     return *dev;
     112              : }
     113              : 
     114              : 
     115              : bool
     116       951566 : OutputDevice::createDeviceByOption(const std::string& optionName,
     117              :                                    const std::string& rootElement,
     118              :                                    const std::string& schemaFile) {
     119       951566 :     if (!OptionsCont::getOptions().isSet(optionName)) {
     120              :         return false;
     121              :     }
     122        44198 :     OutputDevice& dev = OutputDevice::getDevice(OptionsCont::getOptions().getString(optionName));
     123        22077 :     if (rootElement != "") {
     124        44152 :         dev.writeXMLHeader(rootElement, schemaFile);
     125              :     }
     126              :     return true;
     127              : }
     128              : 
     129              : 
     130              : OutputDevice&
     131     17230108 : OutputDevice::getDeviceByOption(const std::string& optionName) {
     132     17230108 :     std::string devName = OptionsCont::getOptions().getString(optionName);
     133     17230108 :     if (myOutputDevices.find(devName) == myOutputDevices.end()) {
     134            0 :         throw InvalidArgument("Output device '" + devName + "' for option '" + optionName + "' has not been created.");
     135              :     }
     136     34460216 :     return OutputDevice::getDevice(devName);
     137              : }
     138              : 
     139              : 
     140              : void
     141            0 : OutputDevice::flushAll() {
     142            0 :     for (auto item : myOutputDevices) {
     143              :         item.second->flush();
     144              :     }
     145            0 : }
     146              : 
     147              : 
     148              : void
     149       166609 : OutputDevice::closeAll(bool keepErrorRetrievers) {
     150              :     std::vector<OutputDevice*> errorDevices;
     151              :     std::vector<OutputDevice*> nonErrorDevices;
     152       469052 :     for (std::map<std::string, OutputDevice*>::iterator i = myOutputDevices.begin(); i != myOutputDevices.end(); ++i) {
     153       302443 :         if (MsgHandler::getErrorInstance()->isRetriever(i->second)) {
     154       166914 :             errorDevices.push_back(i->second);
     155              :         } else {
     156       135529 :             nonErrorDevices.push_back(i->second);
     157              :         }
     158              :     }
     159       302138 :     for (OutputDevice* const dev : nonErrorDevices) {
     160              :         try {
     161       135529 :             dev->close();
     162            1 :         } catch (const IOError& e) {
     163            1 :             WRITE_ERROR(TL("Error on closing output devices."));
     164            1 :             WRITE_ERROR(e.what());
     165            1 :         }
     166              :     }
     167       166609 :     if (!keepErrorRetrievers) {
     168       252829 :         for (OutputDevice* const dev : errorDevices) {
     169              :             try {
     170       126495 :                 dev->close();
     171            0 :             } catch (const IOError& e) {
     172              :                 std::cerr << "Error on closing error output devices." << std::endl;
     173            0 :                 std::cerr << e.what() << std::endl;
     174            0 :             }
     175              :         }
     176              : #ifdef WIN32
     177              :         if (myPrevConsoleCP != -1) {
     178              :             SetConsoleOutputCP(myPrevConsoleCP);
     179              :         }
     180              : #endif
     181              :     }
     182       166609 : }
     183              : 
     184              : 
     185              : std::string
     186      1474795 : OutputDevice::realString(const double v, const int precision) {
     187      1474795 :     std::ostringstream oss;
     188      1474795 :     if (v == 0) {
     189       329474 :         return "0";
     190              :     }
     191      1145321 :     if (fabs(v) < pow(10., -precision)) {
     192              :         oss.setf(std::ios::scientific, std::ios::floatfield);
     193              :     } else {
     194              :         oss.setf(std::ios::fixed, std::ios::floatfield);     // use decimal format
     195              :         oss.setf(std::ios::showpoint);    // print decimal point
     196              :         oss << std::setprecision(precision);
     197              :     }
     198              :     oss << v;
     199              :     return oss.str();
     200      1474795 : }
     201              : 
     202              : 
     203              : // ===========================================================================
     204              : // member method definitions
     205              : // ===========================================================================
     206      1488202 : OutputDevice::OutputDevice(const int defaultIndentation, const std::string& filename) :
     207      1488202 :     myFilename(filename), myFormatter(new PlainXMLFormatter(defaultIndentation)) {
     208      1488202 : }
     209              : 
     210              : 
     211      1488031 : OutputDevice::~OutputDevice() {
     212      1488031 :     delete myFormatter;
     213      1488031 : }
     214              : 
     215              : 
     216              : bool
     217            0 : OutputDevice::ok() {
     218            0 :     return getOStream().good();
     219              : }
     220              : 
     221              : 
     222              : const std::string&
     223            0 : OutputDevice::getFilename() {
     224            0 :     return myFilename;
     225              : }
     226              : 
     227              : void
     228       277371 : OutputDevice::close() {
     229       619810 :     while (closeTag()) {}
     230       383302 :     for (std::map<std::string, OutputDevice*>::iterator i = myOutputDevices.begin(); i != myOutputDevices.end(); ++i) {
     231       383302 :         if (i->second == this) {
     232              :             myOutputDevices.erase(i);
     233              :             break;
     234              :         }
     235              :     }
     236       277370 :     MsgHandler::removeRetrieverFromAllInstances(this);
     237       277370 :     delete this;
     238       277370 : }
     239              : 
     240              : 
     241              : void
     242      3627227 : OutputDevice::setPrecision(int precision) {
     243      3627227 :     getOStream() << std::setprecision(precision);
     244      3627227 : }
     245              : 
     246              : 
     247              : int
     248        49779 : OutputDevice::precision() {
     249        49779 :     return (int)getOStream().precision();
     250              : }
     251              : 
     252              : 
     253              : bool
     254        61536 : OutputDevice::writeXMLHeader(const std::string& rootElement,
     255              :                              const std::string& schemaFile,
     256              :                              std::map<SumoXMLAttr, std::string> attrs,
     257              :                              bool includeConfig) {
     258        61536 :     if (schemaFile != "") {
     259        58000 :         attrs[SUMO_ATTR_XMLNS] = "http://www.w3.org/2001/XMLSchema-instance";
     260        58000 :         attrs[SUMO_ATTR_SCHEMA_LOCATION] = "http://sumo.dlr.de/xsd/" + schemaFile;
     261              :     }
     262        61536 :     return myFormatter->writeXMLHeader(getOStream(), rootElement, attrs, includeConfig);
     263              : }
     264              : 
     265              : 
     266              : OutputDevice&
     267      7593666 : OutputDevice::openTag(const std::string& xmlElement) {
     268      7593666 :     myFormatter->openTag(getOStream(), xmlElement);
     269      7593666 :     return *this;
     270              : }
     271              : 
     272              : 
     273              : OutputDevice&
     274      5729043 : OutputDevice::openTag(const SumoXMLTag& xmlElement) {
     275      5729043 :     myFormatter->openTag(getOStream(), xmlElement);
     276      5729043 :     return *this;
     277              : }
     278              : 
     279              : 
     280              : bool
     281     13665671 : OutputDevice::closeTag(const std::string& comment) {
     282     13665671 :     if (myFormatter->closeTag(getOStream(), comment)) {
     283     13388301 :         postWriteHook();
     284     13388300 :         return true;
     285              :     }
     286              :     return false;
     287              : }
     288              : 
     289              : 
     290              : void
     291     50635123 : OutputDevice::postWriteHook() {}
     292              : 
     293              : 
     294              : void
     295       647206 : OutputDevice::inform(const std::string& msg, const bool progress) {
     296       647206 :     if (progress) {
     297        28610 :         getOStream() << msg;
     298              :     } else {
     299      1237192 :         getOStream() << msg << '\n';
     300              :     }
     301       647206 :     postWriteHook();
     302       647206 : }
     303              : 
     304              : 
     305              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1