linux/tools/perf/util/strbuf.c
<<
>>
Prefs
   1#include "cache.h"
   2#include <linux/kernel.h>
   3
   4int prefixcmp(const char *str, const char *prefix)
   5{
   6        for (; ; str++, prefix++)
   7                if (!*prefix)
   8                        return 0;
   9                else if (*str != *prefix)
  10                        return (unsigned char)*prefix - (unsigned char)*str;
  11}
  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 */
  18char strbuf_slopbuf[1];
  19
  20void strbuf_init(struct strbuf *sb, ssize_t hint)
  21{
  22        sb->alloc = sb->len = 0;
  23        sb->buf = strbuf_slopbuf;
  24        if (hint)
  25                strbuf_grow(sb, hint);
  26}
  27
  28void strbuf_release(struct strbuf *sb)
  29{
  30        if (sb->alloc) {
  31                zfree(&sb->buf);
  32                strbuf_init(sb, 0);
  33        }
  34}
  35
  36char *strbuf_detach(struct strbuf *sb, size_t *sz)
  37{
  38        char *res = sb->alloc ? sb->buf : NULL;
  39        if (sz)
  40                *sz = sb->len;
  41        strbuf_init(sb, 0);
  42        return res;
  43}
  44
  45void strbuf_grow(struct strbuf *sb, size_t extra)
  46{
  47        if (sb->len + extra + 1 <= sb->len)
  48                die("you want to use way too much memory");
  49        if (!sb->alloc)
  50                sb->buf = NULL;
  51        ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
  52}
  53
  54void strbuf_addch(struct strbuf *sb, int c)
  55{
  56        strbuf_grow(sb, 1);
  57        sb->buf[sb->len++] = c;
  58        sb->buf[sb->len] = '\0';
  59}
  60
  61void strbuf_add(struct strbuf *sb, const void *data, size_t len)
  62{
  63        strbuf_grow(sb, len);
  64        memcpy(sb->buf + sb->len, data, len);
  65        strbuf_setlen(sb, sb->len + len);
  66}
  67
  68static void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
  69{
  70        int len;
  71        va_list ap_saved;
  72
  73        if (!strbuf_avail(sb))
  74                strbuf_grow(sb, 64);
  75
  76        va_copy(ap_saved, ap);
  77        len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
  78        if (len < 0)
  79                die("your vsnprintf is broken");
  80        if (len > strbuf_avail(sb)) {
  81                strbuf_grow(sb, len);
  82                len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
  83                va_end(ap_saved);
  84                if (len > strbuf_avail(sb)) {
  85                        die("this should not happen, your vsnprintf is broken");
  86                }
  87        }
  88        strbuf_setlen(sb, sb->len + len);
  89}
  90
  91void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
  92{
  93        va_list ap;
  94
  95        va_start(ap, fmt);
  96        strbuf_addv(sb, fmt, ap);
  97        va_end(ap);
  98}
  99
 100ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
 101{
 102        size_t oldlen = sb->len;
 103        size_t oldalloc = sb->alloc;
 104
 105        strbuf_grow(sb, hint ? hint : 8192);
 106        for (;;) {
 107                ssize_t cnt;
 108
 109                cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
 110                if (cnt < 0) {
 111                        if (oldalloc == 0)
 112                                strbuf_release(sb);
 113                        else
 114                                strbuf_setlen(sb, oldlen);
 115                        return -1;
 116                }
 117                if (!cnt)
 118                        break;
 119                sb->len += cnt;
 120                strbuf_grow(sb, 8192);
 121        }
 122
 123        sb->buf[sb->len] = '\0';
 124        return sb->len - oldlen;
 125}
 126