New strbuf APIs: splice and attach.
[git] / strbuf.c
1 #include "cache.h"
2 #include "strbuf.h"
3
4 void strbuf_init(struct strbuf *sb, size_t hint)
5 {
6         memset(sb, 0, sizeof(*sb));
7         if (hint)
8                 strbuf_grow(sb, hint);
9 }
10
11 void strbuf_release(struct strbuf *sb)
12 {
13         free(sb->buf);
14         memset(sb, 0, sizeof(*sb));
15 }
16
17 void strbuf_reset(struct strbuf *sb)
18 {
19         if (sb->len)
20                 strbuf_setlen(sb, 0);
21         sb->eof = 0;
22 }
23
24 char *strbuf_detach(struct strbuf *sb)
25 {
26         char *res = sb->buf;
27         strbuf_init(sb, 0);
28         return res;
29 }
30
31 void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
32 {
33         strbuf_release(sb);
34         sb->buf   = buf;
35         sb->len   = len;
36         sb->alloc = alloc;
37         strbuf_grow(sb, 0);
38         sb->buf[sb->len] = '\0';
39 }
40
41 void strbuf_grow(struct strbuf *sb, size_t extra)
42 {
43         if (sb->len + extra + 1 <= sb->len)
44                 die("you want to use way too much memory");
45         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
46 }
47
48 void strbuf_rtrim(struct strbuf *sb)
49 {
50         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
51                 sb->len--;
52         sb->buf[sb->len] = '\0';
53 }
54
55 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
56 {
57         strbuf_grow(sb, len);
58         if (pos > sb->len)
59                 die("`pos' is too far after the end of the buffer");
60         memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos);
61         memcpy(sb->buf + pos, data, len);
62         strbuf_setlen(sb, sb->len + len);
63 }
64
65 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
66                                    const void *data, size_t dlen)
67 {
68         if (pos + len < pos)
69                 die("you want to use way too much memory");
70         if (pos > sb->len)
71                 die("`pos' is too far after the end of the buffer");
72         if (pos + len > sb->len)
73                 die("`pos + len' is too far after the end of the buffer");
74
75         if (dlen >= len)
76                 strbuf_grow(sb, dlen - len);
77         memmove(sb->buf + pos + dlen,
78                         sb->buf + pos + len,
79                         sb->len - pos - len);
80         memcpy(sb->buf + pos, data, dlen);
81         strbuf_setlen(sb, sb->len + dlen - len);
82 }
83
84 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
85 {
86         strbuf_grow(sb, len);
87         memcpy(sb->buf + sb->len, data, len);
88         strbuf_setlen(sb, sb->len + len);
89 }
90
91 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
92 {
93         int len;
94         va_list ap;
95
96         va_start(ap, fmt);
97         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
98         va_end(ap);
99         if (len < 0) {
100                 len = 0;
101         }
102         if (len > strbuf_avail(sb)) {
103                 strbuf_grow(sb, len);
104                 va_start(ap, fmt);
105                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
106                 va_end(ap);
107                 if (len > strbuf_avail(sb)) {
108                         die("this should not happen, your snprintf is broken");
109                 }
110         }
111         strbuf_setlen(sb, sb->len + len);
112 }
113
114 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
115 {
116         size_t res;
117
118         strbuf_grow(sb, size);
119         res = fread(sb->buf + sb->len, 1, size, f);
120         if (res > 0) {
121                 strbuf_setlen(sb, sb->len + res);
122         }
123         return res;
124 }
125
126 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
127 {
128         size_t oldlen = sb->len;
129
130         strbuf_grow(sb, hint ? hint : 8192);
131         for (;;) {
132                 ssize_t cnt;
133
134                 cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
135                 if (cnt < 0) {
136                         strbuf_setlen(sb, oldlen);
137                         return -1;
138                 }
139                 if (!cnt)
140                         break;
141                 sb->len += cnt;
142                 strbuf_grow(sb, 8192);
143         }
144
145         sb->buf[sb->len] = '\0';
146         return sb->len - oldlen;
147 }
148
149 void read_line(struct strbuf *sb, FILE *fp, int term)
150 {
151         int ch;
152         if (feof(fp)) {
153                 strbuf_release(sb);
154                 sb->eof = 1;
155                 return;
156         }
157
158         strbuf_reset(sb);
159         while ((ch = fgetc(fp)) != EOF) {
160                 if (ch == term)
161                         break;
162                 strbuf_grow(sb, 1);
163                 sb->buf[sb->len++] = ch;
164         }
165         if (ch == EOF && sb->len == 0) {
166                 strbuf_release(sb);
167                 sb->eof = 1;
168         }
169
170         strbuf_grow(sb, 1);
171         sb->buf[sb->len] = '\0';
172 }