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