xref: /netbsd-src/usr.bin/telnet/ring.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 /* from: static char sccsid[] = "@(#)ring.c	8.1 (Berkeley) 6/6/93"; */
36 static char *rcsid = "$Id: ring.c,v 1.3 1994/02/25 03:00:34 cgd Exp $";
37 #endif /* not lint */
38 
39 /*
40  * This defines a structure for a ring buffer.
41  *
42  * The circular buffer has two parts:
43  *(((
44  *	full:	[consume, supply)
45  *	empty:	[supply, consume)
46  *]]]
47  *
48  */
49 
50 #include	<stdio.h>
51 #include	<errno.h>
52 
53 #ifdef	size_t
54 #undef	size_t
55 #endif
56 
57 #include	<sys/types.h>
58 #ifndef	FILIO_H
59 #include	<sys/ioctl.h>
60 #endif
61 #include	<sys/socket.h>
62 
63 #include	"ring.h"
64 #include	"general.h"
65 
66 /* Internal macros */
67 
68 #if	!defined(MIN)
69 #define	MIN(a,b)	(((a)<(b))? (a):(b))
70 #endif	/* !defined(MIN) */
71 
72 #define	ring_subtract(d,a,b)	(((a)-(b) >= 0)? \
73 					(a)-(b): (((a)-(b))+(d)->size))
74 
75 #define	ring_increment(d,a,c)	(((a)+(c) < (d)->top)? \
76 					(a)+(c) : (((a)+(c))-(d)->size))
77 
78 #define	ring_decrement(d,a,c)	(((a)-(c) >= (d)->bottom)? \
79 					(a)-(c) : (((a)-(c))-(d)->size))
80 
81 
82 /*
83  * The following is a clock, used to determine full, empty, etc.
84  *
85  * There is some trickiness here.  Since the ring buffers are initialized
86  * to ZERO on allocation, we need to make sure, when interpreting the
87  * clock, that when the times are EQUAL, then the buffer is FULL.
88  */
89 static u_long ring_clock = 0;
90 
91 
92 #define	ring_empty(d) (((d)->consume == (d)->supply) && \
93 				((d)->consumetime >= (d)->supplytime))
94 #define	ring_full(d) (((d)->supply == (d)->consume) && \
95 				((d)->supplytime > (d)->consumetime))
96 
97 
98 
99 
100 
101 /* Buffer state transition routines */
102 
103     ring_init(ring, buffer, count)
104 Ring *ring;
105     unsigned char *buffer;
106     int count;
107 {
108     memset((char *)ring, 0, sizeof *ring);
109 
110     ring->size = count;
111 
112     ring->supply = ring->consume = ring->bottom = buffer;
113 
114     ring->top = ring->bottom+ring->size;
115 
116 
117     return 1;
118 }
119 
120 /* Mark routines */
121 
122 /*
123  * Mark the most recently supplied byte.
124  */
125 
126     void
127 ring_mark(ring)
128     Ring *ring;
129 {
130     ring->mark = ring_decrement(ring, ring->supply, 1);
131 }
132 
133 /*
134  * Is the ring pointing to the mark?
135  */
136 
137     int
138 ring_at_mark(ring)
139     Ring *ring;
140 {
141     if (ring->mark == ring->consume) {
142 	return 1;
143     } else {
144 	return 0;
145     }
146 }
147 
148 /*
149  * Clear any mark set on the ring.
150  */
151 
152     void
153 ring_clear_mark(ring)
154     Ring *ring;
155 {
156     ring->mark = 0;
157 }
158 
159 /*
160  * Add characters from current segment to ring buffer.
161  */
162     void
163 ring_supplied(ring, count)
164     Ring *ring;
165     int count;
166 {
167     ring->supply = ring_increment(ring, ring->supply, count);
168     ring->supplytime = ++ring_clock;
169 }
170 
171 /*
172  * We have just consumed "c" bytes.
173  */
174     void
175 ring_consumed(ring, count)
176     Ring *ring;
177     int count;
178 {
179     if (count == 0)	/* don't update anything */
180 	return;
181 
182     if (ring->mark &&
183 		(ring_subtract(ring, ring->mark, ring->consume) < count)) {
184 	ring->mark = 0;
185     }
186     ring->consume = ring_increment(ring, ring->consume, count);
187     ring->consumetime = ++ring_clock;
188     /*
189      * Try to encourage "ring_empty_consecutive()" to be large.
190      */
191     if (ring_empty(ring)) {
192 	ring->consume = ring->supply = ring->bottom;
193     }
194 }
195 
196 
197 
198 /* Buffer state query routines */
199 
200 
201 /* Number of bytes that may be supplied */
202     int
203 ring_empty_count(ring)
204     Ring *ring;
205 {
206     if (ring_empty(ring)) {	/* if empty */
207 	    return ring->size;
208     } else {
209 	return ring_subtract(ring, ring->consume, ring->supply);
210     }
211 }
212 
213 /* number of CONSECUTIVE bytes that may be supplied */
214     int
215 ring_empty_consecutive(ring)
216     Ring *ring;
217 {
218     if ((ring->consume < ring->supply) || ring_empty(ring)) {
219 			    /*
220 			     * if consume is "below" supply, or empty, then
221 			     * return distance to the top
222 			     */
223 	return ring_subtract(ring, ring->top, ring->supply);
224     } else {
225 				    /*
226 				     * else, return what we may.
227 				     */
228 	return ring_subtract(ring, ring->consume, ring->supply);
229     }
230 }
231 
232 /* Return the number of bytes that are available for consuming
233  * (but don't give more than enough to get to cross over set mark)
234  */
235 
236     int
237 ring_full_count(ring)
238     Ring *ring;
239 {
240     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
241 	if (ring_full(ring)) {
242 	    return ring->size;	/* nothing consumed, but full */
243 	} else {
244 	    return ring_subtract(ring, ring->supply, ring->consume);
245 	}
246     } else {
247 	return ring_subtract(ring, ring->mark, ring->consume);
248     }
249 }
250 
251 /*
252  * Return the number of CONSECUTIVE bytes available for consuming.
253  * However, don't return more than enough to cross over set mark.
254  */
255     int
256 ring_full_consecutive(ring)
257     Ring *ring;
258 {
259     if ((ring->mark == 0) || (ring->mark == ring->consume)) {
260 	if ((ring->supply < ring->consume) || ring_full(ring)) {
261 	    return ring_subtract(ring, ring->top, ring->consume);
262 	} else {
263 	    return ring_subtract(ring, ring->supply, ring->consume);
264 	}
265     } else {
266 	if (ring->mark < ring->consume) {
267 	    return ring_subtract(ring, ring->top, ring->consume);
268 	} else {	/* Else, distance to mark */
269 	    return ring_subtract(ring, ring->mark, ring->consume);
270 	}
271     }
272 }
273 
274 /*
275  * Move data into the "supply" portion of of the ring buffer.
276  */
277     void
278 ring_supply_data(ring, buffer, count)
279     Ring *ring;
280     unsigned char *buffer;
281     int count;
282 {
283     int i;
284 
285     while (count) {
286 	i = MIN(count, ring_empty_consecutive(ring));
287 	memcpy(ring->supply, buffer, i);
288 	ring_supplied(ring, i);
289 	count -= i;
290 	buffer += i;
291     }
292 }
293 
294 #ifdef notdef
295 
296 /*
297  * Move data from the "consume" portion of the ring buffer
298  */
299     void
300 ring_consume_data(ring, buffer, count)
301     Ring *ring;
302     unsigned char *buffer;
303     int count;
304 {
305     int i;
306 
307     while (count) {
308 	i = MIN(count, ring_full_consecutive(ring));
309 	memcpy(buffer, ring->consume, i);
310 	ring_consumed(ring, i);
311 	count -= i;
312 	buffer += i;
313     }
314 }
315 #endif
316 
317