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