common/iobuf.c: Combine iobuf_open, iobuf_create and iobuf_openrw.
[gnupg.git] / common / t-iobuf.c
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 static int
10 every_other_filter (void *opaque, int control,
11                     iobuf_t chain, byte *buf, size_t *len)
12 {
13   (void) opaque;
14
15   if (control == IOBUFCTRL_DESC)
16     {
17       *(char **) buf = "every_other_filter";
18     }
19   if (control == IOBUFCTRL_UNDERFLOW)
20     {
21       int c = iobuf_readbyte (chain);
22       int c2;
23       if (c == -1)
24         c2 = -1;
25       else
26         c2 = iobuf_readbyte (chain);
27
28       // printf ("Discarding %d (%c); return %d (%c)\n", c, c, c2, c2);
29
30       if (c2 == -1)
31         {
32           *len = 0;
33           return -1;
34         }
35
36       *buf = c2;
37       *len = 1;
38
39       return 0;
40     }
41
42   return 0;
43 }
44
45 struct content_filter_state
46 {
47   int pos;
48   int len;
49   const char *buffer;
50 };
51
52 static struct content_filter_state *
53 content_filter_new (const char *buffer)
54 {
55   struct content_filter_state *state
56     = malloc (sizeof (struct content_filter_state));
57
58   state->pos = 0;
59   state->len = strlen (buffer);
60   state->buffer = buffer;
61
62   return state;
63 }
64
65 static int
66 content_filter (void *opaque, int control,
67                 iobuf_t chain, byte *buf, size_t *len)
68 {
69   struct content_filter_state *state = opaque;
70
71   (void) chain;
72
73   if (control == IOBUFCTRL_UNDERFLOW)
74     {
75       int remaining = state->len - state->pos;
76       int toread = *len;
77       assert (toread > 0);
78
79       if (toread > remaining)
80         toread = remaining;
81
82       if (toread == 0)
83         return -1;
84
85       memcpy (buf, &state->buffer[state->pos], toread);
86
87       state->pos += toread;
88
89       *len = toread;
90
91       return 0;
92     }
93
94   return 0;
95 }
96
97 int
98 main (int argc, char *argv[])
99 {
100   (void) argc;
101   (void) argv;
102
103   /* A simple test to make sure filters work.  We use a static buffer
104      and then add a filter in front of it that returns every other
105      character.  */
106   {
107     char *content = "0123456789abcdefghijklm";
108     iobuf_t iobuf;
109     int c;
110     int n;
111     int rc;
112
113     iobuf = iobuf_temp_with_content (content, strlen (content));
114     rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
115     assert (rc == 0);
116
117     n = 0;
118     while ((c = iobuf_readbyte (iobuf)) != -1)
119       {
120         // printf ("%d: %c\n", n + 1, (char) c);
121         assert (content[2 * n + 1] == c);
122         n ++;
123       }
124     // printf ("Got EOF after reading %d bytes (content: %d)\n",
125     // n, strlen (content));
126     assert (n == strlen (content) / 2);
127
128     iobuf_close (iobuf);
129   }
130
131   /* A simple test to check buffering.  Make sure that when we add a
132      filter to a pipeline, any buffered data gets processed by the */
133   {
134     char *content = "0123456789abcdefghijklm";
135     iobuf_t iobuf;
136     int c;
137     int n;
138     int rc;
139     int i;
140
141     iobuf = iobuf_temp_with_content (content, strlen (content));
142
143     n = 0;
144     for (i = 0; i < 10; i ++)
145       {
146         c = iobuf_readbyte (iobuf);
147         assert (content[i] == c);
148         n ++;
149       }
150
151     rc = iobuf_push_filter (iobuf, every_other_filter, NULL);
152     assert (rc == 0);
153
154     while ((c = iobuf_readbyte (iobuf)) != -1)
155       {
156         // printf ("%d: %c\n", n + 1, (char) c);
157         assert (content[2 * (n - 5) + 1] == c);
158         n ++;
159       }
160     assert (n == 10 + (strlen (content) - 10) / 2);
161   }
162
163
164   /* A simple test to check that iobuf_read_line works.  */
165   {
166     /* - 3 characters plus new line
167        - 4 characters plus new line
168        - 5 characters plus new line
169        - 5 characters, no new line
170      */
171     char *content = "abc\ndefg\nhijkl\nmnopq";
172     iobuf_t iobuf;
173     byte *buffer;
174     unsigned size;
175     unsigned max_len;
176     int n;
177
178     iobuf = iobuf_temp_with_content (content, strlen(content));
179
180     /* We read a line with 3 characters plus a newline.  If we
181        allocate a buffer that is 5 bytes long, then no reallocation
182        should be required.  */
183     size = 5;
184     buffer = malloc (size);
185     assert (buffer);
186     max_len = 100;
187     n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
188     assert (n == 4);
189     assert (strcmp (buffer, "abc\n") == 0);
190     assert (size == 5);
191     assert (max_len == 100);
192     free (buffer);
193
194     /* We now read a line with 4 characters plus a newline.  This
195        requires 6 bytes of storage.  We pass a buffer that is 5 bytes
196        large and we allow the buffer to be grown.  */
197     size = 5;
198     buffer = malloc (size);
199     max_len = 100;
200     n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
201     assert (n == 5);
202     assert (strcmp (buffer, "defg\n") == 0);
203     assert (size >= 6);
204     /* The string shouldn't have been truncated (max_len == 0).  */
205     assert (max_len == 100);
206     free (buffer);
207
208     /* We now read a line with 5 characters plus a newline.  This
209        requires 7 bytes of storage.  We pass a buffer that is 5 bytes
210        large and we don't allow the buffer to be grown.  */
211     size = 5;
212     buffer = malloc (size);
213     max_len = 5;
214     n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
215     assert (n == 4);
216     /* Note: the string should still have a trailing \n.  */
217     assert (strcmp (buffer, "hij\n") == 0);
218     assert (size == 5);
219     /* The string should have been truncated (max_len == 0).  */
220     assert (max_len == 0);
221     free (buffer);
222
223     /* We now read a line with 6 characters without a newline.  This
224        requires 7 bytes of storage.  We pass a NULL buffer and we
225        don't allow the buffer to be grown larger than 5 bytes.  */
226     size = 5;
227     buffer = NULL;
228     max_len = 5;
229     n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
230     assert (n == 4);
231     /* Note: the string should still have a trailing \n.  */
232     assert (strcmp (buffer, "mno\n") == 0);
233     assert (size == 5);
234     /* The string should have been truncated (max_len == 0).  */
235     assert (max_len == 0);
236     free (buffer);
237   }
238
239   {
240     /* - 3 characters plus new line
241        - 4 characters plus new line
242        - 5 characters plus new line
243        - 5 characters, no new line
244      */
245     char *content = "abcdefghijklmnopq";
246     char *content2 = "0123456789";
247     iobuf_t iobuf;
248     int rc;
249     int c;
250     int n;
251     int lastc = 0;
252
253     iobuf = iobuf_temp_with_content (content, strlen(content));
254     rc = iobuf_push_filter (iobuf,
255                             content_filter, content_filter_new (content2));
256     assert (rc == 0);
257
258     n = 0;
259     while (1)
260       {
261         c = iobuf_readbyte (iobuf);
262         if (c == -1 && lastc == -1)
263           {
264             printf("Two EOFs in a row.  Done.\n");
265             break;
266           }
267
268         lastc = c;
269
270         if (c == -1)
271           printf("After %d bytes, got EOF.\n", n);
272         else
273           {
274             n ++;
275             printf ("%d: '%c' (%d)\n", n, c, c);
276           }
277       }
278   }
279
280   return 0;
281 }