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