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