1/* 2 * Copyright (c) 2002-2006 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 "base/cprintf.hh" 32 33#include <cassert> 34#include <iomanip> 35#include <iostream> 36#include <sstream> 37 38#include "base/compiler.hh" 39 40using namespace std; 41 42namespace cp { 43 44Print::Print(std::ostream &stream, const std::string &format) 45 : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false) 46{ 47 saved_flags = stream.flags(); 48 saved_fill = stream.fill(); 49 saved_precision = stream.precision(); 50 saved_width = stream.width(); 51} 52 53Print::Print(std::ostream &stream, const char *format) 54 : stream(stream), format(format), ptr(format), cont(false) 55{ 56 saved_flags = stream.flags(); 57 saved_fill = stream.fill(); 58 saved_precision = stream.precision(); 59 saved_width = stream.width(); 60} 61 62Print::~Print() 63{ 64} 65 66void 67Print::process() 68{ 69 fmt.clear(); 70 71 size_t len; 72 73 while (*ptr) { 74 switch (*ptr) { 75 case '%': 76 if (ptr[1] != '%') { 77 process_flag(); 78 return; 79 } 80 stream.put('%'); 81 ptr += 2; 82 break; 83 84 case '\n': 85 stream << endl; 86 ++ptr; 87 break; 88 case '\r': 89 ++ptr; 90 if (*ptr != '\n') 91 stream << endl; 92 break; 93 94 default: 95 len = strcspn(ptr, "%\n\r\0"); 96 stream.write(ptr, len); 97 ptr += len; 98 break; 99 } 100 } 101} 102 103void 104Print::process_flag() 105{ 106 bool done = false; 107 bool end_number = false; 108 bool have_precision = false; 109 int number = 0; 110 111 stream.fill(' '); 112 stream.flags((ios::fmtflags)0); 113 114 while (!done) { 115 ++ptr; 116 if (*ptr >= '0' && *ptr <= '9') { 117 if (end_number) 118 continue; 119 } else if (number > 0) 120 end_number = true; 121 122 switch (*ptr) { 123 case 's': 124 fmt.format = Format::string; 125 done = true; 126 break; 127 128 case 'c': 129 fmt.format = Format::character; 130 done = true; 131 break; 132 133 case 'l': 134 continue; 135 136 case 'p': 137 fmt.format = Format::integer; 138 fmt.base = Format::hex; 139 fmt.alternate_form = true; 140 done = true; 141 break; 142 143 case 'X': 144 fmt.uppercase = true; 145 M5_FALLTHROUGH; 146 case 'x': 147 fmt.base = Format::hex; 148 fmt.format = Format::integer; 149 done = true; 150 break; 151 152 case 'o': 153 fmt.base = Format::oct; 154 fmt.format = Format::integer; 155 done = true; 156 break; 157 158 case 'd': 159 case 'i': 160 case 'u': 161 fmt.format = Format::integer; 162 done = true; 163 break; 164 165 case 'G': 166 fmt.uppercase = true; 167 M5_FALLTHROUGH; 168 case 'g': 169 fmt.format = Format::floating; 170 fmt.float_format = Format::best; 171 done = true; 172 break; 173 174 case 'E': 175 fmt.uppercase = true; 176 M5_FALLTHROUGH; 177 case 'e': 178 fmt.format = Format::floating; 179 fmt.float_format = Format::scientific; 180 done = true; 181 break; 182 183 case 'f': 184 fmt.format = Format::floating; 185 fmt.float_format = Format::fixed; 186 done = true; 187 break; 188 189 case 'n': 190 stream << "we don't do %n!!!\n"; 191 done = true; 192 break; 193 194 case '#': 195 fmt.alternate_form = true; 196 break; 197 198 case '-': 199 fmt.flush_left = true; 200 break; 201 202 case '+': 203 fmt.print_sign = true; 204 break; 205 206 case ' ': 207 fmt.blank_space = true; 208 break; 209 210 case '.': 211 fmt.width = number; 212 fmt.precision = 0; 213 have_precision = true; 214 number = 0; 215 end_number = false; 216 break; 217 218 case '0': 219 if (number == 0) { 220 fmt.fill_zero = true; 221 break; 222 } 223 M5_FALLTHROUGH; 224 case '1': 225 case '2': 226 case '3': 227 case '4': 228 case '5': 229 case '6': 230 case '7': 231 case '8': 232 case '9': 233 number = number * 10 + (*ptr - '0'); 234 break; 235 236 case '*': 237 if (have_precision) 238 fmt.get_precision = true; 239 else 240 fmt.get_width = true; 241 break; 242 243 case '%': 244 assert(false && "we shouldn't get here"); 245 break; 246 247 default: 248 done = true; 249 break; 250 } 251 252 if (end_number) { 253 if (have_precision) 254 fmt.precision = number; 255 else 256 fmt.width = number; 257 258 end_number = false; 259 number = 0; 260 } 261 262 if (done) { 263 if ((fmt.format == Format::integer) && have_precision) { 264 // specified a . but not a float, set width 265 fmt.width = fmt.precision; 266 // precision requries digits for width, must fill with 0 267 fmt.fill_zero = true; 268 } else if ((fmt.format == Format::floating) && !have_precision && 269 fmt.fill_zero) { 270 // ambiguous case, matching printf 271 fmt.precision = fmt.width; 272 } 273 } 274 } // end while 275 276 ++ptr; 277} 278 279void 280Print::end_args() 281{ 282 size_t len; 283 284 while (*ptr) { 285 switch (*ptr) { 286 case '%': 287 if (ptr[1] != '%') 288 stream << "<extra arg>"; 289 290 stream.put('%'); 291 ptr += 2; 292 break; 293 294 case '\n': 295 stream << endl; 296 ++ptr; 297 break; 298 case '\r': 299 ++ptr; 300 if (*ptr != '\n') 301 stream << endl; 302 break; 303 304 default: 305 len = strcspn(ptr, "%\n\r\0"); 306 stream.write(ptr, len); 307 ptr += len; 308 break; 309 } 310 } 311 312 stream.flags(saved_flags); 313 stream.fill(saved_fill); 314 stream.precision(saved_precision); 315 stream.width(saved_width); 316} 317 318} // namespace cp 319