ab0a8b8916b0d898cc79678f893c589970225fdd
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / sfio / sfsetbuf.c
1 /* $XConsortium: sfsetbuf.c /main/3 1995/11/01 18:35:58 rswiston $ */
2 /***************************************************************
3 *                                                              *
4 *                      AT&T - PROPRIETARY                      *
5 *                                                              *
6 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
7 *                          AT&T CORP.                          *
8 *                                                              *
9 *                Copyright (c) 1995 AT&T Corp.                 *
10 *                     All Rights Reserved                      *
11 *                                                              *
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        *
15 *                                                              *
16 *               This software was created by the               *
17 *           Software Engineering Research Department           *
18 *                    AT&T Bell Laboratories                    *
19 *                                                              *
20 *               For further information contact                *
21 *                     gsf@research.att.com                     *
22 *                                                              *
23 ***************************************************************/
24 #include        "sfhdr.h"
25
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.
30 **
31 **      Written by Kiem-Phong Vo (06/27/90)
32 */
33
34 #if __STD_C
35 Void_t* sfsetbuf(reg Sfio_t* f, reg Void_t* buf, reg int size)
36 #else
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 */
41 #endif
42 {
43         reg int         sf_malloc;
44         struct stat     st;
45         reg uchar*      obuf;
46         reg Sfdisc_t*   disc;
47         reg int         osize, oflags, blksize;
48         reg int         justopen, init, okmmap, local;
49
50         GETLOCAL(f,local);
51
52         if(size == 0 && buf)
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;
56         }
57
58         /* cleanup actions already done, don't allow write buffering any more */
59         if(_Sfexiting && !(f->flags&SF_STRING) && (f->mode&SF_WRITE))
60                 return NIL(Void_t*);
61
62         if((init = f->mode&SF_INIT) )
63         {       if(!f->pool && _sfsetpool(f) < 0)
64                         return NIL(Void_t*);
65         }
66         else if((f->mode&SF_RDWR) != SFMODE(f,local) && _sfmode(f,0,local) < 0)
67                 return NIL(Void_t*);
68
69         justopen = f->mode&SF_OPEN;
70         f->mode &= ~SF_OPEN;
71         if(init)
72                 f->mode = (f->mode&SF_RDWR)|SF_LOCK;
73         else
74         {       int     rv;
75
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)
79                         return NIL(Void_t*);
80
81                 /* synchronize first */
82                 SFLOCK(f,local); rv = SFSYNC(f); SFOPEN(f,local);
83                 if(rv < 0)
84                         return NIL(Void_t*);
85
86                 /* turn off the SF_SYNCED bit because buffer is changing */
87                 f->mode &= ~SF_SYNCED;
88         }
89
90         SFLOCK(f,local);
91
92         blksize = 0;
93         oflags = f->flags;
94
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;
97
98         /* save old buffer info */
99 #ifdef MAP_TYPE
100         if(f->flags&SF_MMAP)
101         {       if(f->data)
102                 {       (void)munmap((caddr_t)f->data,f->endb-f->data);
103                         f->data = NIL(uchar*);
104                 }
105         } else
106 #endif
107         if(f->data == f->tiny)
108         {       f->data = NIL(uchar*);
109                 f->size = 0;
110         }
111         obuf  = f->data;
112         osize = f->size;
113
114         f->flags &= ~(SF_MMAP|SF_MALLOC);
115
116         /* pure read/string streams must have a valid string */
117         if((f->flags&(SF_RDWR|SF_STRING)) == SF_RDSTR && (size < 0 || !buf))
118                 size = 0;
119
120         /* set disc to the first discipline with a seekf */
121         for(disc = f->disc; disc; disc = disc->disc)
122                 if(disc->seekf)
123                         break;
124
125         if((init || local) && !(f->flags&SF_STRING))
126         {       /* ASSERT(f->file >= 0) */
127                 st.st_mode = 0;
128
129                 /* if has discipline, set size by discipline if possible */
130                 if(disc)
131                 {       if((f->here = SFSK(f,0L,1,disc)) < 0)
132                                 goto unseekable;
133                         else
134                         {       f->extent = SFSK(f,0L,2,disc);
135                                 (void)SFSK(f,f->here,0,disc);
136                                 goto setbuf;
137                         }
138                 }
139
140                 /* get file descriptor status */
141                 if(fstat(f->file,&st) < 0)
142                         goto unseekable;
143
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;
148 #endif
149                 if(S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
150                         f->here = justopen ? 0L : SFSK(f,0L,1,f->disc);
151                 else    f->here = -1;
152                 if(f->here >= 0)
153                 {       /* normal file, set file extent */
154                         f->extent = (long)st.st_size;
155
156                         /* don't MMAP directories */
157                         if(S_ISDIR(st.st_mode) )
158                                 okmmap = 0;
159
160                         /* seekable std-devices are share-public by default */
161                         if(f == sfstdin || f == sfstdout || f == sfstderr)
162                                 f->flags |= SF_SHARE|SF_PUBLIC;
163                 }
164                 else
165                 {
166                 unseekable:
167                         f->extent = -1L;
168                         f->here = 0L;
169
170                         if(init)
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;
174                                 }
175                                 else if(S_ISCHR(st.st_mode) )
176                                 {       /* set line mode for terminals */
177                                         if(!(f->flags&SF_LINE) && isatty(f->file))
178                                                 f->flags |= SF_LINE;
179         
180                                         /* special case /dev/null for efficiency */
181                                         else
182                                         {       reg int dev, ino;
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)
187                                                 {       SFSETNULL(f);
188                                                         blksize = 1024;
189                                                 }
190                                         }
191                                 }
192
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);
196                         }
197                 }
198
199                 /* set page size, this is also the desired default buffer size */
200 #if _lib_getpagesize
201                 if(_Sfpage <= 0)
202                         _Sfpage = (int)getpagesize();
203 #endif
204                 if(_Sfpage <= 0)
205                         _Sfpage = SF_PAGE;
206         }
207
208 #ifdef MAP_TYPE
209         if(okmmap && size && (f->mode&SF_READ) && f->extent >= 0 )
210         {       /* see if we can try memory mapping */
211                 if(!disc)
212                         for(disc = f->disc; disc; disc = disc->disc)
213                                 if(disc->readf)
214                                         break;
215                 if(!disc)
216                 {       f->flags |= SF_MMAP;
217                         if(size < 0)
218                         {       size = (blksize > 0 ? blksize : _Sfpage) * SF_NMAP;
219                                 size = ((size+_Sfpage-1)/_Sfpage)*_Sfpage;
220                         }
221                 }
222         }
223 #endif
224
225         /* get buffer space */
226 setbuf:
227         if(size < 0)
228         {       /* define a default size suitable for block transfer */
229                 if(init && osize > 0)
230                         size = osize;
231                 else if(f == sfstderr && (f->mode&SF_WRITE))
232                         size = 0;
233                 else if((f->flags&SF_STRING) || f->extent < 0)
234                         size = SF_GRAIN;
235                 else if(blksize > 0)
236                         size = blksize;
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;
240                 else    size = _Sfpage;
241
242                 buf = NIL(Void_t*);
243         }
244
245         sf_malloc = 0;
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;
250                         obuf = NIL(uchar*);
251                         sf_malloc = (oflags&SF_MALLOC);
252                 }
253                 if(!buf)
254                 {       /* do allocation */
255                         while(!(buf = (Void_t*) malloc(size)) && size > 0)
256                                 size /= 2;
257                         if(size > 0)
258                                 sf_malloc = SF_MALLOC;
259                 }
260         }
261
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;
266         }
267
268         /* set up new buffer */
269         f->size = size;
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;
275                 f->here = 0L;
276
277                 /* read+string stream should have all data available */
278                 if((f->mode&SF_READ) && !sf_malloc)
279                         f->endb = f->data+size;
280         }
281
282         f->flags = (f->flags & ~SF_MALLOC)|sf_malloc;
283
284         if(obuf && obuf != f->data && osize > 0 && (oflags&SF_MALLOC))
285         {       free((Void_t*)obuf);
286                 obuf = NIL(uchar*);
287         }
288
289         _Sfi = obuf ? osize : 0;
290
291         SFOPEN(f,local);
292
293         return (Void_t*)obuf;
294 }