source: rrlib_util/fstream/fileno.hpp @ 43:0b04f7b6406e

Last change on this file since 43:0b04f7b6406e was 43:0b04f7b6406e, checked in by Tobias Föhst <foehst@…>, 8 years ago

Reformatted with astyle 2.02.1

File size: 8.1 KB
Line 
1//
2// You received this file as part of RRLib
3// Robotics Research Library
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20//
21//----------------------------------------------------------------------
22/*!\file    fileno.hpp
23 *
24 * \author  Tobias Foehst
25 *
26 * \date    2010-07-29
27 *
28 */
29//----------------------------------------------------------------------
30
31//----------------------------------------------------------------------
32// External includes (system with <>, local with "")
33//----------------------------------------------------------------------
34#include <cstdio>
35#include <fstream>
36#include <cerrno>
37
38#if defined(__GLIBCXX__) || (defined(__GLIBCPP__) && __GLIBCPP__>=20020514)  // GCC >= 3.1.0
39# include <ext/stdio_filebuf.h>
40#endif
41#if defined(__GLIBCXX__) // GCC >= 3.4.0
42# include <ext/stdio_sync_filebuf.h>
43#endif
44
45//----------------------------------------------------------------------
46// Internal includes with ""
47//----------------------------------------------------------------------
48
49//----------------------------------------------------------------------
50// Debugging
51//----------------------------------------------------------------------
52
53//----------------------------------------------------------------------
54// Namespace declaration
55//----------------------------------------------------------------------
56namespace rrlib
57{
58namespace util
59{
60
61//----------------------------------------------------------------------
62// Forward declarations / typedefs / enums
63//----------------------------------------------------------------------
64
65//----------------------------------------------------------------------
66// Const values
67//----------------------------------------------------------------------
68
69//----------------------------------------------------------------------
70// Implementation
71//----------------------------------------------------------------------
72
73namespace
74{
75
76template <typename charT, typename traits>
77inline int fileno_hack(std::basic_streambuf<charT, traits> *stream_buffer)
78{
79  // Some C++ runtime libraries shipped with ancient GCC, Sun Pro,
80  // Sun WS/Forte 5/6, Compaq C++ supported non-standard file descriptor
81  // access basic_filebuf<>::fd().  Alas, starting from GCC 3.1, the GNU C++
82  // runtime removes all non-standard std::filebuf methods and provides an
83  // extension template class __gnu_cxx::stdio_filebuf on all systems where
84  // that appears to make sense (i.e. at least all Unix systems).  Starting
85  // from GCC 3.4, there is an __gnu_cxx::stdio_sync_filebuf, in addition.
86  // Sorry, darling, I must get brutal to fetch the darn file descriptor!
87  // Please complain to your compiler/libstdc++ vendor...
88#if defined(__GLIBCXX__) || defined(__GLIBCPP__)
89  // OK, stop reading here, because it's getting obscene.  Cross fingers!
90# if defined(__GLIBCXX__)  // >= GCC 3.4.0
91  // This applies to cin, cout and cerr when not synced with stdio:
92  typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t;
93  unix_filebuf_t *fbuf = dynamic_cast<unix_filebuf_t *>(stream_buffer);
94  if (fbuf != NULL)
95  {
96    return fbuf->fd();
97  }
98
99  // This applies to filestreams:
100  typedef std::basic_filebuf<charT, traits> filebuf_t;
101  filebuf_t *bbuf = dynamic_cast<filebuf_t *>(stream_buffer);
102  if (bbuf != NULL)
103  {
104    // This subclass is only there for accessing the FILE*.  Ouuwww, sucks!
105    struct my_filebuf : public std::basic_filebuf<charT, traits>
106    {
107      int fd()
108      {
109        return this->_M_file.fd();
110      }
111    };
112    return static_cast<my_filebuf *>(bbuf)->fd();
113  }
114
115  // This applies to cin, cout and cerr when synced with stdio:
116  typedef __gnu_cxx::stdio_sync_filebuf<charT, traits> sync_filebuf_t;
117  sync_filebuf_t *sbuf = dynamic_cast<sync_filebuf_t *>(stream_buffer);
118  if (sbuf != NULL)
119  {
120#  if (__GLIBCXX__<20040906) // GCC < 3.4.2
121    // This subclass is only there for accessing the FILE*.
122    // See GCC PR#14600 and PR#16411.
123    struct my_filebuf : public sync_filebuf_t
124    {
125      my_filebuf();  // Dummy ctor keeps the compiler happy.
126      // Note: stdio_sync_filebuf has a FILE* as its first (but private)
127      // member variable.  However, it is derived from basic_streambuf<>
128      // and the FILE* is the first non-inherited member variable.
129      FILE* c_file()
130      {
131        return *(FILE **)((char*)this + sizeof(std::basic_streambuf<charT, traits>));
132      }
133    };
134    return ::fileno(static_cast<my_filebuf *>(sbuf)->c_file());
135#  else
136    return ::fileno(sbuf->file());
137#  endif
138  }
139# else  // GCC < 3.4.0 used __GLIBCPP__
140#  if (__GLIBCPP__>=20020514)  // GCC >= 3.1.0
141  // This applies to cin, cout and cerr:
142  typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t;
143  unix_filebuf_t *buf = dynamic_cast<unix_filebuf_t *>(stream_buffer);
144  if (buf != NULL)
145  {
146    return buf->fd();
147  }
148
149  // This applies to filestreams:
150  typedef std::basic_filebuf<charT, traits> filebuf_t;
151  filebuf_t *bbuf = dynamic_cast<filebuf_t *>(stream.rdbuf());
152  if (bbuf != NULL)
153  {
154    // This subclass is only there for accessing the FILE*.  Ouuwww, sucks!
155    struct my_filebuf : public std::basic_filebuf<charT, traits>
156    {
157      // Note: _M_file is of type __basic_file<char> which has a
158      // FILE* as its first (but private) member variable.
159      FILE *c_file()
160      {
161        return *(FILE **)(&this->_M_file);
162      }
163    };
164    FILE *c_file = static_cast<my_filebuf*>(bbuf)->c_file();
165    if (c_file != NULL)    // Could be NULL for failed ifstreams.
166    {
167      return ::fileno(c_file);
168    }
169  }
170#  else  // GCC 3.0.x
171  typedef std::basic_filebuf<charT, traits> filebuf_t;
172  filebuf_t *fbuf = dynamic_cast<filebuf_t *>(stream_buffer);
173  if (fbuf != NULL)
174  {
175    struct my_filebuf : public filebuf_t
176    {
177      // Note: basic_filebuf<charT, traits> has a __basic_file<charT>* as
178      // its first (but private) member variable.  Since it is derived
179      // from basic_streambuf<charT, traits> we can guess its offset.
180      // __basic_file<charT> in turn has a FILE* as its first (but
181      // private) member variable.  Get it by brute force.  Oh, geez!
182      FILE *c_file()
183      {
184        std::__basic_file<charT> *ptr_M_file = *(std::__basic_file<charT> **)((char*)this + sizeof(std::basic_streambuf<charT, traits>));
185#  if _GLIBCPP_BASIC_FILE_INHERITANCE
186        // __basic_file<charT> inherits from __basic_file_base<charT>
187        return *(FILE **)((char *)ptr_M_file + sizeof(std::__basic_file_base<charT>));
188#  else
189        // __basic_file<charT> is base class, but with vptr.
190        return *(FILE **)((char *)ptr_M_file + sizeof(void*));
191#  endif
192      }
193    };
194    return ::fileno(static_cast<my_filebuf *>(fbuf)->c_file());
195  }
196#  endif
197# endif
198#else
199#  error "Does anybody know how to fetch the bloody file descriptor?"
200  return stream.rdbuf()->fd();  // Maybe a good start?
201#endif
202  errno = EBADF;
203  return -1;
204}
205
206}
207
208//! 8-Bit character instantiation: GetFileDescriptor(ios).
209template <>
210int GetFileDescriptor<char>(const std::streambuf *stream_buffer)
211{
212  return fileno_hack(const_cast<std::streambuf *>(stream_buffer));
213}
214
215#if !(defined(__GLIBCXX__) || defined(__GLIBCPP__)) || (defined(_GLIBCPP_USE_WCHAR_T) || defined(_GLIBCXX_USE_WCHAR_T))
216//! Wide character instantiation: GetFileDescriptor(wios).
217template <>
218int GetFileDescriptor<wchar_t>(const std::wstreambuf *stream_buffer)
219{
220  return fileno_hack(const_cast<std::wstreambuf *>(stream_buffer));
221}
222#endif
223
224//----------------------------------------------------------------------
225// End of namespace declaration
226//----------------------------------------------------------------------
227}
228}
Note: See TracBrowser for help on using the repository browser.