root/tools/perf/util/strbuf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. strbuf_init
  2. strbuf_release
  3. strbuf_detach
  4. strbuf_grow
  5. strbuf_addch
  6. strbuf_add
  7. strbuf_addv
  8. strbuf_addf
  9. strbuf_read

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include "cache.h"
   3 #include "debug.h"
   4 #include "strbuf.h"
   5 #include <linux/kernel.h>
   6 #include <linux/string.h>
   7 #include <linux/zalloc.h>
   8 #include <errno.h>
   9 #include <stdio.h>
  10 #include <stdlib.h>
  11 #include <unistd.h>
  12 
  13 /*
  14  * Used as the default ->buf value, so that people can always assume
  15  * buf is non NULL and ->buf is NUL terminated even for a freshly
  16  * initialized strbuf.
  17  */
  18 char strbuf_slopbuf[1];
  19 
  20 int strbuf_init(struct strbuf *sb, ssize_t hint)
  21 {
  22         sb->alloc = sb->len = 0;
  23         sb->buf = strbuf_slopbuf;
  24         if (hint)
  25                 return strbuf_grow(sb, hint);
  26         return 0;
  27 }
  28 
  29 void strbuf_release(struct strbuf *sb)
  30 {
  31         if (sb->alloc) {
  32                 zfree(&sb->buf);
  33                 strbuf_init(sb, 0);
  34         }
  35 }
  36 
  37 char *strbuf_detach(struct strbuf *sb, size_t *sz)
  38 {
  39         char *res = sb->alloc ? sb->buf : NULL;
  40         if (sz)
  41                 *sz = sb->len;
  42         strbuf_init(sb, 0);
  43         return res;
  44 }
  45 
  46 int strbuf_grow(struct strbuf *sb, size_t extra)
  47 {
  48         char *buf;
  49         size_t nr = sb->len + extra + 1;
  50 
  51         if (nr < sb->alloc)
  52                 return 0;
  53 
  54         if (nr <= sb->len)
  55                 return -E2BIG;
  56 
  57         if (alloc_nr(sb->alloc) > nr)
  58                 nr = alloc_nr(sb->alloc);
  59 
  60         /*
  61          * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
  62          * a static variable. Thus we have to avoid passing it to realloc.
  63          */
  64         buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
  65         if (!buf)
  66                 return -ENOMEM;
  67 
  68         sb->buf = buf;
  69         sb->alloc = nr;
  70         return 0;
  71 }
  72 
  73 int strbuf_addch(struct strbuf *sb, int c)
  74 {
  75         int ret = strbuf_grow(sb, 1);
  76         if (ret)
  77                 return ret;
  78 
  79         sb->buf[sb->len++] = c;
  80         sb->buf[sb->len] = '\0';
  81         return 0;
  82 }
  83 
  84 int strbuf_add(struct strbuf *sb, const void *data, size_t len)
  85 {
  86         int ret = strbuf_grow(sb, len);
  87         if (ret)
  88                 return ret;
  89 
  90         memcpy(sb->buf + sb->len, data, len);
  91         return strbuf_setlen(sb, sb->len + len);
  92 }
  93 
  94 static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
  95 {
  96         int len, ret;
  97         va_list ap_saved;
  98 
  99         if (!strbuf_avail(sb)) {
 100                 ret = strbuf_grow(sb, 64);
 101                 if (ret)
 102                         return ret;
 103         }
 104 
 105         va_copy(ap_saved, ap);
 106         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 107         if (len < 0) {
 108                 va_end(ap_saved);
 109                 return len;
 110         }
 111         if (len > strbuf_avail(sb)) {
 112                 ret = strbuf_grow(sb, len);
 113                 if (ret) {
 114                         va_end(ap_saved);
 115                         return ret;
 116                 }
 117                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
 118                 if (len > strbuf_avail(sb)) {
 119                         pr_debug("this should not happen, your vsnprintf is broken");
 120                         va_end(ap_saved);
 121                         return -EINVAL;
 122                 }
 123         }
 124         va_end(ap_saved);
 125         return strbuf_setlen(sb, sb->len + len);
 126 }
 127 
 128 int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 129 {
 130         va_list ap;
 131         int ret;
 132 
 133         va_start(ap, fmt);
 134         ret = strbuf_addv(sb, fmt, ap);
 135         va_end(ap);
 136         return ret;
 137 }
 138 
 139 ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
 140 {
 141         size_t oldlen = sb->len;
 142         size_t oldalloc = sb->alloc;
 143         int ret;
 144 
 145         ret = strbuf_grow(sb, hint ? hint : 8192);
 146         if (ret)
 147                 return ret;
 148 
 149         for (;;) {
 150                 ssize_t cnt;
 151 
 152                 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
 153                 if (cnt < 0) {
 154                         if (oldalloc == 0)
 155                                 strbuf_release(sb);
 156                         else
 157                                 strbuf_setlen(sb, oldlen);
 158                         return cnt;
 159                 }
 160                 if (!cnt)
 161                         break;
 162                 sb->len += cnt;
 163                 ret = strbuf_grow(sb, 8192);
 164                 if (ret)
 165                         return ret;
 166         }
 167 
 168         sb->buf[sb->len] = '\0';
 169         return sb->len - oldlen;
 170 }

/* [<][>][^][v][top][bottom][index][help] */