cprintf.cc revision 56
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 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