2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: sfsetbuf.c /main/3 1995/11/01 18:35:58 rswiston $ */
24 /***************************************************************
26 * AT&T - PROPRIETARY *
28 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
31 * Copyright (c) 1995 AT&T Corp. *
32 * All Rights Reserved *
34 * This software is licensed by AT&T Corp. *
35 * under the terms and conditions of the license in *
36 * http://www.research.att.com/orgs/ssr/book/reuse *
38 * This software was created by the *
39 * Software Engineering Research Department *
40 * AT&T Bell Laboratories *
42 * For further information contact *
43 * gsf@research.att.com *
45 ***************************************************************/
48 /* Set a (new) buffer for a stream.
49 ** If size < 0, it is assigned a suitable value depending on the
50 ** kind of stream. The actual buffer size allocated is dependent
51 ** on how much memory is available.
53 ** Written by Kiem-Phong Vo (06/27/90)
57 Void_t* sfsetbuf(reg Sfio_t* f, reg Void_t* buf, reg int size)
59 Void_t* sfsetbuf(f,buf,size)
60 reg Sfio_t* f; /* stream to be buffered */
61 reg Void_t* buf; /* new buffer */
62 reg int size; /* buffer size, -1 for default size */
69 reg int osize, oflags, blksize;
70 reg int justopen, init, okmmap, local;
75 { /* special case to get buffer info */
76 _Sfi = (f->flags&SF_MMAP) ? (f->endb-f->data) : f->size;
77 return (Void_t*)f->data;
80 /* cleanup actions already done, don't allow write buffering any more */
81 if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
84 if((init = f->mode&SF_INIT) )
85 { if(!f->pool && _sfsetpool(f) < 0)
88 else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
91 justopen = f->mode&SF_OPEN;
94 f->mode = (f->mode&SF_RDWR)|SF_LOCK;
98 /* make sure there is no hidden read data */
99 if((f->flags&(SF_PROCESS|SF_READ)) == (SF_PROCESS|SF_READ) &&
100 (f->mode&SF_WRITE) && _sfmode(f,SF_READ,local) < 0)
103 /* synchronize first */
104 SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
108 /* turn off the SF_SYNCED bit because buffer is changing */
109 f->mode &= ~SF_SYNCED;
117 /* see if memory mapping is possible (see sfwrite for SF_BOTH) */
118 okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1;
120 /* save old buffer info */
124 { (void)munmap((caddr_t)f->data,f->endb-f->data);
125 f->data = NIL(uchar*);
129 if(f->data == f->tiny)
130 { f->data = NIL(uchar*);
136 f->flags &= ~(SF_MMAP|SF_MALLOC);
138 /* pure read/string streams must have a valid string */
139 if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR && (size < 0 || !buf))
142 /* set disc to the first discipline with a seekf */
143 for(disc = f->disc; disc; disc = disc->disc)
147 if((init || local) && !(f->flags&SF_STRING))
148 { /* ASSERT(f->file >= 0) */
151 /* if has discipline, set size by discipline if possible */
153 { if((f->here = SFSK(f,0L,1,disc)) < 0)
156 { f->extent = SFSK(f,0L,2,disc);
157 (void)SFSK(f,f->here,0,disc);
162 /* get file descriptor status */
163 if(fstat(f->file,&st) < 0)
166 #if _stat_blksize /* preferred io block size */
167 if((blksize = (int)st.st_blksize) > 0)
168 while((blksize + (int)st.st_blksize) <= SF_PAGE)
169 blksize += (int)st.st_blksize;
171 if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
172 f->here = justopen ? 0L : SFSK(f,0L,1,f->disc);
175 { /* normal file, set file extent */
176 f->extent = (long)st.st_size;
178 /* don't MMAP directories */
179 if(S_ISDIR(st.st_mode) )
182 /* seekable std-devices are share-public by default */
183 if(f == sfstdin || f == sfstdout || f == sfstderr)
184 f->flags |= SF_SHARE|SF_PUBLIC;
193 { /* pipe std-devices are automatically shared */
194 if(S_ISFIFO(st.st_mode) )
195 { if(f == sfstdin || f == sfstdout || f == sfstderr) f->flags |= SF_SHARE;
197 else if(S_ISCHR(st.st_mode) )
198 { /* set line mode for terminals */
199 if(!(f->flags&SF_LINE) && isatty(f->file))
202 /* special case /dev/null for efficiency */
205 dev = (int)st.st_dev;
206 ino = (int)st.st_ino;
207 if(stat(DEVNULL,&st) >= 0 &&
208 dev == st.st_dev && ino == st.st_ino)
215 /* initialize save input buffer for r+w streams */
216 if(!(f->flags&SF_PROCESS) && (f->flags&SF_BOTH) )
217 (void)_sfpopen(f,-1,-1);
221 /* set page size, this is also the desired default buffer size */
224 _Sfpage = (int)getpagesize();
231 if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
232 { /* see if we can try memory mapping */
234 for(disc = f->disc; disc; disc = disc->disc)
238 { f->flags |= SF_MMAP;
240 { size = (blksize > 0 ? blksize : _Sfpage) * SF_NMAP;
241 size = ((size+_Sfpage-1)/_Sfpage)*_Sfpage;
247 /* get buffer space */
250 { /* define a default size suitable for block transfer */
251 if(init && osize > 0)
253 else if(f == sfstderr && (f->mode&SF_WRITE))
255 else if((f->flags&SF_STRING) || f->extent < 0)
259 else if((f->flags&(SF_READ|SF_BOTH)) == SF_READ &&
260 f->extent > 0 && f->extent < _Sfpage )
261 size = (((int)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
268 if(size > 0 && !buf && !(f->flags&SF_MMAP))
269 { /* try to allocate a buffer */
270 if(obuf && size == osize)
271 { buf = (Void_t*)obuf;
273 sf_malloc = (oflags&SF_MALLOC);
276 { /* do allocation */
277 while(!(buf = (Void_t*) malloc(size)) && size > 0)
280 sf_malloc = SF_MALLOC;
284 if(size == 0 && !(f->flags&(SF_MMAP|SF_STRING)) && (f->mode&SF_READ))
285 { /* use the internal buffer */
286 size = sizeof(f->tiny);
287 buf = (Void_t*)f->tiny;
290 /* set up new buffer */
292 f->next = f->data = f->endr = f->endw = (uchar*)buf;
293 f->endb = (f->mode&SF_READ) ? f->data : f->data+size;
294 if(f->flags&SF_STRING)
295 { /* these fields are used to test actual size - see sfseek() */
296 f->extent = (!sf_malloc && (f->flags&(SF_BOTH|SF_READ))) ? size : 0;
299 /* read+string stream should have all data available */
300 if((f->mode&SF_READ) && !sf_malloc)
301 f->endb = f->data+size;
304 f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
306 if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
307 { free((Void_t*)obuf);
311 _Sfi = obuf ? osize : 0;
315 return (Void_t*)obuf;