blob: 9f709c067ae13d409a8195f5dc1f32fae4012f42 [file] [log] [blame]
/* -*- 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 <string.h> // 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(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