written by Eric Allman; add Berkeley specific header
[unix-history] / usr / src / usr.bin / telnet / ring.c
CommitLineData
897ce52e
KB
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that this notice is preserved and that due credit is given
7 * to the University of California at Berkeley. The name of the University
8 * may not be used to endorse or promote products derived from this
9 * software without specific prior written permission. This software
10 * is provided ``as is'' without express or implied warranty.
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)ring.c 1.8 (Berkeley) %G%";
15#endif /* not lint */
16
cde671b6 17/*
8b6750f5 18 * This defines a structure for a ring buffer.
cde671b6 19 *
8b6750f5 20 * The circular buffer has two parts:
cde671b6 21 *(((
8b6750f5
GM
22 * full: [consume, supply)
23 * empty: [supply, consume)
cde671b6
GM
24 *]]]
25 *
cde671b6
GM
26 */
27
28#include <stdio.h>
29#include <errno.h>
30
31#ifdef size_t
32#undef size_t
33#endif
34
35#include <sys/types.h>
36#include <sys/ioctl.h>
37#include <sys/socket.h>
38
39#include "ring.h"
40#include "general.h"
41
42/* Internal macros */
43
115a5494
GM
44#if !defined(MIN)
45#define MIN(a,b) (((a)<(b))? (a):(b))
46#endif /* !defined(MIN) */
cde671b6 47
115a5494
GM
48#define ring_subtract(d,a,b) ((((int)(a))-((int)(b)) >= 0)? \
49 (a)-(b): (((a)-(b))+(d)->size))
cde671b6
GM
50
51#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \
52 (a)+(c) : (((a)+(c))-(d)->size))
53
218b1a4c
GM
54#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \
55 (a)-(c) : (((a)-(c))-(d)->size))
56
cde671b6
GM
57
58/*
59 * The following is a clock, used to determine full, empty, etc.
60 *
61 * There is some trickiness here. Since the ring buffers are initialized
62 * to ZERO on allocation, we need to make sure, when interpreting the
8b6750f5 63 * clock, that when the times are EQUAL, then the buffer is FULL.
cde671b6
GM
64 */
65static u_long ring_clock = 0;
66
67
8b6750f5
GM
68#define ring_empty(d) (((d)->consume == (d)->supply) && \
69 ((d)->consumetime >= (d)->supplytime))
70#define ring_full(d) (((d)->supply == (d)->consume) && \
71 ((d)->supplytime > (d)->consumetime))
cde671b6
GM
72
73
74
75
76
77/* Buffer state transition routines */
78
115a5494
GM
79ring_init(ring, buffer, count)
80Ring *ring;
81char *buffer;
82int count;
83{
84 memset((char *)ring, 0, sizeof *ring);
85
86 ring->size = count;
87
8b6750f5 88 ring->supply = ring->consume = ring->bottom = buffer;
115a5494
GM
89
90 ring->top = ring->bottom+ring->size;
91
92 return 1;
93}
cde671b6 94
218b1a4c
GM
95/* Mark routines */
96
97/*
98 * Mark the most recently supplied byte.
99 */
100
101void
102ring_mark(ring)
103Ring *ring;
104{
105 ring->mark = ring_decrement(ring, ring->supply, 1);
106}
107
108/*
109 * Is the ring pointing to the mark?
110 */
111
112int
113ring_at_mark(ring)
114Ring *ring;
115{
116 if (ring->mark == ring->consume) {
117 return 1;
118 } else {
119 return 0;
120 }
121}
122
123/*
124 * Clear any mark set on the ring.
125 */
126
127void
128ring_clear_mark(ring)
129Ring *ring;
130{
131 ring->mark = 0;
132}
133
cde671b6
GM
134/*
135 * Add characters from current segment to ring buffer.
136 */
137void
8b6750f5 138ring_supplied(ring, count)
cde671b6
GM
139Ring *ring;
140int count;
141{
8b6750f5
GM
142 ring->supply = ring_increment(ring, ring->supply, count);
143 ring->supplytime = ++ring_clock;
cde671b6
GM
144}
145
146/*
8b6750f5 147 * We have just consumed "c" bytes.
cde671b6
GM
148 */
149void
8b6750f5 150ring_consumed(ring, count)
cde671b6
GM
151Ring *ring;
152int count;
153{
ad1c581e
GM
154 if (count == 0) /* don't update anything */
155 return;
156
218b1a4c
GM
157 if (ring->mark &&
158 (ring_subtract(ring, ring->mark, ring->consume) < count)) {
159 ring->mark = 0;
160 }
8b6750f5
GM
161 ring->consume = ring_increment(ring, ring->consume, count);
162 ring->consumetime = ++ring_clock;
8166d918
GM
163 /*
164 * Try to encourage "ring_empty_consecutive()" to be large.
165 */
166 if (ring_empty(ring)) {
167 ring->consume = ring->supply = ring->bottom;
168 }
cde671b6
GM
169}
170
e8507c1e 171
cde671b6
GM
172
173/* Buffer state query routines */
174
175
8b6750f5 176/* Number of bytes that may be supplied */
cde671b6
GM
177int
178ring_empty_count(ring)
179Ring *ring;
180{
8b6750f5 181 if (ring_empty(ring)) { /* if empty */
cde671b6
GM
182 return ring->size;
183 } else {
8b6750f5 184 return ring_subtract(ring, ring->consume, ring->supply);
cde671b6
GM
185 }
186}
187
8b6750f5 188/* number of CONSECUTIVE bytes that may be supplied */
cde671b6
GM
189int
190ring_empty_consecutive(ring)
191Ring *ring;
192{
8b6750f5
GM
193 if ((ring->consume < ring->supply) || ring_empty(ring)) {
194 /*
195 * if consume is "below" supply, or empty, then
196 * return distance to the top
197 */
198 return ring_subtract(ring, ring->top, ring->supply);
cde671b6
GM
199 } else {
200 /*
201 * else, return what we may.
202 */
8b6750f5 203 return ring_subtract(ring, ring->consume, ring->supply);
cde671b6
GM
204 }
205}
206
218b1a4c
GM
207/* Return the number of bytes that are available for consuming
208 * (but don't give more than enough to get to cross over set mark)
209 */
210
cde671b6 211int
8b6750f5 212ring_full_count(ring)
cde671b6
GM
213Ring *ring;
214{
218b1a4c
GM
215 if ((ring->mark == 0) || (ring->mark == ring->consume)) {
216 if (ring_full(ring)) {
217 return ring->size; /* nothing consumed, but full */
218 } else {
219 return ring_subtract(ring, ring->supply, ring->consume);
220 }
cde671b6 221 } else {
218b1a4c 222 return ring_subtract(ring, ring->mark, ring->consume);
cde671b6
GM
223 }
224}
225
218b1a4c
GM
226/*
227 * Return the number of CONSECUTIVE bytes available for consuming.
228 * However, don't return more than enough to cross over set mark.
229 */
cde671b6 230int
8b6750f5 231ring_full_consecutive(ring)
cde671b6
GM
232Ring *ring;
233{
218b1a4c
GM
234 if ((ring->mark == 0) || (ring->mark == ring->consume)) {
235 if ((ring->supply < ring->consume) || ring_full(ring)) {
236 return ring_subtract(ring, ring->top, ring->consume);
237 } else {
238 return ring_subtract(ring, ring->supply, ring->consume);
239 }
cde671b6 240 } else {
218b1a4c
GM
241 if (ring->mark < ring->consume) {
242 return ring_subtract(ring, ring->top, ring->consume);
243 } else { /* Else, distance to mark */
244 return ring_subtract(ring, ring->mark, ring->consume);
245 }
cde671b6
GM
246 }
247}
248
cde671b6 249/*
8b6750f5 250 * Move data into the "supply" portion of of the ring buffer.
cde671b6
GM
251 */
252void
8b6750f5 253ring_supply_data(ring, buffer, count)
cde671b6
GM
254Ring *ring;
255char *buffer;
256int count;
257{
258 int i;
259
260 while (count) {
115a5494 261 i = MIN(count, ring_empty_consecutive(ring));
8b6750f5
GM
262 memcpy(ring->supply, buffer, i);
263 ring_supplied(ring, i);
cde671b6
GM
264 count -= i;
265 buffer += i;
266 }
267}
268
269
270/*
8b6750f5 271 * Move data from the "consume" portion of the ring buffer
cde671b6
GM
272 */
273void
8b6750f5 274ring_consume_data(ring, buffer, count)
cde671b6
GM
275Ring *ring;
276char *buffer;
277int count;
278{
279 int i;
280
281 while (count) {
8b6750f5
GM
282 i = MIN(count, ring_full_consecutive(ring));
283 memcpy(buffer, ring->consume, i);
284 ring_consumed(ring, i);
cde671b6
GM
285 count -= i;
286 buffer += i;
287 }
288}