This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

patch - implementation of stdio_fstream


Hi,

I have implemented the stdio_fstream template which makes the
implementation of stdio_filebuf a bit more usefull since users will no
longer have to implement their own.

I have also created a test case. However, I have run into a problem with
test 10 and would appreciate if someone could take a look at this.

Also when this works I'd appreciate it if this could be merged with the
main trunk (any chance this can make it into 3.4?)

Thanks,
Robert

This work was based on gcc-3.4-20040211

file stdio_fstream.h

// File based streams -*- C++ -*-

// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
// Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
along
// with this library; see the file COPYING.  If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307,
// USA.

// As a special exception, you may use this file as part of a free
software
// library without restriction.  Specifically, if other files
instantiate
// templates or use macros or inline functions from this file, or you
compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered
by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered
by
// the GNU General Public License.

//
// Non standar stream supporting legacy API
//

/** @file stdio_fstream
 *  This nonstandard implementation of the streams supports the legacy
API
 *  used by many application. It is necessary especially since the 
 *  Standard C++ Library does not support connecting a stream to a pipe
 *  or open file. This type of extension is also found in most
commercial
 *  imlpementations of the STL, namely Dinkumware and Rogue Wave.
*/

#ifndef _CPP_STDIO_FSTREAM
#define _CPP_STDIO_FSTREAM  1

#pragma GCC system_header

#include <istream>
#include <ostream>
#include <ext/stdio_filebuf.h>

namespace __gnu_cxx
{
  // Non standard file input
  
 template<typename _CharT, typename _Traits>
 class stdio_ifstream : public std::basic_istream<_CharT, _Traits>
 {
 public:
    // Types:
    typedef _CharT char_type;
    typedef _Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    typedef stdio_filebuf<char_type, traits_type> __filebuf_type;
    typedef std::basic_istream<char_type, traits_type> __istream_type;

 private:
     __filebuf_type     _M_filebuf;

 public:
     // Default ctor deferred initialization
     stdio_ifstream() 
     : __istream_type(NULL), _M_filebuf()
     { this->init(&_M_filebuf); }

    // Standard ctor
    stdio_ifstream(const char* __s, 
                   std::ios_base::openmode __mode = std::ios_base::in)
    : __istream_type(NULL), _M_filebuf()
    {
        this->init(&_M_filebuf);
        this->open(__s,__mode);
    }

    // ctor that takes a C FILE*
    stdio_ifstream(std::__c_file* __f)
    : __istream_type(NULL), _M_filebuf(__f, std::ios_base::in)
    { this->init(&_M_filebuf); }

    // ctor that takes a file descriptor
    stdio_ifstream(int __fd)
    : __istream_type(NULL), _M_filebuf(__fd, std::ios_base::in)
    { this->init(&_M_filebuf); }
    

    ~stdio_ifstream() {}

    stdio_filebuf<char_type>* rdbuf() const
    { return const_cast<stdio_filebuf<char_type>*>(&_M_filebuf); }

    int fd() { return _M_filebuf.fd(); }

    bool is_open() { return _M_filebuf.is_open(); }
    
    void open(const char* __s, 
              std::ios_base::openmode __mode = std::ios_base::in)
    {
        if (! _M_filebuf.open(__s, __mode | std::ios_base::in))
            this->setstate(std::ios_base::failbit);
    }

    void close()
    {
        if (! _M_filebuf.close())
            this->setstate(std::ios_base::failbit);
    }
};

  template<typename _CharT, typename _Traits>
  class stdio_ofstream : public std::basic_ostream<_CharT, _Traits>
  {
  public:
    // Types:
    typedef _CharT char_type;
    typedef _Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    typedef stdio_filebuf<char_type, traits_type> __filebuf_type;
    typedef std::basic_ostream<char_type, traits_type> __ostream_type;

  private:
     __filebuf_type     _M_filebuf;

  public:
    // Default ctor deferred initialization
    stdio_ofstream()
    : __ostream_type(NULL), _M_filebuf()
    { this->init(&_M_filebuf); }

    // Standard ctor
    stdio_ofstream(const char* __s, 
                   std::ios_base::openmode __mode = std::ios_base::out)
    : __ostream_type(NULL), _M_filebuf()
    {
        this->init(&_M_filebuf);
        this->open(__s,__mode);
    }

    // ctor that takes a C FILE*
    stdio_ofstream(std::__c_file* __f)
    : __ostream_type(NULL), _M_filebuf(__f, std::ios_base::out)
    { this->init(&_M_filebuf); }

    // ctor that takes a file descriptor
    stdio_ofstream(int __fd)
    : __ostream_type(NULL), _M_filebuf(__fd, std::ios_base::out)
    { this->init(&_M_filebuf); }
    

    ~stdio_ofstream() {}

    stdio_filebuf<char_type>* rdbuf() const
    { return const_cast<stdio_filebuf<char_type>*>(&_M_filebuf); }

    int fd() {return _M_filebuf.fd();}

    bool is_open() {return _M_filebuf.is_open();}
    
    void open(const char* __s, 
              std::ios_base::openmode __mode = std::ios_base::out)
    {
        if (! _M_filebuf.open(__s, __mode | std::ios_base::out))
            this->setstate(std::ios_base::failbit);
    }

    void close()
    {
        if (! _M_filebuf.close())
            this->setstate(std::ios_base::failbit);
    }
};

  template<typename _CharT, typename _Traits>
  class stdio_fstream : public std::basic_iostream<_CharT, _Traits>
  {
  public:
    // Types:
    typedef _CharT char_type;
    typedef _Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;

    typedef stdio_filebuf<char_type, traits_type> __filebuf_type;
    typedef std::basic_iostream<char_type, traits_type> __iostream_type;

  private:
      __filebuf_type    _M_filebuf;

  public:
    // Default ctor deferred initialization
    stdio_fstream() : __iostream_type(NULL), _M_filebuf()
    { this->init(&_M_filebuf); }

    // Standard ctor
    stdio_fstream(const char* __s, 
         std::ios_base::openmode __mode =
std::ios_base::in|std::ios_base::out)
    : __iostream_type(NULL), _M_filebuf()
    {
        this->init(&_M_filebuf);
        this->open(__s, __mode);
    }

    // ctor that takes a C FILE*
    stdio_fstream(std::__c_file* __f)
    : __iostream_type(NULL), 
      _M_filebuf(__f, std::ios_base::in|std::ios_base::out)
    { this->init(&_M_filebuf); }

    // ctor that takes a file descriptor
    stdio_fstream(int __fd)
    : __iostream_type(NULL), 
      _M_filebuf(__fd, std::ios_base::in|std::ios_base::out) 
    { this->init(&_M_filebuf);}
    

    ~stdio_fstream() {}

    stdio_filebuf<char_type>* rdbuf() const
    { return const_cast<stdio_filebuf<char_type>*>(&_M_filebuf); }


    int fd() { return _M_filebuf.fd(); }

    bool is_open() { return _M_filebuf.is_open(); }
    
    void open(const char* __s, 
         std::ios_base::openmode __mode =
std::ios_base::in|std::ios_base::out)
    {
        if (! _M_filebuf.open(__s, __mode))
            this->setstate(std::ios_base::failbit);
    }

    void close()
    {
        if (! _M_filebuf.close())
            this->setstate(std::ios_base::failbit);
    }
  };
}  // namespace __gnu_cxx

#endif


file stdio_filebuf.h the only change here was the addition of the
default ctor

// File descriptor layer for filebuf -*- C++ -*-

// Copyright (C) 2002, 2003 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
along
// with this library; see the file COPYING.  If not, write to the Free
// Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307,
// USA.

// As a special exception, you may use this file as part of a free
software
// library without restriction.  Specifically, if other files
instantiate
// templates or use macros or inline functions from this file, or you
compile
// this file and link it with other files to produce an executable, this
// file does not by itself cause the resulting executable to be covered
by
// the GNU General Public License.  This exception does not however
// invalidate any other reasons why the executable file might be covered
by
// the GNU General Public License.

/** @file ext/stdio_filebuf.h
 *  This file is a GNU extension to the Standard C++ Library.
 */

#ifndef _STDIO_FILEBUF_H
#define _STDIO_FILEBUF_H 1

#pragma GCC system_header

#include <fstream>

namespace __gnu_cxx
{
  /**
   *  @class stdio_filebuf ext/stdio_filebuf.h <ext/stdio_filebuf.h>
   *  @brief Provides a layer of compatibility for C/POSIX.
   *
   *  This GNU extension provides extensions for working with standard C
   *  FILE*'s and POSIX file descriptors.  It must be instantiated by
the
   *  user with the type of character used in the file stream, e.g.,
   *  stdio_filebuf<char>.
  */
  template<typename _CharT, typename _Traits = std::char_traits<_CharT>
>
    class stdio_filebuf : public std::basic_filebuf<_CharT, _Traits>
    {
    public:
      // Types:
      typedef _CharT                                    char_type;
      typedef _Traits                                   traits_type;
      typedef typename traits_type::int_type            int_type;
      typedef typename traits_type::pos_type            pos_type;
      typedef typename traits_type::off_type            off_type;
      typedef std::size_t                               size_t;

    public:
      /**
       * deferred initialization
      */
      stdio_filebuf() : std::basic_filebuf<_CharT, _Traits>() {}

      /**
       *  @param  fd  An open file descriptor.
       *  @param  mode  Same meaning as in a standard filebuf.
       *  @param  size  Optimal or preferred size of internal buffer, in
chars.
       *
       *  This constructor associates a file stream buffer with an open
       *  POSIX file descriptor.
      */
      stdio_filebuf(int __fd, std::ios_base::openmode __mode,
                    size_t __size = static_cast<size_t>(BUFSIZ));

      /**
       *  @param  f  An open @c FILE*.
       *  @param  mode  Same meaning as in a standard filebuf.
       *  @param  size  Optimal or preferred size of internal buffer, in
chars.
       *                Defaults to system's @c BUFSIZ.
       *
       *  This constructor associates a file stream buffer with an open
       *  C @c FILE*.  The @c FILE* will not be automatically closed
when the
       *  stdio_filebuf is closed/destroyed.
      */
      stdio_filebuf(std::__c_file* __f, std::ios_base::openmode __mode,
                    size_t __size = static_cast<size_t>(BUFSIZ));

      /**
       *  Possibly closes the external data stream, in the case of the
file
       *  descriptor constructor and @c del @c == @c true.
      */
      virtual
      ~stdio_filebuf();

      /**
       *  @return  The underlying file descriptor.
       *
       *  Once associated with an external data stream, this function
can be
       *  used to access the underlying POSIX file descriptor.  Note
that
       *  there is no way for the library to track what you do with the
       *  descriptor, so be careful.
      */
      int
      fd()
      { return this->_M_file.fd(); }
    };

  template<typename _CharT, typename _Traits>
    stdio_filebuf<_CharT, _Traits>::~stdio_filebuf()
    { }

  template<typename _CharT, typename _Traits>
    stdio_filebuf<_CharT, _Traits>::
    stdio_filebuf(int __fd, std::ios_base::openmode __mode, size_t
__size)
    {
      this->_M_file.sys_open(__fd, __mode);
      if (this->is_open())
        {
          this->_M_mode = __mode;
          this->_M_buf_size = __size;
          this->_M_allocate_internal_buffer();
          this->_M_reading = false;
          this->_M_writing = false;
          this->_M_set_buffer(-1);
        }
    }

  template<typename _CharT, typename _Traits>
    stdio_filebuf<_CharT, _Traits>::
    stdio_filebuf(std::__c_file* __f, std::ios_base::openmode __mode,
                  size_t __size)
    {
      this->_M_file.sys_open(__f, __mode);
      if (this->is_open())
        {
          this->_M_mode = __mode;
          this->_M_buf_size = __size;
          this->_M_allocate_internal_buffer();
          this->_M_reading = false;
          this->_M_writing = false;
          this->_M_set_buffer(-1);
        }
    }
} // namespace __gnu_cxx

#endif

test case; file extFstreamTest.cc

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#include <iostream>

#include <ext/stdio_fstream.h>

using namespace std;
using namespace __gnu_cxx;

// Test case for the non standard file stream implementation

int main()
{
    int success = 1;

    stdio_ofstream<char, std::char_traits<char> >* testOfStream = NULL;
    stdio_ifstream<char, std::char_traits<char> >* testIfStream = NULL;
    stdio_fstream<char, std::char_traits<char> >* testFStream = NULL;

    // Test 1: 
    // create a file and use the fd to create an ofstream
    // write to the file
    int fd = creat("test1.txt", O_CREAT|S_IRUSR|S_IWUSR);
    testOfStream = new stdio_ofstream<char, std::char_traits<char>
>(fd);
    *testOfStream << "Hello_world_1" << endl;
    testOfStream->close();
    testOfStream = NULL;

    // Test 2:
    // open an existing file and read the contents
    fd = open("test1.txt", O_RDONLY);
    testIfStream = new stdio_ifstream<char, std::char_traits<char>
>(fd);
    char buf[14];
    *testIfStream >> buf;
    if (! strncmp("Hello_world_1", buf, 13))
    {
        cerr << "SUCCESS:\tTest 1\t\t" << buf << endl;
        cerr << "SUCCESS:\tTest 2\t\t" << buf << endl;
    }
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test1.txt (Test 2)" << endl;
    }

    // Test 3:
    // open an existing file by name and write to it
    testOfStream = new stdio_ofstream<char, std::char_traits<char> >
        ("test1.txt");
    if (testOfStream->fail())
    {
        success = 0;
        cerr << "FAIL:\tCould not open test1.txt for writing (Test 3)"
<< endl;
    }
    else
        cerr << "SUCCESS:\tTest 3" << endl;

    *testOfStream << "Hello_world_2" << endl;
    testOfStream->close();
    testOfStream = NULL;

    // Test 4:
    // open an existing file by name and read from it
    testIfStream = new stdio_ifstream<char, std::char_traits<char> >
        ("test1.txt");
    if (testIfStream->fail())
    {
        success = 0;
        cerr << "FAIL:\tCould not open test1.txt for reading (Test 4)"
<< endl;
    }
    else
        cerr << "SUCCESS:\tTest 4 part a" << endl;

    *testIfStream >> buf;
    if (! strncmp("Hello_world_2", buf, 13))
        cerr << "SUCCESS:\tTest 4 part b\t" << buf << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test1.txt (Test 4)" << endl;
    }    

    // Test 5:
    // try to open a non existing file for writing
    testOfStream = new stdio_ofstream<char, std::char_traits<char> >
        ("test2.txt");
    if (testOfStream->fail())
    {
        success = 0;
        cerr << "FAIL:\tCould not open test2.txt for writing (Test 5)"
<< endl;
    }
    else
         cerr << "SUCCESS:\tTest 5" << endl;

    *testOfStream << "Hello_world_3" << endl;
    testOfStream->close();
    testOfStream = NULL;

    // Test 6:
    // try to open a non existing file for reading
    testIfStream = new stdio_ifstream<char, std::char_traits<char> >
        ("test2.txt");
    if (testIfStream->fail())
    {
        success = 0;
        cerr << "FAIL:\tCould not open test2.txt for reading (Test 6)"
<< endl;
    }
    else
        cerr << "SUCCESS:\tTest 6 part a" << endl;

    *testIfStream >> buf;
    if (! strncmp("Hello_world_3", buf, 13))
        cerr << "SUCCESS:\tTest 6 part b\t" << buf << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test1.txt (Test 4)" << endl;
    }
        
    testIfStream = NULL;

    // Test 7:
    // open an ofstream with a FILE*
    FILE* moFile = fopen("test1.txt", "w");
    testOfStream = new stdio_ofstream<char, std::char_traits<char>
>(moFile);
    *testOfStream << "Hello_world_4" << endl;
    testOfStream->close();
    testOfStream = NULL;

    // Test 8:
    // open an ifstream with FILE*
    FILE* miFile = fopen("test1.txt","r");
    testIfStream = new stdio_ifstream<char, std::char_traits<char>
>(miFile);
    *testIfStream >> buf;
    if (! strncmp("Hello_world_4", buf, 13))
        cerr << "SUCCESS:\tTest 8\t\t" << buf << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test1.txt (Test 8)" << endl;
    }
    
    // Test 9:
    // open an fstream for a non existent file 
    // (the file should not get created)
    testFStream = new stdio_fstream<char, std::char_traits<char> >
        ("test3.txt");
    if (testFStream->fail())
        cerr << "SUCCESS:\tTest 9" << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tWas able to open non existent file with fstream"
             << endl;
    }
    testFStream = NULL;

    // Test 10:
    // create a file and use the fd to create an fstream
    // write to the file
    // read from the file
    fd = creat("test3.txt", 
               O_CREAT|O_NONBLOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
    testFStream = new stdio_fstream<char, std::char_traits<char> >(fd);
    *testFStream << "Hello_world_5" << endl;
    testFStream->seekg(0);
    *testFStream >> buf;
    if (! strncmp("Hello_world_5", buf, 13))
        cerr << "SUCCESS:\tTest 10\t\t" << buf << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test3.txt (Test 10)" << endl;
    }
    testFStream->close();
    testFStream = NULL;

    // Test 11:
    // open and existing file by name
    // write to the file and read the data back in
    testFStream = new stdio_fstream<char, std::char_traits<char> >
        ("test3.txt");
    if (testFStream->fail())
    {
        success = 0;
        cerr << "FAIL:\tWas unable to open existing file test3.txt "
             << "with fstream" << endl;
    }
    else
        cerr << "SUCCESS:\tTest 11 part a" << endl;
    *testFStream << "Hello_world_6" << endl;
    testFStream->seekg(0);
    *testFStream >> buf;
    if (! strncmp("Hello_world_6", buf, 13))
        cerr << "SUCCESS:\tTest 11 part b\t" << buf << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test3.txt (Test 11)" << endl;
    }
    testFStream->close();
    testFStream = NULL;

    // Test 12:
    // open fstream with FILE*
    // write to the file and read the data back in
    FILE* mfile = fopen("test3.txt", "r+");
    testFStream = new stdio_fstream<char, std::char_traits<char>
>(mfile);
    *testFStream << "Hello_world_7" << endl;
    testFStream->seekg(0);
    *testFStream >> buf;
    if (! strncmp("Hello_world_7", buf, 13))
        cerr << "SUCCESS:\tTest 12\t\t" << buf << endl;
    else
    {
        success = 0;
        cerr << "FAIL:\tCould not read test3.txt (Test 12)" << endl;
    }
    testFStream->close();
    testFStream = NULL;

    // Clean up
    unlink ("test1.txt");
    unlink ("test2.txt");
    unlink ("test3.txt");

    return success;
}

-- 
Robert Schweikert                   MAY THE SOURCE BE WITH YOU
rjschwei@cox.net                               LINUX



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]