1 /* $XConsortium: sfsetbuf.c /main/3 1995/11/01 18:35:58 rswiston $ */
2 /***************************************************************
6 * THIS IS PROPRIETARY SOURCE CODE LICENSED BY *
9 * Copyright (c) 1995 AT&T Corp. *
10 * All Rights Reserved *
12 * This software is licensed by AT&T Corp. *
13 * under the terms and conditions of the license in *
14 * http://www.research.att.com/orgs/ssr/book/reuse *
16 * This software was created by the *
17 * Software Engineering Research Department *
18 * AT&T Bell Laboratories *
20 * For further information contact *
21 * gsf@research.att.com *
23 ***************************************************************/
26 /* Set a (new) buffer for a stream.
27 ** If size < 0, it is assigned a suitable value depending on the
28 ** kind of stream. The actual buffer size allocated is dependent
29 ** on how much memory is available.
31 ** Written by Kiem-Phong Vo (06/27/90)
35 Void_t* sfsetbuf(reg Sfio_t* f, reg Void_t* buf, reg int size)
37 Void_t* sfsetbuf(f,buf,size)
38 reg Sfio_t* f; /* stream to be buffered */
39 reg Void_t* buf; /* new buffer */
40 reg int size; /* buffer size, -1 for default size */
47 reg int osize, oflags, blksize;
48 reg int justopen, init, okmmap, local;
53 { /* special case to get buffer info */
54 _Sfi = (f->flags&SF_MMAP) ? (f->endb-f->data) : f->size;
55 return (Void_t*)f->data;
58 /* cleanup actions already done, don't allow write buffering any more */
59 if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
62 if((init = f->mode&SF_INIT) )
63 { if(!f->pool && _sfsetpool(f) < 0)
66 else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
69 justopen = f->mode&SF_OPEN;
72 f->mode = (f->mode&SF_RDWR)|SF_LOCK;
76 /* make sure there is no hidden read data */
77 if((f->flags&(SF_PROCESS|SF_READ)) == (SF_PROCESS|SF_READ) &&
78 (f->mode&SF_WRITE) && _sfmode(f,SF_READ,local) < 0)
81 /* synchronize first */
82 SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
86 /* turn off the SF_SYNCED bit because buffer is changing */
87 f->mode &= ~SF_SYNCED;
95 /* see if memory mapping is possible (see sfwrite for SF_BOTH) */
96 okmmap = (buf || (f->flags&SF_STRING) || (f->flags&SF_RDWR) == SF_RDWR) ? 0 : 1;
98 /* save old buffer info */
102 { (void)munmap((caddr_t)f->data,f->endb-f->data);
103 f->data = NIL(uchar*);
107 if(f->data == f->tiny)
108 { f->data = NIL(uchar*);
114 f->flags &= ~(SF_MMAP|SF_MALLOC);
116 /* pure read/string streams must have a valid string */
117 if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR && (size < 0 || !buf))
120 /* set disc to the first discipline with a seekf */
121 for(disc = f->disc; disc; disc = disc->disc)
125 if((init || local) && !(f->flags&SF_STRING))
126 { /* ASSERT(f->file >= 0) */
129 /* if has discipline, set size by discipline if possible */
131 { if((f->here = SFSK(f,0L,1,disc)) < 0)
134 { f->extent = SFSK(f,0L,2,disc);
135 (void)SFSK(f,f->here,0,disc);
140 /* get file descriptor status */
141 if(fstat(f->file,&st) < 0)
144 #if _stat_blksize /* preferred io block size */
145 if((blksize = (int)st.st_blksize) > 0)
146 while((blksize + (int)st.st_blksize) <= SF_PAGE)
147 blksize += (int)st.st_blksize;
149 if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
150 f->here = justopen ? 0L : SFSK(f,0L,1,f->disc);
153 { /* normal file, set file extent */
154 f->extent = (long)st.st_size;
156 /* don't MMAP directories */
157 if(S_ISDIR(st.st_mode) )
160 /* seekable std-devices are share-public by default */
161 if(f == sfstdin || f == sfstdout || f == sfstderr)
162 f->flags |= SF_SHARE|SF_PUBLIC;
171 { /* pipe std-devices are automatically shared */
172 if(S_ISFIFO(st.st_mode) )
173 { if(f == sfstdin || f == sfstdout || f == sfstderr) f->flags |= SF_SHARE;
175 else if(S_ISCHR(st.st_mode) )
176 { /* set line mode for terminals */
177 if(!(f->flags&SF_LINE) && isatty(f->file))
180 /* special case /dev/null for efficiency */
183 dev = (int)st.st_dev;
184 ino = (int)st.st_ino;
185 if(stat(DEVNULL,&st) >= 0 &&
186 dev == st.st_dev && ino == st.st_ino)
193 /* initialize save input buffer for r+w streams */
194 if(!(f->flags&SF_PROCESS) && (f->flags&SF_BOTH) )
195 (void)_sfpopen(f,-1,-1);
199 /* set page size, this is also the desired default buffer size */
202 _Sfpage = (int)getpagesize();
209 if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
210 { /* see if we can try memory mapping */
212 for(disc = f->disc; disc; disc = disc->disc)
216 { f->flags |= SF_MMAP;
218 { size = (blksize > 0 ? blksize : _Sfpage) * SF_NMAP;
219 size = ((size+_Sfpage-1)/_Sfpage)*_Sfpage;
225 /* get buffer space */
228 { /* define a default size suitable for block transfer */
229 if(init && osize > 0)
231 else if(f == sfstderr && (f->mode&SF_WRITE))
233 else if((f->flags&SF_STRING) || f->extent < 0)
237 else if((f->flags&(SF_READ|SF_BOTH)) == SF_READ &&
238 f->extent > 0 && f->extent < _Sfpage )
239 size = (((int)f->extent + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
246 if(size > 0 && !buf && !(f->flags&SF_MMAP))
247 { /* try to allocate a buffer */
248 if(obuf && size == osize)
249 { buf = (Void_t*)obuf;
251 sf_malloc = (oflags&SF_MALLOC);
254 { /* do allocation */
255 while(!(buf = (Void_t*) malloc(size)) && size > 0)
258 sf_malloc = SF_MALLOC;
262 if(size == 0 && !(f->flags&(SF_MMAP|SF_STRING)) && (f->mode&SF_READ))
263 { /* use the internal buffer */
264 size = sizeof(f->tiny);
265 buf = (Void_t*)f->tiny;
268 /* set up new buffer */
270 f->next = f->data = f->endr = f->endw = (uchar*)buf;
271 f->endb = (f->mode&SF_READ) ? f->data : f->data+size;
272 if(f->flags&SF_STRING)
273 { /* these fields are used to test actual size - see sfseek() */
274 f->extent = (!sf_malloc && (f->flags&(SF_BOTH|SF_READ))) ? size : 0;
277 /* read+string stream should have all data available */
278 if((f->mode&SF_READ) && !sf_malloc)
279 f->endb = f->data+size;
282 f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
284 if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
285 { free((Void_t*)obuf);
289 _Sfi = obuf ? osize : 0;
293 return (Void_t*)obuf;