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