cprintf.cc revision 5756:88038cdbb9e1
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                goto processing;
74
75            stream.put('%');
76            ptr += 2;
77            break;
78
79          case '\n':
80            stream << endl;
81            ++ptr;
82            break;
83          case '\r':
84            ++ptr;
85            if (*ptr != '\n')
86                stream << endl;
87            break;
88
89          default:
90            len = strcspn(ptr, "%\n\r\0");
91            stream.write(ptr, len);
92            ptr += len;
93            break;
94        }
95    }
96
97    return;
98
99  processing:
100    bool done = false;
101    bool end_number = false;
102    bool have_precision = false;
103    int number = 0;
104
105    stream.fill(' ');
106    stream.flags((ios::fmtflags)0);
107
108    while (!done) {
109        ++ptr;
110        if (*ptr >= '0' && *ptr <= '9') {
111            if (end_number)
112                continue;
113        } else if (number > 0)
114            end_number = true;
115
116        switch (*ptr) {
117          case 's':
118            fmt.format = Format::string;
119            done = true;
120            break;
121
122          case 'c':
123            fmt.format = Format::character;
124            done = true;
125            break;
126
127          case 'l':
128            continue;
129
130          case 'p':
131            fmt.format = Format::integer;
132            fmt.base = Format::hex;
133            fmt.alternate_form = true;
134            done = true;
135            break;
136
137          case 'X':
138            fmt.uppercase = true;
139          case 'x':
140            fmt.base = Format::hex;
141            fmt.format = Format::integer;
142            done = true;
143            break;
144
145          case 'o':
146            fmt.base = Format::oct;
147            fmt.format = Format::integer;
148            done = true;
149            break;
150
151          case 'd':
152          case 'i':
153          case 'u':
154            fmt.format = Format::integer;
155            done = true;
156            break;
157
158          case 'G':
159            fmt.uppercase = true;
160          case 'g':
161            fmt.format = Format::floating;
162            fmt.float_format = Format::best;
163            done = true;
164            break;
165
166          case 'E':
167            fmt.uppercase = true;
168          case 'e':
169            fmt.format = Format::floating;
170            fmt.float_format = Format::scientific;
171            done = true;
172            break;
173
174          case 'f':
175            fmt.format = Format::floating;
176            fmt.float_format = Format::fixed;
177            done = true;
178            break;
179
180          case 'n':
181            stream << "we don't do %n!!!\n";
182            done = true;
183            break;
184
185          case '#':
186            fmt.alternate_form = true;
187            break;
188
189          case '-':
190            fmt.flush_left = true;
191            break;
192
193          case '+':
194            fmt.print_sign = true;
195            break;
196
197          case ' ':
198            fmt.blank_space = true;
199            break;
200
201          case '.':
202            fmt.width = number;
203            fmt.precision = 0;
204            have_precision = true;
205            number = 0;
206            end_number = false;
207            break;
208
209          case '0':
210            if (number == 0) {
211                fmt.fill_zero = true;
212                break;
213            }
214          case '1':
215          case '2':
216          case '3':
217          case '4':
218          case '5':
219          case '6':
220          case '7':
221          case '8':
222          case '9':
223            number = number * 10 + (*ptr - '0');
224            break;
225
226          case '*':
227            if (have_precision)
228                fmt.get_precision = true;
229            else
230                fmt.get_width = true;
231            break;
232
233          case '%':
234            assert(false && "we shouldn't get here");
235            break;
236
237          default:
238            done = true;
239            break;
240        }
241
242        if (end_number) {
243            if (have_precision)
244                fmt.precision = number;
245            else
246                fmt.width = number;
247
248            end_number = false;
249            number = 0;
250        }
251    }
252
253    ++ptr;
254}
255
256void
257Print::end_args()
258{
259    size_t len;
260
261    while (*ptr) {
262        switch (*ptr) {
263          case '%':
264            if (ptr[1] != '%')
265                stream << "<extra arg>";
266
267            stream.put('%');
268            ptr += 2;
269            break;
270
271          case '\n':
272            stream << endl;
273            ++ptr;
274            break;
275          case '\r':
276            ++ptr;
277            if (*ptr != '\n')
278                stream << endl;
279            break;
280
281          default:
282            len = strcspn(ptr, "%\n\r\0");
283            stream.write(ptr, len);
284            ptr += len;
285            break;
286        }
287    }
288
289    stream.flags(saved_flags);
290    stream.fill(saved_fill);
291    stream.precision(saved_precision);
292}
293
294/* end namespace cp */ }
295