1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate 
6*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate /*
9*7c478bd9Sstevel@tonic-gate  * prof_tree.c --- these routines maintain the parse tree of the
10*7c478bd9Sstevel@tonic-gate  * 	config file.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  * All of the details of how the tree is stored is abstracted away in
13*7c478bd9Sstevel@tonic-gate  * this file; all of the other profile routines build, access, and
14*7c478bd9Sstevel@tonic-gate  * modify the tree via the accessor functions found in this file.
15*7c478bd9Sstevel@tonic-gate  *
16*7c478bd9Sstevel@tonic-gate  * Each node may represent either a relation or a section header.
17*7c478bd9Sstevel@tonic-gate  *
18*7c478bd9Sstevel@tonic-gate  * A section header must have its value field set to 0, and may a one
19*7c478bd9Sstevel@tonic-gate  * or more child nodes, pointed to by first_child.
20*7c478bd9Sstevel@tonic-gate  *
21*7c478bd9Sstevel@tonic-gate  * A relation has as its value a pointer to allocated memory
22*7c478bd9Sstevel@tonic-gate  * containing a string.  Its first_child pointer must be null.
23*7c478bd9Sstevel@tonic-gate  *
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #include <stdio.h>
27*7c478bd9Sstevel@tonic-gate #include <string.h>
28*7c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H
29*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
30*7c478bd9Sstevel@tonic-gate #endif
31*7c478bd9Sstevel@tonic-gate #include <errno.h>
32*7c478bd9Sstevel@tonic-gate #include <ctype.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "prof_int.h"
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate struct profile_node {
37*7c478bd9Sstevel@tonic-gate 	errcode_t	magic;
38*7c478bd9Sstevel@tonic-gate 	char *name;
39*7c478bd9Sstevel@tonic-gate 	char *value;
40*7c478bd9Sstevel@tonic-gate 	int group_level;
41*7c478bd9Sstevel@tonic-gate 	int final:1;		/* Indicate don't search next file */
42*7c478bd9Sstevel@tonic-gate 	struct profile_node *first_child;
43*7c478bd9Sstevel@tonic-gate 	struct profile_node *parent;
44*7c478bd9Sstevel@tonic-gate 	struct profile_node *next, *prev;
45*7c478bd9Sstevel@tonic-gate };
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #define CHECK_MAGIC(node) \
48*7c478bd9Sstevel@tonic-gate 	  if ((node)->magic != PROF_MAGIC_NODE) \
49*7c478bd9Sstevel@tonic-gate 		  return PROF_MAGIC_NODE;
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * Free a node, and any children
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate void profile_free_node(node)
55*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	struct profile_node *child, *next;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 	if (node->magic != PROF_MAGIC_NODE)
60*7c478bd9Sstevel@tonic-gate 		return;
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	if (node->name)
63*7c478bd9Sstevel@tonic-gate 		free(node->name);
64*7c478bd9Sstevel@tonic-gate 	if (node->value)
65*7c478bd9Sstevel@tonic-gate 		free(node->value);
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	for (child=node->first_child; child; child = next) {
68*7c478bd9Sstevel@tonic-gate 		next = child->next;
69*7c478bd9Sstevel@tonic-gate 		profile_free_node(child);
70*7c478bd9Sstevel@tonic-gate 	}
71*7c478bd9Sstevel@tonic-gate 	node->magic = 0;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 	free(node);
74*7c478bd9Sstevel@tonic-gate }
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * Create a node
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate errcode_t profile_create_node(name, value, ret_node)
80*7c478bd9Sstevel@tonic-gate 	const char *name, *value;
81*7c478bd9Sstevel@tonic-gate 	struct profile_node **ret_node;
82*7c478bd9Sstevel@tonic-gate {
83*7c478bd9Sstevel@tonic-gate 	struct profile_node *new;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	new = (struct profile_node *)malloc(sizeof(struct profile_node));
86*7c478bd9Sstevel@tonic-gate 	if (!new)
87*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
88*7c478bd9Sstevel@tonic-gate 	memset(new, 0, sizeof(struct profile_node));
89*7c478bd9Sstevel@tonic-gate 	new->name = (char *) malloc(strlen(name)+1);
90*7c478bd9Sstevel@tonic-gate 	if (new->name == 0) {
91*7c478bd9Sstevel@tonic-gate 		profile_free_node(new);
92*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
93*7c478bd9Sstevel@tonic-gate 	}
94*7c478bd9Sstevel@tonic-gate 	strcpy(new->name, name);
95*7c478bd9Sstevel@tonic-gate 	if (value) {
96*7c478bd9Sstevel@tonic-gate 		new->value = (char *) malloc(strlen(value)+1);
97*7c478bd9Sstevel@tonic-gate 		if (new->value == 0) {
98*7c478bd9Sstevel@tonic-gate 			profile_free_node(new);
99*7c478bd9Sstevel@tonic-gate 			return ENOMEM;
100*7c478bd9Sstevel@tonic-gate 		}
101*7c478bd9Sstevel@tonic-gate 		strcpy(new->value, value);
102*7c478bd9Sstevel@tonic-gate 	}
103*7c478bd9Sstevel@tonic-gate 	new->magic = PROF_MAGIC_NODE;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	*ret_node = new;
106*7c478bd9Sstevel@tonic-gate 	return 0;
107*7c478bd9Sstevel@tonic-gate }
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /*
110*7c478bd9Sstevel@tonic-gate  * This function verifies that all of the representation invarients of
111*7c478bd9Sstevel@tonic-gate  * the profile are true.  If not, we have a programming bug somewhere,
112*7c478bd9Sstevel@tonic-gate  * probably in this file.
113*7c478bd9Sstevel@tonic-gate  */
114*7c478bd9Sstevel@tonic-gate errcode_t profile_verify_node(node)
115*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
116*7c478bd9Sstevel@tonic-gate {
117*7c478bd9Sstevel@tonic-gate 	struct profile_node *p, *last;
118*7c478bd9Sstevel@tonic-gate 	errcode_t	retval;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(node);
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	if (node->value && node->first_child)
123*7c478bd9Sstevel@tonic-gate 		return PROF_SECTION_WITH_VALUE;
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	last = 0;
126*7c478bd9Sstevel@tonic-gate 	for (p = node->first_child; p; last = p, p = p->next) {
127*7c478bd9Sstevel@tonic-gate 		if (p->prev != last)
128*7c478bd9Sstevel@tonic-gate 			return PROF_BAD_LINK_LIST;
129*7c478bd9Sstevel@tonic-gate 		if (last && (last->next != p))
130*7c478bd9Sstevel@tonic-gate 			return PROF_BAD_LINK_LIST;
131*7c478bd9Sstevel@tonic-gate 		if (node->group_level+1 != p->group_level)
132*7c478bd9Sstevel@tonic-gate 			return PROF_BAD_GROUP_LVL;
133*7c478bd9Sstevel@tonic-gate 		if (p->parent != node)
134*7c478bd9Sstevel@tonic-gate 			return PROF_BAD_PARENT_PTR;
135*7c478bd9Sstevel@tonic-gate 		retval = profile_verify_node(p);
136*7c478bd9Sstevel@tonic-gate 		if (retval)
137*7c478bd9Sstevel@tonic-gate 			return retval;
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate 	return 0;
140*7c478bd9Sstevel@tonic-gate }
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate /*
143*7c478bd9Sstevel@tonic-gate  * Add a node to a particular section
144*7c478bd9Sstevel@tonic-gate  */
145*7c478bd9Sstevel@tonic-gate errcode_t profile_add_node(section, name, value, ret_node)
146*7c478bd9Sstevel@tonic-gate 	struct profile_node *section;
147*7c478bd9Sstevel@tonic-gate 	const char *name, *value;
148*7c478bd9Sstevel@tonic-gate 	struct profile_node **ret_node;
149*7c478bd9Sstevel@tonic-gate {
150*7c478bd9Sstevel@tonic-gate 	errcode_t retval;
151*7c478bd9Sstevel@tonic-gate 	struct profile_node *p, *last, *new;
152*7c478bd9Sstevel@tonic-gate 	int	cmp = -1;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(section);
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	if (section->value)
157*7c478bd9Sstevel@tonic-gate 		return PROF_ADD_NOT_SECTION;
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate 	/*
160*7c478bd9Sstevel@tonic-gate 	 * Find the place to insert the new node.  We look for the
161*7c478bd9Sstevel@tonic-gate 	 * place *after* the last match of the node name, since
162*7c478bd9Sstevel@tonic-gate 	 * order matters.
163*7c478bd9Sstevel@tonic-gate 	 */
164*7c478bd9Sstevel@tonic-gate 	for (p=section->first_child, last = 0; p; last = p, p = p->next) {
165*7c478bd9Sstevel@tonic-gate 		cmp = strcmp(p->name, name);
166*7c478bd9Sstevel@tonic-gate 		if (cmp > 0)
167*7c478bd9Sstevel@tonic-gate 			break;
168*7c478bd9Sstevel@tonic-gate 	}
169*7c478bd9Sstevel@tonic-gate 	retval = profile_create_node(name, value, &new);
170*7c478bd9Sstevel@tonic-gate 	if (retval)
171*7c478bd9Sstevel@tonic-gate 		return retval;
172*7c478bd9Sstevel@tonic-gate 	new->group_level = section->group_level+1;
173*7c478bd9Sstevel@tonic-gate 	new->parent = section;
174*7c478bd9Sstevel@tonic-gate 	new->prev = last;
175*7c478bd9Sstevel@tonic-gate 	new->next = p;
176*7c478bd9Sstevel@tonic-gate 	if (p)
177*7c478bd9Sstevel@tonic-gate 		p->prev = new;
178*7c478bd9Sstevel@tonic-gate 	if (last)
179*7c478bd9Sstevel@tonic-gate 		last->next = new;
180*7c478bd9Sstevel@tonic-gate 	else
181*7c478bd9Sstevel@tonic-gate 		section->first_child = new;
182*7c478bd9Sstevel@tonic-gate 	if (ret_node)
183*7c478bd9Sstevel@tonic-gate 		*ret_node = new;
184*7c478bd9Sstevel@tonic-gate 	return 0;
185*7c478bd9Sstevel@tonic-gate }
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate /*
188*7c478bd9Sstevel@tonic-gate  * Set the final flag on a particular node.
189*7c478bd9Sstevel@tonic-gate  */
190*7c478bd9Sstevel@tonic-gate errcode_t profile_make_node_final(node)
191*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
192*7c478bd9Sstevel@tonic-gate {
193*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(node);
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	node->final = 1;
196*7c478bd9Sstevel@tonic-gate 	return 0;
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate  * Check the final flag on a node
201*7c478bd9Sstevel@tonic-gate  */
202*7c478bd9Sstevel@tonic-gate int profile_is_node_final(node)
203*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
204*7c478bd9Sstevel@tonic-gate {
205*7c478bd9Sstevel@tonic-gate 	return (node->final != 0);
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate /*
209*7c478bd9Sstevel@tonic-gate  * Return the name of a node.  (Note: this is for internal functions
210*7c478bd9Sstevel@tonic-gate  * only; if the name needs to be returned from an exported function,
211*7c478bd9Sstevel@tonic-gate  * strdup it first!)
212*7c478bd9Sstevel@tonic-gate  */
213*7c478bd9Sstevel@tonic-gate const char *profile_get_node_name(node)
214*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
215*7c478bd9Sstevel@tonic-gate {
216*7c478bd9Sstevel@tonic-gate 	return node->name;
217*7c478bd9Sstevel@tonic-gate }
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate /*
220*7c478bd9Sstevel@tonic-gate  * Return the value of a node.  (Note: this is for internal functions
221*7c478bd9Sstevel@tonic-gate  * only; if the name needs to be returned from an exported function,
222*7c478bd9Sstevel@tonic-gate  * strdup it first!)
223*7c478bd9Sstevel@tonic-gate  */
224*7c478bd9Sstevel@tonic-gate const char *profile_get_node_value(node)
225*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
226*7c478bd9Sstevel@tonic-gate {
227*7c478bd9Sstevel@tonic-gate 	return node->value;
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate /*
231*7c478bd9Sstevel@tonic-gate  * Iterate through the section, returning the nodes which match
232*7c478bd9Sstevel@tonic-gate  * the given name.  If name is NULL, then interate through all the
233*7c478bd9Sstevel@tonic-gate  * nodes in the section.  If section_flag is non-zero, only return the
234*7c478bd9Sstevel@tonic-gate  * section which matches the name; don't return relations.  If value
235*7c478bd9Sstevel@tonic-gate  * is non-NULL, then only return relations which match the requested
236*7c478bd9Sstevel@tonic-gate  * value.  (The value argument is ignored if section_flag is non-zero.)
237*7c478bd9Sstevel@tonic-gate  *
238*7c478bd9Sstevel@tonic-gate  * The first time this routine is called, the state pointer must be
239*7c478bd9Sstevel@tonic-gate  * null.  When this profile_find_node_relation() returns, if the state
240*7c478bd9Sstevel@tonic-gate  * pointer is non-NULL, then this routine should be called again.
241*7c478bd9Sstevel@tonic-gate  * (This won't happen if section_flag is non-zero, obviously.)
242*7c478bd9Sstevel@tonic-gate  *
243*7c478bd9Sstevel@tonic-gate  */
244*7c478bd9Sstevel@tonic-gate errcode_t profile_find_node(section, name, value, section_flag, state, node)
245*7c478bd9Sstevel@tonic-gate 	struct profile_node *section;
246*7c478bd9Sstevel@tonic-gate 	const char *name;
247*7c478bd9Sstevel@tonic-gate 	const char *value;
248*7c478bd9Sstevel@tonic-gate 	int section_flag;
249*7c478bd9Sstevel@tonic-gate 	void **state;
250*7c478bd9Sstevel@tonic-gate 	struct profile_node **node;
251*7c478bd9Sstevel@tonic-gate {
252*7c478bd9Sstevel@tonic-gate 	struct profile_node *p;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(section);
255*7c478bd9Sstevel@tonic-gate 	p = *state;
256*7c478bd9Sstevel@tonic-gate 	if (p) {
257*7c478bd9Sstevel@tonic-gate 		CHECK_MAGIC(p);
258*7c478bd9Sstevel@tonic-gate 	} else
259*7c478bd9Sstevel@tonic-gate 		p = section->first_child;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	for (; p; p = p->next) {
262*7c478bd9Sstevel@tonic-gate 		if (name && (strcmp(p->name, name)))
263*7c478bd9Sstevel@tonic-gate 			continue;
264*7c478bd9Sstevel@tonic-gate 		if (section_flag) {
265*7c478bd9Sstevel@tonic-gate 			if (p->value)
266*7c478bd9Sstevel@tonic-gate 				continue;
267*7c478bd9Sstevel@tonic-gate 		} else {
268*7c478bd9Sstevel@tonic-gate 			if (!p->value)
269*7c478bd9Sstevel@tonic-gate 				continue;
270*7c478bd9Sstevel@tonic-gate 			if (value && (strcmp(p->value, value)))
271*7c478bd9Sstevel@tonic-gate 				continue;
272*7c478bd9Sstevel@tonic-gate 		}
273*7c478bd9Sstevel@tonic-gate 		/* A match! */
274*7c478bd9Sstevel@tonic-gate 		if (node)
275*7c478bd9Sstevel@tonic-gate 			*node = p;
276*7c478bd9Sstevel@tonic-gate 		break;
277*7c478bd9Sstevel@tonic-gate 	}
278*7c478bd9Sstevel@tonic-gate 	if (p == 0) {
279*7c478bd9Sstevel@tonic-gate 		*state = 0;
280*7c478bd9Sstevel@tonic-gate 		return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION;
281*7c478bd9Sstevel@tonic-gate 	}
282*7c478bd9Sstevel@tonic-gate 	/*
283*7c478bd9Sstevel@tonic-gate 	 * OK, we've found one match; now let's try to find another
284*7c478bd9Sstevel@tonic-gate 	 * one.  This way, if we return a non-zero state pointer,
285*7c478bd9Sstevel@tonic-gate 	 * there's guaranteed to be another match that's returned.
286*7c478bd9Sstevel@tonic-gate 	 */
287*7c478bd9Sstevel@tonic-gate 	for (p = p->next; p; p = p->next) {
288*7c478bd9Sstevel@tonic-gate 		if (name && (strcmp(p->name, name)))
289*7c478bd9Sstevel@tonic-gate 			continue;
290*7c478bd9Sstevel@tonic-gate 		if (section_flag) {
291*7c478bd9Sstevel@tonic-gate 			if (p->value)
292*7c478bd9Sstevel@tonic-gate 				continue;
293*7c478bd9Sstevel@tonic-gate 		} else {
294*7c478bd9Sstevel@tonic-gate 			if (!p->value)
295*7c478bd9Sstevel@tonic-gate 				continue;
296*7c478bd9Sstevel@tonic-gate 			if (value && (strcmp(p->value, value)))
297*7c478bd9Sstevel@tonic-gate 				continue;
298*7c478bd9Sstevel@tonic-gate 		}
299*7c478bd9Sstevel@tonic-gate 		/* A match! */
300*7c478bd9Sstevel@tonic-gate 		break;
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 	*state = p;
303*7c478bd9Sstevel@tonic-gate 	return 0;
304*7c478bd9Sstevel@tonic-gate }
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate /*
308*7c478bd9Sstevel@tonic-gate  * Iterate through the section, returning the relations which match
309*7c478bd9Sstevel@tonic-gate  * the given name.  If name is NULL, then interate through all the
310*7c478bd9Sstevel@tonic-gate  * relations in the section.  The first time this routine is called,
311*7c478bd9Sstevel@tonic-gate  * the state pointer must be null.  When this profile_find_node_relation()
312*7c478bd9Sstevel@tonic-gate  * returns, if the state pointer is non-NULL, then this routine should
313*7c478bd9Sstevel@tonic-gate  * be called again.
314*7c478bd9Sstevel@tonic-gate  *
315*7c478bd9Sstevel@tonic-gate  * The returned character string in value points to the stored
316*7c478bd9Sstevel@tonic-gate  * character string in the parse string.  Before this string value is
317*7c478bd9Sstevel@tonic-gate  * returned to a calling application (profile_find_node_relation is not an
318*7c478bd9Sstevel@tonic-gate  * exported interface), it should be strdup()'ed.
319*7c478bd9Sstevel@tonic-gate  */
320*7c478bd9Sstevel@tonic-gate errcode_t profile_find_node_relation(section, name, state, ret_name, value)
321*7c478bd9Sstevel@tonic-gate 	struct profile_node *section;
322*7c478bd9Sstevel@tonic-gate 	const char *name;
323*7c478bd9Sstevel@tonic-gate 	void **state;
324*7c478bd9Sstevel@tonic-gate 	char **ret_name, **value;
325*7c478bd9Sstevel@tonic-gate {
326*7c478bd9Sstevel@tonic-gate 	struct profile_node *p;
327*7c478bd9Sstevel@tonic-gate 	errcode_t	retval;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	retval = profile_find_node(section, name, 0, 0, state, &p);
330*7c478bd9Sstevel@tonic-gate 	if (retval)
331*7c478bd9Sstevel@tonic-gate 		return retval;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	if (p) {
334*7c478bd9Sstevel@tonic-gate 		if (value)
335*7c478bd9Sstevel@tonic-gate 			*value = p->value;
336*7c478bd9Sstevel@tonic-gate 		if (ret_name)
337*7c478bd9Sstevel@tonic-gate 			*ret_name = p->name;
338*7c478bd9Sstevel@tonic-gate 	}
339*7c478bd9Sstevel@tonic-gate 	return 0;
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate /*
343*7c478bd9Sstevel@tonic-gate  * Iterate through the section, returning the subsections which match
344*7c478bd9Sstevel@tonic-gate  * the given name.  If name is NULL, then interate through all the
345*7c478bd9Sstevel@tonic-gate  * subsections in the section.  The first time this routine is called,
346*7c478bd9Sstevel@tonic-gate  * the state pointer must be null.  When this profile_find_node_subsection()
347*7c478bd9Sstevel@tonic-gate  * returns, if the state pointer is non-NULL, then this routine should
348*7c478bd9Sstevel@tonic-gate  * be called again.
349*7c478bd9Sstevel@tonic-gate  *
350*7c478bd9Sstevel@tonic-gate  * This is (plus accessor functions for the name and value given a
351*7c478bd9Sstevel@tonic-gate  * profile node) makes this function mostly syntactic sugar for
352*7c478bd9Sstevel@tonic-gate  * profile_find_node.
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate errcode_t profile_find_node_subsection(section, name, state, ret_name,
355*7c478bd9Sstevel@tonic-gate 				       subsection)
356*7c478bd9Sstevel@tonic-gate 	struct profile_node *section;
357*7c478bd9Sstevel@tonic-gate 	const char *name;
358*7c478bd9Sstevel@tonic-gate 	void **state;
359*7c478bd9Sstevel@tonic-gate 	char **ret_name;
360*7c478bd9Sstevel@tonic-gate 	struct profile_node **subsection;
361*7c478bd9Sstevel@tonic-gate {
362*7c478bd9Sstevel@tonic-gate 	struct profile_node *p;
363*7c478bd9Sstevel@tonic-gate 	errcode_t	retval;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	if (section == (struct profile_node *)NULL)
366*7c478bd9Sstevel@tonic-gate 		return (PROF_NO_PROFILE);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	retval = profile_find_node(section, name, 0, 1, state, &p);
369*7c478bd9Sstevel@tonic-gate 	if (retval)
370*7c478bd9Sstevel@tonic-gate 		return retval;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	if (p) {
373*7c478bd9Sstevel@tonic-gate 		if (subsection)
374*7c478bd9Sstevel@tonic-gate 			*subsection = p;
375*7c478bd9Sstevel@tonic-gate 		if (ret_name)
376*7c478bd9Sstevel@tonic-gate 			*ret_name = p->name;
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 	return 0;
379*7c478bd9Sstevel@tonic-gate }
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate /*
382*7c478bd9Sstevel@tonic-gate  * This function returns the parent of a particular node.
383*7c478bd9Sstevel@tonic-gate  */
384*7c478bd9Sstevel@tonic-gate errcode_t profile_get_node_parent(section, parent)
385*7c478bd9Sstevel@tonic-gate 	struct profile_node *section, **parent;
386*7c478bd9Sstevel@tonic-gate {
387*7c478bd9Sstevel@tonic-gate 	*parent = section->parent;
388*7c478bd9Sstevel@tonic-gate 	return 0;
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate /*
392*7c478bd9Sstevel@tonic-gate  * This is a general-purpose iterator for returning all nodes that
393*7c478bd9Sstevel@tonic-gate  * match the specified name array.
394*7c478bd9Sstevel@tonic-gate  */
395*7c478bd9Sstevel@tonic-gate struct profile_iterator {
396*7c478bd9Sstevel@tonic-gate 	prf_magic_t		magic;
397*7c478bd9Sstevel@tonic-gate 	profile_t		profile;
398*7c478bd9Sstevel@tonic-gate 	int			flags;
399*7c478bd9Sstevel@tonic-gate 	const char 		**names;
400*7c478bd9Sstevel@tonic-gate 	const char		*name;
401*7c478bd9Sstevel@tonic-gate 	prf_file_t		file;
402*7c478bd9Sstevel@tonic-gate 	int			file_serial;
403*7c478bd9Sstevel@tonic-gate 	int			done_idx;
404*7c478bd9Sstevel@tonic-gate 	struct profile_node 	*node;
405*7c478bd9Sstevel@tonic-gate 	int			num;
406*7c478bd9Sstevel@tonic-gate };
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate errcode_t profile_node_iterator_create(profile, names, flags, ret_iter)
409*7c478bd9Sstevel@tonic-gate 	profile_t	profile;
410*7c478bd9Sstevel@tonic-gate 	const char	**names;
411*7c478bd9Sstevel@tonic-gate 	int		flags;
412*7c478bd9Sstevel@tonic-gate 	void		**ret_iter;
413*7c478bd9Sstevel@tonic-gate {
414*7c478bd9Sstevel@tonic-gate 	struct profile_iterator *iter;
415*7c478bd9Sstevel@tonic-gate 	int	done_idx = 0;
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	if (profile == 0)
418*7c478bd9Sstevel@tonic-gate 		return PROF_NO_PROFILE;
419*7c478bd9Sstevel@tonic-gate 	if (profile->magic != PROF_MAGIC_PROFILE)
420*7c478bd9Sstevel@tonic-gate 		return PROF_MAGIC_PROFILE;
421*7c478bd9Sstevel@tonic-gate 	if (!names)
422*7c478bd9Sstevel@tonic-gate 		return PROF_BAD_NAMESET;
423*7c478bd9Sstevel@tonic-gate 	if (!(flags & PROFILE_ITER_LIST_SECTION)) {
424*7c478bd9Sstevel@tonic-gate 		if (!names[0])
425*7c478bd9Sstevel@tonic-gate 			return PROF_BAD_NAMESET;
426*7c478bd9Sstevel@tonic-gate 		done_idx = 1;
427*7c478bd9Sstevel@tonic-gate 	}
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 	if ((iter = (struct profile_iterator *)
430*7c478bd9Sstevel@tonic-gate 		malloc(sizeof(struct profile_iterator))) == NULL)
431*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	iter->magic = PROF_MAGIC_ITERATOR;
434*7c478bd9Sstevel@tonic-gate 	iter->profile = profile;
435*7c478bd9Sstevel@tonic-gate 	iter->names = names;
436*7c478bd9Sstevel@tonic-gate 	iter->flags = flags;
437*7c478bd9Sstevel@tonic-gate 	iter->file = profile->first_file;
438*7c478bd9Sstevel@tonic-gate 	iter->done_idx = done_idx;
439*7c478bd9Sstevel@tonic-gate 	iter->node = 0;
440*7c478bd9Sstevel@tonic-gate 	iter->num = 0;
441*7c478bd9Sstevel@tonic-gate 	*ret_iter = iter;
442*7c478bd9Sstevel@tonic-gate 	return 0;
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate void profile_node_iterator_free(iter_p)
446*7c478bd9Sstevel@tonic-gate 	void	**iter_p;
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate 	struct profile_iterator *iter;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (!iter_p)
451*7c478bd9Sstevel@tonic-gate 		return;
452*7c478bd9Sstevel@tonic-gate 	iter = *iter_p;
453*7c478bd9Sstevel@tonic-gate 	if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
454*7c478bd9Sstevel@tonic-gate 		return;
455*7c478bd9Sstevel@tonic-gate 	free(iter);
456*7c478bd9Sstevel@tonic-gate 	*iter_p = 0;
457*7c478bd9Sstevel@tonic-gate }
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate /*
460*7c478bd9Sstevel@tonic-gate  * Note: the returned character strings in ret_name and ret_value
461*7c478bd9Sstevel@tonic-gate  * points to the stored character string in the parse string.  Before
462*7c478bd9Sstevel@tonic-gate  * this string value is returned to a calling application
463*7c478bd9Sstevel@tonic-gate  * (profile_node_iterator is not an exported interface), it should be
464*7c478bd9Sstevel@tonic-gate  * strdup()'ed.
465*7c478bd9Sstevel@tonic-gate  */
466*7c478bd9Sstevel@tonic-gate errcode_t profile_node_iterator(iter_p, ret_node, ret_name, ret_value)
467*7c478bd9Sstevel@tonic-gate 	void	**iter_p;
468*7c478bd9Sstevel@tonic-gate 	struct profile_node	**ret_node;
469*7c478bd9Sstevel@tonic-gate 	char **ret_name, **ret_value;
470*7c478bd9Sstevel@tonic-gate {
471*7c478bd9Sstevel@tonic-gate 	struct profile_iterator 	*iter = *iter_p;
472*7c478bd9Sstevel@tonic-gate 	struct profile_node 		*section, *p;
473*7c478bd9Sstevel@tonic-gate 	const char			**cpp;
474*7c478bd9Sstevel@tonic-gate 	errcode_t			retval;
475*7c478bd9Sstevel@tonic-gate 	int				skip_num = 0;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (!iter || iter->magic != PROF_MAGIC_ITERATOR)
478*7c478bd9Sstevel@tonic-gate 		return PROF_MAGIC_ITERATOR;
479*7c478bd9Sstevel@tonic-gate 	/*
480*7c478bd9Sstevel@tonic-gate 	 * If the file has changed, then the node pointer is invalid,
481*7c478bd9Sstevel@tonic-gate 	 * so we'll have search the file again looking for it.
482*7c478bd9Sstevel@tonic-gate 	 */
483*7c478bd9Sstevel@tonic-gate 	if (iter->node && (iter->file->upd_serial != iter->file_serial)) {
484*7c478bd9Sstevel@tonic-gate 		iter->flags &= ~PROFILE_ITER_FINAL_SEEN;
485*7c478bd9Sstevel@tonic-gate 		skip_num = iter->num;
486*7c478bd9Sstevel@tonic-gate 		iter->node = 0;
487*7c478bd9Sstevel@tonic-gate 	}
488*7c478bd9Sstevel@tonic-gate get_new_file:
489*7c478bd9Sstevel@tonic-gate 	if (iter->node == 0) {
490*7c478bd9Sstevel@tonic-gate 		if (iter->file == 0 ||
491*7c478bd9Sstevel@tonic-gate 		    (iter->flags & PROFILE_ITER_FINAL_SEEN)) {
492*7c478bd9Sstevel@tonic-gate 			profile_node_iterator_free(iter_p);
493*7c478bd9Sstevel@tonic-gate 			if (ret_node)
494*7c478bd9Sstevel@tonic-gate 				*ret_node = 0;
495*7c478bd9Sstevel@tonic-gate 			if (ret_name)
496*7c478bd9Sstevel@tonic-gate 				*ret_name = 0;
497*7c478bd9Sstevel@tonic-gate 			if (ret_value)
498*7c478bd9Sstevel@tonic-gate 				*ret_value =0;
499*7c478bd9Sstevel@tonic-gate 			return 0;
500*7c478bd9Sstevel@tonic-gate 		}
501*7c478bd9Sstevel@tonic-gate 		if ((retval = profile_update_file(iter->file))) {
502*7c478bd9Sstevel@tonic-gate 			profile_node_iterator_free(iter_p);
503*7c478bd9Sstevel@tonic-gate 			return retval;
504*7c478bd9Sstevel@tonic-gate 		}
505*7c478bd9Sstevel@tonic-gate 		iter->file_serial = iter->file->upd_serial;
506*7c478bd9Sstevel@tonic-gate 		/*
507*7c478bd9Sstevel@tonic-gate 		 * Find the section to list if we are a LIST_SECTION,
508*7c478bd9Sstevel@tonic-gate 		 * or find the containing section if not.
509*7c478bd9Sstevel@tonic-gate 		 */
510*7c478bd9Sstevel@tonic-gate 		section = iter->file->root;
511*7c478bd9Sstevel@tonic-gate 		for (cpp = iter->names; cpp[iter->done_idx]; cpp++) {
512*7c478bd9Sstevel@tonic-gate 			for (p=section->first_child; p; p = p->next)
513*7c478bd9Sstevel@tonic-gate 				if (!strcmp(p->name, *cpp) && !p->value)
514*7c478bd9Sstevel@tonic-gate 					break;
515*7c478bd9Sstevel@tonic-gate 			if (!p) {
516*7c478bd9Sstevel@tonic-gate 				section = 0;
517*7c478bd9Sstevel@tonic-gate 				break;
518*7c478bd9Sstevel@tonic-gate 			}
519*7c478bd9Sstevel@tonic-gate 			section = p;
520*7c478bd9Sstevel@tonic-gate 			if (p->final)
521*7c478bd9Sstevel@tonic-gate 				iter->flags |= PROFILE_ITER_FINAL_SEEN;
522*7c478bd9Sstevel@tonic-gate 		}
523*7c478bd9Sstevel@tonic-gate 		if (!section) {
524*7c478bd9Sstevel@tonic-gate 			iter->file = iter->file->next;
525*7c478bd9Sstevel@tonic-gate 			skip_num = 0;
526*7c478bd9Sstevel@tonic-gate 			goto get_new_file;
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		iter->name = *cpp;
529*7c478bd9Sstevel@tonic-gate 		iter->node = section->first_child;
530*7c478bd9Sstevel@tonic-gate 	}
531*7c478bd9Sstevel@tonic-gate 	/*
532*7c478bd9Sstevel@tonic-gate 	 * OK, now we know iter->node is set up correctly.  Let's do
533*7c478bd9Sstevel@tonic-gate 	 * the search.
534*7c478bd9Sstevel@tonic-gate 	 */
535*7c478bd9Sstevel@tonic-gate 	for (p = iter->node; p; p = p->next) {
536*7c478bd9Sstevel@tonic-gate 		if (iter->name && strcmp(p->name, iter->name))
537*7c478bd9Sstevel@tonic-gate 			continue;
538*7c478bd9Sstevel@tonic-gate 		if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) &&
539*7c478bd9Sstevel@tonic-gate 		    p->value)
540*7c478bd9Sstevel@tonic-gate 			continue;
541*7c478bd9Sstevel@tonic-gate 		if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) &&
542*7c478bd9Sstevel@tonic-gate 		    !p->value)
543*7c478bd9Sstevel@tonic-gate 			continue;
544*7c478bd9Sstevel@tonic-gate 		if (skip_num > 0) {
545*7c478bd9Sstevel@tonic-gate 			skip_num--;
546*7c478bd9Sstevel@tonic-gate 			continue;
547*7c478bd9Sstevel@tonic-gate 		}
548*7c478bd9Sstevel@tonic-gate 		break;
549*7c478bd9Sstevel@tonic-gate 	}
550*7c478bd9Sstevel@tonic-gate 	iter->num++;
551*7c478bd9Sstevel@tonic-gate 	if (!p) {
552*7c478bd9Sstevel@tonic-gate 		iter->file = iter->file->next;
553*7c478bd9Sstevel@tonic-gate 		iter->node = 0;
554*7c478bd9Sstevel@tonic-gate 		skip_num = 0;
555*7c478bd9Sstevel@tonic-gate 		goto get_new_file;
556*7c478bd9Sstevel@tonic-gate 	}
557*7c478bd9Sstevel@tonic-gate 	if ((iter->node = p->next) == NULL)
558*7c478bd9Sstevel@tonic-gate 		iter->file = iter->file->next;
559*7c478bd9Sstevel@tonic-gate 	if (ret_node)
560*7c478bd9Sstevel@tonic-gate 		*ret_node = p;
561*7c478bd9Sstevel@tonic-gate 	if (ret_name)
562*7c478bd9Sstevel@tonic-gate 		*ret_name = p->name;
563*7c478bd9Sstevel@tonic-gate 	if (ret_value)
564*7c478bd9Sstevel@tonic-gate 		*ret_value = p->value;
565*7c478bd9Sstevel@tonic-gate 	return 0;
566*7c478bd9Sstevel@tonic-gate }
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate /*
569*7c478bd9Sstevel@tonic-gate  * Remove a particular node.
570*7c478bd9Sstevel@tonic-gate  *
571*7c478bd9Sstevel@tonic-gate  * TYT, 2/25/99
572*7c478bd9Sstevel@tonic-gate  */
573*7c478bd9Sstevel@tonic-gate errcode_t profile_remove_node(node)
574*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(node);
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	if (node->parent == 0)
579*7c478bd9Sstevel@tonic-gate 		return PROF_EINVAL; /* Can't remove the root! */
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 	if (node->prev)
582*7c478bd9Sstevel@tonic-gate 		node->prev->next = node->next;
583*7c478bd9Sstevel@tonic-gate 	else
584*7c478bd9Sstevel@tonic-gate 		node->parent->first_child = node->next;
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	if (node->next)
587*7c478bd9Sstevel@tonic-gate 		node->next->prev = node->prev;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	profile_free_node(node);
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	return 0;
592*7c478bd9Sstevel@tonic-gate }
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate /*
595*7c478bd9Sstevel@tonic-gate  * Set the value of a specific node containing a relation.
596*7c478bd9Sstevel@tonic-gate  *
597*7c478bd9Sstevel@tonic-gate  * TYT, 2/25/99
598*7c478bd9Sstevel@tonic-gate  */
599*7c478bd9Sstevel@tonic-gate errcode_t profile_set_relation_value(node, new_value)
600*7c478bd9Sstevel@tonic-gate 	struct profile_node *node;
601*7c478bd9Sstevel@tonic-gate 	const char *new_value;
602*7c478bd9Sstevel@tonic-gate {
603*7c478bd9Sstevel@tonic-gate 	char	*cp;
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(node);
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (!node->value)
608*7c478bd9Sstevel@tonic-gate 		return PROF_SET_SECTION_VALUE;
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	cp = (char *) malloc(strlen(new_value)+1);
611*7c478bd9Sstevel@tonic-gate 	if (!cp)
612*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	strcpy(cp, new_value);
615*7c478bd9Sstevel@tonic-gate 	free(node->value);
616*7c478bd9Sstevel@tonic-gate 	node->value = cp;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 	return 0;
619*7c478bd9Sstevel@tonic-gate }
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate /*
622*7c478bd9Sstevel@tonic-gate  * Rename a specific node
623*7c478bd9Sstevel@tonic-gate  *
624*7c478bd9Sstevel@tonic-gate  * TYT 2/25/99
625*7c478bd9Sstevel@tonic-gate  */
626*7c478bd9Sstevel@tonic-gate errcode_t profile_rename_node(node, new_name)
627*7c478bd9Sstevel@tonic-gate 	struct profile_node	*node;
628*7c478bd9Sstevel@tonic-gate 	const char		*new_name;
629*7c478bd9Sstevel@tonic-gate {
630*7c478bd9Sstevel@tonic-gate 	char			*new_string;
631*7c478bd9Sstevel@tonic-gate 	struct profile_node 	*p, *last;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	CHECK_MAGIC(node);
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 	if (strcmp(new_name, node->name) == 0)
636*7c478bd9Sstevel@tonic-gate 		return 0;	/* It's the same name, return */
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	/*
639*7c478bd9Sstevel@tonic-gate 	 * Make sure we can allocate memory for the new name, first!
640*7c478bd9Sstevel@tonic-gate 	 */
641*7c478bd9Sstevel@tonic-gate 	new_string = (char *) malloc(strlen(new_name)+1);
642*7c478bd9Sstevel@tonic-gate 	if (!new_string)
643*7c478bd9Sstevel@tonic-gate 		return ENOMEM;
644*7c478bd9Sstevel@tonic-gate 	strcpy(new_string, new_name);
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	/*
647*7c478bd9Sstevel@tonic-gate 	 * Find the place to where the new node should go.  We look
648*7c478bd9Sstevel@tonic-gate 	 * for the place *after* the last match of the node name,
649*7c478bd9Sstevel@tonic-gate 	 * since order matters.
650*7c478bd9Sstevel@tonic-gate 	 */
651*7c478bd9Sstevel@tonic-gate 	for (p=node->parent->first_child, last = 0; p; last = p, p = p->next) {
652*7c478bd9Sstevel@tonic-gate 		if (strcmp(p->name, new_name) > 0)
653*7c478bd9Sstevel@tonic-gate 			break;
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	/*
657*7c478bd9Sstevel@tonic-gate 	 * If we need to move the node, do it now.
658*7c478bd9Sstevel@tonic-gate 	 */
659*7c478bd9Sstevel@tonic-gate 	if ((p != node) && (last != node)) {
660*7c478bd9Sstevel@tonic-gate 		/*
661*7c478bd9Sstevel@tonic-gate 		 * OK, let's detach the node
662*7c478bd9Sstevel@tonic-gate 		 */
663*7c478bd9Sstevel@tonic-gate 		if (node->prev)
664*7c478bd9Sstevel@tonic-gate 			node->prev->next = node->next;
665*7c478bd9Sstevel@tonic-gate 		else
666*7c478bd9Sstevel@tonic-gate 			node->parent->first_child = node->next;
667*7c478bd9Sstevel@tonic-gate 		if (node->next)
668*7c478bd9Sstevel@tonic-gate 			node->next->prev = node->prev;
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 		/*
671*7c478bd9Sstevel@tonic-gate 		 * Now let's reattach it in the right place.
672*7c478bd9Sstevel@tonic-gate 		 */
673*7c478bd9Sstevel@tonic-gate 		if (p)
674*7c478bd9Sstevel@tonic-gate 			p->prev = node;
675*7c478bd9Sstevel@tonic-gate 		if (last)
676*7c478bd9Sstevel@tonic-gate 			last->next = node;
677*7c478bd9Sstevel@tonic-gate 		else
678*7c478bd9Sstevel@tonic-gate 			node->parent->first_child = node;
679*7c478bd9Sstevel@tonic-gate 		node->next = p;
680*7c478bd9Sstevel@tonic-gate 		node->prev = last;
681*7c478bd9Sstevel@tonic-gate 	}
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	free(node->name);
684*7c478bd9Sstevel@tonic-gate 	node->name = new_string;
685*7c478bd9Sstevel@tonic-gate 	return 0;
686*7c478bd9Sstevel@tonic-gate }
687