sh(1): bring sh from freebsd
[dragonfly.git] / bin / sh / nodes.c.pat
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  * 3. 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: head/bin/sh/nodes.c.pat 314436 2017-02-28 23:42:47Z imp $
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
49 struct nodesize {
50         int     blocksize;      /* size of structures in function */
51         int     stringsize;     /* size of strings in node */
52 };
53
54 struct nodecopystate {
55         pointer block;          /* block to allocate function from */
56         char   *string;         /* block to allocate strings from */
57 };
58
59 %SIZES
60
61
62 static void calcsize(union node *, struct nodesize *);
63 static void sizenodelist(struct nodelist *, struct nodesize *);
64 static union node *copynode(union node *, struct nodecopystate *);
65 static struct nodelist *copynodelist(struct nodelist *, struct nodecopystate *);
66 static char *nodesavestr(const char *, struct nodecopystate *);
67
68
69 struct funcdef {
70         unsigned int refcount;
71         union node n;
72 };
73
74 /*
75  * Make a copy of a parse tree.
76  */
77
78 struct funcdef *
79 copyfunc(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
99 union node *
100 getfuncnode(struct funcdef *fn)
101 {
102         return fn == NULL ? NULL : &fn->n;
103 }
104
105
106 static void
107 calcsize(union node *n, struct nodesize *result)
108 {
109         %CALCSIZE
110 }
111
112
113
114 static void
115 sizenodelist(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
126 static union node *
127 copynode(union node *n, struct nodecopystate *state)
128 {
129         union node *new;
130
131         %COPY
132         return new;
133 }
134
135
136 static struct nodelist *
137 copynodelist(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
157 static char *
158 nodesavestr(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
171 void
172 reffunc(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
184 void
185 unreffunc(struct funcdef *fn)
186 {
187         if (fn) {
188                 fn->refcount--;
189                 if (fn->refcount > 0)
190                         return;
191                 ckfree(fn);
192         }
193 }