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