1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#include	"sfhdr.h"
23
24/*	Write data out to the file system
25**
26**	Written by Kiem-Phong Vo.
27*/
28
29#if __STD_C
30ssize_t sfwrite(Sfio_t* f, const Void_t* buf, size_t n)
31#else
32ssize_t sfwrite(f,buf,n)
33Sfio_t*		f;	/* write to this stream. 	*/
34Void_t*		buf;	/* buffer to be written.	*/
35size_t		n;	/* number of bytes. 		*/
36#endif
37{
38	reg uchar	*s, *begs, *next;
39	reg ssize_t	w;
40	reg int		local;
41	SFMTXDECL(f);
42
43	SFMTXENTER(f, (ssize_t)(-1));
44
45	GETLOCAL(f,local);
46
47	if(!buf)
48		SFMTXRETURN(f, (ssize_t)(n == 0 ? 0 : -1) );
49
50	/* release peek lock */
51	if(f->mode&SF_PEEK)
52	{	if(!(f->mode&SF_WRITE) && (f->flags&SF_RDWR) != SF_RDWR)
53			SFMTXRETURN(f, (ssize_t)(-1));
54
55		if((uchar*)buf != f->next &&
56		   (!f->rsrv || f->rsrv->data != (uchar*)buf) )
57			SFMTXRETURN(f, (ssize_t)(-1));
58
59		f->mode &= ~SF_PEEK;
60
61		if(f->mode&SF_PKRD)
62		{	/* read past peeked data */
63			char		buf[16];
64			reg ssize_t	r;
65
66			for(w = n; w > 0; )
67			{	if((r = w) > sizeof(buf))
68					r = sizeof(buf);
69				if((r = sysreadf(f->file,buf,r)) <= 0)
70				{	n -= w;
71					break;
72				}
73				else	w -= r;
74			}
75
76			f->mode &= ~SF_PKRD;
77			f->endb = f->data + n;
78			f->here += n;
79		}
80
81		if((f->mode&SF_READ) && f->proc)
82			f->next += n;
83	}
84
85	s = begs = (uchar*)buf;
86	for(;; f->mode &= ~SF_LOCK)
87	{	/* check stream mode */
88		if(SFMODE(f,local) != SF_WRITE && _sfmode(f,SF_WRITE,local) < 0 )
89		{	w = s > begs ? s-begs : -1;
90			SFMTXRETURN(f,w);
91		}
92
93		SFLOCK(f,local);
94
95		w = f->endb - f->next;
96
97		if(s == f->next) /* after sfreserve */
98		{	if(w > (ssize_t)n)
99				w = (ssize_t)n;
100			f->next = (s += w);
101			n -= w;
102			break;
103		}
104
105		/* attempt to create space in buffer */
106		if(w == 0 || ((f->flags&SF_WHOLE) && w < (ssize_t)n) )
107		{	if(f->flags&SF_STRING) /* extend buffer */
108			{	(void)SFWR(f, s, n-w, f->disc);
109				if((w = f->endb - f->next) < (ssize_t)n)
110				{	if(!(f->flags&SF_STRING)) /* maybe sftmp */
111					{	if(f->next > f->data)
112							goto fls_buf;
113					}
114					else if(w == 0)
115						break;
116				}
117			}
118			else if(f->next > f->data)
119			{ fls_buf:
120				(void)SFFLSBUF(f, -1);
121				if((w = f->endb - f->next) < (ssize_t)n &&
122				   (f->flags&SF_WHOLE) && f->next > f->data )
123						break;
124			}
125		}
126
127		if(!(f->flags&SF_STRING) && f->next == f->data &&
128		   (((f->flags&SF_WHOLE) && w <= n) || SFDIRECT(f,n)) )
129		{	/* bypass buffering */
130			if((w = SFWR(f,s,n,f->disc)) <= 0 )
131				break;
132		}
133		else
134		{	if(w > (ssize_t)n)
135				w = (ssize_t)n;
136			if(w <= 0) /* no forward progress possible */
137				break;
138			memmove(f->next, s, w);
139			f->next += w;
140		}
141
142		s += w;
143		if((n -= w) <= 0)
144			break;
145	}
146
147	/* always flush buffer for share streams */
148	if(f->extent < 0 && (f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC) )
149		(void)SFFLSBUF(f,-1);
150
151	/* check to see if buffer should be flushed */
152	else if(n == 0 && (f->flags&SF_LINE) && !(f->flags&SF_STRING))
153	{	if((ssize_t)(n = f->next-f->data) > (w = s-begs))
154			n = w;
155		if(n > 0 && n < HIFORLINE)
156		{	for(next = f->next-1; n > 0; --n, --next)
157			{	if(*next == '\n')
158				{	n = HIFORLINE;
159					break;
160				}
161			}
162		}
163		if(n >= HIFORLINE)
164			(void)SFFLSBUF(f,-1);
165	}
166
167	SFOPEN(f,local);
168
169	w = s-begs;
170	SFMTXRETURN(f,w);
171}
172