/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Robin J. Maxwell 11-22-96 */ #include "prstrms.h" #include // memmove // // Definition of macros _PRSTR_BP, _PRSTR_DELBUF, and _PRSTR_DELBUF_C. // // _PRSTR_BP is the protected member of class ios that is returned // by the public method rdbuf(). // // _PRSTR_DELBUF is the method or data member of class ios, if available, // with which we can ensure that the ios destructor does not delete // the associated streambuf. If such a method or data member does not // exist, define _PRSTR_DELBUF to be empty. // // _PRSTR_DELBUF_C is just _PRSTR_DELBUF qualified by a base class. // #if defined(__GNUC__) #define _PRSTR_BP _strbuf #define _PRSTR_DELBUF(x) /* as nothing */ #define _PRSTR_DELBUF_C(c, x) /* as nothing */ #elif defined(WIN32) #define _PRSTR_BP bp #define _PRSTR_DELBUF(x) delbuf(x) #define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x) #elif defined(VMS) #undef _PRSTR_BP #define _PRSTR_DELBUF(x) /* as nothing */ #define _PRSTR_DELBUF_C(c, x) /* as nothing */ #elif defined(OSF1) #define _PRSTR_BP m_psb #define _PRSTR_DELBUF(x) /* as nothing */ #define _PRSTR_DELBUF_C(c, x) /* as nothing */ #elif defined(QNX) #define PRFSTREAMS_BROKEN #else #define _PRSTR_BP bp // Unix compilers don't believe in encapsulation // At least on Solaris this is also ignored #define _PRSTR_DELBUF(x) delbuf = x #define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x) #endif const PRIntn STRM_BUFSIZ = 8192; #if !defined (PRFSTREAMS_BROKEN) PRfilebuf::PRfilebuf(): _fd(0), _opened(PR_FALSE), _allocated(PR_FALSE) { } PRfilebuf::PRfilebuf(PRFileDesc *fd): streambuf(), _fd(fd), _opened(PR_FALSE), _allocated(PR_FALSE) { } PRfilebuf::PRfilebuf(PRFileDesc *fd, char * buffptr, int bufflen): _fd(fd), _opened(PR_FALSE), _allocated(PR_FALSE) { PRfilebuf::setbuf(buffptr, bufflen); } PRfilebuf::~PRfilebuf() { if (_opened){ close(); }else sync(); if (_allocated) delete base(); } PRfilebuf* PRfilebuf::open(const char *name, int mode, int flags) { if (_fd != 0) return 0; // error if already open PRIntn PRmode = 0; // translate mode argument if (!(mode & ios::nocreate)) PRmode |= PR_CREATE_FILE; //if (mode & ios::noreplace) // PRmode |= O_EXCL; if (mode & ios::app){ mode |= ios::out; PRmode |= PR_APPEND; } if (mode & ios::trunc){ mode |= ios::out; // IMPLIED PRmode |= PR_TRUNCATE; } if (mode & ios::out){ if (mode & ios::in) PRmode |= PR_RDWR; else PRmode |= PR_WRONLY; if (!(mode & (ios::in|ios::app|ios::ate|ios::noreplace))){ mode |= ios::trunc; // IMPLIED PRmode |= PR_TRUNCATE; } }else if (mode & ios::in) PRmode |= PR_RDONLY; else return 0; // error if not ios:in or ios::out // // The usual portable across unix crap... // NT gets a hokey piece of junk layer that prevents // access to the API. #ifdef WIN32 _fd = PR_Open(name, PRmode, PRmode); #else _fd = PR_Open(name, PRmode, flags); #endif if (_fd == 0) return 0; _opened = PR_TRUE; if ((!unbuffered()) && (!ebuf())){ char * sbuf = new char[STRM_BUFSIZ]; if (!sbuf) unbuffered(1); else{ _allocated = PR_TRUE; streambuf::setb(sbuf,sbuf+STRM_BUFSIZ,0); } } if (mode & ios::ate){ if (seekoff(0,ios::end,mode)==EOF){ close(); return 0; } } return this; } PRfilebuf* PRfilebuf::attach(PRFileDesc *fd) { _opened = PR_FALSE; _fd = fd; return this; } int PRfilebuf::overflow(int c) { if (allocate()==EOF) // make sure there is a reserve area return EOF; if (PRfilebuf::sync()==EOF) // sync before new buffer created below return EOF; if (!unbuffered()) setp(base(),ebuf()); if (c!=EOF){ if ((!unbuffered()) && (pptr() < epptr())) // guard against recursion sputc(c); else{ if (PR_Write(_fd, &c, 1)!=1) return(EOF); } } return(1); // return something other than EOF if successful } int PRfilebuf::underflow() { int count; unsigned char tbuf; if (in_avail()) return (int)(unsigned char) *gptr(); if (allocate()==EOF) // make sure there is a reserve area return EOF; if (PRfilebuf::sync()==EOF) return EOF; if (unbuffered()) { if (PR_Read(_fd,(void *)&tbuf,1)<=0) return EOF; return (int)tbuf; } if ((count=PR_Read(_fd,(void *)base(),blen())) <= 0) return EOF; // reached EOF setg(base(),base(),base()+count); return (int)(unsigned char) *gptr(); } streambuf* PRfilebuf::setbuf(char *buffptr, PRstreambuflen bufflen) { if (is_open() && (ebuf())) return 0; if ((!buffptr) || (bufflen <= 0)) unbuffered(1); else setb(buffptr, buffptr+bufflen, 0); return this; } streampos PRfilebuf::seekoff(streamoff offset, ios::seek_dir dir, int /* mode */) { if (PR_GetDescType(_fd) == PR_DESC_FILE){ PRSeekWhence fdir; PRInt32 retpos; switch (dir) { case ios::beg : fdir = PR_SEEK_SET; break; case ios::cur : fdir = PR_SEEK_CUR; break; case ios::end : fdir = PR_SEEK_END; break; default: // error return(EOF); } if (PRfilebuf::sync()==EOF) return EOF; if ((retpos=PR_Seek(_fd, offset, fdir))==-1L) return (EOF); return((streampos)retpos); }else return (EOF); } int PRfilebuf::sync() { PRInt32 count; if (_fd==0) return(EOF); if (!unbuffered()){ // Sync write area if ((count=out_waiting())!=0){ PRInt32 nout; if ((nout =PR_Write(_fd, (void *) pbase(), (unsigned int)count)) != count){ if (nout > 0) { // should set _pptr -= nout pbump(-(int)nout); memmove(pbase(), pbase()+nout, (int)(count-nout)); } return(EOF); } } setp(0,0); // empty put area if (PR_GetDescType(_fd) == PR_DESC_FILE){ // Sockets can't seek; don't need this if ((count=in_avail()) > 0){ if (PR_Seek(_fd, -count, PR_SEEK_CUR)!=-1L) { return (EOF); } } } setg(0,0,0); // empty get area } return(0); } PRfilebuf * PRfilebuf::close() { int retval; if (_fd==0) return 0; retval = sync(); if ((PR_Close(_fd)==0) || (retval==EOF)) return 0; _fd = 0; return this; } PRifstream::PRifstream(): istream(new PRfilebuf) { _PRSTR_DELBUF(0); } PRifstream::PRifstream(PRFileDesc *fd): istream(new PRfilebuf(fd)) { _PRSTR_DELBUF(0); } PRifstream::PRifstream(PRFileDesc *fd, char *buff, int bufflen): istream(new PRfilebuf(fd, buff, bufflen)) { _PRSTR_DELBUF(0); } PRifstream::PRifstream(const char * name, int mode, int flags): istream(new PRfilebuf) { _PRSTR_DELBUF(0); if (!rdbuf()->open(name, (mode|ios::in), flags)) clear(rdstate() | ios::failbit); } PRifstream::~PRifstream() { sync(); delete rdbuf(); #ifdef _PRSTR_BP _PRSTR_BP = 0; #endif } streambuf * PRifstream::setbuf(char * ptr, int len) { if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ clear(rdstate() | ios::failbit); return 0; } return rdbuf(); } void PRifstream::attach(PRFileDesc *fd) { if (!(rdbuf()->attach(fd))) clear(rdstate() | ios::failbit); } void PRifstream::open(const char * name, int mode, int flags) { if (is_open() || !(rdbuf()->open(name, (mode|ios::in), flags))) clear(rdstate() | ios::failbit); } void PRifstream::close() { clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); } PRofstream::PRofstream(): ostream(new PRfilebuf) { _PRSTR_DELBUF(0); } PRofstream::PRofstream(PRFileDesc *fd): ostream(new PRfilebuf(fd)) { _PRSTR_DELBUF(0); } PRofstream::PRofstream(PRFileDesc *fd, char *buff, int bufflen): ostream(new PRfilebuf(fd, buff, bufflen)) { _PRSTR_DELBUF(0); } PRofstream::PRofstream(const char *name, int mode, int flags): ostream(new PRfilebuf) { _PRSTR_DELBUF(0); if (!rdbuf()->open(name, (mode|ios::out), flags)) clear(rdstate() | ios::failbit); } PRofstream::~PRofstream() { flush(); delete rdbuf(); #ifdef _PRSTR_BP _PRSTR_BP = 0; #endif } streambuf * PRofstream::setbuf(char * ptr, int len) { if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ clear(rdstate() | ios::failbit); return 0; } return rdbuf(); } void PRofstream::attach(PRFileDesc *fd) { if (!(rdbuf()->attach(fd))) clear(rdstate() | ios::failbit); } void PRofstream::open(const char * name, int mode, int flags) { if (is_open() || !(rdbuf()->open(name, (mode|ios::out), flags))) clear(rdstate() | ios::failbit); } void PRofstream::close() { clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); } PRfstream::PRfstream(): iostream(new PRfilebuf) { _PRSTR_DELBUF_C(istream, 0); _PRSTR_DELBUF_C(ostream, 0); } PRfstream::PRfstream(PRFileDesc *fd): iostream(new PRfilebuf(fd)) { _PRSTR_DELBUF_C(istream, 0); _PRSTR_DELBUF_C(ostream, 0); } PRfstream::PRfstream(PRFileDesc *fd, char *buff, int bufflen): iostream(new PRfilebuf(fd, buff, bufflen)) { _PRSTR_DELBUF_C(istream, 0); _PRSTR_DELBUF_C(ostream, 0); } PRfstream::PRfstream(const char *name, int mode, int flags): iostream(new PRfilebuf) { _PRSTR_DELBUF_C(istream, 0); _PRSTR_DELBUF_C(ostream, 0); if (!rdbuf()->open(name, (mode|(ios::in|ios::out)), flags)) clear(rdstate() | ios::failbit); } PRfstream::~PRfstream() { sync(); flush(); delete rdbuf(); #ifdef _PRSTR_BP istream::_PRSTR_BP = 0; ostream::_PRSTR_BP = 0; #endif } streambuf * PRfstream::setbuf(char * ptr, int len) { if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){ clear(rdstate() | ios::failbit); return 0; } return rdbuf(); } void PRfstream::attach(PRFileDesc *fd) { if (!(rdbuf()->attach(fd))) clear(rdstate() | ios::failbit); } void PRfstream::open(const char * name, int mode, int flags) { if (is_open() || !(rdbuf()->open(name, (mode|(ios::in|ios::out)), flags))) clear(rdstate() | ios::failbit); } void PRfstream::close() { clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit)); } #else // fix it sometime int fix_prfstreams () { return 0; } #endif