xref: /titanic_50/usr/src/lib/libast/common/sfio/sffilbuf.c (revision ff3124eff995e6cd8ebd8c6543648e0670920034)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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 /*	Fill the buffer of a stream with data.
25 **	If n < 0, sffilbuf() attempts to fill the buffer if it's empty.
26 **	If n == 0, if the buffer is not empty, just return the first byte;
27 **		otherwise fill the buffer and return the first byte.
28 **	If n > 0, even if the buffer is not empty, try a read to get as
29 **		close to n as possible. n is reset to -1 if stack pops.
30 **
31 **	Written by Kiem-Phong Vo
32 */
33 
34 #if __STD_C
35 int _sffilbuf(Sfio_t* f, reg int n)
36 #else
37 int _sffilbuf(f,n)
38 Sfio_t*	f;	/* fill the read buffer of this stream */
39 reg int	n;	/* see above */
40 #endif
41 {
42 	reg ssize_t	r;
43 	reg int		first, local, rcrv, rc, justseek;
44 
45 	SFMTXSTART(f,-1);
46 
47 	GETLOCAL(f,local);
48 
49 	/* any peek data must be preserved across stacked streams */
50 	rcrv = f->mode&(SF_RC|SF_RV|SF_LOCK);
51 	rc = f->getr;
52 
53 	justseek = f->bits&SF_JUSTSEEK; f->bits &= ~SF_JUSTSEEK;
54 
55 	for(first = 1;; first = 0, (f->mode &= ~SF_LOCK) )
56 	{	/* check mode */
57 		if(SFMODE(f,local) != SF_READ && _sfmode(f,SF_READ,local) < 0)
58 			SFMTXRETURN(f,-1);
59 		SFLOCK(f,local);
60 
61 		/* current extent of available data */
62 		if((r = f->endb-f->next) > 0)
63 		{	/* on first iteration, n is amount beyond current buffer;
64 			   afterward, n is the exact amount requested */
65 			if((first && n <= 0) || (!first && n <= r) ||
66 			   (f->flags&SF_STRING))
67 				break;
68 
69 			/* try shifting left to make room for new data */
70 			if(!(f->bits&SF_MMAP) && f->next > f->data &&
71 			   n > (f->size - (f->endb-f->data)) )
72 			{	ssize_t	s = r;
73 
74 				/* try to maintain block alignment */
75 				if(f->blksz > 0 && (f->here%f->blksz) == 0 )
76 				{	s = ((r + f->blksz-1)/f->blksz)*f->blksz;
77 					if(s+n > f->size)
78 						s = r;
79 				}
80 
81 				memcpy(f->data, f->endb-s, s);
82 				f->next = f->data + (s-r);
83 				f->endb = f->data + s;
84 			}
85 		}
86 		else if(!(f->flags&SF_STRING) && !(f->bits&SF_MMAP) )
87 			f->next = f->endb = f->endr = f->data;
88 
89 		if(f->bits&SF_MMAP)
90 			r = n > 0 ? n : f->size;
91 		else if(!(f->flags&SF_STRING) )
92 		{	r = f->size - (f->endb - f->data); /* available buffer */
93 			if(n > 0)
94 			{	if(r > n && f->extent < 0 && (f->flags&SF_SHARE) )
95 					r = n;	/* read only as much as requested */
96 				else if(justseek && n <= f->iosz && f->iosz <= f->size)
97 					r = f->iosz;	/* limit buffer filling */
98 			}
99 		}
100 
101 		/* SFRD takes care of discipline read and stack popping */
102 		f->mode |= rcrv;
103 		f->getr = rc;
104 		if((r = SFRD(f,f->endb,r,f->disc)) >= 0)
105 		{	r = f->endb - f->next;
106 			break;
107 		}
108 	}
109 
110 	SFOPEN(f,local);
111 
112 	rcrv = (n == 0) ? (r > 0 ? (int)(*f->next++) : EOF) : (int)r;
113 
114 	SFMTXRETURN(f,rcrv);
115 }
116