Eclipse SUMO - Simulation of Urban MObility
OutputDevice.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2004-2022 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/****************************************************************************/
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"
39#include "PlainXMLFormatter.h"
47
48
49// ===========================================================================
50// static member definitions
51// ===========================================================================
52std::map<std::string, OutputDevice*> OutputDevice::myOutputDevices;
54
55
56// ===========================================================================
57// static method definitions
58// ===========================================================================
60OutputDevice::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 if (myOutputDevices.find(name) != myOutputDevices.end()) {
70 return *myOutputDevices[name];
71 }
72 // build the device
73 OutputDevice* dev = nullptr;
74 // check whether the device shall print to stdout
75 if (name == "stdout") {
77 } else if (name == "stderr") {
79 } else if (FileHelpers::isSocket(name)) {
80 try {
81 int port = StringUtils::toInt(name.substr(name.find(":") + 1));
82 dev = new OutputDevice_Network(name.substr(0, name.find(":")), port);
83 } catch (NumberFormatException&) {
84 throw IOError("Given port number '" + name.substr(name.find(":") + 1) + "' is not numeric.");
85 } catch (EmptyData&) {
86 throw IOError("No port number given.");
87 }
88 } else {
89 std::string name2 = (name == "nul" || name == "NUL") ? "/dev/null" : name;
90 if (usePrefix && OptionsCont::getOptions().isSet("output-prefix") && name2 != "/dev/null") {
91 std::string prefix = OptionsCont::getOptions().getString("output-prefix");
92 const std::string::size_type metaTimeIndex = prefix.find("TIME");
93 if (metaTimeIndex != std::string::npos) {
94 const time_t rawtime = std::chrono::system_clock::to_time_t(OptionsIO::getLoadTime());
95 char buffer [80];
96 struct tm* timeinfo = localtime(&rawtime);
97 strftime(buffer, 80, "%Y-%m-%d-%H-%M-%S", timeinfo);
98 prefix.replace(metaTimeIndex, 4, buffer);
99 }
100 name2 = FileHelpers::prependToLastPathComponent(prefix, name);
101 }
103 const int len = (int)name.length();
104 dev = new OutputDevice_File(name2, len > 3 && name.substr(len - 3) == ".gz");
105 }
106 dev->setPrecision();
107 dev->getOStream() << std::setiosflags(std::ios::fixed);
108 myOutputDevices[name] = dev;
109 return *dev;
110}
111
112
113bool
114OutputDevice::createDeviceByOption(const std::string& optionName,
115 const std::string& rootElement,
116 const std::string& schemaFile) {
117 if (!OptionsCont::getOptions().isSet(optionName)) {
118 return false;
119 }
120 OutputDevice& dev = OutputDevice::getDevice(OptionsCont::getOptions().getString(optionName));
121 if (rootElement != "") {
122 dev.writeXMLHeader(rootElement, schemaFile);
123 }
124 return true;
125}
126
127
129OutputDevice::getDeviceByOption(const std::string& optionName) {
130 std::string devName = OptionsCont::getOptions().getString(optionName);
131 if (myOutputDevices.find(devName) == myOutputDevices.end()) {
132 throw InvalidArgument("Device '" + devName + "' has not been created.");
133 }
134 return OutputDevice::getDevice(devName);
135}
136
137
138void
139OutputDevice::closeAll(bool keepErrorRetrievers) {
140 std::vector<OutputDevice*> errorDevices;
141 std::vector<OutputDevice*> nonErrorDevices;
142 for (std::map<std::string, OutputDevice*>::iterator i = myOutputDevices.begin(); i != myOutputDevices.end(); ++i) {
143 if (MsgHandler::getErrorInstance()->isRetriever(i->second)) {
144 errorDevices.push_back(i->second);
145 } else {
146 nonErrorDevices.push_back(i->second);
147 }
148 }
149 for (OutputDevice* const dev : nonErrorDevices) {
150 try {
151 dev->close();
152 } catch (const IOError& e) {
153 WRITE_ERROR(TL("Error on closing output devices."));
154 WRITE_ERROR(e.what());
155 }
156 }
157 if (!keepErrorRetrievers) {
158 for (OutputDevice* const dev : errorDevices) {
159 try {
160 dev->close();
161 } catch (const IOError& e) {
162 std::cerr << "Error on closing error output devices." << std::endl;
163 std::cerr << e.what() << std::endl;
164 }
165 }
166#ifdef WIN32
167 if (myPrevConsoleCP != -1) {
168 SetConsoleOutputCP(myPrevConsoleCP);
169 }
170#endif
171 }
172}
173
174
175std::string
176OutputDevice::realString(const double v, const int precision) {
177 std::ostringstream oss;
178 if (v == 0) {
179 return "0";
180 }
181 if (v < pow(10., -precision)) {
182 oss.setf(std::ios::scientific, std::ios::floatfield);
183 } else {
184 oss.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
185 oss.setf(std::ios::showpoint); // print decimal point
186 oss << std::setprecision(precision);
187 }
188 oss << v;
189 return oss.str();
190}
191
192
193// ===========================================================================
194// member method definitions
195// ===========================================================================
196OutputDevice::OutputDevice(const int defaultIndentation, const std::string& filename) :
197 myFilename(filename), myFormatter(new PlainXMLFormatter(defaultIndentation)) {
198}
199
200
202 delete myFormatter;
203}
204
205
206bool
208 return getOStream().good();
209}
210
211
212const std::string&
214 return myFilename;
215}
216
217void
219 while (closeTag()) {}
220 for (std::map<std::string, OutputDevice*>::iterator i = myOutputDevices.begin(); i != myOutputDevices.end(); ++i) {
221 if (i->second == this) {
222 myOutputDevices.erase(i);
223 break;
224 }
225 }
227 delete this;
228}
229
230
231void
233 getOStream() << std::setprecision(precision);
234}
235
236
237int
239 return (int)getOStream().precision();
240}
241
242
243bool
244OutputDevice::writeXMLHeader(const std::string& rootElement,
245 const std::string& schemaFile,
246 std::map<SumoXMLAttr, std::string> attrs,
247 bool includeConfig) {
248 if (schemaFile != "") {
249 attrs[SUMO_ATTR_XMLNS] = "http://www.w3.org/2001/XMLSchema-instance";
250 attrs[SUMO_ATTR_SCHEMA_LOCATION] = "http://sumo.dlr.de/xsd/" + schemaFile;
251 }
252 return myFormatter->writeXMLHeader(getOStream(), rootElement, attrs, includeConfig);
253}
254
255
257OutputDevice::openTag(const std::string& xmlElement) {
258 myFormatter->openTag(getOStream(), xmlElement);
259 return *this;
260}
261
262
265 myFormatter->openTag(getOStream(), xmlElement);
266 return *this;
267}
268
269
270bool
271OutputDevice::closeTag(const std::string& comment) {
272 if (myFormatter->closeTag(getOStream(), comment)) {
274 return true;
275 }
276 return false;
277}
278
279
280void
282
283
284void
285OutputDevice::inform(const std::string& msg, const char progress) {
286 if (progress != 0) {
287 getOStream() << msg << progress;
288 } else {
289 getOStream() << msg << '\n';
290 }
292}
293
294
295/****************************************************************************/
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:274
#define TL(string)
Definition: MsgHandler.h:282
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_ATTR_XMLNS
@ SUMO_ATTR_SCHEMA_LOCATION
static bool isSocket(const std::string &name)
Returns the information whether the given name represents a socket.
static std::string prependToLastPathComponent(const std::string &prefix, const std::string &path)
prepend the given prefix to the last path component of the given file path
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:79
static void removeRetrieverFromAllInstances(OutputDevice *out)
ensure that that given output device is no longer used as retriever by any instance
Definition: MsgHandler.cpp:208
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:59
static const std::chrono::time_point< std::chrono::system_clock > & getLoadTime()
Return the time stamp of the last init.
Definition: OptionsIO.h:101
static OutputDevice * getDevice()
Returns the single cerr instance.
static OutputDevice * getDevice()
Returns the single cout instance.
An output device that encapsulates an ofstream.
An output device for TCP/IP network connections.
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
virtual std::ostream & getOStream()=0
Returns the associated ostream.
virtual ~OutputDevice()
Destructor.
OutputDevice(const int defaultIndentation=0, const std::string &filename="")
Constructor.
static std::string realString(const double v, const int precision=gPrecision)
Helper method for string formatting.
void close()
Closes the device and removes it from the dictionary.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
virtual void postWriteHook()
Called after every write access.
static bool createDeviceByOption(const std::string &optionName, const std::string &rootElement="", const std::string &schemaFile="")
Creates the device using the output definition stored in the named option.
int precision()
return precision set on the device
const std::string & getFilename()
get filename or suitable description of this device
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
void setPrecision(int precision=gPrecision)
Sets the precision or resets it to default.
const std::string myFilename
Definition: OutputDevice.h:366
static void closeAll(bool keepErrorRetrievers=false)
void inform(const std::string &msg, const char progress=0)
Retrieves a message to this device.
static OutputDevice & getDevice(const std::string &name, bool usePrefix=true)
Returns the described OutputDevice.
OutputFormatter *const myFormatter
The formatter for XML.
Definition: OutputDevice.h:370
static int myPrevConsoleCP
old console code page to restore after ending
Definition: OutputDevice.h:363
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >(), bool includeConfig=true)
Writes an XML header with optional configuration.
static std::map< std::string, OutputDevice * > myOutputDevices
map from names to output devices
Definition: OutputDevice.h:360
virtual bool ok()
returns the information whether one can write into the device
virtual bool writeXMLHeader(std::ostream &into, const std::string &rootElement, const std::map< SumoXMLAttr, std::string > &attrs, bool includeConfig=true)=0
Writes an XML header with optional configuration.
virtual bool closeTag(std::ostream &into, const std::string &comment="")=0
Closes the most recently opened tag and optinally add a comment.
virtual void openTag(std::ostream &into, const std::string &xmlElement)=0
Opens an XML tag.
Output formatter for plain XML output.
static std::string substituteEnvironment(const std::string &str, const std::chrono::time_point< std::chrono::system_clock > *const timeRef=nullptr)
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...