Merge branch 'j6t/mingw'
[git] / 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, size_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_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
45 {
46         strbuf_release(sb);
47         sb->buf   = buf;
48         sb->len   = len;
49         sb->alloc = alloc;
50         strbuf_grow(sb, 0);
51         sb->buf[sb->len] = '\0';
52 }
53
54 void strbuf_grow(struct strbuf *sb, size_t extra)
55 {
56         if (sb->len + extra + 1 <= sb->len)
57                 die("you want to use way too much memory");
58         if (!sb->alloc)
59                 sb->buf = NULL;
60         ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
61 }
62
63 void strbuf_rtrim(struct strbuf *sb)
64 {
65         while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
66                 sb->len--;
67         sb->buf[sb->len] = '\0';
68 }
69
70 int strbuf_cmp(struct strbuf *a, struct strbuf *b)
71 {
72         int cmp;
73         if (a->len < b->len) {
74                 cmp = memcmp(a->buf, b->buf, a->len);
75                 return cmp ? cmp : -1;
76         } else {
77                 cmp = memcmp(a->buf, b->buf, b->len);
78                 return cmp ? cmp : a->len != b->len;
79         }
80 }
81
82 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
83                                    const void *data, size_t dlen)
84 {
85         if (pos + len < pos)
86                 die("you want to use way too much memory");
87         if (pos > sb->len)
88                 die("`pos' is too far after the end of the buffer");
89         if (pos + len > sb->len)
90                 die("`pos + len' is too far after the end of the buffer");
91
92         if (dlen >= len)
93                 strbuf_grow(sb, dlen - len);
94         memmove(sb->buf + pos + dlen,
95                         sb->buf + pos + len,
96                         sb->len - pos - len);
97         memcpy(sb->buf + pos, data, dlen);
98         strbuf_setlen(sb, sb->len + dlen - len);
99 }
100
101 void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
102 {
103         strbuf_splice(sb, pos, 0, data, len);
104 }
105
106 void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
107 {
108         strbuf_splice(sb, pos, len, NULL, 0);
109 }
110
111 void strbuf_add(struct strbuf *sb, const void *data, size_t len)
112 {
113         strbuf_grow(sb, len);
114         memcpy(sb->buf + sb->len, data, len);
115         strbuf_setlen(sb, sb->len + len);
116 }
117
118 void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
119 {
120         strbuf_grow(sb, len);
121         memcpy(sb->buf + sb->len, sb->buf + pos, len);
122         strbuf_setlen(sb, sb->len + len);
123 }
124
125 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
126 {
127         int len;
128         va_list ap;
129
130         if (!strbuf_avail(sb))
131                 strbuf_grow(sb, 64);
132         va_start(ap, fmt);
133         len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
134         va_end(ap);
135         if (len < 0)
136                 die("your vsnprintf is broken");
137         if (len > strbuf_avail(sb)) {
138                 strbuf_grow(sb, len);
139                 va_start(ap, fmt);
140                 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
141                 va_end(ap);
142                 if (len > strbuf_avail(sb)) {
143                         die("this should not happen, your snprintf is broken");
144                 }
145         }
146         strbuf_setlen(sb, sb->len + len);
147 }
148
149 void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
150                    void *context)
151 {
152         for (;;) {
153                 const char *percent;
154                 size_t consumed;
155
156                 percent = strchrnul(format, '%');
157                 strbuf_add(sb, format, percent - format);
158                 if (!*percent)
159                         break;
160                 format = percent + 1;
161
162                 consumed = fn(sb, format, context);
163                 if (consumed)
164                         format += consumed;
165                 else
166                         strbuf_addch(sb, '%');
167         }
168 }
169
170 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
171 {
172         size_t res;
173
174         strbuf_grow(sb, size);
175         res = fread(sb->buf + sb->len, 1, size, f);
176         if (res > 0) {
177                 strbuf_setlen(sb, sb->len + res);
178         }
179         return res;
180 }
181
182 ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
183 {
184         size_t oldlen = sb->len;
185
186         strbuf_grow(sb, hint ? hint : 8192);
187         for (;;) {
188                 ssize_t cnt;
189
190                 cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
191                 if (cnt < 0) {
192                         strbuf_setlen(sb, oldlen);
193                         return -1;
194                 }
195                 if (!cnt)
196                         break;
197                 sb->len += cnt;
198                 strbuf_grow(sb, 8192);
199         }
200
201         sb->buf[sb->len] = '\0';
202         return sb->len - oldlen;
203 }
204
205 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
206 {
207         int ch;
208
209         strbuf_grow(sb, 0);
210         if (feof(fp))
211                 return EOF;
212
213         strbuf_reset(sb);
214         while ((ch = fgetc(fp)) != EOF) {
215                 if (ch == term)
216                         break;
217                 strbuf_grow(sb, 1);
218                 sb->buf[sb->len++] = ch;
219         }
220         if (ch == EOF && sb->len == 0)
221                 return EOF;
222
223         sb->buf[sb->len] = '\0';
224         return 0;
225 }
226
227 int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
228 {
229         int fd, len;
230
231         fd = open(path, O_RDONLY);
232         if (fd < 0)
233                 return -1;
234         len = strbuf_read(sb, fd, hint);
235         close(fd);
236         if (len < 0)
237                 return -1;
238
239         return len;
240 }