/* * Copyright (c) 2003 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "cprintf.hh" using namespace std; namespace cp { void ArgList::dump(const string &format) { const char *p = format.c_str(); stream->fill(' '); stream->flags((ios::fmtflags)0); Format fmt; while (*p) { switch (*p) { case '%': { if (p[1] == '%') { *stream << '%'; p += 2; continue; } if (objects.empty()) format_invalid(*stream); Base *data = objects.front(); fmt.clear(); bool done = false; bool end_number = false; bool have_precision = false; int number = 0; while (!done) { ++p; if (*p >= '0' && *p <= '9') { if (end_number) continue; } else if (number > 0) end_number = true; switch (*p) { case 's': fmt.format = Format::string; done = true; break; case 'c': fmt.format = Format::character; done = true; break; case 'l': continue; case 'p': fmt.format = Format::integer; fmt.base = Format::hex; fmt.alternate_form = true; done = true; break; case 'X': fmt.uppercase = true; case 'x': fmt.base = Format::hex; fmt.format = Format::integer; done = true; break; case 'o': fmt.base = Format::oct; fmt.format = Format::integer; done = true; break; case 'd': case 'i': case 'u': fmt.format = Format::integer; done = true; break; case 'G': fmt.uppercase = true; case 'g': fmt.format = Format::floating; fmt.float_format = Format::best; done = true; break; case 'E': fmt.uppercase = true; case 'e': fmt.format = Format::floating; fmt.float_format = Format::scientific; done = true; break; case 'f': fmt.format = Format::floating; fmt.float_format = Format::fixed; done = true; break; case 'n': *stream << "we don't do %n!!!\n"; done = true; break; case '#': fmt.alternate_form = true; break; case '-': fmt.flush_left = true; break; case '+': fmt.print_sign = true; break; case ' ': fmt.blank_space = true; break; case '.': fmt.width = number; fmt.precision = 0; have_precision = true; number = 0; end_number = false; break; case '0': if (number == 0) { fmt.fill_zero = true; break; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': number = number * 10 + (*p - '0'); break; case '%': assert("we shouldn't get here"); break; default: done = true; break; } if (end_number) { if (have_precision) fmt.precision = number; else fmt.width = number; end_number = false; number = 0; } } ios::fmtflags saved_flags = stream->flags(); char old_fill = stream->fill(); int old_precision = stream->precision(); data->process(*stream, fmt); stream->flags(saved_flags); stream->fill(old_fill); stream->precision(old_precision); delete data; objects.pop_front(); ++p; } break; case '\n': *stream << endl; ++p; break; case '\r': ++p; if (*p != '\n') *stream << endl; break; default: { size_t len = strcspn(p, "%\n\r\0"); stream->write(p, len); p += len; } break; } ios::iostate state = stream->rdstate(); if (state) { #if 0 cout << "stream->rdstate() == " << state << endl; if (state & ios::badbit) cout << "stream is bad!\n"; if (state & ios::eofbit) cout << "stream at eof!\n"; if (state & ios::failbit) cout << "stream failed!\n"; if (state & ios::goodbit) cout << "stream is good!!\n"; #endif stream->clear(); } } while (!objects.empty()) { Base *data = objects.front(); data->process(*stream, fmt); delete data; objects.pop_front(); } } string ArgList::dumpToString(const string &format) { stringstream ss; dump(ss, format); return ss.str(); } }