1*06b9b3e0SSimon J. Gerraty /* $NetBSD: suff.c,v 1.335 2021/01/10 21:20:46 rillig Exp $ */ 23955d011SMarcel Moolenaar 33955d011SMarcel Moolenaar /* 43955d011SMarcel Moolenaar * Copyright (c) 1988, 1989, 1990, 1993 53955d011SMarcel Moolenaar * The Regents of the University of California. All rights reserved. 63955d011SMarcel Moolenaar * 73955d011SMarcel Moolenaar * This code is derived from software contributed to Berkeley by 83955d011SMarcel Moolenaar * Adam de Boor. 93955d011SMarcel Moolenaar * 103955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 113955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 123955d011SMarcel Moolenaar * are met: 133955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 143955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 153955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 163955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 173955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 183955d011SMarcel Moolenaar * 3. Neither the name of the University nor the names of its contributors 193955d011SMarcel Moolenaar * may be used to endorse or promote products derived from this software 203955d011SMarcel Moolenaar * without specific prior written permission. 213955d011SMarcel Moolenaar * 223955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 233955d011SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 243955d011SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 253955d011SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 263955d011SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 273955d011SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 283955d011SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 293955d011SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 303955d011SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 313955d011SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 323955d011SMarcel Moolenaar * SUCH DAMAGE. 333955d011SMarcel Moolenaar */ 343955d011SMarcel Moolenaar 353955d011SMarcel Moolenaar /* 363955d011SMarcel Moolenaar * Copyright (c) 1989 by Berkeley Softworks 373955d011SMarcel Moolenaar * All rights reserved. 383955d011SMarcel Moolenaar * 393955d011SMarcel Moolenaar * This code is derived from software contributed to Berkeley by 403955d011SMarcel Moolenaar * Adam de Boor. 413955d011SMarcel Moolenaar * 423955d011SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 433955d011SMarcel Moolenaar * modification, are permitted provided that the following conditions 443955d011SMarcel Moolenaar * are met: 453955d011SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 463955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 473955d011SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 483955d011SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 493955d011SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 503955d011SMarcel Moolenaar * 3. All advertising materials mentioning features or use of this software 513955d011SMarcel Moolenaar * must display the following acknowledgement: 523955d011SMarcel Moolenaar * This product includes software developed by the University of 533955d011SMarcel Moolenaar * California, Berkeley and its contributors. 543955d011SMarcel Moolenaar * 4. Neither the name of the University nor the names of its contributors 553955d011SMarcel Moolenaar * may be used to endorse or promote products derived from this software 563955d011SMarcel Moolenaar * without specific prior written permission. 573955d011SMarcel Moolenaar * 583955d011SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 593955d011SMarcel Moolenaar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 603955d011SMarcel Moolenaar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 613955d011SMarcel Moolenaar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 623955d011SMarcel Moolenaar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 633955d011SMarcel Moolenaar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 643955d011SMarcel Moolenaar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 653955d011SMarcel Moolenaar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 663955d011SMarcel Moolenaar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 673955d011SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 683955d011SMarcel Moolenaar * SUCH DAMAGE. 693955d011SMarcel Moolenaar */ 703955d011SMarcel Moolenaar 71e2eeea75SSimon J. Gerraty /* 72e2eeea75SSimon J. Gerraty * Maintain suffix lists and find implicit dependents using suffix 73e2eeea75SSimon J. Gerraty * transformation rules such as ".c.o". 743955d011SMarcel Moolenaar * 753955d011SMarcel Moolenaar * Interface: 76e2eeea75SSimon J. Gerraty * Suff_Init Initialize the module. 773955d011SMarcel Moolenaar * 78e2eeea75SSimon J. Gerraty * Suff_End Clean up the module. 793955d011SMarcel Moolenaar * 80e2eeea75SSimon J. Gerraty * Suff_DoPaths Extend the search path of each suffix to include the 81e2eeea75SSimon J. Gerraty * default search path. 823955d011SMarcel Moolenaar * 83956e45f6SSimon J. Gerraty * Suff_ClearSuffixes 84e2eeea75SSimon J. Gerraty * Clear out all the suffixes and transformations. 853955d011SMarcel Moolenaar * 86956e45f6SSimon J. Gerraty * Suff_IsTransform 87e2eeea75SSimon J. Gerraty * See if the passed string is a transformation rule. 883955d011SMarcel Moolenaar * 893955d011SMarcel Moolenaar * Suff_AddSuffix Add the passed string as another known suffix. 903955d011SMarcel Moolenaar * 913955d011SMarcel Moolenaar * Suff_GetPath Return the search path for the given suffix. 923955d011SMarcel Moolenaar * 93956e45f6SSimon J. Gerraty * Suff_AddInclude 94956e45f6SSimon J. Gerraty * Mark the given suffix as denoting an include file. 953955d011SMarcel Moolenaar * 963955d011SMarcel Moolenaar * Suff_AddLib Mark the given suffix as denoting a library. 973955d011SMarcel Moolenaar * 98956e45f6SSimon J. Gerraty * Suff_AddTransform 99e2eeea75SSimon J. Gerraty * Add another transformation to the suffix graph. 1003955d011SMarcel Moolenaar * 1013955d011SMarcel Moolenaar * Suff_SetNull Define the suffix to consider the suffix of 1023955d011SMarcel Moolenaar * any file that doesn't have a known one. 1033955d011SMarcel Moolenaar * 1043955d011SMarcel Moolenaar * Suff_FindDeps Find implicit sources for and the location of 1053955d011SMarcel Moolenaar * a target based on its suffix. Returns the 1063955d011SMarcel Moolenaar * bottom-most node added to the graph or NULL 1073955d011SMarcel Moolenaar * if the target had no implicit sources. 1083955d011SMarcel Moolenaar * 109956e45f6SSimon J. Gerraty * Suff_FindPath Return the appropriate path to search in order to 110956e45f6SSimon J. Gerraty * find the node. 1113955d011SMarcel Moolenaar */ 1123955d011SMarcel Moolenaar 1133955d011SMarcel Moolenaar #include "make.h" 1143955d011SMarcel Moolenaar #include "dir.h" 1153955d011SMarcel Moolenaar 116956e45f6SSimon J. Gerraty /* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */ 117*06b9b3e0SSimon J. Gerraty MAKE_RCSID("$NetBSD: suff.c,v 1.335 2021/01/10 21:20:46 rillig Exp $"); 1182c3632d1SSimon J. Gerraty 119*06b9b3e0SSimon J. Gerraty typedef List SuffixList; 120*06b9b3e0SSimon J. Gerraty typedef ListNode SuffixListNode; 1212c3632d1SSimon J. Gerraty 122*06b9b3e0SSimon J. Gerraty typedef List CandidateList; 123*06b9b3e0SSimon J. Gerraty typedef ListNode CandidateListNode; 1242c3632d1SSimon J. Gerraty 125*06b9b3e0SSimon J. Gerraty /* The defined suffixes, such as '.c', '.o', '.l'. */ 126*06b9b3e0SSimon J. Gerraty static SuffixList sufflist = LST_INIT; 1273955d011SMarcel Moolenaar #ifdef CLEANUP 128*06b9b3e0SSimon J. Gerraty /* The suffixes to be cleaned up at the end. */ 129*06b9b3e0SSimon J. Gerraty static SuffixList suffClean = LST_INIT; 1303955d011SMarcel Moolenaar #endif 131e2eeea75SSimon J. Gerraty 132*06b9b3e0SSimon J. Gerraty /* 133*06b9b3e0SSimon J. Gerraty * The transformation rules, such as '.c.o' to transform '.c' into '.o', 134*06b9b3e0SSimon J. Gerraty * or simply '.c' to transform 'file.c' into 'file'. 135*06b9b3e0SSimon J. Gerraty */ 136*06b9b3e0SSimon J. Gerraty static GNodeList transforms = LST_INIT; 1373955d011SMarcel Moolenaar 138*06b9b3e0SSimon J. Gerraty /* 139*06b9b3e0SSimon J. Gerraty * Counter for assigning suffix numbers. 140*06b9b3e0SSimon J. Gerraty * TODO: What are these suffix numbers used for? 141*06b9b3e0SSimon J. Gerraty */ 142*06b9b3e0SSimon J. Gerraty static int sNum = 0; 1433955d011SMarcel Moolenaar 144*06b9b3e0SSimon J. Gerraty typedef enum SuffixFlags { 145*06b9b3e0SSimon J. Gerraty SUFF_NONE = 0, 1462c3632d1SSimon J. Gerraty 147*06b9b3e0SSimon J. Gerraty /* 148*06b9b3e0SSimon J. Gerraty * This suffix marks include files. Their search path ends up in the 149*06b9b3e0SSimon J. Gerraty * undocumented special variable '.INCLUDES'. 150*06b9b3e0SSimon J. Gerraty */ 151*06b9b3e0SSimon J. Gerraty SUFF_INCLUDE = 1 << 0, 152*06b9b3e0SSimon J. Gerraty 153*06b9b3e0SSimon J. Gerraty /* 154*06b9b3e0SSimon J. Gerraty * This suffix marks library files. Their search path ends up in the 155*06b9b3e0SSimon J. Gerraty * undocumented special variable '.LIBS'. 156*06b9b3e0SSimon J. Gerraty */ 157*06b9b3e0SSimon J. Gerraty SUFF_LIBRARY = 1 << 1, 158*06b9b3e0SSimon J. Gerraty 159*06b9b3e0SSimon J. Gerraty /* 160*06b9b3e0SSimon J. Gerraty * The empty suffix. 161*06b9b3e0SSimon J. Gerraty * 162*06b9b3e0SSimon J. Gerraty * XXX: What is the difference between the empty suffix and the null 163*06b9b3e0SSimon J. Gerraty * suffix? 164*06b9b3e0SSimon J. Gerraty * 165*06b9b3e0SSimon J. Gerraty * XXX: Why is SUFF_NULL needed at all? Wouldn't nameLen == 0 mean 166*06b9b3e0SSimon J. Gerraty * the same? 167*06b9b3e0SSimon J. Gerraty */ 168*06b9b3e0SSimon J. Gerraty SUFF_NULL = 1 << 2 169*06b9b3e0SSimon J. Gerraty 170*06b9b3e0SSimon J. Gerraty } SuffixFlags; 171*06b9b3e0SSimon J. Gerraty 172*06b9b3e0SSimon J. Gerraty ENUM_FLAGS_RTTI_3(SuffixFlags, 1732c3632d1SSimon J. Gerraty SUFF_INCLUDE, SUFF_LIBRARY, SUFF_NULL); 1742c3632d1SSimon J. Gerraty 175*06b9b3e0SSimon J. Gerraty typedef List SuffixListList; 176956e45f6SSimon J. Gerraty 177*06b9b3e0SSimon J. Gerraty /* 178*06b9b3e0SSimon J. Gerraty * A suffix such as ".c" or ".o" that is used in suffix transformation rules 179*06b9b3e0SSimon J. Gerraty * such as ".c.o:". 180*06b9b3e0SSimon J. Gerraty */ 181*06b9b3e0SSimon J. Gerraty typedef struct Suffix { 182e2eeea75SSimon J. Gerraty /* The suffix itself, such as ".c" */ 183e2eeea75SSimon J. Gerraty char *name; 184e2eeea75SSimon J. Gerraty /* Length of the name, to avoid strlen calls */ 185e2eeea75SSimon J. Gerraty size_t nameLen; 186e2eeea75SSimon J. Gerraty /* Type of suffix */ 187*06b9b3e0SSimon J. Gerraty SuffixFlags flags; 188e2eeea75SSimon J. Gerraty /* The path along which files of this suffix may be found */ 189e2eeea75SSimon J. Gerraty SearchPath *searchPath; 190e2eeea75SSimon J. Gerraty /* The suffix number; TODO: document the purpose of this number */ 191e2eeea75SSimon J. Gerraty int sNum; 192e2eeea75SSimon J. Gerraty /* Reference count of list membership and several other places */ 193e2eeea75SSimon J. Gerraty int refCount; 194e2eeea75SSimon J. Gerraty /* Suffixes we have a transformation to */ 195*06b9b3e0SSimon J. Gerraty SuffixList parents; 196e2eeea75SSimon J. Gerraty /* Suffixes we have a transformation from */ 197*06b9b3e0SSimon J. Gerraty SuffixList children; 198e2eeea75SSimon J. Gerraty 199e2eeea75SSimon J. Gerraty /* Lists in which this suffix is referenced. 200*06b9b3e0SSimon J. Gerraty * 201*06b9b3e0SSimon J. Gerraty * XXX: These lists are used nowhere, they are just appended to, for 202*06b9b3e0SSimon J. Gerraty * no apparent reason. They do have the side effect of increasing 203*06b9b3e0SSimon J. Gerraty * refCount though. */ 204*06b9b3e0SSimon J. Gerraty SuffixListList ref; 205*06b9b3e0SSimon J. Gerraty } Suffix; 2063955d011SMarcel Moolenaar 2073955d011SMarcel Moolenaar /* 208*06b9b3e0SSimon J. Gerraty * A candidate when searching for implied sources. 209*06b9b3e0SSimon J. Gerraty * 210*06b9b3e0SSimon J. Gerraty * For example, when "src.o" is to be made, a typical candidate is "src.c" 211*06b9b3e0SSimon J. Gerraty * via the transformation rule ".c.o". If that doesn't exist, maybe there is 212*06b9b3e0SSimon J. Gerraty * another transformation rule ".pas.c" that would make "src.pas" an indirect 213*06b9b3e0SSimon J. Gerraty * candidate as well. The first such chain that leads to an existing file or 214*06b9b3e0SSimon J. Gerraty * node is finally chosen to be made. 2153955d011SMarcel Moolenaar */ 216*06b9b3e0SSimon J. Gerraty typedef struct Candidate { 217*06b9b3e0SSimon J. Gerraty /* The file or node to look for. */ 218*06b9b3e0SSimon J. Gerraty char *file; 219*06b9b3e0SSimon J. Gerraty /* The prefix from which file was formed. 220*06b9b3e0SSimon J. Gerraty * Its memory is shared among all candidates. */ 221*06b9b3e0SSimon J. Gerraty char *prefix; 222*06b9b3e0SSimon J. Gerraty /* The suffix on the file. */ 223*06b9b3e0SSimon J. Gerraty Suffix *suff; 224*06b9b3e0SSimon J. Gerraty 225*06b9b3e0SSimon J. Gerraty /* The candidate that can be made from this, 226*06b9b3e0SSimon J. Gerraty * or NULL for the top-level candidate. */ 227*06b9b3e0SSimon J. Gerraty struct Candidate *parent; 228*06b9b3e0SSimon J. Gerraty /* The node describing the file. */ 229*06b9b3e0SSimon J. Gerraty GNode *node; 230*06b9b3e0SSimon J. Gerraty 231*06b9b3e0SSimon J. Gerraty /* Count of existing children, only used for memory management, so we 232*06b9b3e0SSimon J. Gerraty * don't free this candidate too early or too late. */ 233*06b9b3e0SSimon J. Gerraty int numChildren; 2343955d011SMarcel Moolenaar #ifdef DEBUG_SRC 235*06b9b3e0SSimon J. Gerraty CandidateList childrenList; 2363955d011SMarcel Moolenaar #endif 237*06b9b3e0SSimon J. Gerraty } Candidate; 2383955d011SMarcel Moolenaar 239*06b9b3e0SSimon J. Gerraty typedef struct CandidateSearcher { 240*06b9b3e0SSimon J. Gerraty 241*06b9b3e0SSimon J. Gerraty CandidateList list; 242*06b9b3e0SSimon J. Gerraty 243*06b9b3e0SSimon J. Gerraty /* 244*06b9b3e0SSimon J. Gerraty * TODO: Add HashSet for seen entries, to avoid endless loops such as 245*06b9b3e0SSimon J. Gerraty * in suff-transform-endless.mk. 246*06b9b3e0SSimon J. Gerraty */ 247*06b9b3e0SSimon J. Gerraty 248*06b9b3e0SSimon J. Gerraty } CandidateSearcher; 249*06b9b3e0SSimon J. Gerraty 250*06b9b3e0SSimon J. Gerraty 251*06b9b3e0SSimon J. Gerraty /* TODO: Document the difference between nullSuff and emptySuff. */ 252e2eeea75SSimon J. Gerraty /* The NULL suffix for this run */ 253*06b9b3e0SSimon J. Gerraty static Suffix *nullSuff; 254e2eeea75SSimon J. Gerraty /* The empty suffix required for POSIX single-suffix transformation rules */ 255*06b9b3e0SSimon J. Gerraty static Suffix *emptySuff; 2563955d011SMarcel Moolenaar 2573955d011SMarcel Moolenaar 258*06b9b3e0SSimon J. Gerraty static Suffix * 259*06b9b3e0SSimon J. Gerraty Suffix_Ref(Suffix *suff) 260*06b9b3e0SSimon J. Gerraty { 261*06b9b3e0SSimon J. Gerraty suff->refCount++; 262*06b9b3e0SSimon J. Gerraty return suff; 263*06b9b3e0SSimon J. Gerraty } 264*06b9b3e0SSimon J. Gerraty 265*06b9b3e0SSimon J. Gerraty /* Change the value of a Suffix variable, adjusting the reference counts. */ 266*06b9b3e0SSimon J. Gerraty static void 267*06b9b3e0SSimon J. Gerraty Suffix_Reassign(Suffix **var, Suffix *suff) 268*06b9b3e0SSimon J. Gerraty { 269*06b9b3e0SSimon J. Gerraty if (*var != NULL) 270*06b9b3e0SSimon J. Gerraty (*var)->refCount--; 271*06b9b3e0SSimon J. Gerraty *var = suff; 272*06b9b3e0SSimon J. Gerraty suff->refCount++; 273*06b9b3e0SSimon J. Gerraty } 274*06b9b3e0SSimon J. Gerraty 275*06b9b3e0SSimon J. Gerraty /* Set a Suffix variable to NULL, adjusting the reference count. */ 276*06b9b3e0SSimon J. Gerraty static void 277*06b9b3e0SSimon J. Gerraty Suffix_Unassign(Suffix **var) 278*06b9b3e0SSimon J. Gerraty { 279*06b9b3e0SSimon J. Gerraty if (*var != NULL) 280*06b9b3e0SSimon J. Gerraty (*var)->refCount--; 281*06b9b3e0SSimon J. Gerraty *var = NULL; 282*06b9b3e0SSimon J. Gerraty } 2833955d011SMarcel Moolenaar 284e2eeea75SSimon J. Gerraty /* 2853955d011SMarcel Moolenaar * See if pref is a prefix of str. 286e2eeea75SSimon J. Gerraty * Return NULL if it ain't, pointer to character in str after prefix if so. 2873955d011SMarcel Moolenaar */ 2883955d011SMarcel Moolenaar static const char * 289*06b9b3e0SSimon J. Gerraty StrTrimPrefix(const char *pref, const char *str) 2903955d011SMarcel Moolenaar { 291*06b9b3e0SSimon J. Gerraty while (*str != '\0' && *pref == *str) { 2923955d011SMarcel Moolenaar pref++; 2933955d011SMarcel Moolenaar str++; 2943955d011SMarcel Moolenaar } 2953955d011SMarcel Moolenaar 296e2eeea75SSimon J. Gerraty return *pref != '\0' ? NULL : str; 2973955d011SMarcel Moolenaar } 2983955d011SMarcel Moolenaar 299e2eeea75SSimon J. Gerraty /* 300*06b9b3e0SSimon J. Gerraty * See if suff is a suffix of str, and if so, return the pointer to the suffix 301*06b9b3e0SSimon J. Gerraty * in str, which at the same time marks the end of the prefix. 3023955d011SMarcel Moolenaar */ 303956e45f6SSimon J. Gerraty static const char * 304*06b9b3e0SSimon J. Gerraty StrTrimSuffix(const char *str, size_t strLen, const char *suff, size_t suffLen) 3053955d011SMarcel Moolenaar { 306*06b9b3e0SSimon J. Gerraty const char *suffInStr; 307*06b9b3e0SSimon J. Gerraty size_t i; 3083955d011SMarcel Moolenaar 309*06b9b3e0SSimon J. Gerraty if (strLen < suffLen) 310*06b9b3e0SSimon J. Gerraty return NULL; 3113955d011SMarcel Moolenaar 312*06b9b3e0SSimon J. Gerraty suffInStr = str + strLen - suffLen; 313*06b9b3e0SSimon J. Gerraty for (i = 0; i < suffLen; i++) 314*06b9b3e0SSimon J. Gerraty if (suff[i] != suffInStr[i]) 315*06b9b3e0SSimon J. Gerraty return NULL; 3163955d011SMarcel Moolenaar 317*06b9b3e0SSimon J. Gerraty return suffInStr; 3183955d011SMarcel Moolenaar } 3193955d011SMarcel Moolenaar 320*06b9b3e0SSimon J. Gerraty /* 321*06b9b3e0SSimon J. Gerraty * See if suff is a suffix of name, and if so, return the end of the prefix 322*06b9b3e0SSimon J. Gerraty * in name. 323*06b9b3e0SSimon J. Gerraty */ 324*06b9b3e0SSimon J. Gerraty static const char * 325*06b9b3e0SSimon J. Gerraty Suffix_TrimSuffix(const Suffix *suff, size_t nameLen, const char *nameEnd) 326*06b9b3e0SSimon J. Gerraty { 327*06b9b3e0SSimon J. Gerraty return StrTrimSuffix(nameEnd - nameLen, nameLen, 328*06b9b3e0SSimon J. Gerraty suff->name, suff->nameLen); 3293955d011SMarcel Moolenaar } 3303955d011SMarcel Moolenaar 3312c3632d1SSimon J. Gerraty static Boolean 332*06b9b3e0SSimon J. Gerraty Suffix_IsSuffix(const Suffix *suff, size_t nameLen, const char *nameEnd) 3333955d011SMarcel Moolenaar { 334*06b9b3e0SSimon J. Gerraty return Suffix_TrimSuffix(suff, nameLen, nameEnd) != NULL; 3353955d011SMarcel Moolenaar } 3363955d011SMarcel Moolenaar 337*06b9b3e0SSimon J. Gerraty static Suffix * 338*06b9b3e0SSimon J. Gerraty FindSuffixByNameLen(const char *name, size_t nameLen) 3393955d011SMarcel Moolenaar { 340*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 341956e45f6SSimon J. Gerraty 342*06b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 343*06b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 344*06b9b3e0SSimon J. Gerraty if (suff->nameLen == nameLen && 345*06b9b3e0SSimon J. Gerraty memcmp(suff->name, name, nameLen) == 0) 346956e45f6SSimon J. Gerraty return suff; 347956e45f6SSimon J. Gerraty } 348956e45f6SSimon J. Gerraty return NULL; 3493955d011SMarcel Moolenaar } 3503955d011SMarcel Moolenaar 351*06b9b3e0SSimon J. Gerraty static Suffix * 352*06b9b3e0SSimon J. Gerraty FindSuffixByName(const char *name) 3533955d011SMarcel Moolenaar { 354*06b9b3e0SSimon J. Gerraty return FindSuffixByNameLen(name, strlen(name)); 3553955d011SMarcel Moolenaar } 3563955d011SMarcel Moolenaar 357956e45f6SSimon J. Gerraty static GNode * 358956e45f6SSimon J. Gerraty FindTransformByName(const char *name) 3593955d011SMarcel Moolenaar { 360956e45f6SSimon J. Gerraty GNodeListNode *ln; 361*06b9b3e0SSimon J. Gerraty 362*06b9b3e0SSimon J. Gerraty for (ln = transforms.first; ln != NULL; ln = ln->next) { 363956e45f6SSimon J. Gerraty GNode *gn = ln->datum; 364956e45f6SSimon J. Gerraty if (strcmp(gn->name, name) == 0) 365956e45f6SSimon J. Gerraty return gn; 366956e45f6SSimon J. Gerraty } 367956e45f6SSimon J. Gerraty return NULL; 3683955d011SMarcel Moolenaar } 3693955d011SMarcel Moolenaar 3703955d011SMarcel Moolenaar static void 371*06b9b3e0SSimon J. Gerraty SuffixList_Unref(SuffixList *list, Suffix *suff) 3723955d011SMarcel Moolenaar { 373*06b9b3e0SSimon J. Gerraty SuffixListNode *ln = Lst_FindDatum(list, suff); 3743955d011SMarcel Moolenaar if (ln != NULL) { 375956e45f6SSimon J. Gerraty Lst_Remove(list, ln); 376956e45f6SSimon J. Gerraty suff->refCount--; 3773955d011SMarcel Moolenaar } 3783955d011SMarcel Moolenaar } 3793955d011SMarcel Moolenaar 3802c3632d1SSimon J. Gerraty /* Free up all memory associated with the given suffix structure. */ 3813955d011SMarcel Moolenaar static void 382*06b9b3e0SSimon J. Gerraty Suffix_Free(Suffix *suff) 3833955d011SMarcel Moolenaar { 3843955d011SMarcel Moolenaar 385*06b9b3e0SSimon J. Gerraty if (suff == nullSuff) 386*06b9b3e0SSimon J. Gerraty nullSuff = NULL; 3873955d011SMarcel Moolenaar 388e2eeea75SSimon J. Gerraty if (suff == emptySuff) 3893955d011SMarcel Moolenaar emptySuff = NULL; 3903955d011SMarcel Moolenaar 391956e45f6SSimon J. Gerraty #if 0 3923955d011SMarcel Moolenaar /* We don't delete suffixes in order, so we cannot use this */ 393e2eeea75SSimon J. Gerraty if (suff->refCount != 0) 394e2eeea75SSimon J. Gerraty Punt("Internal error deleting suffix `%s' with refcount = %d", 395e2eeea75SSimon J. Gerraty suff->name, suff->refCount); 3963955d011SMarcel Moolenaar #endif 3973955d011SMarcel Moolenaar 398*06b9b3e0SSimon J. Gerraty Lst_Done(&suff->ref); 399*06b9b3e0SSimon J. Gerraty Lst_Done(&suff->children); 400*06b9b3e0SSimon J. Gerraty Lst_Done(&suff->parents); 401*06b9b3e0SSimon J. Gerraty SearchPath_Free(suff->searchPath); 4023955d011SMarcel Moolenaar 403e2eeea75SSimon J. Gerraty free(suff->name); 404e2eeea75SSimon J. Gerraty free(suff); 4053955d011SMarcel Moolenaar } 4063955d011SMarcel Moolenaar 407*06b9b3e0SSimon J. Gerraty static void 408*06b9b3e0SSimon J. Gerraty SuffFree(void *p) 409*06b9b3e0SSimon J. Gerraty { 410*06b9b3e0SSimon J. Gerraty Suffix_Free(p); 411*06b9b3e0SSimon J. Gerraty } 412*06b9b3e0SSimon J. Gerraty 4132c3632d1SSimon J. Gerraty /* Remove the suffix from the list, and free if it is otherwise unused. */ 4143955d011SMarcel Moolenaar static void 415*06b9b3e0SSimon J. Gerraty SuffixList_Remove(SuffixList *list, Suffix *suff) 4163955d011SMarcel Moolenaar { 417*06b9b3e0SSimon J. Gerraty SuffixList_Unref(list, suff); 418956e45f6SSimon J. Gerraty if (suff->refCount == 0) { 419e2eeea75SSimon J. Gerraty /* XXX: can lead to suff->refCount == -1 */ 420*06b9b3e0SSimon J. Gerraty SuffixList_Unref(&sufflist, suff); 421*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Removing suffix \"%s\"\n", suff->name); 422956e45f6SSimon J. Gerraty SuffFree(suff); 4233955d011SMarcel Moolenaar } 4243955d011SMarcel Moolenaar } 4252c3632d1SSimon J. Gerraty 426*06b9b3e0SSimon J. Gerraty /* 427*06b9b3e0SSimon J. Gerraty * Insert the suffix into the list, keeping the list ordered by suffix 428*06b9b3e0SSimon J. Gerraty * number. 429*06b9b3e0SSimon J. Gerraty */ 4303955d011SMarcel Moolenaar static void 431*06b9b3e0SSimon J. Gerraty SuffixList_Insert(SuffixList *list, Suffix *suff) 4323955d011SMarcel Moolenaar { 433*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 434*06b9b3e0SSimon J. Gerraty Suffix *listSuff = NULL; 4353955d011SMarcel Moolenaar 436956e45f6SSimon J. Gerraty for (ln = list->first; ln != NULL; ln = ln->next) { 437956e45f6SSimon J. Gerraty listSuff = ln->datum; 438956e45f6SSimon J. Gerraty if (listSuff->sNum >= suff->sNum) 4393955d011SMarcel Moolenaar break; 4403955d011SMarcel Moolenaar } 4412c3632d1SSimon J. Gerraty 4423955d011SMarcel Moolenaar if (ln == NULL) { 443*06b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "inserting \"%s\" (%d) at end of list\n", 444956e45f6SSimon J. Gerraty suff->name, suff->sNum); 445*06b9b3e0SSimon J. Gerraty Lst_Append(list, Suffix_Ref(suff)); 446*06b9b3e0SSimon J. Gerraty Lst_Append(&suff->ref, list); 447956e45f6SSimon J. Gerraty } else if (listSuff->sNum != suff->sNum) { 448e2eeea75SSimon J. Gerraty DEBUG4(SUFF, "inserting \"%s\" (%d) before \"%s\" (%d)\n", 449956e45f6SSimon J. Gerraty suff->name, suff->sNum, listSuff->name, listSuff->sNum); 450*06b9b3e0SSimon J. Gerraty Lst_InsertBefore(list, ln, Suffix_Ref(suff)); 451*06b9b3e0SSimon J. Gerraty Lst_Append(&suff->ref, list); 4522c3632d1SSimon J. Gerraty } else { 453*06b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "\"%s\" (%d) is already there\n", 454*06b9b3e0SSimon J. Gerraty suff->name, suff->sNum); 4553955d011SMarcel Moolenaar } 4563955d011SMarcel Moolenaar } 4573955d011SMarcel Moolenaar 458e2eeea75SSimon J. Gerraty static void 459*06b9b3e0SSimon J. Gerraty Relate(Suffix *srcSuff, Suffix *targSuff) 460e2eeea75SSimon J. Gerraty { 461*06b9b3e0SSimon J. Gerraty SuffixList_Insert(&targSuff->children, srcSuff); 462*06b9b3e0SSimon J. Gerraty SuffixList_Insert(&srcSuff->parents, targSuff); 463e2eeea75SSimon J. Gerraty } 464e2eeea75SSimon J. Gerraty 465*06b9b3e0SSimon J. Gerraty static Suffix * 466*06b9b3e0SSimon J. Gerraty Suffix_New(const char *name) 4672c3632d1SSimon J. Gerraty { 468*06b9b3e0SSimon J. Gerraty Suffix *suff = bmake_malloc(sizeof *suff); 4692c3632d1SSimon J. Gerraty 470e2eeea75SSimon J. Gerraty suff->name = bmake_strdup(name); 471e2eeea75SSimon J. Gerraty suff->nameLen = strlen(suff->name); 472*06b9b3e0SSimon J. Gerraty suff->searchPath = SearchPath_New(); 473*06b9b3e0SSimon J. Gerraty Lst_Init(&suff->children); 474*06b9b3e0SSimon J. Gerraty Lst_Init(&suff->parents); 475*06b9b3e0SSimon J. Gerraty Lst_Init(&suff->ref); 476e2eeea75SSimon J. Gerraty suff->sNum = sNum++; 477*06b9b3e0SSimon J. Gerraty suff->flags = SUFF_NONE; 478e2eeea75SSimon J. Gerraty suff->refCount = 1; /* XXX: why 1? It's not assigned anywhere yet. */ 4792c3632d1SSimon J. Gerraty 480e2eeea75SSimon J. Gerraty return suff; 4812c3632d1SSimon J. Gerraty } 4822c3632d1SSimon J. Gerraty 483e2eeea75SSimon J. Gerraty /* 484e2eeea75SSimon J. Gerraty * Nuke the list of suffixes but keep all transformation rules around. The 485e2eeea75SSimon J. Gerraty * transformation graph is destroyed in this process, but we leave the list 486e2eeea75SSimon J. Gerraty * of rules so when a new graph is formed, the rules will remain. This 487e2eeea75SSimon J. Gerraty * function is called when a line '.SUFFIXES:' with an empty suffixes list is 488e2eeea75SSimon J. Gerraty * encountered in a makefile. 489e2eeea75SSimon J. Gerraty */ 4903955d011SMarcel Moolenaar void 4913955d011SMarcel Moolenaar Suff_ClearSuffixes(void) 4923955d011SMarcel Moolenaar { 4933955d011SMarcel Moolenaar #ifdef CLEANUP 494*06b9b3e0SSimon J. Gerraty Lst_MoveAll(&suffClean, &sufflist); 4953955d011SMarcel Moolenaar #endif 496*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "Clearing all suffixes\n"); 497*06b9b3e0SSimon J. Gerraty Lst_Init(&sufflist); 4983955d011SMarcel Moolenaar sNum = 0; 499*06b9b3e0SSimon J. Gerraty if (nullSuff != NULL) 500*06b9b3e0SSimon J. Gerraty SuffFree(nullSuff); 501*06b9b3e0SSimon J. Gerraty emptySuff = nullSuff = Suffix_New(""); 5026e050540SSimon J. Gerraty 503*06b9b3e0SSimon J. Gerraty SearchPath_AddAll(nullSuff->searchPath, &dirSearchPath); 504*06b9b3e0SSimon J. Gerraty nullSuff->flags = SUFF_NULL; 5053955d011SMarcel Moolenaar } 5063955d011SMarcel Moolenaar 507*06b9b3e0SSimon J. Gerraty /* 508*06b9b3e0SSimon J. Gerraty * Parse a transformation string such as ".c.o" to find its two component 509956e45f6SSimon J. Gerraty * suffixes (the source ".c" and the target ".o"). If there are no such 510956e45f6SSimon J. Gerraty * suffixes, try a single-suffix transformation as well. 5113955d011SMarcel Moolenaar * 512956e45f6SSimon J. Gerraty * Return TRUE if the string is a valid transformation. 5133955d011SMarcel Moolenaar */ 5143955d011SMarcel Moolenaar static Boolean 515*06b9b3e0SSimon J. Gerraty ParseTransform(const char *str, Suffix **out_src, Suffix **out_targ) 5163955d011SMarcel Moolenaar { 517*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 518*06b9b3e0SSimon J. Gerraty Suffix *single = NULL; 5193955d011SMarcel Moolenaar 5203955d011SMarcel Moolenaar /* 5213955d011SMarcel Moolenaar * Loop looking first for a suffix that matches the start of the 5223955d011SMarcel Moolenaar * string and then for one that exactly matches the rest of it. If 5233955d011SMarcel Moolenaar * we can find two that meet these criteria, we've successfully 5243955d011SMarcel Moolenaar * parsed the string. 5253955d011SMarcel Moolenaar */ 526*06b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 527*06b9b3e0SSimon J. Gerraty Suffix *src = ln->datum; 528956e45f6SSimon J. Gerraty 529*06b9b3e0SSimon J. Gerraty if (StrTrimPrefix(src->name, str) == NULL) 530956e45f6SSimon J. Gerraty continue; 531956e45f6SSimon J. Gerraty 532956e45f6SSimon J. Gerraty if (str[src->nameLen] == '\0') { 533*06b9b3e0SSimon J. Gerraty single = src; 5343955d011SMarcel Moolenaar } else { 535*06b9b3e0SSimon J. Gerraty Suffix *targ = FindSuffixByName(str + src->nameLen); 536956e45f6SSimon J. Gerraty if (targ != NULL) { 537956e45f6SSimon J. Gerraty *out_src = src; 538956e45f6SSimon J. Gerraty *out_targ = targ; 539956e45f6SSimon J. Gerraty return TRUE; 5403955d011SMarcel Moolenaar } 541956e45f6SSimon J. Gerraty } 542956e45f6SSimon J. Gerraty } 543956e45f6SSimon J. Gerraty 544*06b9b3e0SSimon J. Gerraty if (single != NULL) { 5453955d011SMarcel Moolenaar /* 546*06b9b3e0SSimon J. Gerraty * There was a suffix that encompassed the entire string, so we 547*06b9b3e0SSimon J. Gerraty * assume it was a transformation to the null suffix (thank you 548*06b9b3e0SSimon J. Gerraty * POSIX; search for "single suffix" or "single-suffix"). 5493955d011SMarcel Moolenaar * 550*06b9b3e0SSimon J. Gerraty * We still prefer to find a double rule over a singleton, 551*06b9b3e0SSimon J. Gerraty * hence we leave this check until the end. 552*06b9b3e0SSimon J. Gerraty * 553*06b9b3e0SSimon J. Gerraty * XXX: Use emptySuff over nullSuff? 5543955d011SMarcel Moolenaar */ 555*06b9b3e0SSimon J. Gerraty *out_src = single; 556*06b9b3e0SSimon J. Gerraty *out_targ = nullSuff; 5573841c287SSimon J. Gerraty return TRUE; 5583955d011SMarcel Moolenaar } 5593841c287SSimon J. Gerraty return FALSE; 5603955d011SMarcel Moolenaar } 5613955d011SMarcel Moolenaar 562*06b9b3e0SSimon J. Gerraty /* 563*06b9b3e0SSimon J. Gerraty * Return TRUE if the given string is a transformation rule, that is, a 564e2eeea75SSimon J. Gerraty * concatenation of two known suffixes such as ".c.o" or a single suffix 565*06b9b3e0SSimon J. Gerraty * such as ".o". 566*06b9b3e0SSimon J. Gerraty */ 5673955d011SMarcel Moolenaar Boolean 568956e45f6SSimon J. Gerraty Suff_IsTransform(const char *str) 5693955d011SMarcel Moolenaar { 570*06b9b3e0SSimon J. Gerraty Suffix *src, *targ; 5713955d011SMarcel Moolenaar 572*06b9b3e0SSimon J. Gerraty return ParseTransform(str, &src, &targ); 5733955d011SMarcel Moolenaar } 5743955d011SMarcel Moolenaar 575*06b9b3e0SSimon J. Gerraty /* 576*06b9b3e0SSimon J. Gerraty * Add the transformation rule to the list of rules and place the 577956e45f6SSimon J. Gerraty * transformation itself in the graph. 5783955d011SMarcel Moolenaar * 579956e45f6SSimon J. Gerraty * The transformation is linked to the two suffixes mentioned in the name. 580956e45f6SSimon J. Gerraty * 5813955d011SMarcel Moolenaar * Input: 582956e45f6SSimon J. Gerraty * name must have the form ".from.to" or just ".from" 5833955d011SMarcel Moolenaar * 5843955d011SMarcel Moolenaar * Results: 585956e45f6SSimon J. Gerraty * The created or existing transformation node in the transforms list 5863955d011SMarcel Moolenaar */ 5873955d011SMarcel Moolenaar GNode * 588956e45f6SSimon J. Gerraty Suff_AddTransform(const char *name) 5893955d011SMarcel Moolenaar { 590*06b9b3e0SSimon J. Gerraty Suffix *srcSuff; 591*06b9b3e0SSimon J. Gerraty Suffix *targSuff; 5923955d011SMarcel Moolenaar 593e2eeea75SSimon J. Gerraty GNode *gn = FindTransformByName(name); 594956e45f6SSimon J. Gerraty if (gn == NULL) { 5953955d011SMarcel Moolenaar /* 596*06b9b3e0SSimon J. Gerraty * Make a new graph node for the transformation. It will be 597*06b9b3e0SSimon J. Gerraty * filled in by the Parse module. 5983955d011SMarcel Moolenaar */ 599e2eeea75SSimon J. Gerraty gn = GNode_New(name); 600*06b9b3e0SSimon J. Gerraty Lst_Append(&transforms, gn); 6013955d011SMarcel Moolenaar } else { 6023955d011SMarcel Moolenaar /* 603*06b9b3e0SSimon J. Gerraty * New specification for transformation rule. Just nuke the 604*06b9b3e0SSimon J. Gerraty * old list of commands so they can be filled in again. We 605*06b9b3e0SSimon J. Gerraty * don't actually free the commands themselves, because a 606*06b9b3e0SSimon J. Gerraty * given command can be attached to several different 607*06b9b3e0SSimon J. Gerraty * transformations. 6083955d011SMarcel Moolenaar */ 609*06b9b3e0SSimon J. Gerraty Lst_Done(&gn->commands); 610*06b9b3e0SSimon J. Gerraty Lst_Init(&gn->commands); 611*06b9b3e0SSimon J. Gerraty Lst_Done(&gn->children); 612*06b9b3e0SSimon J. Gerraty Lst_Init(&gn->children); 6133955d011SMarcel Moolenaar } 6143955d011SMarcel Moolenaar 6153955d011SMarcel Moolenaar gn->type = OP_TRANSFORM; 6163955d011SMarcel Moolenaar 617e2eeea75SSimon J. Gerraty { 618*06b9b3e0SSimon J. Gerraty /* TODO: Avoid the redundant parsing here. */ 619*06b9b3e0SSimon J. Gerraty Boolean ok = ParseTransform(name, &srcSuff, &targSuff); 6202c3632d1SSimon J. Gerraty assert(ok); 6212c3632d1SSimon J. Gerraty (void)ok; 622e2eeea75SSimon J. Gerraty } 6233955d011SMarcel Moolenaar 624*06b9b3e0SSimon J. Gerraty /* Link the two together in the proper relationship and order. */ 625*06b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "defining transformation from `%s' to `%s'\n", 626e2eeea75SSimon J. Gerraty srcSuff->name, targSuff->name); 627*06b9b3e0SSimon J. Gerraty Relate(srcSuff, targSuff); 6283955d011SMarcel Moolenaar 6293841c287SSimon J. Gerraty return gn; 6303955d011SMarcel Moolenaar } 6313955d011SMarcel Moolenaar 632*06b9b3e0SSimon J. Gerraty /* 633*06b9b3e0SSimon J. Gerraty * Handle the finish of a transformation definition, removing the 6342c3632d1SSimon J. Gerraty * transformation from the graph if it has neither commands nor sources. 6352c3632d1SSimon J. Gerraty * 6362c3632d1SSimon J. Gerraty * If the node has no commands or children, the children and parents lists 6372c3632d1SSimon J. Gerraty * of the affected suffixes are altered. 6383955d011SMarcel Moolenaar * 6393955d011SMarcel Moolenaar * Input: 640956e45f6SSimon J. Gerraty * gn Node for transformation 6413955d011SMarcel Moolenaar */ 642956e45f6SSimon J. Gerraty void 643956e45f6SSimon J. Gerraty Suff_EndTransform(GNode *gn) 6443955d011SMarcel Moolenaar { 645*06b9b3e0SSimon J. Gerraty Suffix *srcSuff, *targSuff; 646*06b9b3e0SSimon J. Gerraty SuffixList *srcSuffParents; 647e2eeea75SSimon J. Gerraty 648*06b9b3e0SSimon J. Gerraty if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&gn->cohorts)) 649*06b9b3e0SSimon J. Gerraty gn = gn->cohorts.last->datum; 650*06b9b3e0SSimon J. Gerraty 651*06b9b3e0SSimon J. Gerraty if (!(gn->type & OP_TRANSFORM)) 652*06b9b3e0SSimon J. Gerraty return; 653*06b9b3e0SSimon J. Gerraty 654*06b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&gn->commands) || !Lst_IsEmpty(&gn->children)) { 655*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "transformation %s complete\n", gn->name); 656*06b9b3e0SSimon J. Gerraty return; 657*06b9b3e0SSimon J. Gerraty } 6583955d011SMarcel Moolenaar 6593955d011SMarcel Moolenaar /* 6603955d011SMarcel Moolenaar * SuffParseTransform() may fail for special rules which are not 6613955d011SMarcel Moolenaar * actual transformation rules. (e.g. .DEFAULT) 6623955d011SMarcel Moolenaar */ 663*06b9b3e0SSimon J. Gerraty if (!ParseTransform(gn->name, &srcSuff, &targSuff)) 664*06b9b3e0SSimon J. Gerraty return; 665e2eeea75SSimon J. Gerraty 666*06b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "deleting incomplete transformation from `%s' to `%s'\n", 667e2eeea75SSimon J. Gerraty srcSuff->name, targSuff->name); 6683955d011SMarcel Moolenaar 669*06b9b3e0SSimon J. Gerraty /* 670*06b9b3e0SSimon J. Gerraty * Remember the parents since srcSuff could be deleted in 671*06b9b3e0SSimon J. Gerraty * SuffixList_Remove. 672*06b9b3e0SSimon J. Gerraty */ 673*06b9b3e0SSimon J. Gerraty srcSuffParents = &srcSuff->parents; 674*06b9b3e0SSimon J. Gerraty SuffixList_Remove(&targSuff->children, srcSuff); 675*06b9b3e0SSimon J. Gerraty SuffixList_Remove(srcSuffParents, targSuff); 6763955d011SMarcel Moolenaar } 6773955d011SMarcel Moolenaar 678*06b9b3e0SSimon J. Gerraty /* 679*06b9b3e0SSimon J. Gerraty * Called from Suff_AddSuffix to search through the list of 6802c3632d1SSimon J. Gerraty * existing transformation rules and rebuild the transformation graph when 6812c3632d1SSimon J. Gerraty * it has been destroyed by Suff_ClearSuffixes. If the given rule is a 6822c3632d1SSimon J. Gerraty * transformation involving this suffix and another, existing suffix, the 6832c3632d1SSimon J. Gerraty * proper relationship is established between the two. 6842c3632d1SSimon J. Gerraty * 6852c3632d1SSimon J. Gerraty * The appropriate links will be made between this suffix and others if 6862c3632d1SSimon J. Gerraty * transformation rules exist for it. 6873955d011SMarcel Moolenaar * 6883955d011SMarcel Moolenaar * Input: 689956e45f6SSimon J. Gerraty * transform Transformation to test 690956e45f6SSimon J. Gerraty * suff Suffix to rebuild 6913955d011SMarcel Moolenaar */ 692956e45f6SSimon J. Gerraty static void 693*06b9b3e0SSimon J. Gerraty RebuildGraph(GNode *transform, Suffix *suff) 6943955d011SMarcel Moolenaar { 695956e45f6SSimon J. Gerraty const char *name = transform->name; 696956e45f6SSimon J. Gerraty size_t nameLen = strlen(name); 697956e45f6SSimon J. Gerraty const char *toName; 6983955d011SMarcel Moolenaar 699*06b9b3e0SSimon J. Gerraty /* See if it is a transformation from this suffix to another suffix. */ 700*06b9b3e0SSimon J. Gerraty toName = StrTrimPrefix(suff->name, name); 701956e45f6SSimon J. Gerraty if (toName != NULL) { 702*06b9b3e0SSimon J. Gerraty Suffix *to = FindSuffixByName(toName); 703956e45f6SSimon J. Gerraty if (to != NULL) { 704*06b9b3e0SSimon J. Gerraty Relate(suff, to); 705956e45f6SSimon J. Gerraty return; 7063955d011SMarcel Moolenaar } 7073955d011SMarcel Moolenaar } 7083955d011SMarcel Moolenaar 709*06b9b3e0SSimon J. Gerraty /* See if it is a transformation from another suffix to this suffix. */ 710*06b9b3e0SSimon J. Gerraty toName = Suffix_TrimSuffix(suff, nameLen, name + nameLen); 711956e45f6SSimon J. Gerraty if (toName != NULL) { 712*06b9b3e0SSimon J. Gerraty Suffix *from = FindSuffixByNameLen(name, 713*06b9b3e0SSimon J. Gerraty (size_t)(toName - name)); 714e2eeea75SSimon J. Gerraty if (from != NULL) 715*06b9b3e0SSimon J. Gerraty Relate(from, suff); 7163955d011SMarcel Moolenaar } 7173955d011SMarcel Moolenaar } 7183955d011SMarcel Moolenaar 719*06b9b3e0SSimon J. Gerraty /* 720*06b9b3e0SSimon J. Gerraty * During Suff_AddSuffix, search through the list of existing targets and find 721956e45f6SSimon J. Gerraty * if any of the existing targets can be turned into a transformation rule. 7222c3632d1SSimon J. Gerraty * 7232c3632d1SSimon J. Gerraty * If such a target is found and the target is the current main target, the 7242c3632d1SSimon J. Gerraty * main target is set to NULL and the next target examined (if that exists) 7252c3632d1SSimon J. Gerraty * becomes the main target. 7263955d011SMarcel Moolenaar * 7273955d011SMarcel Moolenaar * Results: 728956e45f6SSimon J. Gerraty * TRUE iff a new main target has been selected. 7293955d011SMarcel Moolenaar */ 730956e45f6SSimon J. Gerraty static Boolean 731*06b9b3e0SSimon J. Gerraty UpdateTarget(GNode *target, GNode **inout_main, Suffix *suff, 732*06b9b3e0SSimon J. Gerraty Boolean *inout_removedMain) 7333955d011SMarcel Moolenaar { 734*06b9b3e0SSimon J. Gerraty Suffix *srcSuff, *targSuff; 7353955d011SMarcel Moolenaar char *ptr; 7363955d011SMarcel Moolenaar 737*06b9b3e0SSimon J. Gerraty if (*inout_main == NULL && *inout_removedMain && 738*06b9b3e0SSimon J. Gerraty !(target->type & OP_NOTARGET)) { 739*06b9b3e0SSimon J. Gerraty DEBUG1(MAKE, "Setting main node to \"%s\"\n", target->name); 740956e45f6SSimon J. Gerraty *inout_main = target; 7413955d011SMarcel Moolenaar Targ_SetMain(target); 742*06b9b3e0SSimon J. Gerraty /* 743*06b9b3e0SSimon J. Gerraty * XXX: Why could it be a good idea to return TRUE here? 744*06b9b3e0SSimon J. Gerraty * The main task of this function is to turn ordinary nodes 745*06b9b3e0SSimon J. Gerraty * into transformations, no matter whether or not a new .MAIN 746*06b9b3e0SSimon J. Gerraty * node has been found. 747*06b9b3e0SSimon J. Gerraty */ 748*06b9b3e0SSimon J. Gerraty /* 749*06b9b3e0SSimon J. Gerraty * XXX: Even when changing this to FALSE, none of the existing 750*06b9b3e0SSimon J. Gerraty * unit tests fails. 751*06b9b3e0SSimon J. Gerraty */ 752956e45f6SSimon J. Gerraty return TRUE; 7533955d011SMarcel Moolenaar } 7543955d011SMarcel Moolenaar 7552c3632d1SSimon J. Gerraty if (target->type == OP_TRANSFORM) 756956e45f6SSimon J. Gerraty return FALSE; 7573955d011SMarcel Moolenaar 758*06b9b3e0SSimon J. Gerraty /* 759*06b9b3e0SSimon J. Gerraty * XXX: What about a transformation ".cpp.c"? If ".c" is added as 760*06b9b3e0SSimon J. Gerraty * a new suffix, it seems wrong that this transformation would be 761*06b9b3e0SSimon J. Gerraty * skipped just because ".c" happens to be a prefix of ".cpp". 762*06b9b3e0SSimon J. Gerraty */ 763*06b9b3e0SSimon J. Gerraty ptr = strstr(target->name, suff->name); 764*06b9b3e0SSimon J. Gerraty if (ptr == NULL) 765956e45f6SSimon J. Gerraty return FALSE; 7663955d011SMarcel Moolenaar 767*06b9b3e0SSimon J. Gerraty /* 768*06b9b3e0SSimon J. Gerraty * XXX: In suff-rebuild.mk, in the line '.SUFFIXES: .c .b .a', this 769*06b9b3e0SSimon J. Gerraty * condition prevents the rule '.b.c' from being added again during 770*06b9b3e0SSimon J. Gerraty * Suff_AddSuffix(".b"). 771*06b9b3e0SSimon J. Gerraty * 772*06b9b3e0SSimon J. Gerraty * XXX: Removing this paragraph makes suff-add-later.mk use massive 773*06b9b3e0SSimon J. Gerraty * amounts of memory. 774*06b9b3e0SSimon J. Gerraty */ 775*06b9b3e0SSimon J. Gerraty if (ptr == target->name) 776*06b9b3e0SSimon J. Gerraty return FALSE; 777*06b9b3e0SSimon J. Gerraty 778*06b9b3e0SSimon J. Gerraty if (ParseTransform(target->name, &srcSuff, &targSuff)) { 779956e45f6SSimon J. Gerraty if (*inout_main == target) { 780*06b9b3e0SSimon J. Gerraty DEBUG1(MAKE, 781*06b9b3e0SSimon J. Gerraty "Setting main node from \"%s\" back to null\n", 782*06b9b3e0SSimon J. Gerraty target->name); 783*06b9b3e0SSimon J. Gerraty *inout_removedMain = TRUE; 784956e45f6SSimon J. Gerraty *inout_main = NULL; 7853955d011SMarcel Moolenaar Targ_SetMain(NULL); 7863955d011SMarcel Moolenaar } 787*06b9b3e0SSimon J. Gerraty Lst_Done(&target->children); 788*06b9b3e0SSimon J. Gerraty Lst_Init(&target->children); 7893955d011SMarcel Moolenaar target->type = OP_TRANSFORM; 790*06b9b3e0SSimon J. Gerraty 7913955d011SMarcel Moolenaar /* 792*06b9b3e0SSimon J. Gerraty * Link the two together in the proper relationship and order. 7933955d011SMarcel Moolenaar */ 794*06b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "defining transformation from `%s' to `%s'\n", 795e2eeea75SSimon J. Gerraty srcSuff->name, targSuff->name); 796*06b9b3e0SSimon J. Gerraty Relate(srcSuff, targSuff); 7973955d011SMarcel Moolenaar } 798956e45f6SSimon J. Gerraty return FALSE; 799956e45f6SSimon J. Gerraty } 800956e45f6SSimon J. Gerraty 801*06b9b3e0SSimon J. Gerraty /* 802*06b9b3e0SSimon J. Gerraty * Look at all existing targets to see if adding this suffix will make one 803956e45f6SSimon J. Gerraty * of the current targets mutate into a suffix rule. 804956e45f6SSimon J. Gerraty * 805956e45f6SSimon J. Gerraty * This is ugly, but other makes treat all targets that start with a '.' as 806*06b9b3e0SSimon J. Gerraty * suffix rules. 807*06b9b3e0SSimon J. Gerraty */ 808956e45f6SSimon J. Gerraty static void 809*06b9b3e0SSimon J. Gerraty UpdateTargets(GNode **inout_main, Suffix *suff) 810956e45f6SSimon J. Gerraty { 811*06b9b3e0SSimon J. Gerraty Boolean removedMain = FALSE; 812956e45f6SSimon J. Gerraty GNodeListNode *ln; 813*06b9b3e0SSimon J. Gerraty 814956e45f6SSimon J. Gerraty for (ln = Targ_List()->first; ln != NULL; ln = ln->next) { 815956e45f6SSimon J. Gerraty GNode *gn = ln->datum; 816*06b9b3e0SSimon J. Gerraty if (UpdateTarget(gn, inout_main, suff, &removedMain)) 817956e45f6SSimon J. Gerraty break; 818956e45f6SSimon J. Gerraty } 8193955d011SMarcel Moolenaar } 8203955d011SMarcel Moolenaar 821*06b9b3e0SSimon J. Gerraty /* 822*06b9b3e0SSimon J. Gerraty * Add the suffix to the end of the list of known suffixes. 823*06b9b3e0SSimon J. Gerraty * Should we restructure the suffix graph? Make doesn't. 8243955d011SMarcel Moolenaar * 825*06b9b3e0SSimon J. Gerraty * A GNode is created for the suffix (XXX: this sounds completely wrong) and 826*06b9b3e0SSimon J. Gerraty * a Suffix structure is created and added to the suffixes list unless the 827*06b9b3e0SSimon J. Gerraty * suffix was already known. 8283955d011SMarcel Moolenaar * The mainNode passed can be modified if a target mutated into a 8293955d011SMarcel Moolenaar * transform and that target happened to be the main target. 8302c3632d1SSimon J. Gerraty * 8312c3632d1SSimon J. Gerraty * Input: 8322c3632d1SSimon J. Gerraty * name the name of the suffix to add 8333955d011SMarcel Moolenaar */ 8343955d011SMarcel Moolenaar void 835956e45f6SSimon J. Gerraty Suff_AddSuffix(const char *name, GNode **inout_main) 8363955d011SMarcel Moolenaar { 837956e45f6SSimon J. Gerraty GNodeListNode *ln; 8383955d011SMarcel Moolenaar 839*06b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(name); 840*06b9b3e0SSimon J. Gerraty if (suff != NULL) 841956e45f6SSimon J. Gerraty return; 842956e45f6SSimon J. Gerraty 843*06b9b3e0SSimon J. Gerraty suff = Suffix_New(name); 844*06b9b3e0SSimon J. Gerraty Lst_Append(&sufflist, suff); 845*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Adding suffix \"%s\"\n", suff->name); 846956e45f6SSimon J. Gerraty 847*06b9b3e0SSimon J. Gerraty UpdateTargets(inout_main, suff); 848956e45f6SSimon J. Gerraty 8493955d011SMarcel Moolenaar /* 8503955d011SMarcel Moolenaar * Look for any existing transformations from or to this suffix. 8513955d011SMarcel Moolenaar * XXX: Only do this after a Suff_ClearSuffixes? 8523955d011SMarcel Moolenaar */ 853*06b9b3e0SSimon J. Gerraty for (ln = transforms.first; ln != NULL; ln = ln->next) 854*06b9b3e0SSimon J. Gerraty RebuildGraph(ln->datum, suff); 8553955d011SMarcel Moolenaar } 8563955d011SMarcel Moolenaar 8572c3632d1SSimon J. Gerraty /* Return the search path for the given suffix, or NULL. */ 858956e45f6SSimon J. Gerraty SearchPath * 859956e45f6SSimon J. Gerraty Suff_GetPath(const char *sname) 8603955d011SMarcel Moolenaar { 861*06b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(sname); 862*06b9b3e0SSimon J. Gerraty return suff != NULL ? suff->searchPath : NULL; 8633955d011SMarcel Moolenaar } 8643955d011SMarcel Moolenaar 865e2eeea75SSimon J. Gerraty /* 866e2eeea75SSimon J. Gerraty * Extend the search paths for all suffixes to include the default search 867e2eeea75SSimon J. Gerraty * path (dirSearchPath). 8683955d011SMarcel Moolenaar * 869e2eeea75SSimon J. Gerraty * The default search path can be defined using the special target '.PATH'. 870e2eeea75SSimon J. Gerraty * The search path of each suffix can be defined using the special target 871e2eeea75SSimon J. Gerraty * '.PATH<suffix>'. 872e2eeea75SSimon J. Gerraty * 873e2eeea75SSimon J. Gerraty * If paths were specified for the ".h" suffix, the directories are stuffed 874e2eeea75SSimon J. Gerraty * into a global variable called ".INCLUDES" with each directory preceded by 875e2eeea75SSimon J. Gerraty * '-I'. The same is done for the ".a" suffix, except the variable is called 876e2eeea75SSimon J. Gerraty * ".LIBS" and the flag is '-L'. 8773955d011SMarcel Moolenaar */ 8783955d011SMarcel Moolenaar void 8793955d011SMarcel Moolenaar Suff_DoPaths(void) 8803955d011SMarcel Moolenaar { 881*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 882*06b9b3e0SSimon J. Gerraty char *flags; 883*06b9b3e0SSimon J. Gerraty SearchPath *includesPath = SearchPath_New(); 884*06b9b3e0SSimon J. Gerraty SearchPath *libsPath = SearchPath_New(); 8853955d011SMarcel Moolenaar 886*06b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 887*06b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 888*06b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(suff->searchPath)) { 8893955d011SMarcel Moolenaar #ifdef INCLUDES 890*06b9b3e0SSimon J. Gerraty if (suff->flags & SUFF_INCLUDE) 891*06b9b3e0SSimon J. Gerraty SearchPath_AddAll(includesPath, 892*06b9b3e0SSimon J. Gerraty suff->searchPath); 893956e45f6SSimon J. Gerraty #endif 8943955d011SMarcel Moolenaar #ifdef LIBRARIES 895*06b9b3e0SSimon J. Gerraty if (suff->flags & SUFF_LIBRARY) 896*06b9b3e0SSimon J. Gerraty SearchPath_AddAll(libsPath, suff->searchPath); 897956e45f6SSimon J. Gerraty #endif 898*06b9b3e0SSimon J. Gerraty SearchPath_AddAll(suff->searchPath, &dirSearchPath); 8993955d011SMarcel Moolenaar } else { 900*06b9b3e0SSimon J. Gerraty SearchPath_Free(suff->searchPath); 901*06b9b3e0SSimon J. Gerraty suff->searchPath = Dir_CopyDirSearchPath(); 9023955d011SMarcel Moolenaar } 9033955d011SMarcel Moolenaar } 9043955d011SMarcel Moolenaar 905*06b9b3e0SSimon J. Gerraty flags = SearchPath_ToFlags("-I", includesPath); 906*06b9b3e0SSimon J. Gerraty Var_Set(".INCLUDES", flags, VAR_GLOBAL); 907*06b9b3e0SSimon J. Gerraty free(flags); 9083955d011SMarcel Moolenaar 909*06b9b3e0SSimon J. Gerraty flags = SearchPath_ToFlags("-L", libsPath); 910*06b9b3e0SSimon J. Gerraty Var_Set(".LIBS", flags, VAR_GLOBAL); 911*06b9b3e0SSimon J. Gerraty free(flags); 912*06b9b3e0SSimon J. Gerraty 913*06b9b3e0SSimon J. Gerraty SearchPath_Free(includesPath); 914*06b9b3e0SSimon J. Gerraty SearchPath_Free(libsPath); 9153955d011SMarcel Moolenaar } 9163955d011SMarcel Moolenaar 917*06b9b3e0SSimon J. Gerraty /* 918*06b9b3e0SSimon J. Gerraty * Add the given suffix as a type of file which gets included. 919*06b9b3e0SSimon J. Gerraty * Called when a '.INCLUDES: .h' line is parsed. 920*06b9b3e0SSimon J. Gerraty * To have an effect, the suffix must already exist. 921*06b9b3e0SSimon J. Gerraty * This affects the magic variable '.INCLUDES'. 9223955d011SMarcel Moolenaar */ 9233955d011SMarcel Moolenaar void 924*06b9b3e0SSimon J. Gerraty Suff_AddInclude(const char *suffName) 9253955d011SMarcel Moolenaar { 926*06b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(suffName); 927956e45f6SSimon J. Gerraty if (suff != NULL) 928956e45f6SSimon J. Gerraty suff->flags |= SUFF_INCLUDE; 9293955d011SMarcel Moolenaar } 9303955d011SMarcel Moolenaar 931*06b9b3e0SSimon J. Gerraty /* 932*06b9b3e0SSimon J. Gerraty * Add the given suffix as a type of file which is a library. 933*06b9b3e0SSimon J. Gerraty * Called when a '.LIBS: .a' line is parsed. 934*06b9b3e0SSimon J. Gerraty * To have an effect, the suffix must already exist. 935*06b9b3e0SSimon J. Gerraty * This affects the magic variable '.LIBS'. 9363955d011SMarcel Moolenaar */ 9373955d011SMarcel Moolenaar void 938*06b9b3e0SSimon J. Gerraty Suff_AddLib(const char *suffName) 9393955d011SMarcel Moolenaar { 940*06b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(suffName); 941956e45f6SSimon J. Gerraty if (suff != NULL) 942956e45f6SSimon J. Gerraty suff->flags |= SUFF_LIBRARY; 9433955d011SMarcel Moolenaar } 9443955d011SMarcel Moolenaar 9453955d011SMarcel Moolenaar /********** Implicit Source Search Functions *********/ 9463955d011SMarcel Moolenaar 947*06b9b3e0SSimon J. Gerraty static void 948*06b9b3e0SSimon J. Gerraty CandidateSearcher_Init(CandidateSearcher *cs) 949*06b9b3e0SSimon J. Gerraty { 950*06b9b3e0SSimon J. Gerraty Lst_Init(&cs->list); 951*06b9b3e0SSimon J. Gerraty } 952*06b9b3e0SSimon J. Gerraty 953*06b9b3e0SSimon J. Gerraty static void 954*06b9b3e0SSimon J. Gerraty CandidateSearcher_Done(CandidateSearcher *cs) 955*06b9b3e0SSimon J. Gerraty { 956*06b9b3e0SSimon J. Gerraty Lst_Done(&cs->list); 957*06b9b3e0SSimon J. Gerraty } 958*06b9b3e0SSimon J. Gerraty 959*06b9b3e0SSimon J. Gerraty static void 960*06b9b3e0SSimon J. Gerraty CandidateSearcher_Add(CandidateSearcher *cs, Candidate *cand) 961*06b9b3e0SSimon J. Gerraty { 962*06b9b3e0SSimon J. Gerraty /* TODO: filter duplicates */ 963*06b9b3e0SSimon J. Gerraty Lst_Append(&cs->list, cand); 964*06b9b3e0SSimon J. Gerraty } 965*06b9b3e0SSimon J. Gerraty 966*06b9b3e0SSimon J. Gerraty static void 967*06b9b3e0SSimon J. Gerraty CandidateSearcher_AddIfNew(CandidateSearcher *cs, Candidate *cand) 968*06b9b3e0SSimon J. Gerraty { 969*06b9b3e0SSimon J. Gerraty /* TODO: filter duplicates */ 970*06b9b3e0SSimon J. Gerraty if (Lst_FindDatum(&cs->list, cand) == NULL) 971*06b9b3e0SSimon J. Gerraty Lst_Append(&cs->list, cand); 972*06b9b3e0SSimon J. Gerraty } 973*06b9b3e0SSimon J. Gerraty 974*06b9b3e0SSimon J. Gerraty static void 975*06b9b3e0SSimon J. Gerraty CandidateSearcher_MoveAll(CandidateSearcher *cs, CandidateList *list) 976*06b9b3e0SSimon J. Gerraty { 977*06b9b3e0SSimon J. Gerraty /* TODO: filter duplicates */ 978*06b9b3e0SSimon J. Gerraty Lst_MoveAll(&cs->list, list); 979*06b9b3e0SSimon J. Gerraty } 980*06b9b3e0SSimon J. Gerraty 981*06b9b3e0SSimon J. Gerraty 982956e45f6SSimon J. Gerraty #ifdef DEBUG_SRC 983956e45f6SSimon J. Gerraty static void 984*06b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(CandidateList *list) 985956e45f6SSimon J. Gerraty { 986*06b9b3e0SSimon J. Gerraty CandidateListNode *ln; 987*06b9b3e0SSimon J. Gerraty 988*06b9b3e0SSimon J. Gerraty for (ln = list->first; ln != NULL; ln = ln->next) { 989*06b9b3e0SSimon J. Gerraty Candidate *cand = ln->datum; 990*06b9b3e0SSimon J. Gerraty debug_printf(" %p:%s", cand, cand->file); 991*06b9b3e0SSimon J. Gerraty } 992956e45f6SSimon J. Gerraty debug_printf("\n"); 993956e45f6SSimon J. Gerraty } 994956e45f6SSimon J. Gerraty #endif 995956e45f6SSimon J. Gerraty 996*06b9b3e0SSimon J. Gerraty static Candidate * 997*06b9b3e0SSimon J. Gerraty Candidate_New(char *name, char *prefix, Suffix *suff, Candidate *parent, 998*06b9b3e0SSimon J. Gerraty GNode *gn) 999956e45f6SSimon J. Gerraty { 1000*06b9b3e0SSimon J. Gerraty Candidate *cand = bmake_malloc(sizeof *cand); 1001956e45f6SSimon J. Gerraty 1002*06b9b3e0SSimon J. Gerraty cand->file = name; 1003*06b9b3e0SSimon J. Gerraty cand->prefix = prefix; 1004*06b9b3e0SSimon J. Gerraty cand->suff = Suffix_Ref(suff); 1005*06b9b3e0SSimon J. Gerraty cand->parent = parent; 1006*06b9b3e0SSimon J. Gerraty cand->node = gn; 1007*06b9b3e0SSimon J. Gerraty cand->numChildren = 0; 1008956e45f6SSimon J. Gerraty #ifdef DEBUG_SRC 1009*06b9b3e0SSimon J. Gerraty Lst_Init(&cand->childrenList); 1010956e45f6SSimon J. Gerraty #endif 1011956e45f6SSimon J. Gerraty 1012*06b9b3e0SSimon J. Gerraty return cand; 1013956e45f6SSimon J. Gerraty } 1014956e45f6SSimon J. Gerraty 1015*06b9b3e0SSimon J. Gerraty /* Add a new candidate to the list. */ 1016*06b9b3e0SSimon J. Gerraty /*ARGSUSED*/ 1017956e45f6SSimon J. Gerraty static void 1018*06b9b3e0SSimon J. Gerraty CandidateList_Add(CandidateList *list, char *srcName, Candidate *targ, 1019*06b9b3e0SSimon J. Gerraty Suffix *suff, const char *debug_tag) 1020956e45f6SSimon J. Gerraty { 1021*06b9b3e0SSimon J. Gerraty Candidate *cand = Candidate_New(srcName, targ->prefix, suff, targ, 1022*06b9b3e0SSimon J. Gerraty NULL); 1023e2eeea75SSimon J. Gerraty targ->numChildren++; 1024*06b9b3e0SSimon J. Gerraty Lst_Append(list, cand); 1025*06b9b3e0SSimon J. Gerraty 1026956e45f6SSimon J. Gerraty #ifdef DEBUG_SRC 1027*06b9b3e0SSimon J. Gerraty Lst_Append(&targ->childrenList, cand); 1028*06b9b3e0SSimon J. Gerraty debug_printf("%s add suff %p:%s candidate %p:%s to list %p:", 1029*06b9b3e0SSimon J. Gerraty debug_tag, targ, targ->file, cand, cand->file, list); 1030*06b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(list); 1031956e45f6SSimon J. Gerraty #endif 1032956e45f6SSimon J. Gerraty } 1033956e45f6SSimon J. Gerraty 1034*06b9b3e0SSimon J. Gerraty /* 1035*06b9b3e0SSimon J. Gerraty * Add all candidates to the list that can be formed by applying a suffix to 1036*06b9b3e0SSimon J. Gerraty * the candidate. 10373955d011SMarcel Moolenaar */ 1038956e45f6SSimon J. Gerraty static void 1039*06b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(CandidateList *list, Candidate *cand) 10403955d011SMarcel Moolenaar { 1041*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 1042*06b9b3e0SSimon J. Gerraty for (ln = cand->suff->children.first; ln != NULL; ln = ln->next) { 1043*06b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 1044*06b9b3e0SSimon J. Gerraty 1045956e45f6SSimon J. Gerraty if ((suff->flags & SUFF_NULL) && suff->name[0] != '\0') { 10463955d011SMarcel Moolenaar /* 1047*06b9b3e0SSimon J. Gerraty * If the suffix has been marked as the NULL suffix, 1048*06b9b3e0SSimon J. Gerraty * also create a candidate for a file with no suffix 1049*06b9b3e0SSimon J. Gerraty * attached. 10503955d011SMarcel Moolenaar */ 1051*06b9b3e0SSimon J. Gerraty CandidateList_Add(list, bmake_strdup(cand->prefix), 1052*06b9b3e0SSimon J. Gerraty cand, suff, "1"); 10533955d011SMarcel Moolenaar } 10543955d011SMarcel Moolenaar 1055*06b9b3e0SSimon J. Gerraty CandidateList_Add(list, str_concat2(cand->prefix, suff->name), 1056*06b9b3e0SSimon J. Gerraty cand, suff, "2"); 1057956e45f6SSimon J. Gerraty } 10583955d011SMarcel Moolenaar } 10593955d011SMarcel Moolenaar 1060*06b9b3e0SSimon J. Gerraty /* 1061*06b9b3e0SSimon J. Gerraty * Free the first candidate in the list that is not referenced anymore. 1062*06b9b3e0SSimon J. Gerraty * Return whether a candidate was removed. 1063*06b9b3e0SSimon J. Gerraty */ 10642c3632d1SSimon J. Gerraty static Boolean 1065*06b9b3e0SSimon J. Gerraty RemoveCandidate(CandidateList *srcs) 10663955d011SMarcel Moolenaar { 1067*06b9b3e0SSimon J. Gerraty CandidateListNode *ln; 10682c3632d1SSimon J. Gerraty 10693955d011SMarcel Moolenaar #ifdef DEBUG_SRC 1070*06b9b3e0SSimon J. Gerraty debug_printf("cleaning list %p:", srcs); 1071*06b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(srcs); 10723955d011SMarcel Moolenaar #endif 10733955d011SMarcel Moolenaar 1074*06b9b3e0SSimon J. Gerraty for (ln = srcs->first; ln != NULL; ln = ln->next) { 1075*06b9b3e0SSimon J. Gerraty Candidate *src = ln->datum; 1076956e45f6SSimon J. Gerraty 1077e2eeea75SSimon J. Gerraty if (src->numChildren == 0) { 1078e2eeea75SSimon J. Gerraty if (src->parent == NULL) 1079*06b9b3e0SSimon J. Gerraty free(src->prefix); 10803955d011SMarcel Moolenaar else { 10813955d011SMarcel Moolenaar #ifdef DEBUG_SRC 1082*06b9b3e0SSimon J. Gerraty /* XXX: Lst_RemoveDatum */ 1083*06b9b3e0SSimon J. Gerraty CandidateListNode *ln2; 1084*06b9b3e0SSimon J. Gerraty ln2 = Lst_FindDatum(&src->parent->childrenList, 1085*06b9b3e0SSimon J. Gerraty src); 108695e3ed2cSSimon J. Gerraty if (ln2 != NULL) 1087*06b9b3e0SSimon J. Gerraty Lst_Remove(&src->parent->childrenList, 1088*06b9b3e0SSimon J. Gerraty ln2); 10893955d011SMarcel Moolenaar #endif 1090e2eeea75SSimon J. Gerraty src->parent->numChildren--; 10913955d011SMarcel Moolenaar } 10923955d011SMarcel Moolenaar #ifdef DEBUG_SRC 1093*06b9b3e0SSimon J. Gerraty debug_printf("free: list %p src %p:%s children %d\n", 1094*06b9b3e0SSimon J. Gerraty srcs, src, src->file, src->numChildren); 1095*06b9b3e0SSimon J. Gerraty Lst_Done(&src->childrenList); 10963955d011SMarcel Moolenaar #endif 1097*06b9b3e0SSimon J. Gerraty Lst_Remove(srcs, ln); 1098*06b9b3e0SSimon J. Gerraty free(src->file); 1099e2eeea75SSimon J. Gerraty free(src); 11003955d011SMarcel Moolenaar return TRUE; 11013955d011SMarcel Moolenaar } 11023955d011SMarcel Moolenaar #ifdef DEBUG_SRC 11033955d011SMarcel Moolenaar else { 1104*06b9b3e0SSimon J. Gerraty debug_printf("keep: list %p src %p:%s children %d:", 1105*06b9b3e0SSimon J. Gerraty srcs, src, src->file, src->numChildren); 1106*06b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(&src->childrenList); 11073955d011SMarcel Moolenaar } 11083955d011SMarcel Moolenaar #endif 11093955d011SMarcel Moolenaar } 11103955d011SMarcel Moolenaar 11112c3632d1SSimon J. Gerraty return FALSE; 11123955d011SMarcel Moolenaar } 11133955d011SMarcel Moolenaar 1114e2eeea75SSimon J. Gerraty /* Find the first existing file/target in srcs. */ 1115*06b9b3e0SSimon J. Gerraty static Candidate * 1116*06b9b3e0SSimon J. Gerraty FindThem(CandidateList *srcs, CandidateSearcher *cs) 11173955d011SMarcel Moolenaar { 1118*06b9b3e0SSimon J. Gerraty HashSet seen; 1119*06b9b3e0SSimon J. Gerraty 1120*06b9b3e0SSimon J. Gerraty HashSet_Init(&seen); 11213955d011SMarcel Moolenaar 11223955d011SMarcel Moolenaar while (!Lst_IsEmpty(srcs)) { 1123*06b9b3e0SSimon J. Gerraty Candidate *src = Lst_Dequeue(srcs); 11243955d011SMarcel Moolenaar 1125*06b9b3e0SSimon J. Gerraty #ifdef DEBUG_SRC 1126*06b9b3e0SSimon J. Gerraty debug_printf("remove from list %p src %p:%s\n", 1127*06b9b3e0SSimon J. Gerraty srcs, src, src->file); 1128*06b9b3e0SSimon J. Gerraty #endif 1129*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\ttrying %s...", src->file); 11303955d011SMarcel Moolenaar 11313955d011SMarcel Moolenaar /* 11323955d011SMarcel Moolenaar * A file is considered to exist if either a node exists in the 11333955d011SMarcel Moolenaar * graph for it or the file actually exists. 11343955d011SMarcel Moolenaar */ 1135956e45f6SSimon J. Gerraty if (Targ_FindNode(src->file) != NULL) { 1136*06b9b3e0SSimon J. Gerraty found: 1137*06b9b3e0SSimon J. Gerraty HashSet_Done(&seen); 1138*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "got it\n"); 1139*06b9b3e0SSimon J. Gerraty return src; 11403955d011SMarcel Moolenaar } 11413955d011SMarcel Moolenaar 1142956e45f6SSimon J. Gerraty { 1143*06b9b3e0SSimon J. Gerraty char *file = Dir_FindFile(src->file, 1144*06b9b3e0SSimon J. Gerraty src->suff->searchPath); 1145956e45f6SSimon J. Gerraty if (file != NULL) { 1146956e45f6SSimon J. Gerraty free(file); 1147*06b9b3e0SSimon J. Gerraty goto found; 11483955d011SMarcel Moolenaar } 1149956e45f6SSimon J. Gerraty } 11503955d011SMarcel Moolenaar 1151*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "not there\n"); 11523955d011SMarcel Moolenaar 1153*06b9b3e0SSimon J. Gerraty if (HashSet_Add(&seen, src->file)) 1154*06b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(srcs, src); 1155*06b9b3e0SSimon J. Gerraty else { 1156*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "FindThem: skipping duplicate \"%s\"\n", 1157*06b9b3e0SSimon J. Gerraty src->file); 11583955d011SMarcel Moolenaar } 11593955d011SMarcel Moolenaar 1160*06b9b3e0SSimon J. Gerraty CandidateSearcher_Add(cs, src); 11613955d011SMarcel Moolenaar } 11623955d011SMarcel Moolenaar 1163*06b9b3e0SSimon J. Gerraty HashSet_Done(&seen); 1164*06b9b3e0SSimon J. Gerraty return NULL; 1165*06b9b3e0SSimon J. Gerraty } 1166*06b9b3e0SSimon J. Gerraty 1167*06b9b3e0SSimon J. Gerraty /* 1168*06b9b3e0SSimon J. Gerraty * See if any of the children of the candidate's GNode is one from which the 1169*06b9b3e0SSimon J. Gerraty * target can be transformed. If there is one, a candidate is put together 1170*06b9b3e0SSimon J. Gerraty * for it and returned. 11713955d011SMarcel Moolenaar */ 1172*06b9b3e0SSimon J. Gerraty static Candidate * 1173*06b9b3e0SSimon J. Gerraty FindCmds(Candidate *targ, CandidateSearcher *cs) 11743955d011SMarcel Moolenaar { 1175956e45f6SSimon J. Gerraty GNodeListNode *gln; 1176956e45f6SSimon J. Gerraty GNode *tgn; /* Target GNode */ 1177956e45f6SSimon J. Gerraty GNode *sgn; /* Source GNode */ 1178956e45f6SSimon J. Gerraty size_t prefLen; /* The length of the defined prefix */ 1179*06b9b3e0SSimon J. Gerraty Suffix *suff; /* Suffix on matching beastie */ 1180*06b9b3e0SSimon J. Gerraty Candidate *ret; /* Return value */ 11813955d011SMarcel Moolenaar 1182956e45f6SSimon J. Gerraty tgn = targ->node; 1183*06b9b3e0SSimon J. Gerraty prefLen = strlen(targ->prefix); 11843955d011SMarcel Moolenaar 1185*06b9b3e0SSimon J. Gerraty for (gln = tgn->children.first; gln != NULL; gln = gln->next) { 1186*06b9b3e0SSimon J. Gerraty const char *cp; 1187*06b9b3e0SSimon J. Gerraty 1188956e45f6SSimon J. Gerraty sgn = gln->datum; 11893955d011SMarcel Moolenaar 1190*06b9b3e0SSimon J. Gerraty if (sgn->type & OP_OPTIONAL && Lst_IsEmpty(&tgn->commands)) { 11913955d011SMarcel Moolenaar /* 1192*06b9b3e0SSimon J. Gerraty * We haven't looked to see if .OPTIONAL files exist 1193*06b9b3e0SSimon J. Gerraty * yet, so don't use one as the implicit source. 1194*06b9b3e0SSimon J. Gerraty * This allows us to use .OPTIONAL in .depend files so 1195*06b9b3e0SSimon J. Gerraty * make won't complain "don't know how to make xxx.h" 1196*06b9b3e0SSimon J. Gerraty * when a dependent file has been moved/deleted. 11973955d011SMarcel Moolenaar */ 11983955d011SMarcel Moolenaar continue; 11993955d011SMarcel Moolenaar } 12003955d011SMarcel Moolenaar 1201*06b9b3e0SSimon J. Gerraty cp = str_basename(sgn->name); 1202*06b9b3e0SSimon J. Gerraty if (strncmp(cp, targ->prefix, prefLen) != 0) 12033955d011SMarcel Moolenaar continue; 1204*06b9b3e0SSimon J. Gerraty /* The node matches the prefix, see if it has a known suffix. */ 1205*06b9b3e0SSimon J. Gerraty suff = FindSuffixByName(cp + prefLen); 1206956e45f6SSimon J. Gerraty if (suff == NULL) 12073955d011SMarcel Moolenaar continue; 1208956e45f6SSimon J. Gerraty 12093955d011SMarcel Moolenaar /* 12103955d011SMarcel Moolenaar * It even has a known suffix, see if there's a transformation 12113955d011SMarcel Moolenaar * defined between the node's suffix and the target's suffix. 12123955d011SMarcel Moolenaar * 12133955d011SMarcel Moolenaar * XXX: Handle multi-stage transformations here, too. 12143955d011SMarcel Moolenaar */ 12153955d011SMarcel Moolenaar 1216*06b9b3e0SSimon J. Gerraty if (Lst_FindDatum(&suff->parents, targ->suff) != NULL) 12173955d011SMarcel Moolenaar break; 12183955d011SMarcel Moolenaar } 12193955d011SMarcel Moolenaar 1220956e45f6SSimon J. Gerraty if (gln == NULL) 1221956e45f6SSimon J. Gerraty return NULL; 1222956e45f6SSimon J. Gerraty 1223*06b9b3e0SSimon J. Gerraty ret = Candidate_New(bmake_strdup(sgn->name), targ->prefix, suff, targ, 1224*06b9b3e0SSimon J. Gerraty sgn); 1225e2eeea75SSimon J. Gerraty targ->numChildren++; 12263955d011SMarcel Moolenaar #ifdef DEBUG_SRC 1227*06b9b3e0SSimon J. Gerraty debug_printf("3 add targ %p:%s ret %p:%s\n", 1228*06b9b3e0SSimon J. Gerraty targ, targ->file, ret, ret->file); 1229*06b9b3e0SSimon J. Gerraty Lst_Append(&targ->childrenList, ret); 12303955d011SMarcel Moolenaar #endif 1231*06b9b3e0SSimon J. Gerraty CandidateSearcher_Add(cs, ret); 1232*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\tusing existing source %s\n", sgn->name); 12333841c287SSimon J. Gerraty return ret; 12343955d011SMarcel Moolenaar } 12353955d011SMarcel Moolenaar 12363955d011SMarcel Moolenaar static void 1237*06b9b3e0SSimon J. Gerraty ExpandWildcards(GNodeListNode *cln, GNode *pgn) 12383955d011SMarcel Moolenaar { 1239956e45f6SSimon J. Gerraty GNode *cgn = cln->datum; 1240*06b9b3e0SSimon J. Gerraty StringList expansions; 12413955d011SMarcel Moolenaar 1242*06b9b3e0SSimon J. Gerraty if (!Dir_HasWildcards(cgn->name)) 12433955d011SMarcel Moolenaar return; 12443955d011SMarcel Moolenaar 12453955d011SMarcel Moolenaar /* 1246*06b9b3e0SSimon J. Gerraty * Expand the word along the chosen path 12473955d011SMarcel Moolenaar */ 1248*06b9b3e0SSimon J. Gerraty Lst_Init(&expansions); 1249*06b9b3e0SSimon J. Gerraty Dir_Expand(cgn->name, Suff_FindPath(cgn), &expansions); 1250*06b9b3e0SSimon J. Gerraty 1251*06b9b3e0SSimon J. Gerraty while (!Lst_IsEmpty(&expansions)) { 1252*06b9b3e0SSimon J. Gerraty GNode *gn; 1253*06b9b3e0SSimon J. Gerraty /* 1254*06b9b3e0SSimon J. Gerraty * Fetch next expansion off the list and find its GNode 1255*06b9b3e0SSimon J. Gerraty */ 1256*06b9b3e0SSimon J. Gerraty char *cp = Lst_Dequeue(&expansions); 1257*06b9b3e0SSimon J. Gerraty 1258*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "%s...", cp); 1259*06b9b3e0SSimon J. Gerraty gn = Targ_GetNode(cp); 1260*06b9b3e0SSimon J. Gerraty 1261*06b9b3e0SSimon J. Gerraty /* Add gn to the parents child list before the original child */ 1262*06b9b3e0SSimon J. Gerraty Lst_InsertBefore(&pgn->children, cln, gn); 1263*06b9b3e0SSimon J. Gerraty Lst_Append(&gn->parents, pgn); 1264*06b9b3e0SSimon J. Gerraty pgn->unmade++; 12653955d011SMarcel Moolenaar } 12663955d011SMarcel Moolenaar 1267*06b9b3e0SSimon J. Gerraty Lst_Done(&expansions); 12683955d011SMarcel Moolenaar 1269*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "\n"); 1270*06b9b3e0SSimon J. Gerraty 1271*06b9b3e0SSimon J. Gerraty /* 1272*06b9b3e0SSimon J. Gerraty * Now the source is expanded, remove it from the list of children to 1273*06b9b3e0SSimon J. Gerraty * keep it from being processed. 1274*06b9b3e0SSimon J. Gerraty */ 1275*06b9b3e0SSimon J. Gerraty pgn->unmade--; 1276*06b9b3e0SSimon J. Gerraty Lst_Remove(&pgn->children, cln); 1277*06b9b3e0SSimon J. Gerraty Lst_Remove(&cgn->parents, Lst_FindDatum(&cgn->parents, pgn)); 1278*06b9b3e0SSimon J. Gerraty } 1279*06b9b3e0SSimon J. Gerraty 1280*06b9b3e0SSimon J. Gerraty /* 1281*06b9b3e0SSimon J. Gerraty * Break the result into a vector of strings whose nodes we can find, then 1282*06b9b3e0SSimon J. Gerraty * add those nodes to the members list. 1283*06b9b3e0SSimon J. Gerraty * 1284*06b9b3e0SSimon J. Gerraty * Unfortunately, we can't use Str_Words because it doesn't understand about 1285*06b9b3e0SSimon J. Gerraty * variable specifications with spaces in them. 1286*06b9b3e0SSimon J. Gerraty */ 1287*06b9b3e0SSimon J. Gerraty static void 1288*06b9b3e0SSimon J. Gerraty ExpandChildrenRegular(char *cp, GNode *pgn, GNodeList *members) 12892c3632d1SSimon J. Gerraty { 12903955d011SMarcel Moolenaar char *start; 12913955d011SMarcel Moolenaar 1292*06b9b3e0SSimon J. Gerraty pp_skip_hspace(&cp); 1293e2eeea75SSimon J. Gerraty start = cp; 1294956e45f6SSimon J. Gerraty while (*cp != '\0') { 12953955d011SMarcel Moolenaar if (*cp == ' ' || *cp == '\t') { 1296*06b9b3e0SSimon J. Gerraty GNode *gn; 12973955d011SMarcel Moolenaar /* 12983955d011SMarcel Moolenaar * White-space -- terminate element, find the node, 12993955d011SMarcel Moolenaar * add it, skip any further spaces. 13003955d011SMarcel Moolenaar */ 13013955d011SMarcel Moolenaar *cp++ = '\0'; 1302956e45f6SSimon J. Gerraty gn = Targ_GetNode(start); 13032c3632d1SSimon J. Gerraty Lst_Append(members, gn); 1304e2eeea75SSimon J. Gerraty pp_skip_hspace(&cp); 1305*06b9b3e0SSimon J. Gerraty /* Continue at the next non-space. */ 1306*06b9b3e0SSimon J. Gerraty start = cp; 13073955d011SMarcel Moolenaar } else if (*cp == '$') { 1308*06b9b3e0SSimon J. Gerraty /* Skip over the variable expression. */ 1309956e45f6SSimon J. Gerraty const char *nested_p = cp; 1310*06b9b3e0SSimon J. Gerraty FStr junk; 13113955d011SMarcel Moolenaar 1312*06b9b3e0SSimon J. Gerraty (void)Var_Parse(&nested_p, pgn, VARE_NONE, &junk); 1313956e45f6SSimon J. Gerraty /* TODO: handle errors */ 1314*06b9b3e0SSimon J. Gerraty if (junk.str == var_Error) { 1315956e45f6SSimon J. Gerraty Parse_Error(PARSE_FATAL, 1316956e45f6SSimon J. Gerraty "Malformed variable expression at \"%s\"", 1317956e45f6SSimon J. Gerraty cp); 1318956e45f6SSimon J. Gerraty cp++; 1319956e45f6SSimon J. Gerraty } else { 1320956e45f6SSimon J. Gerraty cp += nested_p - cp; 13213955d011SMarcel Moolenaar } 13223955d011SMarcel Moolenaar 1323*06b9b3e0SSimon J. Gerraty FStr_Done(&junk); 1324e2eeea75SSimon J. Gerraty } else if (cp[0] == '\\' && cp[1] != '\0') { 1325*06b9b3e0SSimon J. Gerraty /* Escaped something -- skip over it. */ 13263955d011SMarcel Moolenaar /* 1327*06b9b3e0SSimon J. Gerraty * XXX: In other places, escaping at this syntactical 1328*06b9b3e0SSimon J. Gerraty * position is done by a '$', not a '\'. The '\' is 1329*06b9b3e0SSimon J. Gerraty * only used in variable modifiers. 13303955d011SMarcel Moolenaar */ 1331956e45f6SSimon J. Gerraty cp += 2; 1332956e45f6SSimon J. Gerraty } else { 13333955d011SMarcel Moolenaar cp++; 13343955d011SMarcel Moolenaar } 13353955d011SMarcel Moolenaar } 13363955d011SMarcel Moolenaar 13373955d011SMarcel Moolenaar if (cp != start) { 13383955d011SMarcel Moolenaar /* 13393955d011SMarcel Moolenaar * Stuff left over -- add it to the list too 13403955d011SMarcel Moolenaar */ 1341*06b9b3e0SSimon J. Gerraty GNode *gn = Targ_GetNode(start); 13422c3632d1SSimon J. Gerraty Lst_Append(members, gn); 13433955d011SMarcel Moolenaar } 1344*06b9b3e0SSimon J. Gerraty } 1345*06b9b3e0SSimon J. Gerraty 13463955d011SMarcel Moolenaar /* 1347*06b9b3e0SSimon J. Gerraty * Expand the names of any children of a given node that contain variable 1348*06b9b3e0SSimon J. Gerraty * expressions or file wildcards into actual targets. 1349*06b9b3e0SSimon J. Gerraty * 1350*06b9b3e0SSimon J. Gerraty * The expanded node is removed from the parent's list of children, and the 1351*06b9b3e0SSimon J. Gerraty * parent's unmade counter is decremented, but other nodes may be added. 1352*06b9b3e0SSimon J. Gerraty * 1353*06b9b3e0SSimon J. Gerraty * Input: 1354*06b9b3e0SSimon J. Gerraty * cln Child to examine 1355*06b9b3e0SSimon J. Gerraty * pgn Parent node being processed 13563955d011SMarcel Moolenaar */ 1357*06b9b3e0SSimon J. Gerraty static void 1358*06b9b3e0SSimon J. Gerraty ExpandChildren(GNodeListNode *cln, GNode *pgn) 1359*06b9b3e0SSimon J. Gerraty { 1360*06b9b3e0SSimon J. Gerraty GNode *cgn = cln->datum; 1361*06b9b3e0SSimon J. Gerraty char *cp; /* Expanded value */ 1362*06b9b3e0SSimon J. Gerraty 1363*06b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&cgn->order_pred) || !Lst_IsEmpty(&cgn->order_succ)) 1364*06b9b3e0SSimon J. Gerraty /* It is all too hard to process the result of .ORDER */ 1365*06b9b3e0SSimon J. Gerraty return; 1366*06b9b3e0SSimon J. Gerraty 1367*06b9b3e0SSimon J. Gerraty if (cgn->type & OP_WAIT) 1368*06b9b3e0SSimon J. Gerraty /* Ignore these (& OP_PHONY ?) */ 1369*06b9b3e0SSimon J. Gerraty return; 1370*06b9b3e0SSimon J. Gerraty 1371*06b9b3e0SSimon J. Gerraty /* 1372*06b9b3e0SSimon J. Gerraty * First do variable expansion -- this takes precedence over wildcard 1373*06b9b3e0SSimon J. Gerraty * expansion. If the result contains wildcards, they'll be gotten to 1374*06b9b3e0SSimon J. Gerraty * later since the resulting words are tacked on to the end of the 1375*06b9b3e0SSimon J. Gerraty * children list. 1376*06b9b3e0SSimon J. Gerraty */ 1377*06b9b3e0SSimon J. Gerraty if (strchr(cgn->name, '$') == NULL) { 1378*06b9b3e0SSimon J. Gerraty ExpandWildcards(cln, pgn); 1379*06b9b3e0SSimon J. Gerraty return; 1380*06b9b3e0SSimon J. Gerraty } 1381*06b9b3e0SSimon J. Gerraty 1382*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Expanding \"%s\"...", cgn->name); 1383*06b9b3e0SSimon J. Gerraty (void)Var_Subst(cgn->name, pgn, VARE_WANTRES | VARE_UNDEFERR, &cp); 1384*06b9b3e0SSimon J. Gerraty /* TODO: handle errors */ 1385*06b9b3e0SSimon J. Gerraty 1386*06b9b3e0SSimon J. Gerraty { 1387*06b9b3e0SSimon J. Gerraty GNodeList members = LST_INIT; 1388*06b9b3e0SSimon J. Gerraty 1389*06b9b3e0SSimon J. Gerraty if (cgn->type & OP_ARCHV) { 1390*06b9b3e0SSimon J. Gerraty /* 1391*06b9b3e0SSimon J. Gerraty * Node was an archive(member) target, so we want to 1392*06b9b3e0SSimon J. Gerraty * call on the Arch module to find the nodes for us, 1393*06b9b3e0SSimon J. Gerraty * expanding variables in the parent's context. 1394*06b9b3e0SSimon J. Gerraty */ 1395*06b9b3e0SSimon J. Gerraty char *p = cp; 1396*06b9b3e0SSimon J. Gerraty (void)Arch_ParseArchive(&p, &members, pgn); 1397*06b9b3e0SSimon J. Gerraty } else { 1398*06b9b3e0SSimon J. Gerraty ExpandChildrenRegular(cp, pgn, &members); 13993955d011SMarcel Moolenaar } 14003955d011SMarcel Moolenaar 14013955d011SMarcel Moolenaar /* 14023955d011SMarcel Moolenaar * Add all elements of the members list to the parent node. 14033955d011SMarcel Moolenaar */ 1404*06b9b3e0SSimon J. Gerraty while (!Lst_IsEmpty(&members)) { 1405*06b9b3e0SSimon J. Gerraty GNode *gn = Lst_Dequeue(&members); 14063955d011SMarcel Moolenaar 1407*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "%s...", gn->name); 1408*06b9b3e0SSimon J. Gerraty /* 1409*06b9b3e0SSimon J. Gerraty * Add gn to the parents child list before the 1410*06b9b3e0SSimon J. Gerraty * original child. 1411*06b9b3e0SSimon J. Gerraty */ 1412*06b9b3e0SSimon J. Gerraty Lst_InsertBefore(&pgn->children, cln, gn); 1413*06b9b3e0SSimon J. Gerraty Lst_Append(&gn->parents, pgn); 14143955d011SMarcel Moolenaar pgn->unmade++; 14153955d011SMarcel Moolenaar /* Expand wildcards on new node */ 1416*06b9b3e0SSimon J. Gerraty ExpandWildcards(cln->prev, pgn); 14173955d011SMarcel Moolenaar } 1418*06b9b3e0SSimon J. Gerraty Lst_Done(&members); 14193955d011SMarcel Moolenaar 14203955d011SMarcel Moolenaar free(cp); 14213955d011SMarcel Moolenaar } 14222c3632d1SSimon J. Gerraty 1423*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "\n"); 14243955d011SMarcel Moolenaar 14253955d011SMarcel Moolenaar /* 14263955d011SMarcel Moolenaar * Now the source is expanded, remove it from the list of children to 14273955d011SMarcel Moolenaar * keep it from being processed. 14283955d011SMarcel Moolenaar */ 14293955d011SMarcel Moolenaar pgn->unmade--; 1430*06b9b3e0SSimon J. Gerraty Lst_Remove(&pgn->children, cln); 1431*06b9b3e0SSimon J. Gerraty Lst_Remove(&cgn->parents, Lst_FindDatum(&cgn->parents, pgn)); 14323955d011SMarcel Moolenaar } 14333955d011SMarcel Moolenaar 14343955d011SMarcel Moolenaar static void 1435*06b9b3e0SSimon J. Gerraty ExpandAllChildren(GNode *gn) 14363955d011SMarcel Moolenaar { 1437*06b9b3e0SSimon J. Gerraty GNodeListNode *ln, *nln; 14383955d011SMarcel Moolenaar 1439*06b9b3e0SSimon J. Gerraty for (ln = gn->children.first; ln != NULL; ln = nln) { 1440*06b9b3e0SSimon J. Gerraty nln = ln->next; 1441*06b9b3e0SSimon J. Gerraty ExpandChildren(ln, gn); 1442*06b9b3e0SSimon J. Gerraty } 14433955d011SMarcel Moolenaar } 14443955d011SMarcel Moolenaar 14453955d011SMarcel Moolenaar /* 1446*06b9b3e0SSimon J. Gerraty * Find a path along which to expand the node. 14473955d011SMarcel Moolenaar * 1448e2eeea75SSimon J. Gerraty * If the node has a known suffix, use that path. 14493955d011SMarcel Moolenaar * If it has no known suffix, use the default system search path. 14503955d011SMarcel Moolenaar * 14513955d011SMarcel Moolenaar * Input: 14523955d011SMarcel Moolenaar * gn Node being examined 14533955d011SMarcel Moolenaar * 14543955d011SMarcel Moolenaar * Results: 14553955d011SMarcel Moolenaar * The appropriate path to search for the GNode. 14563955d011SMarcel Moolenaar */ 1457956e45f6SSimon J. Gerraty SearchPath * 14583955d011SMarcel Moolenaar Suff_FindPath(GNode *gn) 14593955d011SMarcel Moolenaar { 1460*06b9b3e0SSimon J. Gerraty Suffix *suff = gn->suffix; 14613955d011SMarcel Moolenaar 14623955d011SMarcel Moolenaar if (suff == NULL) { 1463956e45f6SSimon J. Gerraty char *name = gn->name; 1464956e45f6SSimon J. Gerraty size_t nameLen = strlen(gn->name); 1465*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 1466*06b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) 1467*06b9b3e0SSimon J. Gerraty if (Suffix_IsSuffix(ln->datum, nameLen, name + nameLen)) 1468956e45f6SSimon J. Gerraty break; 14693955d011SMarcel Moolenaar 1470*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Wildcard expanding \"%s\"...", gn->name); 14713955d011SMarcel Moolenaar if (ln != NULL) 1472956e45f6SSimon J. Gerraty suff = ln->datum; 1473*06b9b3e0SSimon J. Gerraty /* 1474*06b9b3e0SSimon J. Gerraty * XXX: Here we can save the suffix so we don't have to do 1475*06b9b3e0SSimon J. Gerraty * this again. 1476*06b9b3e0SSimon J. Gerraty */ 14773955d011SMarcel Moolenaar } 14783955d011SMarcel Moolenaar 14793955d011SMarcel Moolenaar if (suff != NULL) { 1480*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "suffix is \"%s\"...\n", suff->name); 14813955d011SMarcel Moolenaar return suff->searchPath; 14823955d011SMarcel Moolenaar } else { 1483*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "\n"); 1484*06b9b3e0SSimon J. Gerraty return &dirSearchPath; /* Use default search path */ 14853955d011SMarcel Moolenaar } 14863955d011SMarcel Moolenaar } 14873955d011SMarcel Moolenaar 1488*06b9b3e0SSimon J. Gerraty /* 1489*06b9b3e0SSimon J. Gerraty * Apply a transformation rule, given the source and target nodes and 14902c3632d1SSimon J. Gerraty * suffixes. 14913955d011SMarcel Moolenaar * 1492e2eeea75SSimon J. Gerraty * The source and target are linked and the commands from the transformation 1493e2eeea75SSimon J. Gerraty * are added to the target node's commands list. The target also inherits all 1494e2eeea75SSimon J. Gerraty * the sources for the transformation rule. 14953955d011SMarcel Moolenaar * 14963955d011SMarcel Moolenaar * Results: 14973955d011SMarcel Moolenaar * TRUE if successful, FALSE if not. 14983955d011SMarcel Moolenaar */ 14993955d011SMarcel Moolenaar static Boolean 1500*06b9b3e0SSimon J. Gerraty ApplyTransform(GNode *tgn, GNode *sgn, Suffix *tsuff, Suffix *ssuff) 15013955d011SMarcel Moolenaar { 1502e2eeea75SSimon J. Gerraty GNodeListNode *ln; 15033955d011SMarcel Moolenaar char *tname; /* Name of transformation rule */ 1504*06b9b3e0SSimon J. Gerraty GNode *gn; /* Node for the transformation rule */ 15053955d011SMarcel Moolenaar 1506*06b9b3e0SSimon J. Gerraty /* Form the proper links between the target and source. */ 1507*06b9b3e0SSimon J. Gerraty Lst_Append(&tgn->children, sgn); 1508*06b9b3e0SSimon J. Gerraty Lst_Append(&sgn->parents, tgn); 1509e2eeea75SSimon J. Gerraty tgn->unmade++; 15103955d011SMarcel Moolenaar 1511*06b9b3e0SSimon J. Gerraty /* Locate the transformation rule itself. */ 1512e2eeea75SSimon J. Gerraty tname = str_concat2(ssuff->name, tsuff->name); 1513956e45f6SSimon J. Gerraty gn = FindTransformByName(tname); 15143955d011SMarcel Moolenaar free(tname); 15153955d011SMarcel Moolenaar 1516e2eeea75SSimon J. Gerraty /* This can happen when linking an OP_MEMBER and OP_ARCHV node. */ 1517*06b9b3e0SSimon J. Gerraty if (gn == NULL) 15183841c287SSimon J. Gerraty return FALSE; 15193955d011SMarcel Moolenaar 1520e2eeea75SSimon J. Gerraty DEBUG3(SUFF, "\tapplying %s -> %s to \"%s\"\n", 1521e2eeea75SSimon J. Gerraty ssuff->name, tsuff->name, tgn->name); 15223955d011SMarcel Moolenaar 1523e2eeea75SSimon J. Gerraty /* Record last child; Make_HandleUse may add child nodes. */ 1524*06b9b3e0SSimon J. Gerraty ln = tgn->children.last; 15253955d011SMarcel Moolenaar 1526e2eeea75SSimon J. Gerraty /* Apply the rule. */ 1527e2eeea75SSimon J. Gerraty Make_HandleUse(gn, tgn); 15283955d011SMarcel Moolenaar 1529e2eeea75SSimon J. Gerraty /* Deal with wildcards and variables in any acquired sources. */ 1530e2eeea75SSimon J. Gerraty ln = ln != NULL ? ln->next : NULL; 1531e2eeea75SSimon J. Gerraty while (ln != NULL) { 1532e2eeea75SSimon J. Gerraty GNodeListNode *nln = ln->next; 1533*06b9b3e0SSimon J. Gerraty ExpandChildren(ln, tgn); 1534e2eeea75SSimon J. Gerraty ln = nln; 15353955d011SMarcel Moolenaar } 15363955d011SMarcel Moolenaar 15373955d011SMarcel Moolenaar /* 1538e2eeea75SSimon J. Gerraty * Keep track of another parent to which this node is transformed so 15393955d011SMarcel Moolenaar * the .IMPSRC variable can be set correctly for the parent. 15403955d011SMarcel Moolenaar */ 1541*06b9b3e0SSimon J. Gerraty Lst_Append(&sgn->implicitParents, tgn); 15423955d011SMarcel Moolenaar 15433841c287SSimon J. Gerraty return TRUE; 15443955d011SMarcel Moolenaar } 15453955d011SMarcel Moolenaar 1546*06b9b3e0SSimon J. Gerraty /* 1547*06b9b3e0SSimon J. Gerraty * Member has a known suffix, so look for a transformation rule from 1548*06b9b3e0SSimon J. Gerraty * it to a possible suffix of the archive. 1549*06b9b3e0SSimon J. Gerraty * 1550*06b9b3e0SSimon J. Gerraty * Rather than searching through the entire list, we just look at 1551*06b9b3e0SSimon J. Gerraty * suffixes to which the member's suffix may be transformed. 1552*06b9b3e0SSimon J. Gerraty */ 1553*06b9b3e0SSimon J. Gerraty static void 1554*06b9b3e0SSimon J. Gerraty ExpandMember(GNode *gn, const char *eoarch, GNode *mem, Suffix *memSuff) 1555*06b9b3e0SSimon J. Gerraty { 1556*06b9b3e0SSimon J. Gerraty GNodeListNode *ln; 1557*06b9b3e0SSimon J. Gerraty size_t nameLen = (size_t)(eoarch - gn->name); 15583955d011SMarcel Moolenaar 1559*06b9b3e0SSimon J. Gerraty /* Use first matching suffix... */ 1560*06b9b3e0SSimon J. Gerraty for (ln = memSuff->parents.first; ln != NULL; ln = ln->next) 1561*06b9b3e0SSimon J. Gerraty if (Suffix_IsSuffix(ln->datum, nameLen, eoarch)) 1562*06b9b3e0SSimon J. Gerraty break; 1563*06b9b3e0SSimon J. Gerraty 1564*06b9b3e0SSimon J. Gerraty if (ln != NULL) { 1565*06b9b3e0SSimon J. Gerraty /* Got one -- apply it */ 1566*06b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 1567*06b9b3e0SSimon J. Gerraty if (!ApplyTransform(gn, mem, suff, memSuff)) { 1568*06b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "\tNo transformation from %s -> %s\n", 1569*06b9b3e0SSimon J. Gerraty memSuff->name, suff->name); 1570*06b9b3e0SSimon J. Gerraty } 1571*06b9b3e0SSimon J. Gerraty } 1572*06b9b3e0SSimon J. Gerraty } 1573*06b9b3e0SSimon J. Gerraty 1574*06b9b3e0SSimon J. Gerraty static void FindDeps(GNode *, CandidateSearcher *); 1575*06b9b3e0SSimon J. Gerraty 1576*06b9b3e0SSimon J. Gerraty /* 1577*06b9b3e0SSimon J. Gerraty * Locate dependencies for an OP_ARCHV node. 15783955d011SMarcel Moolenaar * 15793955d011SMarcel Moolenaar * Input: 15803955d011SMarcel Moolenaar * gn Node for which to locate dependencies 15813955d011SMarcel Moolenaar * 15823955d011SMarcel Moolenaar * Side Effects: 15833955d011SMarcel Moolenaar * Same as Suff_FindDeps 15843955d011SMarcel Moolenaar */ 15853955d011SMarcel Moolenaar static void 1586*06b9b3e0SSimon J. Gerraty FindDepsArchive(GNode *gn, CandidateSearcher *cs) 15873955d011SMarcel Moolenaar { 15883955d011SMarcel Moolenaar char *eoarch; /* End of archive portion */ 15893955d011SMarcel Moolenaar char *eoname; /* End of member portion */ 15903955d011SMarcel Moolenaar GNode *mem; /* Node for member */ 1591*06b9b3e0SSimon J. Gerraty Suffix *memSuff; 1592*06b9b3e0SSimon J. Gerraty const char *name; /* Start of member's name */ 15933955d011SMarcel Moolenaar 15943955d011SMarcel Moolenaar /* 15953955d011SMarcel Moolenaar * The node is an archive(member) pair. so we must find a 15963955d011SMarcel Moolenaar * suffix for both of them. 15973955d011SMarcel Moolenaar */ 15983955d011SMarcel Moolenaar eoarch = strchr(gn->name, '('); 15993955d011SMarcel Moolenaar eoname = strchr(eoarch, ')'); 16003955d011SMarcel Moolenaar 1601e1cee40dSSimon J. Gerraty /* 1602e1cee40dSSimon J. Gerraty * Caller guarantees the format `libname(member)', via 1603e1cee40dSSimon J. Gerraty * Arch_ParseArchive. 1604e1cee40dSSimon J. Gerraty */ 1605e1cee40dSSimon J. Gerraty assert(eoarch != NULL); 1606e1cee40dSSimon J. Gerraty assert(eoname != NULL); 1607e1cee40dSSimon J. Gerraty 16083955d011SMarcel Moolenaar *eoname = '\0'; /* Nuke parentheses during suffix search */ 16093955d011SMarcel Moolenaar *eoarch = '\0'; /* So a suffix can be found */ 16103955d011SMarcel Moolenaar 16113955d011SMarcel Moolenaar name = eoarch + 1; 16123955d011SMarcel Moolenaar 16133955d011SMarcel Moolenaar /* 1614*06b9b3e0SSimon J. Gerraty * To simplify things, call Suff_FindDeps recursively on the member 1615*06b9b3e0SSimon J. Gerraty * now, so we can simply compare the member's .PREFIX and .TARGET 1616*06b9b3e0SSimon J. Gerraty * variables to locate its suffix. This allows us to figure out the 1617*06b9b3e0SSimon J. Gerraty * suffix to use for the archive without having to do a quadratic 1618*06b9b3e0SSimon J. Gerraty * search over the suffix list, backtracking for each one. 16193955d011SMarcel Moolenaar */ 1620956e45f6SSimon J. Gerraty mem = Targ_GetNode(name); 1621*06b9b3e0SSimon J. Gerraty FindDeps(mem, cs); 16223955d011SMarcel Moolenaar 1623*06b9b3e0SSimon J. Gerraty /* Create the link between the two nodes right off. */ 1624*06b9b3e0SSimon J. Gerraty Lst_Append(&gn->children, mem); 1625*06b9b3e0SSimon J. Gerraty Lst_Append(&mem->parents, gn); 1626956e45f6SSimon J. Gerraty gn->unmade++; 16273955d011SMarcel Moolenaar 1628*06b9b3e0SSimon J. Gerraty /* Copy in the variables from the member node to this one. */ 1629956e45f6SSimon J. Gerraty Var_Set(PREFIX, GNode_VarPrefix(mem), gn); 1630956e45f6SSimon J. Gerraty Var_Set(TARGET, GNode_VarTarget(mem), gn); 16313955d011SMarcel Moolenaar 1632*06b9b3e0SSimon J. Gerraty memSuff = mem->suffix; 1633*06b9b3e0SSimon J. Gerraty if (memSuff == NULL) { /* Didn't know what it was. */ 1634*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "using null suffix\n"); 1635*06b9b3e0SSimon J. Gerraty memSuff = nullSuff; 16363955d011SMarcel Moolenaar } 16373955d011SMarcel Moolenaar 16383955d011SMarcel Moolenaar 1639*06b9b3e0SSimon J. Gerraty /* Set the other two local variables required for this target. */ 16403841c287SSimon J. Gerraty Var_Set(MEMBER, name, gn); 16413841c287SSimon J. Gerraty Var_Set(ARCHIVE, gn->name, gn); 1642*06b9b3e0SSimon J. Gerraty /* Set $@ for compatibility with other makes. */ 16433841c287SSimon J. Gerraty Var_Set(TARGET, gn->name, gn); 16443bebe729SSimon J. Gerraty 16453bebe729SSimon J. Gerraty /* 16463bebe729SSimon J. Gerraty * Now we've got the important local variables set, expand any sources 16473bebe729SSimon J. Gerraty * that still contain variables or wildcards in their names. 16483bebe729SSimon J. Gerraty */ 1649*06b9b3e0SSimon J. Gerraty ExpandAllChildren(gn); 16503bebe729SSimon J. Gerraty 1651*06b9b3e0SSimon J. Gerraty if (memSuff != NULL) 1652*06b9b3e0SSimon J. Gerraty ExpandMember(gn, eoarch, mem, memSuff); 16533955d011SMarcel Moolenaar 16543955d011SMarcel Moolenaar /* 1655*06b9b3e0SSimon J. Gerraty * Replace the opening and closing parens now we've no need of the 1656*06b9b3e0SSimon J. Gerraty * separate pieces. 16573955d011SMarcel Moolenaar */ 1658e2eeea75SSimon J. Gerraty *eoarch = '('; 1659e2eeea75SSimon J. Gerraty *eoname = ')'; 16603955d011SMarcel Moolenaar 16613955d011SMarcel Moolenaar /* 1662*06b9b3e0SSimon J. Gerraty * Pretend gn appeared to the left of a dependency operator so the 1663*06b9b3e0SSimon J. Gerraty * user needn't provide a transformation from the member to the 16643955d011SMarcel Moolenaar * archive. 16653955d011SMarcel Moolenaar */ 1666e2eeea75SSimon J. Gerraty if (!GNode_IsTarget(gn)) 16673955d011SMarcel Moolenaar gn->type |= OP_DEPENDS; 16683955d011SMarcel Moolenaar 16693955d011SMarcel Moolenaar /* 16703955d011SMarcel Moolenaar * Flag the member as such so we remember to look in the archive for 1671*06b9b3e0SSimon J. Gerraty * its modification time. The OP_JOIN | OP_MADE is needed because 1672*06b9b3e0SSimon J. Gerraty * this target should never get made. 16733955d011SMarcel Moolenaar */ 16743bebe729SSimon J. Gerraty mem->type |= OP_MEMBER | OP_JOIN | OP_MADE; 16753955d011SMarcel Moolenaar } 16763955d011SMarcel Moolenaar 1677*06b9b3e0SSimon J. Gerraty /* 1678*06b9b3e0SSimon J. Gerraty * If the node is a library, it is the arch module's job to find it 1679*06b9b3e0SSimon J. Gerraty * and set the TARGET variable accordingly. We merely provide the 1680*06b9b3e0SSimon J. Gerraty * search path, assuming all libraries end in ".a" (if the suffix 1681*06b9b3e0SSimon J. Gerraty * hasn't been defined, there's nothing we can do for it, so we just 1682*06b9b3e0SSimon J. Gerraty * set the TARGET variable to the node's name in order to give it a 1683*06b9b3e0SSimon J. Gerraty * value). 1684*06b9b3e0SSimon J. Gerraty */ 1685956e45f6SSimon J. Gerraty static void 1686*06b9b3e0SSimon J. Gerraty FindDepsLib(GNode *gn) 1687956e45f6SSimon J. Gerraty { 1688*06b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(LIBSUFF); 1689*06b9b3e0SSimon J. Gerraty if (suff != NULL) { 1690*06b9b3e0SSimon J. Gerraty Suffix_Reassign(&gn->suffix, suff); 1691*06b9b3e0SSimon J. Gerraty Arch_FindLib(gn, suff->searchPath); 1692*06b9b3e0SSimon J. Gerraty } else { 1693*06b9b3e0SSimon J. Gerraty Suffix_Unassign(&gn->suffix); 1694*06b9b3e0SSimon J. Gerraty Var_Set(TARGET, gn->name, gn); 1695*06b9b3e0SSimon J. Gerraty } 1696*06b9b3e0SSimon J. Gerraty 1697*06b9b3e0SSimon J. Gerraty /* 1698*06b9b3e0SSimon J. Gerraty * Because a library (-lfoo) target doesn't follow the standard 1699*06b9b3e0SSimon J. Gerraty * filesystem conventions, we don't set the regular variables for 1700*06b9b3e0SSimon J. Gerraty * the thing. .PREFIX is simply made empty. 1701*06b9b3e0SSimon J. Gerraty */ 1702*06b9b3e0SSimon J. Gerraty Var_Set(PREFIX, "", gn); 1703*06b9b3e0SSimon J. Gerraty } 1704*06b9b3e0SSimon J. Gerraty 1705*06b9b3e0SSimon J. Gerraty static void 1706*06b9b3e0SSimon J. Gerraty FindDepsRegularKnown(const char *name, size_t nameLen, GNode *gn, 1707*06b9b3e0SSimon J. Gerraty CandidateList *srcs, CandidateList *targs) 1708*06b9b3e0SSimon J. Gerraty { 1709*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 1710*06b9b3e0SSimon J. Gerraty Candidate *targ; 1711956e45f6SSimon J. Gerraty char *pref; 1712956e45f6SSimon J. Gerraty 1713*06b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 1714*06b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 1715*06b9b3e0SSimon J. Gerraty if (!Suffix_IsSuffix(suff, nameLen, name + nameLen)) 1716956e45f6SSimon J. Gerraty continue; 1717956e45f6SSimon J. Gerraty 1718956e45f6SSimon J. Gerraty pref = bmake_strldup(name, (size_t)(nameLen - suff->nameLen)); 1719*06b9b3e0SSimon J. Gerraty targ = Candidate_New(bmake_strdup(gn->name), pref, suff, NULL, 1720*06b9b3e0SSimon J. Gerraty gn); 1721956e45f6SSimon J. Gerraty 1722*06b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(srcs, targ); 1723956e45f6SSimon J. Gerraty 1724*06b9b3e0SSimon J. Gerraty /* Record the target so we can nuke it. */ 1725956e45f6SSimon J. Gerraty Lst_Append(targs, targ); 1726956e45f6SSimon J. Gerraty } 1727956e45f6SSimon J. Gerraty } 1728956e45f6SSimon J. Gerraty 1729956e45f6SSimon J. Gerraty static void 1730*06b9b3e0SSimon J. Gerraty FindDepsRegularUnknown(GNode *gn, const char *sopref, 1731*06b9b3e0SSimon J. Gerraty CandidateList *srcs, CandidateList *targs) 1732956e45f6SSimon J. Gerraty { 1733*06b9b3e0SSimon J. Gerraty Candidate *targ; 1734956e45f6SSimon J. Gerraty 1735*06b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(targs) || nullSuff == NULL) 1736956e45f6SSimon J. Gerraty return; 1737956e45f6SSimon J. Gerraty 1738*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name); 1739956e45f6SSimon J. Gerraty 1740*06b9b3e0SSimon J. Gerraty targ = Candidate_New(bmake_strdup(gn->name), bmake_strdup(sopref), 1741*06b9b3e0SSimon J. Gerraty nullSuff, NULL, gn); 1742956e45f6SSimon J. Gerraty 1743956e45f6SSimon J. Gerraty /* 1744956e45f6SSimon J. Gerraty * Only use the default suffix rules if we don't have commands 1745*06b9b3e0SSimon J. Gerraty * defined for this gnode; traditional make programs used to not 1746*06b9b3e0SSimon J. Gerraty * define suffix rules if the gnode had children but we don't do 1747*06b9b3e0SSimon J. Gerraty * this anymore. 1748956e45f6SSimon J. Gerraty */ 1749*06b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&gn->commands)) 1750*06b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(srcs, targ); 1751956e45f6SSimon J. Gerraty else { 1752*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "not "); 1753956e45f6SSimon J. Gerraty } 1754956e45f6SSimon J. Gerraty 1755*06b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "adding suffix rules\n"); 1756956e45f6SSimon J. Gerraty 1757956e45f6SSimon J. Gerraty Lst_Append(targs, targ); 1758956e45f6SSimon J. Gerraty } 1759956e45f6SSimon J. Gerraty 1760956e45f6SSimon J. Gerraty /* 1761*06b9b3e0SSimon J. Gerraty * Deal with finding the thing on the default search path. We always do 1762*06b9b3e0SSimon J. Gerraty * that, not only if the node is only a source (not on the lhs of a 1763*06b9b3e0SSimon J. Gerraty * dependency operator or [XXX] it has neither children or commands) as 1764*06b9b3e0SSimon J. Gerraty * the old pmake did. 1765956e45f6SSimon J. Gerraty */ 1766956e45f6SSimon J. Gerraty static void 1767*06b9b3e0SSimon J. Gerraty FindDepsRegularPath(GNode *gn, Candidate *targ) 1768956e45f6SSimon J. Gerraty { 1769956e45f6SSimon J. Gerraty if (gn->type & (OP_PHONY | OP_NOPATH)) 1770956e45f6SSimon J. Gerraty return; 1771956e45f6SSimon J. Gerraty 1772956e45f6SSimon J. Gerraty free(gn->path); 1773956e45f6SSimon J. Gerraty gn->path = Dir_FindFile(gn->name, 1774*06b9b3e0SSimon J. Gerraty (targ == NULL ? &dirSearchPath : 1775956e45f6SSimon J. Gerraty targ->suff->searchPath)); 1776956e45f6SSimon J. Gerraty if (gn->path == NULL) 1777956e45f6SSimon J. Gerraty return; 1778956e45f6SSimon J. Gerraty 1779956e45f6SSimon J. Gerraty Var_Set(TARGET, gn->path, gn); 1780956e45f6SSimon J. Gerraty 1781956e45f6SSimon J. Gerraty if (targ != NULL) { 1782956e45f6SSimon J. Gerraty /* 1783956e45f6SSimon J. Gerraty * Suffix known for the thing -- trim the suffix off 1784956e45f6SSimon J. Gerraty * the path to form the proper .PREFIX variable. 1785956e45f6SSimon J. Gerraty */ 1786956e45f6SSimon J. Gerraty size_t savep = strlen(gn->path) - targ->suff->nameLen; 1787956e45f6SSimon J. Gerraty char savec; 1788956e45f6SSimon J. Gerraty 1789*06b9b3e0SSimon J. Gerraty Suffix_Reassign(&gn->suffix, targ->suff); 1790956e45f6SSimon J. Gerraty 1791956e45f6SSimon J. Gerraty savec = gn->path[savep]; 1792956e45f6SSimon J. Gerraty gn->path[savep] = '\0'; 1793956e45f6SSimon J. Gerraty 1794*06b9b3e0SSimon J. Gerraty Var_Set(PREFIX, str_basename(gn->path), gn); 1795956e45f6SSimon J. Gerraty 1796956e45f6SSimon J. Gerraty gn->path[savep] = savec; 1797956e45f6SSimon J. Gerraty } else { 1798*06b9b3e0SSimon J. Gerraty /* 1799*06b9b3e0SSimon J. Gerraty * The .PREFIX gets the full path if the target has no 1800*06b9b3e0SSimon J. Gerraty * known suffix. 1801*06b9b3e0SSimon J. Gerraty */ 1802*06b9b3e0SSimon J. Gerraty Suffix_Unassign(&gn->suffix); 1803*06b9b3e0SSimon J. Gerraty Var_Set(PREFIX, str_basename(gn->path), gn); 1804956e45f6SSimon J. Gerraty } 1805956e45f6SSimon J. Gerraty } 1806956e45f6SSimon J. Gerraty 1807*06b9b3e0SSimon J. Gerraty /* 1808*06b9b3e0SSimon J. Gerraty * Locate implicit dependencies for regular targets. 18093955d011SMarcel Moolenaar * 18103955d011SMarcel Moolenaar * Input: 18113955d011SMarcel Moolenaar * gn Node for which to find sources 18123955d011SMarcel Moolenaar * 18133955d011SMarcel Moolenaar * Side Effects: 18142c3632d1SSimon J. Gerraty * Same as Suff_FindDeps 18153955d011SMarcel Moolenaar */ 18163955d011SMarcel Moolenaar static void 1817*06b9b3e0SSimon J. Gerraty FindDepsRegular(GNode *gn, CandidateSearcher *cs) 18183955d011SMarcel Moolenaar { 1819*06b9b3e0SSimon J. Gerraty /* List of sources at which to look */ 1820*06b9b3e0SSimon J. Gerraty CandidateList srcs = LST_INIT; 1821*06b9b3e0SSimon J. Gerraty /* 1822*06b9b3e0SSimon J. Gerraty * List of targets to which things can be transformed. 1823*06b9b3e0SSimon J. Gerraty * They all have the same file, but different suff and prefix fields. 1824*06b9b3e0SSimon J. Gerraty */ 1825*06b9b3e0SSimon J. Gerraty CandidateList targs = LST_INIT; 1826*06b9b3e0SSimon J. Gerraty Candidate *bottom; /* Start of found transformation path */ 1827*06b9b3e0SSimon J. Gerraty Candidate *src; 1828*06b9b3e0SSimon J. Gerraty Candidate *targ; 18293955d011SMarcel Moolenaar 1830956e45f6SSimon J. Gerraty const char *name = gn->name; 1831956e45f6SSimon J. Gerraty size_t nameLen = strlen(name); 18323955d011SMarcel Moolenaar 1833*06b9b3e0SSimon J. Gerraty #ifdef DEBUG_SRC 1834*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "FindDepsRegular \"%s\"\n", gn->name); 1835*06b9b3e0SSimon J. Gerraty #endif 18363955d011SMarcel Moolenaar 18373955d011SMarcel Moolenaar /* 1838*06b9b3e0SSimon J. Gerraty * We're caught in a catch-22 here. On the one hand, we want to use 1839*06b9b3e0SSimon J. Gerraty * any transformation implied by the target's sources, but we can't 1840*06b9b3e0SSimon J. Gerraty * examine the sources until we've expanded any variables/wildcards 1841*06b9b3e0SSimon J. Gerraty * they may hold, and we can't do that until we've set up the 1842*06b9b3e0SSimon J. Gerraty * target's local variables and we can't do that until we know what 1843*06b9b3e0SSimon J. Gerraty * the proper suffix for the target is (in case there are two 1844*06b9b3e0SSimon J. Gerraty * suffixes one of which is a suffix of the other) and we can't know 1845*06b9b3e0SSimon J. Gerraty * that until we've found its implied source, which we may not want 1846*06b9b3e0SSimon J. Gerraty * to use if there's an existing source that implies a different 1847*06b9b3e0SSimon J. Gerraty * transformation. 18483955d011SMarcel Moolenaar * 18493955d011SMarcel Moolenaar * In an attempt to get around this, which may not work all the time, 1850*06b9b3e0SSimon J. Gerraty * but should work most of the time, we look for implied sources 1851*06b9b3e0SSimon J. Gerraty * first, checking transformations to all possible suffixes of the 1852*06b9b3e0SSimon J. Gerraty * target, use what we find to set the target's local variables, 1853*06b9b3e0SSimon J. Gerraty * expand the children, then look for any overriding transformations 1854*06b9b3e0SSimon J. Gerraty * they imply. Should we find one, we discard the one we found before. 18553955d011SMarcel Moolenaar */ 18564fc82fe4SSimon J. Gerraty bottom = NULL; 18574fc82fe4SSimon J. Gerraty targ = NULL; 18584fc82fe4SSimon J. Gerraty 18594fc82fe4SSimon J. Gerraty if (!(gn->type & OP_PHONY)) { 18603955d011SMarcel Moolenaar 1861*06b9b3e0SSimon J. Gerraty FindDepsRegularKnown(name, nameLen, gn, &srcs, &targs); 18623955d011SMarcel Moolenaar 1863956e45f6SSimon J. Gerraty /* Handle target of unknown suffix... */ 1864*06b9b3e0SSimon J. Gerraty FindDepsRegularUnknown(gn, name, &srcs, &targs); 18653955d011SMarcel Moolenaar 18663955d011SMarcel Moolenaar /* 186752d86256SSimon J. Gerraty * Using the list of possible sources built up from the target 1868*06b9b3e0SSimon J. Gerraty * suffix(es), try and find an existing file/target that 1869*06b9b3e0SSimon J. Gerraty * matches. 18703955d011SMarcel Moolenaar */ 1871*06b9b3e0SSimon J. Gerraty bottom = FindThem(&srcs, cs); 18723955d011SMarcel Moolenaar 18733955d011SMarcel Moolenaar if (bottom == NULL) { 18743955d011SMarcel Moolenaar /* 1875*06b9b3e0SSimon J. Gerraty * No known transformations -- use the first suffix 1876*06b9b3e0SSimon J. Gerraty * found for setting the local variables. 18773955d011SMarcel Moolenaar */ 1878*06b9b3e0SSimon J. Gerraty if (targs.first != NULL) 1879*06b9b3e0SSimon J. Gerraty targ = targs.first->datum; 1880e2eeea75SSimon J. Gerraty else 18813955d011SMarcel Moolenaar targ = NULL; 18823955d011SMarcel Moolenaar } else { 18833955d011SMarcel Moolenaar /* 1884*06b9b3e0SSimon J. Gerraty * Work up the transformation path to find the suffix 1885*06b9b3e0SSimon J. Gerraty * of the target to which the transformation was made. 18863955d011SMarcel Moolenaar */ 1887*06b9b3e0SSimon J. Gerraty for (targ = bottom; 1888*06b9b3e0SSimon J. Gerraty targ->parent != NULL; targ = targ->parent) 18893955d011SMarcel Moolenaar continue; 18903955d011SMarcel Moolenaar } 18914fc82fe4SSimon J. Gerraty } 18923955d011SMarcel Moolenaar 1893956e45f6SSimon J. Gerraty Var_Set(TARGET, GNode_Path(gn), gn); 1894*06b9b3e0SSimon J. Gerraty Var_Set(PREFIX, targ != NULL ? targ->prefix : gn->name, gn); 18953955d011SMarcel Moolenaar 18963955d011SMarcel Moolenaar /* 18973955d011SMarcel Moolenaar * Now we've got the important local variables set, expand any sources 18983955d011SMarcel Moolenaar * that still contain variables or wildcards in their names. 18993955d011SMarcel Moolenaar */ 1900956e45f6SSimon J. Gerraty { 1901*06b9b3e0SSimon J. Gerraty GNodeListNode *ln, *nln; 1902*06b9b3e0SSimon J. Gerraty for (ln = gn->children.first; ln != NULL; ln = nln) { 1903956e45f6SSimon J. Gerraty nln = ln->next; 1904*06b9b3e0SSimon J. Gerraty ExpandChildren(ln, gn); 19053955d011SMarcel Moolenaar } 1906956e45f6SSimon J. Gerraty } 19073955d011SMarcel Moolenaar 19083955d011SMarcel Moolenaar if (targ == NULL) { 1909*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\tNo valid suffix on %s\n", gn->name); 19103955d011SMarcel Moolenaar 19113955d011SMarcel Moolenaar sfnd_abort: 1912*06b9b3e0SSimon J. Gerraty FindDepsRegularPath(gn, targ); 19133955d011SMarcel Moolenaar goto sfnd_return; 19143955d011SMarcel Moolenaar } 19153955d011SMarcel Moolenaar 19163955d011SMarcel Moolenaar /* 19173955d011SMarcel Moolenaar * If the suffix indicates that the target is a library, mark that in 19183955d011SMarcel Moolenaar * the node's type field. 19193955d011SMarcel Moolenaar */ 1920e2eeea75SSimon J. Gerraty if (targ->suff->flags & SUFF_LIBRARY) 19213955d011SMarcel Moolenaar gn->type |= OP_LIB; 19223955d011SMarcel Moolenaar 19233955d011SMarcel Moolenaar /* 19243955d011SMarcel Moolenaar * Check for overriding transformation rule implied by sources 19253955d011SMarcel Moolenaar */ 1926*06b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&gn->children)) { 1927*06b9b3e0SSimon J. Gerraty src = FindCmds(targ, cs); 19283955d011SMarcel Moolenaar 19293955d011SMarcel Moolenaar if (src != NULL) { 19303955d011SMarcel Moolenaar /* 1931*06b9b3e0SSimon J. Gerraty * Free up all the candidates in the transformation 1932*06b9b3e0SSimon J. Gerraty * path, up to but not including the parent node. 19333955d011SMarcel Moolenaar */ 1934e2eeea75SSimon J. Gerraty while (bottom != NULL && bottom->parent != NULL) { 1935*06b9b3e0SSimon J. Gerraty CandidateSearcher_AddIfNew(cs, bottom); 19363955d011SMarcel Moolenaar bottom = bottom->parent; 19373955d011SMarcel Moolenaar } 19383955d011SMarcel Moolenaar bottom = src; 19393955d011SMarcel Moolenaar } 19403955d011SMarcel Moolenaar } 19413955d011SMarcel Moolenaar 19423955d011SMarcel Moolenaar if (bottom == NULL) { 1943*06b9b3e0SSimon J. Gerraty /* No idea from where it can come -- return now. */ 19443955d011SMarcel Moolenaar goto sfnd_abort; 19453955d011SMarcel Moolenaar } 19463955d011SMarcel Moolenaar 19473955d011SMarcel Moolenaar /* 1948*06b9b3e0SSimon J. Gerraty * We now have a list of candidates headed by 'bottom' and linked via 19493955d011SMarcel Moolenaar * their 'parent' pointers. What we do next is create links between 19503955d011SMarcel Moolenaar * source and target nodes (which may or may not have been created) 1951*06b9b3e0SSimon J. Gerraty * and set the necessary local variables in each target. 1952*06b9b3e0SSimon J. Gerraty * 1953*06b9b3e0SSimon J. Gerraty * The commands for each target are set from the commands of the 19543955d011SMarcel Moolenaar * transformation rule used to get from the src suffix to the targ 19553955d011SMarcel Moolenaar * suffix. Note that this causes the commands list of the original 1956*06b9b3e0SSimon J. Gerraty * node, gn, to be replaced with the commands of the final 1957*06b9b3e0SSimon J. Gerraty * transformation rule. 19583955d011SMarcel Moolenaar */ 1959e2eeea75SSimon J. Gerraty if (bottom->node == NULL) 1960956e45f6SSimon J. Gerraty bottom->node = Targ_GetNode(bottom->file); 19613955d011SMarcel Moolenaar 19623955d011SMarcel Moolenaar for (src = bottom; src->parent != NULL; src = src->parent) { 19633955d011SMarcel Moolenaar targ = src->parent; 19643955d011SMarcel Moolenaar 1965*06b9b3e0SSimon J. Gerraty Suffix_Reassign(&src->node->suffix, src->suff); 19663955d011SMarcel Moolenaar 1967e2eeea75SSimon J. Gerraty if (targ->node == NULL) 1968956e45f6SSimon J. Gerraty targ->node = Targ_GetNode(targ->file); 19693955d011SMarcel Moolenaar 1970*06b9b3e0SSimon J. Gerraty ApplyTransform(targ->node, src->node, 19713955d011SMarcel Moolenaar targ->suff, src->suff); 19723955d011SMarcel Moolenaar 19733955d011SMarcel Moolenaar if (targ->node != gn) { 19743955d011SMarcel Moolenaar /* 1975*06b9b3e0SSimon J. Gerraty * Finish off the dependency-search process for any 1976*06b9b3e0SSimon J. Gerraty * nodes between bottom and gn (no point in questing 1977*06b9b3e0SSimon J. Gerraty * around the filesystem for their implicit source 1978*06b9b3e0SSimon J. Gerraty * when it's already known). Note that the node 1979*06b9b3e0SSimon J. Gerraty * can't have any sources that need expanding, since 1980*06b9b3e0SSimon J. Gerraty * SuffFindThem will stop on an existing node, so all 1981*06b9b3e0SSimon J. Gerraty * we need to do is set the standard variables. 19823955d011SMarcel Moolenaar */ 19833955d011SMarcel Moolenaar targ->node->type |= OP_DEPS_FOUND; 1984*06b9b3e0SSimon J. Gerraty Var_Set(PREFIX, targ->prefix, targ->node); 19853841c287SSimon J. Gerraty Var_Set(TARGET, targ->node->name, targ->node); 19863955d011SMarcel Moolenaar } 19873955d011SMarcel Moolenaar } 19883955d011SMarcel Moolenaar 1989*06b9b3e0SSimon J. Gerraty Suffix_Reassign(&gn->suffix, src->suff); 19903955d011SMarcel Moolenaar 19913955d011SMarcel Moolenaar /* 1992*06b9b3e0SSimon J. Gerraty * Nuke the transformation path and the candidates left over in the 19933955d011SMarcel Moolenaar * two lists. 19943955d011SMarcel Moolenaar */ 19953955d011SMarcel Moolenaar sfnd_return: 1996*06b9b3e0SSimon J. Gerraty if (bottom != NULL) 1997*06b9b3e0SSimon J. Gerraty CandidateSearcher_AddIfNew(cs, bottom); 19983955d011SMarcel Moolenaar 1999*06b9b3e0SSimon J. Gerraty while (RemoveCandidate(&srcs) || RemoveCandidate(&targs)) 20003955d011SMarcel Moolenaar continue; 20013955d011SMarcel Moolenaar 2002*06b9b3e0SSimon J. Gerraty CandidateSearcher_MoveAll(cs, &srcs); 2003*06b9b3e0SSimon J. Gerraty CandidateSearcher_MoveAll(cs, &targs); 2004*06b9b3e0SSimon J. Gerraty } 2005*06b9b3e0SSimon J. Gerraty 2006*06b9b3e0SSimon J. Gerraty static void 2007*06b9b3e0SSimon J. Gerraty CandidateSearcher_CleanUp(CandidateSearcher *cs) 2008*06b9b3e0SSimon J. Gerraty { 2009*06b9b3e0SSimon J. Gerraty while (RemoveCandidate(&cs->list)) 2010*06b9b3e0SSimon J. Gerraty continue; 2011*06b9b3e0SSimon J. Gerraty assert(Lst_IsEmpty(&cs->list)); 20123955d011SMarcel Moolenaar } 20133955d011SMarcel Moolenaar 20143955d011SMarcel Moolenaar 2015*06b9b3e0SSimon J. Gerraty /* 2016*06b9b3e0SSimon J. Gerraty * Find implicit sources for the target. 20173955d011SMarcel Moolenaar * 2018*06b9b3e0SSimon J. Gerraty * Nodes are added to the graph as children of the passed-in node. The nodes 2019*06b9b3e0SSimon J. Gerraty * are marked to have their IMPSRC variable filled in. The PREFIX variable 2020*06b9b3e0SSimon J. Gerraty * is set for the given node and all its implied children. 20213955d011SMarcel Moolenaar * 20222c3632d1SSimon J. Gerraty * The path found by this target is the shortest path in the transformation 2023*06b9b3e0SSimon J. Gerraty * graph, which may pass through nonexistent targets, to an existing target. 20242c3632d1SSimon J. Gerraty * The search continues on all paths from the root suffix until a file is 20252c3632d1SSimon J. Gerraty * found. I.e. if there's a path .o -> .c -> .l -> .l,v from the root and the 20262c3632d1SSimon J. Gerraty * .l,v file exists but the .c and .l files don't, the search will branch out 20272c3632d1SSimon J. Gerraty * in all directions from .o and again from all the nodes on the next level 20282c3632d1SSimon J. Gerraty * until the .l,v node is encountered. 20293955d011SMarcel Moolenaar */ 20303955d011SMarcel Moolenaar void 20313955d011SMarcel Moolenaar Suff_FindDeps(GNode *gn) 20323955d011SMarcel Moolenaar { 2033*06b9b3e0SSimon J. Gerraty CandidateSearcher cs; 20343955d011SMarcel Moolenaar 2035*06b9b3e0SSimon J. Gerraty CandidateSearcher_Init(&cs); 2036*06b9b3e0SSimon J. Gerraty 2037*06b9b3e0SSimon J. Gerraty FindDeps(gn, &cs); 2038*06b9b3e0SSimon J. Gerraty 2039*06b9b3e0SSimon J. Gerraty CandidateSearcher_CleanUp(&cs); 2040*06b9b3e0SSimon J. Gerraty CandidateSearcher_Done(&cs); 20413955d011SMarcel Moolenaar } 20423955d011SMarcel Moolenaar 20433955d011SMarcel Moolenaar static void 2044*06b9b3e0SSimon J. Gerraty FindDeps(GNode *gn, CandidateSearcher *cs) 20453955d011SMarcel Moolenaar { 20462c3632d1SSimon J. Gerraty if (gn->type & OP_DEPS_FOUND) 20473955d011SMarcel Moolenaar return; 20483955d011SMarcel Moolenaar gn->type |= OP_DEPS_FOUND; 20492c3632d1SSimon J. Gerraty 2050*06b9b3e0SSimon J. Gerraty /* Make sure we have these set, may get revised below. */ 2051956e45f6SSimon J. Gerraty Var_Set(TARGET, GNode_Path(gn), gn); 20523841c287SSimon J. Gerraty Var_Set(PREFIX, gn->name, gn); 20534fc82fe4SSimon J. Gerraty 2054*06b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "SuffFindDeps \"%s\"\n", gn->name); 20553955d011SMarcel Moolenaar 2056*06b9b3e0SSimon J. Gerraty if (gn->type & OP_ARCHV) 2057*06b9b3e0SSimon J. Gerraty FindDepsArchive(gn, cs); 2058*06b9b3e0SSimon J. Gerraty else if (gn->type & OP_LIB) 2059*06b9b3e0SSimon J. Gerraty FindDepsLib(gn); 2060*06b9b3e0SSimon J. Gerraty else 2061*06b9b3e0SSimon J. Gerraty FindDepsRegular(gn, cs); 20623955d011SMarcel Moolenaar } 20633955d011SMarcel Moolenaar 2064*06b9b3e0SSimon J. Gerraty /* 2065*06b9b3e0SSimon J. Gerraty * Define which suffix is the null suffix. 20662c3632d1SSimon J. Gerraty * 20672c3632d1SSimon J. Gerraty * Need to handle the changing of the null suffix gracefully so the old 20682c3632d1SSimon J. Gerraty * transformation rules don't just go away. 20693955d011SMarcel Moolenaar * 20703955d011SMarcel Moolenaar * Input: 20713955d011SMarcel Moolenaar * name Name of null suffix 20723955d011SMarcel Moolenaar */ 20733955d011SMarcel Moolenaar void 2074956e45f6SSimon J. Gerraty Suff_SetNull(const char *name) 20753955d011SMarcel Moolenaar { 2076*06b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(name); 2077e2eeea75SSimon J. Gerraty if (suff == NULL) { 2078*06b9b3e0SSimon J. Gerraty Parse_Error(PARSE_WARNING, 2079*06b9b3e0SSimon J. Gerraty "Desired null suffix %s not defined.", 2080956e45f6SSimon J. Gerraty name); 2081956e45f6SSimon J. Gerraty return; 2082956e45f6SSimon J. Gerraty } 20833955d011SMarcel Moolenaar 2084*06b9b3e0SSimon J. Gerraty if (nullSuff != NULL) 2085*06b9b3e0SSimon J. Gerraty nullSuff->flags &= ~(unsigned)SUFF_NULL; 2086e2eeea75SSimon J. Gerraty suff->flags |= SUFF_NULL; 2087*06b9b3e0SSimon J. Gerraty /* XXX: Here's where the transformation mangling would take place. */ 2088*06b9b3e0SSimon J. Gerraty nullSuff = suff; 20893955d011SMarcel Moolenaar } 20903955d011SMarcel Moolenaar 20912c3632d1SSimon J. Gerraty /* Initialize the suffixes module. */ 20923955d011SMarcel Moolenaar void 20933955d011SMarcel Moolenaar Suff_Init(void) 20943955d011SMarcel Moolenaar { 20953955d011SMarcel Moolenaar /* 2096*06b9b3e0SSimon J. Gerraty * Create null suffix for single-suffix rules (POSIX). The thing 2097*06b9b3e0SSimon J. Gerraty * doesn't actually go on the suffix list or everyone will think 2098*06b9b3e0SSimon J. Gerraty * that's its suffix. 20993955d011SMarcel Moolenaar */ 21006e050540SSimon J. Gerraty Suff_ClearSuffixes(); 21013955d011SMarcel Moolenaar } 21023955d011SMarcel Moolenaar 21033955d011SMarcel Moolenaar 21042c3632d1SSimon J. Gerraty /* Clean up the suffixes module. */ 21053955d011SMarcel Moolenaar void 21063955d011SMarcel Moolenaar Suff_End(void) 21073955d011SMarcel Moolenaar { 21083955d011SMarcel Moolenaar #ifdef CLEANUP 2109*06b9b3e0SSimon J. Gerraty Lst_DoneCall(&sufflist, SuffFree); 2110*06b9b3e0SSimon J. Gerraty Lst_DoneCall(&suffClean, SuffFree); 2111*06b9b3e0SSimon J. Gerraty if (nullSuff != NULL) 2112*06b9b3e0SSimon J. Gerraty SuffFree(nullSuff); 2113*06b9b3e0SSimon J. Gerraty Lst_Done(&transforms); 21143955d011SMarcel Moolenaar #endif 21153955d011SMarcel Moolenaar } 21163955d011SMarcel Moolenaar 21173955d011SMarcel Moolenaar 2118956e45f6SSimon J. Gerraty static void 2119*06b9b3e0SSimon J. Gerraty PrintSuffNames(const char *prefix, SuffixList *suffs) 21203955d011SMarcel Moolenaar { 2121*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 212295e3ed2cSSimon J. Gerraty 2123956e45f6SSimon J. Gerraty debug_printf("#\t%s: ", prefix); 2124956e45f6SSimon J. Gerraty for (ln = suffs->first; ln != NULL; ln = ln->next) { 2125*06b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 2126956e45f6SSimon J. Gerraty debug_printf("%s ", suff->name); 2127956e45f6SSimon J. Gerraty } 2128956e45f6SSimon J. Gerraty debug_printf("\n"); 21293955d011SMarcel Moolenaar } 21303955d011SMarcel Moolenaar 2131956e45f6SSimon J. Gerraty static void 2132*06b9b3e0SSimon J. Gerraty Suffix_Print(Suffix *suff) 21333955d011SMarcel Moolenaar { 2134e2eeea75SSimon J. Gerraty debug_printf("# \"%s\" (num %d, ref %d)", 2135e2eeea75SSimon J. Gerraty suff->name, suff->sNum, suff->refCount); 2136e2eeea75SSimon J. Gerraty if (suff->flags != 0) { 2137*06b9b3e0SSimon J. Gerraty char flags_buf[SuffixFlags_ToStringSize]; 21382c3632d1SSimon J. Gerraty 2139956e45f6SSimon J. Gerraty debug_printf(" (%s)", 21402c3632d1SSimon J. Gerraty Enum_FlagsToString(flags_buf, sizeof flags_buf, 2141*06b9b3e0SSimon J. Gerraty suff->flags, 2142*06b9b3e0SSimon J. Gerraty SuffixFlags_ToStringSpecs)); 21433955d011SMarcel Moolenaar } 2144956e45f6SSimon J. Gerraty debug_printf("\n"); 2145956e45f6SSimon J. Gerraty 2146*06b9b3e0SSimon J. Gerraty PrintSuffNames("To", &suff->parents); 2147*06b9b3e0SSimon J. Gerraty PrintSuffNames("From", &suff->children); 2148956e45f6SSimon J. Gerraty 2149956e45f6SSimon J. Gerraty debug_printf("#\tSearch Path: "); 2150*06b9b3e0SSimon J. Gerraty SearchPath_Print(suff->searchPath); 2151956e45f6SSimon J. Gerraty debug_printf("\n"); 21523955d011SMarcel Moolenaar } 21533955d011SMarcel Moolenaar 2154956e45f6SSimon J. Gerraty static void 2155956e45f6SSimon J. Gerraty PrintTransformation(GNode *t) 21563955d011SMarcel Moolenaar { 2157956e45f6SSimon J. Gerraty debug_printf("%-16s:", t->name); 21583955d011SMarcel Moolenaar Targ_PrintType(t->type); 2159956e45f6SSimon J. Gerraty debug_printf("\n"); 2160956e45f6SSimon J. Gerraty Targ_PrintCmds(t); 2161956e45f6SSimon J. Gerraty debug_printf("\n"); 21623955d011SMarcel Moolenaar } 21633955d011SMarcel Moolenaar 21643955d011SMarcel Moolenaar void 21653955d011SMarcel Moolenaar Suff_PrintAll(void) 21663955d011SMarcel Moolenaar { 2167956e45f6SSimon J. Gerraty debug_printf("#*** Suffixes:\n"); 2168956e45f6SSimon J. Gerraty { 2169*06b9b3e0SSimon J. Gerraty SuffixListNode *ln; 2170*06b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) 2171*06b9b3e0SSimon J. Gerraty Suffix_Print(ln->datum); 2172956e45f6SSimon J. Gerraty } 21733955d011SMarcel Moolenaar 2174956e45f6SSimon J. Gerraty debug_printf("#*** Transformations:\n"); 2175956e45f6SSimon J. Gerraty { 2176956e45f6SSimon J. Gerraty GNodeListNode *ln; 2177*06b9b3e0SSimon J. Gerraty for (ln = transforms.first; ln != NULL; ln = ln->next) 2178956e45f6SSimon J. Gerraty PrintTransformation(ln->datum); 2179956e45f6SSimon J. Gerraty } 21803955d011SMarcel Moolenaar } 2181