Line data Source code
1 : /* src/toolbox/OStream.cpp - 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 : #include "toolbox/OStream.hpp"
26 :
27 : #include "threads/thread.hpp"
28 :
29 : #include <cassert>
30 :
31 : namespace cacao {
32 :
33 0 : OStream& err() {
34 0 : static OStream stream(stderr);
35 :
36 0 : return stream;
37 : }
38 :
39 0 : OStream& out() {
40 0 : static OStream stream(stdout);
41 :
42 0 : return stream;
43 : }
44 :
45 : FillZero fillzero;
46 : Left left;
47 : Right right;
48 : Dec dec;
49 : Oct oct;
50 : Hex hex;
51 : FloatDec float_dec;
52 : Scientific scientific;
53 : FloatHex float_hex;
54 : Indent indent;
55 : Dedent dedent;
56 : Nl nl;
57 : Flush flush;
58 :
59 : ThreadId threadid;
60 :
61 : ResetColor reset_color;
62 : Bold bold;
63 : NoBold nobold;
64 : Underline underline;
65 : NoUnderline nounderline;
66 :
67 0 : OStream::OStream(FILE *file) : file(file), newline(true) {
68 0 : assert(file);
69 0 : init_flag_defaults();
70 : // in practice all tty's support ansi escape codes
71 0 : _use_color = isatty(fileno(file));
72 0 : }
73 :
74 : int OStream::force_color = 0;
75 :
76 0 : void OStream::set_force_color(int b) {
77 0 : switch(b){
78 : case 1:
79 : case -1:
80 0 : force_color = b;
81 0 : break;
82 : default:
83 0 : force_color = 0;
84 : }
85 0 : }
86 :
87 0 : inline bool OStream::use_color() const {
88 0 : switch (force_color) {
89 : case 1:
90 0 : return true;
91 : case -1:
92 0 : return false;
93 : }
94 0 : return _use_color;
95 : }
96 :
97 0 : OStream::OStream(const OStream& os) : file(os.file), newline(os.newline), _use_color(os._use_color) {
98 0 : init_flag_defaults();
99 0 : }
100 :
101 0 : void OStream::init_flag_defaults() {
102 0 : init_transient_flags();
103 0 : init_persistent_flags();
104 0 : }
105 :
106 0 : void OStream::init_transient_flags() {
107 : // keep comments in Flags class in sync with this!
108 :
109 0 : width = 0;
110 0 : precision = -1;
111 0 : fill_zero = false;
112 0 : }
113 :
114 0 : void OStream::init_persistent_flags() {
115 : // keep comments in Flags class in sync with this!
116 :
117 0 : align = Align_right;
118 0 : int_fmt = OStream::IntFmt_decimal;
119 0 : float_fmt = OStream::FloatFmt_decimal;
120 0 : indent_lvl = 0;
121 0 : prefix = NULL;
122 0 : prefix_color = InvalidColor;
123 0 : }
124 :
125 0 : void OStream::on_newline() {
126 0 : if (!newline) return;
127 :
128 0 : newline = false;
129 :
130 : // set color
131 :
132 0 : if (prefix_color != InvalidColor) (*this) << prefix_color;
133 :
134 : // print prefix
135 :
136 0 : if (prefix) {
137 0 : fputs(prefix, file);
138 0 : fputc(' ', file);
139 : }
140 :
141 : // reset color
142 :
143 0 : if (prefix_color != InvalidColor) (*this) << reset_color;
144 :
145 : // indent
146 :
147 0 : for (size_t indent = indent_lvl * 4; indent > 0; indent--) {
148 0 : fputc(' ', file);
149 : }
150 : }
151 :
152 : #define PRINT_INT_FLAG(DEC, OCT, HEX, VAL, FLAG) \
153 : switch (int_fmt) { \
154 : case IntFmt_decimal: \
155 : fprintf(file, "%" FLAG "*" #DEC, (int) width, VAL);break; \
156 : case IntFmt_octal: \
157 : fprintf(file, "%" FLAG "*" #OCT, (int) width, VAL);break; \
158 : case IntFmt_hexadecimal: \
159 : fprintf(file, "%" FLAG "*" #HEX, (int) width, VAL);break; \
160 : default: assert(false && "Bad int format"); \
161 : }
162 :
163 : #define PRINT_INT(DEC, OCT, HEX, VAL) \
164 : switch (align) { \
165 : case Align_left: \
166 : /* left align (i.e. - ) and zero padding not valid */ \
167 : PRINT_INT_FLAG(DEC,OCT,HEX,VAL,"-"); \
168 : break; \
169 : case Align_right: \
170 : if (fill_zero) { \
171 : PRINT_INT_FLAG(DEC,OCT,HEX,VAL,"0"); \
172 : } else { \
173 : PRINT_INT_FLAG(DEC,OCT,HEX,VAL,""); \
174 : } \
175 : break; \
176 : default: \
177 : assert(false && "Bad alignment"); \
178 : }
179 :
180 : #define PRINT_FLOAT_FLAG(DEC, SCI, HEX, VAL, FLAG) \
181 : switch (float_fmt) { \
182 : case FloatFmt_decimal: \
183 : fprintf(file, "%" FLAG "*.*" #DEC, (int) width, precision, VAL); break; \
184 : case FloatFmt_scientific: \
185 : fprintf(file, "%" FLAG "*.*" #SCI, (int) width, precision, VAL); break; \
186 : case FloatFmt_hexadecimal: \
187 : fprintf(file, "%" FLAG "*.*" #HEX, (int) width, precision, VAL); break; \
188 : default: \
189 : assert(false && "Bad float format"); \
190 : }
191 :
192 : #define PRINT_FLOAT(DEC, SCI, HEX, VAL) \
193 : switch (align) { \
194 : case Align_left: \
195 : /* left align (i.e. - ) and zero padding not valid */ \
196 : PRINT_FLOAT_FLAG(DEC,SCI,HEX,VAL,"-"); \
197 : break; \
198 : case Align_right: \
199 : if (fill_zero) { \
200 : PRINT_FLOAT_FLAG(DEC,SCI,HEX,VAL,"0"); \
201 : } else { \
202 : PRINT_FLOAT_FLAG(DEC,SCI,HEX,VAL,""); \
203 : } \
204 : break; \
205 : default: \
206 : assert(false && "Bad alignment"); \
207 : }
208 :
209 0 : OStream& OStream::operator<<(char c) {
210 0 : on_newline();
211 :
212 0 : if (!width) {
213 0 : fputc(c, file);
214 : } else {
215 0 : switch (align) {
216 : case Align_left:
217 0 : fprintf(file, "%-*c", (int) width, c);
218 0 : break;
219 : case Align_right:
220 0 : fprintf(file, "%*c", (int) width, c);
221 : break;
222 : }
223 : }
224 :
225 0 : init_transient_flags();
226 0 : return (*this);
227 : }
228 0 : OStream& OStream::operator<<(bool b) {
229 0 : return (*this) << (b ? "true" : "false");
230 : }
231 0 : OStream& OStream::operator<<(long n) {
232 0 : on_newline();
233 :
234 0 : PRINT_INT(ld, lo, lx, n);
235 :
236 0 : init_transient_flags();
237 0 : return (*this);
238 : }
239 0 : OStream& OStream::operator<<(long long n) {
240 0 : on_newline();
241 :
242 0 : PRINT_INT(lld, llo, llx, n);
243 :
244 0 : init_transient_flags();
245 0 : return (*this);
246 : }
247 0 : OStream& OStream::operator<<(unsigned long n) {
248 0 : on_newline();
249 :
250 0 : PRINT_INT(lu, lo, lx, n);
251 :
252 0 : init_transient_flags();
253 0 : return (*this);
254 : }
255 0 : OStream& OStream::operator<<(unsigned long long n) {
256 0 : on_newline();
257 :
258 0 : PRINT_INT(llu, llo, llx, n);
259 :
260 0 : init_transient_flags();
261 0 : return (*this);
262 : }
263 : /**
264 : * @Cpp11 Flag %a introduced in C99, disable hex float for now
265 : */
266 0 : OStream& OStream::operator<<(double n) {
267 0 : on_newline();
268 :
269 : //PRINT_FLOAT(f, e, a, n);
270 0 : PRINT_FLOAT(f, e, e, n);
271 :
272 0 : init_transient_flags();
273 0 : return (*this);
274 : }
275 0 : OStream& OStream::operator<<(const void *p) {
276 0 : on_newline();
277 :
278 0 : if (!p) return (*this) << "NULL";
279 :
280 0 : OStream OS = (*this); // new OStream for new flags
281 0 : OS << "0x" << hex << (const long int)p;
282 0 : return (*this);
283 : }
284 0 : OStream& OStream::operator<<(const char *cs) {
285 0 : on_newline();
286 :
287 0 : if (!cs) cs = "(null)";
288 :
289 0 : if (!width) {
290 0 : fputs(cs, file);
291 : } else {
292 0 : switch (align) {
293 : case Align_left:
294 0 : fprintf(file, "%-*s", (int) width, cs);
295 0 : break;
296 : case Align_right:
297 0 : fprintf(file, "%*s", (int) width, cs);
298 : break;
299 : }
300 : }
301 :
302 0 : init_transient_flags();
303 0 : return (*this);
304 : }
305 :
306 0 : OStream& OStream::operator<<(const SetWidth& s) {
307 0 : width = s.width;
308 :
309 0 : return (*this);
310 : }
311 0 : OStream& OStream::operator<<(const SetZero& s) {
312 0 : width = s.width;
313 0 : fill_zero = true;
314 0 : return (*this);
315 : }
316 0 : OStream& OStream::operator<<(const SetPrecision& s) {
317 0 : precision = s.precision;
318 :
319 0 : return (*this);
320 : }
321 0 : OStream& OStream::operator<<(const SetIndent& s) {
322 0 : indent_lvl = s.indent;
323 :
324 0 : return (*this);
325 : }
326 0 : OStream& OStream::operator<<(const SetPrefix& s) {
327 0 : prefix = s.prefix;
328 0 : prefix_color = s.color;
329 :
330 0 : return (*this);
331 : }
332 :
333 0 : OStream& OStream::operator<<(const FillZero&) {
334 0 : fill_zero = true;
335 :
336 0 : return (*this);
337 : }
338 :
339 0 : OStream& OStream::operator<<(const Left&) {
340 0 : align = OStream::Align_left;
341 :
342 0 : return (*this);
343 : }
344 0 : OStream& OStream::operator<<(const Right&) {
345 0 : align = OStream::Align_right;
346 :
347 0 : return (*this);
348 : }
349 0 : OStream& OStream::operator<<(const Dec&) {
350 0 : int_fmt = OStream::IntFmt_decimal;
351 :
352 0 : return (*this);
353 : }
354 0 : OStream& OStream::operator<<(const Oct&) {
355 0 : int_fmt = OStream::IntFmt_octal;
356 :
357 0 : return (*this);
358 : }
359 0 : OStream& OStream::operator<<(const Hex&) {
360 0 : int_fmt = OStream::IntFmt_hexadecimal;
361 :
362 0 : return (*this);
363 : }
364 0 : OStream& OStream::operator<<(const FloatDec&) {
365 0 : float_fmt = OStream::FloatFmt_decimal;
366 :
367 0 : return (*this);
368 : }
369 0 : OStream& OStream::operator<<(const Scientific&) {
370 0 : float_fmt = OStream::FloatFmt_scientific;
371 :
372 0 : return (*this);
373 : }
374 0 : OStream& OStream::operator<<(const FloatHex&) {
375 0 : float_fmt = OStream::FloatFmt_hexadecimal;
376 :
377 0 : return (*this);
378 : }
379 0 : OStream& OStream::operator<<(const Indent&) {
380 0 : indent_lvl++;
381 :
382 0 : return (*this);
383 : }
384 0 : OStream& OStream::operator<<(const Dedent&) {
385 0 : indent_lvl--;
386 :
387 0 : return (*this);
388 : }
389 0 : OStream& OStream::operator<<(const Nl&) {
390 0 : (*this) << '\n';
391 0 : newline = true;
392 :
393 0 : return (*this);
394 : }
395 0 : OStream& OStream::operator<<(const Flush&) {
396 0 : fflush(file);
397 :
398 0 : return (*this);
399 : }
400 :
401 0 : OStream& OStream::operator<<(const ThreadId&) {
402 0 : return (*this) << "[" << hex << setw(16) << fillzero << threads_get_current_tid() << dec << "]";
403 : }
404 :
405 0 : OStream& OStream::operator<<(Color c) {
406 0 : if (!use_color()) return (*this);
407 :
408 0 : switch (c) {
409 0 : case Black: return (*this) << "\033[30m";
410 0 : case Red: return (*this) << "\033[31m";
411 0 : case Green: return (*this) << "\033[32m";
412 0 : case Yellow: return (*this) << "\033[33m";
413 0 : case Blue: return (*this) << "\033[34m";
414 0 : case Magenta: return (*this) << "\033[35m";
415 0 : case Cyan: return (*this) << "\033[36m";
416 0 : case White: return (*this) << "\033[37m";
417 0 : case BoldBlack: return (*this) << "\033[30m\033[1m";
418 0 : case BoldRed: return (*this) << "\033[31m\033[1m";
419 0 : case BoldGreen: return (*this) << "\033[32m\033[1m";
420 0 : case BoldYellow: return (*this) << "\033[33m\033[1m";
421 0 : case BoldBlue: return (*this) << "\033[34m\033[1m";
422 0 : case BoldMagenta: return (*this) << "\033[35m\033[1m";
423 0 : case BoldCyan: return (*this) << "\033[36m\033[1m";
424 0 : case BoldWhite: return (*this) << "\033[37m\033[1m";
425 : default:
426 0 : assert(false && "Unknown color code");
427 : break;
428 : }
429 :
430 : return (*this);
431 : }
432 0 : OStream& OStream::operator<<(const ResetColor&) {
433 0 : if (!use_color()) return (*this);
434 0 : return (*this) << "\033[0m";
435 : }
436 0 : OStream& OStream::operator<<(const Bold&) {
437 0 : if (!use_color()) return (*this);
438 0 : return (*this) << "\033[1m";
439 : }
440 0 : OStream& OStream::operator<<(const NoBold&) {
441 0 : if (!use_color()) return (*this);
442 0 : return (*this) << "\033[21m";
443 : }
444 0 : OStream& OStream::operator<<(const Underline&) {
445 0 : if (!use_color()) return (*this);
446 0 : return (*this) << "\033[4m";
447 : }
448 0 : OStream& OStream::operator<<(const NoUnderline&) {
449 0 : if (!use_color()) return (*this);
450 0 : return (*this) << "\033[24m";
451 : }
452 :
453 : } // end namespace cacao
454 :
455 : /*
456 : * These are local overrides for various environment variables in Emacs.
457 : * Please do not remove this and leave it at the end of the file, where
458 : * Emacs will automagically detect them.
459 : * ---------------------------------------------------------------------
460 : * Local variables:
461 : * mode: c++
462 : * indent-tabs-mode: t
463 : * c-basic-offset: 4
464 : * tab-width: 4
465 : * End:
466 : * vim:noexpandtab:sw=4:ts=4:
467 : */
|