2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2020, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure, Markus Armbruster
6 * Empire is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * See files README, COPYING and CREDITS in the root of the source
22 * tree for related information and legal notices. It is expected
23 * that future projects/authors will amend these files as needed.
27 * ringbuf.c: Simple ring buffer
29 * Known contributors to this file:
30 * Markus Armbruster, 2007-2017
41 * Initialize empty ring buffer.
42 * Not necessary if *@r is already zeroed.
45 ring_init(struct ring *r)
47 r->cons = r->prod = 0;
51 * Return number of bytes held in ring buffer.
54 ring_len(struct ring *r)
56 assert(r->prod - r->cons <= RING_SIZE);
57 return r->prod - r->cons;
61 * Return how much space is left in ring buffer.
64 ring_space(struct ring *r)
66 return RING_SIZE - (r->prod - r->cons);
70 * Peek at ring buffer contents.
71 * @n must be between -RING_SIZE-1 and RING_SIZE.
72 * If @n>=0, peek at the (@n+1)-th byte to be gotten.
73 * If @n<0, peek at the -@n-th byte that has been put in.
74 * Return the byte as unsigned char coverted to int, or EOF if there
75 * aren't that many bytes in the ring buffer.
78 ring_peek(struct ring *r, int n)
82 assert(-RING_SIZE - 1 <= n && n <= RING_SIZE);
89 /* Beware, r->prod - -n can wrap around, avoid that */
90 if (r->prod < r->cons + -n)
95 return r->buf[idx % RING_SIZE];
99 * Get and remove the oldest byte from the ring buffer.
100 * Return it as unsigned char converted to int, or EOF if the buffer was
104 ring_getc(struct ring *r)
106 if (r->cons == r->prod)
108 return r->buf[r->cons++ % RING_SIZE];
112 * Attempt to put byte @c into the ring buffer.
113 * Return EOF when the buffer is full, else @c.
116 ring_putc(struct ring *r, unsigned char c)
118 if (r->prod - r->cons == RING_SIZE)
120 return r->buf[r->prod++ % RING_SIZE] = c;
124 * Attempt to put @sz bytes from @buf into the ring buffer.
125 * Return space left in ring buffer when it fits, else don't change
126 * the ring buffer and return how much space is missing times -1.
129 ring_putm(struct ring *r, void *buf, size_t sz)
132 int left = ring_space(r) - sz;
138 for (i = 0; i < sz; i++)
139 res = ring_putc(r, p[i]);
147 * Discard the @n oldest bytes from the ring buffer.
148 * It must hold at least that many.
151 ring_discard(struct ring *r, int n)
153 assert(0 <= n && n <= ring_len(r));
158 * Search the ring buffer for zero-terminated string @s.
159 * Start at the (@n+1)-th byte to be gotten.
160 * If found, return the number of bytes in the buffer before @s.
164 ring_search(struct ring *r, char *s, int n)
166 size_t len = strlen(s);
169 for (i = r->cons + n; i + len <= r->prod; i++) {
170 for (j = 0; s[j] && s[j] == (char)r->buf[(i + j) % RING_SIZE]; j++)
179 * Fill ring buffer from file referred by file descriptor @fd.
180 * If ring buffer is already full, do nothing and return 0.
181 * Else attempt to read as many bytes as space permits, with readv(),
182 * and return its value.
185 ring_from_file(struct ring *r, int fd)
187 unsigned cons = r->cons % RING_SIZE;
188 unsigned prod = r->prod % RING_SIZE;
193 if (r->prod == r->cons + RING_SIZE)
196 iov[0].iov_base = r->buf + prod;
199 iov[0].iov_len = RING_SIZE - prod;
200 /* r->buf[..cons-1] */
201 iov[1].iov_base = r->buf;
202 iov[1].iov_len = cons;
205 /* r->buf[prod..cons-1] */
206 iov[0].iov_len = cons - prod;
209 res = readv(fd, iov, cnt);
217 * Set up @iov[] to describe complete contents of ring buffer.
218 * @iov[] must have at least two elements.
219 * Return number of elements used (zero for an empty ring buffer).
222 ring_to_iovec(struct ring *r, struct iovec iov[])
224 unsigned cons = r->cons % RING_SIZE;
225 unsigned prod = r->prod % RING_SIZE;
227 if (r->cons == r->prod)
230 iov[0].iov_base = r->buf + cons;
232 /* r->buf[cons..prod-1] */
233 iov[0].iov_len = prod - cons;
237 iov[0].iov_len = RING_SIZE - cons;
238 /* r->buf[..prod-1] */
239 iov[1].iov_base = r->buf;
240 iov[1].iov_len = prod;