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