Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / sfio / sfsetbuf.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
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
22  */
23 /* $XConsortium: sfsetbuf.c /main/3 1995/11/01 18:35:58 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
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        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46 #include        "sfhdr.h"
47
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.
52 **
53 **      Written by Kiem-Phong Vo (06/27/90)
54 */
55
56 #if __STD_C
57 Void_t* sfsetbuf(reg Sfio_t* f, reg Void_t* buf, reg int size)
58 #else
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 */
63 #endif
64 {
65         reg int         sf_malloc;
66         struct stat     st;
67         reg uchar*      obuf;
68         reg Sfdisc_t*   disc;
69         reg int         osize, oflags, blksize;
70         reg int         justopen, init, okmmap, local;
71
72         GETLOCAL(f,local);
73
74         if(size == 0 && buf)
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;
78         }
79
80         /* cleanup actions already done, don't allow write buffering any more */
81         if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
82                 return NIL(Void_t*);
83
84         if((init = f->mode&SF_INIT) )
85         {       if(!f->pool && _sfsetpool(f) < 0)
86                         return NIL(Void_t*);
87         }
88         else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
89                 return NIL(Void_t*);
90
91         justopen = f->mode&SF_OPEN;
92         f->mode &= ~SF_OPEN;
93         if(init)
94                 f->mode = (f->mode&SF_RDWR)|SF_LOCK;
95         else
96         {       int     rv;
97
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)
101                         return NIL(Void_t*);
102
103                 /* synchronize first */
104                 SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
105                 if(rv < 0)
106                         return NIL(Void_t*);
107
108                 /* turn off the SF_SYNCED bit because buffer is changing */
109                 f->mode &= ~SF_SYNCED;
110         }
111
112         SFLOCK(f,local);
113
114         blksize = 0;
115         oflags = f->flags;
116
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;
119
120         /* save old buffer info */
121 #ifdef MAP_TYPE
122         if(f->flags&SF_MMAP)
123         {       if(f->data)
124                 {       (void)munmap((caddr_t)f->data,f->endb-f->data);
125                         f->data = NIL(uchar*);
126                 }
127         } else
128 #endif
129         if(f->data == f->tiny)
130         {       f->data = NIL(uchar*);
131                 f->size = 0;
132         }
133         obuf  = f->data;
134         osize = f->size;
135
136         f->flags &= ~(SF_MMAP|SF_MALLOC);
137
138         /* pure read/string streams must have a valid string */
139         if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR && (size < 0 || !buf))
140                 size = 0;
141
142         /* set disc to the first discipline with a seekf */
143         for(disc = f->disc; disc; disc = disc->disc)
144                 if(disc->seekf)
145                         break;
146
147         if((init || local) && !(f->flags&SF_STRING))
148         {       /* ASSERT(f->file >= 0) */
149                 st.st_mode = 0;
150
151                 /* if has discipline, set size by discipline if possible */
152                 if(disc)
153                 {       if((f->here = SFSK(f,0L,1,disc)) < 0)
154                                 goto unseekable;
155                         else
156                         {       f->extent = SFSK(f,0L,2,disc);
157                                 (void)SFSK(f,f->here,0,disc);
158                                 goto setbuf;
159                         }
160                 }
161
162                 /* get file descriptor status */
163                 if(fstat(f->file,&st) < 0)
164                         goto unseekable;
165
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;
170 #endif
171                 if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
172                         f->here = justopen ? 0L : SFSK(f,0L,1,f->disc);
173                 else    f->here = -1;
174                 if(f->here >= 0)
175                 {       /* normal file, set file extent */
176                         f->extent = (long)st.st_size;
177
178                         /* don't MMAP directories */
179                         if(S_ISDIR(st.st_mode) )
180                                 okmmap = 0;
181
182                         /* seekable std-devices are share-public by default */
183                         if(f == sfstdin || f == sfstdout || f == sfstderr)
184                                 f->flags |= SF_SHARE|SF_PUBLIC;
185                 }
186                 else
187                 {
188                 unseekable:
189                         f->extent = -1L;
190                         f->here = 0L;
191
192                         if(init)
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;
196                                 }
197                                 else if(S_ISCHR(st.st_mode) )
198                                 {       /* set line mode for terminals */
199                                         if(!(f->flags&SF_LINE) && isatty(f->file))
200                                                 f->flags |= SF_LINE;
201         
202                                         /* special case /dev/null for efficiency */
203                                         else
204                                         {       reg int dev, ino;
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)
209                                                 {       SFSETNULL(f);
210                                                         blksize = 1024;
211                                                 }
212                                         }
213                                 }
214
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);
218                         }
219                 }
220
221                 /* set page size, this is also the desired default buffer size */
222 #if _lib_getpagesize
223                 if(_Sfpage <= 0)
224                         _Sfpage = (int)getpagesize();
225 #endif
226                 if(_Sfpage <= 0)
227                         _Sfpage = SF_PAGE;
228         }
229
230 #ifdef MAP_TYPE
231         if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
232         {       /* see if we can try memory mapping */
233                 if(!disc)
234                         for(disc = f->disc; disc; disc = disc->disc)
235                                 if(disc->readf)
236                                         break;
237                 if(!disc)
238                 {       f->flags |= SF_MMAP;
239                         if(size < 0)
240                         {       size = (blksize > 0 ? blksize : _Sfpage) * SF_NMAP;
241                                 size = ((size+_Sfpage-1)/_Sfpage)*_Sfpage;
242                         }
243                 }
244         }
245 #endif
246
247         /* get buffer space */
248 setbuf:
249         if(size < 0)
250         {       /* define a default size suitable for block transfer */
251                 if(init && osize > 0)
252                         size = osize;
253                 else if(f == sfstderr && (f->mode&SF_WRITE))
254                         size = 0;
255                 else if((f->flags&SF_STRING) || f->extent < 0)
256                         size = SF_GRAIN;
257                 else if(blksize > 0)
258                         size = blksize;
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;
262                 else    size = _Sfpage;
263
264                 buf = NIL(Void_t*);
265         }
266
267         sf_malloc = 0;
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;
272                         obuf = NIL(uchar*);
273                         sf_malloc = (oflags&SF_MALLOC);
274                 }
275                 if(!buf)
276                 {       /* do allocation */
277                         while(!(buf = (Void_t*) malloc(size)) && size > 0)
278                                 size /= 2;
279                         if(size > 0)
280                                 sf_malloc = SF_MALLOC;
281                 }
282         }
283
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;
288         }
289
290         /* set up new buffer */
291         f->size = size;
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;
297                 f->here = 0L;
298
299                 /* read+string stream should have all data available */
300                 if((f->mode&SF_READ) && !sf_malloc)
301                         f->endb = f->data+size;
302         }
303
304         f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
305
306         if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
307         {       free((Void_t*)obuf);
308                 obuf = NIL(uchar*);
309         }
310
311         _Sfi = obuf ? osize : 0;
312
313         SFOPEN(f,local);
314
315         return (Void_t*)obuf;
316 }