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