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