How to get file descriptor from std :: basic_ios for clang on OS X?

I am porting some code to Darwin OS X and as part of the change, we are moving from gcc to the clang compiler.

The code has a feature dating back to 2005 and located in several places on the Internet. It provides functions for several different old versions of GCC, I edited everything except the last one it offers, v3.4.0 or later. The code depends on two special GCC classes: __gnu_cxx::stdio_filebuf and __gnu_cxx::stdio_sync_filebuf .

 //! Similar to fileno(3), but taking a C++ stream as argument instead of a //! FILE*. Note that there is no way for the library to track what you do with //! the descriptor, so be careful. //! \return The integer file descriptor associated with the stream, or -1 if //! that stream is invalid. In the latter case, for the sake of keeping the //! code as similar to fileno(3), errno is set to EBADF. //! \see The <A HREF="http://www.ginac.de/~kreckel/fileno/">upstream page at //! http://www.ginac.de/~kreckel/fileno/</A> of this code provides more //! detailed information. template <typename charT, typename traits> inline int fileno_hack(const std::basic_ios<charT, traits>& stream) { // Some C++ runtime libraries shipped with ancient GCC, Sun Pro, // Sun WS/Forte 5/6, Compaq C++ supported non-standard file descriptor // access basic_filebuf<>::fd(). Alas, starting from GCC 3.1, the GNU C++ // runtime removes all non-standard std::filebuf methods and provides an // extension template class __gnu_cxx::stdio_filebuf on all systems where // that appears to make sense (ie at least all Unix systems). Starting // from GCC 3.4, there is an __gnu_cxx::stdio_sync_filebuf, in addition. // Sorry, darling, I must get brutal to fetch the darn file descriptor! // Please complain to your compiler/libstdc++ vendor... #if defined(__GLIBCXX__) || defined(__GLIBCPP__) // OK, stop reading here, because it getting obscene. Cross fingers! # if defined(__GLIBCXX__) // >= GCC 3.4.0 // This applies to cin, cout and cerr when not synced with stdio: typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t; unix_filebuf_t* fbuf = dynamic_cast<unix_filebuf_t*>(stream.rdbuf()); if (fbuf != NULL) { return fbuf->fd(); } // This applies to filestreams: typedef std::basic_filebuf<charT, traits> filebuf_t; filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf()); if (bbuf != NULL) { // This subclass is only there for accessing the FILE*. Ouuwww, sucks! struct my_filebuf : public std::basic_filebuf<charT, traits> { int fd() { return this->_M_file.fd(); } }; return static_cast<my_filebuf*>(bbuf)->fd(); } // This applies to cin, cout and cerr when synced with stdio: typedef __gnu_cxx::stdio_sync_filebuf<charT, traits> sync_filebuf_t; sync_filebuf_t* sbuf = dynamic_cast<sync_filebuf_t*>(stream.rdbuf()); if (sbuf != NULL) { return fileno(sbuf->file()); } # endif #else # error "Does anybody know how to fetch the bloody file descriptor?" return stream.rdbuf()->fd(); // Maybe a good start? #endif errno = EBADF; return -1; } 

The question is, for clang 5.1 on OS X Mavericks, would there be a way to compute the file descriptor for std::basic_ios ?

+8
c ++ iostream file-descriptor porting macos
source share
1 answer

If you do not mind that your hands are really dirty, stuck in the private details of the implementation, the following code works:

 #include <iostream> #include <fstream> // Generate a static data member of type Tag::type in which to store // the address of a private member. It is crucial that Tag does not // depend on the /value/ of the the stored address in any way so that // we can access it from ordinary code without directly touching // private data. template < class Tag > struct stowed { static typename Tag::type value; }; template < class Tag > typename Tag::type stowed< Tag >::value; // Generate a static data member whose constructor initializes // stowed< Tag >::value. This type will only be named in an explicit // instantiation, where it is legal to pass the address of a private // member. template < class Tag, typename Tag::type x > struct stow_private { stow_private() { stowed< Tag >::value = x; } static stow_private instance; }; template < class Tag, typename Tag::type x > stow_private< Tag, x > stow_private< Tag, x >::instance; struct filebuf_file { typedef FILE*( std::filebuf::*type ); }; template struct stow_private< filebuf_file, &std::filebuf::__file_ >; FILE* c_file( std::filebuf& fb ) { return fb.*stowed< filebuf_file >::value; } int main(int argc, const char * argv[]) { std::ofstream fs("test.txt"); FILE* file = c_file(*fs.rdbuf()); std::cout << file->_file << "\n"; return 0; } 
+2
source share

All Articles