]> git.pond.sub.org Git - empserver/blob - src/lib/gen/ioqueue.c
Import of Empire 4.2.12
[empserver] / src / lib / gen / ioqueue.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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 the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  ioqueue.c: Read and write i/o queues
29  * 
30  *  Known contributors to this file:
31  *     
32  */
33
34 /*
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.
38  */
39
40 #include <stdio.h>
41 #include <stdlib.h> /* malloc free */
42 #include <sys/types.h>
43 #if !defined(_WIN32)
44 #include <sys/uio.h>
45 #endif
46 #include "misc.h"
47 #include "queue.h"
48 #include "ioqueue.h"
49
50 static int ioqtocbuf(struct ioqueue *ioq, s_char *buf, int cc, register int stopc);
51 #if !defined(_WIN32)
52 static int ioqtoiov(struct ioqueue *ioq, struct iovec *iov, register int max);
53 #endif
54 static int ioqtobuf(struct ioqueue *ioq, s_char *buf, int cc);
55 static int appendcc(struct ioqueue *ioq, s_char *buf, int cc);
56 static int removecc(struct ioqueue *ioq, register int cc);
57
58 #if defined(_WIN32)
59 static void loc_StripDels(char *pBuf);
60 #endif
61
62 struct ioqueue *
63 ioq_create(int size)
64 {
65         struct  ioqueue *ioq;
66
67         ioq = (struct ioqueue *) malloc(sizeof(struct ioqueue));
68         emp_initque(&ioq->list.queue);
69         ioq->list.nbytes = 0;
70         ioq->list.offset = 0;
71         ioq->list.size = 0;
72         ioq->list.data = 0;
73         ioq->bufsize = size;
74         ioq->cc = 0;
75         return ioq;
76 }
77
78 void
79 ioq_destroy(struct ioqueue *ioq)
80 {
81 #if !defined(aix) && !defined(NeXT) 
82 /* ioq_drain doesn't work under aix or NeXT... dunno why --ts */
83         ioq_drain(ioq); 
84 #endif /* aix */
85         free((s_char *)ioq);
86 }
87
88 void
89 ioq_drain(struct ioqueue *ioq)
90 {
91         struct emp_qelem *qp;
92         struct io *io;
93
94         while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue){
95                 io = (struct io *) qp;
96                 (void) emp_remque(&io->queue);
97                 (void) free((s_char *)io->data);
98                 (void) free((s_char *)io);
99         }
100         
101         ioq->cc = 0;
102 }
103
104 /*
105  * copy batch of pointers into the passed
106  * iovec, but don't actually dequeue the data.
107  * return # of iovec initialized.
108  */
109 #if !defined(_WIN32)
110 int
111 ioq_makeiov(struct ioqueue *ioq, struct iovec *iov, int cc)
112 {
113         if (ioq->cc <= 0)
114                 return 0;
115         return ioqtoiov(ioq, iov, cc);
116 }
117 #endif
118
119 /*
120  * Copy the specified number of characters into the buffer
121  * provided, without actually dequeueing the data.  Return
122  * number of bytes actually found.
123  */
124 int
125 ioq_peek(struct ioqueue *ioq, s_char *buf, int cc)
126 {
127         return ioqtobuf(ioq, buf, cc);
128 }
129
130 int
131 ioq_dequeue(struct ioqueue *ioq, int cc)
132 {
133         return removecc(ioq, cc);
134 }
135
136 void
137 ioq_append(struct ioqueue *ioq, s_char *buf, int cc)
138 {
139         appendcc(ioq, buf, cc);
140 }
141
142 int
143 ioq_qsize(struct ioqueue *ioq)
144 {
145         return ioq->cc;
146 }
147
148 /*
149  * read a line of text up to (but not including)
150  * the newline.  return -1 and read nothing if
151  * no input is available
152  */
153 int
154 ioq_gets(struct ioqueue *ioq, s_char *buf, int cc)
155 {
156         int     nbytes;
157         int     actual;
158
159         nbytes = ioqtocbuf(ioq, buf, cc - 1, '\n');
160         if (nbytes >= 0) {
161                 actual = nbytes;
162                 if (actual > cc - 1)
163                         actual = cc - 1;
164                 buf[actual] = '\0';
165                 /* remove the newline too */
166                 removecc(ioq, nbytes + 1);
167 #if defined(_WIN32)
168         loc_StripDels(buf);
169 #endif
170         }
171         return nbytes;
172 }
173
174 int
175 ioq_puts(struct ioqueue *ioq, s_char *buf)
176 {
177         return appendcc(ioq, buf, strlen(buf));
178 }
179
180 /*
181  * all the rest are local to this module
182  */
183
184
185 /*
186  * copy cc bytes from ioq to buf.
187  * this routine doesn't free memory; this is
188  * left for a higher level.
189  */
190 static
191 int
192 ioqtobuf(struct ioqueue *ioq, s_char *buf, int cc)
193 {
194         struct io *io;
195         struct emp_qelem *qp;
196         struct emp_qelem *head;
197         register int nbytes;
198         register int nleft;
199         register s_char *offset;
200
201         nleft = cc;
202         offset = buf;
203         head = &ioq->list.queue;
204         for (qp = head->q_forw; qp != head && nleft > 0; qp = qp->q_forw) {
205                 io = (struct io *) qp;
206                 if ((nbytes = io->nbytes - io->offset) < 0) {
207                         /* XXX log something here */
208                         continue;
209                 }
210                 if (nbytes > 0) {
211                         if (nleft < nbytes)
212                                 nbytes = nleft;
213                         bcopy(io->data + io->offset, offset, nbytes);
214                         offset += nbytes;
215                         nleft -= nbytes;
216                 }
217         }
218         return offset - buf;
219 }
220
221 /*
222  * copy at most cc bytes from ioq to buf,
223  * terminating on the stop character.
224  */
225 static
226 int
227 ioqtocbuf(struct ioqueue *ioq, s_char *buf, int cc, register int stopc)
228 {
229         register int nbytes;
230         register s_char *p;
231         register int n;
232         struct  io *io;
233         struct  emp_qelem *qp;
234         struct  emp_qelem *head;
235         int     total;
236         int     found;
237
238         head = &ioq->list.queue;
239         found = 0;
240         total = 0;
241         for (qp = head->q_forw; qp != head; qp = qp->q_forw) {
242                 io = (struct io *) qp;
243                 if ((nbytes = io->nbytes - io->offset) <= 0)
244                         continue;
245                 p = io->data + io->offset;
246                 for (n=0; n < nbytes && p[n] != stopc; n++)
247                         ;
248                 total += n;
249                 if (n < nbytes) {
250                         found++;
251                         break;
252                 }
253         }
254         if (found == 0)
255                 return -1;
256         ioqtobuf(ioq, buf, cc < total ? cc : total);
257         return total;
258 }
259
260 /*
261  * initialize an iovec to point at max bytes worth
262  * of data from the ioqueue.
263  */
264 #if !defined(_WIN32)
265 static
266 int
267 ioqtoiov(struct ioqueue *ioq, struct iovec *iov, register int max)
268 {
269         struct io *io;
270         register int cc;
271         register int niov;
272         register int len;
273         struct  emp_qelem *qp;
274
275         cc = max;
276         niov = 0;
277         qp = ioq->list.queue.q_forw;
278         while (qp != &ioq->list.queue && cc > 0) {
279                 io = (struct io *) qp;
280                 len = io->nbytes - io->offset;
281                 if (len > cc)
282                         len = cc;
283                 iov->iov_base = io->data + io->offset;
284                 iov->iov_len = len;
285                 cc -= len;
286                 niov++;
287                 iov++;
288                 qp = qp->q_forw;
289                 if (niov >= 16)
290                         break;
291         }
292         return niov;
293 }
294 #endif
295
296 /*
297  * append a buffer to the end of the ioq.
298  */
299 static
300 int
301 appendcc(struct ioqueue *ioq, s_char *buf, int cc)
302 {
303         struct io *io;
304         int     len;
305         s_char  *ptr;
306         int     avail;
307
308         /* determine if any space is left */
309         io = (struct io *)ioq->list.queue.q_back;
310         avail = io->size - io->nbytes;
311         if (avail > 0) {
312                 /* append to existing buffer */
313                 len = cc > avail ? avail : cc;
314                 bcopy(buf, io->data + io->nbytes, len);
315                 io->nbytes += len;
316                 ioq->cc += len;
317                 if (avail < cc)
318                         appendcc(ioq, buf + len, cc - len);
319         } else {
320                 /* create a new buffer, minimum bufsize bytes */
321                 len = cc > ioq->bufsize ? cc : ioq->bufsize;
322                 ptr = malloc(len);
323                 bcopy(buf, ptr, cc);
324                 io = (struct io *) malloc(sizeof(struct io));
325                 io->nbytes = cc;
326                 io->size = len;
327                 io->offset = 0;
328                 io->data = ptr;
329                 emp_insque(&io->queue, ioq->list.queue.q_back);
330                 ioq->cc += cc;
331         }
332         return cc;
333 }
334
335 /*
336  * remove cc bytes from ioqueue ioq
337  * free memory, dequeue io elements
338  * which are no longer used.
339  */
340 static
341 int
342 removecc(struct ioqueue *ioq, register int cc)
343 {
344         struct io *io;
345         struct emp_qelem *qp;
346         register int nbytes;
347         register int there;
348         register int remain;
349
350         nbytes = 0;
351         remain = cc;
352         while ((qp = ioq->list.queue.q_forw) != &ioq->list.queue) {
353                 io = (struct io *) qp;
354                 there = io->nbytes - io->offset;
355                 if (there < 0) {
356                         /* error */
357                         (void) emp_remque(&io->queue);
358                         (void) free((s_char *)io);
359                         continue;
360                 }
361                 if (remain >= there) {
362                         /* not enough or exact; free entry */
363                         nbytes += there;
364                         remain -= there;
365                         (void) emp_remque(&io->queue);
366                         (void) free(io->data);
367                         (void) free((s_char *)io);
368                 } else {
369                         /* too much; increment offset */
370                         io->offset += remain;
371                         nbytes += remain;
372                         remain = 0;
373                 }
374                 if (remain <= 0)
375                         break;
376         }
377         ioq->cc -= nbytes;
378         return nbytes;
379 }
380 #if defined(_WIN32)
381 /*
382  * Make an (output) buffer up to the
383  * maximum size of the buffer.
384  *
385  * We don't free the bytes...
386  */
387 int
388 ioq_makebuf(struct ioqueue *ioq, char *pBuf, int nBufLen)
389 {
390         struct io *io;
391         struct emp_qelem *qp;
392         struct emp_qelem *head;
393         int nbytes;
394         int nleft;
395     int ncopied;
396         s_char *offset;
397
398     ncopied = 0;
399         nleft = nBufLen;
400         offset = pBuf;
401         head = &ioq->list.queue;
402
403         for (qp = head->q_forw;
404                     (qp != head) && (nleft > 0);
405                     qp = qp->q_forw) {
406                 io = (struct io *) qp;
407                 nbytes = io->nbytes - io->offset;
408                 if (nbytes < 0) {
409             /* Paranoid check for bad buffer. */
410                         continue;
411                 }
412
413         /* too many bytes, wait till next time. */
414         if (nbytes > nleft)
415             break;
416
417                 bcopy(io->data + io->offset, offset, nbytes);
418                 offset += nbytes;
419                 nleft -= nbytes;
420         ncopied += nbytes;
421         }
422         return ncopied;
423 }
424 #endif /* _WIN32 */
425
426 #if defined(_WIN32)
427 /*
428  * Remove backspaces and DELs from the buffer.
429  *
430  * Why?  Because I got tired of telneting into the
431  * server and having to type perfectly...
432  */
433 static void
434 loc_StripDels(char *pBuf)
435 {
436     char *cp;
437     char *dp;
438     char *sp;
439
440     for (cp = pBuf; *cp;) {
441         /* Remove Backspace and DEL */
442         if (*cp == '\b' || *cp == '\x8F') {
443             if (cp == pBuf)
444                 dp = cp;
445             else
446                 dp = cp - 1;
447             sp = cp + 1;
448             while (*sp)
449                 *dp++ = *sp++;
450             *dp = 0;
451         } else
452             cp++;
453     }
454 }
455 #endif
456