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