LCOV - code coverage report
Current view: top level - common - t-iobuf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 151 155 97.4 %
Date: 2015-11-05 17:10:59 Functions: 5 5 100.0 %

          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             : }

Generated by: LCOV version 1.11