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