|
|
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.