strbuf.con commit Merge branch 'ks/maint-getenv-fix' (09a8fbd)
   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        if (sb->len + extra + 1 <= sb->len)
  67                die("you want to use way too much memory");
  68        if (!sb->alloc)
  69                sb->buf = NULL;
  70        ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
  71}
  72
  73void strbuf_trim(struct strbuf *sb)
  74{
  75        char *b = sb->buf;
  76        while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
  77                sb->len--;
  78        while (sb->len > 0 && isspace(*b)) {
  79                b++;
  80                sb->len--;
  81        }
  82        memmove(sb->buf, b, sb->len);
  83        sb->buf[sb->len] = '\0';
  84}
  85void strbuf_rtrim(struct strbuf *sb)
  86{
  87        while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1]))
  88                sb->len--;
  89        sb->buf[sb->len] = '\0';
  90}
  91
  92void strbuf_ltrim(struct strbuf *sb)
  93{
  94        char *b = sb->buf;
  95        while (sb->len > 0 && isspace(*b)) {
  96                b++;
  97                sb->len--;
  98        }
  99        memmove(sb->buf, b, sb->len);
 100        sb->buf[sb->len] = '\0';
 101}
 102
 103struct strbuf **strbuf_split(const struct strbuf *sb, int delim)
 104{
 105        int alloc = 2, pos = 0;
 106        char *n, *p;
 107        struct strbuf **ret;
 108        struct strbuf *t;
 109
 110        ret = xcalloc(alloc, sizeof(struct strbuf *));
 111        p = n = sb->buf;
 112        while (n < sb->buf + sb->len) {
 113                int len;
 114                n = memchr(n, delim, sb->len - (n - sb->buf));
 115                if (pos + 1 >= alloc) {
 116                        alloc = alloc * 2;
 117                        ret = xrealloc(ret, sizeof(struct strbuf *) * alloc);
 118                }
 119                if (!n)
 120                        n = sb->buf + sb->len - 1;
 121                len = n - p + 1;
 122                t = xmalloc(sizeof(struct strbuf));
 123                strbuf_init(t, len);
 124                strbuf_add(t, p, len);
 125                ret[pos] = t;
 126                ret[++pos] = NULL;
 127                p = ++n;
 128        }
 129        return ret;
 130}
 131
 132void strbuf_list_free(struct strbuf **sbs)
 133{
 134        struct strbuf **s = sbs;
 135
 136        while (*s) {
 137                strbuf_release(*s);
 138                free(*s++);
 139        }
 140        free(sbs);
 141}
 142
 143int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 144{
 145        int len = a->len < b->len ? a->len: b->len;
 146        int cmp = memcmp(a->buf, b->buf, len);
 147        if (cmp)
 148                return cmp;
 149        return a->len < b->len ? -1: a->len != b->len;
 150}
 151
 152void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
 153                                   const void *data, size_t dlen)
 154{
 155        if (pos + len < pos)
 156                die("you want to use way too much memory");
 157        if (pos > sb->len)
 158                die("`pos' is too far after the end of the buffer");
 159        if (pos + len > sb->len)
 160                die("`pos + len' is too far after the end of the buffer");
 161
 162        if (dlen >= len)
 163                strbuf_grow(sb, dlen - len);
 164        memmove(sb->buf + pos + dlen,
 165                        sb->buf + pos + len,
 166                        sb->len - pos - len);
 167        memcpy(sb->buf + pos, data, dlen);
 168        strbuf_setlen(sb, sb->len + dlen - len);
 169}
 170
 171void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
 172{
 173        strbuf_splice(sb, pos, 0, data, len);
 174}
 175
 176void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
 177{
 178        strbuf_splice(sb, pos, len, NULL, 0);
 179}
 180
 181void strbuf_add(struct strbuf *sb, const void *data, size_t len)
 182{
 183        strbuf_grow(sb, len);
 184        memcpy(sb->buf + sb->len, data, len);
 185        strbuf_setlen(sb, sb->len + len);
 186}
 187
 188void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
 189{
 190        strbuf_grow(sb, len);
 191        memcpy(sb->buf + sb->len, sb->buf + pos, len);
 192        strbuf_setlen(sb, sb->len + len);
 193}
 194
 195void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 196{
 197        int len;
 198        va_list ap;
 199
 200        if (!strbuf_avail(sb))
 201                strbuf_grow(sb, 64);
 202        va_start(ap, fmt);
 203        len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 204        va_end(ap);
 205        if (len < 0)
 206                die("your vsnprintf is broken");
 207        if (len > strbuf_avail(sb)) {
 208                strbuf_grow(sb, len);
 209                va_start(ap, fmt);
 210                len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
 211                va_end(ap);
 212                if (len > strbuf_avail(sb)) {
 213                        die("this should not happen, your snprintf is broken");
 214                }
 215        }
 216        strbuf_setlen(sb, sb->len + len);
 217}
 218
 219void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
 220                   void *context)
 221{
 222        for (;;) {
 223                const char *percent;
 224                size_t consumed;
 225
 226                percent = strchrnul(format, '%');
 227                strbuf_add(sb, format, percent - format);
 228                if (!*percent)
 229                        break;
 230                format = percent + 1;
 231
 232                if (*format == '%') {
 233                        strbuf_addch(sb, '%');
 234                        format++;
 235                        continue;
 236                }
 237
 238                consumed = fn(sb, format, context);
 239                if (consumed)
 240                        format += consumed;
 241                else
 242                        strbuf_addch(sb, '%');
 243        }
 244}
 245
 246size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
 247                void *context)
 248{
 249        struct strbuf_expand_dict_entry *e = context;
 250        size_t len;
 251
 252        for (; e->placeholder && (len = strlen(e->placeholder)); e++) {
 253                if (!strncmp(placeholder, e->placeholder, len)) {
 254                        if (e->value)
 255                                strbuf_addstr(sb, e->value);
 256                        return len;
 257                }
 258        }
 259        return 0;
 260}
 261
 262void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
 263{
 264        int i, len = src->len;
 265
 266        for (i = 0; i < len; i++) {
 267                if (src->buf[i] == '%')
 268                        strbuf_addch(dst, '%');
 269                strbuf_addch(dst, src->buf[i]);
 270        }
 271}
 272
 273size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
 274{
 275        size_t res;
 276        size_t oldalloc = sb->alloc;
 277
 278        strbuf_grow(sb, size);
 279        res = fread(sb->buf + sb->len, 1, size, f);
 280        if (res > 0)
 281                strbuf_setlen(sb, sb->len + res);
 282        else if (oldalloc == 0)
 283                strbuf_release(sb);
 284        return res;
 285}
 286
 287ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
 288{
 289        size_t oldlen = sb->len;
 290        size_t oldalloc = sb->alloc;
 291
 292        strbuf_grow(sb, hint ? hint : 8192);
 293        for (;;) {
 294                ssize_t cnt;
 295
 296                cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
 297                if (cnt < 0) {
 298                        if (oldalloc == 0)
 299                                strbuf_release(sb);
 300                        else
 301                                strbuf_setlen(sb, oldlen);
 302                        return -1;
 303                }
 304                if (!cnt)
 305                        break;
 306                sb->len += cnt;
 307                strbuf_grow(sb, 8192);
 308        }
 309
 310        sb->buf[sb->len] = '\0';
 311        return sb->len - oldlen;
 312}
 313
 314#define STRBUF_MAXLINK (2*PATH_MAX)
 315
 316int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
 317{
 318        size_t oldalloc = sb->alloc;
 319
 320        if (hint < 32)
 321                hint = 32;
 322
 323        while (hint < STRBUF_MAXLINK) {
 324                int len;
 325
 326                strbuf_grow(sb, hint);
 327                len = readlink(path, sb->buf, hint);
 328                if (len < 0) {
 329                        if (errno != ERANGE)
 330                                break;
 331                } else if (len < hint) {
 332                        strbuf_setlen(sb, len);
 333                        return 0;
 334                }
 335
 336                /* .. the buffer was too small - try again */
 337                hint *= 2;
 338        }
 339        if (oldalloc == 0)
 340                strbuf_release(sb);
 341        return -1;
 342}
 343
 344int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
 345{
 346        int ch;
 347
 348        strbuf_grow(sb, 0);
 349        if (feof(fp))
 350                return EOF;
 351
 352        strbuf_reset(sb);
 353        while ((ch = fgetc(fp)) != EOF) {
 354                strbuf_grow(sb, 1);
 355                sb->buf[sb->len++] = ch;
 356                if (ch == term)
 357                        break;
 358        }
 359        if (ch == EOF && sb->len == 0)
 360                return EOF;
 361
 362        sb->buf[sb->len] = '\0';
 363        return 0;
 364}
 365
 366int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
 367{
 368        if (strbuf_getwholeline(sb, fp, term))
 369                return EOF;
 370        if (sb->buf[sb->len-1] == term)
 371                strbuf_setlen(sb, sb->len-1);
 372        return 0;
 373}
 374
 375int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint)
 376{
 377        int fd, len;
 378
 379        fd = open(path, O_RDONLY);
 380        if (fd < 0)
 381                return -1;
 382        len = strbuf_read(sb, fd, hint);
 383        close(fd);
 384        if (len < 0)
 385                return -1;
 386
 387        return len;
 388}