Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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  * Used as the default ->buf value, so that people can always assume
0015  * buf is non NULL and ->buf is NUL terminated even for a freshly
0016  * initialized strbuf.
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      * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is
0062      * a static variable. Thus we have to avoid passing it to realloc.
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 }