1*e6c7c102Sjsg /* $OpenBSD: expandchildren.c,v 1.4 2024/04/23 13:34:50 jsg Exp $ */
2483cbdb0Sespie /* $NetBSD: suff.c,v 1.13 1996/11/06 17:59:25 christos Exp $ */
3483cbdb0Sespie
4483cbdb0Sespie /*
5483cbdb0Sespie * Copyright (c) 1988, 1989, 1990, 1993
6483cbdb0Sespie * The Regents of the University of California. All rights reserved.
7483cbdb0Sespie * Copyright (c) 1989 by Berkeley Softworks
8483cbdb0Sespie * All rights reserved.
9483cbdb0Sespie *
10483cbdb0Sespie * This code is derived from software contributed to Berkeley by
11483cbdb0Sespie * Adam de Boor.
12483cbdb0Sespie *
13483cbdb0Sespie * Redistribution and use in source and binary forms, with or without
14483cbdb0Sespie * modification, are permitted provided that the following conditions
15483cbdb0Sespie * are met:
16483cbdb0Sespie * 1. Redistributions of source code must retain the above copyright
17483cbdb0Sespie * notice, this list of conditions and the following disclaimer.
18483cbdb0Sespie * 2. Redistributions in binary form must reproduce the above copyright
19483cbdb0Sespie * notice, this list of conditions and the following disclaimer in the
20483cbdb0Sespie * documentation and/or other materials provided with the distribution.
21483cbdb0Sespie * 3. Neither the name of the University nor the names of its contributors
22483cbdb0Sespie * may be used to endorse or promote products derived from this software
23483cbdb0Sespie * without specific prior written permission.
24483cbdb0Sespie *
25483cbdb0Sespie * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26483cbdb0Sespie * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27483cbdb0Sespie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28483cbdb0Sespie * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29483cbdb0Sespie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30483cbdb0Sespie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31483cbdb0Sespie * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32483cbdb0Sespie * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33483cbdb0Sespie * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34483cbdb0Sespie * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35483cbdb0Sespie * SUCH DAMAGE.
36483cbdb0Sespie */
37483cbdb0Sespie
38483cbdb0Sespie /*-
39483cbdb0Sespie * expandchildren.c --
40483cbdb0Sespie * Dealing with final children expansion before building stuff
41483cbdb0Sespie */
42483cbdb0Sespie
43483cbdb0Sespie #include <ctype.h>
44483cbdb0Sespie #include <stdio.h>
45483cbdb0Sespie #include <stdlib.h>
46483cbdb0Sespie #include <string.h>
47483cbdb0Sespie #include "defines.h"
48483cbdb0Sespie #include "direxpand.h"
49483cbdb0Sespie #include "engine.h"
50483cbdb0Sespie #include "arch.h"
51483cbdb0Sespie #include "expandchildren.h"
52483cbdb0Sespie #include "var.h"
53483cbdb0Sespie #include "targ.h"
54483cbdb0Sespie #include "lst.h"
55483cbdb0Sespie #include "gnode.h"
56483cbdb0Sespie #include "suff.h"
57483cbdb0Sespie
58483cbdb0Sespie static void ExpandChildren(LstNode, GNode *);
59483cbdb0Sespie static void ExpandVarChildren(LstNode, GNode *, GNode *);
60483cbdb0Sespie static void ExpandWildChildren(LstNode, GNode *, GNode *);
61483cbdb0Sespie
62483cbdb0Sespie void
LinkParent(GNode * cgn,GNode * pgn)63483cbdb0Sespie LinkParent(GNode *cgn, GNode *pgn)
64483cbdb0Sespie {
65483cbdb0Sespie Lst_AtEnd(&cgn->parents, pgn);
66483cbdb0Sespie if (!has_been_built(cgn))
67483cbdb0Sespie pgn->children_left++;
6818cc0328Sespie else if ( ! (cgn->type & OP_USE)) {
69483cbdb0Sespie if (cgn->built_status == REBUILT)
70483cbdb0Sespie pgn->child_rebuilt = true;
71483cbdb0Sespie (void)Make_TimeStamp(pgn, cgn);
72483cbdb0Sespie }
73483cbdb0Sespie }
74483cbdb0Sespie
75483cbdb0Sespie static void
ExpandVarChildren(LstNode after,GNode * cgn,GNode * pgn)76483cbdb0Sespie ExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn)
77483cbdb0Sespie {
78483cbdb0Sespie GNode *gn; /* New source 8) */
79483cbdb0Sespie char *cp; /* Expanded value */
80483cbdb0Sespie LIST members;
81483cbdb0Sespie
82483cbdb0Sespie
83483cbdb0Sespie if (DEBUG(SUFF))
84483cbdb0Sespie printf("Expanding \"%s\"...", cgn->name);
85483cbdb0Sespie
86483cbdb0Sespie cp = Var_Subst(cgn->name, &pgn->localvars, true);
87483cbdb0Sespie if (cp == NULL) {
88483cbdb0Sespie printf("Problem substituting in %s", cgn->name);
89483cbdb0Sespie printf("\n");
90483cbdb0Sespie return;
91483cbdb0Sespie }
92483cbdb0Sespie
93483cbdb0Sespie Lst_Init(&members);
94483cbdb0Sespie
95483cbdb0Sespie if (cgn->type & OP_ARCHV) {
96483cbdb0Sespie /*
97483cbdb0Sespie * Node was an archive(member) target, so we want to call
98483cbdb0Sespie * on the Arch module to find the nodes for us, expanding
99483cbdb0Sespie * variables in the parent's context.
100483cbdb0Sespie */
101483cbdb0Sespie const char *sacrifice = (const char *)cp;
102483cbdb0Sespie
103483cbdb0Sespie (void)Arch_ParseArchive(&sacrifice, &members, &pgn->localvars);
104483cbdb0Sespie } else {
105483cbdb0Sespie /* Break the result into a vector of strings whose nodes
106483cbdb0Sespie * we can find, then add those nodes to the members list.
107483cbdb0Sespie * Unfortunately, we can't use brk_string because it
108483cbdb0Sespie * doesn't understand about variable specifications with
109483cbdb0Sespie * spaces in them... */
110483cbdb0Sespie const char *start, *cp2;
111483cbdb0Sespie
112483cbdb0Sespie for (start = cp; *start == ' ' || *start == '\t'; start++)
113483cbdb0Sespie continue;
114483cbdb0Sespie for (cp2 = start; *cp2 != '\0';) {
115483cbdb0Sespie if (ISSPACE(*cp2)) {
116483cbdb0Sespie /* White-space -- terminate element, find the
117483cbdb0Sespie * node, add it, skip any further spaces. */
118483cbdb0Sespie gn = Targ_FindNodei(start, cp2, TARG_CREATE);
119483cbdb0Sespie cp2++;
120483cbdb0Sespie Lst_AtEnd(&members, gn);
121483cbdb0Sespie while (ISSPACE(*cp2))
122483cbdb0Sespie cp2++;
123483cbdb0Sespie /* Adjust cp2 for increment at start of loop,
124483cbdb0Sespie * but set start to first non-space. */
125483cbdb0Sespie start = cp2;
126483cbdb0Sespie } else if (*cp2 == '$')
127483cbdb0Sespie /* Start of a variable spec -- contact variable
128483cbdb0Sespie * module to find the end so we can skip over
129483cbdb0Sespie * it. */
130483cbdb0Sespie Var_ParseSkip(&cp2, &pgn->localvars);
131483cbdb0Sespie else if (*cp2 == '\\' && cp2[1] != '\0')
132483cbdb0Sespie /* Escaped something -- skip over it. */
133483cbdb0Sespie cp2+=2;
134483cbdb0Sespie else
135483cbdb0Sespie cp2++;
136483cbdb0Sespie }
137483cbdb0Sespie
138483cbdb0Sespie if (cp2 != start) {
139483cbdb0Sespie /* Stuff left over -- add it to the list too. */
140483cbdb0Sespie gn = Targ_FindNodei(start, cp2, TARG_CREATE);
141483cbdb0Sespie Lst_AtEnd(&members, gn);
142483cbdb0Sespie }
143483cbdb0Sespie }
144483cbdb0Sespie /* Add all elements of the members list to the parent node. */
145483cbdb0Sespie while ((gn = Lst_DeQueue(&members)) != NULL) {
146483cbdb0Sespie if (DEBUG(SUFF))
147483cbdb0Sespie printf("%s...", gn->name);
148483cbdb0Sespie if (Lst_Member(&pgn->children, gn) == NULL) {
149483cbdb0Sespie Lst_Append(&pgn->children, after, gn);
150483cbdb0Sespie after = Lst_Adv(after);
151483cbdb0Sespie LinkParent(gn, pgn);
152483cbdb0Sespie }
153483cbdb0Sespie }
154483cbdb0Sespie /* Free the result. */
155483cbdb0Sespie free(cp);
156483cbdb0Sespie if (DEBUG(SUFF))
157483cbdb0Sespie printf("\n");
158483cbdb0Sespie }
159483cbdb0Sespie
160483cbdb0Sespie static void
ExpandWildChildren(LstNode after,GNode * cgn,GNode * pgn)161483cbdb0Sespie ExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn)
162483cbdb0Sespie {
163483cbdb0Sespie char *cp; /* Expanded value */
164483cbdb0Sespie
165483cbdb0Sespie LIST exp; /* List of expansions */
166483cbdb0Sespie Lst path; /* Search path along which to expand */
167483cbdb0Sespie
168483cbdb0Sespie if (DEBUG(SUFF))
169483cbdb0Sespie printf("Wildcard expanding \"%s\"...", cgn->name);
170483cbdb0Sespie
171483cbdb0Sespie /* Find a path along which to expand the word: if
172483cbdb0Sespie * the word has a known suffix, use the path for that suffix,
173483cbdb0Sespie * otherwise use the default path. */
174483cbdb0Sespie path = find_best_path(cgn->name);
175483cbdb0Sespie
176483cbdb0Sespie /* Expand the word along the chosen path. */
177483cbdb0Sespie Lst_Init(&exp);
178483cbdb0Sespie Dir_Expand(cgn->name, path, &exp);
179483cbdb0Sespie
180483cbdb0Sespie /* Fetch next expansion off the list and find its GNode. */
181483cbdb0Sespie while ((cp = Lst_DeQueue(&exp)) != NULL) {
182483cbdb0Sespie GNode *gn; /* New source 8) */
183483cbdb0Sespie if (DEBUG(SUFF))
184483cbdb0Sespie printf("%s...", cp);
185483cbdb0Sespie gn = Targ_FindNode(cp, TARG_CREATE);
186483cbdb0Sespie
187483cbdb0Sespie /* If gn isn't already a child of the parent, make it so and
188483cbdb0Sespie * up the parent's count of children to build. */
189483cbdb0Sespie if (Lst_Member(&pgn->children, gn) == NULL) {
190483cbdb0Sespie Lst_Append(&pgn->children, after, gn);
191483cbdb0Sespie after = Lst_Adv(after);
192483cbdb0Sespie LinkParent(gn, pgn);
193483cbdb0Sespie }
194483cbdb0Sespie }
195483cbdb0Sespie
196483cbdb0Sespie if (DEBUG(SUFF))
197483cbdb0Sespie printf("\n");
198483cbdb0Sespie }
199483cbdb0Sespie
200483cbdb0Sespie /*-
201483cbdb0Sespie *-----------------------------------------------------------------------
202483cbdb0Sespie * ExpandChildren --
203483cbdb0Sespie * Expand the names of any children of a given node that contain
204483cbdb0Sespie * variable invocations or file wildcards into actual targets.
205483cbdb0Sespie *
206483cbdb0Sespie * Side Effects:
207483cbdb0Sespie * The expanded node is removed from the parent's list of children,
208483cbdb0Sespie * and the parent's children to build counter is decremented,
209483cbdb0Sespie * but other nodes may be added.
210483cbdb0Sespie *-----------------------------------------------------------------------
211483cbdb0Sespie */
212483cbdb0Sespie static void
ExpandChildren(LstNode ln,GNode * pgn)213483cbdb0Sespie ExpandChildren(LstNode ln, /* LstNode of child, so we can replace it */
214483cbdb0Sespie GNode *pgn)
215483cbdb0Sespie {
216483cbdb0Sespie GNode *cgn = Lst_Datum(ln);
217483cbdb0Sespie
218483cbdb0Sespie /* First do variable expansion -- this takes precedence over wildcard
219483cbdb0Sespie * expansion. If the result contains wildcards, they'll be gotten to
220483cbdb0Sespie * later since the resulting words are tacked on to the end of the
221483cbdb0Sespie * children list. */
222483cbdb0Sespie if (strchr(cgn->name, '$') != NULL)
223483cbdb0Sespie ExpandVarChildren(ln, cgn, pgn);
224483cbdb0Sespie else if (Dir_HasWildcards(cgn->name))
225483cbdb0Sespie ExpandWildChildren(ln, cgn, pgn);
226483cbdb0Sespie else
227483cbdb0Sespie /* Third case: nothing to expand. */
228483cbdb0Sespie return;
229483cbdb0Sespie
230483cbdb0Sespie /* Since the source was expanded, remove it from the list of children to
231483cbdb0Sespie * keep it from being processed. */
232483cbdb0Sespie pgn->children_left--;
233483cbdb0Sespie Lst_Remove(&pgn->children, ln);
234483cbdb0Sespie }
235483cbdb0Sespie
236483cbdb0Sespie void
expand_children_from(GNode * parent,LstNode from)237483cbdb0Sespie expand_children_from(GNode *parent, LstNode from)
238483cbdb0Sespie {
239483cbdb0Sespie LstNode np, ln;
240483cbdb0Sespie
241483cbdb0Sespie for (ln = from; ln != NULL; ln = np) {
242483cbdb0Sespie np = Lst_Adv(ln);
243483cbdb0Sespie ExpandChildren(ln, parent);
244483cbdb0Sespie }
245483cbdb0Sespie }
246