strbuf.con commit Documentation: Describe "git diff <blob> <blob>" separately (bd52900)
   1#include "cache.h"
   2#include "refs.h"
   3
   4int prefixcmp(const char *str, const char *prefix)
   5{
   6        for (; ; str++, prefix++)
   7                if (!*prefix)
   8                        return 0;
   9                else if (*str != *prefix)
  10                        return (unsigned char)*prefix - (unsigned char)*str;
  11}
  12
  13int suffixcmp(const char *str, const char *suffix)
  14{
  15        int len = strlen(str), suflen = strlen(suffix);
  16        if (len < suflen)
  17                return -1;
  18        else
  19                return strcmp(str + len - suflen, suffix);
  20}
  21
  22/*
  23 * Used as the default ->buf value, so that people can always assume
  24 * buf is non NULL and ->buf is NUL terminated even for a freshly
  25 * initialized strbuf.
  26 */
  27char strbuf_slopbuf[1];
  28
  29void strbuf_init(struct strbuf *sb, size_t hint)
  30{
  31        sb->alloc = sb->len = 0;
  32        sb->buf = strbuf_slopbuf;
  33        if (hint)
  34                strbuf_grow(sb, hint);
  35}
  36
  37void strbuf_release(struct strbuf *sb)
  38{
  39        if (sb->alloc) {
  40                free(sb->buf);
  41                strbuf_init(sb, 0);
  42        }
  43}
  44
  45char *strbuf_detach(struct strbuf *sb, size_t *sz)
  46{
  47        char *res = sb->alloc ? sb->buf : NULL;
  48        if (sz)
  49                *sz = sb->len;
  50        strbuf_init(sb, 0);
  51        return res;
  52}
  53
  54void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
  55{
  56        strbuf_release(sb);
  57        sb->buf   = buf;
  58        sb->len   = len;
  59        sb->alloc = alloc;
  60        strbuf_grow(sb, 0);
  61        sb->buf[sb->len] = '\0';
  62}
  63
  64void strbuf_grow(struct strbuf *sb, size_t extra)
  65{
  66        int new_buf = !sb->alloc;
  67        if (unsigned_add_overflows(extra, 1) ||
  68            unsigned_add_overflows(sb->len, extra + 1))
  69                die("you want to use way too much memory");
  70        if (new_buf)
  71                sb->buf = NULL;
  72        ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
  73        if (new_buf)
  74                sb->buf[0] = '\0';
  75}
  76
  77void strbuf_trim(struct strbuf *sb)
  78{
  79        char *b = sb->buf;
  80        while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
  81                sb->len--;
  82        while (sb->len > 0 && isspace(*b)) {
  83                b++;
  84                sb->len--;
  85        }
  86        memmove(sb->buf, b, sb->len);
  87        sb->buf[sb->len] = '\0';
  88}
  89void strbuf_rtrim(struct strbuf *sb)
  90{
  91        while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
  92                sb->len--;
  93        sb->buf[sb->len] = '\0';
  94}
  95
  96void strbuf_ltrim(struct strbuf *sb)
  97{
  98        char *b = sb->buf;
  99        while (sb->len > 0 && isspace(*b)) {
 100                b++;
 101                sb->len--;
 102        }
 103        memmove(sb->buf, b, sb->len);
 104        sb->buf[sb->len] = '\0';
 105}
 106
 107struct strbuf **strbuf_split_buf(const char *str, size_t slen, int delim, int max)
 108{
 109        int alloc = 2, pos = 0;
 110        const char *n, *p;
 111        struct strbuf **ret;
 112        struct strbuf *t;
 113
 114        ret = xcalloc(alloc, sizeof(struct strbuf *));
 115        p = n = str;
 116        while (n < str + slen) {
 117                int len;
 118                if (max <= 0 || pos + 1 < max)
 119                        n = memchr(n, delim, slen - (n - str));
 120                else
 121                        n = NULL;
 122                if (pos + 1 >= alloc) {
 123                        alloc = alloc * 2;
 124                        ret = xrealloc(ret, sizeof(struct strbuf *) * alloc);
 125                }
 126                if (!n)
 127                        n = str + slen - 1;
 128                len = n - p + 1;
 129                t = xmalloc(sizeof(struct strbuf));
 130                strbuf_init(t, len);
 131                strbuf_add(t, p, len);
 132                ret[pos] = t;
 133                ret[++pos] = NULL;
 134                p = ++n;
 135        }
 136        return ret;
 137}
 138
 139void strbuf_list_free(struct strbuf **sbs)
 140{
 141        struct strbuf **s = sbs;
 142
 143        while (*s) {
 144                strbuf_release(*s);
 145                free(*s++);
 146        }
 147        free(sbs);
 148}
 149
 150int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 151{
 152        int len = a->len < b->len ? a->len: b->len;
 153        int cmp = memcmp(a->buf, b->buf, len);
 154        if (cmp)
 155                return cmp;
 156        return a->len < b->len ? -1: a->len != b->len;
 157}
 158
 159void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
 160                                   const void *data, size_t dlen)
 161{
 162        if (unsigned_add_overflows(pos, len))
 163                die("you want to use way too much memory");
 164        if (pos > sb->len)
 165                die("`pos' is too far after the end of the buffer");
 166        if (pos + len > sb->len)
 167                die("`pos + len' is too far after the end of the buffer");
 168
 169        if (dlen >= len)
 170                strbuf_grow(sb, dlen - len);
 171        memmove(sb->buf + pos + dlen,
 172                        sb->buf + pos + len,
 173                        sb->len - pos - len);
 174        memcpy(sb->buf + pos, data, dlen);
 175        strbuf_setlen(sb, sb->len + dlen - len);
 176}
 177
 178void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
 179{
 180        strbuf_splice(sb, pos, 0, data, len);
 181}
 182
 183void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
 184{
 185        strbuf_splice(sb, pos, len, NULL, 0);
 186}
 187
 188void strbuf_add(struct strbuf *sb, const void *data, size_t len)
 189{
 190        strbuf_grow(sb, len);
 191        memcpy(sb->buf + sb->len, data, len);
 192        strbuf_setlen(sb, sb->len + len);
 193}
 194
 195void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
 196{
 197        strbuf_grow(sb, len);
 198        memcpy(sb->buf + sb->len, sb->buf + pos, len);
 199        strbuf_setlen(sb, sb->len + len);
 200}
 201
 202void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 203{
 204        va_list ap;
 205        va_start(ap, fmt);
 206        strbuf_vaddf(sb, fmt, ap);
 207        va_end(ap);
 208}
 209
 210void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
 211{
 212        int len;
 213        va_list cp;
 214
 215        if (!strbuf_avail(sb))
 216                strbuf_grow(sb, 64);
 217        va_copy(cp, ap);
 218        len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
 219        va_end(cp);
 220        if (len < 0)
 221                die("BUG: your vsnprintf is broken (returned %d)", len);
 222        if (len > strbuf_avail(sb)) {
 223                strbuf_grow(sb, len);
 224                len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 225                if (len > strbuf_avail(sb))
 226                        die("BUG: your vsnprintf is broken (insatiable)");
 227        }
 228        strbuf_setlen(sb, sb->len + len);
 229}
 230
 231void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
 232                   void *context)
 233{
 234        for (;;) {
 235                const char *percent;
 236                size_t consumed;
 237
 238                percent = strchrnul(format, '%');
 239                strbuf_add(sb, format, percent - format);
 240                if (!*percent)
 241                        break;
 242                format = percent + 1;
 243
 244                if (*format == '%') {
 245                        strbuf_addch(sb, '%');
 246                        format++;
 247                        continue;
 248                }
 249
 250                consumed = fn(sb, format, context);
 251                if (consumed)
 252                        format += consumed;
 253                else
 254                        strbuf_addch(sb, '%');
 255        }
 256}
 257
 258size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
 259                void *context)
 260{
 261        struct strbuf_expand_dict_entry *e = context;
 262        size_t len;
 263
 264        for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
 265                if (!strncmp(placeholder, e->placeholder, len)) {
 266                        if (e->value)
 267                                strbuf_addstr(sb, e->value);
 268                        return len;
 269                }
 270        }
 271        return 0;
 272}
 273
 274void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
 275{
 276        int i, len = src->len;
 277
 278        for (i = 0; i < len; i++) {
 279                if (src->buf[i] == '%')
 280                        strbuf_addch(dst, '%');
 281                strbuf_addch(dst, src->buf[i]);
 282        }
 283}
 284
 285size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
 286{
 287        size_t res;
 288        size_t oldalloc = sb->alloc;
 289
 290        strbuf_grow(sb, size);
 291        res = fread(sb->buf + sb->len, 1, size, f);
 292        if (res > 0)
 293                strbuf_setlen(sb, sb->len + res);
 294        else if (oldalloc == 0)
 295                strbuf_release(sb);
 296        return res;
 297}
 298
 299ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
 300{
 301        size_t oldlen = sb->len;
 302        size_t oldalloc = sb->alloc;
 303
 304        strbuf_grow(sb, hint ? hint : 8192);
 305        for (;;) {
 306                ssize_t cnt;
 307
 308                cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
 309                if (cnt < 0) {
 310                        if (oldalloc == 0)
 311                                strbuf_release(sb);
 312                        else
 313                                strbuf_setlen(sb, oldlen);
 314                        return -1;
 315                }
 316                if (!cnt)
 317                        break;
 318                sb->len += cnt;
 319                strbuf_grow(sb, 8192);
 320        }
 321
 322        sb->buf[sb->len] = '\0';
 323        return sb->len - oldlen;
 324}
 325
 326#define STRBUF_MAXLINK (2*PATH_MAX)
 327
 328int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
 329{
 330        size_t oldalloc = sb->alloc;
 331
 332        if (hint < 32)
 333                hint = 32;
 334
 335        while (hint < STRBUF_MAXLINK) {
 336                int len;
 337
 338                strbuf_grow(sb, hint);
 339                len = readlink(path, sb->buf, hint);
 340                if (len < 0) {
 341                        if (errno != ERANGE)
 342                                break;
 343                } else if (len < hint) {
 344                        strbuf_setlen(sb, len);
 345                        return 0;
 346                }
 347
 348                /* .. the buffer was too small - try again */
 349                hint *= 2;
 350        }
 351        if (oldalloc == 0)
 352                strbuf_release(sb);
 353        return -1;
 354}
 355
 356int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
 357{
 358        int ch;
 359
 360        if (feof(fp))
 361                return EOF;
 362
 363        strbuf_reset(sb);
 364        while ((ch = fgetc(fp)) != EOF) {
 365                strbuf_grow(sb, 1);
 366                sb->buf[sb->len++] = ch;
 367                if (ch == term)
 368                        break;
 369        }
 370        if (ch == EOF && sb->len == 0)
 371                return EOF;
 372
 373        sb->buf[sb->len] = '\0';
 374        return 0;
 375}
 376
 377int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
 378{
 379        if (strbuf_getwholeline(sb, fp, term))
 380                return EOF;
 381        if (sb->buf[sb->len-1] == term)
 382                strbuf_setlen(sb, sb->len-1);
 383        return 0;
 384}
 385
 386int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term)
 387{
 388        strbuf_reset(sb);
 389
 390        while (1) {
 391                char ch;
 392                ssize_t len = xread(fd, &ch, 1);
 393                if (len <= 0)
 394                        return EOF;
 395                strbuf_addch(sb, ch);
 396                if (ch == term)
 397                        break;
 398        }
 399        return 0;
 400}
 401
 402int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
 403{
 404        int fd, len;
 405
 406        fd = open(path, O_RDONLY);
 407        if (fd < 0)
 408                return -1;
 409        len = strbuf_read(sb, fd, hint);
 410        close(fd);
 411        if (len < 0)
 412                return -1;
 413
 414        return len;
 415}
 416
 417void strbuf_add_lines(struct strbuf *out, const char *prefix,
 418                      const char *buf, size_t size)
 419{
 420        while (size) {
 421                const char *next = memchr(buf, '\n', size);
 422                next = next ? (next + 1) : (buf + size);
 423                strbuf_addstr(out, prefix);
 424                strbuf_add(out, buf, next - buf);
 425                size -= next - buf;
 426                buf = next;
 427        }
 428        strbuf_complete_line(out);
 429}
 430
 431static int is_rfc3986_reserved(char ch)
 432{
 433        switch (ch) {
 434                case '!': case '*': case '\'': case '(': case ')': case ';':
 435                case ':': case '@': case '&': case '=': case '+': case '$':
 436                case ',': case '/': case '?': case '#': case '[': case ']':
 437                        return 1;
 438        }
 439        return 0;
 440}
 441
 442static int is_rfc3986_unreserved(char ch)
 443{
 444        return isalnum(ch) ||
 445                ch == '-' || ch == '_' || ch == '.' || ch == '~';
 446}
 447
 448void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
 449                          int reserved)
 450{
 451        strbuf_grow(sb, len);
 452        while (len--) {
 453                char ch = *s++;
 454                if (is_rfc3986_unreserved(ch) ||
 455                    (!reserved && is_rfc3986_reserved(ch)))
 456                        strbuf_addch(sb, ch);
 457                else
 458                        strbuf_addf(sb, "%%%02x", ch);
 459        }
 460}
 461
 462void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
 463                             int reserved)
 464{
 465        strbuf_add_urlencode(sb, s, strlen(s), reserved);
 466}
 467
 468void strbuf_addf_ln(struct strbuf *sb, const char *fmt, ...)
 469{
 470        va_list ap;
 471        va_start(ap, fmt);
 472        strbuf_vaddf(sb, fmt, ap);
 473        va_end(ap);
 474        strbuf_addch(sb, '\n');
 475}
 476
 477int printf_ln(const char *fmt, ...)
 478{
 479        int ret;
 480        va_list ap;
 481        va_start(ap, fmt);
 482        ret = vprintf(fmt, ap);
 483        va_end(ap);
 484        if (ret < 0 || putchar('\n') == EOF)
 485                return -1;
 486        return ret + 1;
 487}
 488
 489int fprintf_ln(FILE *fp, const char *fmt, ...)
 490{
 491        int ret;
 492        va_list ap;
 493        va_start(ap, fmt);
 494        ret = vfprintf(fp, fmt, ap);
 495        va_end(ap);
 496        if (ret < 0 || putc('\n', fp) == EOF)
 497                return -1;
 498        return ret + 1;
 499}