2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
6 * This program 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 2 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * See files README, COPYING and CREDITS in the root of the source
23 * tree for related information and legal notices. It is expected
24 * that future projects/authors will amend these files as needed.
28 * ioqueue.c: Read and write i/o queues
30 * Known contributors to this file:
35 * Read and write onto io queues. Note that
36 * the io queues don't actually do any writing;
37 * that is left for a higher level.
45 #include <sys/types.h>
53 static int ioqtocbuf(struct ioqueue *ioq, char *buf, int cc, int stopc);
55 static int ioqtoiov(struct ioqueue *ioq, struct iovec *iov, int max);
57 static int ioqtobuf(struct ioqueue *ioq, char *buf, int cc);
58 static int appendcc(struct ioqueue *ioq, char *buf, int cc);
59 static int removecc(struct ioqueue *ioq, int cc);
66 ioq = malloc(sizeof(struct ioqueue));
67 emp_initque(&ioq->list.queue);
78 ioq_destroy(struct ioqueue *ioq)
85 ioq_drain(struct ioqueue *ioq)
90 while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
92 emp_remque(&io->queue);
101 * copy batch of pointers into the passed
102 * iovec, but don't actually dequeue the data.
103 * return # of iovec initialized.
107 ioq_makeiov(struct ioqueue *ioq, struct iovec *iov, int cc)
111 return ioqtoiov(ioq, iov, cc);
116 * Copy the specified number of characters into the buffer
117 * provided, without actually dequeueing the data. Return
118 * number of bytes actually found.
121 ioq_peek(struct ioqueue *ioq, char *buf, int cc)
123 return ioqtobuf(ioq, buf, cc);
127 ioq_dequeue(struct ioqueue *ioq, int cc)
129 return removecc(ioq, cc);
133 ioq_append(struct ioqueue *ioq, char *buf, int cc)
135 appendcc(ioq, buf, cc);
139 ioq_qsize(struct ioqueue *ioq)
145 * read a line of text up to (but not including)
146 * the newline. return -1 and read nothing if
147 * no input is available
150 ioq_gets(struct ioqueue *ioq, char *buf, int cc)
155 nbytes = ioqtocbuf(ioq, buf, cc - 1, '\n');
160 /* telnet terminates lines with "\r\n", get rid of \r */
161 if (actual > 0 && buf[actual-1] == '\r')
164 /* remove the newline too */
165 removecc(ioq, nbytes + 1);
171 ioq_puts(struct ioqueue *ioq, char *buf)
173 return appendcc(ioq, buf, strlen(buf));
177 * copy cc bytes from ioq to buf.
178 * this routine doesn't free memory; this is
179 * left for a higher level.
182 ioqtobuf(struct ioqueue *ioq, char *buf, int cc)
185 struct emp_qelem *qp;
186 struct emp_qelem *head;
192 head = &ioq->list.queue;
193 for (qp = head->q_forw; qp != head && nleft > 0; qp = qp->q_forw) {
194 io = (struct io *)qp;
195 if ((nbytes = io->nbytes - io->offset) < 0) {
196 /* XXX log something here */
202 memcpy(offset, io->data + io->offset, nbytes);
211 * copy at most cc bytes from ioq to buf,
212 * terminating on the stop character.
215 ioqtocbuf(struct ioqueue *ioq, char *buf, int cc, int stopc)
221 struct emp_qelem *qp;
222 struct emp_qelem *head;
226 head = &ioq->list.queue;
229 for (qp = head->q_forw; qp != head; qp = qp->q_forw) {
230 io = (struct io *)qp;
231 if ((nbytes = io->nbytes - io->offset) <= 0)
233 p = io->data + io->offset;
234 for (n = 0; n < nbytes && p[n] != stopc; n++) ;
243 ioqtobuf(ioq, buf, cc < total ? cc : total);
248 * initialize an iovec to point at max bytes worth
249 * of data from the ioqueue.
253 ioqtoiov(struct ioqueue *ioq, struct iovec *iov, int max)
257 struct emp_qelem *qp;
261 qp = ioq->list.queue.q_forw;
262 while (qp != &ioq->list.queue && cc > 0) {
263 io = (struct io *)qp;
264 len = io->nbytes - io->offset;
267 iov->iov_base = io->data + io->offset;
281 * append a buffer to the end of the ioq.
284 appendcc(struct ioqueue *ioq, char *buf, int cc)
291 /* determine if any space is left */
292 io = (struct io *)ioq->list.queue.q_back;
293 avail = io->size - io->nbytes;
295 /* append to existing buffer */
296 len = cc > avail ? avail : cc;
297 memcpy(io->data + io->nbytes, buf, len);
301 appendcc(ioq, buf + len, cc - len);
303 /* create a new buffer, minimum bufsize bytes */
304 len = cc > ioq->bufsize ? cc : ioq->bufsize;
306 memcpy(ptr, buf, cc);
307 io = malloc(sizeof(struct io));
312 emp_insque(&io->queue, ioq->list.queue.q_back);
319 * remove cc bytes from ioqueue ioq
320 * free memory, dequeue io elements
321 * which are no longer used.
324 removecc(struct ioqueue *ioq, int cc)
327 struct emp_qelem *qp;
328 int nbytes, there, remain;
332 while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
333 io = (struct io *)qp;
334 there = io->nbytes - io->offset;
337 emp_remque(&io->queue);
341 if (remain >= there) {
342 /* not enough or exact; free entry */
345 emp_remque(&io->queue);
349 /* too much; increment offset */
350 io->offset += remain;
363 * Make an (output) buffer up to the
364 * maximum size of the buffer.
366 * We don't free the bytes...
369 ioq_makebuf(struct ioqueue *ioq, char *pBuf, int nBufLen)
372 struct emp_qelem *qp;
373 struct emp_qelem *head;
382 head = &ioq->list.queue;
384 for (qp = head->q_forw; (qp != head) && (nleft > 0); qp = qp->q_forw) {
385 io = (struct io *)qp;
386 nbytes = io->nbytes - io->offset;
388 /* Paranoid check for bad buffer. */
392 /* too many bytes, wait till next time. */
396 memcpy(offset, io->data + io->offset, nbytes);