0001
0002 #include "cache.h"
0003 #include "debug.h"
0004 #include "strbuf.h"
0005 #include <linux/kernel.h>
0006 #include <linux/string.h>
0007 #include <linux/zalloc.h>
0008 #include <errno.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <unistd.h>
0012
0013
0014
0015
0016
0017
0018 char strbuf_slopbuf[1];
0019
0020 int strbuf_init(struct strbuf *sb, ssize_t hint)
0021 {
0022 sb->alloc = sb->len = 0;
0023 sb->buf = strbuf_slopbuf;
0024 if (hint)
0025 return strbuf_grow(sb, hint);
0026 return 0;
0027 }
0028
0029 void strbuf_release(struct strbuf *sb)
0030 {
0031 if (sb->alloc) {
0032 zfree(&sb->buf);
0033 strbuf_init(sb, 0);
0034 }
0035 }
0036
0037 char *strbuf_detach(struct strbuf *sb, size_t *sz)
0038 {
0039 char *res = sb->alloc ? sb->buf : NULL;
0040 if (sz)
0041 *sz = sb->len;
0042 strbuf_init(sb, 0);
0043 return res;
0044 }
0045
0046 int strbuf_grow(struct strbuf *sb, size_t extra)
0047 {
0048 char *buf;
0049 size_t nr = sb->len + extra + 1;
0050
0051 if (nr < sb->alloc)
0052 return 0;
0053
0054 if (nr <= sb->len)
0055 return -E2BIG;
0056
0057 if (alloc_nr(sb->alloc) > nr)
0058 nr = alloc_nr(sb->alloc);
0059
0060
0061
0062
0063
0064 buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf));
0065 if (!buf)
0066 return -ENOMEM;
0067
0068 sb->buf = buf;
0069 sb->alloc = nr;
0070 return 0;
0071 }
0072
0073 int strbuf_addch(struct strbuf *sb, int c)
0074 {
0075 int ret = strbuf_grow(sb, 1);
0076 if (ret)
0077 return ret;
0078
0079 sb->buf[sb->len++] = c;
0080 sb->buf[sb->len] = '\0';
0081 return 0;
0082 }
0083
0084 int strbuf_add(struct strbuf *sb, const void *data, size_t len)
0085 {
0086 int ret = strbuf_grow(sb, len);
0087 if (ret)
0088 return ret;
0089
0090 memcpy(sb->buf + sb->len, data, len);
0091 return strbuf_setlen(sb, sb->len + len);
0092 }
0093
0094 static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
0095 {
0096 int len, ret;
0097 va_list ap_saved;
0098
0099 if (!strbuf_avail(sb)) {
0100 ret = strbuf_grow(sb, 64);
0101 if (ret)
0102 return ret;
0103 }
0104
0105 va_copy(ap_saved, ap);
0106 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
0107 if (len < 0) {
0108 va_end(ap_saved);
0109 return len;
0110 }
0111 if (len > strbuf_avail(sb)) {
0112 ret = strbuf_grow(sb, len);
0113 if (ret) {
0114 va_end(ap_saved);
0115 return ret;
0116 }
0117 len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved);
0118 if (len > strbuf_avail(sb)) {
0119 pr_debug("this should not happen, your vsnprintf is broken");
0120 va_end(ap_saved);
0121 return -EINVAL;
0122 }
0123 }
0124 va_end(ap_saved);
0125 return strbuf_setlen(sb, sb->len + len);
0126 }
0127
0128 int strbuf_addf(struct strbuf *sb, const char *fmt, ...)
0129 {
0130 va_list ap;
0131 int ret;
0132
0133 va_start(ap, fmt);
0134 ret = strbuf_addv(sb, fmt, ap);
0135 va_end(ap);
0136 return ret;
0137 }
0138
0139 ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint)
0140 {
0141 size_t oldlen = sb->len;
0142 size_t oldalloc = sb->alloc;
0143 int ret;
0144
0145 ret = strbuf_grow(sb, hint ? hint : 8192);
0146 if (ret)
0147 return ret;
0148
0149 for (;;) {
0150 ssize_t cnt;
0151
0152 cnt = read(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
0153 if (cnt < 0) {
0154 if (oldalloc == 0)
0155 strbuf_release(sb);
0156 else
0157 strbuf_setlen(sb, oldlen);
0158 return cnt;
0159 }
0160 if (!cnt)
0161 break;
0162 sb->len += cnt;
0163 ret = strbuf_grow(sb, 8192);
0164 if (ret)
0165 return ret;
0166 }
0167
0168 sb->buf[sb->len] = '\0';
0169 return sb->len - oldlen;
0170 }