14887Schin /***********************************************************************
24887Schin * *
34887Schin * This software is part of the ast package *
4*12068SRoger.Faulkner@Oracle.COM * Copyright (c) 1985-2010 AT&T Intellectual Property *
54887Schin * and is licensed under the *
64887Schin * Common Public License, Version 1.0 *
78462SApril.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
setlinemode()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
sfsetbuf(Sfio_t * f,Void_t * buf,size_t size)938462SApril.Chin@Sun.COM Void_t* sfsetbuf(Sfio_t* f, Void_t* buf, size_t size)
944887Schin #else
954887Schin Void_t* sfsetbuf(f,buf,size)
968462SApril.Chin@Sun.COM Sfio_t* f; /* stream to be buffered */
978462SApril.Chin@Sun.COM Void_t* buf; /* new buffer */
988462SApril.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;
1078462SApril.Chin@Sun.COM SFMTXDECL(f);
1084887Schin
1094887Schin SFONCE();
1104887Schin
1118462SApril.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