1 /* $OpenBSD: expandchildren.c,v 1.4 2024/04/23 13:34:50 jsg Exp $ */
2 /* $NetBSD: suff.c,v 1.13 1996/11/06 17:59:25 christos Exp $ */
3
4 /*
5 * Copyright (c) 1988, 1989, 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 * Copyright (c) 1989 by Berkeley Softworks
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Adam de Boor.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38 /*-
39 * expandchildren.c --
40 * Dealing with final children expansion before building stuff
41 */
42
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include "defines.h"
48 #include "direxpand.h"
49 #include "engine.h"
50 #include "arch.h"
51 #include "expandchildren.h"
52 #include "var.h"
53 #include "targ.h"
54 #include "lst.h"
55 #include "gnode.h"
56 #include "suff.h"
57
58 static void ExpandChildren(LstNode, GNode *);
59 static void ExpandVarChildren(LstNode, GNode *, GNode *);
60 static void ExpandWildChildren(LstNode, GNode *, GNode *);
61
62 void
LinkParent(GNode * cgn,GNode * pgn)63 LinkParent(GNode *cgn, GNode *pgn)
64 {
65 Lst_AtEnd(&cgn->parents, pgn);
66 if (!has_been_built(cgn))
67 pgn->children_left++;
68 else if ( ! (cgn->type & OP_USE)) {
69 if (cgn->built_status == REBUILT)
70 pgn->child_rebuilt = true;
71 (void)Make_TimeStamp(pgn, cgn);
72 }
73 }
74
75 static void
ExpandVarChildren(LstNode after,GNode * cgn,GNode * pgn)76 ExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn)
77 {
78 GNode *gn; /* New source 8) */
79 char *cp; /* Expanded value */
80 LIST members;
81
82
83 if (DEBUG(SUFF))
84 printf("Expanding \"%s\"...", cgn->name);
85
86 cp = Var_Subst(cgn->name, &pgn->localvars, true);
87 if (cp == NULL) {
88 printf("Problem substituting in %s", cgn->name);
89 printf("\n");
90 return;
91 }
92
93 Lst_Init(&members);
94
95 if (cgn->type & OP_ARCHV) {
96 /*
97 * Node was an archive(member) target, so we want to call
98 * on the Arch module to find the nodes for us, expanding
99 * variables in the parent's context.
100 */
101 const char *sacrifice = (const char *)cp;
102
103 (void)Arch_ParseArchive(&sacrifice, &members, &pgn->localvars);
104 } else {
105 /* Break the result into a vector of strings whose nodes
106 * we can find, then add those nodes to the members list.
107 * Unfortunately, we can't use brk_string because it
108 * doesn't understand about variable specifications with
109 * spaces in them... */
110 const char *start, *cp2;
111
112 for (start = cp; *start == ' ' || *start == '\t'; start++)
113 continue;
114 for (cp2 = start; *cp2 != '\0';) {
115 if (ISSPACE(*cp2)) {
116 /* White-space -- terminate element, find the
117 * node, add it, skip any further spaces. */
118 gn = Targ_FindNodei(start, cp2, TARG_CREATE);
119 cp2++;
120 Lst_AtEnd(&members, gn);
121 while (ISSPACE(*cp2))
122 cp2++;
123 /* Adjust cp2 for increment at start of loop,
124 * but set start to first non-space. */
125 start = cp2;
126 } else if (*cp2 == '$')
127 /* Start of a variable spec -- contact variable
128 * module to find the end so we can skip over
129 * it. */
130 Var_ParseSkip(&cp2, &pgn->localvars);
131 else if (*cp2 == '\\' && cp2[1] != '\0')
132 /* Escaped something -- skip over it. */
133 cp2+=2;
134 else
135 cp2++;
136 }
137
138 if (cp2 != start) {
139 /* Stuff left over -- add it to the list too. */
140 gn = Targ_FindNodei(start, cp2, TARG_CREATE);
141 Lst_AtEnd(&members, gn);
142 }
143 }
144 /* Add all elements of the members list to the parent node. */
145 while ((gn = Lst_DeQueue(&members)) != NULL) {
146 if (DEBUG(SUFF))
147 printf("%s...", gn->name);
148 if (Lst_Member(&pgn->children, gn) == NULL) {
149 Lst_Append(&pgn->children, after, gn);
150 after = Lst_Adv(after);
151 LinkParent(gn, pgn);
152 }
153 }
154 /* Free the result. */
155 free(cp);
156 if (DEBUG(SUFF))
157 printf("\n");
158 }
159
160 static void
ExpandWildChildren(LstNode after,GNode * cgn,GNode * pgn)161 ExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn)
162 {
163 char *cp; /* Expanded value */
164
165 LIST exp; /* List of expansions */
166 Lst path; /* Search path along which to expand */
167
168 if (DEBUG(SUFF))
169 printf("Wildcard expanding \"%s\"...", cgn->name);
170
171 /* Find a path along which to expand the word: if
172 * the word has a known suffix, use the path for that suffix,
173 * otherwise use the default path. */
174 path = find_best_path(cgn->name);
175
176 /* Expand the word along the chosen path. */
177 Lst_Init(&exp);
178 Dir_Expand(cgn->name, path, &exp);
179
180 /* Fetch next expansion off the list and find its GNode. */
181 while ((cp = Lst_DeQueue(&exp)) != NULL) {
182 GNode *gn; /* New source 8) */
183 if (DEBUG(SUFF))
184 printf("%s...", cp);
185 gn = Targ_FindNode(cp, TARG_CREATE);
186
187 /* If gn isn't already a child of the parent, make it so and
188 * up the parent's count of children to build. */
189 if (Lst_Member(&pgn->children, gn) == NULL) {
190 Lst_Append(&pgn->children, after, gn);
191 after = Lst_Adv(after);
192 LinkParent(gn, pgn);
193 }
194 }
195
196 if (DEBUG(SUFF))
197 printf("\n");
198 }
199
200 /*-
201 *-----------------------------------------------------------------------
202 * ExpandChildren --
203 * Expand the names of any children of a given node that contain
204 * variable invocations or file wildcards into actual targets.
205 *
206 * Side Effects:
207 * The expanded node is removed from the parent's list of children,
208 * and the parent's children to build counter is decremented,
209 * but other nodes may be added.
210 *-----------------------------------------------------------------------
211 */
212 static void
ExpandChildren(LstNode ln,GNode * pgn)213 ExpandChildren(LstNode ln, /* LstNode of child, so we can replace it */
214 GNode *pgn)
215 {
216 GNode *cgn = Lst_Datum(ln);
217
218 /* First do variable expansion -- this takes precedence over wildcard
219 * expansion. If the result contains wildcards, they'll be gotten to
220 * later since the resulting words are tacked on to the end of the
221 * children list. */
222 if (strchr(cgn->name, '$') != NULL)
223 ExpandVarChildren(ln, cgn, pgn);
224 else if (Dir_HasWildcards(cgn->name))
225 ExpandWildChildren(ln, cgn, pgn);
226 else
227 /* Third case: nothing to expand. */
228 return;
229
230 /* Since the source was expanded, remove it from the list of children to
231 * keep it from being processed. */
232 pgn->children_left--;
233 Lst_Remove(&pgn->children, ln);
234 }
235
236 void
expand_children_from(GNode * parent,LstNode from)237 expand_children_from(GNode *parent, LstNode from)
238 {
239 LstNode np, ln;
240
241 for (ln = from; ln != NULL; ln = np) {
242 np = Lst_Adv(ln);
243 ExpandChildren(ln, parent);
244 }
245 }
246