Line data Source code
1 : /* src/toolbox/OStream.hpp - simple output stream
2 :
3 : Copyright (C) 1996-2013
4 : CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5 :
6 : This file is part of CACAO.
7 :
8 : This program is free software; you can redistribute it and/or
9 : modify it under the terms of the GNU General Public License as
10 : published by the Free Software Foundation; either version 2, or (at
11 : your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program; if not, write to the Free Software
20 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 : 02110-1301, USA.
22 :
23 : */
24 :
25 : #ifndef OSTREAM_HPP_
26 : #define OSTREAM_HPP_ 1
27 :
28 : #include <string>
29 : #include <cstdio>
30 :
31 : namespace cacao {
32 :
33 : class OStream;
34 :
35 : OStream& out();
36 : OStream& err();
37 :
38 : class SetWidth;
39 : class SetZero;
40 : class SetPrecision;
41 : class SetIndent;
42 : class SetPrefix;
43 :
44 : class FillZero;
45 :
46 : class Left;
47 : class Right;
48 : class Dec;
49 : class Oct;
50 : class Hex;
51 : class FloatDec;
52 : class Scientific;
53 : class FloatHex;
54 : class Indent;
55 : class Dedent;
56 : class Nl;
57 : class Flush;
58 :
59 : class ThreadId;
60 :
61 : // ANSI terminal control
62 :
63 : enum Color {
64 : InvalidColor = 0,
65 : Black,
66 : Red,
67 : Green,
68 : Yellow,
69 : Blue,
70 : Magenta,
71 : Cyan,
72 : White,
73 : BoldBlack,
74 : BoldRed,
75 : BoldGreen,
76 : BoldYellow,
77 : BoldBlue,
78 : BoldMagenta,
79 : BoldCyan,
80 : BoldWhite
81 : };
82 :
83 : class ResetColor {};
84 : class Bold {};
85 : class NoBold {};
86 : class Underline {};
87 : class NoUnderline {};
88 :
89 : /** Simple stream class for formatted output
90 : *
91 : * This class is designed for debugging, thus usability trumps performance.
92 : * It mostly mimics the iostreams library, but requires no global constructors.
93 : * Interally everything is forwarded to stdio
94 : *
95 : * A stream can contain a prefix or intentions.
96 : * The stream does not detect if your output contains a '\n' (newline) character.
97 : * You must use the manipulator #nl instead. It works like std::endl but
98 : * does not flush the stream.
99 : *
100 : * Simple examples :
101 : * @code
102 : * OStream os(stdout);
103 : *
104 : * os << "Hi there, my name is " << bold << "cacao" << nobold << nl;
105 : * os << "I was born in " << 1996 << nl;
106 : * os << "Test failures are " << underline << red << "BAD" << reset_color << nl;
107 : * os << nl;
108 : * os << "Do you like hex? " << hex << 255 << dec << nl;
109 : * os << "Or floating point hex? " << float_hex << 17.3 << float_dec << nl;
110 : * @endcode
111 : *
112 : * Unlike a std::iostream you can copy construct an OStream.
113 : * A copied OStream will write to the same file but has it's own set of
114 : * format flags that you can set independent of the original stream.
115 : * But Colors, bold and underline are shared by all streams for a file,
116 : * because they are stored in the underlying terminal.
117 : * You should not write nl to the copied stream since the original will not
118 : * detect the newline.
119 : *
120 : * Example:
121 : * @code
122 : * struct MyLittlePony {
123 : * const char *name;
124 : * Color color;
125 : * };
126 : *
127 : * OStream& operator<<(OStream& os, const MyLittlePony& mlp) {
128 : * OStream os2 = os; // new stream with new flags
129 : *
130 : * os2 << mlp.color;
131 : * os2 << "My little pony is called " << setw(20) << right << mlp.name;
132 : * os2 << hex;
133 : *
134 : * // Forgot to unset hex for os2: no problem, hex flag is not shared
135 : * // Forgot to unset color: big problem, colors are shared!
136 : *
137 : * return os; // always return original stream
138 : * }
139 : * @endcode
140 : */
141 : class OStream {
142 : public:
143 : /// create a new stream with default flags
144 : OStream(FILE *file);
145 :
146 : /** copy stream
147 : *
148 : * creates a new stream with the same file
149 : * but default
150 : */
151 : OStream(const OStream&);
152 :
153 : OStream& operator<<(char);
154 : OStream& operator<<(bool);
155 : OStream& operator<<(long);
156 : OStream& operator<<(unsigned long);
157 : OStream& operator<<(long long );
158 : OStream& operator<<(unsigned long long);
159 : OStream& operator<<(double);
160 : OStream& operator<<(const void*);
161 : OStream& operator<<(const char*);
162 :
163 0 : OStream& operator<<(unsigned int n) {
164 0 : return this->operator<<(static_cast<unsigned long>(n));
165 : }
166 :
167 0 : OStream& operator<<(int n) {
168 0 : return this->operator<<(static_cast<long>(n));
169 : }
170 :
171 : // manipulators
172 : OStream& operator<<(const SetWidth&);
173 : OStream& operator<<(const SetZero&);
174 : OStream& operator<<(const SetPrecision&);
175 : OStream& operator<<(const SetIndent&);
176 : OStream& operator<<(const SetPrefix&);
177 :
178 : OStream& operator<<(const FillZero&);
179 :
180 : OStream& operator<<(const Left&);
181 : OStream& operator<<(const Right&);
182 :
183 : OStream& operator<<(const Dec&);
184 : OStream& operator<<(const Oct&);
185 : OStream& operator<<(const Hex&);
186 :
187 : OStream& operator<<(const FloatDec&);
188 : OStream& operator<<(const Scientific&);
189 : OStream& operator<<(const FloatHex&);
190 :
191 : OStream& operator<<(const Indent&);
192 : OStream& operator<<(const Dedent&);
193 :
194 : OStream& operator<<(const Nl&);
195 : OStream& operator<<(const Flush&);
196 :
197 : OStream& operator<<(const ThreadId&);
198 :
199 : // ANSI codes
200 : OStream& operator<<(Color);
201 :
202 : OStream& operator<<(const ResetColor&);
203 :
204 : OStream& operator<<(const Bold&);
205 : OStream& operator<<(const NoBold&);
206 : OStream& operator<<(const Underline&);
207 : OStream& operator<<(const NoUnderline&);
208 :
209 : void set_file(FILE *file) { this->file = file; }
210 :
211 : /// force color (0 = disabled, 1 = yes, 0 = no)
212 : static void set_force_color(int);
213 : private:
214 : void on_newline();
215 :
216 : /// initialize all format flags to their default value
217 : void init_flag_defaults();
218 :
219 : /// initialize all flags that only apply to one write operation
220 : void init_transient_flags();
221 : /// initialize all flags that survive a write operation
222 : void init_persistent_flags();
223 :
224 : /// file stream writes to
225 : FILE *file;
226 :
227 : /// true iff we are at the beginning of a new line
228 : bool newline;
229 :
230 : /// supports ansi escape codes
231 : bool _use_color;
232 :
233 : /// supports ansi escape codes
234 : bool use_color() const;
235 :
236 : /// force color (0 = disabled, 1 = yes, 0 = no)
237 : static int force_color;
238 :
239 : enum IntegerFormat {
240 : IntFmt_decimal,
241 : IntFmt_octal,
242 : IntFmt_hexadecimal
243 : };
244 : enum FloatFormat {
245 : FloatFmt_decimal,
246 : FloatFmt_scientific,
247 : FloatFmt_hexadecimal
248 : };
249 :
250 : // ********** format flags
251 :
252 : /** padding for next write
253 : *
254 : * ! width is reset to zero by all standard write operations !
255 : *
256 : * default value is 0
257 : */
258 : size_t width;
259 :
260 : /** precision
261 : *
262 : * ! precision is reset to -1 by all standard write operations !
263 : *
264 : * default value is -1 (i.e. turned off)
265 : */
266 : int precision;
267 :
268 : /** fill_zero
269 : *
270 : * ! fill_zero is reset to false by all standard write operations !
271 : *
272 : * default value is false
273 : */
274 : bool fill_zero;
275 :
276 : /** Alignment to use when padding text
277 : *
278 : * default value is OStream::Align_right
279 : */
280 : enum {
281 : Align_left,
282 : Align_right
283 : } align;
284 :
285 : /** format used to print integer types
286 : *
287 : * default value is \link OStream::IntegerFormat::IntFmt_decimal decimal \endlink
288 : */
289 : IntegerFormat int_fmt;
290 :
291 : /** format used to print floating point types
292 : *
293 : * default value is \link OStream::FloatFormat::FloatFmt_decimal decimal \endlink
294 : */
295 : FloatFormat float_fmt;
296 :
297 : /** indentation level
298 : *
299 : * every new line will start with OStream::Flags::indent_lvl * 4 spaces
300 : *
301 : * default value is 0
302 : */
303 : size_t indent_lvl;
304 :
305 : /** line prefix
306 : *
307 : * ignored if NULL
308 : * will be printed at start of every new line
309 : *
310 : * default value is NULL
311 : */
312 : const char *prefix;
313 :
314 : /** color line prefix is printed in
315 : *
316 : * ignored if negative
317 : *
318 : * default value is -1
319 : */
320 : Color prefix_color;
321 :
322 : friend class Logging;
323 : };
324 :
325 : /// Set width flag for next item to be written.
326 : class SetWidth {
327 : size_t width;
328 : public:
329 0 : SetWidth(size_t width) : width(width) {}
330 :
331 : friend class OStream;
332 : };
333 :
334 : /// Set width flag and fill zero for next item to be written.
335 : class SetZero {
336 : size_t width;
337 : public:
338 0 : SetZero(size_t width) : width(width) {}
339 :
340 : friend class OStream;
341 : };
342 :
343 : /// Set precision flag for next item to be written.
344 : class SetPrecision {
345 : int precision;
346 : public:
347 : SetPrecision(int precision) : precision(precision) {}
348 :
349 : friend class OStream;
350 : };
351 :
352 : /// Set indent level in stream
353 : class SetIndent {
354 : size_t indent;
355 : public:
356 : SetIndent(size_t indent) : indent(indent) {}
357 :
358 : friend class OStream;
359 : };
360 :
361 : /// Set stream prefix
362 : class SetPrefix {
363 : const char *prefix;
364 : Color color;
365 : public:
366 : SetPrefix(const char *prefix, Color color)
367 : : prefix(prefix), color(color) {}
368 :
369 : friend class OStream;
370 : };
371 :
372 : class FillZero {};
373 :
374 : class Left {};
375 : class Right {};
376 : class Dec {};
377 : class Oct {};
378 : class Hex {};
379 : class FloatDec {};
380 : class Scientific {};
381 : class FloatHex {};
382 : class Indent {};
383 : class Dedent {};
384 : class Nl {};
385 : class Flush {};
386 :
387 : class ThreadId {};
388 :
389 : class ResetColor;
390 : class Bold;
391 : class NoBold;
392 : class Underline;
393 : class NoUnderline;
394 :
395 0 : inline static SetWidth setw(size_t w) {
396 0 : return SetWidth(w);
397 : }
398 0 : inline static SetZero setz(size_t w) {
399 0 : return SetZero(w);
400 : }
401 : inline static SetPrecision setprecision(int p) {
402 : return SetPrecision(p);
403 : }
404 : inline static SetIndent setindent(size_t i) {
405 : return SetIndent(i);
406 : }
407 : inline static SetPrefix setprefix(const char *prefix, Color color) {
408 : return SetPrefix(prefix, color);
409 : }
410 :
411 : extern FillZero fillzero;
412 : extern Left left;
413 : extern Right right;
414 : extern Dec dec;
415 : extern Oct oct;
416 : extern Hex hex;
417 : extern FloatDec float_dec;
418 : extern Scientific scientific;
419 : extern FloatHex float_hex;
420 : extern Indent indent;
421 : extern Dedent dedent;
422 : extern Nl nl;
423 : extern Flush flush;
424 :
425 : // pipe this into a stream to print the current thread's id
426 : extern ThreadId threadid;
427 :
428 : extern ResetColor reset_color;
429 : extern Bold bold;
430 : extern NoBold nobold;
431 : extern Underline underline;
432 : extern NoUnderline nounderline;
433 :
434 : // helper templates
435 : template <class _ForwardIterator>
436 : inline OStream& print_container(OStream &OS, _ForwardIterator i, const _ForwardIterator &e) {
437 : if (i == e)
438 : return OS << "[<empty>]";
439 : OS << "[" << *i;
440 : ++i;
441 : for( ; i != e ; ++i) {
442 : OS << ", " << *i;
443 : }
444 : return OS << "]";
445 : }
446 :
447 : template <class _ForwardIterator>
448 : inline OStream& print_ptr_container(OStream &OS, _ForwardIterator i, const _ForwardIterator &e) {
449 : if (i == e)
450 : return OS << "[<empty>]";
451 : OS << "[" << **i;
452 : ++i;
453 : for( ; i != e ; ++i) {
454 : OS << ", " << **i;
455 : }
456 : return OS << "]";
457 : }
458 :
459 0 : inline OStream& operator<<(OStream &OS, const std::string &t) {
460 0 : return OS << t.c_str();
461 : }
462 :
463 : } // end namespace cacao
464 :
465 : #endif // OSTREAM_HPP_
466 :
467 :
468 : /*
469 : * These are local overrides for various environment variables in Emacs.
470 : * Please do not remove this and leave it at the end of the file, where
471 : * Emacs will automagically detect them.
472 : * ---------------------------------------------------------------------
473 : * Local variables:
474 : * mode: c++
475 : * indent-tabs-mode: t
476 : * c-basic-offset: 4
477 : * tab-width: 4
478 : * End:
479 : * vim:noexpandtab:sw=4:ts=4:
480 : */
|