Line data Source code
1 : #include <config.h>
2 : #include <stdio.h>
3 : #include <string.h>
4 : #include <assert.h>
5 : #include <stdlib.h>
6 :
7 : #include "iobuf.h"
8 :
9 : /* Return every other byte. In particular, reads two bytes, returns
10 : the second one. */
11 : static int
12 36 : every_other_filter (void *opaque, int control,
13 : iobuf_t chain, byte *buf, size_t *len)
14 : {
15 : (void) opaque;
16 :
17 36 : if (control == IOBUFCTRL_DESC)
18 : {
19 0 : *(char **) buf = "every_other_filter";
20 : }
21 36 : if (control == IOBUFCTRL_UNDERFLOW)
22 : {
23 28 : int c = iobuf_readbyte (chain);
24 : int c2;
25 28 : if (c == -1)
26 1 : c2 = -1;
27 : else
28 27 : c2 = iobuf_readbyte (chain);
29 :
30 : /* printf ("Discarding %d (%c); return %d (%c)\n", c, c, c2, c2); */
31 :
32 28 : if (c2 == -1)
33 : {
34 4 : *len = 0;
35 4 : return -1;
36 : }
37 :
38 24 : *buf = c2;
39 24 : *len = 1;
40 :
41 24 : return 0;
42 : }
43 :
44 8 : return 0;
45 : }
46 :
47 : static int
48 2 : double_filter (void *opaque, int control,
49 : iobuf_t chain, byte *buf, size_t *len)
50 : {
51 : (void) opaque;
52 :
53 2 : if (control == IOBUFCTRL_DESC)
54 : {
55 0 : * (char **) buf = "double_filter";
56 : }
57 2 : if (control == IOBUFCTRL_FLUSH)
58 : {
59 : int i;
60 :
61 5 : for (i = 0; i < *len; i ++)
62 : {
63 : int rc;
64 :
65 4 : rc = iobuf_writebyte (chain, buf[i]);
66 4 : if (rc)
67 0 : return rc;
68 4 : rc = iobuf_writebyte (chain, buf[i]);
69 4 : if (rc)
70 0 : return rc;
71 : }
72 : }
73 :
74 2 : return 0;
75 : }
76 :
77 : struct content_filter_state
78 : {
79 : int pos;
80 : int len;
81 : const char *buffer;
82 : };
83 :
84 : static struct content_filter_state *
85 1 : content_filter_new (const char *buffer)
86 : {
87 1 : struct content_filter_state *state
88 : = malloc (sizeof (struct content_filter_state));
89 :
90 1 : state->pos = 0;
91 1 : state->len = strlen (buffer);
92 1 : state->buffer = buffer;
93 :
94 1 : return state;
95 : }
96 :
97 : static int
98 4 : content_filter (void *opaque, int control,
99 : iobuf_t chain, byte *buf, size_t *len)
100 : {
101 4 : struct content_filter_state *state = opaque;
102 :
103 : (void) chain;
104 :
105 4 : if (control == IOBUFCTRL_UNDERFLOW)
106 : {
107 2 : int remaining = state->len - state->pos;
108 2 : int toread = *len;
109 2 : assert (toread > 0);
110 :
111 2 : if (toread > remaining)
112 2 : toread = remaining;
113 :
114 2 : memcpy (buf, &state->buffer[state->pos], toread);
115 :
116 2 : state->pos += toread;
117 :
118 2 : *len = toread;
119 :
120 2 : if (toread == 0)
121 1 : return -1;
122 1 : return 0;
123 : }
124 :
125 2 : return 0;
126 : }
127 :
128 : int
129 1 : main (int argc, char *argv[])
130 : {
131 : (void) argc;
132 : (void) argv;
133 :
134 : /* A simple test to make sure filters work. We use a static buffer
135 : and then add a filter in front of it that returns every other
136 : character. */
137 : {
138 1 : char *content = "0123456789abcdefghijklm";
139 : iobuf_t iobuf;
140 : int c;
141 : int n;
142 : int rc;
143 :
144 1 : iobuf = iobuf_temp_with_content (content, strlen (content));
145 1 : rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
146 1 : assert (rc == 0);
147 :
148 1 : n = 0;
149 13 : while ((c = iobuf_readbyte (iobuf)) != -1)
150 : {
151 : /* printf ("%d: %c\n", n + 1, (char) c); */
152 11 : assert (content[2 * n + 1] == c);
153 11 : n ++;
154 : }
155 : /* printf ("Got EOF after reading %d bytes (content: %d)\n", */
156 : /* n, strlen (content)); */
157 1 : assert (n == strlen (content) / 2);
158 :
159 1 : iobuf_close (iobuf);
160 : }
161 :
162 : /* A simple test to check buffering. Make sure that when we add a
163 : filter to a pipeline, any buffered data gets processed by the */
164 : {
165 1 : char *content = "0123456789abcdefghijklm";
166 : iobuf_t iobuf;
167 : int c;
168 : int n;
169 : int rc;
170 : int i;
171 :
172 1 : iobuf = iobuf_temp_with_content (content, strlen (content));
173 :
174 1 : n = 0;
175 11 : for (i = 0; i < 10; i ++)
176 : {
177 10 : c = iobuf_readbyte (iobuf);
178 10 : assert (content[i] == c);
179 10 : n ++;
180 : }
181 :
182 1 : rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
183 1 : assert (rc == 0);
184 :
185 8 : while ((c = iobuf_readbyte (iobuf)) != -1)
186 : {
187 : /* printf ("%d: %c\n", n + 1, (char) c); */
188 6 : assert (content[2 * (n - 5) + 1] == c);
189 6 : n ++;
190 : }
191 1 : assert (n == 10 + (strlen (content) - 10) / 2);
192 : }
193 :
194 :
195 : /* A simple test to check that iobuf_read_line works. */
196 : {
197 : /* - 3 characters plus new line
198 : - 4 characters plus new line
199 : - 5 characters plus new line
200 : - 5 characters, no new line
201 : */
202 1 : char *content = "abc\ndefg\nhijkl\nmnopq";
203 : iobuf_t iobuf;
204 : byte *buffer;
205 : unsigned size;
206 : unsigned max_len;
207 : int n;
208 :
209 1 : iobuf = iobuf_temp_with_content (content, strlen(content));
210 :
211 : /* We read a line with 3 characters plus a newline. If we
212 : allocate a buffer that is 5 bytes long, then no reallocation
213 : should be required. */
214 1 : size = 5;
215 1 : buffer = malloc (size);
216 1 : assert (buffer);
217 1 : max_len = 100;
218 1 : n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
219 1 : assert (n == 4);
220 1 : assert (strcmp (buffer, "abc\n") == 0);
221 1 : assert (size == 5);
222 1 : assert (max_len == 100);
223 1 : free (buffer);
224 :
225 : /* We now read a line with 4 characters plus a newline. This
226 : requires 6 bytes of storage. We pass a buffer that is 5 bytes
227 : large and we allow the buffer to be grown. */
228 1 : size = 5;
229 1 : buffer = malloc (size);
230 1 : max_len = 100;
231 1 : n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
232 1 : assert (n == 5);
233 1 : assert (strcmp (buffer, "defg\n") == 0);
234 1 : assert (size >= 6);
235 : /* The string shouldn't have been truncated (max_len == 0). */
236 1 : assert (max_len == 100);
237 1 : free (buffer);
238 :
239 : /* We now read a line with 5 characters plus a newline. This
240 : requires 7 bytes of storage. We pass a buffer that is 5 bytes
241 : large and we don't allow the buffer to be grown. */
242 1 : size = 5;
243 1 : buffer = malloc (size);
244 1 : max_len = 5;
245 1 : n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
246 1 : assert (n == 4);
247 : /* Note: the string should still have a trailing \n. */
248 1 : assert (strcmp (buffer, "hij\n") == 0);
249 1 : assert (size == 5);
250 : /* The string should have been truncated (max_len == 0). */
251 1 : assert (max_len == 0);
252 1 : free (buffer);
253 :
254 : /* We now read a line with 6 characters without a newline. This
255 : requires 7 bytes of storage. We pass a NULL buffer and we
256 : don't allow the buffer to be grown larger than 5 bytes. */
257 1 : size = 5;
258 1 : buffer = NULL;
259 1 : max_len = 5;
260 1 : n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
261 1 : assert (n == 4);
262 : /* Note: the string should still have a trailing \n. */
263 1 : assert (strcmp (buffer, "mno\n") == 0);
264 1 : assert (size == 5);
265 : /* The string should have been truncated (max_len == 0). */
266 1 : assert (max_len == 0);
267 1 : free (buffer);
268 : }
269 :
270 : {
271 : /* - 10 characters, EOF
272 : - 17 characters, EOF
273 : */
274 1 : char *content = "abcdefghijklmnopq";
275 1 : char *content2 = "0123456789";
276 : iobuf_t iobuf;
277 : int rc;
278 : int c;
279 : int n;
280 1 : int lastc = 0;
281 :
282 1 : iobuf = iobuf_temp_with_content (content, strlen(content));
283 1 : rc = iobuf_push_filter (iobuf,
284 1 : content_filter, content_filter_new (content2));
285 1 : assert (rc == 0);
286 :
287 1 : n = 0;
288 : while (1)
289 : {
290 30 : c = iobuf_readbyte (iobuf);
291 30 : if (c == -1 && lastc == -1)
292 : {
293 : /* printf("Two EOFs in a row. Done.\n"); */
294 1 : assert (n == 27);
295 1 : break;
296 : }
297 :
298 29 : lastc = c;
299 :
300 29 : if (c == -1)
301 : {
302 : /* printf("After %d bytes, got EOF.\n", n); */
303 2 : assert (n == 10 || n == 27);
304 : }
305 : else
306 : {
307 27 : n ++;
308 : /* printf ("%d: '%c' (%d)\n", n, c, c); */
309 : }
310 29 : }
311 : }
312 :
313 : /* Write some data to a temporary filter. Push a new filter. The
314 : already written data should not be processed by the new
315 : filter. */
316 : {
317 : iobuf_t iobuf;
318 : int rc;
319 1 : char *content = "0123456789";
320 1 : char *content2 = "abc";
321 : char buffer[4096];
322 : int n;
323 :
324 1 : iobuf = iobuf_temp ();
325 1 : assert (iobuf);
326 :
327 1 : rc = iobuf_write (iobuf, content, strlen (content));
328 1 : assert (rc == 0);
329 :
330 1 : rc = iobuf_push_filter (iobuf, double_filter, NULL);
331 1 : assert (rc == 0);
332 :
333 : /* Include a NUL. */
334 1 : rc = iobuf_write (iobuf, content2, strlen (content2) + 1);
335 1 : assert (rc == 0);
336 :
337 1 : n = iobuf_temp_to_buffer (iobuf, buffer, sizeof (buffer));
338 : #if 0
339 : printf ("Got %d bytes\n", n);
340 : printf ("buffer: `");
341 : fwrite (buffer, n, 1, stdout);
342 : fputc ('\'', stdout);
343 : fputc ('\n', stdout);
344 : #endif
345 :
346 1 : assert (n == strlen (content) + 2 * (strlen (content2) + 1));
347 1 : assert (strcmp (buffer, "0123456789aabbcc") == 0);
348 : }
349 :
350 : {
351 : iobuf_t iobuf;
352 : int rc;
353 1 : char *content = "0123456789";
354 : int n;
355 : int c;
356 1 : char buffer[strlen (content)];
357 :
358 1 : iobuf = iobuf_temp_with_content (content, strlen (content));
359 1 : assert (iobuf);
360 :
361 1 : rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
362 1 : assert (rc == 0);
363 1 : rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
364 1 : assert (rc == 0);
365 :
366 3 : for (n = 0; (c = iobuf_get (iobuf)) != -1; n ++)
367 : {
368 : /* printf ("%d: `%c'\n", n, c); */
369 2 : buffer[n] = c;
370 : }
371 :
372 1 : assert (n == 2);
373 1 : assert (buffer[0] == '3');
374 1 : assert (buffer[1] == '7');
375 : }
376 :
377 1 : return 0;
378 : }
|