1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2012 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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);
101*b30d1939SAndy Fiddaman 			if(f->data &&
102*b30d1939SAndy Fiddaman 			   ((f->bits&SF_MMAP) ||
103*b30d1939SAndy Fiddaman 			    ((f->mode&SF_WRITE) && f->next == f->data) ) )
104da2e3ebdSchin 				(void)SFSETBUF(f,NIL(Void_t*),0);
105da2e3ebdSchin 			f->mode |= pool;
106da2e3ebdSchin 
107da2e3ebdSchin 			SFMTXUNLOCK(f);
108da2e3ebdSchin 			SFOPEN(f,0);
109da2e3ebdSchin 		}
110da2e3ebdSchin 	}
111da2e3ebdSchin }
112da2e3ebdSchin 
113da2e3ebdSchin /* put into discrete pool */
114da2e3ebdSchin #if __STD_C
_sfsetpool(Sfio_t * f)115da2e3ebdSchin int _sfsetpool(Sfio_t* f)
116da2e3ebdSchin #else
117da2e3ebdSchin int _sfsetpool(f)
118da2e3ebdSchin Sfio_t*	f;
119da2e3ebdSchin #endif
120da2e3ebdSchin {
121da2e3ebdSchin 	reg Sfpool_t*	p;
122da2e3ebdSchin 	reg Sfio_t**	array;
123da2e3ebdSchin 	reg int		n, rv;
124da2e3ebdSchin 
125da2e3ebdSchin 	if(!_Sfcleanup)
126da2e3ebdSchin 	{	_Sfcleanup = _sfcleanup;
127da2e3ebdSchin 		(void)atexit(_sfcleanup);
128da2e3ebdSchin 	}
129da2e3ebdSchin 
130da2e3ebdSchin 	if(!(p = f->pool) )
131da2e3ebdSchin 		p = f->pool = &_Sfpool;
132da2e3ebdSchin 
1337c2fbfb3SApril Chin 	POOLMTXENTER(p);
134da2e3ebdSchin 
135da2e3ebdSchin 	rv = -1;
136da2e3ebdSchin 
137da2e3ebdSchin 	if(p->n_sf >= p->s_sf)
138da2e3ebdSchin 	{	if(p->s_sf == 0) /* initialize pool array */
139da2e3ebdSchin 		{	p->s_sf = sizeof(p->array)/sizeof(p->array[0]);
140da2e3ebdSchin 			p->sf = p->array;
141da2e3ebdSchin 		}
142da2e3ebdSchin 		else	/* allocate a larger array */
143da2e3ebdSchin 		{	n = (p->sf != p->array ? p->s_sf : (p->s_sf/4 + 1)*4) + 4;
144da2e3ebdSchin 			if(!(array = (Sfio_t**)malloc(n*sizeof(Sfio_t*))) )
145da2e3ebdSchin 				goto done;
146da2e3ebdSchin 
147da2e3ebdSchin 			/* move old array to new one */
148da2e3ebdSchin 			memcpy((Void_t*)array,(Void_t*)p->sf,p->n_sf*sizeof(Sfio_t*));
149da2e3ebdSchin 			if(p->sf != p->array)
150da2e3ebdSchin 				free((Void_t*)p->sf);
151da2e3ebdSchin 
152da2e3ebdSchin 			p->sf = array;
153da2e3ebdSchin 			p->s_sf = n;
154da2e3ebdSchin 		}
155da2e3ebdSchin 	}
156da2e3ebdSchin 
157da2e3ebdSchin 	/* always add at end of array because if this was done during some sort
158da2e3ebdSchin 	   of walk thru all streams, we'll want the new stream to be seen.
159da2e3ebdSchin 	*/
160da2e3ebdSchin 	p->sf[p->n_sf++] = f;
161da2e3ebdSchin 	rv = 0;
162da2e3ebdSchin 
163da2e3ebdSchin done:
164da2e3ebdSchin 	POOLMTXRETURN(p, rv);
165da2e3ebdSchin }
166da2e3ebdSchin 
167da2e3ebdSchin /* create an auxiliary buffer for sfgetr/sfreserve/sfputr */
168da2e3ebdSchin #if __STD_C
_sfrsrv(reg Sfio_t * f,reg ssize_t size)169da2e3ebdSchin Sfrsrv_t* _sfrsrv(reg Sfio_t* f, reg ssize_t size)
170da2e3ebdSchin #else
171da2e3ebdSchin Sfrsrv_t* _sfrsrv(f,size)
172da2e3ebdSchin reg Sfio_t*	f;
173da2e3ebdSchin reg ssize_t	size;
174da2e3ebdSchin #endif
175da2e3ebdSchin {
176da2e3ebdSchin 	Sfrsrv_t	*rsrv, *rs;
177da2e3ebdSchin 
178da2e3ebdSchin 	/* make buffer if nothing yet */
179da2e3ebdSchin 	size = ((size + SF_GRAIN-1)/SF_GRAIN)*SF_GRAIN;
180da2e3ebdSchin 	if(!(rsrv = f->rsrv) || size > rsrv->size)
181da2e3ebdSchin 	{	if(!(rs = (Sfrsrv_t*)malloc(size+sizeof(Sfrsrv_t))))
182da2e3ebdSchin 			size = -1;
183da2e3ebdSchin 		else
184da2e3ebdSchin 		{	if(rsrv)
185da2e3ebdSchin 			{	if(rsrv->slen > 0)
186da2e3ebdSchin 					memcpy(rs,rsrv,sizeof(Sfrsrv_t)+rsrv->slen);
187da2e3ebdSchin 				free(rsrv);
188da2e3ebdSchin 			}
189da2e3ebdSchin 			f->rsrv = rsrv = rs;
190da2e3ebdSchin 			rsrv->size = size;
191da2e3ebdSchin 			rsrv->slen = 0;
192da2e3ebdSchin 		}
193da2e3ebdSchin 	}
194da2e3ebdSchin 
195da2e3ebdSchin 	if(rsrv && size > 0)
196da2e3ebdSchin 		rsrv->slen = 0;
197da2e3ebdSchin 
198da2e3ebdSchin 	return size >= 0 ? rsrv : NIL(Sfrsrv_t*);
199da2e3ebdSchin }
200da2e3ebdSchin 
201da2e3ebdSchin #ifdef SIGPIPE
202da2e3ebdSchin #if __STD_C
ignoresig(int sig)203da2e3ebdSchin static void ignoresig(int sig)
204da2e3ebdSchin #else
205da2e3ebdSchin static void ignoresig(sig)
206da2e3ebdSchin int sig;
207da2e3ebdSchin #endif
208da2e3ebdSchin {
209da2e3ebdSchin 	signal(sig, ignoresig);
210da2e3ebdSchin }
211da2e3ebdSchin #endif
212da2e3ebdSchin 
213da2e3ebdSchin #if __STD_C
_sfpopen(reg Sfio_t * f,int fd,int pid,int stdio)214da2e3ebdSchin int _sfpopen(reg Sfio_t* f, int fd, int pid, int stdio)
215da2e3ebdSchin #else
216da2e3ebdSchin int _sfpopen(f, fd, pid, stdio)
217da2e3ebdSchin reg Sfio_t*	f;
218da2e3ebdSchin int		fd;
219da2e3ebdSchin int		pid;
220da2e3ebdSchin int		stdio;	/* stdio popen() does not reset SIGPIPE handler */
221da2e3ebdSchin #endif
222da2e3ebdSchin {
223da2e3ebdSchin 	reg Sfproc_t*	p;
224da2e3ebdSchin 
225da2e3ebdSchin 	if(f->proc)
226da2e3ebdSchin 		return 0;
227da2e3ebdSchin 
228da2e3ebdSchin 	if(!(p = f->proc = (Sfproc_t*)malloc(sizeof(Sfproc_t))) )
229da2e3ebdSchin 		return -1;
230da2e3ebdSchin 
231da2e3ebdSchin 	p->pid = pid;
232da2e3ebdSchin 	p->size = p->ndata = 0;
233da2e3ebdSchin 	p->rdata = NIL(uchar*);
234da2e3ebdSchin 	p->file = fd;
235da2e3ebdSchin 	p->sigp = (!stdio && pid >= 0 && (f->flags&SF_WRITE)) ? 1 : 0;
236da2e3ebdSchin 
237da2e3ebdSchin #ifdef SIGPIPE	/* protect from broken pipe signal */
238da2e3ebdSchin 	if(p->sigp)
239da2e3ebdSchin 	{	Sfsignal_f	handler;
240da2e3ebdSchin 
241da2e3ebdSchin 		(void)vtmtxlock(_Sfmutex);
242da2e3ebdSchin 		if((handler = signal(SIGPIPE, ignoresig)) != SIG_DFL &&
243da2e3ebdSchin 		    handler != ignoresig)
244da2e3ebdSchin 			signal(SIGPIPE, handler); /* honor user handler */
245da2e3ebdSchin 		_Sfsigp += 1;
246da2e3ebdSchin 		(void)vtmtxunlock(_Sfmutex);
247da2e3ebdSchin 	}
248da2e3ebdSchin #endif
249da2e3ebdSchin 
250da2e3ebdSchin 	return 0;
251da2e3ebdSchin }
252da2e3ebdSchin 
253da2e3ebdSchin #if __STD_C
_sfpclose(reg Sfio_t * f)254da2e3ebdSchin int _sfpclose(reg Sfio_t* f)
255da2e3ebdSchin #else
256da2e3ebdSchin int _sfpclose(f)
257da2e3ebdSchin reg Sfio_t*	f;	/* stream to close */
258da2e3ebdSchin #endif
259da2e3ebdSchin {
260da2e3ebdSchin 	Sfproc_t*	p;
261da2e3ebdSchin 	int		pid, status;
262da2e3ebdSchin 
263da2e3ebdSchin 	if(!(p = f->proc))
264da2e3ebdSchin 		return -1;
265da2e3ebdSchin 	f->proc = NIL(Sfproc_t*);
266da2e3ebdSchin 
267da2e3ebdSchin 	if(p->rdata)
268da2e3ebdSchin 		free(p->rdata);
269da2e3ebdSchin 
270da2e3ebdSchin 	if(p->pid < 0)
271da2e3ebdSchin 		status = 0;
272da2e3ebdSchin 	else
273da2e3ebdSchin 	{	/* close the associated stream */
274da2e3ebdSchin 		if(p->file >= 0)
275da2e3ebdSchin 			CLOSE(p->file);
276da2e3ebdSchin 
277da2e3ebdSchin 		/* wait for process termination */
278da2e3ebdSchin #if _PACKAGE_ast
279da2e3ebdSchin 		sigcritical(SIG_REG_EXEC|SIG_REG_PROC);
280da2e3ebdSchin #endif
281*b30d1939SAndy Fiddaman 		status = -1;
282da2e3ebdSchin 		while ((pid = waitpid(p->pid,&status,0)) == -1 && errno == EINTR)
283da2e3ebdSchin 			;
284da2e3ebdSchin #if _PACKAGE_ast
285*b30d1939SAndy Fiddaman 		status = status == -1 ?
286*b30d1939SAndy Fiddaman 			 EXIT_QUIT :
287*b30d1939SAndy Fiddaman 			 WIFSIGNALED(status) ?
288*b30d1939SAndy Fiddaman 			 EXIT_TERM(WTERMSIG(status)) :
289*b30d1939SAndy Fiddaman 			 EXIT_CODE(WEXITSTATUS(status));
290da2e3ebdSchin 		sigcritical(0);
291da2e3ebdSchin #endif
292da2e3ebdSchin 
293da2e3ebdSchin #ifdef SIGPIPE
294da2e3ebdSchin 		(void)vtmtxlock(_Sfmutex);
295da2e3ebdSchin 		if(p->sigp && (_Sfsigp -= 1) <= 0)
296da2e3ebdSchin 		{	Sfsignal_f	handler;
297da2e3ebdSchin 			if((handler = signal(SIGPIPE,SIG_DFL)) != SIG_DFL &&
298da2e3ebdSchin 			   handler != ignoresig)
299da2e3ebdSchin 				signal(SIGPIPE,handler); /* honor user handler */
300da2e3ebdSchin 			_Sfsigp = 0;
301da2e3ebdSchin 		}
302da2e3ebdSchin 		(void)vtmtxunlock(_Sfmutex);
303da2e3ebdSchin #endif
304da2e3ebdSchin 	}
305da2e3ebdSchin 
306da2e3ebdSchin 	free(p);
307da2e3ebdSchin 	return status;
308da2e3ebdSchin }
309da2e3ebdSchin 
310da2e3ebdSchin #if __STD_C
_sfpmode(Sfio_t * f,int type)311da2e3ebdSchin static int _sfpmode(Sfio_t* f, int type)
312da2e3ebdSchin #else
313da2e3ebdSchin static int _sfpmode(f,type)
314da2e3ebdSchin Sfio_t*	f;
315da2e3ebdSchin int	type;
316da2e3ebdSchin #endif
317da2e3ebdSchin {
318da2e3ebdSchin 	Sfproc_t*	p;
319da2e3ebdSchin 
320da2e3ebdSchin 	if(!(p = f->proc) )
321da2e3ebdSchin 		return -1;
322da2e3ebdSchin 
323da2e3ebdSchin 	if(type == SF_WRITE)
324da2e3ebdSchin 	{	/* save unread data */
325da2e3ebdSchin 		p->ndata = f->endb-f->next;
326da2e3ebdSchin 		if(p->ndata > p->size)
327da2e3ebdSchin 		{	if(p->rdata)
328da2e3ebdSchin 				free((char*)p->rdata);
329da2e3ebdSchin 			if((p->rdata = (uchar*)malloc(p->ndata)) )
330da2e3ebdSchin 				p->size = p->ndata;
331da2e3ebdSchin 			else
332da2e3ebdSchin 			{	p->size = 0;
333da2e3ebdSchin 				return -1;
334da2e3ebdSchin 			}
335da2e3ebdSchin 		}
336da2e3ebdSchin 		if(p->ndata > 0)
337da2e3ebdSchin 			memcpy((Void_t*)p->rdata,(Void_t*)f->next,p->ndata);
338da2e3ebdSchin 		f->endb = f->data;
339da2e3ebdSchin 	}
340da2e3ebdSchin 	else
341da2e3ebdSchin 	{	/* restore read data */
342da2e3ebdSchin 		if(p->ndata > f->size)	/* may lose data!!! */
343da2e3ebdSchin 			p->ndata = f->size;
344da2e3ebdSchin 		if(p->ndata > 0)
345da2e3ebdSchin 		{	memcpy((Void_t*)f->data,(Void_t*)p->rdata,p->ndata);
346da2e3ebdSchin 			f->endb = f->data+p->ndata;
347da2e3ebdSchin 			p->ndata = 0;
348da2e3ebdSchin 		}
349da2e3ebdSchin 	}
350da2e3ebdSchin 
351da2e3ebdSchin 	/* switch file descriptor */
352da2e3ebdSchin 	if(p->pid >= 0)
353da2e3ebdSchin 	{	type = f->file;
354da2e3ebdSchin 		f->file = p->file;
355da2e3ebdSchin 		p->file = type;
356da2e3ebdSchin 	}
357da2e3ebdSchin 
358da2e3ebdSchin 	return 0;
359da2e3ebdSchin }
360da2e3ebdSchin 
361da2e3ebdSchin #if __STD_C
_sfmode(reg Sfio_t * f,reg int wanted,reg int local)362da2e3ebdSchin int _sfmode(reg Sfio_t* f, reg int wanted, reg int local)
363da2e3ebdSchin #else
364da2e3ebdSchin int _sfmode(f, wanted, local)
365da2e3ebdSchin reg Sfio_t*	f;	/* change r/w mode and sync file pointer for this stream */
366da2e3ebdSchin reg int		wanted;	/* desired mode */
367da2e3ebdSchin reg int		local;	/* a local call */
368da2e3ebdSchin #endif
369da2e3ebdSchin {
370da2e3ebdSchin 	reg int	n;
371da2e3ebdSchin 	Sfoff_t	addr;
372da2e3ebdSchin 	reg int	rv = 0;
373da2e3ebdSchin 
374da2e3ebdSchin 	SFONCE();	/* initialize mutexes */
375da2e3ebdSchin 
376da2e3ebdSchin 	if(wanted&SF_SYNCED) /* for (SF_SYNCED|SF_READ) stream, just junk data */
377da2e3ebdSchin 	{	wanted &= ~SF_SYNCED;
378da2e3ebdSchin 		if((f->mode&(SF_SYNCED|SF_READ)) == (SF_SYNCED|SF_READ) )
379da2e3ebdSchin 		{	f->next = f->endb = f->endr = f->data;
380da2e3ebdSchin 			f->mode &= ~SF_SYNCED;
381da2e3ebdSchin 		}
382da2e3ebdSchin 	}
383da2e3ebdSchin 
384da2e3ebdSchin 	if((!local && SFFROZEN(f)) || (!(f->flags&SF_STRING) && f->file < 0))
385da2e3ebdSchin 	{	if(local || !f->disc || !f->disc->exceptf)
386da2e3ebdSchin 		{	local = 1;
387da2e3ebdSchin 			goto err_notify;
388da2e3ebdSchin 		}
389da2e3ebdSchin 
390da2e3ebdSchin 		for(;;)
391da2e3ebdSchin 		{	if((rv = (*f->disc->exceptf)(f,SF_LOCKED,0,f->disc)) < 0)
392da2e3ebdSchin 				return rv;
393da2e3ebdSchin 			if((!local && SFFROZEN(f)) ||
394da2e3ebdSchin 			   (!(f->flags&SF_STRING) && f->file < 0) )
395da2e3ebdSchin 			{	if(rv == 0)
396da2e3ebdSchin 				{	local = 1;
397da2e3ebdSchin 					goto err_notify;
398da2e3ebdSchin 				}
399da2e3ebdSchin 				else	continue;
400da2e3ebdSchin 			}
401da2e3ebdSchin 			else	break;
402da2e3ebdSchin 		}
403da2e3ebdSchin 	}
404da2e3ebdSchin 
405da2e3ebdSchin 	if(f->mode&SF_GETR)
406da2e3ebdSchin 	{	f->mode &= ~SF_GETR;
407da2e3ebdSchin #ifdef MAP_TYPE
408da2e3ebdSchin 		if((f->bits&SF_MMAP) && (f->tiny[0] += 1) >= (4*SF_NMAP) )
409da2e3ebdSchin 		{	/* turn off mmap to avoid page faulting */
410da2e3ebdSchin 			sfsetbuf(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
411da2e3ebdSchin 			f->tiny[0] = 0;
412da2e3ebdSchin 		}
413da2e3ebdSchin 		else
414da2e3ebdSchin #endif
415da2e3ebdSchin 		if(f->getr)
416da2e3ebdSchin 		{	f->next[-1] = f->getr;
417da2e3ebdSchin 			f->getr = 0;
418da2e3ebdSchin 		}
419da2e3ebdSchin 	}
420da2e3ebdSchin 
421da2e3ebdSchin 	if(f->mode&SF_STDIO) /* synchronizing with stdio pointers */
422da2e3ebdSchin 		(*_Sfstdsync)(f);
423da2e3ebdSchin 
424da2e3ebdSchin 	if(f->disc == _Sfudisc && wanted == SF_WRITE &&
425da2e3ebdSchin 	   sfclose((*_Sfstack)(f,NIL(Sfio_t*))) < 0 )
426da2e3ebdSchin 	{	local = 1;
427da2e3ebdSchin 		goto err_notify;
428da2e3ebdSchin 	}
429da2e3ebdSchin 
430da2e3ebdSchin 	if(f->mode&SF_POOL)
431da2e3ebdSchin 	{	/* move to head of pool */
432da2e3ebdSchin 		if(f == f->pool->sf[0] || (*_Sfpmove)(f,0) < 0 )
433da2e3ebdSchin 		{	local = 1;
434da2e3ebdSchin 			goto err_notify;
435da2e3ebdSchin 		}
436da2e3ebdSchin 		f->mode &= ~SF_POOL;
437da2e3ebdSchin 	}
438da2e3ebdSchin 
439da2e3ebdSchin 	SFLOCK(f,local);
440da2e3ebdSchin 
441da2e3ebdSchin 	/* buffer initialization */
442da2e3ebdSchin 	wanted &= SF_RDWR;
443da2e3ebdSchin 	if(f->mode&SF_INIT)
444da2e3ebdSchin 	{
445da2e3ebdSchin 		if(!f->pool && _sfsetpool(f) < 0)
446da2e3ebdSchin 		{	rv = -1;
447da2e3ebdSchin 			goto done;
448da2e3ebdSchin 		}
449da2e3ebdSchin 
450da2e3ebdSchin 		if(wanted == 0)
451da2e3ebdSchin 			goto done;
452da2e3ebdSchin 
453da2e3ebdSchin 		if(wanted != (int)(f->mode&SF_RDWR) && !(f->flags&wanted) )
454da2e3ebdSchin 			goto err_notify;
455da2e3ebdSchin 
456da2e3ebdSchin 		if((f->flags&SF_STRING) && f->size >= 0 && f->data)
457da2e3ebdSchin 		{	f->mode &= ~SF_INIT;
458da2e3ebdSchin 			f->extent = ((f->flags&SF_READ) || (f->bits&SF_BOTH)) ?
459da2e3ebdSchin 					f->size : 0;
460da2e3ebdSchin 			f->here = 0;
461da2e3ebdSchin 			f->endb = f->data + f->size;
462da2e3ebdSchin 			f->next = f->endr = f->endw = f->data;
463da2e3ebdSchin 			if(f->mode&SF_READ)
464da2e3ebdSchin 				f->endr = f->endb;
465da2e3ebdSchin 			else	f->endw = f->endb;
466da2e3ebdSchin 		}
467da2e3ebdSchin 		else
468da2e3ebdSchin 		{	n = f->flags;
469da2e3ebdSchin 			(void)SFSETBUF(f,f->data,f->size);
470da2e3ebdSchin 			f->flags |= (n&SF_MALLOC);
471da2e3ebdSchin 		}
472da2e3ebdSchin 	}
473da2e3ebdSchin 
474da2e3ebdSchin 	if(wanted == (int)SFMODE(f,1))
475da2e3ebdSchin 		goto done;
476da2e3ebdSchin 
477da2e3ebdSchin 	switch(SFMODE(f,1))
478da2e3ebdSchin 	{
479da2e3ebdSchin 	case SF_WRITE: /* switching to SF_READ */
480da2e3ebdSchin 		if(wanted == 0 || wanted == SF_WRITE)
481da2e3ebdSchin 			break;
482da2e3ebdSchin 		if(!(f->flags&SF_READ) )
483da2e3ebdSchin 			goto err_notify;
484da2e3ebdSchin 		else if(f->flags&SF_STRING)
485da2e3ebdSchin 		{	SFSTRSIZE(f);
486da2e3ebdSchin 			f->endb = f->data+f->extent;
487da2e3ebdSchin 			f->mode = SF_READ;
488da2e3ebdSchin 			break;
489da2e3ebdSchin 		}
490da2e3ebdSchin 
491da2e3ebdSchin 		/* reset buffer */
492da2e3ebdSchin 		if(f->next > f->data && SFFLSBUF(f,-1) < 0)
493da2e3ebdSchin 			goto err_notify;
494da2e3ebdSchin 
495da2e3ebdSchin 		if(f->size == 0)
496da2e3ebdSchin 		{	/* unbuffered */
497da2e3ebdSchin 			f->data = f->tiny;
498da2e3ebdSchin 			f->size = sizeof(f->tiny);
499da2e3ebdSchin 		}
500da2e3ebdSchin 		f->next = f->endr = f->endw = f->endb = f->data;
501da2e3ebdSchin 		f->mode = SF_READ|SF_LOCK;
502da2e3ebdSchin 
503da2e3ebdSchin 		/* restore saved read data for coprocess */
504da2e3ebdSchin 		if(f->proc && _sfpmode(f,wanted) < 0)
505da2e3ebdSchin 			goto err_notify;
506da2e3ebdSchin 
507da2e3ebdSchin 		break;
508da2e3ebdSchin 
509da2e3ebdSchin 	case (SF_READ|SF_SYNCED): /* a previously sync-ed read stream */
510da2e3ebdSchin 		if(wanted != SF_WRITE)
511da2e3ebdSchin 		{	/* just reset the pointers */
512da2e3ebdSchin 			f->mode = SF_READ|SF_LOCK;
513da2e3ebdSchin 
514da2e3ebdSchin 			/* see if must go with new physical location */
515da2e3ebdSchin 			if((f->flags&(SF_SHARE|SF_PUBLIC)) == (SF_SHARE|SF_PUBLIC) &&
516da2e3ebdSchin 			   (addr = SFSK(f,0,SEEK_CUR,f->disc)) != f->here)
517da2e3ebdSchin 			{
518da2e3ebdSchin #ifdef MAP_TYPE
519da2e3ebdSchin 				if((f->bits&SF_MMAP) && f->data)
520da2e3ebdSchin 				{	SFMUNMAP(f,f->data,f->endb-f->data);
521da2e3ebdSchin 					f->data = NIL(uchar*);
522da2e3ebdSchin 				}
523da2e3ebdSchin #endif
524da2e3ebdSchin 				f->endb = f->endr = f->endw = f->next = f->data;
525da2e3ebdSchin 				f->here = addr;
526da2e3ebdSchin 			}
527da2e3ebdSchin 			else
528da2e3ebdSchin 			{	addr = f->here + (f->endb - f->next);
529da2e3ebdSchin 				if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
530da2e3ebdSchin 					goto err_notify;
531da2e3ebdSchin 				f->here = addr;
532da2e3ebdSchin 			}
533da2e3ebdSchin 
534da2e3ebdSchin 			break;
535da2e3ebdSchin 		}
536da2e3ebdSchin 		/* fall thru */
537da2e3ebdSchin 
538da2e3ebdSchin 	case SF_READ: /* switching to SF_WRITE */
539da2e3ebdSchin 		if(wanted != SF_WRITE)
540da2e3ebdSchin 			break;
541da2e3ebdSchin 		else if(!(f->flags&SF_WRITE))
542da2e3ebdSchin 			goto err_notify;
543da2e3ebdSchin 		else if(f->flags&SF_STRING)
544da2e3ebdSchin 		{	f->endb = f->data+f->size;
545da2e3ebdSchin 			f->mode = SF_WRITE|SF_LOCK;
546da2e3ebdSchin 			break;
547da2e3ebdSchin 		}
548da2e3ebdSchin 
549da2e3ebdSchin 		/* save unread data before switching mode */
550da2e3ebdSchin 		if(f->proc && _sfpmode(f,wanted) < 0)
551da2e3ebdSchin 			goto err_notify;
552da2e3ebdSchin 
553da2e3ebdSchin 		/* reset buffer and seek pointer */
554da2e3ebdSchin 		if(!(f->mode&SF_SYNCED) )
555da2e3ebdSchin 		{	n = f->endb - f->next;
556da2e3ebdSchin 			if(f->extent >= 0 && (n > 0 || (f->data && (f->bits&SF_MMAP))) )
557da2e3ebdSchin 			{	/* reset file pointer */
558da2e3ebdSchin 				addr = f->here - n;
559da2e3ebdSchin 				if(SFSK(f,addr,SEEK_SET,f->disc) < 0)
560da2e3ebdSchin 					goto err_notify;
561da2e3ebdSchin 				f->here = addr;
562da2e3ebdSchin 			}
563da2e3ebdSchin 		}
564da2e3ebdSchin 
565da2e3ebdSchin 		f->mode = SF_WRITE|SF_LOCK;
566da2e3ebdSchin #ifdef MAP_TYPE
567da2e3ebdSchin 		if(f->bits&SF_MMAP)
568da2e3ebdSchin 		{	if(f->data)
569da2e3ebdSchin 				SFMUNMAP(f,f->data,f->endb-f->data);
570da2e3ebdSchin 			(void)SFSETBUF(f,(Void_t*)f->tiny,(size_t)SF_UNBOUND);
571da2e3ebdSchin 		}
572da2e3ebdSchin #endif
573da2e3ebdSchin 		if(f->data == f->tiny)
574da2e3ebdSchin 		{	f->endb = f->data = f->next = NIL(uchar*);
575da2e3ebdSchin 			f->size = 0;
576da2e3ebdSchin 		}
577da2e3ebdSchin 		else	f->endb = (f->next = f->data) + f->size;
578da2e3ebdSchin 
579da2e3ebdSchin 		break;
580da2e3ebdSchin 
581da2e3ebdSchin 	default: /* unknown case */
582da2e3ebdSchin 	err_notify:
583da2e3ebdSchin 		if((wanted &= SF_RDWR) == 0 && (wanted = f->flags&SF_RDWR) == SF_RDWR)
584da2e3ebdSchin 			wanted = SF_READ;
585da2e3ebdSchin 
586da2e3ebdSchin 		/* set errno for operations that access wrong stream type */
587da2e3ebdSchin 		if(wanted != (f->mode&SF_RDWR) && f->file >= 0)
588da2e3ebdSchin 			errno = EBADF;
589da2e3ebdSchin 
590da2e3ebdSchin 		if(_Sfnotify) /* notify application of the error */
5917c2fbfb3SApril Chin 			(*_Sfnotify)(f, wanted, (void*)((long)f->file));
592da2e3ebdSchin 
593da2e3ebdSchin 		rv = -1;
594da2e3ebdSchin 		break;
595da2e3ebdSchin 	}
596da2e3ebdSchin 
597da2e3ebdSchin done:
598da2e3ebdSchin 	SFOPEN(f,local);
599da2e3ebdSchin 	return rv;
600da2e3ebdSchin }
601