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 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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 a buffer out to a file descriptor or
25 **	extending a buffer for a SF_STRING stream.
26 **
27 **	Written by Kiem-Phong Vo
28 */
29 
30 #if __STD_C
_sfflsbuf(Sfio_t * f,int c)31 int _sfflsbuf(Sfio_t* f, int c)
32 #else
33 int _sfflsbuf(f,c)
34 Sfio_t*	f;	/* write out the buffered content of this stream */
35 int	c;	/* if c>=0, c is also written out */
36 #endif
37 {
38 	ssize_t		n, w, written;
39 	uchar*		data;
40 	uchar		outc;
41 	int		local, isall;
42 	int		inpc = c;
43 	SFMTXDECL(f); /* declare a local stream variable for multithreading */
44 
45 	SFMTXENTER(f,-1);
46 
47 	GETLOCAL(f,local);
48 
49 	for(written = 0;; f->mode &= ~SF_LOCK)
50 	{	/* check stream mode */
51 		if(SFMODE(f,local) != SF_WRITE && _sfmode(f,SF_WRITE,local) < 0)
52 			SFMTXRETURN(f, -1);
53 		SFLOCK(f,local);
54 
55 		/* current data extent */
56 		n = f->next - (data = f->data);
57 
58 		if(n == (f->endb-data) && (f->flags&SF_STRING))
59 		{	/* call sfwr() to extend string buffer and process events */
60 			w = ((f->bits&SF_PUTR) && f->val > 0) ? f->val : 1;
61 			(void)SFWR(f, data, w, f->disc);
62 
63 			/* !(f->flags&SF_STRING) is required because exception
64 			   handlers may turn a string stream to a file stream */
65 			if(f->next < f->endb || !(f->flags&SF_STRING) )
66 				n = f->next - (data = f->data);
67 			else
68 			{	SFOPEN(f,local);
69 				SFMTXRETURN(f, -1);
70 			}
71 		}
72 
73 		if(c >= 0)
74 		{	/* write into buffer */
75 			if(n < (f->endb - (data = f->data)))
76 			{	*f->next++ = c;
77 				if(c == '\n' &&
78 				   (f->flags&SF_LINE) && !(f->flags&SF_STRING))
79 				{	c = -1;
80 					n += 1;
81 				}
82 				else	break;
83 			}
84 			else if(n == 0)
85 			{	/* unbuffered io */
86 				outc = (uchar)c;
87 				data = &outc;
88 				c = -1;
89 				n = 1;
90 			}
91 		}
92 
93 		if(n == 0 || (f->flags&SF_STRING))
94 			break;
95 
96 		isall = SFISALL(f,isall);
97 		if((w = SFWR(f,data,n,f->disc)) > 0)
98 		{	if((n -= w) > 0) /* save unwritten data, then resume */
99 				memcpy((char*)f->data,(char*)data+w,n);
100 			written += w;
101 			f->next = f->data+n;
102 			if(c < 0 && (!isall || n == 0))
103 				break;
104 		}
105 		else if(w == 0)
106 		{	if(written > 0) /* some buffer was cleared */
107 				break; /* do normal exit below */
108 			else /* nothing was done, returning failure */
109 			{	SFOPEN(f,local);
110 				SFMTXRETURN(f, -1);
111 			}
112 		}
113 		else /* w < 0 means SF_EDISC or SF_ESTACK in sfwr() */
114 		{	if(c < 0) /* back to the calling write operation */
115 				break;
116 			else	continue; /* try again to write out c */
117 		}
118 	}
119 
120 	SFOPEN(f,local);
121 
122 	if(inpc < 0)
123 		inpc = f->endb-f->next;
124 
125 	SFMTXRETURN(f,inpc);
126 }
127