| /* |
| * 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. |
| */ |
| |
| #include "base/cprintf.hh" |
| |
| #include <iomanip> |
| #include <iostream> |
| #include <sstream> |
| |
| #include "base/compiler.hh" |
| |
| namespace cp |
| { |
| |
| Print::Print(std::ostream &stream, const std::string &format) |
| : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false) |
| { |
| savedFlags = stream.flags(); |
| savedFill = stream.fill(); |
| savedPrecision = stream.precision(); |
| savedWidth = stream.width(); |
| } |
| |
| Print::Print(std::ostream &stream, const char *format) |
| : stream(stream), format(format), ptr(format), cont(false) |
| { |
| savedFlags = stream.flags(); |
| savedFill = stream.fill(); |
| savedPrecision = stream.precision(); |
| savedWidth = stream.width(); |
| } |
| |
| Print::~Print() |
| { |
| } |
| |
| void |
| Print::process() |
| { |
| fmt.clear(); |
| |
| size_t len; |
| |
| while (*ptr) { |
| switch (*ptr) { |
| case '%': |
| if (ptr[1] != '%') { |
| processFlag(); |
| return; |
| } |
| stream.put('%'); |
| ptr += 2; |
| break; |
| |
| case '\n': |
| stream << std::endl; |
| ++ptr; |
| break; |
| case '\r': |
| ++ptr; |
| if (*ptr != '\n') |
| stream << std::endl; |
| break; |
| |
| default: |
| len = strcspn(ptr, "%\n\r\0"); |
| stream.write(ptr, len); |
| ptr += len; |
| break; |
| } |
| } |
| } |
| |
| void |
| Print::processFlag() |
| { |
| bool done = false; |
| bool end_number = false; |
| bool have_precision = false; |
| int number = 0; |
| |
| stream.fill(' '); |
| stream.flags((std::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.alternateForm = true; |
| done = true; |
| break; |
| |
| case 'X': |
| fmt.uppercase = true; |
| M5_FALLTHROUGH; |
| 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; |
| M5_FALLTHROUGH; |
| case 'g': |
| fmt.format = Format::Floating; |
| fmt.floatFormat = Format::Best; |
| done = true; |
| break; |
| |
| case 'E': |
| fmt.uppercase = true; |
| M5_FALLTHROUGH; |
| case 'e': |
| fmt.format = Format::Floating; |
| fmt.floatFormat = Format::Scientific; |
| done = true; |
| break; |
| |
| case 'f': |
| fmt.format = Format::Floating; |
| fmt.floatFormat = Format::Fixed; |
| done = true; |
| break; |
| |
| case 'n': |
| stream << "we don't do %n!!!\n"; |
| done = true; |
| break; |
| |
| case '#': |
| fmt.alternateForm = true; |
| break; |
| |
| case '-': |
| fmt.flushLeft = true; |
| break; |
| |
| case '+': |
| fmt.printSign = true; |
| break; |
| |
| case ' ': |
| fmt.blankSpace = true; |
| break; |
| |
| case '.': |
| fmt.width = number; |
| fmt.precision = 0; |
| have_precision = true; |
| number = 0; |
| end_number = false; |
| break; |
| |
| case '0': |
| if (number == 0) { |
| fmt.fillZero = true; |
| break; |
| } |
| M5_FALLTHROUGH; |
| 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.getPrecision = true; |
| else |
| fmt.getWidth = true; |
| break; |
| |
| case '%': |
| M5_UNREACHABLE; |
| 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.fillZero = true; |
| } else if ((fmt.format == Format::Floating) && !have_precision && |
| fmt.fillZero) { |
| // ambiguous case, matching printf |
| fmt.precision = fmt.width; |
| } |
| } |
| } // end while |
| |
| ++ptr; |
| } |
| |
| void |
| Print::endArgs() |
| { |
| size_t len; |
| |
| while (*ptr) { |
| switch (*ptr) { |
| case '%': |
| if (ptr[1] != '%') |
| stream << "<extra arg>"; |
| |
| stream.put('%'); |
| ptr += 2; |
| break; |
| |
| case '\n': |
| stream << std::endl; |
| ++ptr; |
| break; |
| case '\r': |
| ++ptr; |
| if (*ptr != '\n') |
| stream << std::endl; |
| break; |
| |
| default: |
| len = strcspn(ptr, "%\n\r\0"); |
| stream.write(ptr, len); |
| ptr += len; |
| break; |
| } |
| } |
| |
| stream.flags(savedFlags); |
| stream.fill(savedFill); |
| stream.precision(savedPrecision); |
| stream.width(savedWidth); |
| } |
| |
| } // namespace cp |