LCOV - code coverage report
Current view: top level - common - t-iobuf.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 156 160 97.5 %
Date: 2016-11-29 15:00:56 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             : #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             : }

Generated by: LCOV version 1.11