filter-branch: use $SHELL_PATH instead of 'sh'
[gitweb.git] / strbuf.c
index d1e338bfb695322cf2c90fa39bc8d482a3ade297..4aed75265e945d7b8dfafb36913006376768b4d3 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -1,27 +1,42 @@
 #include "cache.h"
 
+int prefixcmp(const char *str, const char *prefix)
+{
+       for (; ; str++, prefix++)
+               if (!*prefix)
+                       return 0;
+               else if (*str != *prefix)
+                       return (unsigned char)*prefix - (unsigned char)*str;
+}
+
+/*
+ * 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];
+
 void strbuf_init(struct strbuf *sb, size_t hint)
 {
-       memset(sb, 0, sizeof(*sb));
+       sb->alloc = sb->len = 0;
+       sb->buf = strbuf_slopbuf;
        if (hint)
                strbuf_grow(sb, hint);
 }
 
 void strbuf_release(struct strbuf *sb)
 {
-       free(sb->buf);
-       memset(sb, 0, sizeof(*sb));
-}
-
-void strbuf_reset(struct strbuf *sb)
-{
-       if (sb->len)
-               strbuf_setlen(sb, 0);
+       if (sb->alloc) {
+               free(sb->buf);
+               strbuf_init(sb, 0);
+       }
 }
 
-char *strbuf_detach(struct strbuf *sb)
+char *strbuf_detach(struct strbuf *sb, size_t *sz)
 {
-       char *res = sb->buf;
+       char *res = sb->alloc ? sb->buf : NULL;
+       if (sz)
+               *sz = sb->len;
        strbuf_init(sb, 0);
        return res;
 }
@@ -40,6 +55,8 @@ void strbuf_grow(struct strbuf *sb, size_t extra)
 {
        if (sb->len + extra + 1 <= sb->len)
                die("you want to use way too much memory");
+       if (!sb->alloc)
+               sb->buf = NULL;
        ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
 }
 
@@ -98,17 +115,25 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
+{
+       strbuf_grow(sb, len);
+       memcpy(sb->buf + sb->len, sb->buf + pos, len);
+       strbuf_setlen(sb, sb->len + len);
+}
+
 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 {
        int len;
        va_list ap;
 
+       if (!strbuf_avail(sb))
+               strbuf_grow(sb, 64);
        va_start(ap, fmt);
        len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
        va_end(ap);
-       if (len < 0) {
-               len = 0;
-       }
+       if (len < 0)
+               die("your vsnprintf is broken");
        if (len > strbuf_avail(sb)) {
                strbuf_grow(sb, len);
                va_start(ap, fmt);
@@ -121,6 +146,27 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
+                  void *context)
+{
+       for (;;) {
+               const char *percent;
+               size_t consumed;
+
+               percent = strchrnul(format, '%');
+               strbuf_add(sb, format, percent - format);
+               if (!*percent)
+                       break;
+               format = percent + 1;
+
+               consumed = fn(sb, format, context);
+               if (consumed)
+                       format += consumed;
+               else
+                       strbuf_addch(sb, '%');
+       }
+}
+
 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
 {
        size_t res;
@@ -178,14 +224,14 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
        return 0;
 }
 
-int strbuf_read_file(struct strbuf *sb, const char *path)
+int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
 {
        int fd, len;
 
        fd = open(path, O_RDONLY);
        if (fd < 0)
                return -1;
-       len = strbuf_read(sb, fd, 0);
+       len = strbuf_read(sb, fd, hint);
        close(fd);
        if (len < 0)
                return -1;