LCOV - code coverage report
Current view: top level - lib - dynamic-string.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 191 216 88.4 %
Date: 2016-09-14 01:02:56 Functions: 26 29 89.7 %
Branches: 85 102 83.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2016 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "openvswitch/dynamic-string.h"
      19                 :            : #include <inttypes.h>
      20                 :            : #include <stdlib.h>
      21                 :            : #include <string.h>
      22                 :            : #include <time.h>
      23                 :            : #include "timeval.h"
      24                 :            : #include "util.h"
      25                 :            : 
      26                 :            : /* Initializes 'ds' as an empty string buffer. */
      27                 :            : void
      28                 :     884047 : ds_init(struct ds *ds)
      29                 :            : {
      30                 :     884047 :     ds->string = NULL;
      31                 :     884047 :     ds->length = 0;
      32                 :     884047 :     ds->allocated = 0;
      33                 :     884047 : }
      34                 :            : 
      35                 :            : /* Sets 'ds''s length to 0, effectively clearing any existing content.  Does
      36                 :            :  * not free any memory. */
      37                 :            : void
      38                 :   41404605 : ds_clear(struct ds *ds)
      39                 :            : {
      40                 :   41404605 :     ds->length = 0;
      41                 :   41404605 : }
      42                 :            : 
      43                 :            : /* Reduces 'ds''s length to no more than 'new_length'.  (If its length is
      44                 :            :  * already 'new_length' or less, does nothing.)  */
      45                 :            : void
      46                 :          0 : ds_truncate(struct ds *ds, size_t new_length)
      47                 :            : {
      48         [ #  # ]:          0 :     if (ds->length > new_length) {
      49                 :          0 :         ds->length = new_length;
      50                 :          0 :         ds->string[new_length] = '\0';
      51                 :            :     }
      52                 :          0 : }
      53                 :            : 
      54                 :            : /* Ensures that at least 'min_length + 1' bytes (including space for a null
      55                 :            :  * terminator) are allocated for ds->string, allocating or reallocating memory
      56                 :            :  * as necessary. */
      57                 :            : void
      58                 :    5670032 : ds_reserve(struct ds *ds, size_t min_length)
      59                 :            : {
      60 [ +  + ][ +  + ]:    5670032 :     if (min_length > ds->allocated || !ds->string) {
      61                 :    2242175 :         ds->allocated += MAX(min_length, ds->allocated);
      62                 :    2242175 :         ds->allocated = MAX(8, ds->allocated);
      63                 :    2242175 :         ds->string = xrealloc(ds->string, ds->allocated + 1);
      64                 :            :     }
      65                 :    5670032 : }
      66                 :            : 
      67                 :            : /* Appends space for 'n' bytes to the end of 'ds->string', increasing
      68                 :            :  * 'ds->length' by the same amount, and returns the first appended byte.  The
      69                 :            :  * caller should fill in all 'n' bytes starting at the return value. */
      70                 :            : char *
      71                 :    4880144 : ds_put_uninit(struct ds *ds, size_t n)
      72                 :            : {
      73                 :    4880144 :     ds_reserve(ds, ds->length + n);
      74                 :    4880144 :     ds->length += n;
      75                 :    4880144 :     ds->string[ds->length] = '\0';
      76                 :    4880144 :     return &ds->string[ds->length - n];
      77                 :            : }
      78                 :            : 
      79                 :            : void
      80                 :    1200101 : ds_put_char__(struct ds *ds, char c)
      81                 :            : {
      82                 :    1200101 :     *ds_put_uninit(ds, 1) = c;
      83                 :    1200101 : }
      84                 :            : 
      85                 :            : /* Appends unicode code point 'uc' to 'ds' in UTF-8 encoding. */
      86                 :            : void
      87                 :         11 : ds_put_utf8(struct ds *ds, int uc)
      88                 :            : {
      89         [ +  + ]:         11 :     if (uc <= 0x7f) {
      90                 :          9 :         ds_put_char(ds, uc);
      91         [ -  + ]:          2 :     } else if (uc <= 0x7ff) {
      92                 :          0 :         ds_put_char(ds, 0xc0 | (uc >> 6));
      93                 :          0 :         ds_put_char(ds, 0x80 | (uc & 0x3f));
      94         [ -  + ]:          2 :     } else if (uc <= 0xffff) {
      95                 :          0 :         ds_put_char(ds, 0xe0 | (uc >> 12));
      96                 :          0 :         ds_put_char(ds, 0x80 | ((uc >> 6) & 0x3f));
      97                 :          0 :         ds_put_char(ds, 0x80 | (uc & 0x3f));
      98         [ +  - ]:          2 :     } else if (uc <= 0x10ffff) {
      99                 :          2 :         ds_put_char(ds, 0xf0 | (uc >> 18));
     100                 :          2 :         ds_put_char(ds, 0x80 | ((uc >> 12) & 0x3f));
     101                 :          2 :         ds_put_char(ds, 0x80 | ((uc >> 6) & 0x3f));
     102                 :          2 :         ds_put_char(ds, 0x80 | (uc & 0x3f));
     103                 :            :     } else {
     104                 :            :         /* Invalid code point.  Insert the Unicode general substitute
     105                 :            :          * REPLACEMENT CHARACTER. */
     106                 :          0 :         ds_put_utf8(ds, 0xfffd);
     107                 :            :     }
     108                 :         11 : }
     109                 :            : 
     110                 :            : void
     111                 :      44871 : ds_put_char_multiple(struct ds *ds, char c, size_t n)
     112                 :            : {
     113                 :      44871 :     memset(ds_put_uninit(ds, n), c, n);
     114                 :      44871 : }
     115                 :            : 
     116                 :            : void
     117                 :         88 : ds_put_buffer(struct ds *ds, const char *s, size_t n)
     118                 :            : {
     119                 :         88 :     memcpy(ds_put_uninit(ds, n), s, n);
     120                 :         88 : }
     121                 :            : 
     122                 :            : void
     123                 :    3440616 : ds_put_cstr(struct ds *ds, const char *s)
     124                 :            : {
     125                 :    3440616 :     size_t s_len = strlen(s);
     126                 :    3440616 :     memcpy(ds_put_uninit(ds, s_len), s, s_len);
     127                 :    3440616 : }
     128                 :            : 
     129                 :            : void
     130                 :        714 : ds_put_and_free_cstr(struct ds *ds, char *s)
     131                 :            : {
     132                 :        714 :     ds_put_cstr(ds, s);
     133                 :        714 :     free(s);
     134                 :        714 : }
     135                 :            : 
     136                 :            : void
     137                 :   19742572 : ds_put_format(struct ds *ds, const char *format, ...)
     138                 :            : {
     139                 :            :     va_list args;
     140                 :            : 
     141                 :   19742572 :     va_start(args, format);
     142                 :   19742572 :     ds_put_format_valist(ds, format, args);
     143                 :   19742573 :     va_end(args);
     144                 :   19742573 : }
     145                 :            : 
     146                 :            : void
     147                 :   19949147 : ds_put_format_valist(struct ds *ds, const char *format, va_list args_)
     148                 :            : {
     149                 :            :     va_list args;
     150                 :            :     size_t available;
     151                 :            :     int needed;
     152                 :            : 
     153                 :   19949147 :     va_copy(args, args_);
     154         [ +  + ]:   19949147 :     available = ds->string ? ds->allocated - ds->length + 1 : 0;
     155                 :   19949147 :     needed = vsnprintf(&ds->string[ds->length], available, format, args);
     156                 :   19949147 :     va_end(args);
     157                 :            : 
     158         [ +  + ]:   19949147 :     if (needed < available) {
     159                 :   19632115 :         ds->length += needed;
     160                 :            :     } else {
     161                 :     317032 :         ds_reserve(ds, ds->length + needed);
     162                 :            : 
     163                 :     317032 :         va_copy(args, args_);
     164                 :     317032 :         available = ds->allocated - ds->length + 1;
     165                 :     317032 :         needed = vsnprintf(&ds->string[ds->length], available, format, args);
     166                 :     317032 :         va_end(args);
     167                 :            : 
     168         [ -  + ]:     317032 :         ovs_assert(needed < available);
     169                 :     317032 :         ds->length += needed;
     170                 :            :     }
     171                 :   19949147 : }
     172                 :            : 
     173                 :            : void
     174                 :          2 : ds_put_printable(struct ds *ds, const char *s, size_t n)
     175                 :            : {
     176                 :          2 :     ds_reserve(ds, ds->length + n);
     177         [ +  + ]:         24 :     while (n-- > 0) {
     178                 :         22 :         unsigned char c = *s++;
     179 [ +  + ][ +  - ]:         22 :         if (c < 0x20 || c > 0x7e || c == '\\' || c == '"') {
         [ +  - ][ -  + ]
     180                 :          2 :             ds_put_format(ds, "\\%03o", (int) c);
     181                 :            :         } else {
     182                 :         20 :             ds_put_char(ds, c);
     183                 :            :         }
     184                 :            :     }
     185                 :          2 : }
     186                 :            : 
     187                 :            : /* Writes the current time with optional millisecond resolution to 'string'
     188                 :            :  * based on 'template'.
     189                 :            :  * The current time is either localtime or UTC based on 'utc'. */
     190                 :            : void
     191                 :      98949 : ds_put_strftime_msec(struct ds *ds, const char *template, long long int when,
     192                 :            :                      bool utc)
     193                 :            : {
     194                 :            :     struct tm_msec tm;
     195         [ +  - ]:      98949 :     if (utc) {
     196                 :      98949 :         gmtime_msec(when, &tm);
     197                 :            :     } else {
     198                 :          0 :         localtime_msec(when, &tm);
     199                 :            :     }
     200                 :            : 
     201                 :            :     for (;;) {
     202         [ +  - ]:      98949 :         size_t avail = ds->string ? ds->allocated - ds->length + 1 : 0;
     203                 :      98949 :         size_t used = strftime_msec(&ds->string[ds->length], avail, template,
     204                 :            :                                     &tm);
     205         [ +  - ]:      98949 :         if (used) {
     206                 :      98949 :             ds->length += used;
     207                 :      98949 :             return;
     208                 :            :         }
     209         [ #  # ]:          0 :         ds_reserve(ds, ds->length + (avail < 32 ? 64 : 2 * avail));
     210                 :      98949 :     }
     211                 :            : }
     212                 :            : 
     213                 :            : /* Returns a malloc()'d string for time 'when' based on 'template', in local
     214                 :            :  * time or UTC based on 'utc'. */
     215                 :            : char *
     216                 :          0 : xastrftime_msec(const char *template, long long int when, bool utc)
     217                 :            : {
     218                 :            :     struct ds s;
     219                 :            : 
     220                 :          0 :     ds_init(&s);
     221                 :          0 :     ds_put_strftime_msec(&s, template, when, utc);
     222                 :          0 :     return s.string;
     223                 :            : }
     224                 :            : 
     225                 :            : int
     226                 :      28862 : ds_get_line(struct ds *ds, FILE *file)
     227                 :            : {
     228                 :      28862 :     ds_clear(ds);
     229                 :            :     for (;;) {
     230                 :    1709200 :         int c = getc(file);
     231         [ +  + ]:    1709200 :         if (c == EOF) {
     232         [ +  + ]:       4933 :             return ds->length ? 0 : EOF;
     233         [ +  + ]:    1704267 :         } else if (c == '\n') {
     234                 :      23929 :             return 0;
     235                 :            :         } else {
     236                 :    1680338 :             ds_put_char(ds, c);
     237                 :            :         }
     238                 :    1680338 :     }
     239                 :            : }
     240                 :            : 
     241                 :            : /* Reads a line from 'file' into 'ds', clearing anything initially in 'ds'.
     242                 :            :  * Deletes comments introduced by "#" and skips lines that contains only white
     243                 :            :  * space (after deleting comments).
     244                 :            :  *
     245                 :            :  * If 'line_numberp' is nonnull, increments '*line_numberp' by the number of
     246                 :            :  * lines read from 'file'.
     247                 :            :  *
     248                 :            :  * Returns 0 if successful, EOF if no non-blank line was found. */
     249                 :            : int
     250                 :      22320 : ds_get_preprocessed_line(struct ds *ds, FILE *file, int *line_numberp)
     251                 :            : {
     252         [ +  + ]:      22638 :     while (!ds_get_line(ds, file)) {
     253                 :      22282 :         char *line = ds_cstr(ds);
     254                 :            :         char *comment;
     255                 :            : 
     256         [ +  + ]:      22282 :         if (line_numberp) {
     257                 :      21834 :             ++*line_numberp;
     258                 :            :         }
     259                 :            : 
     260                 :            :         /* Delete comments. */
     261                 :      22282 :         comment = strchr(line, '#');
     262         [ +  + ]:      22282 :         if (comment) {
     263                 :         31 :             *comment = '\0';
     264                 :            :         }
     265                 :            : 
     266                 :            :         /* Return successfully unless the line is all spaces. */
     267         [ +  + ]:      22282 :         if (line[strspn(line, " \t\n")] != '\0') {
     268                 :      21964 :             return 0;
     269                 :            :         }
     270                 :            :     }
     271                 :        356 :     return EOF;
     272                 :            : }
     273                 :            : 
     274                 :            : /* Reads a line from 'file' into 'ds' and does some preprocessing on it:
     275                 :            :  *
     276                 :            :  *    - If the line begins with #, prints it on stdout and reads the next line.
     277                 :            :  *
     278                 :            :  *    - Otherwise, if the line contains an # somewhere else, strips it and
     279                 :            :  *      everything following it (as a comment).
     280                 :            :  *
     281                 :            :  *    - If (after comment removal) the line contains only white space, prints
     282                 :            :  *      a blank line on stdout and reads the next line.
     283                 :            :  *
     284                 :            :  *    - Otherwise, returns the line to the caller.
     285                 :            :  *
     286                 :            :  * This is useful in some of the OVS tests, where we want to check that parsing
     287                 :            :  * and then re-formatting some kind of data does not change it, but we also
     288                 :            :  * want to be able to put comments in the input.
     289                 :            :  *
     290                 :            :  * Returns 0 if successful, EOF if no non-blank line was found. */
     291                 :            : int
     292                 :       1382 : ds_get_test_line(struct ds *ds, FILE *file)
     293                 :            : {
     294                 :            :     for (;;) {
     295                 :            :         char *s, *comment;
     296                 :            :         int retval;
     297                 :            : 
     298                 :       1697 :         retval = ds_get_line(ds, file);
     299         [ +  + ]:       1697 :         if (retval) {
     300                 :         50 :             return retval;
     301                 :            :         }
     302                 :            : 
     303                 :       1647 :         s = ds_cstr(ds);
     304         [ +  + ]:       1647 :         if (*s == '#') {
     305                 :        127 :             puts(s);
     306                 :        127 :             continue;
     307                 :            :         }
     308                 :            : 
     309                 :       1520 :         comment = strchr(s, '#');
     310         [ +  + ]:       1520 :         if (comment) {
     311                 :         26 :             *comment = '\0';
     312                 :            :         }
     313         [ +  + ]:       1520 :         if (s[strspn(s, " \t\n")] == '\0') {
     314                 :        188 :             putchar('\n');
     315                 :        188 :             continue;
     316                 :            :         }
     317                 :            : 
     318                 :       1332 :         return 0;
     319                 :        315 :     }
     320                 :            : }
     321                 :            : 
     322                 :            : char *
     323                 :   16483051 : ds_cstr(struct ds *ds)
     324                 :            : {
     325         [ +  + ]:   16483051 :     if (!ds->string) {
     326                 :       9351 :         ds_reserve(ds, 0);
     327                 :            :     }
     328                 :   16483051 :     ds->string[ds->length] = '\0';
     329                 :   16483051 :     return ds->string;
     330                 :            : }
     331                 :            : 
     332                 :            : const char *
     333                 :       4121 : ds_cstr_ro(const struct ds *ds)
     334                 :            : {
     335                 :       4121 :     return ds_cstr(CONST_CAST(struct ds *, ds));
     336                 :            : }
     337                 :            : 
     338                 :            : /* Returns a null-terminated string representing the current contents of 'ds',
     339                 :            :  * which the caller is expected to free with free(), then clears the contents
     340                 :            :  * of 'ds'. */
     341                 :            : char *
     342                 :     223186 : ds_steal_cstr(struct ds *ds)
     343                 :            : {
     344                 :     223186 :     char *s = ds_cstr(ds);
     345                 :     223186 :     ds_init(ds);
     346                 :     223186 :     return s;
     347                 :            : }
     348                 :            : 
     349                 :            : void
     350                 :     303693 : ds_destroy(struct ds *ds)
     351                 :            : {
     352                 :     303693 :     free(ds->string);
     353                 :     303693 : }
     354                 :            : 
     355                 :            : /* Swaps the content of 'a' and 'b'. */
     356                 :            : void
     357                 :      43761 : ds_swap(struct ds *a, struct ds *b)
     358                 :            : {
     359                 :      43761 :     struct ds temp = *a;
     360                 :      43761 :     *a = *b;
     361                 :      43761 :     *b = temp;
     362                 :      43761 : }
     363                 :            : 
     364                 :            : void
     365                 :     108476 : ds_put_hex(struct ds *ds, const void *buf_, size_t size)
     366                 :            : {
     367                 :     108476 :     const uint8_t *buf = buf_;
     368                 :     108476 :     bool printed = false;
     369                 :            :     int i;
     370                 :            : 
     371         [ +  + ]:   12908687 :     for (i = 0; i < size; i++) {
     372                 :   12800211 :         uint8_t val = buf[i];
     373 [ +  + ][ +  + ]:   12800211 :         if (val || printed) {
     374         [ +  + ]:      78512 :             if (!printed) {
     375                 :      71817 :                 ds_put_format(ds, "0x%"PRIx8, val);
     376                 :            :             } else {
     377                 :       6695 :                 ds_put_format(ds, "%02"PRIx8, val);
     378                 :            :             }
     379                 :      78512 :             printed = true;
     380                 :            :         }
     381                 :            :     }
     382         [ +  + ]:     108476 :     if (!printed) {
     383                 :      36659 :         ds_put_char(ds, '0');
     384                 :            :     }
     385                 :     108476 : }
     386                 :            : 
     387                 :            : /* Writes the 'size' bytes in 'buf' to 'string' as hex bytes arranged 16 per
     388                 :            :  * line.  Numeric offsets are also included, starting at 'ofs' for the first
     389                 :            :  * byte in 'buf'.  If 'ascii' is true then the corresponding ASCII characters
     390                 :            :  * are also rendered alongside. */
     391                 :            : void
     392                 :       1219 : ds_put_hex_dump(struct ds *ds, const void *buf_, size_t size,
     393                 :            :                 uintptr_t ofs, bool ascii)
     394                 :            : {
     395                 :       1219 :     const uint8_t *buf = buf_;
     396                 :       1219 :     const size_t per_line = 16; /* Maximum bytes per line. */
     397                 :            : 
     398         [ +  + ]:       5985 :     while (size > 0) {
     399                 :            :         size_t start, end, n;
     400                 :            :         size_t i;
     401                 :            : 
     402                 :            :         /* Number of bytes on this line. */
     403                 :       4766 :         start = ofs % per_line;
     404                 :       4766 :         end = per_line;
     405         [ +  + ]:       4766 :         if (end - start > size)
     406                 :         66 :             end = start + size;
     407                 :       4766 :         n = end - start;
     408                 :            : 
     409                 :            :         /* Print line. */
     410                 :       4766 :         ds_put_format(ds, "%08"PRIxMAX"  ",
     411                 :       4766 :                       (uintmax_t) ROUND_DOWN(ofs, per_line));
     412         [ -  + ]:       4766 :         for (i = 0; i < start; i++) {
     413                 :          0 :             ds_put_format(ds, "   ");
     414                 :            :         }
     415         [ +  + ]:      80675 :         for (; i < end; i++) {
     416         [ +  + ]:      75909 :             ds_put_format(ds, "%02x%c",
     417                 :     151818 :                           buf[i - start], i == per_line / 2 - 1? '-' : ' ');
     418                 :            :         }
     419         [ +  + ]:       4766 :         if (ascii) {
     420         [ +  + ]:       4772 :             for (; i < per_line; i++)
     421                 :        173 :                 ds_put_format(ds, "   ");
     422                 :       4599 :             ds_put_format(ds, "|");
     423         [ -  + ]:       4599 :             for (i = 0; i < start; i++)
     424                 :          0 :                 ds_put_format(ds, " ");
     425         [ +  + ]:      78010 :             for (; i < end; i++) {
     426                 :      73411 :                 int c = buf[i - start];
     427 [ +  + ][ +  + ]:      73411 :                 ds_put_char(ds, c >= 32 && c < 127 ? c : '.');
     428                 :            :             }
     429         [ +  + ]:       4772 :             for (; i < per_line; i++)
     430                 :        173 :                 ds_put_format(ds, " ");
     431                 :       4599 :             ds_put_format(ds, "|");
     432                 :            :         } else {
     433                 :        167 :             ds_chomp(ds, ' ');
     434                 :            :         }
     435                 :       4766 :         ds_put_format(ds, "\n");
     436                 :            : 
     437                 :       4766 :         ofs += n;
     438                 :       4766 :         buf += n;
     439                 :       4766 :         size -= n;
     440                 :            :     }
     441                 :       1219 : }
     442                 :            : 
     443                 :            : int
     444                 :     134042 : ds_last(const struct ds *ds)
     445                 :            : {
     446         [ +  - ]:     134042 :     return ds->length > 0 ? (unsigned char) ds->string[ds->length - 1] : EOF;
     447                 :            : }
     448                 :            : 
     449                 :            : bool
     450                 :     165574 : ds_chomp(struct ds *ds, int c)
     451                 :            : {
     452 [ +  + ][ +  + ]:     165574 :     if (ds->length > 0 && ds->string[ds->length - 1] == (char) c) {
     453                 :     164545 :         ds->string[--ds->length] = '\0';
     454                 :     164545 :         return true;
     455                 :            :     } else {
     456                 :       1029 :         return false;
     457                 :            :     }
     458                 :            : }
     459                 :            : 
     460                 :            : void
     461                 :          0 : ds_clone(struct ds *dst, struct ds *source)
     462                 :            : {
     463                 :          0 :     dst->length = source->length;
     464                 :          0 :     dst->allocated = dst->length;
     465                 :          0 :     dst->string = xmalloc(dst->allocated + 1);
     466                 :          0 :     memcpy(dst->string, source->string, dst->allocated + 1);
     467                 :          0 : }

Generated by: LCOV version 1.12