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