nspr: import 3.0 RC1 cutoff from CVS
[mozilla-nspr.git] / nsprpub / lib / prstreams / prstrms.cpp
blob17b280ea1f1d06b648b162103686bda415da277c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * Robin J. Maxwell 11-22-96
42 #include "prstrms.h"
43 #include <string.h> // memmove
46 // Definition of macros _PRSTR_BP, _PRSTR_DELBUF, and _PRSTR_DELBUF_C.
48 // _PRSTR_BP is the protected member of class ios that is returned
49 // by the public method rdbuf().
51 // _PRSTR_DELBUF is the method or data member of class ios, if available,
52 // with which we can ensure that the ios destructor does not delete
53 // the associated streambuf. If such a method or data member does not
54 // exist, define _PRSTR_DELBUF to be empty.
56 // _PRSTR_DELBUF_C is just _PRSTR_DELBUF qualified by a base class.
59 #if defined(__GNUC__)
60 #define _PRSTR_BP _strbuf
61 #define _PRSTR_DELBUF(x) /* as nothing */
62 #define _PRSTR_DELBUF_C(c, x) /* as nothing */
63 #elif defined(WIN32)
64 #define _PRSTR_BP bp
65 #define _PRSTR_DELBUF(x) delbuf(x)
66 #define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x)
67 #elif defined(VMS)
68 #undef _PRSTR_BP
69 #define _PRSTR_DELBUF(x) /* as nothing */
70 #define _PRSTR_DELBUF_C(c, x) /* as nothing */
71 #elif defined(OSF1)
72 #define _PRSTR_BP m_psb
73 #define _PRSTR_DELBUF(x) /* as nothing */
74 #define _PRSTR_DELBUF_C(c, x) /* as nothing */
75 #elif defined(QNX)
76 #define PRFSTREAMS_BROKEN
77 #else
78 #define _PRSTR_BP bp
79 // Unix compilers don't believe in encapsulation
80 // At least on Solaris this is also ignored
81 #define _PRSTR_DELBUF(x) delbuf = x
82 #define _PRSTR_DELBUF_C(c, x) c::_PRSTR_DELBUF(x)
83 #endif
85 const PRIntn STRM_BUFSIZ = 8192;
87 #if !defined (PRFSTREAMS_BROKEN)
89 PRfilebuf::PRfilebuf():
90 _fd(0),
91 _opened(PR_FALSE),
92 _allocated(PR_FALSE)
96 PRfilebuf::PRfilebuf(PRFileDesc *fd):
97 streambuf(),
98 _fd(fd),
99 _opened(PR_FALSE),
100 _allocated(PR_FALSE)
104 PRfilebuf::PRfilebuf(PRFileDesc *fd, char * buffptr, int bufflen):
105 _fd(fd),
106 _opened(PR_FALSE),
107 _allocated(PR_FALSE)
109 PRfilebuf::setbuf(buffptr, bufflen);
112 PRfilebuf::~PRfilebuf()
114 if (_opened){
115 close();
116 }else
117 sync();
118 if (_allocated)
119 delete base();
122 PRfilebuf*
123 PRfilebuf::open(const char *name, int mode, int flags)
125 if (_fd != 0)
126 return 0; // error if already open
127 PRIntn PRmode = 0;
128 // translate mode argument
129 if (!(mode & ios::nocreate))
130 PRmode |= PR_CREATE_FILE;
131 //if (mode & ios::noreplace)
132 // PRmode |= O_EXCL;
133 if (mode & ios::app){
134 mode |= ios::out;
135 PRmode |= PR_APPEND;
137 if (mode & ios::trunc){
138 mode |= ios::out; // IMPLIED
139 PRmode |= PR_TRUNCATE;
141 if (mode & ios::out){
142 if (mode & ios::in)
143 PRmode |= PR_RDWR;
144 else
145 PRmode |= PR_WRONLY;
146 if (!(mode & (ios::in|ios::app|ios::ate|ios::noreplace))){
147 mode |= ios::trunc; // IMPLIED
148 PRmode |= PR_TRUNCATE;
150 }else if (mode & ios::in)
151 PRmode |= PR_RDONLY;
152 else
153 return 0; // error if not ios:in or ios::out
157 // The usual portable across unix crap...
158 // NT gets a hokey piece of junk layer that prevents
159 // access to the API.
160 #ifdef WIN32
161 _fd = PR_Open(name, PRmode, PRmode);
162 #else
163 _fd = PR_Open(name, PRmode, flags);
164 #endif
165 if (_fd == 0)
166 return 0;
167 _opened = PR_TRUE;
168 if ((!unbuffered()) && (!ebuf())){
169 char * sbuf = new char[STRM_BUFSIZ];
170 if (!sbuf)
171 unbuffered(1);
172 else{
173 _allocated = PR_TRUE;
174 streambuf::setb(sbuf,sbuf+STRM_BUFSIZ,0);
177 if (mode & ios::ate){
178 if (seekoff(0,ios::end,mode)==EOF){
179 close();
180 return 0;
183 return this;
186 PRfilebuf*
187 PRfilebuf::attach(PRFileDesc *fd)
189 _opened = PR_FALSE;
190 _fd = fd;
191 return this;
194 int
195 PRfilebuf::overflow(int c)
197 if (allocate()==EOF) // make sure there is a reserve area
198 return EOF;
199 if (PRfilebuf::sync()==EOF) // sync before new buffer created below
200 return EOF;
202 if (!unbuffered())
203 setp(base(),ebuf());
205 if (c!=EOF){
206 if ((!unbuffered()) && (pptr() < epptr())) // guard against recursion
207 sputc(c);
208 else{
209 if (PR_Write(_fd, &c, 1)!=1)
210 return(EOF);
213 return(1); // return something other than EOF if successful
216 int
217 PRfilebuf::underflow()
219 int count;
220 unsigned char tbuf;
222 if (in_avail())
223 return (int)(unsigned char) *gptr();
225 if (allocate()==EOF) // make sure there is a reserve area
226 return EOF;
227 if (PRfilebuf::sync()==EOF)
228 return EOF;
230 if (unbuffered())
232 if (PR_Read(_fd,(void *)&tbuf,1)<=0)
233 return EOF;
234 return (int)tbuf;
237 if ((count=PR_Read(_fd,(void *)base(),blen())) <= 0)
238 return EOF; // reached EOF
239 setg(base(),base(),base()+count);
240 return (int)(unsigned char) *gptr();
243 streambuf*
244 PRfilebuf::setbuf(char *buffptr, PRstreambuflen bufflen)
246 if (is_open() && (ebuf()))
247 return 0;
248 if ((!buffptr) || (bufflen <= 0))
249 unbuffered(1);
250 else
251 setb(buffptr, buffptr+bufflen, 0);
252 return this;
255 streampos
256 PRfilebuf::seekoff(streamoff offset, ios::seek_dir dir, int /* mode */)
258 if (PR_GetDescType(_fd) == PR_DESC_FILE){
259 PRSeekWhence fdir;
260 PRInt32 retpos;
261 switch (dir) {
262 case ios::beg :
263 fdir = PR_SEEK_SET;
264 break;
265 case ios::cur :
266 fdir = PR_SEEK_CUR;
267 break;
268 case ios::end :
269 fdir = PR_SEEK_END;
270 break;
271 default:
272 // error
273 return(EOF);
276 if (PRfilebuf::sync()==EOF)
277 return EOF;
278 if ((retpos=PR_Seek(_fd, offset, fdir))==-1L)
279 return (EOF);
280 return((streampos)retpos);
281 }else
282 return (EOF);
286 int
287 PRfilebuf::sync()
289 PRInt32 count;
291 if (_fd==0)
292 return(EOF);
294 if (!unbuffered()){
295 // Sync write area
296 if ((count=out_waiting())!=0){
297 PRInt32 nout;
298 if ((nout =PR_Write(_fd,
299 (void *) pbase(),
300 (unsigned int)count)) != count){
301 if (nout > 0) {
302 // should set _pptr -= nout
303 pbump(-(int)nout);
304 memmove(pbase(), pbase()+nout, (int)(count-nout));
306 return(EOF);
309 setp(0,0); // empty put area
311 if (PR_GetDescType(_fd) == PR_DESC_FILE){
312 // Sockets can't seek; don't need this
313 if ((count=in_avail()) > 0){
314 if (PR_Seek(_fd, -count, PR_SEEK_CUR)!=-1L)
316 return (EOF);
320 setg(0,0,0); // empty get area
322 return(0);
325 PRfilebuf *
326 PRfilebuf::close()
328 int retval;
329 if (_fd==0)
330 return 0;
332 retval = sync();
334 if ((PR_Close(_fd)==0) || (retval==EOF))
335 return 0;
336 _fd = 0;
337 return this;
340 PRifstream::PRifstream():
341 istream(new PRfilebuf)
343 _PRSTR_DELBUF(0);
346 PRifstream::PRifstream(PRFileDesc *fd):
347 istream(new PRfilebuf(fd))
349 _PRSTR_DELBUF(0);
352 PRifstream::PRifstream(PRFileDesc *fd, char *buff, int bufflen):
353 istream(new PRfilebuf(fd, buff, bufflen))
355 _PRSTR_DELBUF(0);
358 PRifstream::PRifstream(const char * name, int mode, int flags):
359 istream(new PRfilebuf)
361 _PRSTR_DELBUF(0);
362 if (!rdbuf()->open(name, (mode|ios::in), flags))
363 clear(rdstate() | ios::failbit);
366 PRifstream::~PRifstream()
368 sync();
370 delete rdbuf();
371 #ifdef _PRSTR_BP
372 _PRSTR_BP = 0;
373 #endif
376 streambuf *
377 PRifstream::setbuf(char * ptr, int len)
379 if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){
380 clear(rdstate() | ios::failbit);
381 return 0;
383 return rdbuf();
386 void
387 PRifstream::attach(PRFileDesc *fd)
389 if (!(rdbuf()->attach(fd)))
390 clear(rdstate() | ios::failbit);
393 void
394 PRifstream::open(const char * name, int mode, int flags)
396 if (is_open() || !(rdbuf()->open(name, (mode|ios::in), flags)))
397 clear(rdstate() | ios::failbit);
400 void
401 PRifstream::close()
403 clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit));
406 PRofstream::PRofstream():
407 ostream(new PRfilebuf)
409 _PRSTR_DELBUF(0);
412 PRofstream::PRofstream(PRFileDesc *fd):
413 ostream(new PRfilebuf(fd))
415 _PRSTR_DELBUF(0);
418 PRofstream::PRofstream(PRFileDesc *fd, char *buff, int bufflen):
419 ostream(new PRfilebuf(fd, buff, bufflen))
421 _PRSTR_DELBUF(0);
424 PRofstream::PRofstream(const char *name, int mode, int flags):
425 ostream(new PRfilebuf)
427 _PRSTR_DELBUF(0);
428 if (!rdbuf()->open(name, (mode|ios::out), flags))
429 clear(rdstate() | ios::failbit);
432 PRofstream::~PRofstream()
434 flush();
436 delete rdbuf();
437 #ifdef _PRSTR_BP
438 _PRSTR_BP = 0;
439 #endif
442 streambuf *
443 PRofstream::setbuf(char * ptr, int len)
445 if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){
446 clear(rdstate() | ios::failbit);
447 return 0;
449 return rdbuf();
452 void
453 PRofstream::attach(PRFileDesc *fd)
455 if (!(rdbuf()->attach(fd)))
456 clear(rdstate() | ios::failbit);
459 void
460 PRofstream::open(const char * name, int mode, int flags)
462 if (is_open() || !(rdbuf()->open(name, (mode|ios::out), flags)))
463 clear(rdstate() | ios::failbit);
466 void
467 PRofstream::close()
469 clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit));
472 PRfstream::PRfstream():
473 iostream(new PRfilebuf)
475 _PRSTR_DELBUF_C(istream, 0);
476 _PRSTR_DELBUF_C(ostream, 0);
479 PRfstream::PRfstream(PRFileDesc *fd):
480 iostream(new PRfilebuf(fd))
482 _PRSTR_DELBUF_C(istream, 0);
483 _PRSTR_DELBUF_C(ostream, 0);
486 PRfstream::PRfstream(PRFileDesc *fd, char *buff, int bufflen):
487 iostream(new PRfilebuf(fd, buff, bufflen))
489 _PRSTR_DELBUF_C(istream, 0);
490 _PRSTR_DELBUF_C(ostream, 0);
493 PRfstream::PRfstream(const char *name, int mode, int flags):
494 iostream(new PRfilebuf)
496 _PRSTR_DELBUF_C(istream, 0);
497 _PRSTR_DELBUF_C(ostream, 0);
498 if (!rdbuf()->open(name, (mode|(ios::in|ios::out)), flags))
499 clear(rdstate() | ios::failbit);
502 PRfstream::~PRfstream()
504 sync();
505 flush();
507 delete rdbuf();
508 #ifdef _PRSTR_BP
509 istream::_PRSTR_BP = 0;
510 ostream::_PRSTR_BP = 0;
511 #endif
514 streambuf *
515 PRfstream::setbuf(char * ptr, int len)
517 if ((is_open()) || (!(rdbuf()->setbuf(ptr, len)))){
518 clear(rdstate() | ios::failbit);
519 return 0;
521 return rdbuf();
524 void
525 PRfstream::attach(PRFileDesc *fd)
527 if (!(rdbuf()->attach(fd)))
528 clear(rdstate() | ios::failbit);
531 void
532 PRfstream::open(const char * name, int mode, int flags)
534 if (is_open() || !(rdbuf()->open(name, (mode|(ios::in|ios::out)), flags)))
535 clear(rdstate() | ios::failbit);
538 void
539 PRfstream::close()
541 clear((rdbuf()->close()) ? 0 : (rdstate() | ios::failbit));
544 #else
546 // fix it sometime
548 int fix_prfstreams () { return 0; }
550 #endif