cprintf.cc revision 9331:6630b3ffe7c0
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 <cassert>
32#include <iomanip>
33#include <iostream>
34#include <sstream>
35
36#include "base/cprintf.hh"
37
38using namespace std;
39
40namespace cp {
41
42Print::Print(std::ostream &stream, const std::string &format)
43    : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false)
44{
45    saved_flags = stream.flags();
46    saved_fill = stream.fill();
47    saved_precision = stream.precision();
48}
49
50Print::Print(std::ostream &stream, const char *format)
51    : stream(stream), format(format), ptr(format), cont(false)
52{
53    saved_flags = stream.flags();
54    saved_fill = stream.fill();
55    saved_precision = stream.precision();
56}
57
58Print::~Print()
59{
60}
61
62void
63Print::process()
64{
65    fmt.clear();
66
67    size_t len;
68
69    while (*ptr) {
70        switch (*ptr) {
71          case '%':
72            if (ptr[1] != '%') {
73                process_flag();
74                return;
75            }
76            stream.put('%');
77            ptr += 2;
78            break;
79
80          case '\n':
81            stream << endl;
82            ++ptr;
83            break;
84          case '\r':
85            ++ptr;
86            if (*ptr != '\n')
87                stream << endl;
88            break;
89
90          default:
91            len = strcspn(ptr, "%\n\r\0");
92            stream.write(ptr, len);
93            ptr += len;
94            break;
95        }
96    }
97}
98
99void
100Print::process_flag()
101{
102    bool done = false;
103    bool end_number = false;
104    bool have_precision = false;
105    int number = 0;
106
107    stream.fill(' ');
108    stream.flags((ios::fmtflags)0);
109
110    while (!done) {
111        ++ptr;
112        if (*ptr >= '0' && *ptr <= '9') {
113            if (end_number)
114                continue;
115        } else if (number > 0)
116            end_number = true;
117
118        switch (*ptr) {
119          case 's':
120            fmt.format = Format::string;
121            done = true;
122            break;
123
124          case 'c':
125            fmt.format = Format::character;
126            done = true;
127            break;
128
129          case 'l':
130            continue;
131
132          case 'p':
133            fmt.format = Format::integer;
134            fmt.base = Format::hex;
135            fmt.alternate_form = true;
136            done = true;
137            break;
138
139          case 'X':
140            fmt.uppercase = true;
141          case 'x':
142            fmt.base = Format::hex;
143            fmt.format = Format::integer;
144            done = true;
145            break;
146
147          case 'o':
148            fmt.base = Format::oct;
149            fmt.format = Format::integer;
150            done = true;
151            break;
152
153          case 'd':
154          case 'i':
155          case 'u':
156            fmt.format = Format::integer;
157            done = true;
158            break;
159
160          case 'G':
161            fmt.uppercase = true;
162          case 'g':
163            fmt.format = Format::floating;
164            fmt.float_format = Format::best;
165            done = true;
166            break;
167
168          case 'E':
169            fmt.uppercase = true;
170          case 'e':
171            fmt.format = Format::floating;
172            fmt.float_format = Format::scientific;
173            done = true;
174            break;
175
176          case 'f':
177            fmt.format = Format::floating;
178            fmt.float_format = Format::fixed;
179            done = true;
180            break;
181
182          case 'n':
183            stream << "we don't do %n!!!\n";
184            done = true;
185            break;
186
187          case '#':
188            fmt.alternate_form = true;
189            break;
190
191          case '-':
192            fmt.flush_left = true;
193            break;
194
195          case '+':
196            fmt.print_sign = true;
197            break;
198
199          case ' ':
200            fmt.blank_space = true;
201            break;
202
203          case '.':
204            fmt.width = number;
205            fmt.precision = 0;
206            have_precision = true;
207            number = 0;
208            end_number = false;
209            break;
210
211          case '0':
212            if (number == 0) {
213                fmt.fill_zero = true;
214                break;
215            }
216          case '1':
217          case '2':
218          case '3':
219          case '4':
220          case '5':
221          case '6':
222          case '7':
223          case '8':
224          case '9':
225            number = number * 10 + (*ptr - '0');
226            break;
227
228          case '*':
229            if (have_precision)
230                fmt.get_precision = true;
231            else
232                fmt.get_width = true;
233            break;
234
235          case '%':
236            assert(false && "we shouldn't get here");
237            break;
238
239          default:
240            done = true;
241            break;
242        }
243
244        if (end_number) {
245            if (have_precision)
246                fmt.precision = number;
247            else
248                fmt.width = number;
249
250            end_number = false;
251            number = 0;
252        }
253
254        if (done) {
255            if ((fmt.format == Format::integer) && have_precision) {
256                // specified a . but not a float, set width
257                fmt.width = fmt.precision;
258                // precision requries digits for width, must fill with 0
259                fmt.fill_zero = true;
260            } else if ((fmt.format == Format::floating) && !have_precision &&
261                        fmt.fill_zero) {
262                // ambiguous case, matching printf
263                fmt.precision = fmt.width;
264            }
265        }
266    } // end while
267
268    ++ptr;
269}
270
271void
272Print::end_args()
273{
274    size_t len;
275
276    while (*ptr) {
277        switch (*ptr) {
278          case '%':
279            if (ptr[1] != '%')
280                stream << "<extra arg>";
281
282            stream.put('%');
283            ptr += 2;
284            break;
285
286          case '\n':
287            stream << endl;
288            ++ptr;
289            break;
290          case '\r':
291            ++ptr;
292            if (*ptr != '\n')
293                stream << endl;
294            break;
295
296          default:
297            len = strcspn(ptr, "%\n\r\0");
298            stream.write(ptr, len);
299            ptr += len;
300            break;
301        }
302    }
303
304    stream.flags(saved_flags);
305    stream.fill(saved_fill);
306    stream.precision(saved_precision);
307}
308
309} // namespace cp
310