0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <kunit/test.h>
0010 #include <linux/list.h>
0011 #include <linux/slab.h>
0012
0013 #include "string-stream.h"
0014
0015 struct string_stream_fragment_alloc_context {
0016 struct kunit *test;
0017 int len;
0018 gfp_t gfp;
0019 };
0020
0021 static int string_stream_fragment_init(struct kunit_resource *res,
0022 void *context)
0023 {
0024 struct string_stream_fragment_alloc_context *ctx = context;
0025 struct string_stream_fragment *frag;
0026
0027 frag = kunit_kzalloc(ctx->test, sizeof(*frag), ctx->gfp);
0028 if (!frag)
0029 return -ENOMEM;
0030
0031 frag->test = ctx->test;
0032 frag->fragment = kunit_kmalloc(ctx->test, ctx->len, ctx->gfp);
0033 if (!frag->fragment)
0034 return -ENOMEM;
0035
0036 res->data = frag;
0037
0038 return 0;
0039 }
0040
0041 static void string_stream_fragment_free(struct kunit_resource *res)
0042 {
0043 struct string_stream_fragment *frag = res->data;
0044
0045 list_del(&frag->node);
0046 kunit_kfree(frag->test, frag->fragment);
0047 kunit_kfree(frag->test, frag);
0048 }
0049
0050 static struct string_stream_fragment *alloc_string_stream_fragment(
0051 struct kunit *test, int len, gfp_t gfp)
0052 {
0053 struct string_stream_fragment_alloc_context context = {
0054 .test = test,
0055 .len = len,
0056 .gfp = gfp
0057 };
0058
0059 return kunit_alloc_resource(test,
0060 string_stream_fragment_init,
0061 string_stream_fragment_free,
0062 gfp,
0063 &context);
0064 }
0065
0066 static int string_stream_fragment_destroy(struct string_stream_fragment *frag)
0067 {
0068 return kunit_destroy_resource(frag->test,
0069 kunit_resource_instance_match,
0070 frag);
0071 }
0072
0073 int string_stream_vadd(struct string_stream *stream,
0074 const char *fmt,
0075 va_list args)
0076 {
0077 struct string_stream_fragment *frag_container;
0078 int len;
0079 va_list args_for_counting;
0080
0081
0082 va_copy(args_for_counting, args);
0083
0084
0085 len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1;
0086
0087 va_end(args_for_counting);
0088
0089 frag_container = alloc_string_stream_fragment(stream->test,
0090 len,
0091 stream->gfp);
0092 if (!frag_container)
0093 return -ENOMEM;
0094
0095 len = vsnprintf(frag_container->fragment, len, fmt, args);
0096 spin_lock(&stream->lock);
0097 stream->length += len;
0098 list_add_tail(&frag_container->node, &stream->fragments);
0099 spin_unlock(&stream->lock);
0100
0101 return 0;
0102 }
0103
0104 int string_stream_add(struct string_stream *stream, const char *fmt, ...)
0105 {
0106 va_list args;
0107 int result;
0108
0109 va_start(args, fmt);
0110 result = string_stream_vadd(stream, fmt, args);
0111 va_end(args);
0112
0113 return result;
0114 }
0115
0116 static void string_stream_clear(struct string_stream *stream)
0117 {
0118 struct string_stream_fragment *frag_container, *frag_container_safe;
0119
0120 spin_lock(&stream->lock);
0121 list_for_each_entry_safe(frag_container,
0122 frag_container_safe,
0123 &stream->fragments,
0124 node) {
0125 string_stream_fragment_destroy(frag_container);
0126 }
0127 stream->length = 0;
0128 spin_unlock(&stream->lock);
0129 }
0130
0131 char *string_stream_get_string(struct string_stream *stream)
0132 {
0133 struct string_stream_fragment *frag_container;
0134 size_t buf_len = stream->length + 1;
0135 char *buf;
0136
0137 buf = kunit_kzalloc(stream->test, buf_len, stream->gfp);
0138 if (!buf)
0139 return NULL;
0140
0141 spin_lock(&stream->lock);
0142 list_for_each_entry(frag_container, &stream->fragments, node)
0143 strlcat(buf, frag_container->fragment, buf_len);
0144 spin_unlock(&stream->lock);
0145
0146 return buf;
0147 }
0148
0149 int string_stream_append(struct string_stream *stream,
0150 struct string_stream *other)
0151 {
0152 const char *other_content;
0153
0154 other_content = string_stream_get_string(other);
0155
0156 if (!other_content)
0157 return -ENOMEM;
0158
0159 return string_stream_add(stream, other_content);
0160 }
0161
0162 bool string_stream_is_empty(struct string_stream *stream)
0163 {
0164 return list_empty(&stream->fragments);
0165 }
0166
0167 struct string_stream_alloc_context {
0168 struct kunit *test;
0169 gfp_t gfp;
0170 };
0171
0172 static int string_stream_init(struct kunit_resource *res, void *context)
0173 {
0174 struct string_stream *stream;
0175 struct string_stream_alloc_context *ctx = context;
0176
0177 stream = kunit_kzalloc(ctx->test, sizeof(*stream), ctx->gfp);
0178 if (!stream)
0179 return -ENOMEM;
0180
0181 res->data = stream;
0182 stream->gfp = ctx->gfp;
0183 stream->test = ctx->test;
0184 INIT_LIST_HEAD(&stream->fragments);
0185 spin_lock_init(&stream->lock);
0186
0187 return 0;
0188 }
0189
0190 static void string_stream_free(struct kunit_resource *res)
0191 {
0192 struct string_stream *stream = res->data;
0193
0194 string_stream_clear(stream);
0195 }
0196
0197 struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
0198 {
0199 struct string_stream_alloc_context context = {
0200 .test = test,
0201 .gfp = gfp
0202 };
0203
0204 return kunit_alloc_resource(test,
0205 string_stream_init,
0206 string_stream_free,
0207 gfp,
0208 &context);
0209 }
0210
0211 int string_stream_destroy(struct string_stream *stream)
0212 {
0213 return kunit_destroy_resource(stream->test,
0214 kunit_resource_instance_match,
0215 stream);
0216 }