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