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