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.
49 static int ioqtocbuf(struct ioqueue *ioq, char *buf, int cc, int stopc);
50 static int ioqtoiov(struct ioqueue *ioq, struct iovec *iov, int max);
51 static int ioqtobuf(struct ioqueue *ioq, char *buf, int cc);
52 static int appendcc(struct ioqueue *ioq, char *buf, int cc);
53 static int removecc(struct ioqueue *ioq, int cc);
60 ioq = malloc(sizeof(struct ioqueue));
61 emp_initque(&ioq->list.queue);
72 ioq_destroy(struct ioqueue *ioq)
79 ioq_drain(struct ioqueue *ioq)
84 while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
86 emp_remque(&io->queue);
95 * copy batch of pointers into the passed
96 * iovec, but don't actually dequeue the data.
97 * return # of iovec initialized.
100 ioq_makeiov(struct ioqueue *ioq, struct iovec *iov, int cc)
104 return ioqtoiov(ioq, iov, cc);
108 * Copy the specified number of characters into the buffer
109 * provided, without actually dequeueing the data. Return
110 * number of bytes actually found.
113 ioq_peek(struct ioqueue *ioq, char *buf, int cc)
115 return ioqtobuf(ioq, buf, cc);
119 ioq_dequeue(struct ioqueue *ioq, int cc)
121 return removecc(ioq, cc);
125 ioq_append(struct ioqueue *ioq, char *buf, int cc)
127 appendcc(ioq, buf, cc);
131 ioq_qsize(struct ioqueue *ioq)
137 * read a line of text up to (but not including)
138 * the newline. return -1 and read nothing if
139 * no input is available
142 ioq_gets(struct ioqueue *ioq, char *buf, int cc)
147 nbytes = ioqtocbuf(ioq, buf, cc - 1, '\n');
152 /* telnet terminates lines with "\r\n", get rid of \r */
153 if (actual > 0 && buf[actual-1] == '\r')
156 /* remove the newline too */
157 removecc(ioq, nbytes + 1);
163 ioq_puts(struct ioqueue *ioq, char *buf)
165 return appendcc(ioq, buf, strlen(buf));
169 * copy cc bytes from ioq to buf.
170 * this routine doesn't free memory; this is
171 * left for a higher level.
174 ioqtobuf(struct ioqueue *ioq, char *buf, int cc)
177 struct emp_qelem *qp;
178 struct emp_qelem *head;
184 head = &ioq->list.queue;
185 for (qp = head->q_forw; qp != head && nleft > 0; qp = qp->q_forw) {
186 io = (struct io *)qp;
187 if ((nbytes = io->nbytes - io->offset) < 0) {
188 /* XXX log something here */
194 memcpy(offset, io->data + io->offset, nbytes);
203 * copy at most cc bytes from ioq to buf,
204 * terminating on the stop character.
207 ioqtocbuf(struct ioqueue *ioq, char *buf, int cc, int stopc)
213 struct emp_qelem *qp;
214 struct emp_qelem *head;
218 head = &ioq->list.queue;
221 for (qp = head->q_forw; qp != head; qp = qp->q_forw) {
222 io = (struct io *)qp;
223 if ((nbytes = io->nbytes - io->offset) <= 0)
225 p = io->data + io->offset;
226 for (n = 0; n < nbytes && p[n] != stopc; n++) ;
235 ioqtobuf(ioq, buf, cc < total ? cc : total);
240 * initialize an iovec to point at max bytes worth
241 * of data from the ioqueue.
244 ioqtoiov(struct ioqueue *ioq, struct iovec *iov, int max)
248 struct emp_qelem *qp;
252 qp = ioq->list.queue.q_forw;
253 while (qp != &ioq->list.queue && cc > 0) {
254 io = (struct io *)qp;
255 len = io->nbytes - io->offset;
258 iov->iov_base = io->data + io->offset;
271 * append a buffer to the end of the ioq.
274 appendcc(struct ioqueue *ioq, char *buf, int cc)
281 /* determine if any space is left */
282 io = (struct io *)ioq->list.queue.q_back;
283 avail = io->size - io->nbytes;
285 /* append to existing buffer */
286 len = cc > avail ? avail : cc;
287 memcpy(io->data + io->nbytes, buf, len);
291 appendcc(ioq, buf + len, cc - len);
293 /* create a new buffer, minimum bufsize bytes */
294 len = cc > ioq->bufsize ? cc : ioq->bufsize;
296 memcpy(ptr, buf, cc);
297 io = malloc(sizeof(struct io));
302 emp_insque(&io->queue, ioq->list.queue.q_back);
309 * remove cc bytes from ioqueue ioq
310 * free memory, dequeue io elements
311 * which are no longer used.
314 removecc(struct ioqueue *ioq, int cc)
317 struct emp_qelem *qp;
318 int nbytes, there, remain;
322 while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
323 io = (struct io *)qp;
324 there = io->nbytes - io->offset;
327 emp_remque(&io->queue);
331 if (remain >= there) {
332 /* not enough or exact; free entry */
335 emp_remque(&io->queue);
339 /* too much; increment offset */
340 io->offset += remain;