Merge branch 'master' of git://repo.or.cz/unleashed
[unleashed.git] / contrib / libjeffpc / str.c
blob858388fefdece3ea6384d277166ca6b345077b6a
1 /*
2 * Copyright (c) 2014-2016 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <umem.h>
26 #include <alloca.h>
28 #include <jeffpc/str.h>
29 #include <jeffpc/jeffpc.h>
31 static umem_cache_t *str_cache;
33 void init_str_subsys(void)
35 str_cache = umem_cache_create("str-cache", sizeof(struct str),
36 0, NULL, NULL, NULL, NULL, NULL, 0);
37 ASSERT(str_cache);
40 static struct str *__alloc(char *s, bool copy)
42 struct str *str;
44 str = umem_cache_alloc(str_cache, 0);
45 if (!str)
46 return NULL;
48 refcnt_init(&str->refcnt, 1);
49 str->flags = 0;
51 if (copy) {
52 strcpy(str->inline_str, s);
53 str->str = str->inline_str;
54 } else {
55 str->str = s;
58 return str;
61 struct str *str_dup(const char *s)
63 if (!s)
64 return __alloc("", true);
66 if (strlen(s) <= STR_INLINE_LEN)
67 return __alloc((char *) s, true);
69 return str_alloc(strdup(s));
72 struct str *str_alloc(char *s)
74 return __alloc(s, false);
77 size_t str_len(const struct str *s)
79 return strlen(s->str);
82 int str_cmp(const struct str *a, const struct str *b)
84 return strcmp(a->str, b->str);
87 struct str *str_cat(int n, ...)
89 size_t totallen;
90 struct str *ret;
91 char *buf, *out;
92 size_t *len;
93 va_list ap;
94 int i;
96 if (!n)
97 return NULL;
99 if (n == 1) {
100 va_start(ap, n);
101 ret = va_arg(ap, struct str *);
102 va_end(ap);
103 return ret;
106 totallen = 0;
107 len = alloca(sizeof(size_t) * n);
109 va_start(ap, n);
110 for (i = 0; i < n; i++) {
111 struct str *str = va_arg(ap, struct str *);
113 if (!str)
114 continue;
116 len[i] = strlen(str->str);
118 totallen += len[i];
120 va_end(ap);
122 buf = malloc(totallen + 1);
123 ASSERT(buf);
125 out = buf;
127 va_start(ap, n);
128 for (i = 0; i < n; i++) {
129 struct str *str = va_arg(ap, struct str *);
131 if (!str)
132 continue;
134 strcpy(out, str->str);
136 out += len[i];
138 str_putref(str);
140 va_end(ap);
142 ret = str_alloc(buf);
143 ASSERT(ret);
145 return ret;
148 void str_free(struct str *str)
150 if (!str)
151 return;
153 ASSERT3U(refcnt_read(&str->refcnt), ==, 0);
155 if (str->str != str->inline_str)
156 free(str->str);
157 umem_cache_free(str_cache, str);
161 * We are not using REFCNT_FXNS() here because we want to support statically
162 * defined strings.
164 struct str *str_getref(struct str *x)
166 if (!x)
167 return NULL;
169 if (!(x->flags & STR_FLAG_STATIC)) {
170 ASSERT3U(refcnt_read(&x->refcnt), >=, 1);
172 __refcnt_inc(&x->refcnt);
175 return x;
178 void str_putref(struct str *x)
180 if (!x)
181 return;
183 if (x->flags & STR_FLAG_STATIC)
184 return;
186 ASSERT3S(refcnt_read(&x->refcnt), >=, 1);
188 if (!__refcnt_dec(&x->refcnt))
189 str_free(x);