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