/* Copyright (C) 2004 Garrett A. Kajmowicz This file is part of the uClibc++ Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __STD_HEADER_FSTREAM #define __STD_HEADER_FSTREAM 1 #include #include #include #include #include #include #include #include #include #include #ifdef __UCLIBCXX_HAS_WCHAR__ #include #include #endif //__UCLIBCXX_HAS_WCHAR__ namespace std{ template class basic_filebuf; typedef basic_filebuf filebuf; #ifdef __UCLIBCXX_HAS_WCHAR__ typedef basic_filebuf wfilebuf; #endif template class _UCXXEXPORT basic_filebuf : public basic_streambuf { #ifdef __UCLIBCXX_SUPPORT_CDIR__ friend ios_base::Init::Init(); //Needed for cout/cin stuff #endif public: // Types (inherited from basic_streambuf: typedef typename basic_streambuf::char_type char_type; typedef typename basic_streambuf::int_type int_type; typedef typename basic_streambuf::pos_type pos_type; typedef typename basic_streambuf::off_type off_type; typedef traits traits_type; //Constructors/destructor: _UCXXEXPORT basic_filebuf() : basic_streambuf(), fp(0), pbuffer(0), gbuffer(0) { append=false; pbuffer = new char_type[__UCLIBCXX_IOSTREAM_BUFSIZE__]; gbuffer = new char_type[__UCLIBCXX_IOSTREAM_BUFSIZE__]; setp(pbuffer, pbuffer + __UCLIBCXX_IOSTREAM_BUFSIZE__); //Position get buffer so that there is no data available setg(gbuffer, gbuffer + __UCLIBCXX_IOSTREAM_BUFSIZE__, gbuffer + __UCLIBCXX_IOSTREAM_BUFSIZE__); } _UCXXEXPORT virtual ~basic_filebuf(){ sync(); close(); delete [] pbuffer; delete [] gbuffer; pbuffer = 0; gbuffer = 0; } //Members: _UCXXEXPORT bool is_open() const{ if(fp == 0){ return false; } return true; } _UCXXEXPORT basic_filebuf* open(const char* s, ios_base::openmode mode){ bool move_end = (mode & ios_base::ate) != 0; if(is_open() !=false){ //Must call close() first return 0; } basic_streambuf::openedFor = mode; mode = mode & ~ios_base::ate; if(mode == ios_base::out || mode == (ios_base::out | ios_base::trunc)){ fp = fopen(s, "w" ); }else if((mode & ios_base::app) && ! (mode & ios_base::trunc)){ if(mode & ios_base::binary){ if(mode & ios_base::in){ fp = fopen(s, "a+b"); }else{ fp = fopen(s, "ab"); } }else{ if(mode & ios_base::in){ fp = fopen(s, "a+"); }else{ fp = fopen(s, "a"); } } }else if(mode == ios_base::in){ fp = fopen(s, "r"); }else if(mode == (ios_base::in | ios_base::out)){ fp = fopen(s, "r+"); }else if(mode == (ios_base::in | ios_base::out | ios_base::trunc)){ fp = fopen(s, "w+"); }else if(mode == (ios_base::binary | ios_base::out)){ fp = fopen(s, "wb"); }else if(mode == (ios_base::in | ios_base::binary)){ fp = fopen(s, "rb"); }else if(mode == (ios_base::in | ios_base::binary | ios_base::out)){ fp = fopen(s, "r+b"); }else if(mode==(ios_base::binary | ios_base::out | ios_base::trunc)){ fp = fopen(s, "w+b"); }else if(mode == (ios_base::in | ios_base::binary | ios_base::out | ios_base::trunc)){ fp = fopen(s, "w+b"); } if(fp == 0){ return 0; } if(ferror(fp)){ fclose(fp); fp=0; return 0; } int retval = 0; //Check to make sure the stream is good if(move_end == true){ retval = fseek(fp, 0, SEEK_END); }else{ retval = fseek(fp, 0, SEEK_SET); } if(retval!=0){ //Seek error fclose(fp); fp=0; return 0; } basic_streambuf::mgnext = basic_streambuf::mgend; return this; } _UCXXEXPORT basic_filebuf* close(){ if(fp != 0 && fp != stdin && fp != stdout && fp !=stderr ){ overflow(); sync(); int retval = fclose(fp); if(retval !=0){ //Error of some sort return 0; } fp=0; } return this; } protected: _UCXXEXPORT basic_filebuf(const basic_filebuf &){ } _UCXXEXPORT basic_filebuf & operator=(const basic_filebuf &){ return *this; } //Overridden virtual functions: virtual _UCXXEXPORT int showmanyc(){ return basic_streambuf::egptr() - basic_streambuf::gptr(); } virtual _UCXXEXPORT int_type underflow(){ /* Some variables used internally: Buffer pointers: charT * mgbeg; charT * mgnext; charT * mgend; eback() returns mgbeg gptr() returns mgnext egptr() returns mgend gbump(int n) mgnext+=n */ if(basic_streambuf::eback() == 0){ //No buffer, so... charT c; int retval; retval = fread(&c, sizeof(charT), 1, fp); if(retval == 0 || feof(fp) || ferror(fp) ){ return traits::eof(); } return traits::to_int_type(c); } if(basic_streambuf::eback() == basic_streambuf::gptr()){ //Buffer is full return traits::to_int_type(*basic_streambuf::gptr()); } //Shift entire buffer back to the begining size_t offset = basic_streambuf::gptr() - basic_streambuf::eback(); size_t amountData = basic_streambuf::egptr() - basic_streambuf::gptr(); for(charT * i = basic_streambuf::gptr(); i < basic_streambuf::egptr(); ++i){ *(i-offset) = *i; } size_t retval = 0; //Save operating flags from file descriptor int fcntl_flags = fcntl(fileno(fp), F_GETFL); retval = 0; //Set to non_blocking mode fcntl(fileno(fp), F_SETFL, fcntl_flags | O_NONBLOCK); //Fill rest of buffer retval = fread(basic_streambuf::egptr() - basic_streambuf::gptr() + basic_streambuf::eback(), sizeof(charT), offset, fp ); //Clear problems where we didn't read in enough characters if(EAGAIN == errno){ clearerr(fp); } //Restore file descriptor clase fcntl(fileno(fp), F_SETFL, fcntl_flags); //Now we are going to make sure that we read in at least one character. The hard way. if(retval == 0){ fcntl_flags = fcntl(fileno(fp), F_GETFL); //Set to blocking mode fcntl(fileno(fp), F_SETFL, fcntl_flags & ~O_NONBLOCK); retval = fread(basic_streambuf::egptr() - basic_streambuf::gptr() + basic_streambuf::eback(), sizeof(charT), 1, fp ); //Restore file descriptor clase fcntl(fileno(fp), F_SETFL, fcntl_flags); } if(retval !=offset){ //Slide buffer forward again for(size_t i = 0; i < amountData + retval; ++i){ *(basic_streambuf::egptr() - i - 1) = *(basic_streambuf::eback() + amountData + retval - i - 1); } } basic_streambuf::mgnext -= retval; if( (retval <= 0 && feof(fp)) || ferror(fp) ){ return traits::eof(); } return traits::to_int_type(*basic_streambuf::gptr()); } virtual _UCXXEXPORT int_type uflow(){ bool dobump = (basic_streambuf::gptr() != 0); int_type retval = underflow(); if(dobump){ basic_streambuf::gbump(1); } return retval; } virtual _UCXXEXPORT int_type pbackfail(int_type c = traits::eof()){ if(is_open() == false || basic_streambuf::gptr() == basic_streambuf::eback()) { return traits::eof(); } if(traits::eq_int_type(c,traits::eof()) == false){ if(traits::eq(traits::to_char_type(c), basic_streambuf::gptr()[-1]) == true){ basic_streambuf::gbump(-1); }else{ basic_streambuf::gbump(-1); basic_streambuf::gptr()[0] = c; } return c; }else{ basic_streambuf::gbump(-1); return traits::not_eof(c); } } virtual _UCXXEXPORT int_type overflow(int_type c = traits::eof()){ if(is_open() == false){ //Can't do much return traits::eof(); } if(basic_streambuf::pbase() == 0){ //Unbuffered - elliminate dupe code below if(fputc(c, fp) == EOF){ return traits::eof(); } return c; } if(basic_streambuf::pbase() == 0 && traits::eq_int_type(c,traits::eof()) ){ //Nothing to flush return traits::not_eof(c); } size_t r = basic_streambuf::pptr() - basic_streambuf::pbase(); if( r == 0 && traits::eq_int_type(c,traits::eof()) ){ return traits::not_eof(c); }else if (r == 0 ){ if(fputc(c, fp) == EOF){ return traits::eof(); } return c; } size_t totalChars = r; char_type *buffer = 0; if(traits::eq_int_type(c,traits::eof())){ buffer = new char_type[r]; }else{ buffer = new char_type[r+1]; buffer[r] = c; totalChars++; } traits::copy(buffer, basic_streambuf::pbase(), r); // memcpy(buffer, basic_streambuf::pbase(), r); size_t retval = fwrite(buffer, sizeof(charT), totalChars, fp); if(retval !=totalChars){ if(retval == 0){ delete [] buffer; return traits::eof(); } basic_streambuf::pbump(-retval); fprintf(stderr, "***** Did not write the full buffer out. Should be: %d, actually: %d\n", totalChars, retval); }else{ basic_streambuf::pbump(-r); } delete [] buffer; return traits::not_eof(c); } virtual _UCXXEXPORT basic_streambuf* setbuf(char_type* s, streamsize n){ if(s == 0 && n == 0){ //Unbuffered if(pbuffer !=0){ delete [] pbuffer; } if(gbuffer !=0){ delete [] gbuffer; } pbuffer = 0; gbuffer = 0; }else if(basic_streambuf::gptr() !=0 && basic_streambuf::gptr()==basic_streambuf::egptr()) { delete [] pbuffer; pbuffer = s; } return this; } virtual _UCXXEXPORT pos_type seekoff(off_type off, ios_base::seekdir way, ios_base::openmode = ios_base::in | ios_base::out) { if(is_open() == false){ return -1; } int whence = SEEK_SET; // if(way == basic_ios::beg) off_type position = off; if(way == basic_ios::cur){ whence = SEEK_CUR; position -= (basic_streambuf::egptr() - basic_streambuf::gptr()); }else if(way == basic_ios::end){ whence = SEEK_END; } sync(); int retval = fseek( fp, sizeof(charT)*(position), whence ); //Invalidate read buffer basic_streambuf::gbump( basic_streambuf::egptr() - basic_streambuf::gptr() ); if(-1 != retval){ retval = ftell(fp); } return retval; } virtual _UCXXEXPORT pos_type seekpos(pos_type sp, ios_base::openmode = ios_base::in | ios_base::out){ if(is_open() == false){ return -1; } sync(); int retval = fseek(fp,sizeof(charT)* sp, SEEK_SET); //Invalidate read buffer basic_streambuf::gbump(basic_streambuf::egptr() - basic_streambuf::gptr()); if(retval > -1){ return sp; } return -1; } virtual _UCXXEXPORT int sync(){ if(pbuffer !=0){ if(overflow() == traits::eof()){ return -1; } } if(0 != fp && 0 != fflush(fp)){ return -1; } return 0; } virtual _UCXXEXPORT void imbue(const locale&){ return; } virtual _UCXXEXPORT streamsize xsputn(const char_type* s, streamsize n){ if(is_open() == false){ return 0; } //Check to see if buffered //Check to see if we can buffer the data streamsize buffer_avail = basic_streambuf::epptr() - basic_streambuf::pptr(); if(n > buffer_avail){ //Flush buffer and write directly overflow(); //Flush the buffer return fwrite(s, sizeof(charT), n, fp); } //Add to buffer to be written later traits::copy(basic_streambuf::pptr(), s, n); basic_streambuf::pbump(n); return n; } FILE * fp; char_type * pbuffer; char_type * gbuffer; bool append; }; #ifdef __UCLIBCXX_HAS_WCHAR__ template <> _UCXXEXPORT basic_filebuf >::int_type basic_filebuf >::overflow(int_type c); template <> _UCXXEXPORT basic_filebuf >::int_type basic_filebuf >::underflow(); #endif //__UCLIBCXX_HAS_WCHAR__ #ifdef __UCLIBCXX_EXPAND_FSTREAM_CHAR__ #ifndef __UCLIBCXX_COMPILE_FSTREAM__ #ifdef __UCLIBCXX_EXPAND_CONSTRUCTORS_DESTRUCTORS__ template <> _UCXXEXPORT filebuf::basic_filebuf(); template <> _UCXXEXPORT filebuf::~basic_filebuf(); #endif // __UCLIBCXX_EXPAND_CONSTRUCTORS_DESTRUCTORS__ template <> _UCXXEXPORT filebuf::int_type filebuf::pbackfail(filebuf::int_type c); template <> _UCXXEXPORT filebuf * filebuf::open(const char* s, ios_base::openmode mode); template <> _UCXXEXPORT filebuf * filebuf::close(); template <> _UCXXEXPORT filebuf::int_type filebuf::overflow(filebuf::int_type c); template <> _UCXXEXPORT filebuf::int_type filebuf::underflow (); template <> _UCXXEXPORT basic_streambuf > * filebuf::setbuf(char * s, streamsize n); template <> _UCXXEXPORT streamsize filebuf::xsputn(const char* s, streamsize n); #endif #endif template class _UCXXEXPORT basic_ifstream : public basic_istream { public: typedef charT char_type; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; _UCXXEXPORT basic_ifstream(): basic_ios(&sb), basic_istream(&sb){ //Passing the address of sb } explicit _UCXXEXPORT basic_ifstream(const char* s, ios_base::openmode mode = ios_base::in) : basic_ios(&sb), basic_istream(&sb) { if(sb.open(s, mode) == 0){ basic_ios::setstate(ios_base::failbit); } } virtual _UCXXEXPORT ~basic_ifstream(){ } _UCXXEXPORT basic_filebuf* rdbuf() const{ return (basic_filebuf*)&sb; } _UCXXEXPORT bool is_open() const{ return sb.is_open(); } _UCXXEXPORT void open(const char* s, ios_base::openmode mode = ios_base::in){ if(sb.open(s, mode) == 0){ basic_ios::setstate(ios_base::failbit); } } _UCXXEXPORT void close(){ sb.close(); } private: basic_filebuf sb; }; template class _UCXXEXPORT basic_ofstream : public basic_ostream { public: typedef charT char_type; typedef typename traits::int_type int_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; _UCXXEXPORT basic_ofstream() : basic_ios(&sb), basic_ostream(&sb){ } virtual _UCXXEXPORT ~basic_ofstream(); explicit _UCXXEXPORT basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out | ios_base::trunc) : basic_ios(&sb), basic_ostream(&sb) { if(sb.open(s, mode) == 0){ basic_ios::setstate(ios_base::failbit); } } _UCXXEXPORT basic_filebuf* rdbuf() const{ return (basic_filebuf*)&sb; } _UCXXEXPORT bool is_open() const{ return sb.is_open(); } _UCXXEXPORT void open(const char* s, ios_base::openmode mode = ios_base::out | ios_base::trunc){ if(sb.open(s, mode) == 0){ basic_ios::setstate(ios_base::failbit); } } _UCXXEXPORT void close(){ sb.close(); } private: basic_filebuf sb; }; template _UCXXEXPORT basic_ofstream::~basic_ofstream(){ } template class _UCXXEXPORT basic_fstream : public basic_iostream { public: typedef charT char_type; typedef typename traits::int_type ins_type; typedef typename traits::pos_type pos_type; typedef typename traits::off_type off_type; _UCXXEXPORT basic_fstream(): basic_ios(&sb), basic_iostream(&sb){ } explicit _UCXXEXPORT basic_fstream(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out): basic_ios(&sb), basic_iostream(&sb) { if(sb.open(s, mode) == 0){ basic_ios::setstate(ios_base::failbit); } } _UCXXEXPORT basic_filebuf* rdbuf() const{ return (basic_filebuf*)&sb; } _UCXXEXPORT bool is_open() const{ return sb.is_open(); } _UCXXEXPORT void open(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out){ if(sb.open(s, mode) == 0){ basic_ios::setstate(ios_base::failbit); } } _UCXXEXPORT void close(){ sb.close(); } private: basic_filebuf sb; }; #ifdef __UCLIBCXX_EXPAND_FSTREAM_CHAR__ #ifndef __UCLIBCXX_COMPILE_FSTREAM__ #ifdef __UCLIBCXX_EXPAND_CONSTRUCTORS_DESTRUCTORS__ template <> _UCXXEXPORT basic_ofstream >::basic_ofstream(); template <> _UCXXEXPORT basic_ofstream >::basic_ofstream(const char* s, ios_base::openmode mode); template <> _UCXXEXPORT basic_ofstream >::~basic_ofstream(); template <> _UCXXEXPORT basic_ifstream >::basic_ifstream(); template <> _UCXXEXPORT basic_ifstream >::basic_ifstream(const char* s, ios_base::openmode mode); template <> _UCXXEXPORT basic_ifstream >::~basic_ifstream(); #endif // __UCLIBCXX_EXPAND_CONSTRUCTORS_DESTRUCTORS__ #endif #endif } #endif