1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *	@(#)nodes.c.pat	8.2 (Berkeley) 5/4/95
33 * $FreeBSD$
34 */
35
36#include <sys/param.h>
37#include <stdlib.h>
38#include <stddef.h>
39/*
40 * Routine for dealing with parsed shell commands.
41 */
42
43#include "shell.h"
44#include "nodes.h"
45#include "memalloc.h"
46#include "mystring.h"
47
48
49struct nodesize {
50	int     blocksize;	/* size of structures in function */
51	int     stringsize;	/* size of strings in node */
52};
53
54struct nodecopystate {
55	pointer block;		/* block to allocate function from */
56	char   *string;		/* block to allocate strings from */
57};
58
59%SIZES
60
61
62static void calcsize(union node *, struct nodesize *);
63static void sizenodelist(struct nodelist *, struct nodesize *);
64static union node *copynode(union node *, struct nodecopystate *);
65static struct nodelist *copynodelist(struct nodelist *, struct nodecopystate *);
66static char *nodesavestr(const char *, struct nodecopystate *);
67
68
69struct funcdef {
70	unsigned int refcount;
71	union node n;
72};
73
74/*
75 * Make a copy of a parse tree.
76 */
77
78struct funcdef *
79copyfunc(union node *n)
80{
81	struct nodesize sz;
82	struct nodecopystate st;
83	struct funcdef *fn;
84
85	if (n == NULL)
86		return NULL;
87	sz.blocksize = offsetof(struct funcdef, n);
88	sz.stringsize = 0;
89	calcsize(n, &sz);
90	fn = ckmalloc(sz.blocksize + sz.stringsize);
91	fn->refcount = 1;
92	st.block = (char *)fn + offsetof(struct funcdef, n);
93	st.string = (char *)fn + sz.blocksize;
94	copynode(n, &st);
95	return fn;
96}
97
98
99union node *
100getfuncnode(struct funcdef *fn)
101{
102	return fn == NULL ? NULL : &fn->n;
103}
104
105
106static void
107calcsize(union node *n, struct nodesize *result)
108{
109	%CALCSIZE
110}
111
112
113
114static void
115sizenodelist(struct nodelist *lp, struct nodesize *result)
116{
117	while (lp) {
118		result->blocksize += ALIGN(sizeof(struct nodelist));
119		calcsize(lp->n, result);
120		lp = lp->next;
121	}
122}
123
124
125
126static union node *
127copynode(union node *n, struct nodecopystate *state)
128{
129	union node *new;
130
131	%COPY
132	return new;
133}
134
135
136static struct nodelist *
137copynodelist(struct nodelist *lp, struct nodecopystate *state)
138{
139	struct nodelist *start;
140	struct nodelist **lpp;
141
142	lpp = &start;
143	while (lp) {
144		*lpp = state->block;
145		state->block = (char *)state->block +
146		    ALIGN(sizeof(struct nodelist));
147		(*lpp)->n = copynode(lp->n, state);
148		lp = lp->next;
149		lpp = &(*lpp)->next;
150	}
151	*lpp = NULL;
152	return start;
153}
154
155
156
157static char *
158nodesavestr(const char *s, struct nodecopystate *state)
159{
160	const char *p = s;
161	char *q = state->string;
162	char   *rtn = state->string;
163
164	while ((*q++ = *p++) != '\0')
165		continue;
166	state->string = q;
167	return rtn;
168}
169
170
171void
172reffunc(struct funcdef *fn)
173{
174	if (fn)
175		fn->refcount++;
176}
177
178
179/*
180 * Decrement the reference count of a function definition, freeing it
181 * if it falls to 0.
182 */
183
184void
185unreffunc(struct funcdef *fn)
186{
187	if (fn) {
188		fn->refcount--;
189		if (fn->refcount > 0)
190			return;
191		ckfree(fn);
192	}
193}
194