/** @file * IPRT / No-CRT - Minimal C++ ostream header. */ /* * Copyright (C) 2022 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. * * The contents of this file may alternatively be used under the terms * of the Common Development and Distribution License Version 1.0 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the * VirtualBox OSE distribution, in which case the provisions of the * CDDL are applicable instead of those of the GPL. * * You may elect to license modified versions of this file under the * terms and conditions of either the GPL or the CDDL or both. */ #ifndef IPRT_INCLUDED_nocrt_ostream #define IPRT_INCLUDED_nocrt_ostream #ifndef RT_WITHOUT_PRAGMA_ONCE # pragma once #endif /* Currently all in the ios header. */ #include namespace std { /** * Basic output stream. */ template*/ > class basic_ostream : public basic_ios { protected: /** Sentry class that performs pre and post output work. */ class sentry { private: basic_ostream &m_rParent; public: explicit sentry(basic_ostream &a_rParent) : m_rParent(a_rParent) { if (a_rParent.good()) { basic_ostream *pTiedStream = a_rParent.tie(); if (!pTiedStream) { /* likely? */ } else { pTiedStream->flush(); if (!pTiedStream->good()) a_rParent.setstate(failbit); } } } explicit operator bool() const { return m_rParent.good(); } ~sentry() { if ( (m_rParent.flags() & std::ios_base::unitbuf) && m_rParent.good()) m_rParent.rdbuf()->pubsync(); } }; public: explicit basic_ostream(std::basic_streambuf *a_pBuf) : basic_ios(a_pBuf) { } /** For cerr initialization. * @internal */ explicit basic_ostream(std::basic_streambuf *a_pBuf, std::basic_ostream *a_pTiedStream, bool a_fUnbuffered) : basic_ios(a_pBuf) { m_pTiedStream = a_pTiedStream; if (!a_fUnbuffered) setf(std::ios_base::unitbuf); } private: basic_ostream(basic_ostream const &a_rSrc); /* not copyable */ basic_ostream &operator=(basic_ostream const &a_rSrc); /* not copyable */ public: virtual ~basic_ostream() { } public: basic_ostream &put(char_type a_ch) { sentry PrePost(*this); if (PrePost) { if (m_pBuf->sputc(a_ch) == traits_type::eof()) m_fState |= badbit; } return *this; } basic_ostream &write(const char_type *a_pchSrc, std::streamsize a_cchToWrite) { sentry PrePost(*this); if (PrePost) { std::streamsize cchWritten = m_pBuf->sputn(a_pchSrc, a_cchToWrite); if (cchWritten != a_cchToWrite) m_fState |= badbit; } return *this; } basic_ostream &flush() { if (m_pBuf) m_pBuf->pubsync(); return *this; } pos_type tellp() RT_NOEXCEPT; basic_ostream &seekp(pos_type a_off) RT_NOEXCEPT; basic_ostream &seekp(off_type a_off, seekdir enmDir) RT_NOEXCEPT; /** @name Internal support methods * @{ */ inline basic_ostream &intWrite(const char *a_pchSrc, std::streamsize a_cchToWrite); /**< Internal method outputting char buffers. */ /** @returns 8, 10 or 16. */ inline unsigned intGetIntegerBase() const RT_NOEXCEPT { switch (m_fFlags & basefield) { default: case dec: return 10; case hex: return 16; case oct: return 8; } } /** @returns RTSTR_F_XXX . */ inline unsigned intGetIntegerFlags() const RT_NOEXCEPT { unsigned fFlags = 0; if (m_fFlags & uppercase) fFlags |= RTSTR_F_CAPITAL; if (m_fFlags & showbase) fFlags |= RTSTR_F_SPECIAL; if (m_fFlags & showpos) fFlags |= RTSTR_F_PLUS; return fFlags; } basic_ostream &formatInteger(uint64_t a_uValue, uint32_t a_fFlags, unsigned a_uBase = 0) { a_fFlags |= intGetIntegerFlags(); char szTmp[72]; int cchTmp = RTStrFormatNumber(szTmp, a_uValue, !a_uBase ? intGetIntegerBase() : a_uBase, 0, 0, a_fFlags); /** @todo apply cchWidth and padding. */ return intWrite(szTmp, cchTmp); } /** @} */ }; /** @name Character and string output. * @{ */ /** @todo not sure if this really works... */ template > basic_ostream &operator<<(basic_ostream &a_rDst, char a_ch) { return a_rDst.put(a_ch); } template > basic_ostream &operator<<(basic_ostream &a_rDst, const char *a_psz) { return a_rDst.intWrite(a_psz, strlen(a_psz)); } /** @} */ /** @name Integer formatting. * @{ */ template > basic_ostream &operator<<(basic_ostream &a_rDst, signed char a_iValue) { return a_rDst.formatInteger(a_iValue, RTSTR_F_8BIT | RTSTR_F_VALSIGNED); } template > basic_ostream &operator<<(basic_ostream &a_rDst, unsigned char a_uValue) { return a_rDst.formatInteger(a_uValue, RTSTR_F_8BIT); } template > basic_ostream &operator<<(basic_ostream &a_rDst, short a_iValue) { return a_rDst.formatInteger(a_iValue, RTSTR_F_16BIT | RTSTR_F_VALSIGNED); } template > basic_ostream &operator<<(basic_ostream &a_rDst, unsigned short a_uValue) { return a_rDst.formatInteger(a_uValue, RTSTR_F_16BIT); } template > basic_ostream &operator<<(basic_ostream &a_rDst, int a_iValue) { return a_rDst.formatInteger(a_iValue, RTSTR_F_32BIT | RTSTR_F_VALSIGNED); } template > basic_ostream &operator<<(basic_ostream &a_rDst, unsigned int a_uValue) { return a_rDst.formatInteger(a_uValue, RTSTR_F_32BIT | RTSTR_F_VALSIGNED); } template > basic_ostream &operator<<(basic_ostream &a_rDst, long a_iValue) { return a_rDst.formatInteger(a_iValue, (sizeof(a_iValue) > sizeof(int32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT)); } template > basic_ostream &operator<<(basic_ostream &a_rDst, unsigned long a_uValue) { return a_rDst.formatInteger(a_uValue, RTSTR_F_VALSIGNED | (sizeof(a_uValue) > sizeof(uint32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT)); } template > basic_ostream &operator<<(basic_ostream &a_rDst, void const *a_pvValue) { return a_rDst.formatInteger((uintptr_t)a_pvValue, (sizeof(a_pvValue) > sizeof(uint32_t) ? RTSTR_F_64BIT : RTSTR_F_32BIT), 16); } /** @} */ template<> inline basic_ostream &basic_ostream::intWrite(const char *a_pchSrc, std::streamsize a_cchToWrite) { return write(a_pchSrc, a_cchToWrite); } } #endif /* !IPRT_INCLUDED_nocrt_ostream */