1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include "sfhdr.h"
2334f9b3eeSRoland Mainz static char* Version = "\n@(#)$Id: sfio (AT&T Labs - Research) 2009-09-15 $\0\n";
24da2e3ebdSchin
25da2e3ebdSchin /* Functions to set a given stream to some desired mode
26da2e3ebdSchin **
27da2e3ebdSchin ** Written by Kiem-Phong Vo.
28da2e3ebdSchin **
29da2e3ebdSchin ** Modifications:
30da2e3ebdSchin ** 06/27/1990 (first version)
31da2e3ebdSchin ** 01/06/1991
32da2e3ebdSchin ** 07/08/1991
33da2e3ebdSchin ** 06/18/1992
34da2e3ebdSchin ** 02/02/1993
35da2e3ebdSchin ** 05/25/1993
36da2e3ebdSchin ** 02/07/1994
37da2e3ebdSchin ** 05/21/1996
38da2e3ebdSchin ** 08/01/1997
39da2e3ebdSchin ** 08/01/1998 (extended formatting)
40da2e3ebdSchin ** 09/09/1999 (thread-safe)
41da2e3ebdSchin ** 02/01/2001 (adaptive buffering)
42da2e3ebdSchin ** 05/31/2002 (multi-byte handling in sfvprintf/vscanf)
43da2e3ebdSchin ** 09/06/2002 (SF_IOINTR flag)
44da2e3ebdSchin ** 11/15/2002 (%#c for sfvprintf)
45da2e3ebdSchin ** 05/31/2003 (sfsetbuf(f,f,align_size) to set alignment for data)
46da2e3ebdSchin ** (%I1d is fixed to handle "signed char" correctly)
47da2e3ebdSchin ** 01/01/2004 Porting issues to various platforms resolved.
487c2fbfb3SApril Chin ** 06/01/2008 Allowing notify() at entering/exiting thread-safe routines.
4934f9b3eeSRoland Mainz ** 09/15/2008 Add sfwalk().
50da2e3ebdSchin */
51da2e3ebdSchin
52da2e3ebdSchin /* the below is for protecting the application from SIGPIPE */
53da2e3ebdSchin #if _PACKAGE_ast
54da2e3ebdSchin #include <sig.h>
55da2e3ebdSchin #include <wait.h>
56da2e3ebdSchin #define Sfsignal_f Sig_handler_t
57da2e3ebdSchin #else
58da2e3ebdSchin #include <signal.h>
59da2e3ebdSchin typedef void(* Sfsignal_f)_ARG_((int));
60da2e3ebdSchin #endif
61da2e3ebdSchin static int _Sfsigp = 0; /* # of streams needing SIGPIPE protection */
62da2e3ebdSchin
63da2e3ebdSchin /* done at exiting time */
64da2e3ebdSchin #if __STD_C
_sfcleanup(void)65da2e3ebdSchin static void _sfcleanup(void)
66da2e3ebdSchin #else
67da2e3ebdSchin static void _sfcleanup()
68da2e3ebdSchin #endif
69da2e3ebdSchin {
70da2e3ebdSchin reg Sfpool_t* p;
71da2e3ebdSchin reg Sfio_t* f;
72da2e3ebdSchin reg int n;
73da2e3ebdSchin reg int pool;
74da2e3ebdSchin
75da2e3ebdSchin f = (Sfio_t*)Version; /* shut compiler warning */
76da2e3ebdSchin
77da2e3ebdSchin /* set this so that no more buffering is allowed for write streams */
78da2e3ebdSchin _Sfexiting = 1001;
79da2e3ebdSchin
80da2e3ebdSchin sfsync(NIL(Sfio_t*));
81da2e3ebdSchin
82da2e3ebdSchin for(p = &_Sfpool; p; p = p->next)
83da2e3ebdSchin { for(n = 0; n < p->n_sf; ++n)
84da2e3ebdSchin { if(!(f = p->sf[n]) || SFFROZEN(f) )
85da2e3ebdSchin continue;
86da2e3ebdSchin
87da2e3ebdSchin SFLOCK(f,0);
88da2e3ebdSchin SFMTXLOCK(f);
89da2e3ebdSchin
90da2e3ebdSchin /* let application know that we are leaving */
91da2e3ebdSchin (void)SFRAISE(f, SF_ATEXIT, NIL(Void_t*));
92da2e3ebdSchin
93da2e3ebdSchin if(f->flags&SF_STRING)
94da2e3ebdSchin continue;
95da2e3ebdSchin
96da2e3ebdSchin /* from now on, write streams are unbuffered */
97da2e3ebdSchin pool = f->mode&SF_POOL;
98da2e3ebdSchin f->mode &= ~SF_POOL;
99da2e3ebdSchin if((f->flags&SF_WRITE) && !(f->mode&SF_WRITE))
100da2e3ebdSchin (void)_sfmode(f,SF_WRITE,1);
101da2e3ebdSchin if(((f->bits&SF_MMAP) && f->data) ||
102da2e3ebdSchin ((f->mode&SF_WRITE) && f->next == f->data) )
103da2e3ebdSchin (void)SFSETBUF(f,NIL(Void_t*),0);
104da2e3ebdSchin f->mode |= pool;
105da2e3ebdSchin
106da2e3ebdSchin SFMTXUNLOCK(f);
107da2e3ebdSchin SFOPEN(f,0);
108da2e3ebdSchin }
109da2e3ebdSchin }
110da2e3ebdSchin }
111da2e3ebdSchin
112da2e3ebdSchin /* put into discrete pool */
113da2e3ebdSchin #if __STD_C
_sfsetpool(Sfio_t * f)114da2e3ebdSchin int _sfsetpool(Sfio_t* f)
115da2e3ebdSchin #else
116da2e3ebdSchin int _sfsetpool(f)
117da2e3ebdSchin Sfio_t* f;
118da2e3ebdSchin #endif
119da2e3ebdSchin {
120da2e3ebdSchin reg Sfpool_t* p;
121da2e3ebdSchin reg Sfio_t** array;
122da2e3ebdSchin reg int n, rv;
123da2e3ebdSchin
124da2e3ebdSchin if(!_Sfcleanup)
125da2e3ebdSchin { _Sfcleanup = _sfcleanup;
126da2e3ebdSchin (void)atexit(_sfcleanup);
127da2e3ebdSchin }
128da2e3ebdSchin
129da2e3ebdSchin if(!(p = f->pool) )
130da2e3ebdSchin p = f->pool = &_Sfpool;
131da2e3ebdSchin
1327c2fbfb3SApril Chin POOLMTXENTER(p);
133da2e3ebdSchin
134da2e3ebdSchin rv = -1;
135da2e3ebdSchin
136da2e3ebdSchin if(p->n_sf >= p->s_sf)
137da2e3ebdSchin { if(p->s_sf == 0) /* initialize pool array */
138da2e3ebdSchin { p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
139da2e3ebdSchin p->sf = p->array;
140da2e3ebdSchin }
141da2e3ebdSchin else /* allocate a larger array */
142da2e3ebdSchin { n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
143da2e3ebdSchin if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
144da2e3ebdSchin goto done;
145da2e3ebdSchin
146da2e3ebdSchin /* move old array to new one */
147da2e3ebdSchin memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
148da2e3ebdSchin if(p->sf != p->array)
149da2e3ebdSchin free((Void_t*)p->sf);
150da2e3ebdSchin
151da2e3ebdSchin p->sf = array;
152da2e3ebdSchin p->s_sf = n;
153da2e3ebdSchin }
154da2e3ebdSchin }
155da2e3ebdSchin
156da2e3ebdSchin /* always add at end of array because if this was done during some sort
157da2e3ebdSchin of walk thru all streams, we'll want the new stream to be seen.
158da2e3ebdSchin */
159da2e3ebdSchin p->sf[p->n_sf++] = f;
160da2e3ebdSchin rv = 0;
161da2e3ebdSchin
162da2e3ebdSchin done:
163da2e3ebdSchin POOLMTXRETURN(p, rv);
164da2e3ebdSchin }
165da2e3ebdSchin
166da2e3ebdSchin /* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
167da2e3ebdSchin #if __STD_C
_sfrsrv(reg Sfio_t * f,reg ssize_t size)168da2e3ebdSchin Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
169da2e3ebdSchin #else
170da2e3ebdSchin Sfrsrv_t* _sfrsrv(f,size)
171da2e3ebdSchin reg Sfio_t* f;
172da2e3ebdSchin reg ssize_t size;
173da2e3ebdSchin #endif
174da2e3ebdSchin {
175da2e3ebdSchin Sfrsrv_t *rsrv, *rs;
176da2e3ebdSchin
177da2e3ebdSchin /* make buffer if nothing yet */
178da2e3ebdSchin size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
179da2e3ebdSchin if(!(rsrv = f->rsrv) || size > rsrv->size)
180da2e3ebdSchin { if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
181da2e3ebdSchin size = -1;
182da2e3ebdSchin else
183da2e3ebdSchin { if(rsrv)
184da2e3ebdSchin { if(rsrv->slen > 0)
185da2e3ebdSchin memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
186da2e3ebdSchin free(rsrv);
187da2e3ebdSchin }
188da2e3ebdSchin f->rsrv = rsrv = rs;
189da2e3ebdSchin rsrv->size = size;
190da2e3ebdSchin rsrv->slen = 0;
191da2e3ebdSchin }
192da2e3ebdSchin }
193da2e3ebdSchin
194da2e3ebdSchin if(rsrv && size > 0)
195da2e3ebdSchin rsrv->slen = 0;
196da2e3ebdSchin
197da2e3ebdSchin return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
198da2e3ebdSchin }
199da2e3ebdSchin
200da2e3ebdSchin #ifdef SIGPIPE
201da2e3ebdSchin #if __STD_C
ignoresig(int sig)202da2e3ebdSchin static void ignoresig(int sig)
203da2e3ebdSchin #else
204da2e3ebdSchin static void ignoresig(sig)
205da2e3ebdSchin int sig;
206da2e3ebdSchin #endif
207da2e3ebdSchin {
208da2e3ebdSchin signal(sig, ignoresig);
209da2e3ebdSchin }
210da2e3ebdSchin #endif
211da2e3ebdSchin
212da2e3ebdSchin #if __STD_C
_sfpopen(reg Sfio_t * f,int fd,int pid,int stdio)213da2e3ebdSchin int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio)
214da2e3ebdSchin #else
215da2e3ebdSchin int _sfpopen(f, fd, pid, stdio)
216da2e3ebdSchin reg Sfio_t* f;
217da2e3ebdSchin int fd;
218da2e3ebdSchin int pid;
219da2e3ebdSchin int stdio; /* stdio popen() does not reset SIGPIPE handler */
220da2e3ebdSchin #endif
221da2e3ebdSchin {
222da2e3ebdSchin reg Sfproc_t* p;
223da2e3ebdSchin
224da2e3ebdSchin if(f->proc)
225da2e3ebdSchin return 0;
226da2e3ebdSchin
227da2e3ebdSchin if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
228da2e3ebdSchin return -1;
229da2e3ebdSchin
230da2e3ebdSchin p->pid = pid;
231da2e3ebdSchin p->size = p->ndata = 0;
232da2e3ebdSchin p->rdata = NIL(uchar*);
233da2e3ebdSchin p->file = fd;
234da2e3ebdSchin p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;
235da2e3ebdSchin
236da2e3ebdSchin #ifdef SIGPIPE /* protect from broken pipe signal */
237da2e3ebdSchin if(p->sigp)
238da2e3ebdSchin { Sfsignal_f handler;
239da2e3ebdSchin
240da2e3ebdSchin (void)vtmtxlock(_Sfmutex);
241da2e3ebdSchin if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
242da2e3ebdSchin handler != ignoresig)
243da2e3ebdSchin signal(SIGPIPE, handler); /* honor user handler */
244da2e3ebdSchin _Sfsigp += 1;
245da2e3ebdSchin (void)vtmtxunlock(_Sfmutex);
246da2e3ebdSchin }
247da2e3ebdSchin #endif
248da2e3ebdSchin
249da2e3ebdSchin return 0;
250da2e3ebdSchin }
251da2e3ebdSchin
252da2e3ebdSchin #if __STD_C
_sfpclose(reg Sfio_t * f)253da2e3ebdSchin int _sfpclose(reg Sfio_t* f)
254da2e3ebdSchin #else
255da2e3ebdSchin int _sfpclose(f)
256da2e3ebdSchin reg Sfio_t* f; /* stream to close */
257da2e3ebdSchin #endif
258da2e3ebdSchin {
259da2e3ebdSchin Sfproc_t* p;
260da2e3ebdSchin int pid, status;
261da2e3ebdSchin
262da2e3ebdSchin if(!(p = f->proc))
263da2e3ebdSchin return -1;
264da2e3ebdSchin f->proc = NIL(Sfproc_t*);
265da2e3ebdSchin
266da2e3ebdSchin if(p->rdata)
267da2e3ebdSchin free(p->rdata);
268da2e3ebdSchin
269da2e3ebdSchin if(p->pid < 0)
270da2e3ebdSchin status = 0;
271da2e3ebdSchin else
272da2e3ebdSchin { /* close the associated stream */
273da2e3ebdSchin if(p->file >= 0)
274da2e3ebdSchin CLOSE(p->file);
275da2e3ebdSchin
276da2e3ebdSchin /* wait for process termination */
277da2e3ebdSchin #if _PACKAGE_ast
278da2e3ebdSchin sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
279da2e3ebdSchin #endif
280da2e3ebdSchin while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR)
281da2e3ebdSchin ;
282da2e3ebdSchin if(pid == -1)
283da2e3ebdSchin status = -1;
284da2e3ebdSchin #if _PACKAGE_ast
285da2e3ebdSchin sigcritical(0);
286da2e3ebdSchin #endif
287da2e3ebdSchin
288da2e3ebdSchin #ifdef SIGPIPE
289da2e3ebdSchin (void)vtmtxlock(_Sfmutex);
290da2e3ebdSchin if(p->sigp && (_Sfsigp -= 1) <= 0)
291da2e3ebdSchin { Sfsignal_f handler;
292da2e3ebdSchin if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
293da2e3ebdSchin handler != ignoresig)
294da2e3ebdSchin signal(SIGPIPE,handler); /* honor user handler */
295da2e3ebdSchin _Sfsigp = 0;
296da2e3ebdSchin }
297da2e3ebdSchin (void)vtmtxunlock(_Sfmutex);
298da2e3ebdSchin #endif
299da2e3ebdSchin }
300da2e3ebdSchin
301da2e3ebdSchin free(p);
302da2e3ebdSchin return status;
303da2e3ebdSchin }
304da2e3ebdSchin
305da2e3ebdSchin #if __STD_C
_sfpmode(Sfio_t * f,int type)306da2e3ebdSchin static int _sfpmode(Sfio_t* f, int type)
307da2e3ebdSchin #else
308da2e3ebdSchin static int _sfpmode(f,type)
309da2e3ebdSchin Sfio_t* f;
310da2e3ebdSchin int type;
311da2e3ebdSchin #endif
312da2e3ebdSchin {
313da2e3ebdSchin Sfproc_t* p;
314da2e3ebdSchin
315da2e3ebdSchin if(!(p = f->proc) )
316da2e3ebdSchin return -1;
317da2e3ebdSchin
318da2e3ebdSchin if(type == SF_WRITE)
319da2e3ebdSchin { /* save unread data */
320da2e3ebdSchin p->ndata = f->endb-f->next;
321da2e3ebdSchin if(p->ndata > p->size)
322da2e3ebdSchin { if(p->rdata)
323da2e3ebdSchin free((char*)p->rdata);
324da2e3ebdSchin if((p->rdata = (uchar*)malloc(p->ndata)) )
325da2e3ebdSchin p->size = p->ndata;
326da2e3ebdSchin else
327da2e3ebdSchin { p->size = 0;
328da2e3ebdSchin return -1;
329da2e3ebdSchin }
330da2e3ebdSchin }
331da2e3ebdSchin if(p->ndata > 0)
332da2e3ebdSchin memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
333da2e3ebdSchin f->endb = f->data;
334da2e3ebdSchin }
335da2e3ebdSchin else
336da2e3ebdSchin { /* restore read data */
337da2e3ebdSchin if(p->ndata > f->size) /* may lose data!!! */
338da2e3ebdSchin p->ndata = f->size;
339da2e3ebdSchin if(p->ndata > 0)
340da2e3ebdSchin { memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
341da2e3ebdSchin f->endb = f->data+p->ndata;
342da2e3ebdSchin p->ndata = 0;
343da2e3ebdSchin }
344da2e3ebdSchin }
345da2e3ebdSchin
346da2e3ebdSchin /* switch file descriptor */
347da2e3ebdSchin if(p->pid >= 0)
348da2e3ebdSchin { type = f->file;
349da2e3ebdSchin f->file = p->file;
350da2e3ebdSchin p->file = type;
351da2e3ebdSchin }
352da2e3ebdSchin
353da2e3ebdSchin return 0;
354da2e3ebdSchin }
355da2e3ebdSchin
356da2e3ebdSchin #if __STD_C
_sfmode(reg Sfio_t * f,reg int wanted,reg int local)357da2e3ebdSchin int _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
358da2e3ebdSchin #else
359da2e3ebdSchin int _sfmode(f, wanted, local)
360da2e3ebdSchin reg Sfio_t* f; /* change r/w mode and sync file pointer for this stream */
361da2e3ebdSchin reg int wanted; /* desired mode */
362da2e3ebdSchin reg int local; /* a local call */
363da2e3ebdSchin #endif
364da2e3ebdSchin {
365da2e3ebdSchin reg int n;
366da2e3ebdSchin Sfoff_t addr;
367da2e3ebdSchin reg int rv = 0;
368da2e3ebdSchin
369da2e3ebdSchin SFONCE(); /* initialize mutexes */
370da2e3ebdSchin
371da2e3ebdSchin if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */
372da2e3ebdSchin { wanted &= ~SF_SYNCED;
373da2e3ebdSchin if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
374da2e3ebdSchin { f->next = f->endb = f->endr = f->data;
375da2e3ebdSchin f->mode &= ~SF_SYNCED;
376da2e3ebdSchin }
377da2e3ebdSchin }
378da2e3ebdSchin
379da2e3ebdSchin if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
380da2e3ebdSchin { if(local || !f->disc || !f->disc->exceptf)
381da2e3ebdSchin { local = 1;
382da2e3ebdSchin goto err_notify;
383da2e3ebdSchin }
384da2e3ebdSchin
385da2e3ebdSchin for(;;)
386da2e3ebdSchin { if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
387da2e3ebdSchin return rv;
388da2e3ebdSchin if((!local && SFFROZEN(f)) ||
389da2e3ebdSchin (!(f->flags&SF_STRING) && f->file < 0) )
390da2e3ebdSchin { if(rv == 0)
391da2e3ebdSchin { local = 1;
392da2e3ebdSchin goto err_notify;
393da2e3ebdSchin }
394da2e3ebdSchin else continue;
395da2e3ebdSchin }
396da2e3ebdSchin else break;
397da2e3ebdSchin }
398da2e3ebdSchin }
399da2e3ebdSchin
400da2e3ebdSchin if(f->mode&SF_GETR)
401da2e3ebdSchin { f->mode &= ~SF_GETR;
402da2e3ebdSchin #ifdef MAP_TYPE
403da2e3ebdSchin if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) )
404da2e3ebdSchin { /* turn off mmap to avoid page faulting */
405da2e3ebdSchin sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
406da2e3ebdSchin f->tiny[0] = 0;
407da2e3ebdSchin }
408da2e3ebdSchin else
409da2e3ebdSchin #endif
410da2e3ebdSchin if(f->getr)
411da2e3ebdSchin { f->next[-1] = f->getr;
412da2e3ebdSchin f->getr = 0;
413da2e3ebdSchin }
414da2e3ebdSchin }
415da2e3ebdSchin
416da2e3ebdSchin if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
417da2e3ebdSchin (*_Sfstdsync)(f);
418da2e3ebdSchin
419da2e3ebdSchin if(f->disc == _Sfudisc && wanted == SF_WRITE &&
420da2e3ebdSchin sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
421da2e3ebdSchin { local = 1;
422da2e3ebdSchin goto err_notify;
423da2e3ebdSchin }
424da2e3ebdSchin
425da2e3ebdSchin if(f->mode&SF_POOL)
426da2e3ebdSchin { /* move to head of pool */
427da2e3ebdSchin if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
428da2e3ebdSchin { local = 1;
429da2e3ebdSchin goto err_notify;
430da2e3ebdSchin }
431da2e3ebdSchin f->mode &= ~SF_POOL;
432da2e3ebdSchin }
433da2e3ebdSchin
434da2e3ebdSchin SFLOCK(f,local);
435da2e3ebdSchin
436da2e3ebdSchin /* buffer initialization */
437da2e3ebdSchin wanted &= SF_RDWR;
438da2e3ebdSchin if(f->mode&SF_INIT)
439da2e3ebdSchin {
440da2e3ebdSchin if(!f->pool && _sfsetpool(f) < 0)
441da2e3ebdSchin { rv = -1;
442da2e3ebdSchin goto done;
443da2e3ebdSchin }
444da2e3ebdSchin
445da2e3ebdSchin if(wanted == 0)
446da2e3ebdSchin goto done;
447da2e3ebdSchin
448da2e3ebdSchin if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
449da2e3ebdSchin goto err_notify;
450da2e3ebdSchin
451da2e3ebdSchin if((f->flags&SF_STRING) && f->size >= 0 && f->data)
452da2e3ebdSchin { f->mode &= ~SF_INIT;
453da2e3ebdSchin f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
454da2e3ebdSchin f->size : 0;
455da2e3ebdSchin f->here = 0;
456da2e3ebdSchin f->endb = f->data + f->size;
457da2e3ebdSchin f->next = f->endr = f->endw = f->data;
458da2e3ebdSchin if(f->mode&SF_READ)
459da2e3ebdSchin f->endr = f->endb;
460da2e3ebdSchin else f->endw = f->endb;
461da2e3ebdSchin }
462da2e3ebdSchin else
463da2e3ebdSchin { n = f->flags;
464da2e3ebdSchin (void)SFSETBUF(f,f->data,f->size);
465da2e3ebdSchin f->flags |= (n&SF_MALLOC);
466da2e3ebdSchin }
467da2e3ebdSchin }
468da2e3ebdSchin
469da2e3ebdSchin if(wanted == (int)SFMODE(f,1))
470da2e3ebdSchin goto done;
471da2e3ebdSchin
472da2e3ebdSchin switch(SFMODE(f,1))
473da2e3ebdSchin {
474da2e3ebdSchin case SF_WRITE: /* switching to SF_READ */
475da2e3ebdSchin if(wanted == 0 || wanted == SF_WRITE)
476da2e3ebdSchin break;
477da2e3ebdSchin if(!(f->flags&SF_READ) )
478da2e3ebdSchin goto err_notify;
479da2e3ebdSchin else if(f->flags&SF_STRING)
480da2e3ebdSchin { SFSTRSIZE(f);
481da2e3ebdSchin f->endb = f->data+f->extent;
482da2e3ebdSchin f->mode = SF_READ;
483da2e3ebdSchin break;
484da2e3ebdSchin }
485da2e3ebdSchin
486da2e3ebdSchin /* reset buffer */
487da2e3ebdSchin if(f->next > f->data && SFFLSBUF(f,-1) < 0)
488da2e3ebdSchin goto err_notify;
489da2e3ebdSchin
490da2e3ebdSchin if(f->size == 0)
491da2e3ebdSchin { /* unbuffered */
492da2e3ebdSchin f->data = f->tiny;
493da2e3ebdSchin f->size = sizeof(f->tiny);
494da2e3ebdSchin }
495da2e3ebdSchin f->next = f->endr = f->endw = f->endb = f->data;
496da2e3ebdSchin f->mode = SF_READ|SF_LOCK;
497da2e3ebdSchin
498da2e3ebdSchin /* restore saved read data for coprocess */
499da2e3ebdSchin if(f->proc && _sfpmode(f,wanted) < 0)
500da2e3ebdSchin goto err_notify;
501da2e3ebdSchin
502da2e3ebdSchin break;
503da2e3ebdSchin
504da2e3ebdSchin case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
505da2e3ebdSchin if(wanted != SF_WRITE)
506da2e3ebdSchin { /* just reset the pointers */
507da2e3ebdSchin f->mode = SF_READ|SF_LOCK;
508da2e3ebdSchin
509da2e3ebdSchin /* see if must go with new physical location */
510da2e3ebdSchin if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
511da2e3ebdSchin (addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
512da2e3ebdSchin {
513da2e3ebdSchin #ifdef MAP_TYPE
514da2e3ebdSchin if((f->bits&SF_MMAP) && f->data)
515da2e3ebdSchin { SFMUNMAP(f,f->data,f->endb-f->data);
516da2e3ebdSchin f->data = NIL(uchar*);
517da2e3ebdSchin }
518da2e3ebdSchin #endif
519da2e3ebdSchin f->endb = f->endr = f->endw = f->next = f->data;
520da2e3ebdSchin f->here = addr;
521da2e3ebdSchin }
522da2e3ebdSchin else
523da2e3ebdSchin { addr = f->here + (f->endb - f->next);
524da2e3ebdSchin if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
525da2e3ebdSchin goto err_notify;
526da2e3ebdSchin f->here = addr;
527da2e3ebdSchin }
528da2e3ebdSchin
529da2e3ebdSchin break;
530da2e3ebdSchin }
531da2e3ebdSchin /* fall thru */
532da2e3ebdSchin
533da2e3ebdSchin case SF_READ: /* switching to SF_WRITE */
534da2e3ebdSchin if(wanted != SF_WRITE)
535da2e3ebdSchin break;
536da2e3ebdSchin else if(!(f->flags&SF_WRITE))
537da2e3ebdSchin goto err_notify;
538da2e3ebdSchin else if(f->flags&SF_STRING)
539da2e3ebdSchin { f->endb = f->data+f->size;
540da2e3ebdSchin f->mode = SF_WRITE|SF_LOCK;
541da2e3ebdSchin break;
542da2e3ebdSchin }
543da2e3ebdSchin
544da2e3ebdSchin /* save unread data before switching mode */
545da2e3ebdSchin if(f->proc && _sfpmode(f,wanted) < 0)
546da2e3ebdSchin goto err_notify;
547da2e3ebdSchin
548da2e3ebdSchin /* reset buffer and seek pointer */
549da2e3ebdSchin if(!(f->mode&SF_SYNCED) )
550da2e3ebdSchin { n = f->endb - f->next;
551da2e3ebdSchin if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
552da2e3ebdSchin { /* reset file pointer */
553da2e3ebdSchin addr = f->here - n;
554da2e3ebdSchin if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
555da2e3ebdSchin goto err_notify;
556da2e3ebdSchin f->here = addr;
557da2e3ebdSchin }
558da2e3ebdSchin }
559da2e3ebdSchin
560da2e3ebdSchin f->mode = SF_WRITE|SF_LOCK;
561da2e3ebdSchin #ifdef MAP_TYPE
562da2e3ebdSchin if(f->bits&SF_MMAP)
563da2e3ebdSchin { if(f->data)
564da2e3ebdSchin SFMUNMAP(f,f->data,f->endb-f->data);
565da2e3ebdSchin (void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
566da2e3ebdSchin }
567da2e3ebdSchin #endif
568da2e3ebdSchin if(f->data == f->tiny)
569da2e3ebdSchin { f->endb = f->data = f->next = NIL(uchar*);
570da2e3ebdSchin f->size = 0;
571da2e3ebdSchin }
572da2e3ebdSchin else f->endb = (f->next = f->data) + f->size;
573da2e3ebdSchin
574da2e3ebdSchin break;
575da2e3ebdSchin
576da2e3ebdSchin default: /* unknown case */
577da2e3ebdSchin err_notify:
578da2e3ebdSchin if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
579da2e3ebdSchin wanted = SF_READ;
580da2e3ebdSchin
581da2e3ebdSchin /* set errno for operations that access wrong stream type */
582da2e3ebdSchin if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
583da2e3ebdSchin errno = EBADF;
584da2e3ebdSchin
585da2e3ebdSchin if(_Sfnotify) /* notify application of the error */
5867c2fbfb3SApril Chin (*_Sfnotify)(f, wanted, (void*)((long)f->file));
587da2e3ebdSchin
588da2e3ebdSchin rv = -1;
589da2e3ebdSchin break;
590da2e3ebdSchin }
591da2e3ebdSchin
592da2e3ebdSchin done:
593da2e3ebdSchin SFOPEN(f,local);
594da2e3ebdSchin return rv;
595da2e3ebdSchin }
596