xref: /openbsd-src/usr.bin/make/expandchildren.c (revision e6c7c102cf5d9891f32552a42895134a59937045)
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