/* * 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 #include #include #include "base/compiler.hh" namespace gem5 { 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; [[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; [[fallthrough]]; case 'g': fmt.format = Format::Floating; fmt.floatFormat = Format::Best; done = true; break; case 'E': fmt.uppercase = true; [[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; } [[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 '%': GEM5_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 << ""; 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 } // namespace gem5