1*4226f635SJason King /*
2*4226f635SJason King  * This file and its contents are supplied under the terms of the
3*4226f635SJason King  * Common Development and Distribution License ("CDDL"), version 1.0.
4*4226f635SJason King  * You may only use this file in accordance with the terms of version
5*4226f635SJason King  * 1.0 of the CDDL.
6*4226f635SJason King  *
7*4226f635SJason King  * A full copy of the text of the CDDL should have accompanied this
8*4226f635SJason King  * source.  A copy of the CDDL is also available via the Internet at
9*4226f635SJason King  * http://www.illumos.org/license/CDDL.
10*4226f635SJason King  */
11*4226f635SJason King 
12*4226f635SJason King /*
13*4226f635SJason King  * Copyright 2017 Jason King
14*4226f635SJason King  */
15*4226f635SJason King #include <string.h>
16*4226f635SJason King #include "str.h"
17*4226f635SJason King #include "demangle_int.h"
18*4226f635SJason King 
19*4226f635SJason King #define	STR_CHUNK_SZ	(64U)
20*4226f635SJason King 
21*4226f635SJason King /* are we storing a reference vs. a dynamically allocated copy? */
22*4226f635SJason King #define	IS_REF(s) ((s)->str_s != NULL && (s)->str_size == 0)
23*4226f635SJason King 
24*4226f635SJason King /*
25*4226f635SJason King  * Dynamically resizeable strings, with lazy allocation when initialized
26*4226f635SJason King  * with a constant string value
27*4226f635SJason King  *
28*4226f635SJason King  * NOTE: these are not necessairly 0-terminated
29*4226f635SJason King  *
30*4226f635SJason King  * Additionally, these can store references instead of copies of strings
31*4226f635SJason King  * (as indicated by the IS_REF() macro.  However mutation may cause a
32*4226f635SJason King  * string to convert from a refence to a dynamically allocated copy.
33*4226f635SJason King  */
34*4226f635SJason King 
35*4226f635SJason King void
str_init(str_t * restrict s,sysdem_ops_t * restrict ops)36*4226f635SJason King str_init(str_t *restrict s, sysdem_ops_t *restrict ops)
37*4226f635SJason King {
38*4226f635SJason King 	(void) memset(s, 0, sizeof (*s));
39*4226f635SJason King 	s->str_ops = (ops != NULL) ? ops : sysdem_ops_default;
40*4226f635SJason King }
41*4226f635SJason King 
42*4226f635SJason King void
str_fini(str_t * s)43*4226f635SJason King str_fini(str_t *s)
44*4226f635SJason King {
45*4226f635SJason King 	if (s == NULL)
46*4226f635SJason King 		return;
47*4226f635SJason King 	if (!IS_REF(s))
48*4226f635SJason King 		xfree(s->str_ops, s->str_s, s->str_size);
49*4226f635SJason King 	(void) memset(s, 0, sizeof (*s));
50*4226f635SJason King }
51*4226f635SJason King 
52*4226f635SJason King size_t
str_length(const str_t * s)53*4226f635SJason King str_length(const str_t *s)
54*4226f635SJason King {
55*4226f635SJason King 	return (s->str_len);
56*4226f635SJason King }
57*4226f635SJason King 
58*4226f635SJason King /*
59*4226f635SJason King  * store as a reference instead of a copy
60*4226f635SJason King  * if len == 0, means store entire copy of 0 terminated string
61*4226f635SJason King  */
62*4226f635SJason King void
str_set(str_t * s,const char * cstr,size_t len)63*4226f635SJason King str_set(str_t *s, const char *cstr, size_t len)
64*4226f635SJason King {
65*4226f635SJason King 	sysdem_ops_t *ops = s->str_ops;
66*4226f635SJason King 
67*4226f635SJason King 	str_fini(s);
68*4226f635SJason King 	s->str_ops = ops;
69*4226f635SJason King 	s->str_s = (char *)cstr;
70*4226f635SJason King 	s->str_len = (len == 0 && cstr != NULL) ? strlen(cstr) : len;
71*4226f635SJason King }
72*4226f635SJason King 
73*4226f635SJason King boolean_t
str_copy(const str_t * src,str_t * dest)74*4226f635SJason King str_copy(const str_t *src, str_t *dest)
75*4226f635SJason King {
76*4226f635SJason King 	str_fini(dest);
77*4226f635SJason King 	str_init(dest, src->str_ops);
78*4226f635SJason King 
79*4226f635SJason King 	if (src->str_len == 0)
80*4226f635SJason King 		return (B_TRUE);
81*4226f635SJason King 
82*4226f635SJason King 	size_t len = roundup(src->str_len, STR_CHUNK_SZ);
83*4226f635SJason King 	dest->str_s = zalloc(src->str_ops, len);
84*4226f635SJason King 	if (dest->str_s == NULL)
85*4226f635SJason King 		return (B_FALSE);
86*4226f635SJason King 
87*4226f635SJason King 	(void) memcpy(dest->str_s, src->str_s, src->str_len);
88*4226f635SJason King 	dest->str_len = src->str_len;
89*4226f635SJason King 	dest->str_size = len;
90*4226f635SJason King 
91*4226f635SJason King 	return (B_TRUE);
92*4226f635SJason King }
93*4226f635SJason King 
94*4226f635SJason King /*
95*4226f635SJason King  * ensure s has at least amt bytes free, resizing if necessary
96*4226f635SJason King  */
97*4226f635SJason King static boolean_t
str_reserve(str_t * s,size_t amt)98*4226f635SJason King str_reserve(str_t *s, size_t amt)
99*4226f635SJason King {
100*4226f635SJason King 	size_t newlen = s->str_len + amt;
101*4226f635SJason King 
102*4226f635SJason King 	/* overflow check */
103*4226f635SJason King 	if (newlen < s->str_len || newlen < amt)
104*4226f635SJason King 		return (B_FALSE);
105*4226f635SJason King 
106*4226f635SJason King 	if ((amt > 0) && (s->str_len + amt <= s->str_size))
107*4226f635SJason King 		return (B_TRUE);
108*4226f635SJason King 
109*4226f635SJason King 	size_t newsize = roundup(newlen, STR_CHUNK_SZ);
110*4226f635SJason King 	void *temp;
111*4226f635SJason King 
112*4226f635SJason King 	if (IS_REF(s)) {
113*4226f635SJason King 		temp = zalloc(s->str_ops, newsize);
114*4226f635SJason King 		if (temp == NULL)
115*4226f635SJason King 			return (B_FALSE);
116*4226f635SJason King 
117*4226f635SJason King 		(void) memcpy(temp, s->str_s, s->str_len);
118*4226f635SJason King 	} else {
119*4226f635SJason King 		temp = xrealloc(s->str_ops, s->str_s, s->str_size, newsize);
120*4226f635SJason King 		if (temp == NULL)
121*4226f635SJason King 			return (B_FALSE);
122*4226f635SJason King 	}
123*4226f635SJason King 
124*4226f635SJason King 	s->str_s = temp;
125*4226f635SJason King 	s->str_size = newsize;
126*4226f635SJason King 
127*4226f635SJason King 	return (B_TRUE);
128*4226f635SJason King }
129*4226f635SJason King 
130*4226f635SJason King /* append to s, cstrlen == 0 means entire length of string */
131*4226f635SJason King boolean_t
str_append(str_t * s,const char * cstr,size_t cstrlen)132*4226f635SJason King str_append(str_t *s, const char *cstr, size_t cstrlen)
133*4226f635SJason King {
134*4226f635SJason King 	if (cstr != NULL && cstrlen == 0)
135*4226f635SJason King 		cstrlen = strlen(cstr);
136*4226f635SJason King 
137*4226f635SJason King 	const str_t src = {
138*4226f635SJason King 		.str_s = (char *)cstr,
139*4226f635SJason King 		.str_len = cstrlen,
140*4226f635SJason King 		.str_ops = s->str_ops
141*4226f635SJason King 	};
142*4226f635SJason King 
143*4226f635SJason King 	return (str_append_str(s, &src));
144*4226f635SJason King }
145*4226f635SJason King 
146*4226f635SJason King boolean_t
str_append_str(str_t * dest,const str_t * src)147*4226f635SJason King str_append_str(str_t *dest, const str_t *src)
148*4226f635SJason King {
149*4226f635SJason King 	/* empty string is a noop */
150*4226f635SJason King 	if (src->str_s == NULL || src->str_len == 0)
151*4226f635SJason King 		return (B_TRUE);
152*4226f635SJason King 
153*4226f635SJason King 	/* if src is a reference, we can just copy that */
154*4226f635SJason King 	if (dest->str_s == NULL && IS_REF(src)) {
155*4226f635SJason King 		*dest = *src;
156*4226f635SJason King 		return (B_TRUE);
157*4226f635SJason King 	}
158*4226f635SJason King 
159*4226f635SJason King 	if (!str_reserve(dest, src->str_len))
160*4226f635SJason King 		return (B_FALSE);
161*4226f635SJason King 
162*4226f635SJason King 	(void) memcpy(dest->str_s + dest->str_len, src->str_s, src->str_len);
163*4226f635SJason King 	dest->str_len += src->str_len;
164*4226f635SJason King 	return (B_TRUE);
165*4226f635SJason King }
166*4226f635SJason King 
167*4226f635SJason King boolean_t
str_append_c(str_t * s,char c)168*4226f635SJason King str_append_c(str_t *s, char c)
169*4226f635SJason King {
170*4226f635SJason King 	if (!str_reserve(s, 1))
171*4226f635SJason King 		return (B_FALSE);
172*4226f635SJason King 
173*4226f635SJason King 	s->str_s[s->str_len++] = c;
174*4226f635SJason King 	return (B_TRUE);
175*4226f635SJason King }
176*4226f635SJason King 
177*4226f635SJason King boolean_t
str_insert(str_t * s,size_t idx,const char * cstr,size_t cstrlen)178*4226f635SJason King str_insert(str_t *s, size_t idx, const char *cstr, size_t cstrlen)
179*4226f635SJason King {
180*4226f635SJason King 	if (cstr == NULL)
181*4226f635SJason King 		return (B_TRUE);
182*4226f635SJason King 
183*4226f635SJason King 	if (cstrlen == 0)
184*4226f635SJason King 		cstrlen = strlen(cstr);
185*4226f635SJason King 
186*4226f635SJason King 	str_t src = {
187*4226f635SJason King 		.str_s = (char *)cstr,
188*4226f635SJason King 		.str_len = cstrlen,
189*4226f635SJason King 		.str_ops = s->str_ops,
190*4226f635SJason King 		.str_size = 0
191*4226f635SJason King 	};
192*4226f635SJason King 
193*4226f635SJason King 	return (str_insert_str(s, idx, &src));
194*4226f635SJason King }
195*4226f635SJason King 
196*4226f635SJason King boolean_t
str_insert_str(str_t * dest,size_t idx,const str_t * src)197*4226f635SJason King str_insert_str(str_t *dest, size_t idx, const str_t *src)
198*4226f635SJason King {
199*4226f635SJason King 	ASSERT3U(idx, <=, dest->str_len);
200*4226f635SJason King 
201*4226f635SJason King 	if (idx == dest->str_len)
202*4226f635SJason King 		return (str_append_str(dest, src));
203*4226f635SJason King 
204*4226f635SJason King 	if (idx == 0 && dest->str_s == NULL && IS_REF(src)) {
205*4226f635SJason King 		sysdem_ops_t *ops = dest->str_ops;
206*4226f635SJason King 		*dest = *src;
207*4226f635SJason King 		dest->str_ops = ops;
208*4226f635SJason King 		return (B_TRUE);
209*4226f635SJason King 	}
210*4226f635SJason King 
211*4226f635SJason King 	if (!str_reserve(dest, src->str_len))
212*4226f635SJason King 		return (B_FALSE);
213*4226f635SJason King 
214*4226f635SJason King 	/*
215*4226f635SJason King 	 * Shift the contents of dest over at the insertion point.  Since
216*4226f635SJason King 	 * src and dest ranges will overlap, and unlike some programmers,
217*4226f635SJason King 	 * *I* can read man pages - memmove() is the appropriate function
218*4226f635SJason King 	 * to this.
219*4226f635SJason King 	 */
220*4226f635SJason King 	(void) memmove(dest->str_s + idx + src->str_len, dest->str_s + idx,
221*4226f635SJason King 	    dest->str_len - idx);
222*4226f635SJason King 
223*4226f635SJason King 	/*
224*4226f635SJason King 	 * However the content to insert does not overlap with the destination
225*4226f635SJason King 	 * so memcpy() is fine here.
226*4226f635SJason King 	 */
227*4226f635SJason King 	(void) memcpy(dest->str_s + idx, src->str_s, src->str_len);
228*4226f635SJason King 	dest->str_len += src->str_len;
229*4226f635SJason King 
230*4226f635SJason King 	return (B_TRUE);
231*4226f635SJason King }
232*4226f635SJason King 
233*4226f635SJason King boolean_t
str_erase(str_t * s,size_t pos,size_t len)234*4226f635SJason King str_erase(str_t *s, size_t pos, size_t len)
235*4226f635SJason King {
236*4226f635SJason King 	ASSERT3U(pos, <, s->str_len);
237*4226f635SJason King 	ASSERT3U(pos + len, <=, s->str_len);
238*4226f635SJason King 
239*4226f635SJason King 	if (IS_REF(s)) {
240*4226f635SJason King 		if (!str_reserve(s, 0))
241*4226f635SJason King 			return (B_FALSE);
242*4226f635SJason King 	}
243*4226f635SJason King 
244*4226f635SJason King 	(void) memmove(s->str_s + pos, s->str_s + pos + len, s->str_len - len);
245*4226f635SJason King 	s->str_len -= len;
246*4226f635SJason King 	return (B_TRUE);
247*4226f635SJason King }
248*4226f635SJason King 
249*4226f635SJason King str_pair_t *
str_pair_init(str_pair_t * sp,sysdem_ops_t * ops)250*4226f635SJason King str_pair_init(str_pair_t *sp, sysdem_ops_t *ops)
251*4226f635SJason King {
252*4226f635SJason King 	(void) memset(sp, 0, sizeof (*sp));
253*4226f635SJason King 	str_init(&sp->strp_l, ops);
254*4226f635SJason King 	str_init(&sp->strp_r, ops);
255*4226f635SJason King 	return (sp);
256*4226f635SJason King }
257*4226f635SJason King 
258*4226f635SJason King void
str_pair_fini(str_pair_t * sp)259*4226f635SJason King str_pair_fini(str_pair_t *sp)
260*4226f635SJason King {
261*4226f635SJason King 	str_fini(&sp->strp_l);
262*4226f635SJason King 	str_fini(&sp->strp_r);
263*4226f635SJason King }
264*4226f635SJason King 
265*4226f635SJason King /* combine left and right parts and put result into left part */
266*4226f635SJason King boolean_t
str_pair_merge(str_pair_t * sp)267*4226f635SJason King str_pair_merge(str_pair_t *sp)
268*4226f635SJason King {
269*4226f635SJason King 	/* if right side is empty, don't need to do anything */
270*4226f635SJason King 	if (str_length(&sp->strp_r) == 0)
271*4226f635SJason King 		return (B_TRUE);
272*4226f635SJason King 
273*4226f635SJason King 	/* if left side is empty, just move right to left */
274*4226f635SJason King 	if (str_length(&sp->strp_l) == 0) {
275*4226f635SJason King 		str_fini(&sp->strp_l);
276*4226f635SJason King 		sp->strp_l = sp->strp_r;
277*4226f635SJason King 		sp->strp_r.str_s = NULL;
278*4226f635SJason King 		sp->strp_r.str_len = sp->strp_r.str_size = 0;
279*4226f635SJason King 		return (B_TRUE);
280*4226f635SJason King 	}
281*4226f635SJason King 
282*4226f635SJason King 	if (!str_append_str(&sp->strp_l, &sp->strp_r))
283*4226f635SJason King 		return (B_FALSE);
284*4226f635SJason King 
285*4226f635SJason King 	str_fini(&sp->strp_r);
286*4226f635SJason King 	str_init(&sp->strp_r, sp->strp_l.str_ops);
287*4226f635SJason King 	return (B_TRUE);
288*4226f635SJason King }
289*4226f635SJason King 
290*4226f635SJason King boolean_t
str_pair_copy(const str_pair_t * src,str_pair_t * dest)291*4226f635SJason King str_pair_copy(const str_pair_t *src, str_pair_t *dest)
292*4226f635SJason King {
293*4226f635SJason King 	boolean_t ok = B_TRUE;
294*4226f635SJason King 
295*4226f635SJason King 	ok &= str_copy(&src->strp_l, &dest->strp_l);
296*4226f635SJason King 	ok &= str_copy(&src->strp_r, &dest->strp_r);
297*4226f635SJason King 
298*4226f635SJason King 	if (!ok) {
299*4226f635SJason King 		str_fini(&dest->strp_l);
300*4226f635SJason King 		str_fini(&dest->strp_r);
301*4226f635SJason King 		return (B_FALSE);
302*4226f635SJason King 	}
303*4226f635SJason King 
304*4226f635SJason King 	return (B_TRUE);
305*4226f635SJason King }
306*4226f635SJason King 
307*4226f635SJason King size_t
str_pair_len(const str_pair_t * sp)308*4226f635SJason King str_pair_len(const str_pair_t *sp)
309*4226f635SJason King {
310*4226f635SJason King 	return (str_length(&sp->strp_l) + str_length(&sp->strp_r));
311*4226f635SJason King }