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