implement missing function in buffer.c
[libdht.git] / buffer.c
bloba3ff83bf78f32ee6d69285f03a3ed063c26a969c
1 /*
2 * Copyright (c) 2016 Mohamed Aslan <maslan@sce.carleton.ca>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <buffer.h>
21 #include <sys/param.h>
23 struct rbuffer *
24 rbuffer_new(size_t capacity)
26 struct rbuffer *rbuf;
28 rbuf = malloc(sizeof(struct rbuffer));
29 if (rbuf == NULL)
30 goto ret;
31 rbuf->rb_capacity = capacity > 0 ? capacity : BUFSIZ;
32 rbuf->rb_len = 0;
33 rbuf->rb_data = reallocarray(NULL, rbuf->rb_capacity, sizeof(char));
34 if (rbuf->rb_data == NULL) {
35 free(rbuf);
36 goto ret;
38 rbuf->rb_wp = rbuf->rb_data;
39 rbuf->rb_rp = rbuf->rb_data;
40 ret:
41 return rbuf;
44 void
45 rbuffer_free(struct rbuffer *rbuf)
47 if (rbuf == NULL)
48 return;
49 free(rbuf->rb_data);
50 free(rbuf);
53 int
54 rbuffer_write(struct rbuffer *rbuf, const char *src, size_t len)
56 int crossed = 0;
57 size_t block, n, copied = 0, free, rem = len;
59 if (rbuf == NULL)
60 return -1;
62 free = rbuf->rb_capacity - rbuf->rb_len;
63 if (len > free)
64 crossed = 1;
66 /* TODO: optimize, copy only what needs to be copied. */
67 while (rem) {
68 block = rbuf->rb_capacity - (rbuf->rb_wp - rbuf->rb_data);
69 n = MIN(rem, block);
70 memcpy(rbuf->rb_wp, src + copied, n);
71 rbuf->rb_len += n;
72 copied += n;
74 rbuf->rb_wp += n;
75 if (rbuf->rb_wp >= rbuf->rb_data + rbuf->rb_capacity)
76 rbuf->rb_wp = rbuf->rb_data;
78 rem -= n;
81 /* check if wp crossed rp */
82 if (crossed)
83 rbuf->rb_rp = rbuf->rb_wp;
85 rbuf->rb_len = MIN(rbuf->rb_len, rbuf->rb_capacity);
87 return 0;
90 char *
91 rbuffer_read(struct rbuffer *rbuf, size_t len)
93 char *str;
94 size_t total, n;
96 total = MIN(len, rbuf->rb_len);
97 if (!total)
98 return NULL;
99 str = reallocarray(NULL, total, sizeof(char));
101 n = MIN(len, (rbuf->rb_data + rbuf->rb_capacity) - rbuf->rb_rp);
102 memcpy(str, rbuf->rb_rp, n);
103 rbuf->rb_rp += n;
105 if (n < total) {
106 memcpy(str + n, rbuf->rb_data, total - n);
107 rbuf->rb_rp = rbuf->rb_data + (total - n);
110 rbuf->rb_len -= total;
112 return str;
115 static int
116 rbuffer_find(struct rbuffer *rbuf, char ch, size_t *len)
118 char *ptr = rbuf->rb_rp;
119 size_t n, m;
121 n = MIN(rbuf->rb_len, (rbuf->rb_data + rbuf->rb_capacity) - rbuf->rb_rp);
122 m = rbuf->rb_len - n;
123 for (ptr = rbuf->rb_rp ; n-- ; ptr++) {
124 if (*ptr == ch) {
125 *len = rbuf->rb_len - n - m;
126 return 1;
129 for (ptr = rbuf->rb_data ; m-- ; ptr++) {
130 if (*ptr == ch) {
131 *len = rbuf->rb_len - m;
132 return 1;
135 return 0;
138 char *
139 rbuffer_readline(struct rbuffer *rbuf)
141 char *str;
142 size_t n;
144 if (!rbuf->rb_len)
145 return NULL;
146 if (rbuffer_find(rbuf, '\n', &n)) {
147 str = rbuffer_read(rbuf, n);
148 str[n - 1] = '\0';
149 return str;
151 return NULL;