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