Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[pandora-kernel.git] / tools / perf / util / strbuf.c
1 #include "cache.h"
2
3 int prefixcmp(const char *str, const char *prefix)
4 {
5         for (; ; str++, prefix++)
6                 if (!*prefix)
7                         return 0;
8                 else if (*str != *prefix)
9                         return (unsigned char)*prefix - (unsigned char)*str;
10 }
11
12 /*
13  * Used as the default ->buf value, so that people can always assume
14  * buf is non NULL and ->buf is NUL terminated even for a freshly
15  * initialized strbuf.
16  */
17 char strbuf_slopbuf[1];
18
19 void strbuf_init(struct strbuf *sb, ssize_t hint)
20 {
21         sb->alloc = sb->len = 0;
22         sb->buf = strbuf_slopbuf;
23         if (hint)
24                 strbuf_grow(sb, hint);
25 }
26
27 void strbuf_release(struct strbuf *sb)
28 {
29         if (sb->alloc) {
30                 free(sb->buf);
31                 strbuf_init(sb, 0);
32         }
33 }
34
35 char *strbuf_detach(struct strbuf *sb, size_t *sz)
36 {
37         char *res = sb->alloc ? sb->buf : NULL;
38         if (sz)
39                 *sz = sb->len;
40         strbuf_init(sb, 0);
41         return res;
42 }
43
44 void strbuf_grow(struct strbuf *sb, size_t extra)
45 {
46         if (sb->len + extra + 1 <= sb->len)
47                 die("you want to use way too much memory");
48         if (!sb->alloc)
49                 sb->buf = NULL;
50         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
51 }
52
53 static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
54                                    const void *data, size_t dlen)
55 {
56         if (pos + len < pos)
57                 die("you want to use way too much memory");
58         if (pos > sb->len)
59                 die("`pos' is too far after the end of the buffer");
60         if (pos + len > sb->len)
61                 die("`pos + len' is too far after the end of the buffer");
62
63         if (dlen >= len)
64                 strbuf_grow(sb, dlen - len);
65         memmove(sb->buf + pos + dlen,
66                         sb->buf + pos + len,
67                         sb->len - pos - len);
68         memcpy(sb->buf + pos, data, dlen);
69         strbuf_setlen(sb, sb->len + dlen - len);
70 }
71
72 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
73 {
74         strbuf_splice(sb, pos, len, NULL, 0);
75 }
76
77 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
78 {
79         strbuf_grow(sb, len);
80         memcpy(sb->buf + sb->len, data, len);
81         strbuf_setlen(sb, sb->len + len);
82 }
83
84 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
85 {
86         int len;
87         va_list ap;
88
89         if (!strbuf_avail(sb))
90                 strbuf_grow(sb, 64);
91         va_start(ap, fmt);
92         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
93         va_end(ap);
94         if (len < 0)
95                 die("your vsnprintf is broken");
96         if (len > strbuf_avail(sb)) {
97                 strbuf_grow(sb, len);
98                 va_start(ap, fmt);
99                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
100                 va_end(ap);
101                 if (len > strbuf_avail(sb)) {
102                         die("this should not happen, your snprintf is broken");
103                 }
104         }
105         strbuf_setlen(sb, sb->len + len);
106 }
107
108 ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
109 {
110         size_t oldlen = sb->len;
111         size_t oldalloc = sb->alloc;
112
113         strbuf_grow(sb, hint ? hint : 8192);
114         for (;;) {
115                 ssize_t cnt;
116
117                 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
118                 if (cnt < 0) {
119                         if (oldalloc == 0)
120                                 strbuf_release(sb);
121                         else
122                                 strbuf_setlen(sb, oldlen);
123                         return -1;
124                 }
125                 if (!cnt)
126                         break;
127                 sb->len += cnt;
128                 strbuf_grow(sb, 8192);
129         }
130
131         sb->buf[sb->len] = '\0';
132         return sb->len - oldlen;
133 }