|
|
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:
18: #include "streamdefs.h"
19:
20: #ifdef STDIO_ONLY
21: #include <stdio.h>
22:
23: static int open(const char* name,int flags, int prot = 0) ;
24: static int creat(const char* name, int prot ) ;
25: static streampos lseek(int fd, long, ios::seek_dir) ;
26: static int read(int fd, char* b, int len) ;
27: static int write(int fd, char* b, int len) ;
28: static int close(int fd) ;
29: #else
30:
31: #include <osfcn.h>
32:
33: #ifndef O_RDONLY
34: #include <fcntl.h>
35: #endif
36:
37: #endif /* STDIO_ONLY */
38:
39: #ifndef O_RDONLY
40: # define O_RDONLY 0
41: #endif
42:
43: #ifndef O_WRONLY
44: # define O_WRONLY 1
45: #endif
46:
47: #ifndef O_RDWR
48: # define O_RDWR 2
49: #endif
50:
51: #ifndef O_CREAT
52: # define O_CREAT 00400
53: #endif
54:
55: #ifndef O_TRUNC
56: # define O_TRUNC 01000
57: #endif
58:
59: #ifndef O_EXCL
60: # define O_EXCL 02000
61: #endif
62:
63: #ifndef O_APPEND
64: static const int NOSYSAPPEND = 1 ;
65: # define O_APPEND 010
66: #else
67: static const int NOSYSAPPEND = 0 ;
68: #endif
69:
70: #include <errno.h>
71: extern int errno ;
72:
73: const int filebuf::openprot = 0644 ;
74:
75: static const int input=ios::in ;
76: static const int output=ios::out ;
77: static const int append=ios::app ;
78: static const int atend=ios::ate ;
79: static const int tcate=ios::trunc ;
80: static const int nocr=ios::nocreate ;
81: static const int norep=ios::noreplace ;
82:
83: static const int seek_beg=ios::beg ;
84: static const int seek_end=ios::end ;
85: static const int seek_cur=ios::cur ;
86:
87: int filebuf::last_op()
88: {
89: return (pptr()?output:(gptr()?input:0)) ;
90: }
91:
92: inline void save_errno(int& orig)
93: {
94: orig = ::errno ;
95: ::errno = 0 ;
96: }
97:
98: inline int restore_errno(int& orig)
99: {
100: if ( ::errno == 0 ) ::errno = orig ;
101: return EOF ;
102: }
103:
104: /*
105: * Open a file with the given mode.
106: * Return: NULL if failure
107: * this if success
108: */
109: filebuf* filebuf::open (const char *name, int om, int prot)
110: {
111: int errno_orig ;
112: save_errno(errno_orig) ;
113: if ( om&append ) om |= output ;
114:
115: if ( opened ) {
116: restore_errno(errno_orig) ;
117: return 0 ;
118: }
119:
120: int flags = 0 ;
121: if ( om&append ) flags |= O_APPEND ;
122:
123: switch (om&(input|output)) {
124: case input :
125: flags |= O_RDONLY ;
126: xfd = ::open(name,flags) ;
127: break ;
128:
129: case output :
130: flags |= O_WRONLY|O_CREAT|O_TRUNC ;
131: if ( om&nocr ) flags &= ~O_CREAT ;
132: if ( om&norep ) flags |= O_CREAT|O_EXCL ;
133: if ( om&append ) flags |= O_APPEND ;
134: if ( om&(append|atend) ) flags &= ~O_TRUNC ;
135: if ( flags == (O_WRONLY|O_CREAT|O_TRUNC) ) {
136: xfd = ::creat(name,prot) ;
137: }
138: else {
139: xfd = ::open(name,flags,prot) ;
140: }
141:
142: if ( xfd >= 0 && (om&(atend|append))) lseek(xfd,0,2) ;
143: break ;
144:
145: case input|output:
146: flags |= O_RDWR|O_CREAT ;
147: if ( om&tcate ) flags |= O_TRUNC ;
148: if ( om&append ) flags |= O_APPEND ;
149: if ( om&nocr ) flags &= ~O_CREAT ;
150: xfd = ::open(name,flags,prot) ;
151: if ( xfd >= 0 && (om&(atend|append))) lseek(xfd,0,2) ;
152: break;
153: }
154:
155: if (xfd < 0) return 0;
156:
157: opened = 1;
158: setp(0,0) ;
159: setg(0,0,0) ;
160: mode = om ;
161: last_seek = EOF ;
162: restore_errno(errno_orig) ;
163: return this;
164: }
165:
166: filebuf* filebuf::attach (int f)
167: {
168: if ( opened ) return 0 ;
169: xfd = f;
170: opened = 1;
171: setp(0,0) ;
172: setg(0,0,0) ;
173: mode=0 ;
174: last_seek= EOF;
175: return this;
176: }
177:
178: /*
179: * Empty an output buffer.
180: * Returns: EOF on error
181: * 0 on success
182: */
183: int filebuf::overflow(int c)
184: {
185: int errno_orig ;
186: save_errno(errno_orig) ;
187: if ( !opened ) return restore_errno(errno_orig) ;
188: if ( allocate() == EOF ) return restore_errno(errno_orig) ;
189: if ( last_op() == input ) {
190: if ( sync()==EOF ) return restore_errno(errno_orig) ;
191: }
192:
193: register char* p = base() ;
194: // pptr()==NULL does not imply p < pptr(), so we need separate
195: // test.
196: while ( pptr() && p < pptr() ) {
197: if ( NOSYSAPPEND && (mode&append) ) {
198: // System doesn't have an append mode, so approximate
199: // as best we can.
200: lseek(xfd,0,2) ;
201: }
202: /* Partial writes are sometimes possible in peculiar
203: * circumstances */
204: register int count = write(xfd,p,pptr()-p) ;
205: if ( count < 0 ) {
206: last_seek = EOF ;
207: return restore_errno(errno_orig) ;
208: }
209: p += count ;
210:
211: if ( SEEK_ARITH_OK
212: && last_seek != EOF
213: && mode && !(mode&append)
214: && count >= 0 ) {
215: last_seek += count ;
216: } else {
217: last_seek = EOF ;
218: }
219:
220: if ( count < 0 ) return restore_errno(errno_orig) ;
221: }
222:
223: setp(base(),ebuf()) ;
224: setg(0,0,0);
225:
226: if ( c == EOF ) /* don't do anything */ ;
227: else if ( unbuffered() ) {
228: char ch = c;
229: last_seek = EOF ;
230: while ( write(xfd,&ch,1)!=1 && ::errno==0 ) ;
231: if ( ::errno != 0 ) return restore_errno(errno_orig) ;
232: }
233: else {
234: sputc(c) ;
235: }
236:
237: restore_errno(errno_orig) ;
238: return zapeof(c) ;
239: }
240:
241:
242: /*
243: * Fill an input buffer.
244: * Returns: EOF on error or end of input
245: * next character on success
246: */
247: int filebuf::underflow()
248: {
249: int count;
250:
251: if ( !opened ) return EOF ;
252: if ( allocate() == EOF ) return EOF ;
253: if ( last_op() == output ) {
254: if ( sync()==EOF ) return EOF ;
255: }
256: int orig_errno ;
257: save_errno(orig_errno) ;
258: setp(0,0) ;
259: if ( unbuffered() ) {
260: last_seek=EOF ;
261: count = read(xfd,&lahead[0],1) ;
262: setg(&lahead[0],&lahead[0],&lahead[count]) ;
263: if ( count <= 0 ) return EOF ;
264: }
265: else {
266: register int rdsize ;
267: if ( blen() > 2*sizeof(long) ) {
268: /* gptr must be set greater than base to
269: * guarantee at least 1 char of pushback.
270: * putting it farther will tend in many common
271: * cases to keep things aligned.
272: */
273: in_start = base()+sizeof(long) ;
274: rdsize = blen()-sizeof(long) ;
275: } else {
276: in_start = base()+1 ;
277: rdsize = blen()-1 ;
278: }
279: count = read(xfd,in_start,rdsize) ;
280: while ( count<=0 && ::errno==EINTR ) {
281: /*
282: * Signal caught and returned before any data
283: * transfered.
284: */
285: ::errno = 0 ;
286: count = read(xfd,in_start,rdsize) ;
287: }
288:
289: if ( SEEK_ARITH_OK
290: && last_seek != EOF
291: && mode && !(mode&append)
292: && count >= 0 ) {
293: last_seek += count ;
294: } else {
295: last_seek = EOF ;
296: }
297:
298: if ( count <= 0 ) {
299: setg(0,0,0) ;
300: return restore_errno(orig_errno) ;
301: }
302: setg(base(),in_start,in_start+count) ;
303: }
304:
305: restore_errno(orig_errno) ;
306: return zapeof(*gptr());
307: }
308:
309: filebuf* filebuf::close()
310: {
311: int f = xfd ;
312: if ( !opened ) {
313: return 0 ;
314: }
315: if (last_op()==output) overflow();
316: setg(0,0,0) ;
317: setp(0,0) ;
318: opened = 0 ;
319: xfd = -1 ;
320: last_seek = EOF ;
321: if ( mode != 0 ) {
322: mode = 0 ;
323: int orig_errno ;
324: save_errno(orig_errno) ;
325: int ok = ::close(f);
326: restore_errno(orig_errno) ;
327: return ( ok==EOF ? 0 : this ) ;
328: } else {
329: return this ;
330: }
331: }
332:
333: int filebuf::sync()
334: {
335: int ok = 0 ;
336: int orig_errno ;
337: save_errno(orig_errno) ;
338: switch(last_op()) {
339: case input:
340: last_seek = lseek(xfd,gptr()-egptr(),seek_cur) ;
341: if ( last_seek < 0 ) {
342: ok = EOF ;
343: last_seek = EOF ;
344: }
345: break ;
346: case output:
347: ok = overflow() ;
348: /* This does not result in infinite recursion even though
349: * under some circumstances overflow might call sync.
350: * it explicitly does not when last_op==output
351: */
352: break;
353: }
354: setp(0,0) ;
355: setg(0,0,0) ;
356: last_seek = EOF ;
357: restore_errno(orig_errno) ;
358: return (ok==EOF ? EOF : 0 ) ;
359: }
360:
361: streampos filebuf::seekoff(streamoff p, ios::seek_dir d, int m)
362: {
363: int orig_errno ;
364: save_errno(orig_errno) ;
365:
366: if ( last_seek == EOF ) {
367: last_seek = lseek(xfd,0,seek_cur) ;
368: }
369: if ( last_seek == EOF ) return EOF ;
370: if( SEEK_ARITH_OK && !unbuffered() ) {
371: char* refptr = 0 ;
372: streampos sneed ;
373: streampos sref, minavail, maxavail ;
374:
375: switch ( last_op() ) {
376: case input : {
377: refptr = gptr() ;
378: sref = last_seek-(egptr()-gptr()) ;
379: minavail = last_seek-(egptr()-in_start) ;
380: maxavail = last_seek-1 ;
381: } break ;
382: case output : {
383: // only allowable seek during output is
384: // to present position.
385: refptr = pptr() ;
386: sref = last_seek+pptr()-pbase() ;
387: minavail = maxavail = sref ;
388: } break ;
389: }
390: switch( d ) {
391: case seek_beg : sneed = p ; break ;
392: case seek_cur : sneed = sref+p ;break ;
393: case seek_end : refptr = 0 ; break ;
394: /* Can't do seek_end */
395: }
396: if ( refptr && sneed >= minavail && sneed <= maxavail ) {
397: switch( last_op() ) {
398: case input : {
399: setg(eback(),refptr+(sneed-sref),egptr());
400: } break ;
401: case output : {
402: // Seeking to current position. Nothing to
403: // do.
404: } break ;
405: default : {
406: // shouldn't get here. Try to recover somehow
407: sync() ;
408: seekoff(p,d,m);
409: } break ;
410: }
411: return sneed ;
412: }
413: if ( refptr && sneed < sref && sneed+blen()/2 > sref
414: && last_op() == input ) {
415: // looks like we are stepping backward through
416: // a file. Performance may be improved by
417: // backing up a little extra.
418:
419: streampos toofar = sneed-blen()/2 ;
420: if ( toofar < 0 ) toofar = 0 ;
421: sync() ;
422: last_seek=lseek(xfd,toofar,seek_beg) ;
423: overflow();
424: seekoff(p,d,m);
425: }
426: }
427:
428: restore_errno(orig_errno) ;
429: if ( sync()==EOF ) return EOF ;
430: else {
431: last_seek=lseek(xfd,p,d) ;
432: return last_seek ;
433: }
434: }
435:
436: filebuf::filebuf()
437: : xfd(-1), opened(0), mode(0), last_seek(EOF)
438: {
439:
440: }
441:
442: filebuf::filebuf(int f)
443: : xfd(f), opened(1), mode(0), last_seek(EOF)
444: {
445:
446: }
447:
448: filebuf::filebuf(int f, char* p, int l)
449: : streambuf(p,l), xfd(f), opened(1), mode(0), last_seek(EOF)
450: {
451:
452: }
453:
454: filebuf::~filebuf() {
455: close() ;
456: }
457:
458: streambuf* filebuf::setbuf(char* p , int len)
459: {
460: if ( is_open() && base() ) return 0 ;
461: // Note the special case of allowing buffering to be turned
462: // on even for an already opened filebuf.
463: setb(0,0) ;
464: return streambuf::setbuf(p,len) ;
465: }
466:
467: #ifdef STDIO_ONLY
468:
469: /****
470: The following functions will simulate the UNIX function
471: calls using stdio operations. They are intended for
472: non-unix environments. Simulation is not perfect and
473: there may be problems porting code to such environments.
474: In particular issues of binary files are not dealt with
475: here
476: *****/
477: #ifndef SEEK_SET
478: # define SEEK_SET 0
479: #endif
480:
481: #ifndef SEEK_CUR
482: # define SEEK_CUR 1
483: #endif
484:
485: #ifndef SEEK_END
486: # define SEEK_END 2
487: #endif
488:
489: typedef FILE* Filep ;
490:
491: static Filep* files = 0 ;
492: static int nfiles = 0 ;
493:
494: static Filep zfp ;
495:
496: static Filep& file(int fd)
497: {
498: if ( fd < nfiles ) return files[fd] ;
499: if ( !files ) {
500: files = new Filep [3] ;
501: if ( !files ) {
502: // Malloc failed. We're in deep trouble
503: return zfp ;
504: }
505: files[0] = stdin ;
506: files[1] = stdout ;
507: files[2] = stderr ;
508: nfiles = 3 ;
509: }
510: if ( fd < nfiles ) return files[fd] ;
511:
512: Filep* newfiles = new Filep [2*nfiles] ;
513: if ( !newfiles ) {
514: // Oh dear malloc failed. There isn't really any
515: // reasonable recovery, so I just kind of boot.
516: return zfp ;
517: }
518: int x ;
519: for ( x = 0 ; x < nfiles ; ++x) newfiles[x] = files[x] ;
520: nfiles = 2*nfiles ;
521: for ( ; x < nfiles ; ++x ) newfiles[x] = 0 ;
522: delete files ;
523: files = newfiles ;
524: return files[fd] ;
525: }
526:
527: static int xfile()
528: {
529: if ( !files ) file(0) ;
530: for ( int x = 0 ; x < nfiles ; ++x ) {
531: if ( !files[x] ) return x ;
532: }
533: return nfiles ;
534: }
535:
536: static int open(const char* name, int flags, int )
537: {
538: /* not all modes can be simulated using stdio, sorry */
539: char* type = "" ;
540: switch ( flags & 03 ) {
541: case 0 : /* RD_ONLY */ {
542: type = "r" ;
543: } break ;
544: case 1 : /* WR_ONLY */ {
545: if ( flags & O_TRUNC ) type = "w" ;
546: else type = "a" ;
547: } break ;
548: case 2 : /* RDWR */ {
549: if ( flags & O_TRUNC) type = "w+" ;
550: else if ( flags & O_APPEND ) type = "a+" ;
551: else type = "r+" ;
552: } break ;
553: }
554:
555: int x = xfile() ;
556: if ( x < 0 ) return -1 ;
557: Filep* xfile = &file(x) ;
558: *xfile = fopen(name, type) ;
559: return ( *xfile ? x : -1 ) ;
560: }
561:
562: static int creat(const char* name, int)
563: {
564: return open(name,O_WRONLY|O_CREAT|O_TRUNC,0) ;
565: }
566:
567: static streampos lseek(int fd, long n, ios::seek_dir d )
568: {
569: int whence ;
570: switch ( d ) {
571: case seek_beg : whence = SEEK_SET ; break ;
572: case seek_cur : whence = SEEK_CUR ; break ;
573: case seek_end : whence = SEEK_END ; break ;
574: }
575: Filep f = file(fd) ;
576: if ( !f ) return EOF ;
577: int fail = fseek(f, n, whence ) ;
578: if ( fail ) return EOF ;
579: return ftell(f) ;
580: }
581:
582:
583: static int read(int fd, char* b, int len)
584: {
585: Filep f = file(fd) ;
586: if ( !f ) return 0 ;
587: return fread(b,1,len,file(fd)) ;
588: }
589:
590: static int write(int fd, char* b, int len)
591: {
592: Filep f = file(fd) ;
593: if ( !f ) return 0 ;
594: int n = fwrite(b,1,len,f) ;
595: fflush(f) ;
596: return n ;
597: }
598:
599: static int close(int fd)
600: {
601: Filep f = file(fd) ;
602: if (!f ) return 0 ;
603: return fclose(f) ;
604: }
605:
606: #endif /* STDIO_ONLY */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.