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