1+ /* !
2+ * \file LogStream.cxx
3+ * \brief
4+ * \author Thomas Helfer
5+ * \date 24/02/2026
6+ */
7+
8+ #include < memory>
9+ #include < variant>
10+ #include < fstream>
11+ #include < iostream>
12+ #include " MGIS/LogStream.hxx"
13+
14+ namespace mgis {
15+
16+ [[nodiscard]] static std::
17+ variant<std::monostate, std::ostream *, std::shared_ptr<std::ostream>>
18+ &getGlobalLogStream () noexcept {
19+ static std::variant<std::monostate, std::ostream *,
20+ std::shared_ptr<std::ostream>>
21+ os;
22+ return os;
23+ } // end of getGlobalLogStream
24+
25+ std::ostream &getDefaultLogStream () noexcept {
26+ auto &os = getGlobalLogStream ();
27+ if (std::holds_alternative<std::ostream *>(os)) {
28+ auto * const ptr = std::get<std::ostream *>(os);
29+ if (ptr == nullptr ) {
30+ return std::cout;
31+ }
32+ return *ptr;
33+ } else if (std::holds_alternative<std::shared_ptr<std::ostream>>(os)) {
34+ auto ptr = std::get<std::shared_ptr<std::ostream>>(os);
35+ if (ptr.get () == nullptr ) {
36+ return std::cout;
37+ }
38+ return *ptr;
39+ }
40+ return std::cout;
41+ } // end of getDefaultLogStream
42+
43+ std::pair<bool , std::string> setDefaultLogStream (
44+ std::string_view n) noexcept {
45+ auto ptr = std::make_shared<std::ofstream>(std::string{n});
46+ if (!(*ptr)) {
47+ return {false ,
48+ " setDefaultLogStream: can't open file '" + std::string{n} + " '" };
49+ }
50+ setDefaultLogStream (ptr);
51+ return {true , " " };
52+ } // end of setDefaultLogStream
53+
54+ void setDefaultLogStream (std::ostream & os) noexcept {
55+ getGlobalLogStream () = &os;
56+ } // end of setDefaultLogStream
57+
58+ void setDefaultLogStream (std::shared_ptr<std::ostream> ptr) noexcept {
59+ if (ptr.get () == nullptr ) {
60+ resetDefaultLogStream ();
61+ return ;
62+ }
63+ getGlobalLogStream () = ptr;
64+ } // end of setDefaultLogStream
65+
66+ void resetDefaultLogStream () noexcept {
67+ getGlobalLogStream () = std::monostate{};
68+ } // end of resetDefaultLogStream
69+
70+ void disableDefaultLogStream () noexcept {
71+ /* !
72+ * \brief a buffer which allows to create no-op output streams, i.e. streams
73+ * that does not nothing.
74+ *
75+ * see
76+ * https://stackoverflow.com/questions/11826554/standard-no-op-output-stream
77+ * for details
78+ */
79+ struct NullBuffer : public std ::streambuf {
80+ int overflow (int c) override { return c; }
81+ };
82+ static NullBuffer null_buffer;
83+ static std::ostream null_stream (&null_buffer);
84+ setDefaultLogStream (null_stream);
85+ } // end of disableDefaultLogStream
86+
87+
88+ /* !
89+ * \class TerminalColors
90+ * \brief This class contains char sequence corresponding to colors.
91+ * This enables to write ouput messages in color in the terminal.
92+ * \author Thomas Helfer
93+ * \date 26/07/2006
94+ */
95+ struct TerminalColors {
96+ /* !
97+ * \brief char sequence correponding to black.
98+ * \code
99+ * cout.write(TerminalColors::Black,sizeof(TerminalColors::Black));
100+ * \endcode
101+ */
102+ static constexpr char Black[5 ] = {033 , ' [' , ' 3' , ' 0' , ' m' };
103+ /* !
104+ * \brief char sequence correponding to red.
105+ * \code
106+ * cout.write(TerminalColors::Red,sizeof(TerminalColors::Red));
107+ * \endcode
108+ */
109+ static constexpr char Red[5 ] = {033 , ' [' , ' 3' , ' 1' , ' m' };
110+ /* !
111+ * \brief char sequence correponding to green.
112+ * \code
113+ * cout.write(TerminalColors::Green,sizeof(TerminalColors::Greeb));
114+ * \endcode
115+ */
116+ static constexpr char Green[5 ] = {033 , ' [' , ' 3' , ' 2' , ' m' };
117+ /* !
118+ * \brief char sequence correponding to yellow.
119+ * \code
120+ * cout.write(TerminalColors::Yellow,sizeof(TerminalColors::Yellow));
121+ * \endcode
122+ */
123+ static constexpr char Yellow[5 ] = {033 , ' [' , ' 3' , ' 3' , ' m' };
124+ /* !
125+ * \brief char sequence correponding to blue.
126+ * \code
127+ * cout.write(TerminalColors::Blue,sizeof(TerminalColors::Blue));
128+ * \endcode
129+ */
130+ static constexpr char Blue[5 ] = {033 , ' [' , ' 3' , ' 4' , ' m' };
131+ /* !
132+ * \brief char sequence correponding to purple.
133+ * \code
134+ * cout.write(TerminalColors::Purple,sizeof(TerminalColors::Purple));
135+ * \endcode
136+ */
137+ static constexpr char Purple[5 ] = {033 , ' [' , ' 3' , ' 5' , ' m' };
138+ /* !
139+ * \brief char sequence correponding to light blue.
140+ * \code
141+ * cout.write(TerminalColors::LightBlue,sizeof(TerminalColors::LightBlue));
142+ * \endcode
143+ */
144+ static constexpr char LightBlue[5 ] = {033 , ' [' , ' 3' , ' 6' , ' m' };
145+ /* !
146+ * \brief char sequence correponding to white.
147+ * \code
148+ * cout.write(TerminalColors::White,sizeof(TerminalColors::White));
149+ * \endcode
150+ */
151+ static constexpr char White[5 ] = {033 , ' [' , ' 3' , ' 7' , ' m' };
152+ /* !
153+ * \brief char sequence correponding to the reset command.
154+ * This causes the terminal to go back to its initial state.
155+ * \code
156+ * cout.write(TerminalColors::Reset,sizeof(TerminalColors::Reset));
157+ * \endcode
158+ */
159+ static constexpr char Reset[4 ] = {033 , ' [' , ' m' , 017 };
160+ };
161+
162+ void setErrorColor (std::ostream &os) noexcept {
163+ os.write (TerminalColors::Red, sizeof (TerminalColors::Red));
164+ }
165+
166+ void setWarningColor (std::ostream &os) noexcept {
167+ os.write (TerminalColors::LightBlue, sizeof (TerminalColors::LightBlue));
168+ }
169+
170+ void resetOutputColor (std::ostream & os) noexcept {
171+ os.write (TerminalColors::Reset, sizeof (TerminalColors::Reset));
172+ }
173+
174+ } // end of namespace mgis
0 commit comments