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 
16*4226f635SJason King #include <string.h>
17*4226f635SJason King #include <errno.h>
18*4226f635SJason King #include <stdlib.h>
19*4226f635SJason King #include "demangle_int.h"
20*4226f635SJason King #include "cxx.h"
21*4226f635SJason King 
22*4226f635SJason King #define	CHUNK_SIZE  (8U)
23*4226f635SJason King 
24*4226f635SJason King /*
25*4226f635SJason King  * A name_t is essentially a stack of str_pair_t's.  Generally, the parsing
26*4226f635SJason King  * code will push (via name_add() or the like) portions of the demangled
27*4226f635SJason King  * name into a name_t, and periodically combine them via name_join().
28*4226f635SJason King  *
29*4226f635SJason King  * As such it should be noted that since items are added at the end of
30*4226f635SJason King  * name_t->nm_items, the numbering of name_at() starts at the end
31*4226f635SJason King  * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
32*4226f635SJason King  *
33*4226f635SJason King  * It should also be noted that for name_t's, adding is a move operation in
34*4226f635SJason King  * that it takes ownership of the passed in string/str_t/etc
35*4226f635SJason King  */
36*4226f635SJason King 
37*4226f635SJason King void
name_init(name_t * n,sysdem_ops_t * ops)38*4226f635SJason King name_init(name_t *n, sysdem_ops_t *ops)
39*4226f635SJason King {
40*4226f635SJason King 	(void) memset(n, 0, sizeof (*n));
41*4226f635SJason King 	n->nm_ops = (ops != NULL) ? ops : sysdem_ops_default;
42*4226f635SJason King }
43*4226f635SJason King 
44*4226f635SJason King void
name_fini(name_t * n)45*4226f635SJason King name_fini(name_t *n)
46*4226f635SJason King {
47*4226f635SJason King 	if (n == NULL)
48*4226f635SJason King 		return;
49*4226f635SJason King 
50*4226f635SJason King 	name_clear(n);
51*4226f635SJason King 	xfree(n->nm_ops, n->nm_items, n->nm_size);
52*4226f635SJason King 	n->nm_items = NULL;
53*4226f635SJason King 	n->nm_size = 0;
54*4226f635SJason King }
55*4226f635SJason King 
56*4226f635SJason King size_t
name_len(const name_t * n)57*4226f635SJason King name_len(const name_t *n)
58*4226f635SJason King {
59*4226f635SJason King 	return (n->nm_len);
60*4226f635SJason King }
61*4226f635SJason King 
62*4226f635SJason King boolean_t
name_empty(const name_t * n)63*4226f635SJason King name_empty(const name_t *n)
64*4226f635SJason King {
65*4226f635SJason King 	return (name_len(n) == 0 ? B_TRUE : B_FALSE);
66*4226f635SJason King }
67*4226f635SJason King 
68*4226f635SJason King void
name_clear(name_t * n)69*4226f635SJason King name_clear(name_t *n)
70*4226f635SJason King {
71*4226f635SJason King 	if (n == NULL)
72*4226f635SJason King 		return;
73*4226f635SJason King 
74*4226f635SJason King 	for (size_t i = 0; i < n->nm_len; i++) {
75*4226f635SJason King 		str_pair_t *sp = &n->nm_items[i];
76*4226f635SJason King 		sysdem_ops_t *ops = sp->strp_l.str_ops;
77*4226f635SJason King 
78*4226f635SJason King 		str_pair_fini(sp);
79*4226f635SJason King 		(void) str_pair_init(sp, ops);
80*4226f635SJason King 	}
81*4226f635SJason King 
82*4226f635SJason King 	n->nm_len = 0;
83*4226f635SJason King }
84*4226f635SJason King 
85*4226f635SJason King static boolean_t
name_reserve(name_t * n,size_t amt)86*4226f635SJason King name_reserve(name_t *n, size_t amt)
87*4226f635SJason King {
88*4226f635SJason King 	size_t newlen = n->nm_len + amt;
89*4226f635SJason King 
90*4226f635SJason King 	if (newlen == cpp_name_max_depth) {
91*4226f635SJason King 		errno = ENAMETOOLONG;
92*4226f635SJason King 		return (B_FALSE);
93*4226f635SJason King 	}
94*4226f635SJason King 
95*4226f635SJason King 	if (newlen < n->nm_size)
96*4226f635SJason King 		return (B_TRUE);
97*4226f635SJason King 
98*4226f635SJason King 	size_t newsize = roundup(newlen, CHUNK_SIZE);
99*4226f635SJason King 	if (newsize > cpp_name_max_depth)
100*4226f635SJason King 		newsize = cpp_name_max_depth;
101*4226f635SJason King 
102*4226f635SJason King 	void *temp = xrealloc(n->nm_ops, n->nm_items,
103*4226f635SJason King 	    n->nm_size * sizeof (str_pair_t), newsize * sizeof (str_pair_t));
104*4226f635SJason King 
105*4226f635SJason King 	if (temp == NULL)
106*4226f635SJason King 		return (B_FALSE);
107*4226f635SJason King 
108*4226f635SJason King 	n->nm_items = temp;
109*4226f635SJason King 	n->nm_size = newsize;
110*4226f635SJason King 	return (B_TRUE);
111*4226f635SJason King }
112*4226f635SJason King 
113*4226f635SJason King boolean_t
name_add(name_t * n,const char * l,size_t l_len,const char * r,size_t r_len)114*4226f635SJason King name_add(name_t *n, const char *l, size_t l_len, const char *r, size_t r_len)
115*4226f635SJason King {
116*4226f635SJason King 	str_t sl = { 0 };
117*4226f635SJason King 	str_t sr = { 0 };
118*4226f635SJason King 
119*4226f635SJason King 	str_init(&sl, n->nm_ops);
120*4226f635SJason King 	str_init(&sr, n->nm_ops);
121*4226f635SJason King 	str_set(&sl, l, l_len);
122*4226f635SJason King 	str_set(&sr, r, r_len);
123*4226f635SJason King 	return (name_add_str(n, &sl, &sr));
124*4226f635SJason King }
125*4226f635SJason King 
126*4226f635SJason King boolean_t
name_add_str(name_t * n,str_t * l,str_t * r)127*4226f635SJason King name_add_str(name_t *n, str_t *l, str_t *r)
128*4226f635SJason King {
129*4226f635SJason King 	str_pair_t sp;
130*4226f635SJason King 
131*4226f635SJason King 	(void) str_pair_init(&sp, n->nm_ops);
132*4226f635SJason King 
133*4226f635SJason King 	if (!name_reserve(n, 1))
134*4226f635SJason King 		return (B_FALSE);
135*4226f635SJason King 
136*4226f635SJason King 	if (l != NULL) {
137*4226f635SJason King 		sp.strp_l = *l;
138*4226f635SJason King 		(void) memset(l, 0, sizeof (*l));
139*4226f635SJason King 	}
140*4226f635SJason King 
141*4226f635SJason King 	if (r != NULL) {
142*4226f635SJason King 		sp.strp_r = *r;
143*4226f635SJason King 		(void) memset(r, 0, sizeof (*r));
144*4226f635SJason King 	}
145*4226f635SJason King 
146*4226f635SJason King 	n->nm_items[n->nm_len++] = sp;
147*4226f635SJason King 
148*4226f635SJason King 	return (B_TRUE);
149*4226f635SJason King }
150*4226f635SJason King 
151*4226f635SJason King str_pair_t *
name_at(const name_t * n,size_t idx)152*4226f635SJason King name_at(const name_t *n, size_t idx)
153*4226f635SJason King {
154*4226f635SJason King 	VERIFY(!name_empty(n));
155*4226f635SJason King 	VERIFY3U(idx, <, n->nm_len);
156*4226f635SJason King 	return (&n->nm_items[n->nm_len - idx - 1]);
157*4226f635SJason King }
158*4226f635SJason King 
159*4226f635SJason King str_pair_t *
name_top(name_t * n)160*4226f635SJason King name_top(name_t *n)
161*4226f635SJason King {
162*4226f635SJason King 	return (name_at(n, 0));
163*4226f635SJason King }
164*4226f635SJason King 
165*4226f635SJason King void
name_pop(name_t * n,str_pair_t * sp)166*4226f635SJason King name_pop(name_t *n, str_pair_t *sp)
167*4226f635SJason King {
168*4226f635SJason King 	if (n->nm_len == 0)
169*4226f635SJason King 		return;
170*4226f635SJason King 
171*4226f635SJason King 	str_pair_t *top = name_top(n);
172*4226f635SJason King 
173*4226f635SJason King 	if (sp != NULL) {
174*4226f635SJason King 		*sp = *top;
175*4226f635SJason King 		(void) memset(top, 0, sizeof (*top));
176*4226f635SJason King 	} else {
177*4226f635SJason King 		str_pair_fini(top);
178*4226f635SJason King 	}
179*4226f635SJason King 
180*4226f635SJason King 	n->nm_len--;
181*4226f635SJason King }
182*4226f635SJason King 
183*4226f635SJason King boolean_t
name_join(name_t * n,size_t amt,const char * sep)184*4226f635SJason King name_join(name_t *n, size_t amt, const char *sep)
185*4226f635SJason King {
186*4226f635SJason King 	str_pair_t *sp = NULL;
187*4226f635SJason King 	str_t res = { 0 };
188*4226f635SJason King 	size_t seplen = strlen(sep);
189*4226f635SJason King 
190*4226f635SJason King 	VERIFY3U(amt, <=, n->nm_len);
191*4226f635SJason King 
192*4226f635SJason King 	/*
193*4226f635SJason King 	 * A join of 0 elements places an empty string on the stack.  This
194*4226f635SJason King 	 * simplifies code that wants to do things like:
195*4226f635SJason King 	 *   name_join(...); name_fmt(.., "({0})", ...)
196*4226f635SJason King 	 */
197*4226f635SJason King 	if (amt == 0) {
198*4226f635SJason King 		(void) name_add(n, "", 0, "", 0);
199*4226f635SJason King 		return (B_TRUE);
200*4226f635SJason King 	}
201*4226f635SJason King 
202*4226f635SJason King 	/* A join of 1 element just implies merging the top str_pair_t */
203*4226f635SJason King 	if (amt == 1) {
204*4226f635SJason King 		VERIFY3U(name_len(n), >, 0);
205*4226f635SJason King 		return (str_pair_merge(name_top(n)));
206*4226f635SJason King 	}
207*4226f635SJason King 
208*4226f635SJason King 	(void) str_init(&res, n->nm_ops);
209*4226f635SJason King 
210*4226f635SJason King 	sp = name_at(n, amt - 1);
211*4226f635SJason King 	for (size_t i = 0; i < amt; i++) {
212*4226f635SJason King 		if (i > 0) {
213*4226f635SJason King 			if (!str_append(&res, sep, seplen))
214*4226f635SJason King 				goto error;
215*4226f635SJason King 		}
216*4226f635SJason King 
217*4226f635SJason King 		if (!str_append_str(&res, &sp->strp_l))
218*4226f635SJason King 			goto error;
219*4226f635SJason King 		if (!str_append_str(&res, &sp->strp_r))
220*4226f635SJason King 			goto error;
221*4226f635SJason King 
222*4226f635SJason King 		sp++;
223*4226f635SJason King 	}
224*4226f635SJason King 
225*4226f635SJason King 	for (size_t i = 0; i < amt; i++)
226*4226f635SJason King 		name_pop(n, NULL);
227*4226f635SJason King 
228*4226f635SJason King 	/* since we've removed at least 1 entry, this should always succeed */
229*4226f635SJason King 	VERIFY(name_add_str(n, &res, NULL));
230*4226f635SJason King 	return (B_TRUE);
231*4226f635SJason King 
232*4226f635SJason King error:
233*4226f635SJason King 	str_fini(&res);
234*4226f635SJason King 	return (B_FALSE);
235*4226f635SJason King }
236*4226f635SJason King 
237*4226f635SJason King static boolean_t
name_fmt_s(name_t * n,str_t * s,const char * fmt,long * maxp)238*4226f635SJason King name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
239*4226f635SJason King {
240*4226f635SJason King 	const char *p;
241*4226f635SJason King 	long max = -1;
242*4226f635SJason King 
243*4226f635SJason King 	if (fmt == NULL)
244*4226f635SJason King 		return (B_TRUE);
245*4226f635SJason King 
246*4226f635SJason King 	for (p = fmt; *p != '\0'; p++) {
247*4226f635SJason King 		if (*p != '{') {
248*4226f635SJason King 			(void) str_append_c(s, *p);
249*4226f635SJason King 			continue;
250*4226f635SJason King 		}
251*4226f635SJason King 
252*4226f635SJason King 		errno = 0;
253*4226f635SJason King 		char *q = NULL;
254*4226f635SJason King 		long val = strtol(p + 1, &q, 10);
255*4226f635SJason King 
256*4226f635SJason King 		VERIFY(val != 0 || errno == 0);
257*4226f635SJason King 		VERIFY3U(val, <, n->nm_len);
258*4226f635SJason King 
259*4226f635SJason King 		str_pair_t *sp = name_at(n, val);
260*4226f635SJason King 
261*4226f635SJason King 		if (val > max)
262*4226f635SJason King 			max = val;
263*4226f635SJason King 
264*4226f635SJason King 		switch (q[0]) {
265*4226f635SJason King 		case '}':
266*4226f635SJason King 			if (!str_append_str(s, &sp->strp_l))
267*4226f635SJason King 				return (B_FALSE);
268*4226f635SJason King 			if (!str_append_str(s, &sp->strp_r))
269*4226f635SJason King 				return (B_FALSE);
270*4226f635SJason King 			p = q;
271*4226f635SJason King 			continue;
272*4226f635SJason King 		case ':':
273*4226f635SJason King 			switch (q[1]) {
274*4226f635SJason King 			case 'L':
275*4226f635SJason King 				if (!str_append_str(s, &sp->strp_l))
276*4226f635SJason King 					return (B_FALSE);
277*4226f635SJason King 				break;
278*4226f635SJason King 			case 'R':
279*4226f635SJason King 				if (!str_append_str(s, &sp->strp_r))
280*4226f635SJason King 					return (B_FALSE);
281*4226f635SJason King 				break;
282*4226f635SJason King 			}
283*4226f635SJason King 
284*4226f635SJason King 			p = q + 2;
285*4226f635SJason King 			VERIFY(*p == '}');
286*4226f635SJason King 			break;
287*4226f635SJason King 		}
288*4226f635SJason King 	}
289*4226f635SJason King 
290*4226f635SJason King 	if (*maxp < max)
291*4226f635SJason King 		*maxp = max;
292*4226f635SJason King 
293*4226f635SJason King 	return (B_TRUE);
294*4226f635SJason King }
295*4226f635SJason King 
296*4226f635SJason King /*
297*4226f635SJason King  * Replace a number of elements in the name stack with a formatted string
298*4226f635SJason King  * for format is a plain string with optional {nnn} or {nnn:L|R} substitutions
299*4226f635SJason King  * where nnn is the stack position of an element and it's contents (both
300*4226f635SJason King  * left and right pieces) are inserted.  Optionally, only the left or
301*4226f635SJason King  * right piece can specified using :L|R e.g. {2:L}{3}{2:R} would insert
302*4226f635SJason King  * the left piece of element 2, all of element 3, then the right piece of
303*4226f635SJason King  * element 2.
304*4226f635SJason King  *
305*4226f635SJason King  * Once complete, all elements up to the deepest one references are popped
306*4226f635SJason King  * off the stack, and the resulting formatted string is pushed into n.
307*4226f635SJason King  *
308*4226f635SJason King  * This could be done as a sequence of push & pops, but this makes the
309*4226f635SJason King  * intended output far clearer to see.
310*4226f635SJason King  */
311*4226f635SJason King boolean_t
name_fmt(name_t * n,const char * fmt_l,const char * fmt_r)312*4226f635SJason King name_fmt(name_t *n, const char *fmt_l, const char *fmt_r)
313*4226f635SJason King {
314*4226f635SJason King 	str_pair_t res;
315*4226f635SJason King 	long max = -1;
316*4226f635SJason King 
317*4226f635SJason King 	(void) str_pair_init(&res, n->nm_ops);
318*4226f635SJason King 
319*4226f635SJason King 	if (!name_reserve(n, 1))
320*4226f635SJason King 		return (B_FALSE);
321*4226f635SJason King 
322*4226f635SJason King 	if (!name_fmt_s(n, &res.strp_l, fmt_l, &max))
323*4226f635SJason King 		goto error;
324*4226f635SJason King 	if (!name_fmt_s(n, &res.strp_r, fmt_r, &max))
325*4226f635SJason King 		goto error;
326*4226f635SJason King 
327*4226f635SJason King 	if (max >= 0) {
328*4226f635SJason King 		for (size_t i = 0; i <= max; i++)
329*4226f635SJason King 			name_pop(n, NULL);
330*4226f635SJason King 	}
331*4226f635SJason King 
332*4226f635SJason King 	n->nm_items[n->nm_len++] = res;
333*4226f635SJason King 	return (B_TRUE);
334*4226f635SJason King 
335*4226f635SJason King error:
336*4226f635SJason King 	str_pair_fini(&res);
337*4226f635SJason King 	return (B_FALSE);
338*4226f635SJason King }
339*4226f635SJason King 
340*4226f635SJason King /*
341*4226f635SJason King  * The substitution list is a list of name_t's that get added as the
342*4226f635SJason King  * demangled name is parsed.  Adding a name_t to the substitution list
343*4226f635SJason King  * is a copy operation, and likewise inserting a substitution into a name_t
344*4226f635SJason King  * is also a copy operation.
345*4226f635SJason King  */
346*4226f635SJason King void
sub_init(sub_t * sub,sysdem_ops_t * ops)347*4226f635SJason King sub_init(sub_t *sub, sysdem_ops_t *ops)
348*4226f635SJason King {
349*4226f635SJason King 	(void) memset(sub, 0, sizeof (*sub));
350*4226f635SJason King 	sub->sub_ops = (ops != NULL) ? ops : sysdem_ops_default;
351*4226f635SJason King }
352*4226f635SJason King 
353*4226f635SJason King void
sub_fini(sub_t * sub)354*4226f635SJason King sub_fini(sub_t *sub)
355*4226f635SJason King {
356*4226f635SJason King 	if (sub == NULL)
357*4226f635SJason King 		return;
358*4226f635SJason King 
359*4226f635SJason King 	sub_clear(sub);
360*4226f635SJason King 	xfree(sub->sub_ops, sub->sub_items, sub->sub_size);
361*4226f635SJason King 	sub->sub_items = NULL;
362*4226f635SJason King 	sub->sub_size = 0;
363*4226f635SJason King }
364*4226f635SJason King 
365*4226f635SJason King void
sub_clear(sub_t * sub)366*4226f635SJason King sub_clear(sub_t *sub)
367*4226f635SJason King {
368*4226f635SJason King 	if (sub == NULL)
369*4226f635SJason King 		return;
370*4226f635SJason King 
371*4226f635SJason King 	for (size_t i = 0; i < sub->sub_len; i++)
372*4226f635SJason King 		name_fini(&sub->sub_items[i]);
373*4226f635SJason King 
374*4226f635SJason King 	sub->sub_len = 0;
375*4226f635SJason King }
376*4226f635SJason King 
377*4226f635SJason King boolean_t
sub_empty(const sub_t * sub)378*4226f635SJason King sub_empty(const sub_t *sub)
379*4226f635SJason King {
380*4226f635SJason King 	return ((sub->sub_len == 0) ? B_TRUE : B_FALSE);
381*4226f635SJason King }
382*4226f635SJason King 
383*4226f635SJason King size_t
sub_len(const sub_t * sub)384*4226f635SJason King sub_len(const sub_t *sub)
385*4226f635SJason King {
386*4226f635SJason King 	return (sub->sub_len);
387*4226f635SJason King }
388*4226f635SJason King 
389*4226f635SJason King static boolean_t
sub_reserve(sub_t * sub,size_t amt)390*4226f635SJason King sub_reserve(sub_t *sub, size_t amt)
391*4226f635SJason King {
392*4226f635SJason King 	if (sub->sub_len + amt < sub->sub_size)
393*4226f635SJason King 		return (B_TRUE);
394*4226f635SJason King 
395*4226f635SJason King 	size_t newsize = roundup(sub->sub_size + amt, CHUNK_SIZE);
396*4226f635SJason King 	void *temp = xrealloc(sub->sub_ops, sub->sub_items,
397*4226f635SJason King 	    sub->sub_size * sizeof (name_t), newsize * sizeof (name_t));
398*4226f635SJason King 
399*4226f635SJason King 	if (temp == NULL)
400*4226f635SJason King 		return (B_FALSE);
401*4226f635SJason King 
402*4226f635SJason King 	sub->sub_items = temp;
403*4226f635SJason King 	sub->sub_size = newsize;
404*4226f635SJason King 
405*4226f635SJason King 	return (B_TRUE);
406*4226f635SJason King }
407*4226f635SJason King 
408*4226f635SJason King /* save the element of n (up to depth elements deep) as a substitution */
409*4226f635SJason King boolean_t
sub_save(sub_t * sub,const name_t * n,size_t depth)410*4226f635SJason King sub_save(sub_t *sub, const name_t *n, size_t depth)
411*4226f635SJason King {
412*4226f635SJason King 	if (depth == 0)
413*4226f635SJason King 		return (B_TRUE);
414*4226f635SJason King 
415*4226f635SJason King 	if (!sub_reserve(sub, 1))
416*4226f635SJason King 		return (B_FALSE);
417*4226f635SJason King 
418*4226f635SJason King 	name_t *dest = &sub->sub_items[sub->sub_len++];
419*4226f635SJason King 	name_init(dest, sub->sub_ops);
420*4226f635SJason King 
421*4226f635SJason King 	if (!name_reserve(dest, depth)) {
422*4226f635SJason King 		name_fini(dest);
423*4226f635SJason King 		sub->sub_len--;
424*4226f635SJason King 		return (B_FALSE);
425*4226f635SJason King 	}
426*4226f635SJason King 
427*4226f635SJason King 	const str_pair_t *src_sp = name_at(n, depth - 1);
428*4226f635SJason King 
429*4226f635SJason King 	for (size_t i = 0; i < depth; i++, src_sp++) {
430*4226f635SJason King 		str_pair_t copy = { 0 };
431*4226f635SJason King 		(void) str_pair_init(&copy, n->nm_ops);
432*4226f635SJason King 		if (!str_pair_copy(src_sp, &copy)) {
433*4226f635SJason King 			str_pair_fini(&copy);
434*4226f635SJason King 			name_fini(dest);
435*4226f635SJason King 			return (B_FALSE);
436*4226f635SJason King 		}
437*4226f635SJason King 
438*4226f635SJason King 		VERIFY(name_add_str(dest, &copy.strp_l, &copy.strp_r));
439*4226f635SJason King 	}
440*4226f635SJason King 
441*4226f635SJason King 	return (B_TRUE);
442*4226f635SJason King }
443*4226f635SJason King 
444*4226f635SJason King /* push substitution idx onto n */
445*4226f635SJason King boolean_t
sub_substitute(const sub_t * sub,size_t idx,name_t * n)446*4226f635SJason King sub_substitute(const sub_t *sub, size_t idx, name_t *n)
447*4226f635SJason King {
448*4226f635SJason King 	VERIFY3U(idx, <, sub->sub_len);
449*4226f635SJason King 
450*4226f635SJason King 	const name_t *src = &sub->sub_items[idx];
451*4226f635SJason King 	const str_pair_t *sp = src->nm_items;
452*4226f635SJason King 	size_t save = name_len(n);
453*4226f635SJason King 
454*4226f635SJason King 	for (size_t i = 0; i < src->nm_len; i++, sp++) {
455*4226f635SJason King 		str_pair_t copy = { 0 };
456*4226f635SJason King 
457*4226f635SJason King 		if (!str_pair_copy(sp, &copy))
458*4226f635SJason King 			goto fail;
459*4226f635SJason King 
460*4226f635SJason King 		if (!name_add_str(n, &copy.strp_l, &copy.strp_r))
461*4226f635SJason King 			goto fail;
462*4226f635SJason King 	}
463*4226f635SJason King 
464*4226f635SJason King 	return (B_TRUE);
465*4226f635SJason King 
466*4226f635SJason King fail:
467*4226f635SJason King 	for (size_t i = 0; i < name_len(n) - save; i++)
468*4226f635SJason King 		name_pop(n, NULL);
469*4226f635SJason King 	return (B_FALSE);
470*4226f635SJason King }
471*4226f635SJason King 
472*4226f635SJason King void
sub_pop(sub_t * sub)473*4226f635SJason King sub_pop(sub_t *sub)
474*4226f635SJason King {
475*4226f635SJason King 	name_t *top = &sub->sub_items[--sub->sub_len];
476*4226f635SJason King 	name_fini(top);
477*4226f635SJason King }
478*4226f635SJason King 
479*4226f635SJason King /*
480*4226f635SJason King  * Templates can use substitutions for it's arguments (using T instead of
481*4226f635SJason King  * S).  Since templates can nest however, each nesting requires a new
482*4226f635SJason King  * set of substitutions.  As such a new, empty list of template substitutions
483*4226f635SJason King  * is pushed onto cpp_templ each time templates are nested, and popped at
484*4226f635SJason King  * the end of the current template argument list.
485*4226f635SJason King  */
486*4226f635SJason King static boolean_t
templ_reserve(templ_t * tpl,size_t n)487*4226f635SJason King templ_reserve(templ_t *tpl, size_t n)
488*4226f635SJason King {
489*4226f635SJason King 	if (tpl->tpl_len + n < tpl->tpl_size)
490*4226f635SJason King 		return (B_TRUE);
491*4226f635SJason King 
492*4226f635SJason King 	size_t newsize = tpl->tpl_size + CHUNK_SIZE;
493*4226f635SJason King 	void *temp = xrealloc(tpl->tpl_ops, tpl->tpl_items,
494*4226f635SJason King 	    tpl->tpl_size * sizeof (sub_t), newsize * sizeof (sub_t));
495*4226f635SJason King 
496*4226f635SJason King 	if (temp == NULL)
497*4226f635SJason King 		return (B_FALSE);
498*4226f635SJason King 
499*4226f635SJason King 	tpl->tpl_items = temp;
500*4226f635SJason King 	tpl->tpl_size = newsize;
501*4226f635SJason King 	return (B_TRUE);
502*4226f635SJason King }
503*4226f635SJason King 
504*4226f635SJason King void
templ_init(templ_t * tpl,sysdem_ops_t * ops)505*4226f635SJason King templ_init(templ_t *tpl, sysdem_ops_t *ops)
506*4226f635SJason King {
507*4226f635SJason King 	(void) memset(tpl, 0, sizeof (*tpl));
508*4226f635SJason King 	tpl->tpl_ops = ops;
509*4226f635SJason King }
510*4226f635SJason King 
511*4226f635SJason King void
templ_fini(templ_t * tpl)512*4226f635SJason King templ_fini(templ_t *tpl)
513*4226f635SJason King {
514*4226f635SJason King 	if (tpl == NULL)
515*4226f635SJason King 		return;
516*4226f635SJason King 
517*4226f635SJason King 	for (size_t i = 0; i < tpl->tpl_len; i++)
518*4226f635SJason King 		sub_fini(&tpl->tpl_items[i]);
519*4226f635SJason King 
520*4226f635SJason King 	xfree(tpl->tpl_ops, tpl->tpl_items, tpl->tpl_size * sizeof (sub_t));
521*4226f635SJason King 	sysdem_ops_t *ops = tpl->tpl_ops;
522*4226f635SJason King 	(void) memset(tpl, 0, sizeof (*tpl));
523*4226f635SJason King 	tpl->tpl_ops = ops;
524*4226f635SJason King }
525*4226f635SJason King 
526*4226f635SJason King boolean_t
templ_push(templ_t * tpl)527*4226f635SJason King templ_push(templ_t *tpl)
528*4226f635SJason King {
529*4226f635SJason King 	if (!templ_reserve(tpl, 1))
530*4226f635SJason King 		return (B_FALSE);
531*4226f635SJason King 
532*4226f635SJason King 	sub_t *sub = &tpl->tpl_items[tpl->tpl_len++];
533*4226f635SJason King 	sub_init(sub, tpl->tpl_ops);
534*4226f635SJason King 	return (B_TRUE);
535*4226f635SJason King }
536*4226f635SJason King 
537*4226f635SJason King void
templ_pop(templ_t * tpl)538*4226f635SJason King templ_pop(templ_t *tpl)
539*4226f635SJason King {
540*4226f635SJason King 	VERIFY(!templ_empty(tpl));
541*4226f635SJason King 
542*4226f635SJason King 	sub_t *sub = &tpl->tpl_items[--tpl->tpl_len];
543*4226f635SJason King 	sub_fini(sub);
544*4226f635SJason King }
545*4226f635SJason King 
546*4226f635SJason King sub_t *
templ_top(templ_t * tpl)547*4226f635SJason King templ_top(templ_t *tpl)
548*4226f635SJason King {
549*4226f635SJason King 	if (tpl->tpl_len == 0)
550*4226f635SJason King 		return (NULL);
551*4226f635SJason King 	return (&tpl->tpl_items[tpl->tpl_len - 1]);
552*4226f635SJason King }
553*4226f635SJason King 
554*4226f635SJason King boolean_t
templ_empty(const templ_t * tpl)555*4226f635SJason King templ_empty(const templ_t *tpl)
556*4226f635SJason King {
557*4226f635SJason King 	return ((tpl->tpl_len == 0) ? B_TRUE : B_FALSE);
558*4226f635SJason King }
559*4226f635SJason King 
560*4226f635SJason King size_t
templ_top_len(const templ_t * tpl)561*4226f635SJason King templ_top_len(const templ_t *tpl)
562*4226f635SJason King {
563*4226f635SJason King 	const sub_t *sub = templ_top((templ_t *)tpl);
564*4226f635SJason King 
565*4226f635SJason King 	return (sub->sub_len);
566*4226f635SJason King }
567*4226f635SJason King 
568*4226f635SJason King boolean_t
templ_sub(const templ_t * tpl,size_t idx,name_t * n)569*4226f635SJason King templ_sub(const templ_t *tpl, size_t idx, name_t *n)
570*4226f635SJason King {
571*4226f635SJason King 	const sub_t *sub = templ_top((templ_t *)tpl);
572*4226f635SJason King 
573*4226f635SJason King 	return (sub_substitute(sub, idx, n));
574*4226f635SJason King }
575*4226f635SJason King 
576*4226f635SJason King boolean_t
templ_save(const name_t * n,size_t amt,templ_t * tpl)577*4226f635SJason King templ_save(const name_t *n, size_t amt, templ_t *tpl)
578*4226f635SJason King {
579*4226f635SJason King 	VERIFY3U(tpl->tpl_len, >, 0);
580*4226f635SJason King 
581*4226f635SJason King 	sub_t *s = templ_top(tpl);
582*4226f635SJason King 	boolean_t res = B_TRUE;
583*4226f635SJason King 
584*4226f635SJason King 	/* a bit of a hack -- want an 'empty' entry when saving 0 params */
585*4226f635SJason King 	if (amt == 0) {
586*4226f635SJason King 		name_t name = { 0 };
587*4226f635SJason King 
588*4226f635SJason King 		name_init(&name, tpl->tpl_ops);
589*4226f635SJason King 		res &= name_add(&name, "", 0, "", 0);
590*4226f635SJason King 		if (res)
591*4226f635SJason King 			res &= sub_save(s, &name, 1);
592*4226f635SJason King 		name_fini(&name);
593*4226f635SJason King 	} else {
594*4226f635SJason King 		res &= sub_save(s, n, amt);
595*4226f635SJason King 	}
596*4226f635SJason King 
597*4226f635SJason King 	return (res);
598*4226f635SJason King }
599