cprintf.cc revision 12392:e0dbdf30a2a5
1/*
2 * Copyright (c) 2002-2006 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Nathan Binkert
29 */
30
31#include "base/cprintf.hh"
32
33#include <cassert>
34#include <iomanip>
35#include <iostream>
36#include <sstream>
37
38#include "base/compiler.hh"
39
40using namespace std;
41
42namespace cp {
43
44Print::Print(std::ostream &stream, const std::string &format)
45    : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false)
46{
47    saved_flags = stream.flags();
48    saved_fill = stream.fill();
49    saved_precision = stream.precision();
50}
51
52Print::Print(std::ostream &stream, const char *format)
53    : stream(stream), format(format), ptr(format), cont(false)
54{
55    saved_flags = stream.flags();
56    saved_fill = stream.fill();
57    saved_precision = stream.precision();
58}
59
60Print::~Print()
61{
62}
63
64void
65Print::process()
66{
67    fmt.clear();
68
69    size_t len;
70
71    while (*ptr) {
72        switch (*ptr) {
73          case '%':
74            if (ptr[1] != '%') {
75                process_flag();
76                return;
77            }
78            stream.put('%');
79            ptr += 2;
80            break;
81
82          case '\n':
83            stream << endl;
84            ++ptr;
85            break;
86          case '\r':
87            ++ptr;
88            if (*ptr != '\n')
89                stream << endl;
90            break;
91
92          default:
93            len = strcspn(ptr, "%\n\r\0");
94            stream.write(ptr, len);
95            ptr += len;
96            break;
97        }
98    }
99}
100
101void
102Print::process_flag()
103{
104    bool done = false;
105    bool end_number = false;
106    bool have_precision = false;
107    int number = 0;
108
109    stream.fill(' ');
110    stream.flags((ios::fmtflags)0);
111
112    while (!done) {
113        ++ptr;
114        if (*ptr >= '0' && *ptr <= '9') {
115            if (end_number)
116                continue;
117        } else if (number > 0)
118            end_number = true;
119
120        switch (*ptr) {
121          case 's':
122            fmt.format = Format::string;
123            done = true;
124            break;
125
126          case 'c':
127            fmt.format = Format::character;
128            done = true;
129            break;
130
131          case 'l':
132            continue;
133
134          case 'p':
135            fmt.format = Format::integer;
136            fmt.base = Format::hex;
137            fmt.alternate_form = true;
138            done = true;
139            break;
140
141          case 'X':
142            fmt.uppercase = true;
143            M5_FALLTHROUGH;
144          case 'x':
145            fmt.base = Format::hex;
146            fmt.format = Format::integer;
147            done = true;
148            break;
149
150          case 'o':
151            fmt.base = Format::oct;
152            fmt.format = Format::integer;
153            done = true;
154            break;
155
156          case 'd':
157          case 'i':
158          case 'u':
159            fmt.format = Format::integer;
160            done = true;
161            break;
162
163          case 'G':
164            fmt.uppercase = true;
165            M5_FALLTHROUGH;
166          case 'g':
167            fmt.format = Format::floating;
168            fmt.float_format = Format::best;
169            done = true;
170            break;
171
172          case 'E':
173            fmt.uppercase = true;
174            M5_FALLTHROUGH;
175          case 'e':
176            fmt.format = Format::floating;
177            fmt.float_format = Format::scientific;
178            done = true;
179            break;
180
181          case 'f':
182            fmt.format = Format::floating;
183            fmt.float_format = Format::fixed;
184            done = true;
185            break;
186
187          case 'n':
188            stream << "we don't do %n!!!\n";
189            done = true;
190            break;
191
192          case '#':
193            fmt.alternate_form = true;
194            break;
195
196          case '-':
197            fmt.flush_left = true;
198            break;
199
200          case '+':
201            fmt.print_sign = true;
202            break;
203
204          case ' ':
205            fmt.blank_space = true;
206            break;
207
208          case '.':
209            fmt.width = number;
210            fmt.precision = 0;
211            have_precision = true;
212            number = 0;
213            end_number = false;
214            break;
215
216          case '0':
217            if (number == 0) {
218                fmt.fill_zero = true;
219                break;
220            }
221            M5_FALLTHROUGH;
222          case '1':
223          case '2':
224          case '3':
225          case '4':
226          case '5':
227          case '6':
228          case '7':
229          case '8':
230          case '9':
231            number = number * 10 + (*ptr - '0');
232            break;
233
234          case '*':
235            if (have_precision)
236                fmt.get_precision = true;
237            else
238                fmt.get_width = true;
239            break;
240
241          case '%':
242            assert(false && "we shouldn't get here");
243            break;
244
245          default:
246            done = true;
247            break;
248        }
249
250        if (end_number) {
251            if (have_precision)
252                fmt.precision = number;
253            else
254                fmt.width = number;
255
256            end_number = false;
257            number = 0;
258        }
259
260        if (done) {
261            if ((fmt.format == Format::integer) && have_precision) {
262                // specified a . but not a float, set width
263                fmt.width = fmt.precision;
264                // precision requries digits for width, must fill with 0
265                fmt.fill_zero = true;
266            } else if ((fmt.format == Format::floating) && !have_precision &&
267                        fmt.fill_zero) {
268                // ambiguous case, matching printf
269                fmt.precision = fmt.width;
270            }
271        }
272    } // end while
273
274    ++ptr;
275}
276
277void
278Print::end_args()
279{
280    size_t len;
281
282    while (*ptr) {
283        switch (*ptr) {
284          case '%':
285            if (ptr[1] != '%')
286                stream << "<extra arg>";
287
288            stream.put('%');
289            ptr += 2;
290            break;
291
292          case '\n':
293            stream << endl;
294            ++ptr;
295            break;
296          case '\r':
297            ++ptr;
298            if (*ptr != '\n')
299                stream << endl;
300            break;
301
302          default:
303            len = strcspn(ptr, "%\n\r\0");
304            stream.write(ptr, len);
305            ptr += len;
306            break;
307        }
308    }
309
310    stream.flags(saved_flags);
311    stream.fill(saved_fill);
312    stream.precision(saved_precision);
313}
314
315} // namespace cp
316