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