| /* |
| * Copyright (c) 2002-2006 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. |
| * |
| * Authors: Nathan Binkert |
| */ |
| |
| #include "base/cprintf.hh" |
| |
| #include <cassert> |
| #include <iomanip> |
| #include <iostream> |
| #include <sstream> |
| |
| using namespace std; |
| |
| namespace cp { |
| |
| Print::Print(std::ostream &stream, const std::string &format) |
| : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false) |
| { |
| saved_flags = stream.flags(); |
| saved_fill = stream.fill(); |
| saved_precision = stream.precision(); |
| } |
| |
| Print::Print(std::ostream &stream, const char *format) |
| : stream(stream), format(format), ptr(format), cont(false) |
| { |
| saved_flags = stream.flags(); |
| saved_fill = stream.fill(); |
| saved_precision = stream.precision(); |
| } |
| |
| Print::~Print() |
| { |
| } |
| |
| void |
| Print::process() |
| { |
| fmt.clear(); |
| |
| size_t len; |
| |
| while (*ptr) { |
| switch (*ptr) { |
| case '%': |
| if (ptr[1] != '%') { |
| process_flag(); |
| return; |
| } |
| stream.put('%'); |
| ptr += 2; |
| break; |
| |
| case '\n': |
| stream << endl; |
| ++ptr; |
| break; |
| case '\r': |
| ++ptr; |
| if (*ptr != '\n') |
| stream << endl; |
| break; |
| |
| default: |
| len = strcspn(ptr, "%\n\r\0"); |
| stream.write(ptr, len); |
| ptr += len; |
| break; |
| } |
| } |
| } |
| |
| void |
| Print::process_flag() |
| { |
| bool done = false; |
| bool end_number = false; |
| bool have_precision = false; |
| int number = 0; |
| |
| stream.fill(' '); |
| stream.flags((ios::fmtflags)0); |
| |
| while (!done) { |
| ++ptr; |
| if (*ptr >= '0' && *ptr <= '9') { |
| if (end_number) |
| continue; |
| } else if (number > 0) |
| end_number = true; |
| |
| switch (*ptr) { |
| 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 + (*ptr - '0'); |
| break; |
| |
| case '*': |
| if (have_precision) |
| fmt.get_precision = true; |
| else |
| fmt.get_width = true; |
| break; |
| |
| case '%': |
| assert(false && "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; |
| } |
| |
| if (done) { |
| if ((fmt.format == Format::integer) && have_precision) { |
| // specified a . but not a float, set width |
| fmt.width = fmt.precision; |
| // precision requries digits for width, must fill with 0 |
| fmt.fill_zero = true; |
| } else if ((fmt.format == Format::floating) && !have_precision && |
| fmt.fill_zero) { |
| // ambiguous case, matching printf |
| fmt.precision = fmt.width; |
| } |
| } |
| } // end while |
| |
| ++ptr; |
| } |
| |
| void |
| Print::end_args() |
| { |
| size_t len; |
| |
| while (*ptr) { |
| switch (*ptr) { |
| case '%': |
| if (ptr[1] != '%') |
| stream << "<extra arg>"; |
| |
| stream.put('%'); |
| ptr += 2; |
| break; |
| |
| case '\n': |
| stream << endl; |
| ++ptr; |
| break; |
| case '\r': |
| ++ptr; |
| if (*ptr != '\n') |
| stream << endl; |
| break; |
| |
| default: |
| len = strcspn(ptr, "%\n\r\0"); |
| stream.write(ptr, len); |
| ptr += len; |
| break; |
| } |
| } |
| |
| stream.flags(saved_flags); |
| stream.fill(saved_fill); |
| stream.precision(saved_precision); |
| } |
| |
| } // namespace cp |