]> jfr.im git - solanum.git/blame - librb/src/linebuf.c
librb: linebuf: don't reinvent rb_dlinkAddTailAlloc().
[solanum.git] / librb / src / linebuf.c
CommitLineData
db137867
AC
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * linebuf.c: Maintains linebuffers.
4 *
5 * Copyright (C) 2001-2002 Adrian Chadd <adrian@creative.net.au>
6 * Copyright (C) 2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 * USA
23 *
db137867
AC
24 */
25
fe037171
EM
26#include <librb_config.h>
27#include <rb_lib.h>
db137867
AC
28#include <commio-int.h>
29
db137867 30static rb_bh *rb_linebuf_heap;
db137867
AC
31
32static int bufline_count = 0;
33
34#ifndef LINEBUF_HEAP_SIZE
35#define LINEBUF_HEAP_SIZE 2048
36#endif
37
38/*
39 * rb_linebuf_init
40 *
41 * Initialise the linebuf mechanism
42 */
43
44void
45rb_linebuf_init(size_t heap_size)
46{
db137867 47 rb_linebuf_heap = rb_bh_create(sizeof(buf_line_t), heap_size, "librb_linebuf_heap");
db137867
AC
48}
49
50static buf_line_t *
51rb_linebuf_allocate(void)
52{
53 buf_line_t *t;
db137867 54 t = rb_bh_alloc(rb_linebuf_heap);
db137867
AC
55 return (t);
56
57}
58
59static void
60rb_linebuf_free(buf_line_t * p)
61{
db137867 62 rb_bh_free(rb_linebuf_heap, p);
db137867
AC
63}
64
65/*
66 * rb_linebuf_new_line
67 *
68 * Create a new line, and link it to the given linebuf.
69 * It will be initially empty.
70 */
71static buf_line_t *
72rb_linebuf_new_line(buf_head_t * bufhead)
73{
74 buf_line_t *bufline;
db137867
AC
75
76 bufline = rb_linebuf_allocate();
77 if(bufline == NULL)
78 return NULL;
79 ++bufline_count;
80
db137867 81 /* Stick it at the end of the buf list */
a2bfe0f8 82 rb_dlinkAddTailAlloc(bufline, &bufhead->list);
db137867
AC
83 bufline->refcount++;
84
85 /* And finally, update the allocated size */
86 bufhead->alloclen++;
87 bufhead->numlines++;
88
89 return bufline;
90}
91
92
93/*
94 * rb_linebuf_done_line
95 *
96 * We've finished with the given line, so deallocate it
97 */
98static void
3202e249 99rb_linebuf_done_line(buf_head_t * bufhead, buf_line_t * bufline, rb_dlink_node *node)
db137867
AC
100{
101 /* Remove it from the linked list */
102 rb_dlinkDestroy(node, &bufhead->list);
103
104 /* Update the allocated size */
105 bufhead->alloclen--;
106 bufhead->len -= bufline->len;
107 lrb_assert(bufhead->len >= 0);
108 bufhead->numlines--;
109
110 bufline->refcount--;
111 lrb_assert(bufline->refcount >= 0);
112
113 if(bufline->refcount == 0)
114 {
115 /* and finally, deallocate the buf */
116 --bufline_count;
117 lrb_assert(bufline_count >= 0);
118 rb_linebuf_free(bufline);
119 }
120}
121
122
123/*
124 * skip to end of line or the crlfs, return the number of bytes ..
125 */
126static inline int
127rb_linebuf_skip_crlf(char *ch, int len)
128{
129 int orig_len = len;
130
131 /* First, skip until the first non-CRLF */
132 for(; len; len--, ch++)
133 {
134 if(*ch == '\r')
135 break;
136 else if(*ch == '\n')
137 break;
138 }
139
140 /* Then, skip until the last CRLF */
141 for(; len; len--, ch++)
142 {
143 if((*ch != '\r') && (*ch != '\n'))
144 break;
145 }
146 lrb_assert(orig_len > len);
147 return (orig_len - len);
148}
149
150
151
152/*
153 * rb_linebuf_newbuf
154 *
155 * Initialise the new buffer
156 */
157void
158rb_linebuf_newbuf(buf_head_t * bufhead)
159{
160 /* not much to do right now :) */
161 memset(bufhead, 0, sizeof(buf_head_t));
162}
163
164/*
165 * rb_linebuf_donebuf
166 *
167 * Flush all the lines associated with this buffer
168 */
169void
170rb_linebuf_donebuf(buf_head_t * bufhead)
171{
172 while(bufhead->list.head != NULL)
173 {
3202e249
VY
174 rb_linebuf_done_line(bufhead, (buf_line_t *) bufhead->list.head->data,
175 bufhead->list.head);
db137867
AC
176 }
177}
178
179/*
180 * rb_linebuf_copy_line
181 *
182 * Okay..this functions comments made absolutely no sense.
55abcbb2 183 *
db137867
AC
184 * Basically what we do is this. Find the first chunk of text
185 * and then scan for a CRLF. If we didn't find it, but we didn't
186 * overflow our buffer..we wait for some more data.
187 * If we found a CRLF, we replace them with a \0 character.
188 * If we overflowed, we copy the most our buffer can handle, terminate
189 * it with a \0 and return.
190 *
191 * The return value is the amount of data we consumed. This could
192 * be different than the size of the linebuffer, as when we discard
193 * the overflow, we don't want to process it again.
194 *
195 * This still sucks in my opinion, but it seems to work.
196 *
197 * -Aaron
198 */
199static int
200rb_linebuf_copy_line(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
201{
202 int cpylen = 0; /* how many bytes we've copied */
203 char *ch = data; /* Pointer to where we are in the read data */
204 char *bufch = bufline->buf + bufline->len;
205 int clen = 0; /* how many bytes we've processed,
206 and don't ever want to see again.. */
207
208 /* If its full or terminated, ignore it */
209
210 bufline->raw = 0;
211 lrb_assert(bufline->len < BUF_DATA_SIZE);
212 if(bufline->terminated == 1)
213 return 0;
214
215 clen = cpylen = rb_linebuf_skip_crlf(ch, len);
216 if(clen == -1)
217 return -1;
218
219 /* This is the ~overflow case..This doesn't happen often.. */
220 if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
221 {
1c864688
JT
222 cpylen = BUF_DATA_SIZE - bufline->len - 1;
223 memcpy(bufch, ch, cpylen);
db137867
AC
224 bufline->buf[BUF_DATA_SIZE - 1] = '\0';
225 bufch = bufline->buf + BUF_DATA_SIZE - 2;
226 while(cpylen && (*bufch == '\r' || *bufch == '\n'))
227 {
228 *bufch = '\0';
229 cpylen--;
230 bufch--;
231 }
232 bufline->terminated = 1;
233 bufline->len = BUF_DATA_SIZE - 1;
234 bufhead->len += BUF_DATA_SIZE - 1;
235 return clen;
236 }
237
238 memcpy(bufch, ch, cpylen);
239 bufch += cpylen;
240 *bufch = '\0';
241 bufch--;
242
243 if(*bufch != '\r' && *bufch != '\n')
244 {
245 /* No linefeed, bail for the next time */
246 bufhead->len += cpylen;
247 bufline->len += cpylen;
248 bufline->terminated = 0;
249 return clen;
250 }
251
252 /* Yank the CRLF off this, replace with a \0 */
253 while(cpylen && (*bufch == '\r' || *bufch == '\n'))
254 {
255 *bufch = '\0';
256 cpylen--;
257 bufch--;
258 }
259
260 bufline->terminated = 1;
261 bufhead->len += cpylen;
262 bufline->len += cpylen;
263 return clen;
264}
265
266/*
267 * rb_linebuf_copy_raw
268 *
269 * Copy as much data as possible directly into a linebuf,
270 * splitting at \r\n, but without altering any data.
271 *
272 */
273static int
274rb_linebuf_copy_raw(buf_head_t * bufhead, buf_line_t * bufline, char *data, int len)
275{
276 int cpylen = 0; /* how many bytes we've copied */
277 char *ch = data; /* Pointer to where we are in the read data */
278 char *bufch = bufline->buf + bufline->len;
279 int clen = 0; /* how many bytes we've processed,
280 and don't ever want to see again.. */
281
282 /* If its full or terminated, ignore it */
283
284 bufline->raw = 1;
285 lrb_assert(bufline->len < BUF_DATA_SIZE);
286 if(bufline->terminated == 1)
287 return 0;
288
289 clen = cpylen = rb_linebuf_skip_crlf(ch, len);
290 if(clen == -1)
291 return -1;
292
293 /* This is the overflow case..This doesn't happen often.. */
294 if(cpylen > (BUF_DATA_SIZE - bufline->len - 1))
295 {
296 clen = BUF_DATA_SIZE - bufline->len - 1;
297 memcpy(bufch, ch, clen);
298 bufline->buf[BUF_DATA_SIZE - 1] = '\0';
299 bufch = bufline->buf + BUF_DATA_SIZE - 2;
300 bufline->terminated = 1;
301 bufline->len = BUF_DATA_SIZE - 1;
302 bufhead->len += BUF_DATA_SIZE - 1;
303 return clen;
304 }
305
306 memcpy(bufch, ch, cpylen);
307 bufch += cpylen;
308 *bufch = '\0';
309 bufch--;
310
311 if(*bufch != '\r' && *bufch != '\n')
312 {
313 /* No linefeed, bail for the next time */
314 bufhead->len += cpylen;
315 bufline->len += cpylen;
316 bufline->terminated = 0;
317 return clen;
318 }
319
320 bufline->terminated = 1;
321 bufhead->len += cpylen;
322 bufline->len += cpylen;
323 return clen;
324}
325
326
327/*
328 * rb_linebuf_parse
329 *
330 * Take a given buffer and break out as many buffers as we can.
331 * If we find a CRLF, we terminate that buffer and create a new one.
332 * If we don't find a CRLF whilst parsing a buffer, we don't mark it
333 * 'finished', so the next loop through we can continue appending ..
334 *
335 * A few notes here, which you'll need to understand before continuing.
336 *
337 * - right now I'm only dealing with single sized buffers. Later on,
338 * I might consider chaining buffers together to get longer "lines"
339 * but seriously, I don't see the advantage right now.
340 *
341 * - This *is* designed to turn into a reference-counter-protected setup
342 * to dodge copious copies.
343 */
344int
345rb_linebuf_parse(buf_head_t * bufhead, char *data, int len, int raw)
346{
347 buf_line_t *bufline;
348 int cpylen;
349 int linecnt = 0;
350
351 /* First, if we have a partial buffer, try to squeze data into it */
352 if(bufhead->list.tail != NULL)
353 {
354 /* Check we're doing the partial buffer thing */
355 bufline = bufhead->list.tail->data;
db137867
AC
356 /* just try, the worst it could do is *reject* us .. */
357 if(!raw)
358 cpylen = rb_linebuf_copy_line(bufhead, bufline, data, len);
359 else
360 cpylen = rb_linebuf_copy_raw(bufhead, bufline, data, len);
361
362 if(cpylen == -1)
363 return -1;
364
365 linecnt++;
366 /* If we've copied the same as what we've got, quit now */
367 if(cpylen == len)
368 return linecnt; /* all the data done so soon? */
369
370 /* Skip the data and update len .. */
371 len -= cpylen;
372 lrb_assert(len >= 0);
373 data += cpylen;
374 }
375
376 /* Next, the loop */
377 while(len > 0)
378 {
379 /* We obviously need a new buffer, so .. */
380 bufline = rb_linebuf_new_line(bufhead);
381
382 /* And parse */
383 if(!raw)
384 cpylen = rb_linebuf_copy_line(bufhead, bufline, data, len);
385 else
386 cpylen = rb_linebuf_copy_raw(bufhead, bufline, data, len);
387
388 if(cpylen == -1)
389 return -1;
390
391 len -= cpylen;
392 lrb_assert(len >= 0);
393 data += cpylen;
394 linecnt++;
395 }
396 return linecnt;
397}
398
399
400/*
401 * rb_linebuf_get
402 *
403 * get the next buffer from our line. For the time being it will copy
404 * data into the given buffer and free the underlying linebuf.
405 */
406int
407rb_linebuf_get(buf_head_t * bufhead, char *buf, int buflen, int partial, int raw)
408{
409 buf_line_t *bufline;
410 int cpylen;
411 char *start, *ch;
412
413 /* make sure we have a line */
414 if(bufhead->list.head == NULL)
415 return 0; /* Obviously not.. hrm. */
416
417 bufline = bufhead->list.head->data;
418
419 /* make sure that the buffer was actually *terminated */
420 if(!(partial || bufline->terminated))
421 return 0; /* Wait for more data! */
422
423 if(buflen < bufline->len)
424 cpylen = buflen - 1;
425 else
426 cpylen = bufline->len;
427
428 /* Copy it */
429 start = bufline->buf;
430
431 /* if we left extraneous '\r\n' characters in the string,
432 * and we don't want to read the raw data, clean up the string.
433 */
434 if(bufline->raw && !raw)
435 {
436 /* skip leading EOL characters */
437 while(cpylen && (*start == '\r' || *start == '\n'))
438 {
439 start++;
440 cpylen--;
441 }
442 /* skip trailing EOL characters */
443 ch = &start[cpylen - 1];
444 while(cpylen && (*ch == '\r' || *ch == '\n'))
445 {
446 ch--;
447 cpylen--;
448 }
449 }
450
451 memcpy(buf, start, cpylen);
452
453 /* convert CR/LF to NULL */
454 if(!raw)
455 buf[cpylen] = '\0';
456
457 lrb_assert(cpylen >= 0);
458
459 /* Deallocate the line */
460 rb_linebuf_done_line(bufhead, bufline, bufhead->list.head);
461
462 /* return how much we copied */
463 return cpylen;
464}
465
466/*
467 * rb_linebuf_attach
468 *
469 * attach the lines in a buf_head_t to another buf_head_t
470 * without copying the data (using refcounts).
471 */
472void
473rb_linebuf_attach(buf_head_t * bufhead, buf_head_t * new)
474{
475 rb_dlink_node *ptr;
476 buf_line_t *line;
477
478 RB_DLINK_FOREACH(ptr, new->list.head)
479 {
480 line = ptr->data;
481 rb_dlinkAddTailAlloc(line, &bufhead->list);
482
483 /* Update the allocated size */
484 bufhead->alloclen++;
485 bufhead->len += line->len;
486 bufhead->numlines++;
487
488 line->refcount++;
489 }
490}
491
db137867
AC
492/*
493 * rb_linebuf_putmsg
494 *
495 * Similar to rb_linebuf_put, but designed for use by send.c.
496 *
497 * prefixfmt is used as a format for the varargs, and is inserted first.
498 * Then format/va_args is appended to the buffer.
499 */
500void
3202e249
VY
501rb_linebuf_putmsg(buf_head_t * bufhead, const char *format, va_list * va_args,
502 const char *prefixfmt, ...)
db137867
AC
503{
504 buf_line_t *bufline;
505 int len = 0;
506 va_list prefix_args;
507
508 /* make sure the previous line is terminated */
509#ifndef NDEBUG
510 if(bufhead->list.tail)
511 {
512 bufline = bufhead->list.tail->data;
513 lrb_assert(bufline->terminated);
514 }
515#endif
516 /* Create a new line */
517 bufline = rb_linebuf_new_line(bufhead);
518
519 if(prefixfmt != NULL)
520 {
521 va_start(prefix_args, prefixfmt);
5203cba5 522 len = vsnprintf(bufline->buf, BUF_DATA_SIZE, prefixfmt, prefix_args);
db137867
AC
523 va_end(prefix_args);
524 }
525
526 if(va_args != NULL)
527 {
5203cba5 528 len += vsnprintf((bufline->buf + len), (BUF_DATA_SIZE - len), format, *va_args);
db137867
AC
529 }
530
531 bufline->terminated = 1;
532
533 /* Truncate the data if required */
c2ac22cc 534 if(rb_unlikely(len > 510))
db137867
AC
535 {
536 len = 510;
537 bufline->buf[len++] = '\r';
538 bufline->buf[len++] = '\n';
539 }
c2ac22cc 540 else if(rb_unlikely(len == 0))
db137867
AC
541 {
542 bufline->buf[len++] = '\r';
543 bufline->buf[len++] = '\n';
544 bufline->buf[len] = '\0';
545 }
546 else
547 {
548 /* Chop trailing CRLF's .. */
3202e249
VY
549 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
550 || (bufline->buf[len] == '\0'))
db137867
AC
551 {
552 len--;
553 }
554
555 bufline->buf[++len] = '\r';
556 bufline->buf[++len] = '\n';
557 bufline->buf[++len] = '\0';
558 }
559
560 bufline->len = len;
561 bufhead->len += len;
562}
563
5abeae60
AC
564/*
565 * rb_linebuf_putprefix
566 *
567 * Similar to rb_linebuf_put, but designed for use by send.c.
568 *
569 * prefix is inserted first, then format/va_args is appended to the buffer.
570 */
571void
572rb_linebuf_putprefix(buf_head_t * bufhead, const char *format, va_list * va_args,
573 const char *prefix)
574{
575 buf_line_t *bufline;
576 int len = 0;
577
578 /* make sure the previous line is terminated */
579#ifndef NDEBUG
580 if(bufhead->list.tail)
581 {
582 bufline = bufhead->list.tail->data;
583 lrb_assert(bufline->terminated);
584 }
585#endif
586 /* Create a new line */
587 bufline = rb_linebuf_new_line(bufhead);
588
589 if(prefix != NULL)
590 len = rb_strlcpy(bufline->buf, prefix, BUF_DATA_SIZE);
591
592 if(va_args != NULL)
593 {
594 len += vsnprintf((bufline->buf + len), (BUF_DATA_SIZE - len), format, *va_args);
595 }
596
597 bufline->terminated = 1;
598
599 /* Truncate the data if required */
600 if(rb_unlikely(len > 510))
601 {
602 len = 510;
603 bufline->buf[len++] = '\r';
604 bufline->buf[len++] = '\n';
605 }
606 else if(rb_unlikely(len == 0))
607 {
608 bufline->buf[len++] = '\r';
609 bufline->buf[len++] = '\n';
610 bufline->buf[len] = '\0';
611 }
612 else
613 {
614 /* Chop trailing CRLF's .. */
615 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
616 || (bufline->buf[len] == '\0'))
617 {
618 len--;
619 }
620
621 bufline->buf[++len] = '\r';
622 bufline->buf[++len] = '\n';
623 bufline->buf[++len] = '\0';
624 }
625
626 bufline->len = len;
627 bufhead->len += len;
628}
629
db137867 630void
3202e249 631rb_linebuf_putbuf(buf_head_t * bufhead, const char *buffer)
db137867
AC
632{
633 buf_line_t *bufline;
634 int len = 0;
635
636 /* make sure the previous line is terminated */
637#ifndef NDEBUG
638 if(bufhead->list.tail)
639 {
640 bufline = bufhead->list.tail->data;
641 lrb_assert(bufline->terminated);
642 }
643#endif
644 /* Create a new line */
645 bufline = rb_linebuf_new_line(bufhead);
646
c2ac22cc 647 if(rb_unlikely(buffer != NULL))
db137867
AC
648 len = rb_strlcpy(bufline->buf, buffer, BUF_DATA_SIZE);
649
650 bufline->terminated = 1;
651
652 /* Truncate the data if required */
c2ac22cc 653 if(rb_unlikely(len > 510))
db137867
AC
654 {
655 len = 510;
656 bufline->buf[len++] = '\r';
657 bufline->buf[len++] = '\n';
658 }
c2ac22cc 659 else if(rb_unlikely(len == 0))
db137867
AC
660 {
661 bufline->buf[len++] = '\r';
662 bufline->buf[len++] = '\n';
663 bufline->buf[len] = '\0';
664 }
665 else
666 {
667 /* Chop trailing CRLF's .. */
3202e249
VY
668 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
669 || (bufline->buf[len] == '\0'))
db137867
AC
670 {
671 len--;
672 }
673
674 bufline->buf[++len] = '\r';
675 bufline->buf[++len] = '\n';
676 bufline->buf[++len] = '\0';
677 }
678
679 bufline->len = len;
680 bufhead->len += len;
681
3202e249 682
db137867
AC
683}
684
685void
686rb_linebuf_put(buf_head_t * bufhead, const char *format, ...)
687{
688 buf_line_t *bufline;
689 int len = 0;
690 va_list args;
691
692 /* make sure the previous line is terminated */
693#ifndef NDEBUG
694 if(bufhead->list.tail)
695 {
696 bufline = bufhead->list.tail->data;
697 lrb_assert(bufline->terminated);
698 }
699#endif
700 /* Create a new line */
701 bufline = rb_linebuf_new_line(bufhead);
702
c2ac22cc 703 if(rb_unlikely(format != NULL))
db137867
AC
704 {
705 va_start(args, format);
5203cba5 706 len = vsnprintf(bufline->buf, BUF_DATA_SIZE, format, args);
db137867
AC
707 va_end(args);
708 }
709
710 bufline->terminated = 1;
711
712 /* Truncate the data if required */
c2ac22cc 713 if(rb_unlikely(len > 510))
db137867
AC
714 {
715 len = 510;
716 bufline->buf[len++] = '\r';
717 bufline->buf[len++] = '\n';
718 }
c2ac22cc 719 else if(rb_unlikely(len == 0))
db137867
AC
720 {
721 bufline->buf[len++] = '\r';
722 bufline->buf[len++] = '\n';
723 bufline->buf[len] = '\0';
724 }
725 else
726 {
727 /* Chop trailing CRLF's .. */
3202e249
VY
728 while((bufline->buf[len] == '\r') || (bufline->buf[len] == '\n')
729 || (bufline->buf[len] == '\0'))
db137867
AC
730 {
731 len--;
732 }
733
734 bufline->buf[++len] = '\r';
735 bufline->buf[++len] = '\n';
736 bufline->buf[++len] = '\0';
737 }
738
739 bufline->len = len;
740 bufhead->len += len;
741}
742
743
744
745/*
746 * rb_linebuf_flush
747 *
748 * Flush data to the buffer. It tries to write as much data as possible
749 * to the given socket. Any return values are passed straight through.
750 * If there is no data in the socket, EWOULDBLOCK is set as an errno
751 * rather than returning 0 (which would map to an EOF..)
752 *
753 * Notes: XXX We *should* have a clue here when a non-full buffer is arrived.
754 * and tag it so that we don't re-schedule another write until
755 * we have a CRLF.
756 */
757int
758rb_linebuf_flush(rb_fde_t *F, buf_head_t * bufhead)
759{
760 buf_line_t *bufline;
761 int retval;
762
55abcbb2
KB
763/*
764 * autoconf checks for this..but really just want to use it if we have a
db137867
AC
765 * native version even if libircd provides a fake version...
766 */
767#ifdef HAVE_WRITEV
768 if(!rb_fd_ssl(F))
769 {
770 rb_dlink_node *ptr;
771 int x = 0, y;
772 int xret;
773 static struct rb_iovec vec[RB_UIO_MAXIOV];
774
775 memset(vec, 0, sizeof(vec));
776 /* Check we actually have a first buffer */
777 if(bufhead->list.head == NULL)
778 {
779 /* nope, so we return none .. */
780 errno = EWOULDBLOCK;
781 return -1;
782 }
783
784 ptr = bufhead->list.head;
3202e249 785
db137867
AC
786 bufline = ptr->data;
787 if(!bufline->terminated)
788 {
789 errno = EWOULDBLOCK;
790 return -1;
791
792 }
793
39930c66
JT
794 vec[x].iov_base = bufline->buf + bufhead->writeofs;
795 vec[x++].iov_len = bufline->len - bufhead->writeofs;
796 ptr = ptr->next;
db137867
AC
797
798 do
799 {
800 if(ptr == NULL)
801 break;
802
803 bufline = ptr->data;
804 if(!bufline->terminated)
805 break;
3202e249 806
db137867
AC
807 vec[x].iov_base = bufline->buf;
808 vec[x].iov_len = bufline->len;
809 ptr = ptr->next;
810
3202e249
VY
811 }
812 while(++x < RB_UIO_MAXIOV);
db137867
AC
813
814 if(x == 0)
815 {
816 errno = EWOULDBLOCK;
817 return -1;
818 }
819
820 xret = retval = rb_writev(F, vec, x);
821 if(retval <= 0)
822 return retval;
823
824 ptr = bufhead->list.head;
825
826 for(y = 0; y < x; y++)
827 {
828 bufline = ptr->data;
829
39930c66 830 if(xret >= bufline->len - bufhead->writeofs)
db137867 831 {
39930c66 832 xret -= bufline->len - bufhead->writeofs;
db137867
AC
833 ptr = ptr->next;
834 rb_linebuf_done_line(bufhead, bufline, bufhead->list.head);
39930c66 835 bufhead->writeofs = 0;
db137867 836 }
3202e249 837 else
db137867 838 {
39930c66 839 bufhead->writeofs += xret;
db137867
AC
840 break;
841 }
db137867
AC
842 }
843
844 return retval;
845 }
3202e249
VY
846#endif
847
848 /* this is the non-writev case */
db137867 849
db137867
AC
850 /* Check we actually have a first buffer */
851 if(bufhead->list.head == NULL)
852 {
853 /* nope, so we return none .. */
854 errno = EWOULDBLOCK;
855 return -1;
856 }
857
858 bufline = bufhead->list.head->data;
859
860 /* And that its actually full .. */
861 if(!bufline->terminated)
862 {
863 errno = EWOULDBLOCK;
864 return -1;
865 }
866
db137867
AC
867 /* Now, try writing data */
868 retval = rb_write(F, bufline->buf + bufhead->writeofs, bufline->len - bufhead->writeofs);
869
870 if(retval <= 0)
871 return retval;
872
873 /* we've got data, so update the write offset */
874 bufhead->writeofs += retval;
875
876 /* if we've written everything *and* the CRLF, deallocate and update
877 bufhead */
878 if(bufhead->writeofs == bufline->len)
879 {
880 bufhead->writeofs = 0;
881 lrb_assert(bufhead->len >= 0);
882 rb_linebuf_done_line(bufhead, bufline, bufhead->list.head);
883 }
884
885 /* Return line length */
886 return retval;
887}
888
889
890
891/*
892 * count linebufs for stats z
893 */
894
895void
3202e249 896rb_count_rb_linebuf_memory(size_t *count, size_t *rb_linebuf_memory_used)
db137867 897{
db137867 898 rb_bh_usage(rb_linebuf_heap, count, NULL, rb_linebuf_memory_used, NULL);
db137867 899}