|
|
1.1 root 1: /*ident "@(#)ctrans:lib/stream/filebuf.c 1.1.2.2" */
2: /**************************************************************************
3: Copyright (c) 1984 AT&T
4: All Rights Reserved
5:
6: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
7:
8: The copyright notice above does not evidence any
9: actual or intended publication of such source code.
10:
11: filebuf.c:
12:
13: *****************************************************************************/
14:
15: #include <iostream.h>
16: #include <fstream.h>
17: #include <osfcn.h>
18: #include "streamdefs.h"
19:
20: #ifndef O_RDONLY
21: # include <fcntl.h>
22: #endif
23:
24: #ifndef O_CREAT
25: # define O_CREAT 00400
26: #endif
27:
28: #ifndef O_TRUNC
29: # define O_TRUNC 01000
30: #endif
31:
32: #ifndef O_EXCL
33: # define O_EXCL 02000
34: #endif
35:
36:
37: #ifndef O_APPEND
38: # define O_APPEND 0
39: #endif
40:
41: #include <errno.h>
42: extern int errno ;
43:
44: const int filebuf::openprot = 0644 ;
45:
46: static const int input=ios::in ;
47: static const int output=ios::out ;
48: static const int append=ios::app ;
49: static const int atend=ios::ate ;
50: static const int tcate=ios::trunc ;
51: static const int nocr=ios::nocreate ;
52: static const int norep=ios::noreplace ;
53:
54: static const int seek_beg=ios::beg ;
55: static const int seek_end=ios::end ;
56: static const int seek_cur=ios::cur ;
57:
58: int filebuf::last_op()
59: {
60: return (pptr()?output:(gptr()?input:0)) ;
61: }
62:
63: inline void save_errno(int& orig)
64: {
65: orig = ::errno ;
66: ::errno = 0 ;
67: }
68:
69: inline int restore_errno(int& orig)
70: {
71: if ( ::errno == 0 ) ::errno = orig ;
72: return EOF ;
73: }
74:
75: /*
76: * Open a file with the given mode.
77: * Return: NULL if failure
78: * this if success
79: */
80: filebuf* filebuf::open (const char *name, int om, int prot)
81: {
82: int errno_orig ;
83: save_errno(errno_orig) ;
84: if ( om&append ) om |= output ;
85:
86: if ( opened ) {
87: restore_errno(errno_orig) ;
88: return 0 ;
89: }
90:
91: int flags = 0 ;
92: if ( om&append ) flags |= O_APPEND ;
93:
94: switch (om&(input|output)) {
95: case input :
96: flags |= O_RDONLY ;
97: xfd = ::open(name,flags) ;
98: break ;
99:
100: case output :
101: flags |= O_WRONLY|O_CREAT|O_TRUNC ;
102: if ( om&nocr ) flags &= ~O_CREAT ;
103: if ( om&norep ) flags |= O_CREAT|O_EXCL ;
104: if ( om&append ) flags |= O_APPEND ;
105: if ( flags == (O_WRONLY|O_CREAT|O_TRUNC) ) {
106: xfd = ::creat(name,prot) ;
107: }
108: else {
109: xfd = ::open(name,flags,prot) ;
110: }
111:
112: if ( xfd >= 0 && (om&(atend|append))) lseek(xfd,0,2) ;
113: break ;
114:
115: case input|output:
116: flags |= O_RDWR|O_CREAT ;
117: if ( om&tcate ) flags |= O_TRUNC ;
118: if ( om&append ) flags |= O_APPEND ;
119: if ( om&nocr ) flags &= ~O_CREAT ;
120: xfd = ::open(name,flags,prot) ;
121: if ( xfd >= 0 && (om&(atend|append))) lseek(xfd,0,2) ;
122: break;
123: }
124:
125: if (xfd < 0) return 0;
126:
127: opened = 1;
128: setp(0,0) ;
129: setg(0,0,0) ;
130: mode = om ;
131: last_seek = EOF ;
132: restore_errno(errno_orig) ;
133: return this;
134: }
135:
136: filebuf* filebuf::attach (int f)
137: {
138: if ( opened ) return 0 ;
139: xfd = f;
140: opened = 1;
141: setp(0,0) ;
142: setg(0,0,0) ;
143: mode=0 ;
144: last_seek= EOF;
145: return this;
146: }
147:
148: /*
149: * Empty an output buffer.
150: * Returns: EOF on error
151: * 0 on success
152: */
153: int filebuf::overflow(int c)
154: {
155: int errno_orig ;
156: save_errno(errno_orig) ;
157: if ( !opened ) return restore_errno(errno_orig) ;
158: if ( allocate() == EOF ) return restore_errno(errno_orig) ;
159: if ( last_op() == input ) {
160: if ( sync()==EOF ) return restore_errno(errno_orig) ;
161: }
162:
163: register char* p = base() ;
164: // pptr()==NULL does not imply p < pptr(), so we need separate
165: // test.
166: while ( pptr() && p < pptr() ) {
167: if ( O_APPEND==0 && (mode&append) ) {
168: // System doesn't have an append mode, so approximate
169: // as best we can.
170: lseek(xfd,0,2) ;
171: }
172: /* Partial writes are sometimes possible in peculiar
173: * circumstances */
174: register int count = write(xfd,p,pptr()-p) ;
175: if ( count < 0 ) {
176: last_seek = EOF ;
177: return restore_errno(errno_orig) ;
178: }
179: p += count ;
180:
181: if ( SEEK_ARITH_OK
182: && last_seek != EOF
183: && mode && !(mode&append)
184: && count >= 0 ) {
185: last_seek += count ;
186: } else {
187: last_seek = EOF ;
188: }
189:
190: if ( count < 0 ) return restore_errno(errno_orig) ;
191: }
192:
193: setp(base(),ebuf()) ;
194: setg(0,0,0);
195:
196: if ( c == EOF ) /* don't do anything */ ;
197: else if ( unbuffered() ) {
198: char ch = c;
199: last_seek = EOF ;
200: while ( write(xfd,&ch,1)!=1 && ::errno==0 ) ;
201: if ( ::errno != 0 ) return restore_errno(errno_orig) ;
202: }
203: else {
204: sputc(c) ;
205: }
206:
207: restore_errno(errno_orig) ;
208: return zapeof(c) ;
209: }
210:
211:
212: /*
213: * Fill an input buffer.
214: * Returns: EOF on error or end of input
215: * next character on success
216: */
217: int filebuf::underflow()
218: {
219: int count;
220:
221: if ( !opened ) return EOF ;
222: if ( allocate() == EOF ) return EOF ;
223: if ( last_op() == output ) {
224: if ( sync()==EOF ) return EOF ;
225: }
226: int orig_errno ;
227: save_errno(orig_errno) ;
228: setp(0,0) ;
229: if ( unbuffered() ) {
230: last_seek=EOF ;
231: count = read(xfd,&lahead[0],1) ;
232: setg(&lahead[0],&lahead[0],&lahead[count]) ;
233: if ( count <= 0 ) return EOF ;
234: }
235: else {
236: register int rdsize ;
237: if ( blen() > 2*sizeof(long) ) {
238: /* gptr must be set greater than base to
239: * guarantee at least 1 char of pushback.
240: * putting it farther will tend in many common
241: * cases to keep things aligned.
242: */
243: in_start = base()+sizeof(long) ;
244: rdsize = blen()-sizeof(long) ;
245: } else {
246: in_start = base()+1 ;
247: rdsize = blen()-1 ;
248: }
249: count = read(xfd,in_start,rdsize) ;
250: while ( count<=0 && ::errno==EINTR ) {
251: /*
252: * Signal caught and returned before any data
253: * transfered.
254: */
255: ::errno = 0 ;
256: count = read(xfd,in_start,rdsize) ;
257: }
258:
259: if ( SEEK_ARITH_OK
260: && last_seek != EOF
261: && mode && !(mode&append)
262: && count >= 0 ) {
263: last_seek += count ;
264: } else {
265: last_seek = EOF ;
266: }
267:
268: if ( count <= 0 ) {
269: setg(0,0,0) ;
270: return restore_errno(orig_errno) ;
271: }
272: setg(base(),in_start,in_start+count) ;
273: }
274:
275: restore_errno(orig_errno) ;
276: return zapeof(*gptr());
277: }
278:
279: filebuf* filebuf::close()
280: {
281: int f = xfd ;
282: if ( !opened ) {
283: return 0 ;
284: }
285: if (last_op()==output) overflow();
286: setg(0,0,0) ;
287: setp(0,0) ;
288: opened = 0 ;
289: xfd = -1 ;
290: last_seek = EOF ;
291: if ( mode != 0 ) {
292: mode = 0 ;
293: int orig_errno ;
294: save_errno(orig_errno) ;
295: int ok = ::close(f);
296: restore_errno(orig_errno) ;
297: return ( ok==EOF ? 0 : this ) ;
298: } else {
299: return this ;
300: }
301: }
302:
303: int filebuf::sync()
304: {
305: int ok = 0 ;
306: int orig_errno ;
307: save_errno(orig_errno) ;
308: switch(last_op()) {
309: case input:
310: last_seek = lseek(xfd,gptr()-egptr(),seek_cur) ;
311: if ( last_seek < 0 ) {
312: ok = EOF ;
313: last_seek = EOF ;
314: }
315: break ;
316: case output:
317: ok = overflow() ;
318: /* This does not result in infinite recursion even though
319: * under some circumstances overflow might call sync.
320: * it explicitly does not when last_op==output
321: */
322: break;
323: }
324: setp(0,0) ;
325: setg(0,0,0) ;
326: restore_errno(orig_errno) ;
327: return (ok==EOF ? EOF : 0 ) ;
328: }
329:
330: streampos filebuf::seekoff(streamoff p, seek_dir d, int m)
331: {
332: int orig_errno ;
333: save_errno(orig_errno) ;
334:
335: if ( last_seek == EOF ) {
336: last_seek = lseek(xfd,0,seek_cur) ;
337: }
338: if ( last_seek == EOF ) return EOF ;
339: if( SEEK_ARITH_OK && !unbuffered() ) {
340: char* refptr = 0 ;
341: streampos sneed ;
342: streampos sref, minavail, maxavail ;
343:
344: switch ( last_op() ) {
345: case input : {
346: refptr = gptr() ;
347: sref = last_seek-(egptr()-gptr()) ;
348: minavail = last_seek-(egptr()-in_start) ;
349: maxavail = last_seek-1 ;
350: } break ;
351: case output : {
352: // only allowable seek during output is
353: // to present position.
354: refptr = pptr() ;
355: sref = last_seek+pptr()-pbase() ;
356: minavail = maxavail = sref ;
357: } break ;
358: }
359: switch( d ) {
360: case seek_beg : sneed = p ; break ;
361: case seek_cur : sneed = sref+p ;break ;
362: case seek_end : refptr = 0 ; break ;
363: /* Can't do seek_end */
364: }
365: if ( refptr && sneed >= minavail && sneed <= maxavail ) {
366: switch( last_op() ) {
367: case input : {
368: setg(eback(),refptr+(sneed-sref),egptr());
369: } break ;
370: case output : {
371: // Seeking to current position. Nothing to
372: // do.
373: } break ;
374: default : {
375: // shouldn't get here. Try to recover somehow
376: sync() ;
377: seekoff(p,d,m);
378: } break ;
379: }
380: return sneed ;
381: }
382: if ( refptr && sneed < sref && sneed+blen()/2 > sref
383: && last_op() == input ) {
384: // looks like we are stepping backward through
385: // a file. Performance may be improved by
386: // backing up a little extra.
387:
388: streampos toofar = sneed-blen()/2 ;
389: if ( toofar < 0 ) toofar = 0 ;
390: sync() ;
391: last_seek=lseek(xfd,toofar,seek_beg) ;
392: overflow();
393: seekoff(p,d,m);
394: }
395: }
396:
397: restore_errno(orig_errno) ;
398: if ( sync()==EOF ) return EOF ;
399: else {
400: last_seek=lseek(xfd,p,d) ;
401: return last_seek ;
402: }
403: }
404:
405: filebuf::filebuf()
406: : xfd(-1), opened(0), mode(0), last_seek(EOF)
407: {
408:
409: }
410:
411: filebuf::filebuf(int f)
412: : xfd(f), opened(1), mode(0), last_seek(EOF)
413: {
414:
415: }
416:
417: filebuf::filebuf(int f, char* p, int l)
418: : streambuf(p,l), xfd(f), opened(1), mode(0), last_seek(EOF)
419: {
420:
421: }
422:
423: filebuf::~filebuf() {
424: close() ;
425: }
426:
427: streambuf* filebuf::setbuf(char* p , int len)
428: {
429:
430: if ( is_open() ) return 0 ;
431: setb(0,0) ;
432: return streambuf::setbuf(p,len) ;
433: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.