]> git.pond.sub.org Git - empserver/blob - src/client/ioqueue.c
4f271239efbd795ac8f3b92bdd3d937d48d7cdda
[empserver] / src / client / ioqueue.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
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.
10  *
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.
15  *
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
19  *
20  *  ---
21  *
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.
25  *
26  *  ---
27  *
28  *  ioqueue.c: Manage an i/o queue
29  * 
30  *  Known contributors to this file:
31  *     Steve McClure, 1998
32  */
33
34 #include <config.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include "ioqueue.h"
40 #include "misc.h"
41 #include "queue.h"
42
43 static int ioqtobuf(struct ioqueue *ioq, char *buf, int cc);
44 static void enqueuecc(struct ioqueue *ioq, char *buf, int cc);
45 static int dequeuecc(struct ioqueue *ioq, int cc);
46
47
48 void
49 ioq_init(struct ioqueue *ioq, int bsize)
50 {
51     initque(&ioq->queue);
52     ioq->cc = 0;
53     ioq->bsize = bsize;
54 }
55
56 /*
57  * Copy the specified number of characters into the buffer
58  * provided, without actually dequeueing the data.  Return
59  * number of bytes actually found.
60  */
61 int
62 ioq_peek(struct ioqueue *ioq, char *buf, int cc)
63 {
64     return ioqtobuf(ioq, buf, cc);
65 }
66
67 int
68 ioq_dequeue(struct ioqueue *ioq, int cc)
69 {
70     if (dequeuecc(ioq, cc) != cc)
71         return 0;
72     return cc;
73 }
74
75 int
76 ioq_read(struct ioqueue *ioq, char *buf, int cc)
77 {
78     int n;
79
80     n = ioqtobuf(ioq, buf, cc);
81     if (n > 0)
82         dequeuecc(ioq, n);
83     return n;
84 }
85
86 void
87 ioq_write(struct ioqueue *ioq, char *buf, int cc)
88 {
89     enqueuecc(ioq, buf, cc);
90 }
91
92 int
93 ioq_qsize(struct ioqueue *ioq)
94 {
95     return ioq->cc;
96 }
97
98 void
99 ioq_drain(struct ioqueue *ioq)
100 {
101     struct io *io;
102     struct qelem *qp;
103
104     while ((qp = ioq->queue.q_forw) != &ioq->queue) {
105         io = (struct io *)qp;
106         free(io->data);
107         (void)remque(&io->queue);
108         (void)free(io);
109     }
110     ioq->cc = 0;
111 }
112
113 char *
114 ioq_gets(struct ioqueue *ioq, char *buf, int cc, int *eol)
115 {
116     char *p;
117     char *end;
118     int nbytes;
119
120     *eol = 0;
121
122     cc--;
123
124     nbytes = ioqtobuf(ioq, buf, cc);
125     end = &buf[nbytes];
126     for (p = buf; p < end && *p; p++) {
127         if (*p == '\n') {
128             *++p = '\0';
129             *eol = 1;
130             dequeuecc(ioq, p - buf);
131             return buf;
132         }
133     }
134     if (cc && (p - buf) == cc) {
135         dequeuecc(ioq, cc);
136         buf[cc] = '\0';
137         return buf;
138     }
139     return NULL;
140 }
141
142 /*
143  * all the rest are local to this module
144  */
145
146
147 /*
148  * copy cc bytes from ioq to buf.
149  * this routine doesn't free memory; this is
150  * left for a higher level.
151  */
152 static int
153 ioqtobuf(struct ioqueue *ioq, char *buf, int cc)
154 {
155     struct io *io;
156     struct qelem *qp;
157     char *offset;
158     int nbytes;
159     int nleft;
160
161     nleft = cc;
162     offset = buf;
163     for (qp = ioq->queue.q_forw; qp != &ioq->queue; qp = qp->q_forw) {
164         io = (struct io *)qp;
165         if ((nbytes = io->nbytes - io->offset) < 0) {
166             fprintf(stderr, "ioqtobuf: offset %d nbytes %d\n",
167                     io->offset, io->nbytes);
168             continue;
169         }
170         if (nbytes > 0) {
171             if (nleft < nbytes)
172                 nbytes = nleft;
173             memcpy(offset, io->data + io->offset, nbytes);
174             offset += nbytes;
175             nleft -= nbytes;
176         }
177     }
178     return offset - buf;
179 }
180
181 /*
182  * append a buffer to the end of the ioq.
183  */
184 static void
185 enqueuecc(struct ioqueue *ioq, char *buf, int cc)
186 {
187     struct io *io;
188
189     io = malloc(sizeof(*io));
190     io->nbytes = cc;
191     io->offset = 0;
192     io->data = buf;
193     insque(&io->queue, ioq->queue.q_back);
194     ioq->cc += cc;
195 }
196
197 /*
198  * remove cc bytes from ioqueue ioq
199  * free memory, dequeue io elements
200  * which are no longer used.
201  */
202 static int
203 dequeuecc(struct ioqueue *ioq, int cc)
204 {
205     struct io *io;
206     struct qelem *qp;
207     int nbytes;
208     int there;
209
210     nbytes = 0;
211     while ((qp = ioq->queue.q_forw) != &ioq->queue) {
212         io = (struct io *)qp;
213         there = io->nbytes - io->offset;
214         if (there < 0) {
215             fprintf(stderr, "dequeuecc: nbytes %d, offset %d\n",
216                     io->nbytes, io->offset);
217             continue;
218         }
219         if (cc > there) {
220             cc -= there;
221             nbytes += there;
222             (void)remque(&io->queue);
223             free(io->data);
224         } else {
225             io->offset += cc;
226             nbytes += cc;
227             break;
228         }
229     }
230     ioq->cc -= nbytes;
231     return nbytes;
232 }