14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * Phong Vo <kpv@research.att.com> * 204887Schin * * 214887Schin ***********************************************************************/ 224887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide) 234887Schin __STDPP__directive pragma pp:hide getpagesize 244887Schin #else 254887Schin #define getpagesize ______getpagesize 264887Schin #endif 274887Schin 284887Schin #include "sfhdr.h" 294887Schin 304887Schin #if defined(__STDPP__directive) && defined(__STDPP__hide) 314887Schin __STDPP__directive pragma pp:nohide getpagesize 324887Schin #else 334887Schin #undef getpagesize 344887Schin #endif 354887Schin 364887Schin #if _lib_getpagesize 374887Schin _BEGIN_EXTERNS_ 384887Schin extern int getpagesize _ARG_((void)); 394887Schin _END_EXTERNS_ 404887Schin #endif 414887Schin 424887Schin /* Set a (new) buffer for a stream. 434887Schin ** If size < 0, it is assigned a suitable value depending on the 444887Schin ** kind of stream. The actual buffer size allocated is dependent 454887Schin ** on how much memory is available. 464887Schin ** 474887Schin ** Written by Kiem-Phong Vo. 484887Schin */ 494887Schin 504887Schin #if !_sys_stat 514887Schin struct stat 524887Schin { int st_mode; 534887Schin int st_size; 544887Schin }; 554887Schin #undef sysfstatf 564887Schin #define sysfstatf(fd,st) (-1) 574887Schin #endif /*_sys_stat*/ 584887Schin 594887Schin static int setlinemode() 604887Schin { char* astsfio; 614887Schin char* endw; 624887Schin 634887Schin static int modes = -1; 644887Schin static const char sf_line[] = "SF_LINE"; 654887Schin static const char sf_wcwidth[] = "SF_WCWIDTH"; 664887Schin 674887Schin #define ISSEPAR(c) ((c) == ',' || (c) == ' ' || (c) == '\t') 684887Schin if (modes < 0) 694887Schin { modes = 0; 704887Schin if(astsfio = getenv("_AST_SFIO_OPTIONS")) 714887Schin { for(; *astsfio != 0; astsfio = endw) 724887Schin { while(ISSEPAR(*astsfio) ) 734887Schin *astsfio++; 744887Schin for(endw = astsfio; *endw && !ISSEPAR(*endw); ++endw) 754887Schin ; 764887Schin if((endw-astsfio) == (sizeof(sf_line)-1) && 774887Schin strncmp(astsfio,sf_line,endw-astsfio) == 0) 784887Schin { if ((modes |= SF_LINE) == (SF_LINE|SF_WCWIDTH)) 794887Schin break; 804887Schin } 814887Schin else if((endw-astsfio) == (sizeof(sf_wcwidth)-1) && 824887Schin strncmp(astsfio,sf_wcwidth,endw-astsfio) == 0) 834887Schin { if ((modes |= SF_WCWIDTH) == (SF_LINE|SF_WCWIDTH)) 844887Schin break; 854887Schin } 864887Schin } 874887Schin } 884887Schin } 894887Schin return modes; 904887Schin } 914887Schin 924887Schin #if __STD_C 93*8462SApril.Chin@Sun.COM Void_t* sfsetbuf(Sfio_t* f, Void_t* buf, size_t size) 944887Schin #else 954887Schin Void_t* sfsetbuf(f,buf,size) 96*8462SApril.Chin@Sun.COM Sfio_t* f; /* stream to be buffered */ 97*8462SApril.Chin@Sun.COM Void_t* buf; /* new buffer */ 98*8462SApril.Chin@Sun.COM size_t size; /* buffer size, -1 for default size */ 994887Schin #endif 1004887Schin { 1014887Schin int sf_malloc, oflags, init, okmmap, local; 1024887Schin ssize_t bufsize, blksz; 1034887Schin Sfdisc_t* disc; 1044887Schin sfstat_t st; 1054887Schin uchar* obuf = NIL(uchar*); 1064887Schin ssize_t osize = 0; 107*8462SApril.Chin@Sun.COM SFMTXDECL(f); 1084887Schin 1094887Schin SFONCE(); 1104887Schin 111*8462SApril.Chin@Sun.COM SFMTXENTER(f,NIL(Void_t*)); 1124887Schin 1134887Schin GETLOCAL(f,local); 1144887Schin 1154887Schin if(size == 0 && buf) 1164887Schin { /* special case to get buffer info */ 1174887Schin _Sfi = f->val = (f->bits&SF_MMAP) ? (f->endb-f->data) : f->size; 1184887Schin SFMTXRETURN(f, (Void_t*)f->data); 1194887Schin } 1204887Schin 1214887Schin /* cleanup actions already done, don't allow write buffering any more */ 1224887Schin if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE)) 1234887Schin { buf = NIL(Void_t*); 1244887Schin size = 0; 1254887Schin } 1264887Schin 1274887Schin if((init = f->mode&SF_INIT) ) 1284887Schin { if(!f->pool && _sfsetpool(f) < 0) 1294887Schin SFMTXRETURN(f, NIL(Void_t*)); 1304887Schin } 1314887Schin else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0) 1324887Schin SFMTXRETURN(f, NIL(Void_t*)); 1334887Schin 1344887Schin if(init) 1354887Schin f->mode = (f->mode&SF_RDWR)|SF_LOCK; 1364887Schin else 1374887Schin { int rv; 1384887Schin 1394887Schin /* make sure there is no hidden read data */ 1404887Schin if(f->proc && (f->flags&SF_READ) && (f->mode&SF_WRITE) && 1414887Schin _sfmode(f,SF_READ,local) < 0) 1424887Schin SFMTXRETURN(f, NIL(Void_t*)); 1434887Schin 1444887Schin /* synchronize first */ 1454887Schin SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local); 1464887Schin if(rv < 0) 1474887Schin SFMTXRETURN(f, NIL(Void_t*)); 1484887Schin 1494887Schin /* turn off the SF_SYNCED bit because buffer is changing */ 1504887Schin f->mode &= ~SF_SYNCED; 1514887Schin } 1524887Schin 1534887Schin SFLOCK(f,local); 1544887Schin 1554887Schin if((Sfio_t*)buf != f) 1564887Schin blksz = -1; 1574887Schin else /* setting alignment size only */ 1584887Schin { blksz = (ssize_t)size; 1594887Schin 1604887Schin if(!init) /* stream already initialized */ 1614887Schin { obuf = f->data; 1624887Schin osize = f->size; 1634887Schin goto done; 1644887Schin } 1654887Schin else /* initialize stream as if in the default case */ 1664887Schin { buf = NIL(Void_t*); 1674887Schin size = (size_t)SF_UNBOUND; 1684887Schin } 1694887Schin } 1704887Schin 1714887Schin bufsize = 0; 1724887Schin oflags = f->flags; 1734887Schin 1744887Schin /* see if memory mapping is possible (see sfwrite for SF_BOTH) */ 1754887Schin okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1; 1764887Schin 1774887Schin /* save old buffer info */ 1784887Schin #ifdef MAP_TYPE 1794887Schin if(f->bits&SF_MMAP) 1804887Schin { if(f->data) 1814887Schin { SFMUNMAP(f,f->data,f->endb-f->data); 1824887Schin f->data = NIL(uchar*); 1834887Schin } 1844887Schin } else 1854887Schin #endif 1864887Schin if(f->data == f->tiny) 1874887Schin { f->data = NIL(uchar*); 1884887Schin f->size = 0; 1894887Schin } 1904887Schin obuf = f->data; 1914887Schin osize = f->size; 1924887Schin 1934887Schin f->flags &= ~SF_MALLOC; 1944887Schin f->bits &= ~SF_MMAP; 1954887Schin 1964887Schin /* pure read/string streams must have a valid string */ 1974887Schin if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR && 1984887Schin (size == (size_t)SF_UNBOUND || !buf)) 1994887Schin size = 0; 2004887Schin 2014887Schin /* set disc to the first discipline with a seekf */ 2024887Schin for(disc = f->disc; disc; disc = disc->disc) 2034887Schin if(disc->seekf) 2044887Schin break; 2054887Schin 2064887Schin if((init || local) && !(f->flags&SF_STRING)) 2074887Schin { /* ASSERT(f->file >= 0) */ 2084887Schin st.st_mode = 0; 2094887Schin 2104887Schin /* if has discipline, set size by discipline if possible */ 2114887Schin if(!_sys_stat || disc) 2124887Schin { if((f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,disc)) < 0) 2134887Schin goto unseekable; 2144887Schin else 2154887Schin { Sfoff_t e; 2164887Schin if((e = SFSK(f,(Sfoff_t)0,SEEK_END,disc)) >= 0) 2174887Schin f->extent = e > f->here ? e : f->here; 2184887Schin (void)SFSK(f,f->here,SEEK_SET,disc); 2194887Schin goto setbuf; 2204887Schin } 2214887Schin } 2224887Schin 2234887Schin /* get file descriptor status */ 2244887Schin if(sysfstatf((int)f->file,&st) < 0) 2254887Schin f->here = -1; 2264887Schin else 2274887Schin { 2284887Schin #if _sys_stat && _stat_blksize /* preferred io block size */ 2294887Schin f->blksz = (size_t)st.st_blksize; 2304887Schin #endif 2314887Schin bufsize = 64 * 1024; 2324887Schin if(S_ISDIR(st.st_mode) || (Sfoff_t)st.st_size < (Sfoff_t)SF_GRAIN) 2334887Schin okmmap = 0; 2344887Schin if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) 2354887Schin f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,f->disc); 2364887Schin else f->here = -1; 2374887Schin 2384887Schin #if O_TEXT /* no memory mapping with O_TEXT because read()/write() alter data stream */ 2394887Schin if(okmmap && f->here >= 0 && 2404887Schin (sysfcntlf((int)f->file,F_GETFL,0) & O_TEXT) ) 2414887Schin okmmap = 0; 2424887Schin #endif 2434887Schin } 2444887Schin 2454887Schin if(init) 2464887Schin f->flags |= setlinemode(); 2474887Schin 2484887Schin if(f->here >= 0) 2494887Schin { f->extent = (Sfoff_t)st.st_size; 2504887Schin 2514887Schin /* seekable std-devices are share-public by default */ 2524887Schin if(f == sfstdin || f == sfstdout || f == sfstderr) 2534887Schin f->flags |= SF_SHARE|SF_PUBLIC; 2544887Schin } 2554887Schin else 2564887Schin { 2574887Schin unseekable: 2584887Schin f->extent = -1; 2594887Schin f->here = 0; 2604887Schin 2614887Schin if(init) 2624887Schin { if(S_ISCHR(st.st_mode) ) 2634887Schin { int oerrno = errno; 2644887Schin 2654887Schin bufsize = SF_GRAIN; 2664887Schin 2674887Schin /* set line mode for terminals */ 2684887Schin if(!(f->flags&(SF_LINE|SF_WCWIDTH)) && isatty(f->file)) 2694887Schin f->flags |= SF_LINE|SF_WCWIDTH; 2704887Schin #if _sys_stat 2714887Schin else /* special case /dev/null */ 2724887Schin { reg int dev, ino; 2734887Schin dev = (int)st.st_dev; 2744887Schin ino = (int)st.st_ino; 2754887Schin if(sysstatf(DEVNULL,&st) >= 0 && 2764887Schin dev == (int)st.st_dev && 2774887Schin ino == (int)st.st_ino) 2784887Schin SFSETNULL(f); 2794887Schin } 2804887Schin #endif 2814887Schin errno = oerrno; 2824887Schin } 2834887Schin 2844887Schin /* initialize side buffer for r+w unseekable streams */ 2854887Schin if(!f->proc && (f->bits&SF_BOTH) ) 2864887Schin (void)_sfpopen(f,-1,-1,1); 2874887Schin } 2884887Schin } 2894887Schin 2904887Schin /* set page size, this is also the desired default buffer size */ 2914887Schin if(_Sfpage <= 0) 2924887Schin { 2934887Schin #if _lib_getpagesize 2944887Schin if((_Sfpage = (size_t)getpagesize()) <= 0) 2954887Schin #endif 2964887Schin _Sfpage = SF_PAGE; 2974887Schin } 2984887Schin } 2994887Schin 3004887Schin #ifdef MAP_TYPE 3014887Schin if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 ) 3024887Schin { /* see if we can try memory mapping */ 3034887Schin if(!disc) 3044887Schin for(disc = f->disc; disc; disc = disc->disc) 3054887Schin if(disc->readf) 3064887Schin break; 3074887Schin if(!disc) 3084887Schin { f->bits |= SF_MMAP; 3094887Schin if(size == (size_t)SF_UNBOUND) 3104887Schin { if(bufsize > _Sfpage) 3114887Schin size = bufsize * SF_NMAP; 3124887Schin else size = _Sfpage * SF_NMAP; 3134887Schin if(size > 256*1024) 3144887Schin size = 256*1024; 3154887Schin } 3164887Schin } 3174887Schin } 3184887Schin #endif 3194887Schin 3204887Schin /* get buffer space */ 3214887Schin setbuf: 3224887Schin if(size == (size_t)SF_UNBOUND) 3234887Schin { /* define a default size suitable for block transfer */ 3244887Schin if(init && osize > 0) 3254887Schin size = osize; 3264887Schin else if(f == sfstderr && (f->mode&SF_WRITE)) 3274887Schin size = 0; 3284887Schin else if(f->flags&SF_STRING ) 3294887Schin size = SF_GRAIN; 3304887Schin else if((f->flags&SF_READ) && !(f->bits&SF_BOTH) && 3314887Schin f->extent > 0 && f->extent < (Sfoff_t)_Sfpage ) 3324887Schin size = (((size_t)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN; 3334887Schin else if((ssize_t)(size = _Sfpage) < bufsize) 3344887Schin size = bufsize; 3354887Schin 3364887Schin buf = NIL(Void_t*); 3374887Schin } 3384887Schin 3394887Schin sf_malloc = 0; 3404887Schin if(size > 0 && !buf && !(f->bits&SF_MMAP)) 3414887Schin { /* try to allocate a buffer */ 3424887Schin if(obuf && size == (size_t)osize && init) 3434887Schin { buf = (Void_t*)obuf; 3444887Schin obuf = NIL(uchar*); 3454887Schin sf_malloc = (oflags&SF_MALLOC); 3464887Schin } 3474887Schin if(!buf) 3484887Schin { /* do allocation */ 3494887Schin while(!buf && size > 0) 3504887Schin { if((buf = (Void_t*)malloc(size)) ) 3514887Schin break; 3524887Schin else size /= 2; 3534887Schin } 3544887Schin if(size > 0) 3554887Schin sf_malloc = SF_MALLOC; 3564887Schin } 3574887Schin } 3584887Schin 3594887Schin if(size == 0 && !(f->flags&SF_STRING) && !(f->bits&SF_MMAP) && (f->mode&SF_READ)) 3604887Schin { /* use the internal buffer */ 3614887Schin size = sizeof(f->tiny); 3624887Schin buf = (Void_t*)f->tiny; 3634887Schin } 3644887Schin 3654887Schin /* set up new buffer */ 3664887Schin f->size = size; 3674887Schin f->next = f->data = f->endr = f->endw = (uchar*)buf; 3684887Schin f->endb = (f->mode&SF_READ) ? f->data : f->data+size; 3694887Schin if(f->flags&SF_STRING) 3704887Schin { /* these fields are used to test actual size - see sfseek() */ 3714887Schin f->extent = (!sf_malloc && 3724887Schin ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ) ? size : 0; 3734887Schin f->here = 0; 3744887Schin 3754887Schin /* read+string stream should have all data available */ 3764887Schin if((f->mode&SF_READ) && !sf_malloc) 3774887Schin f->endb = f->data+size; 3784887Schin } 3794887Schin 3804887Schin f->flags = (f->flags & ~SF_MALLOC)|sf_malloc; 3814887Schin 3824887Schin if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC)) 3834887Schin { free((Void_t*)obuf); 3844887Schin obuf = NIL(uchar*); 3854887Schin } 3864887Schin 3874887Schin done: 3884887Schin _Sfi = f->val = obuf ? osize : 0; 3894887Schin 3904887Schin /* blksz is used for aligning disk block boundary while reading data to 3914887Schin ** optimize data transfer from disk (eg, via direct I/O). blksz can be 3924887Schin ** at most f->size/2 so that data movement in buffer can be optimized. 3934887Schin ** blksz should also be a power-of-2 for optimal disk seeks. 3944887Schin */ 3954887Schin if(blksz <= 0 || (blksz & (blksz-1)) != 0 ) 3964887Schin blksz = SF_GRAIN; 3974887Schin while(blksz > f->size/2) 3984887Schin blksz /= 2; 3994887Schin f->blksz = blksz; 4004887Schin 4014887Schin SFOPEN(f,local); 4024887Schin 4034887Schin SFMTXRETURN(f, (Void_t*)obuf); 4044887Schin } 405