Line data Source code
1 : // Copyright (c) 2011-2023 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/snapdev 4 : // contact@m2osw.com 5 : // 6 : // This program is free software: you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation, either version 3 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License 17 : // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 : #pragma once 19 : 20 : // C++ 21 : // 22 : #include <fstream> 23 : #include <iostream> 24 : #include <ext/stdio_filebuf.h> 25 : #include <ext/stdio_sync_filebuf.h> 26 : 27 : // C 28 : // 29 : #include <unistd.h> 30 : 31 : 32 : 33 : namespace snapdev 34 : { 35 : 36 : 37 : 38 : namespace detail 39 : { 40 : 41 : template<typename _CharT 42 : , typename _Traits = std::char_traits<_CharT>> 43 : class our_basic_filebuf 44 : : public std::basic_filebuf<_CharT, _Traits> 45 : { 46 : public: 47 1 : std::__c_file * file() throw() 48 : { 49 : //return std::basic_filebuf<_CharT, _Traits>::_M_file.file(); 50 1 : return this->_M_file.file(); 51 : } 52 : }; 53 : 54 : } // namespace detail 55 : 56 : 57 : 58 : /** \brief Check whether a C++ iostream is a TTY. 59 : * 60 : * This function checks the specified stream and if it represents a TTY 61 : * returns true. 62 : * 63 : * If the stream is not a standard file stream, then the function always 64 : * returns false, even if ultimately the stream does represent a TTY. This 65 : * is because we can really only handle the standard fstream's objects here. 66 : * 67 : * \note 68 : * The function dynamic casts to a the three different types of buffers 69 : * to see whether we can find a file() function. If so, then we check 70 : * that the file isatty() or not. 71 : * 72 : * \tparam _CharT type of character this stream handles. 73 : * \tparam _Traits traits of the characters based on CharT by default. 74 : * \param[in] stream The stream to check. 75 : * 76 : * \return true if \p stream is a TTY. 77 : */ 78 : template<typename _CharT 79 : , typename _Traits = std::char_traits<_CharT>> 80 6 : bool isatty(std::basic_ios<_CharT, _Traits> const & s) 81 : { 82 : // in most cases, we use cin, cout, cerr, or clog which are all 83 : // stdio_sync_filebuf<> objects 84 : { 85 : typedef __gnu_cxx::stdio_sync_filebuf<_CharT, _Traits> io_sync_buffer_t; 86 6 : io_sync_buffer_t * buffer(dynamic_cast<io_sync_buffer_t *>(s.rdbuf())); 87 6 : if(buffer != nullptr) 88 : { 89 4 : return ::isatty(fileno(buffer->file())); 90 : } 91 : } 92 : 93 : // in this case, we first do a dynamic_cast<>() to make sure we find the 94 : // correct buffer; if present we can do a static_cast<>() to gain access 95 : // to the _M_file field and thus the file() function (there is also an 96 : // fd() function, but to be consistent with the other cases, I used a 97 : // file() like function only) 98 : { 99 : typedef std::basic_filebuf<_CharT, _Traits> file_buffer_t; 100 2 : file_buffer_t * file_buffer(dynamic_cast<file_buffer_t *>(s.rdbuf())); 101 2 : if(file_buffer != nullptr) 102 : { 103 : typedef detail::our_basic_filebuf<_CharT, _Traits> hack_buffer_t; 104 1 : hack_buffer_t * buffer(static_cast<hack_buffer_t *>(file_buffer)); 105 1 : if(buffer != nullptr) 106 : { 107 1 : return ::isatty(fileno(buffer->file())); 108 : } 109 : } 110 : } 111 : 112 : // older versions (C++98) used this class -- it is probably never 113 : // going to be true so I put it last 114 : { 115 : typedef __gnu_cxx::stdio_filebuf<_CharT, _Traits> io_buffer_t; 116 1 : io_buffer_t * buffer(dynamic_cast<io_buffer_t *>(s.rdbuf())); 117 1 : if(buffer != nullptr) 118 : { 119 0 : return ::isatty(fileno(buffer->file())); 120 : } 121 : } 122 : 123 1 : return false; 124 : } 125 : 126 : 127 : 128 : } // namespace snapdev 129 : // vim: ts=4 sw=4 et 130 :