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