xref: /openbsd/usr.bin/make/expandchildren.c (revision 09467b48)
1 /*	$OpenBSD: expandchildren.c,v 1.2 2020/01/26 12:41:21 espie 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 "config.h"
48 #include "defines.h"
49 #include "direxpand.h"
50 #include "engine.h"
51 #include "arch.h"
52 #include "expandchildren.h"
53 #include "var.h"
54 #include "targ.h"
55 #include "lst.h"
56 #include "gnode.h"
57 #include "suff.h"
58 
59 static void ExpandChildren(LstNode, GNode *);
60 static void ExpandVarChildren(LstNode, GNode *, GNode *);
61 static void ExpandWildChildren(LstNode, GNode *, GNode *);
62 
63 void
64 LinkParent(GNode *cgn, GNode *pgn)
65 {
66 	Lst_AtEnd(&cgn->parents, pgn);
67 	if (!has_been_built(cgn))
68 		pgn->children_left++;
69 	else if ( ! (cgn->type & OP_USE)) {
70 		if (cgn->built_status == REBUILT)
71 			pgn->child_rebuilt = true;
72 		(void)Make_TimeStamp(pgn, cgn);
73 	}
74 }
75 
76 static void
77 ExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn)
78 {
79 	GNode *gn;		/* New source 8) */
80 	char *cp;		/* Expanded value */
81 	LIST members;
82 
83 
84 	if (DEBUG(SUFF))
85 		printf("Expanding \"%s\"...", cgn->name);
86 
87 	cp = Var_Subst(cgn->name, &pgn->localvars, true);
88 	if (cp == NULL) {
89 		printf("Problem substituting in %s", cgn->name);
90 		printf("\n");
91 		return;
92 	}
93 
94 	Lst_Init(&members);
95 
96 	if (cgn->type & OP_ARCHV) {
97 		/*
98 		 * Node was an archive(member) target, so we want to call
99 		 * on the Arch module to find the nodes for us, expanding
100 		 * variables in the parent's context.
101 		 */
102 		const char *sacrifice = (const char *)cp;
103 
104 		(void)Arch_ParseArchive(&sacrifice, &members, &pgn->localvars);
105 	} else {
106 		/* Break the result into a vector of strings whose nodes
107 		 * we can find, then add those nodes to the members list.
108 		 * Unfortunately, we can't use brk_string because it
109 		 * doesn't understand about variable specifications with
110 		 * spaces in them...  */
111 		const char *start, *cp2;
112 
113 		for (start = cp; *start == ' ' || *start == '\t'; start++)
114 			continue;
115 		for (cp2 = start; *cp2 != '\0';) {
116 			if (ISSPACE(*cp2)) {
117 				/* White-space -- terminate element, find the
118 				 * node, add it, skip any further spaces.  */
119 				gn = Targ_FindNodei(start, cp2, TARG_CREATE);
120 				cp2++;
121 				Lst_AtEnd(&members, gn);
122 				while (ISSPACE(*cp2))
123 					cp2++;
124 				/* Adjust cp2 for increment at start of loop,
125 				 * but set start to first non-space.  */
126 				start = cp2;
127 			} else if (*cp2 == '$')
128 				/* Start of a variable spec -- contact variable
129 				 * module to find the end so we can skip over
130 				 * it.  */
131 				Var_ParseSkip(&cp2, &pgn->localvars);
132 			else if (*cp2 == '\\' && cp2[1] != '\0')
133 				/* Escaped something -- skip over it.  */
134 				cp2+=2;
135 			else
136 				cp2++;
137 	    }
138 
139 	    if (cp2 != start) {
140 		    /* Stuff left over -- add it to the list too.  */
141 		    gn = Targ_FindNodei(start, cp2, TARG_CREATE);
142 		    Lst_AtEnd(&members, gn);
143 	    }
144 	}
145 	/* Add all elements of the members list to the parent node.  */
146 	while ((gn = Lst_DeQueue(&members)) != NULL) {
147 		if (DEBUG(SUFF))
148 			printf("%s...", gn->name);
149 		if (Lst_Member(&pgn->children, gn) == NULL) {
150 			Lst_Append(&pgn->children, after, gn);
151 			after = Lst_Adv(after);
152 			LinkParent(gn, pgn);
153 		}
154 	}
155 	/* Free the result.  */
156 	free(cp);
157 	if (DEBUG(SUFF))
158 		printf("\n");
159 }
160 
161 static void
162 ExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn)
163 {
164 	char *cp;	/* Expanded value */
165 
166 	LIST exp;	/* List of expansions */
167 	Lst path;	/* Search path along which to expand */
168 
169 	if (DEBUG(SUFF))
170 		printf("Wildcard expanding \"%s\"...", cgn->name);
171 
172 	/* Find a path along which to expand the word: if
173 	 * the word has a known suffix, use the path for that suffix,
174 	 * otherwise use the default path. */
175 	path = find_best_path(cgn->name);
176 
177 	/* Expand the word along the chosen path. */
178 	Lst_Init(&exp);
179 	Dir_Expand(cgn->name, path, &exp);
180 
181 	/* Fetch next expansion off the list and find its GNode.  */
182 	while ((cp = Lst_DeQueue(&exp)) != NULL) {
183 		GNode *gn;		/* New source 8) */
184 		if (DEBUG(SUFF))
185 			printf("%s...", cp);
186 		gn = Targ_FindNode(cp, TARG_CREATE);
187 
188 		/* If gn isn't already a child of the parent, make it so and
189 		 * up the parent's count of children to build.  */
190 		if (Lst_Member(&pgn->children, gn) == NULL) {
191 			Lst_Append(&pgn->children, after, gn);
192 			after = Lst_Adv(after);
193 			LinkParent(gn, pgn);
194 		}
195 	}
196 
197 	if (DEBUG(SUFF))
198 		printf("\n");
199 }
200 
201 /*-
202  *-----------------------------------------------------------------------
203  * ExpandChildren --
204  *	Expand the names of any children of a given node that contain
205  *	variable invocations or file wildcards into actual targets.
206  *
207  * Side Effects:
208  *	The expanded node is removed from the parent's list of children,
209  *	and the parent's children to build counter is decremented,
210  *      but other nodes may be added.
211  *-----------------------------------------------------------------------
212  */
213 static void
214 ExpandChildren(LstNode ln, /* LstNode of child, so we can replace it */
215     GNode *pgn)
216 {
217 	GNode	*cgn = Lst_Datum(ln);
218 
219 	/* First do variable expansion -- this takes precedence over wildcard
220 	 * expansion. If the result contains wildcards, they'll be gotten to
221 	 * later since the resulting words are tacked on to the end of the
222 	 * children list.  */
223 	if (strchr(cgn->name, '$') != NULL)
224 		ExpandVarChildren(ln, cgn, pgn);
225 	else if (Dir_HasWildcards(cgn->name))
226 		ExpandWildChildren(ln, cgn, pgn);
227 	else
228 	    /* Third case: nothing to expand.  */
229 		return;
230 
231 	/* Since the source was expanded, remove it from the list of children to
232 	 * keep it from being processed.  */
233 	pgn->children_left--;
234 	Lst_Remove(&pgn->children, ln);
235 }
236 
237 void
238 expand_children_from(GNode *parent, LstNode from)
239 {
240 	LstNode np, ln;
241 
242 	for (ln = from; ln != NULL; ln = np) {
243 		np = Lst_Adv(ln);
244 		ExpandChildren(ln, parent);
245 	}
246 }
247