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