Line data Source code
1 : // Copyright (c) 2011-2022 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 2 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : #pragma once
20 :
21 : // C++
22 : //
23 : #include <fstream>
24 : #include <iostream>
25 : #include <ext/stdio_filebuf.h>
26 : #include <ext/stdio_sync_filebuf.h>
27 :
28 : // C
29 : //
30 : #include <unistd.h>
31 :
32 :
33 :
34 : namespace snapdev
35 : {
36 :
37 :
38 :
39 : namespace detail
40 : {
41 :
42 : template<typename _CharT
43 : , typename _Traits = std::char_traits<_CharT>>
44 : class our_basic_filebuf
45 : : public std::basic_filebuf<_CharT, _Traits>
46 : {
47 : public:
48 1 : std::__c_file * file() throw()
49 : {
50 : //return std::basic_filebuf<_CharT, _Traits>::_M_file.file();
51 1 : return this->_M_file.file();
52 : }
53 : };
54 :
55 : } // namespace detail
56 :
57 :
58 :
59 : /** \brief Check whether a C++ iostream is a TTY.
60 : *
61 : * This function checks the specified stream and if it represents a TTY
62 : * returns true.
63 : *
64 : * If the stream is not a standard file stream, then the function always
65 : * returns false, even if ultimately the stream does represent a TTY. This
66 : * is because we can really only handle the standard fstream's objects here.
67 : *
68 : * \note
69 : * The function dynamic casts to a the three different types of buffers
70 : * to see whether we can find a file() function. If so, then we check
71 : * that the file isatty() or not.
72 : *
73 : * \tparam _CharT type of character this stream handles.
74 : * \tparam _Traits traits of the characters based on CharT by default.
75 : * \param[in] stream The stream to check.
76 : *
77 : * \return true if \p stream is a TTY.
78 : */
79 : template<typename _CharT
80 : , typename _Traits = std::char_traits<_CharT>>
81 6 : bool isatty(std::basic_ios<_CharT, _Traits> const & s)
82 : {
83 : // in most cases, we use cin, cout, cerr, or clog which are all
84 : // stdio_sync_filebuf<> objects
85 : {
86 : typedef __gnu_cxx::stdio_sync_filebuf<_CharT, _Traits> io_sync_buffer_t;
87 6 : io_sync_buffer_t * buffer(dynamic_cast<io_sync_buffer_t *>(s.rdbuf()));
88 6 : if(buffer != nullptr)
89 : {
90 4 : return ::isatty(fileno(buffer->file()));
91 : }
92 : }
93 :
94 : {
95 : typedef __gnu_cxx::stdio_filebuf<_CharT, _Traits> io_buffer_t;
96 2 : io_buffer_t * buffer(dynamic_cast<io_buffer_t *>(s.rdbuf()));
97 2 : if(buffer != nullptr)
98 : {
99 0 : return ::isatty(fileno(buffer->file()));
100 : }
101 : }
102 :
103 : // in this case, we first do a dynamic_cast<>() to make sure we find the
104 : // correct buffer; if present we can do a static_cast<>() to gain access
105 : // to the _M_file field and thus the file() function (there is also an
106 : // fd() function, but to be consistent with the other cases, I used a
107 : // file() like function only)
108 : {
109 : typedef std::basic_filebuf<_CharT, _Traits> file_buffer_t;
110 2 : file_buffer_t * file_buffer(dynamic_cast<file_buffer_t *>(s.rdbuf()));
111 2 : if(file_buffer != nullptr)
112 : {
113 : typedef detail::our_basic_filebuf<_CharT, _Traits> hack_buffer_t;
114 1 : hack_buffer_t * buffer(static_cast<hack_buffer_t *>(file_buffer));
115 1 : if(buffer != nullptr)
116 : {
117 1 : return ::isatty(fileno(buffer->file()));
118 : }
119 : }
120 : }
121 :
122 1 : return false;
123 : }
124 :
125 :
126 :
127 : } // namespace snapdev
128 : // vim: ts=4 sw=4 et
129 :
|