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