1*22619282SSimon J. Gerraty /* $NetBSD: suff.c,v 1.382 2024/07/07 07:50:57 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 * 80b0c40a00SSimon J. Gerraty * Suff_ExtendPaths 81b0c40a00SSimon J. Gerraty * Extend the search path of each suffix to include the 82e2eeea75SSimon J. Gerraty * default search path. 833955d011SMarcel Moolenaar * 84956e45f6SSimon J. Gerraty * Suff_ClearSuffixes 85e2eeea75SSimon J. Gerraty * Clear out all the suffixes and transformations. 863955d011SMarcel Moolenaar * 87956e45f6SSimon J. Gerraty * Suff_IsTransform 88e2eeea75SSimon J. Gerraty * See if the passed string is a transformation rule. 893955d011SMarcel Moolenaar * 903955d011SMarcel Moolenaar * Suff_AddSuffix Add the passed string as another known suffix. 913955d011SMarcel Moolenaar * 923955d011SMarcel Moolenaar * Suff_GetPath Return the search path for the given suffix. 933955d011SMarcel Moolenaar * 94956e45f6SSimon J. Gerraty * Suff_AddInclude 95956e45f6SSimon J. Gerraty * Mark the given suffix as denoting an include file. 963955d011SMarcel Moolenaar * 973955d011SMarcel Moolenaar * Suff_AddLib Mark the given suffix as denoting a library. 983955d011SMarcel Moolenaar * 99956e45f6SSimon J. Gerraty * Suff_AddTransform 100e2eeea75SSimon J. Gerraty * Add another transformation to the suffix graph. 1013955d011SMarcel Moolenaar * 1023955d011SMarcel Moolenaar * Suff_SetNull Define the suffix to consider the suffix of 1033955d011SMarcel Moolenaar * any file that doesn't have a known one. 1043955d011SMarcel Moolenaar * 1053955d011SMarcel Moolenaar * Suff_FindDeps Find implicit sources for and the location of 1063955d011SMarcel Moolenaar * a target based on its suffix. Returns the 1073955d011SMarcel Moolenaar * bottom-most node added to the graph or NULL 1083955d011SMarcel Moolenaar * if the target had no implicit sources. 1093955d011SMarcel Moolenaar * 110956e45f6SSimon J. Gerraty * Suff_FindPath Return the appropriate path to search in order to 111956e45f6SSimon J. Gerraty * find the node. 1123955d011SMarcel Moolenaar */ 1133955d011SMarcel Moolenaar 1143955d011SMarcel Moolenaar #include "make.h" 1153955d011SMarcel Moolenaar #include "dir.h" 1163955d011SMarcel Moolenaar 117956e45f6SSimon J. Gerraty /* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */ 118*22619282SSimon J. Gerraty MAKE_RCSID("$NetBSD: suff.c,v 1.382 2024/07/07 07:50:57 rillig Exp $"); 1192c3632d1SSimon J. Gerraty 12006b9b3e0SSimon J. Gerraty typedef List SuffixList; 12106b9b3e0SSimon J. Gerraty typedef ListNode SuffixListNode; 1222c3632d1SSimon J. Gerraty 12306b9b3e0SSimon J. Gerraty typedef List CandidateList; 12406b9b3e0SSimon J. Gerraty typedef ListNode CandidateListNode; 1252c3632d1SSimon J. Gerraty 12606b9b3e0SSimon J. Gerraty /* The defined suffixes, such as '.c', '.o', '.l'. */ 12706b9b3e0SSimon J. Gerraty static SuffixList sufflist = LST_INIT; 1283955d011SMarcel Moolenaar #ifdef CLEANUP 12906b9b3e0SSimon J. Gerraty /* The suffixes to be cleaned up at the end. */ 13006b9b3e0SSimon J. Gerraty static SuffixList suffClean = LST_INIT; 1313955d011SMarcel Moolenaar #endif 132e2eeea75SSimon J. Gerraty 13306b9b3e0SSimon J. Gerraty /* 13406b9b3e0SSimon J. Gerraty * The transformation rules, such as '.c.o' to transform '.c' into '.o', 13506b9b3e0SSimon J. Gerraty * or simply '.c' to transform 'file.c' into 'file'. 13606b9b3e0SSimon J. Gerraty */ 13706b9b3e0SSimon J. Gerraty static GNodeList transforms = LST_INIT; 1383955d011SMarcel Moolenaar 13906b9b3e0SSimon J. Gerraty /* 14006b9b3e0SSimon J. Gerraty * Counter for assigning suffix numbers. 14106b9b3e0SSimon J. Gerraty * TODO: What are these suffix numbers used for? 14206b9b3e0SSimon J. Gerraty */ 14306b9b3e0SSimon J. Gerraty static int sNum = 0; 1443955d011SMarcel Moolenaar 14506b9b3e0SSimon J. Gerraty /* 1461d3f2ddcSSimon J. Gerraty * A suffix such as ".c" or ".o" that may be used in suffix transformation 1471d3f2ddcSSimon J. Gerraty * rules such as ".c.o:". 14806b9b3e0SSimon J. Gerraty */ 14906b9b3e0SSimon J. Gerraty typedef struct Suffix { 150e2eeea75SSimon J. Gerraty /* The suffix itself, such as ".c" */ 151e2eeea75SSimon J. Gerraty char *name; 152e2eeea75SSimon J. Gerraty /* Length of the name, to avoid strlen calls */ 153e2eeea75SSimon J. Gerraty size_t nameLen; 15412904384SSimon J. Gerraty /* 15512904384SSimon J. Gerraty * This suffix marks include files. Their search path ends up in the 15612904384SSimon J. Gerraty * undocumented special variable '.INCLUDES'. 15712904384SSimon J. Gerraty */ 15812904384SSimon J. Gerraty bool include:1; 15912904384SSimon J. Gerraty /* 16012904384SSimon J. Gerraty * This suffix marks library files. Their search path ends up in the 16112904384SSimon J. Gerraty * undocumented special variable '.LIBS'. 16212904384SSimon J. Gerraty */ 16312904384SSimon J. Gerraty bool library:1; 16412904384SSimon J. Gerraty /* 16512904384SSimon J. Gerraty * The empty suffix. 16612904384SSimon J. Gerraty * 16712904384SSimon J. Gerraty * XXX: What is the difference between the empty suffix and the null 16812904384SSimon J. Gerraty * suffix? 16912904384SSimon J. Gerraty * 17012904384SSimon J. Gerraty * XXX: Why is SUFF_NULL needed at all? Wouldn't nameLen == 0 mean 17112904384SSimon J. Gerraty * the same? 17212904384SSimon J. Gerraty */ 17312904384SSimon J. Gerraty bool isNull:1; 174e2eeea75SSimon J. Gerraty /* The path along which files of this suffix may be found */ 175e2eeea75SSimon J. Gerraty SearchPath *searchPath; 17612904384SSimon J. Gerraty 177e2eeea75SSimon J. Gerraty /* The suffix number; TODO: document the purpose of this number */ 178e2eeea75SSimon J. Gerraty int sNum; 179e2eeea75SSimon J. Gerraty /* Reference count of list membership and several other places */ 180e2eeea75SSimon J. Gerraty int refCount; 18112904384SSimon J. Gerraty 182e2eeea75SSimon J. Gerraty /* Suffixes we have a transformation to */ 18306b9b3e0SSimon J. Gerraty SuffixList parents; 184e2eeea75SSimon J. Gerraty /* Suffixes we have a transformation from */ 18506b9b3e0SSimon J. Gerraty SuffixList children; 18606b9b3e0SSimon J. Gerraty } Suffix; 1873955d011SMarcel Moolenaar 1883955d011SMarcel Moolenaar /* 18906b9b3e0SSimon J. Gerraty * A candidate when searching for implied sources. 19006b9b3e0SSimon J. Gerraty * 19106b9b3e0SSimon J. Gerraty * For example, when "src.o" is to be made, a typical candidate is "src.c" 19206b9b3e0SSimon J. Gerraty * via the transformation rule ".c.o". If that doesn't exist, maybe there is 19306b9b3e0SSimon J. Gerraty * another transformation rule ".pas.c" that would make "src.pas" an indirect 19406b9b3e0SSimon J. Gerraty * candidate as well. The first such chain that leads to an existing file or 19506b9b3e0SSimon J. Gerraty * node is finally chosen to be made. 1963955d011SMarcel Moolenaar */ 19706b9b3e0SSimon J. Gerraty typedef struct Candidate { 19806b9b3e0SSimon J. Gerraty /* The file or node to look for. */ 19906b9b3e0SSimon J. Gerraty char *file; 2009f45a3c8SSimon J. Gerraty /* 2019f45a3c8SSimon J. Gerraty * The prefix from which file was formed. Its memory is shared among 2029f45a3c8SSimon J. Gerraty * all candidates. 2039f45a3c8SSimon J. Gerraty */ 20406b9b3e0SSimon J. Gerraty char *prefix; 20506b9b3e0SSimon J. Gerraty /* The suffix on the file. */ 20606b9b3e0SSimon J. Gerraty Suffix *suff; 20706b9b3e0SSimon J. Gerraty 2089f45a3c8SSimon J. Gerraty /* 2099f45a3c8SSimon J. Gerraty * The candidate that can be made from this, or NULL for the 2109f45a3c8SSimon J. Gerraty * top-level candidate. 2119f45a3c8SSimon J. Gerraty */ 21206b9b3e0SSimon J. Gerraty struct Candidate *parent; 21306b9b3e0SSimon J. Gerraty /* The node describing the file. */ 21406b9b3e0SSimon J. Gerraty GNode *node; 21506b9b3e0SSimon J. Gerraty 2169f45a3c8SSimon J. Gerraty /* 2179f45a3c8SSimon J. Gerraty * Count of existing children, only used for memory management, so we 2189f45a3c8SSimon J. Gerraty * don't free this candidate too early or too late. 2199f45a3c8SSimon J. Gerraty */ 22006b9b3e0SSimon J. Gerraty int numChildren; 2213955d011SMarcel Moolenaar #ifdef DEBUG_SRC 22206b9b3e0SSimon J. Gerraty CandidateList childrenList; 2233955d011SMarcel Moolenaar #endif 22406b9b3e0SSimon J. Gerraty } Candidate; 2253955d011SMarcel Moolenaar 22606b9b3e0SSimon J. Gerraty typedef struct CandidateSearcher { 22706b9b3e0SSimon J. Gerraty 22806b9b3e0SSimon J. Gerraty CandidateList list; 22906b9b3e0SSimon J. Gerraty 23006b9b3e0SSimon J. Gerraty /* 23106b9b3e0SSimon J. Gerraty * TODO: Add HashSet for seen entries, to avoid endless loops such as 23206b9b3e0SSimon J. Gerraty * in suff-transform-endless.mk. 23306b9b3e0SSimon J. Gerraty */ 23406b9b3e0SSimon J. Gerraty 23506b9b3e0SSimon J. Gerraty } CandidateSearcher; 23606b9b3e0SSimon J. Gerraty 23706b9b3e0SSimon J. Gerraty 23806b9b3e0SSimon J. Gerraty /* TODO: Document the difference between nullSuff and emptySuff. */ 2399f45a3c8SSimon J. Gerraty /* The NULL suffix is used when a file has no known suffix */ 24006b9b3e0SSimon J. Gerraty static Suffix *nullSuff; 241e2eeea75SSimon J. Gerraty /* The empty suffix required for POSIX single-suffix transformation rules */ 24206b9b3e0SSimon J. Gerraty static Suffix *emptySuff; 2433955d011SMarcel Moolenaar 2443955d011SMarcel Moolenaar 24506b9b3e0SSimon J. Gerraty static Suffix * 24606b9b3e0SSimon J. Gerraty Suffix_Ref(Suffix *suff) 24706b9b3e0SSimon J. Gerraty { 24806b9b3e0SSimon J. Gerraty suff->refCount++; 24906b9b3e0SSimon J. Gerraty return suff; 25006b9b3e0SSimon J. Gerraty } 25106b9b3e0SSimon J. Gerraty 25206b9b3e0SSimon J. Gerraty /* Change the value of a Suffix variable, adjusting the reference counts. */ 25306b9b3e0SSimon J. Gerraty static void 25406b9b3e0SSimon J. Gerraty Suffix_Reassign(Suffix **var, Suffix *suff) 25506b9b3e0SSimon J. Gerraty { 25606b9b3e0SSimon J. Gerraty if (*var != NULL) 25706b9b3e0SSimon J. Gerraty (*var)->refCount--; 25806b9b3e0SSimon J. Gerraty *var = suff; 25906b9b3e0SSimon J. Gerraty suff->refCount++; 26006b9b3e0SSimon J. Gerraty } 26106b9b3e0SSimon J. Gerraty 26206b9b3e0SSimon J. Gerraty /* Set a Suffix variable to NULL, adjusting the reference count. */ 26306b9b3e0SSimon J. Gerraty static void 26406b9b3e0SSimon J. Gerraty Suffix_Unassign(Suffix **var) 26506b9b3e0SSimon J. Gerraty { 26606b9b3e0SSimon J. Gerraty if (*var != NULL) 26706b9b3e0SSimon J. Gerraty (*var)->refCount--; 26806b9b3e0SSimon J. Gerraty *var = NULL; 26906b9b3e0SSimon J. Gerraty } 2703955d011SMarcel Moolenaar 271e2eeea75SSimon J. Gerraty /* 2723955d011SMarcel Moolenaar * See if pref is a prefix of str. 273e2eeea75SSimon J. Gerraty * Return NULL if it ain't, pointer to character in str after prefix if so. 2743955d011SMarcel Moolenaar */ 2753955d011SMarcel Moolenaar static const char * 27606b9b3e0SSimon J. Gerraty StrTrimPrefix(const char *pref, const char *str) 2773955d011SMarcel Moolenaar { 27806b9b3e0SSimon J. Gerraty while (*str != '\0' && *pref == *str) { 2793955d011SMarcel Moolenaar pref++; 2803955d011SMarcel Moolenaar str++; 2813955d011SMarcel Moolenaar } 2823955d011SMarcel Moolenaar 283e2eeea75SSimon J. Gerraty return *pref != '\0' ? NULL : str; 2843955d011SMarcel Moolenaar } 2853955d011SMarcel Moolenaar 286e2eeea75SSimon J. Gerraty /* 28706b9b3e0SSimon J. Gerraty * See if suff is a suffix of str, and if so, return the pointer to the suffix 28806b9b3e0SSimon J. Gerraty * in str, which at the same time marks the end of the prefix. 2893955d011SMarcel Moolenaar */ 290956e45f6SSimon J. Gerraty static const char * 29106b9b3e0SSimon J. Gerraty StrTrimSuffix(const char *str, size_t strLen, const char *suff, size_t suffLen) 2923955d011SMarcel Moolenaar { 29306b9b3e0SSimon J. Gerraty const char *suffInStr; 29406b9b3e0SSimon J. Gerraty size_t i; 2953955d011SMarcel Moolenaar 29606b9b3e0SSimon J. Gerraty if (strLen < suffLen) 29706b9b3e0SSimon J. Gerraty return NULL; 2983955d011SMarcel Moolenaar 29906b9b3e0SSimon J. Gerraty suffInStr = str + strLen - suffLen; 30006b9b3e0SSimon J. Gerraty for (i = 0; i < suffLen; i++) 30106b9b3e0SSimon J. Gerraty if (suff[i] != suffInStr[i]) 30206b9b3e0SSimon J. Gerraty return NULL; 3033955d011SMarcel Moolenaar 30406b9b3e0SSimon J. Gerraty return suffInStr; 3053955d011SMarcel Moolenaar } 3063955d011SMarcel Moolenaar 30706b9b3e0SSimon J. Gerraty /* 30806b9b3e0SSimon J. Gerraty * See if suff is a suffix of name, and if so, return the end of the prefix 30906b9b3e0SSimon J. Gerraty * in name. 31006b9b3e0SSimon J. Gerraty */ 31106b9b3e0SSimon J. Gerraty static const char * 31206b9b3e0SSimon J. Gerraty Suffix_TrimSuffix(const Suffix *suff, size_t nameLen, const char *nameEnd) 31306b9b3e0SSimon J. Gerraty { 31406b9b3e0SSimon J. Gerraty return StrTrimSuffix(nameEnd - nameLen, nameLen, 31506b9b3e0SSimon J. Gerraty suff->name, suff->nameLen); 3163955d011SMarcel Moolenaar } 3173955d011SMarcel Moolenaar 318b0c40a00SSimon J. Gerraty static bool 31906b9b3e0SSimon J. Gerraty Suffix_IsSuffix(const Suffix *suff, size_t nameLen, const char *nameEnd) 3203955d011SMarcel Moolenaar { 32106b9b3e0SSimon J. Gerraty return Suffix_TrimSuffix(suff, nameLen, nameEnd) != NULL; 3223955d011SMarcel Moolenaar } 3233955d011SMarcel Moolenaar 32406b9b3e0SSimon J. Gerraty static Suffix * 32506b9b3e0SSimon J. Gerraty FindSuffixByNameLen(const char *name, size_t nameLen) 3263955d011SMarcel Moolenaar { 32706b9b3e0SSimon J. Gerraty SuffixListNode *ln; 328956e45f6SSimon J. Gerraty 32906b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 33006b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 33106b9b3e0SSimon J. Gerraty if (suff->nameLen == nameLen && 33206b9b3e0SSimon J. Gerraty memcmp(suff->name, name, nameLen) == 0) 333956e45f6SSimon J. Gerraty return suff; 334956e45f6SSimon J. Gerraty } 335956e45f6SSimon J. Gerraty return NULL; 3363955d011SMarcel Moolenaar } 3373955d011SMarcel Moolenaar 33806b9b3e0SSimon J. Gerraty static Suffix * 33906b9b3e0SSimon J. Gerraty FindSuffixByName(const char *name) 3403955d011SMarcel Moolenaar { 34106b9b3e0SSimon J. Gerraty return FindSuffixByNameLen(name, strlen(name)); 3423955d011SMarcel Moolenaar } 3433955d011SMarcel Moolenaar 344956e45f6SSimon J. Gerraty static GNode * 345956e45f6SSimon J. Gerraty FindTransformByName(const char *name) 3463955d011SMarcel Moolenaar { 347956e45f6SSimon J. Gerraty GNodeListNode *ln; 34806b9b3e0SSimon J. Gerraty 34906b9b3e0SSimon J. Gerraty for (ln = transforms.first; ln != NULL; ln = ln->next) { 350956e45f6SSimon J. Gerraty GNode *gn = ln->datum; 351956e45f6SSimon J. Gerraty if (strcmp(gn->name, name) == 0) 352956e45f6SSimon J. Gerraty return gn; 353956e45f6SSimon J. Gerraty } 354956e45f6SSimon J. Gerraty return NULL; 3553955d011SMarcel Moolenaar } 3563955d011SMarcel Moolenaar 3573955d011SMarcel Moolenaar static void 35806b9b3e0SSimon J. Gerraty SuffixList_Unref(SuffixList *list, Suffix *suff) 3593955d011SMarcel Moolenaar { 36006b9b3e0SSimon J. Gerraty SuffixListNode *ln = Lst_FindDatum(list, suff); 3613955d011SMarcel Moolenaar if (ln != NULL) { 362956e45f6SSimon J. Gerraty Lst_Remove(list, ln); 363956e45f6SSimon J. Gerraty suff->refCount--; 3643955d011SMarcel Moolenaar } 3653955d011SMarcel Moolenaar } 3663955d011SMarcel Moolenaar 3673955d011SMarcel Moolenaar static void 36806b9b3e0SSimon J. Gerraty Suffix_Free(Suffix *suff) 3693955d011SMarcel Moolenaar { 3703955d011SMarcel Moolenaar 37106b9b3e0SSimon J. Gerraty if (suff == nullSuff) 37206b9b3e0SSimon J. Gerraty nullSuff = NULL; 3733955d011SMarcel Moolenaar 374e2eeea75SSimon J. Gerraty if (suff == emptySuff) 3753955d011SMarcel Moolenaar emptySuff = NULL; 3763955d011SMarcel Moolenaar 377956e45f6SSimon J. Gerraty #if 0 3783955d011SMarcel Moolenaar /* We don't delete suffixes in order, so we cannot use this */ 379e2eeea75SSimon J. Gerraty if (suff->refCount != 0) 380e2eeea75SSimon J. Gerraty Punt("Internal error deleting suffix `%s' with refcount = %d", 381e2eeea75SSimon J. Gerraty suff->name, suff->refCount); 3823955d011SMarcel Moolenaar #endif 3833955d011SMarcel Moolenaar 38406b9b3e0SSimon J. Gerraty Lst_Done(&suff->children); 38506b9b3e0SSimon J. Gerraty Lst_Done(&suff->parents); 38606b9b3e0SSimon J. Gerraty SearchPath_Free(suff->searchPath); 3873955d011SMarcel Moolenaar 388e2eeea75SSimon J. Gerraty free(suff->name); 389e2eeea75SSimon J. Gerraty free(suff); 3903955d011SMarcel Moolenaar } 3913955d011SMarcel Moolenaar 3922c3632d1SSimon J. Gerraty /* Remove the suffix from the list, and free if it is otherwise unused. */ 3933955d011SMarcel Moolenaar static void 39406b9b3e0SSimon J. Gerraty SuffixList_Remove(SuffixList *list, Suffix *suff) 3953955d011SMarcel Moolenaar { 39606b9b3e0SSimon J. Gerraty SuffixList_Unref(list, suff); 397956e45f6SSimon J. Gerraty if (suff->refCount == 0) { 398e2eeea75SSimon J. Gerraty /* XXX: can lead to suff->refCount == -1 */ 39906b9b3e0SSimon J. Gerraty SuffixList_Unref(&sufflist, suff); 40006b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Removing suffix \"%s\"\n", suff->name); 401d5e0a182SSimon J. Gerraty Suffix_Free(suff); 4023955d011SMarcel Moolenaar } 4033955d011SMarcel Moolenaar } 4042c3632d1SSimon J. Gerraty 40506b9b3e0SSimon J. Gerraty /* 40606b9b3e0SSimon J. Gerraty * Insert the suffix into the list, keeping the list ordered by suffix 40706b9b3e0SSimon J. Gerraty * number. 40806b9b3e0SSimon J. Gerraty */ 4093955d011SMarcel Moolenaar static void 41006b9b3e0SSimon J. Gerraty SuffixList_Insert(SuffixList *list, Suffix *suff) 4113955d011SMarcel Moolenaar { 41206b9b3e0SSimon J. Gerraty SuffixListNode *ln; 41306b9b3e0SSimon J. Gerraty Suffix *listSuff = NULL; 4143955d011SMarcel Moolenaar 415956e45f6SSimon J. Gerraty for (ln = list->first; ln != NULL; ln = ln->next) { 416956e45f6SSimon J. Gerraty listSuff = ln->datum; 417956e45f6SSimon J. Gerraty if (listSuff->sNum >= suff->sNum) 4183955d011SMarcel Moolenaar break; 4193955d011SMarcel Moolenaar } 4202c3632d1SSimon J. Gerraty 4213955d011SMarcel Moolenaar if (ln == NULL) { 42206b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "inserting \"%s\" (%d) at end of list\n", 423956e45f6SSimon J. Gerraty suff->name, suff->sNum); 42406b9b3e0SSimon J. Gerraty Lst_Append(list, Suffix_Ref(suff)); 425956e45f6SSimon J. Gerraty } else if (listSuff->sNum != suff->sNum) { 426e2eeea75SSimon J. Gerraty DEBUG4(SUFF, "inserting \"%s\" (%d) before \"%s\" (%d)\n", 427956e45f6SSimon J. Gerraty suff->name, suff->sNum, listSuff->name, listSuff->sNum); 42806b9b3e0SSimon J. Gerraty Lst_InsertBefore(list, ln, Suffix_Ref(suff)); 4292c3632d1SSimon J. Gerraty } else { 43006b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "\"%s\" (%d) is already there\n", 43106b9b3e0SSimon J. Gerraty suff->name, suff->sNum); 4323955d011SMarcel Moolenaar } 4333955d011SMarcel Moolenaar } 4343955d011SMarcel Moolenaar 435e2eeea75SSimon J. Gerraty static void 43606b9b3e0SSimon J. Gerraty Relate(Suffix *srcSuff, Suffix *targSuff) 437e2eeea75SSimon J. Gerraty { 43806b9b3e0SSimon J. Gerraty SuffixList_Insert(&targSuff->children, srcSuff); 43906b9b3e0SSimon J. Gerraty SuffixList_Insert(&srcSuff->parents, targSuff); 440e2eeea75SSimon J. Gerraty } 441e2eeea75SSimon J. Gerraty 44206b9b3e0SSimon J. Gerraty static Suffix * 44306b9b3e0SSimon J. Gerraty Suffix_New(const char *name) 4442c3632d1SSimon J. Gerraty { 44506b9b3e0SSimon J. Gerraty Suffix *suff = bmake_malloc(sizeof *suff); 4462c3632d1SSimon J. Gerraty 447e2eeea75SSimon J. Gerraty suff->name = bmake_strdup(name); 448e2eeea75SSimon J. Gerraty suff->nameLen = strlen(suff->name); 44906b9b3e0SSimon J. Gerraty suff->searchPath = SearchPath_New(); 45006b9b3e0SSimon J. Gerraty Lst_Init(&suff->children); 45106b9b3e0SSimon J. Gerraty Lst_Init(&suff->parents); 452e2eeea75SSimon J. Gerraty suff->sNum = sNum++; 45312904384SSimon J. Gerraty suff->include = false; 45412904384SSimon J. Gerraty suff->library = false; 45512904384SSimon J. Gerraty suff->isNull = false; 456e2eeea75SSimon J. Gerraty suff->refCount = 1; /* XXX: why 1? It's not assigned anywhere yet. */ 4572c3632d1SSimon J. Gerraty 458e2eeea75SSimon J. Gerraty return suff; 4592c3632d1SSimon J. Gerraty } 4602c3632d1SSimon J. Gerraty 461e2eeea75SSimon J. Gerraty /* 462e2eeea75SSimon J. Gerraty * Nuke the list of suffixes but keep all transformation rules around. The 463e2eeea75SSimon J. Gerraty * transformation graph is destroyed in this process, but we leave the list 464e2eeea75SSimon J. Gerraty * of rules so when a new graph is formed, the rules will remain. This 465e2eeea75SSimon J. Gerraty * function is called when a line '.SUFFIXES:' with an empty suffixes list is 466e2eeea75SSimon J. Gerraty * encountered in a makefile. 467e2eeea75SSimon J. Gerraty */ 4683955d011SMarcel Moolenaar void 4693955d011SMarcel Moolenaar Suff_ClearSuffixes(void) 4703955d011SMarcel Moolenaar { 4713955d011SMarcel Moolenaar #ifdef CLEANUP 47206b9b3e0SSimon J. Gerraty Lst_MoveAll(&suffClean, &sufflist); 4733955d011SMarcel Moolenaar #endif 47406b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "Clearing all suffixes\n"); 47506b9b3e0SSimon J. Gerraty Lst_Init(&sufflist); 4763955d011SMarcel Moolenaar sNum = 0; 47706b9b3e0SSimon J. Gerraty if (nullSuff != NULL) 478d5e0a182SSimon J. Gerraty Suffix_Free(nullSuff); 47906b9b3e0SSimon J. Gerraty emptySuff = nullSuff = Suffix_New(""); 4806e050540SSimon J. Gerraty 48106b9b3e0SSimon J. Gerraty SearchPath_AddAll(nullSuff->searchPath, &dirSearchPath); 48212904384SSimon J. Gerraty nullSuff->include = false; 48312904384SSimon J. Gerraty nullSuff->library = false; 48412904384SSimon J. Gerraty nullSuff->isNull = true; 4853955d011SMarcel Moolenaar } 4863955d011SMarcel Moolenaar 48706b9b3e0SSimon J. Gerraty /* 48806b9b3e0SSimon J. Gerraty * Parse a transformation string such as ".c.o" to find its two component 489956e45f6SSimon J. Gerraty * suffixes (the source ".c" and the target ".o"). If there are no such 490956e45f6SSimon J. Gerraty * suffixes, try a single-suffix transformation as well. 4913955d011SMarcel Moolenaar * 492b0c40a00SSimon J. Gerraty * Return true if the string is a valid transformation. 4933955d011SMarcel Moolenaar */ 494b0c40a00SSimon J. Gerraty static bool 49506b9b3e0SSimon J. Gerraty ParseTransform(const char *str, Suffix **out_src, Suffix **out_targ) 4963955d011SMarcel Moolenaar { 49706b9b3e0SSimon J. Gerraty SuffixListNode *ln; 49806b9b3e0SSimon J. Gerraty Suffix *single = NULL; 4993955d011SMarcel Moolenaar 5003955d011SMarcel Moolenaar /* 5013955d011SMarcel Moolenaar * Loop looking first for a suffix that matches the start of the 5023955d011SMarcel Moolenaar * string and then for one that exactly matches the rest of it. If 5033955d011SMarcel Moolenaar * we can find two that meet these criteria, we've successfully 5043955d011SMarcel Moolenaar * parsed the string. 5053955d011SMarcel Moolenaar */ 50606b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 50706b9b3e0SSimon J. Gerraty Suffix *src = ln->datum; 508956e45f6SSimon J. Gerraty 50906b9b3e0SSimon J. Gerraty if (StrTrimPrefix(src->name, str) == NULL) 510956e45f6SSimon J. Gerraty continue; 511956e45f6SSimon J. Gerraty 512956e45f6SSimon J. Gerraty if (str[src->nameLen] == '\0') { 51306b9b3e0SSimon J. Gerraty single = src; 5143955d011SMarcel Moolenaar } else { 51506b9b3e0SSimon J. Gerraty Suffix *targ = FindSuffixByName(str + src->nameLen); 516956e45f6SSimon J. Gerraty if (targ != NULL) { 517956e45f6SSimon J. Gerraty *out_src = src; 518956e45f6SSimon J. Gerraty *out_targ = targ; 519b0c40a00SSimon J. Gerraty return true; 5203955d011SMarcel Moolenaar } 521956e45f6SSimon J. Gerraty } 522956e45f6SSimon J. Gerraty } 523956e45f6SSimon J. Gerraty 52406b9b3e0SSimon J. Gerraty if (single != NULL) { 5253955d011SMarcel Moolenaar /* 52606b9b3e0SSimon J. Gerraty * There was a suffix that encompassed the entire string, so we 52706b9b3e0SSimon J. Gerraty * assume it was a transformation to the null suffix (thank you 52806b9b3e0SSimon J. Gerraty * POSIX; search for "single suffix" or "single-suffix"). 5293955d011SMarcel Moolenaar * 53006b9b3e0SSimon J. Gerraty * We still prefer to find a double rule over a singleton, 53106b9b3e0SSimon J. Gerraty * hence we leave this check until the end. 53206b9b3e0SSimon J. Gerraty * 53306b9b3e0SSimon J. Gerraty * XXX: Use emptySuff over nullSuff? 5343955d011SMarcel Moolenaar */ 53506b9b3e0SSimon J. Gerraty *out_src = single; 53606b9b3e0SSimon J. Gerraty *out_targ = nullSuff; 537b0c40a00SSimon J. Gerraty return true; 5383955d011SMarcel Moolenaar } 539b0c40a00SSimon J. Gerraty return false; 5403955d011SMarcel Moolenaar } 5413955d011SMarcel Moolenaar 54206b9b3e0SSimon J. Gerraty /* 543b0c40a00SSimon J. Gerraty * Return true if the given string is a transformation rule, that is, a 544e2eeea75SSimon J. Gerraty * concatenation of two known suffixes such as ".c.o" or a single suffix 54506b9b3e0SSimon J. Gerraty * such as ".o". 54606b9b3e0SSimon J. Gerraty */ 547b0c40a00SSimon J. Gerraty bool 548956e45f6SSimon J. Gerraty Suff_IsTransform(const char *str) 5493955d011SMarcel Moolenaar { 55006b9b3e0SSimon J. Gerraty Suffix *src, *targ; 5513955d011SMarcel Moolenaar 55206b9b3e0SSimon J. Gerraty return ParseTransform(str, &src, &targ); 5533955d011SMarcel Moolenaar } 5543955d011SMarcel Moolenaar 55506b9b3e0SSimon J. Gerraty /* 55606b9b3e0SSimon J. Gerraty * Add the transformation rule to the list of rules and place the 557956e45f6SSimon J. Gerraty * transformation itself in the graph. 5583955d011SMarcel Moolenaar * 559956e45f6SSimon J. Gerraty * The transformation is linked to the two suffixes mentioned in the name. 560956e45f6SSimon J. Gerraty * 5613955d011SMarcel Moolenaar * Input: 562956e45f6SSimon J. Gerraty * name must have the form ".from.to" or just ".from" 5633955d011SMarcel Moolenaar * 5643955d011SMarcel Moolenaar * Results: 565956e45f6SSimon J. Gerraty * The created or existing transformation node in the transforms list 5663955d011SMarcel Moolenaar */ 5673955d011SMarcel Moolenaar GNode * 568956e45f6SSimon J. Gerraty Suff_AddTransform(const char *name) 5693955d011SMarcel Moolenaar { 57006b9b3e0SSimon J. Gerraty Suffix *srcSuff; 57106b9b3e0SSimon J. Gerraty Suffix *targSuff; 5723955d011SMarcel Moolenaar 573e2eeea75SSimon J. Gerraty GNode *gn = FindTransformByName(name); 574956e45f6SSimon J. Gerraty if (gn == NULL) { 5753955d011SMarcel Moolenaar /* 57606b9b3e0SSimon J. Gerraty * Make a new graph node for the transformation. It will be 57706b9b3e0SSimon J. Gerraty * filled in by the Parse module. 5783955d011SMarcel Moolenaar */ 579e2eeea75SSimon J. Gerraty gn = GNode_New(name); 58006b9b3e0SSimon J. Gerraty Lst_Append(&transforms, gn); 5813955d011SMarcel Moolenaar } else { 5823955d011SMarcel Moolenaar /* 58306b9b3e0SSimon J. Gerraty * New specification for transformation rule. Just nuke the 58406b9b3e0SSimon J. Gerraty * old list of commands so they can be filled in again. We 58506b9b3e0SSimon J. Gerraty * don't actually free the commands themselves, because a 58606b9b3e0SSimon J. Gerraty * given command can be attached to several different 58706b9b3e0SSimon J. Gerraty * transformations. 5883955d011SMarcel Moolenaar */ 58906b9b3e0SSimon J. Gerraty Lst_Done(&gn->commands); 59006b9b3e0SSimon J. Gerraty Lst_Init(&gn->commands); 59106b9b3e0SSimon J. Gerraty Lst_Done(&gn->children); 59206b9b3e0SSimon J. Gerraty Lst_Init(&gn->children); 5933955d011SMarcel Moolenaar } 5943955d011SMarcel Moolenaar 5953955d011SMarcel Moolenaar gn->type = OP_TRANSFORM; 5963955d011SMarcel Moolenaar 597e2eeea75SSimon J. Gerraty { 59806b9b3e0SSimon J. Gerraty /* TODO: Avoid the redundant parsing here. */ 599b0c40a00SSimon J. Gerraty bool ok = ParseTransform(name, &srcSuff, &targSuff); 6002c3632d1SSimon J. Gerraty assert(ok); 60112904384SSimon J. Gerraty /* LINTED 129 *//* expression has null effect */ 6022c3632d1SSimon J. Gerraty (void)ok; 603e2eeea75SSimon J. Gerraty } 6043955d011SMarcel Moolenaar 60506b9b3e0SSimon J. Gerraty /* Link the two together in the proper relationship and order. */ 60606b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "defining transformation from `%s' to `%s'\n", 607e2eeea75SSimon J. Gerraty srcSuff->name, targSuff->name); 60806b9b3e0SSimon J. Gerraty Relate(srcSuff, targSuff); 6093955d011SMarcel Moolenaar 6103841c287SSimon J. Gerraty return gn; 6113955d011SMarcel Moolenaar } 6123955d011SMarcel Moolenaar 61306b9b3e0SSimon J. Gerraty /* 61406b9b3e0SSimon J. Gerraty * Handle the finish of a transformation definition, removing the 6152c3632d1SSimon J. Gerraty * transformation from the graph if it has neither commands nor sources. 6162c3632d1SSimon J. Gerraty * 6172c3632d1SSimon J. Gerraty * If the node has no commands or children, the children and parents lists 6182c3632d1SSimon J. Gerraty * of the affected suffixes are altered. 6193955d011SMarcel Moolenaar * 6203955d011SMarcel Moolenaar * Input: 621956e45f6SSimon J. Gerraty * gn Node for transformation 6223955d011SMarcel Moolenaar */ 623956e45f6SSimon J. Gerraty void 624956e45f6SSimon J. Gerraty Suff_EndTransform(GNode *gn) 6253955d011SMarcel Moolenaar { 62606b9b3e0SSimon J. Gerraty Suffix *srcSuff, *targSuff; 62706b9b3e0SSimon J. Gerraty SuffixList *srcSuffParents; 628e2eeea75SSimon J. Gerraty 62906b9b3e0SSimon J. Gerraty if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&gn->cohorts)) 63006b9b3e0SSimon J. Gerraty gn = gn->cohorts.last->datum; 63106b9b3e0SSimon J. Gerraty 63206b9b3e0SSimon J. Gerraty if (!(gn->type & OP_TRANSFORM)) 63306b9b3e0SSimon J. Gerraty return; 63406b9b3e0SSimon J. Gerraty 63506b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&gn->commands) || !Lst_IsEmpty(&gn->children)) { 63606b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "transformation %s complete\n", gn->name); 63706b9b3e0SSimon J. Gerraty return; 63806b9b3e0SSimon J. Gerraty } 6393955d011SMarcel Moolenaar 6403955d011SMarcel Moolenaar /* 6413955d011SMarcel Moolenaar * SuffParseTransform() may fail for special rules which are not 6423955d011SMarcel Moolenaar * actual transformation rules. (e.g. .DEFAULT) 6433955d011SMarcel Moolenaar */ 64406b9b3e0SSimon J. Gerraty if (!ParseTransform(gn->name, &srcSuff, &targSuff)) 64506b9b3e0SSimon J. Gerraty return; 646e2eeea75SSimon J. Gerraty 64706b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "deleting incomplete transformation from `%s' to `%s'\n", 648e2eeea75SSimon J. Gerraty srcSuff->name, targSuff->name); 6493955d011SMarcel Moolenaar 65006b9b3e0SSimon J. Gerraty /* 65106b9b3e0SSimon J. Gerraty * Remember the parents since srcSuff could be deleted in 65206b9b3e0SSimon J. Gerraty * SuffixList_Remove. 65306b9b3e0SSimon J. Gerraty */ 65406b9b3e0SSimon J. Gerraty srcSuffParents = &srcSuff->parents; 65506b9b3e0SSimon J. Gerraty SuffixList_Remove(&targSuff->children, srcSuff); 65606b9b3e0SSimon J. Gerraty SuffixList_Remove(srcSuffParents, targSuff); 6573955d011SMarcel Moolenaar } 6583955d011SMarcel Moolenaar 65906b9b3e0SSimon J. Gerraty /* 66006b9b3e0SSimon J. Gerraty * Called from Suff_AddSuffix to search through the list of 6612c3632d1SSimon J. Gerraty * existing transformation rules and rebuild the transformation graph when 6622c3632d1SSimon J. Gerraty * it has been destroyed by Suff_ClearSuffixes. If the given rule is a 6632c3632d1SSimon J. Gerraty * transformation involving this suffix and another, existing suffix, the 6642c3632d1SSimon J. Gerraty * proper relationship is established between the two. 6652c3632d1SSimon J. Gerraty * 6662c3632d1SSimon J. Gerraty * The appropriate links will be made between this suffix and others if 6672c3632d1SSimon J. Gerraty * transformation rules exist for it. 6683955d011SMarcel Moolenaar * 6693955d011SMarcel Moolenaar * Input: 670956e45f6SSimon J. Gerraty * transform Transformation to test 671956e45f6SSimon J. Gerraty * suff Suffix to rebuild 6723955d011SMarcel Moolenaar */ 673956e45f6SSimon J. Gerraty static void 67406b9b3e0SSimon J. Gerraty RebuildGraph(GNode *transform, Suffix *suff) 6753955d011SMarcel Moolenaar { 676956e45f6SSimon J. Gerraty const char *name = transform->name; 677956e45f6SSimon J. Gerraty size_t nameLen = strlen(name); 678956e45f6SSimon J. Gerraty const char *toName; 6793955d011SMarcel Moolenaar 6809f45a3c8SSimon J. Gerraty /* 6819f45a3c8SSimon J. Gerraty * See if it is a transformation from this suffix to another suffix. 6829f45a3c8SSimon J. Gerraty */ 68306b9b3e0SSimon J. Gerraty toName = StrTrimPrefix(suff->name, name); 684956e45f6SSimon J. Gerraty if (toName != NULL) { 68506b9b3e0SSimon J. Gerraty Suffix *to = FindSuffixByName(toName); 686956e45f6SSimon J. Gerraty if (to != NULL) { 68706b9b3e0SSimon J. Gerraty Relate(suff, to); 688956e45f6SSimon J. Gerraty return; 6893955d011SMarcel Moolenaar } 6903955d011SMarcel Moolenaar } 6913955d011SMarcel Moolenaar 6929f45a3c8SSimon J. Gerraty /* 6939f45a3c8SSimon J. Gerraty * See if it is a transformation from another suffix to this suffix. 6949f45a3c8SSimon J. Gerraty */ 69506b9b3e0SSimon J. Gerraty toName = Suffix_TrimSuffix(suff, nameLen, name + nameLen); 696956e45f6SSimon J. Gerraty if (toName != NULL) { 69706b9b3e0SSimon J. Gerraty Suffix *from = FindSuffixByNameLen(name, 69806b9b3e0SSimon J. Gerraty (size_t)(toName - name)); 699e2eeea75SSimon J. Gerraty if (from != NULL) 70006b9b3e0SSimon J. Gerraty Relate(from, suff); 7013955d011SMarcel Moolenaar } 7023955d011SMarcel Moolenaar } 7033955d011SMarcel Moolenaar 70406b9b3e0SSimon J. Gerraty /* 70506b9b3e0SSimon J. Gerraty * During Suff_AddSuffix, search through the list of existing targets and find 706956e45f6SSimon J. Gerraty * if any of the existing targets can be turned into a transformation rule. 7072c3632d1SSimon J. Gerraty * 7082c3632d1SSimon J. Gerraty * If such a target is found and the target is the current main target, the 7092c3632d1SSimon J. Gerraty * main target is set to NULL and the next target examined (if that exists) 7102c3632d1SSimon J. Gerraty * becomes the main target. 7113955d011SMarcel Moolenaar * 7123955d011SMarcel Moolenaar * Results: 713b0c40a00SSimon J. Gerraty * true iff a new main target has been selected. 7143955d011SMarcel Moolenaar */ 715b0c40a00SSimon J. Gerraty static bool 7169f45a3c8SSimon J. Gerraty UpdateTarget(GNode *target, Suffix *suff, bool *inout_removedMain) 7173955d011SMarcel Moolenaar { 71806b9b3e0SSimon J. Gerraty Suffix *srcSuff, *targSuff; 7193955d011SMarcel Moolenaar char *ptr; 7203955d011SMarcel Moolenaar 7219f45a3c8SSimon J. Gerraty if (mainNode == NULL && *inout_removedMain && 7229f45a3c8SSimon J. Gerraty GNode_IsMainCandidate(target)) { 72306b9b3e0SSimon J. Gerraty DEBUG1(MAKE, "Setting main node to \"%s\"\n", target->name); 7249f45a3c8SSimon J. Gerraty mainNode = target; 72506b9b3e0SSimon J. Gerraty /* 726b0c40a00SSimon J. Gerraty * XXX: Why could it be a good idea to return true here? 72706b9b3e0SSimon J. Gerraty * The main task of this function is to turn ordinary nodes 72806b9b3e0SSimon J. Gerraty * into transformations, no matter whether or not a new .MAIN 72906b9b3e0SSimon J. Gerraty * node has been found. 73006b9b3e0SSimon J. Gerraty */ 73106b9b3e0SSimon J. Gerraty /* 732b0c40a00SSimon J. Gerraty * XXX: Even when changing this to false, none of the existing 73306b9b3e0SSimon J. Gerraty * unit tests fails. 73406b9b3e0SSimon J. Gerraty */ 735b0c40a00SSimon J. Gerraty return true; 7363955d011SMarcel Moolenaar } 7373955d011SMarcel Moolenaar 7382c3632d1SSimon J. Gerraty if (target->type == OP_TRANSFORM) 739b0c40a00SSimon J. Gerraty return false; 7403955d011SMarcel Moolenaar 74106b9b3e0SSimon J. Gerraty /* 74206b9b3e0SSimon J. Gerraty * XXX: What about a transformation ".cpp.c"? If ".c" is added as 74306b9b3e0SSimon J. Gerraty * a new suffix, it seems wrong that this transformation would be 74406b9b3e0SSimon J. Gerraty * skipped just because ".c" happens to be a prefix of ".cpp". 74506b9b3e0SSimon J. Gerraty */ 74606b9b3e0SSimon J. Gerraty ptr = strstr(target->name, suff->name); 74706b9b3e0SSimon J. Gerraty if (ptr == NULL) 748b0c40a00SSimon J. Gerraty return false; 7493955d011SMarcel Moolenaar 75006b9b3e0SSimon J. Gerraty /* 75106b9b3e0SSimon J. Gerraty * XXX: In suff-rebuild.mk, in the line '.SUFFIXES: .c .b .a', this 75206b9b3e0SSimon J. Gerraty * condition prevents the rule '.b.c' from being added again during 75306b9b3e0SSimon J. Gerraty * Suff_AddSuffix(".b"). 75406b9b3e0SSimon J. Gerraty * 75506b9b3e0SSimon J. Gerraty * XXX: Removing this paragraph makes suff-add-later.mk use massive 75606b9b3e0SSimon J. Gerraty * amounts of memory. 75706b9b3e0SSimon J. Gerraty */ 75806b9b3e0SSimon J. Gerraty if (ptr == target->name) 759b0c40a00SSimon J. Gerraty return false; 76006b9b3e0SSimon J. Gerraty 76106b9b3e0SSimon J. Gerraty if (ParseTransform(target->name, &srcSuff, &targSuff)) { 7629f45a3c8SSimon J. Gerraty if (mainNode == target) { 76306b9b3e0SSimon J. Gerraty DEBUG1(MAKE, 76406b9b3e0SSimon J. Gerraty "Setting main node from \"%s\" back to null\n", 76506b9b3e0SSimon J. Gerraty target->name); 766b0c40a00SSimon J. Gerraty *inout_removedMain = true; 7679f45a3c8SSimon J. Gerraty mainNode = NULL; 7683955d011SMarcel Moolenaar } 76906b9b3e0SSimon J. Gerraty Lst_Done(&target->children); 77006b9b3e0SSimon J. Gerraty Lst_Init(&target->children); 7713955d011SMarcel Moolenaar target->type = OP_TRANSFORM; 77206b9b3e0SSimon J. Gerraty 7733955d011SMarcel Moolenaar /* 77406b9b3e0SSimon J. Gerraty * Link the two together in the proper relationship and order. 7753955d011SMarcel Moolenaar */ 77606b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "defining transformation from `%s' to `%s'\n", 777e2eeea75SSimon J. Gerraty srcSuff->name, targSuff->name); 77806b9b3e0SSimon J. Gerraty Relate(srcSuff, targSuff); 7793955d011SMarcel Moolenaar } 780b0c40a00SSimon J. Gerraty return false; 781956e45f6SSimon J. Gerraty } 782956e45f6SSimon J. Gerraty 78306b9b3e0SSimon J. Gerraty /* 78406b9b3e0SSimon J. Gerraty * Look at all existing targets to see if adding this suffix will make one 785956e45f6SSimon J. Gerraty * of the current targets mutate into a suffix rule. 786956e45f6SSimon J. Gerraty * 787956e45f6SSimon J. Gerraty * This is ugly, but other makes treat all targets that start with a '.' as 78806b9b3e0SSimon J. Gerraty * suffix rules. 78906b9b3e0SSimon J. Gerraty */ 790956e45f6SSimon J. Gerraty static void 7919f45a3c8SSimon J. Gerraty UpdateTargets(Suffix *suff) 792956e45f6SSimon J. Gerraty { 793b0c40a00SSimon J. Gerraty bool removedMain = false; 794956e45f6SSimon J. Gerraty GNodeListNode *ln; 79506b9b3e0SSimon J. Gerraty 796956e45f6SSimon J. Gerraty for (ln = Targ_List()->first; ln != NULL; ln = ln->next) { 797956e45f6SSimon J. Gerraty GNode *gn = ln->datum; 7989f45a3c8SSimon J. Gerraty if (UpdateTarget(gn, suff, &removedMain)) 799956e45f6SSimon J. Gerraty break; 800956e45f6SSimon J. Gerraty } 8013955d011SMarcel Moolenaar } 8023955d011SMarcel Moolenaar 803d5e0a182SSimon J. Gerraty /* Add the suffix to the end of the list of known suffixes. */ 8043955d011SMarcel Moolenaar void 8059f45a3c8SSimon J. Gerraty Suff_AddSuffix(const char *name) 8063955d011SMarcel Moolenaar { 807956e45f6SSimon J. Gerraty GNodeListNode *ln; 8083955d011SMarcel Moolenaar 80906b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(name); 81006b9b3e0SSimon J. Gerraty if (suff != NULL) 811956e45f6SSimon J. Gerraty return; 812956e45f6SSimon J. Gerraty 81306b9b3e0SSimon J. Gerraty suff = Suffix_New(name); 81406b9b3e0SSimon J. Gerraty Lst_Append(&sufflist, suff); 81506b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Adding suffix \"%s\"\n", suff->name); 816956e45f6SSimon J. Gerraty 8179f45a3c8SSimon J. Gerraty UpdateTargets(suff); 818956e45f6SSimon J. Gerraty 8193955d011SMarcel Moolenaar /* 8203955d011SMarcel Moolenaar * Look for any existing transformations from or to this suffix. 8213955d011SMarcel Moolenaar * XXX: Only do this after a Suff_ClearSuffixes? 8223955d011SMarcel Moolenaar */ 82306b9b3e0SSimon J. Gerraty for (ln = transforms.first; ln != NULL; ln = ln->next) 82406b9b3e0SSimon J. Gerraty RebuildGraph(ln->datum, suff); 8253955d011SMarcel Moolenaar } 8263955d011SMarcel Moolenaar 8272c3632d1SSimon J. Gerraty /* Return the search path for the given suffix, or NULL. */ 828956e45f6SSimon J. Gerraty SearchPath * 8291d3f2ddcSSimon J. Gerraty Suff_GetPath(const char *name) 8303955d011SMarcel Moolenaar { 8311d3f2ddcSSimon J. Gerraty Suffix *suff = FindSuffixByName(name); 83206b9b3e0SSimon J. Gerraty return suff != NULL ? suff->searchPath : NULL; 8333955d011SMarcel Moolenaar } 8343955d011SMarcel Moolenaar 835e2eeea75SSimon J. Gerraty /* 836e2eeea75SSimon J. Gerraty * Extend the search paths for all suffixes to include the default search 837e2eeea75SSimon J. Gerraty * path (dirSearchPath). 8383955d011SMarcel Moolenaar * 839e2eeea75SSimon J. Gerraty * The default search path can be defined using the special target '.PATH'. 840e2eeea75SSimon J. Gerraty * The search path of each suffix can be defined using the special target 841e2eeea75SSimon J. Gerraty * '.PATH<suffix>'. 842e2eeea75SSimon J. Gerraty * 843e2eeea75SSimon J. Gerraty * If paths were specified for the ".h" suffix, the directories are stuffed 844e2eeea75SSimon J. Gerraty * into a global variable called ".INCLUDES" with each directory preceded by 845e2eeea75SSimon J. Gerraty * '-I'. The same is done for the ".a" suffix, except the variable is called 846e2eeea75SSimon J. Gerraty * ".LIBS" and the flag is '-L'. 8473955d011SMarcel Moolenaar */ 8483955d011SMarcel Moolenaar void 849b0c40a00SSimon J. Gerraty Suff_ExtendPaths(void) 8503955d011SMarcel Moolenaar { 85106b9b3e0SSimon J. Gerraty SuffixListNode *ln; 85206b9b3e0SSimon J. Gerraty char *flags; 85306b9b3e0SSimon J. Gerraty SearchPath *includesPath = SearchPath_New(); 85406b9b3e0SSimon J. Gerraty SearchPath *libsPath = SearchPath_New(); 8553955d011SMarcel Moolenaar 85606b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 85706b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 858dba7b0efSSimon J. Gerraty if (!Lst_IsEmpty(&suff->searchPath->dirs)) { 85912904384SSimon J. Gerraty if (suff->include) 86006b9b3e0SSimon J. Gerraty SearchPath_AddAll(includesPath, 86106b9b3e0SSimon J. Gerraty suff->searchPath); 86212904384SSimon J. Gerraty if (suff->library) 86306b9b3e0SSimon J. Gerraty SearchPath_AddAll(libsPath, suff->searchPath); 86406b9b3e0SSimon J. Gerraty SearchPath_AddAll(suff->searchPath, &dirSearchPath); 8653955d011SMarcel Moolenaar } else { 86606b9b3e0SSimon J. Gerraty SearchPath_Free(suff->searchPath); 86706b9b3e0SSimon J. Gerraty suff->searchPath = Dir_CopyDirSearchPath(); 8683955d011SMarcel Moolenaar } 8693955d011SMarcel Moolenaar } 8703955d011SMarcel Moolenaar 871dba7b0efSSimon J. Gerraty flags = SearchPath_ToFlags(includesPath, "-I"); 872dba7b0efSSimon J. Gerraty Global_Set(".INCLUDES", flags); 87306b9b3e0SSimon J. Gerraty free(flags); 8743955d011SMarcel Moolenaar 875dba7b0efSSimon J. Gerraty flags = SearchPath_ToFlags(libsPath, "-L"); 876dba7b0efSSimon J. Gerraty Global_Set(".LIBS", flags); 87706b9b3e0SSimon J. Gerraty free(flags); 87806b9b3e0SSimon J. Gerraty 87906b9b3e0SSimon J. Gerraty SearchPath_Free(includesPath); 88006b9b3e0SSimon J. Gerraty SearchPath_Free(libsPath); 8813955d011SMarcel Moolenaar } 8823955d011SMarcel Moolenaar 88306b9b3e0SSimon J. Gerraty /* 88406b9b3e0SSimon J. Gerraty * Add the given suffix as a type of file which gets included. 88506b9b3e0SSimon J. Gerraty * Called when a '.INCLUDES: .h' line is parsed. 88606b9b3e0SSimon J. Gerraty * To have an effect, the suffix must already exist. 88706b9b3e0SSimon J. Gerraty * This affects the magic variable '.INCLUDES'. 8883955d011SMarcel Moolenaar */ 8893955d011SMarcel Moolenaar void 89006b9b3e0SSimon J. Gerraty Suff_AddInclude(const char *suffName) 8913955d011SMarcel Moolenaar { 89206b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(suffName); 893956e45f6SSimon J. Gerraty if (suff != NULL) 89412904384SSimon J. Gerraty suff->include = true; 8953955d011SMarcel Moolenaar } 8963955d011SMarcel Moolenaar 89706b9b3e0SSimon J. Gerraty /* 89806b9b3e0SSimon J. Gerraty * Add the given suffix as a type of file which is a library. 89906b9b3e0SSimon J. Gerraty * Called when a '.LIBS: .a' line is parsed. 90006b9b3e0SSimon J. Gerraty * To have an effect, the suffix must already exist. 90106b9b3e0SSimon J. Gerraty * This affects the magic variable '.LIBS'. 9023955d011SMarcel Moolenaar */ 9033955d011SMarcel Moolenaar void 90406b9b3e0SSimon J. Gerraty Suff_AddLib(const char *suffName) 9053955d011SMarcel Moolenaar { 90606b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(suffName); 907956e45f6SSimon J. Gerraty if (suff != NULL) 90812904384SSimon J. Gerraty suff->library = true; 9093955d011SMarcel Moolenaar } 9103955d011SMarcel Moolenaar 9113955d011SMarcel Moolenaar /********** Implicit Source Search Functions *********/ 9123955d011SMarcel Moolenaar 91306b9b3e0SSimon J. Gerraty static void 91406b9b3e0SSimon J. Gerraty CandidateSearcher_Init(CandidateSearcher *cs) 91506b9b3e0SSimon J. Gerraty { 91606b9b3e0SSimon J. Gerraty Lst_Init(&cs->list); 91706b9b3e0SSimon J. Gerraty } 91806b9b3e0SSimon J. Gerraty 91906b9b3e0SSimon J. Gerraty static void 92006b9b3e0SSimon J. Gerraty CandidateSearcher_Done(CandidateSearcher *cs) 92106b9b3e0SSimon J. Gerraty { 92206b9b3e0SSimon J. Gerraty Lst_Done(&cs->list); 92306b9b3e0SSimon J. Gerraty } 92406b9b3e0SSimon J. Gerraty 92506b9b3e0SSimon J. Gerraty static void 92606b9b3e0SSimon J. Gerraty CandidateSearcher_Add(CandidateSearcher *cs, Candidate *cand) 92706b9b3e0SSimon J. Gerraty { 92806b9b3e0SSimon J. Gerraty /* TODO: filter duplicates */ 92906b9b3e0SSimon J. Gerraty Lst_Append(&cs->list, cand); 93006b9b3e0SSimon J. Gerraty } 93106b9b3e0SSimon J. Gerraty 93206b9b3e0SSimon J. Gerraty static void 93306b9b3e0SSimon J. Gerraty CandidateSearcher_AddIfNew(CandidateSearcher *cs, Candidate *cand) 93406b9b3e0SSimon J. Gerraty { 93506b9b3e0SSimon J. Gerraty /* TODO: filter duplicates */ 93606b9b3e0SSimon J. Gerraty if (Lst_FindDatum(&cs->list, cand) == NULL) 93706b9b3e0SSimon J. Gerraty Lst_Append(&cs->list, cand); 93806b9b3e0SSimon J. Gerraty } 93906b9b3e0SSimon J. Gerraty 94006b9b3e0SSimon J. Gerraty static void 94106b9b3e0SSimon J. Gerraty CandidateSearcher_MoveAll(CandidateSearcher *cs, CandidateList *list) 94206b9b3e0SSimon J. Gerraty { 94306b9b3e0SSimon J. Gerraty /* TODO: filter duplicates */ 94406b9b3e0SSimon J. Gerraty Lst_MoveAll(&cs->list, list); 94506b9b3e0SSimon J. Gerraty } 94606b9b3e0SSimon J. Gerraty 94706b9b3e0SSimon J. Gerraty 948956e45f6SSimon J. Gerraty #ifdef DEBUG_SRC 949956e45f6SSimon J. Gerraty static void 95006b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(CandidateList *list) 951956e45f6SSimon J. Gerraty { 95206b9b3e0SSimon J. Gerraty CandidateListNode *ln; 95306b9b3e0SSimon J. Gerraty 95406b9b3e0SSimon J. Gerraty for (ln = list->first; ln != NULL; ln = ln->next) { 95506b9b3e0SSimon J. Gerraty Candidate *cand = ln->datum; 95606b9b3e0SSimon J. Gerraty debug_printf(" %p:%s", cand, cand->file); 95706b9b3e0SSimon J. Gerraty } 958956e45f6SSimon J. Gerraty debug_printf("\n"); 959956e45f6SSimon J. Gerraty } 960956e45f6SSimon J. Gerraty #endif 961956e45f6SSimon J. Gerraty 96206b9b3e0SSimon J. Gerraty static Candidate * 96306b9b3e0SSimon J. Gerraty Candidate_New(char *name, char *prefix, Suffix *suff, Candidate *parent, 96406b9b3e0SSimon J. Gerraty GNode *gn) 965956e45f6SSimon J. Gerraty { 96606b9b3e0SSimon J. Gerraty Candidate *cand = bmake_malloc(sizeof *cand); 967956e45f6SSimon J. Gerraty 96806b9b3e0SSimon J. Gerraty cand->file = name; 96906b9b3e0SSimon J. Gerraty cand->prefix = prefix; 97006b9b3e0SSimon J. Gerraty cand->suff = Suffix_Ref(suff); 97106b9b3e0SSimon J. Gerraty cand->parent = parent; 97206b9b3e0SSimon J. Gerraty cand->node = gn; 97306b9b3e0SSimon J. Gerraty cand->numChildren = 0; 974956e45f6SSimon J. Gerraty #ifdef DEBUG_SRC 97506b9b3e0SSimon J. Gerraty Lst_Init(&cand->childrenList); 976956e45f6SSimon J. Gerraty #endif 977956e45f6SSimon J. Gerraty 97806b9b3e0SSimon J. Gerraty return cand; 979956e45f6SSimon J. Gerraty } 980956e45f6SSimon J. Gerraty 98106b9b3e0SSimon J. Gerraty /* Add a new candidate to the list. */ 982956e45f6SSimon J. Gerraty static void 98306b9b3e0SSimon J. Gerraty CandidateList_Add(CandidateList *list, char *srcName, Candidate *targ, 9841d3f2ddcSSimon J. Gerraty Suffix *suff, const char *debug_tag MAKE_ATTR_UNUSED) 985956e45f6SSimon J. Gerraty { 98606b9b3e0SSimon J. Gerraty Candidate *cand = Candidate_New(srcName, targ->prefix, suff, targ, 98706b9b3e0SSimon J. Gerraty NULL); 988e2eeea75SSimon J. Gerraty targ->numChildren++; 98906b9b3e0SSimon J. Gerraty Lst_Append(list, cand); 99006b9b3e0SSimon J. Gerraty 991956e45f6SSimon J. Gerraty #ifdef DEBUG_SRC 99206b9b3e0SSimon J. Gerraty Lst_Append(&targ->childrenList, cand); 99306b9b3e0SSimon J. Gerraty debug_printf("%s add suff %p:%s candidate %p:%s to list %p:", 99406b9b3e0SSimon J. Gerraty debug_tag, targ, targ->file, cand, cand->file, list); 99506b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(list); 996956e45f6SSimon J. Gerraty #endif 997956e45f6SSimon J. Gerraty } 998956e45f6SSimon J. Gerraty 99906b9b3e0SSimon J. Gerraty /* 100006b9b3e0SSimon J. Gerraty * Add all candidates to the list that can be formed by applying a suffix to 100106b9b3e0SSimon J. Gerraty * the candidate. 10023955d011SMarcel Moolenaar */ 1003956e45f6SSimon J. Gerraty static void 100406b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(CandidateList *list, Candidate *cand) 10053955d011SMarcel Moolenaar { 100606b9b3e0SSimon J. Gerraty SuffixListNode *ln; 100706b9b3e0SSimon J. Gerraty for (ln = cand->suff->children.first; ln != NULL; ln = ln->next) { 100806b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 100906b9b3e0SSimon J. Gerraty 101012904384SSimon J. Gerraty if (suff->isNull && suff->name[0] != '\0') { 10113955d011SMarcel Moolenaar /* 101206b9b3e0SSimon J. Gerraty * If the suffix has been marked as the NULL suffix, 101306b9b3e0SSimon J. Gerraty * also create a candidate for a file with no suffix 101406b9b3e0SSimon J. Gerraty * attached. 10153955d011SMarcel Moolenaar */ 101606b9b3e0SSimon J. Gerraty CandidateList_Add(list, bmake_strdup(cand->prefix), 101706b9b3e0SSimon J. Gerraty cand, suff, "1"); 10183955d011SMarcel Moolenaar } 10193955d011SMarcel Moolenaar 102006b9b3e0SSimon J. Gerraty CandidateList_Add(list, str_concat2(cand->prefix, suff->name), 102106b9b3e0SSimon J. Gerraty cand, suff, "2"); 1022956e45f6SSimon J. Gerraty } 10233955d011SMarcel Moolenaar } 10243955d011SMarcel Moolenaar 102506b9b3e0SSimon J. Gerraty /* 102606b9b3e0SSimon J. Gerraty * Free the first candidate in the list that is not referenced anymore. 102706b9b3e0SSimon J. Gerraty * Return whether a candidate was removed. 102806b9b3e0SSimon J. Gerraty */ 1029b0c40a00SSimon J. Gerraty static bool 103006b9b3e0SSimon J. Gerraty RemoveCandidate(CandidateList *srcs) 10313955d011SMarcel Moolenaar { 103206b9b3e0SSimon J. Gerraty CandidateListNode *ln; 10332c3632d1SSimon J. Gerraty 10343955d011SMarcel Moolenaar #ifdef DEBUG_SRC 103506b9b3e0SSimon J. Gerraty debug_printf("cleaning list %p:", srcs); 103606b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(srcs); 10373955d011SMarcel Moolenaar #endif 10383955d011SMarcel Moolenaar 103906b9b3e0SSimon J. Gerraty for (ln = srcs->first; ln != NULL; ln = ln->next) { 104006b9b3e0SSimon J. Gerraty Candidate *src = ln->datum; 1041956e45f6SSimon J. Gerraty 1042e2eeea75SSimon J. Gerraty if (src->numChildren == 0) { 1043e2eeea75SSimon J. Gerraty if (src->parent == NULL) 104406b9b3e0SSimon J. Gerraty free(src->prefix); 10453955d011SMarcel Moolenaar else { 10463955d011SMarcel Moolenaar #ifdef DEBUG_SRC 104706b9b3e0SSimon J. Gerraty /* XXX: Lst_RemoveDatum */ 104806b9b3e0SSimon J. Gerraty CandidateListNode *ln2; 104906b9b3e0SSimon J. Gerraty ln2 = Lst_FindDatum(&src->parent->childrenList, 105006b9b3e0SSimon J. Gerraty src); 105195e3ed2cSSimon J. Gerraty if (ln2 != NULL) 105206b9b3e0SSimon J. Gerraty Lst_Remove(&src->parent->childrenList, 105306b9b3e0SSimon J. Gerraty ln2); 10543955d011SMarcel Moolenaar #endif 1055e2eeea75SSimon J. Gerraty src->parent->numChildren--; 10563955d011SMarcel Moolenaar } 10573955d011SMarcel Moolenaar #ifdef DEBUG_SRC 105806b9b3e0SSimon J. Gerraty debug_printf("free: list %p src %p:%s children %d\n", 105906b9b3e0SSimon J. Gerraty srcs, src, src->file, src->numChildren); 106006b9b3e0SSimon J. Gerraty Lst_Done(&src->childrenList); 10613955d011SMarcel Moolenaar #endif 106206b9b3e0SSimon J. Gerraty Lst_Remove(srcs, ln); 106306b9b3e0SSimon J. Gerraty free(src->file); 1064e2eeea75SSimon J. Gerraty free(src); 1065b0c40a00SSimon J. Gerraty return true; 10663955d011SMarcel Moolenaar } 10673955d011SMarcel Moolenaar #ifdef DEBUG_SRC 10683955d011SMarcel Moolenaar else { 106906b9b3e0SSimon J. Gerraty debug_printf("keep: list %p src %p:%s children %d:", 107006b9b3e0SSimon J. Gerraty srcs, src, src->file, src->numChildren); 107106b9b3e0SSimon J. Gerraty CandidateList_PrintAddrs(&src->childrenList); 10723955d011SMarcel Moolenaar } 10733955d011SMarcel Moolenaar #endif 10743955d011SMarcel Moolenaar } 10753955d011SMarcel Moolenaar 1076b0c40a00SSimon J. Gerraty return false; 10773955d011SMarcel Moolenaar } 10783955d011SMarcel Moolenaar 1079e2eeea75SSimon J. Gerraty /* Find the first existing file/target in srcs. */ 108006b9b3e0SSimon J. Gerraty static Candidate * 108106b9b3e0SSimon J. Gerraty FindThem(CandidateList *srcs, CandidateSearcher *cs) 10823955d011SMarcel Moolenaar { 108306b9b3e0SSimon J. Gerraty HashSet seen; 108406b9b3e0SSimon J. Gerraty 108506b9b3e0SSimon J. Gerraty HashSet_Init(&seen); 10863955d011SMarcel Moolenaar 10873955d011SMarcel Moolenaar while (!Lst_IsEmpty(srcs)) { 108806b9b3e0SSimon J. Gerraty Candidate *src = Lst_Dequeue(srcs); 10893955d011SMarcel Moolenaar 109006b9b3e0SSimon J. Gerraty #ifdef DEBUG_SRC 109106b9b3e0SSimon J. Gerraty debug_printf("remove from list %p src %p:%s\n", 109206b9b3e0SSimon J. Gerraty srcs, src, src->file); 109306b9b3e0SSimon J. Gerraty #endif 109406b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\ttrying %s...", src->file); 10953955d011SMarcel Moolenaar 10963955d011SMarcel Moolenaar /* 10973955d011SMarcel Moolenaar * A file is considered to exist if either a node exists in the 10983955d011SMarcel Moolenaar * graph for it or the file actually exists. 10993955d011SMarcel Moolenaar */ 1100956e45f6SSimon J. Gerraty if (Targ_FindNode(src->file) != NULL) { 110106b9b3e0SSimon J. Gerraty found: 110206b9b3e0SSimon J. Gerraty HashSet_Done(&seen); 110306b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "got it\n"); 110406b9b3e0SSimon J. Gerraty return src; 11053955d011SMarcel Moolenaar } 11063955d011SMarcel Moolenaar 1107956e45f6SSimon J. Gerraty { 110806b9b3e0SSimon J. Gerraty char *file = Dir_FindFile(src->file, 110906b9b3e0SSimon J. Gerraty src->suff->searchPath); 1110956e45f6SSimon J. Gerraty if (file != NULL) { 1111956e45f6SSimon J. Gerraty free(file); 111206b9b3e0SSimon J. Gerraty goto found; 11133955d011SMarcel Moolenaar } 1114956e45f6SSimon J. Gerraty } 11153955d011SMarcel Moolenaar 111606b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "not there\n"); 11173955d011SMarcel Moolenaar 111806b9b3e0SSimon J. Gerraty if (HashSet_Add(&seen, src->file)) 111906b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(srcs, src); 112006b9b3e0SSimon J. Gerraty else { 112106b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "FindThem: skipping duplicate \"%s\"\n", 112206b9b3e0SSimon J. Gerraty src->file); 11233955d011SMarcel Moolenaar } 11243955d011SMarcel Moolenaar 112506b9b3e0SSimon J. Gerraty CandidateSearcher_Add(cs, src); 11263955d011SMarcel Moolenaar } 11273955d011SMarcel Moolenaar 112806b9b3e0SSimon J. Gerraty HashSet_Done(&seen); 112906b9b3e0SSimon J. Gerraty return NULL; 113006b9b3e0SSimon J. Gerraty } 113106b9b3e0SSimon J. Gerraty 113206b9b3e0SSimon J. Gerraty /* 113306b9b3e0SSimon J. Gerraty * See if any of the children of the candidate's GNode is one from which the 113406b9b3e0SSimon J. Gerraty * target can be transformed. If there is one, a candidate is put together 113506b9b3e0SSimon J. Gerraty * for it and returned. 11363955d011SMarcel Moolenaar */ 113706b9b3e0SSimon J. Gerraty static Candidate * 113806b9b3e0SSimon J. Gerraty FindCmds(Candidate *targ, CandidateSearcher *cs) 11393955d011SMarcel Moolenaar { 1140956e45f6SSimon J. Gerraty GNodeListNode *gln; 1141956e45f6SSimon J. Gerraty GNode *tgn; /* Target GNode */ 1142956e45f6SSimon J. Gerraty GNode *sgn; /* Source GNode */ 1143956e45f6SSimon J. Gerraty size_t prefLen; /* The length of the defined prefix */ 1144dba7b0efSSimon J. Gerraty Suffix *suff; /* Suffix of the matching candidate */ 114506b9b3e0SSimon J. Gerraty Candidate *ret; /* Return value */ 11463955d011SMarcel Moolenaar 1147956e45f6SSimon J. Gerraty tgn = targ->node; 114806b9b3e0SSimon J. Gerraty prefLen = strlen(targ->prefix); 11493955d011SMarcel Moolenaar 115006b9b3e0SSimon J. Gerraty for (gln = tgn->children.first; gln != NULL; gln = gln->next) { 1151dba7b0efSSimon J. Gerraty const char *base; 115206b9b3e0SSimon J. Gerraty 1153956e45f6SSimon J. Gerraty sgn = gln->datum; 11543955d011SMarcel Moolenaar 115506b9b3e0SSimon J. Gerraty if (sgn->type & OP_OPTIONAL && Lst_IsEmpty(&tgn->commands)) { 11563955d011SMarcel Moolenaar /* 115706b9b3e0SSimon J. Gerraty * We haven't looked to see if .OPTIONAL files exist 115806b9b3e0SSimon J. Gerraty * yet, so don't use one as the implicit source. 115906b9b3e0SSimon J. Gerraty * This allows us to use .OPTIONAL in .depend files so 116006b9b3e0SSimon J. Gerraty * make won't complain "don't know how to make xxx.h" 116106b9b3e0SSimon J. Gerraty * when a dependent file has been moved/deleted. 11623955d011SMarcel Moolenaar */ 11633955d011SMarcel Moolenaar continue; 11643955d011SMarcel Moolenaar } 11653955d011SMarcel Moolenaar 1166dba7b0efSSimon J. Gerraty base = str_basename(sgn->name); 1167dba7b0efSSimon J. Gerraty if (strncmp(base, targ->prefix, prefLen) != 0) 11683955d011SMarcel Moolenaar continue; 11699f45a3c8SSimon J. Gerraty /* 11709f45a3c8SSimon J. Gerraty * The node matches the prefix, see if it has a known suffix. 11719f45a3c8SSimon J. Gerraty */ 1172dba7b0efSSimon J. Gerraty suff = FindSuffixByName(base + prefLen); 1173956e45f6SSimon J. Gerraty if (suff == NULL) 11743955d011SMarcel Moolenaar continue; 1175956e45f6SSimon J. Gerraty 11763955d011SMarcel Moolenaar /* 11773955d011SMarcel Moolenaar * It even has a known suffix, see if there's a transformation 11783955d011SMarcel Moolenaar * defined between the node's suffix and the target's suffix. 11793955d011SMarcel Moolenaar * 11803955d011SMarcel Moolenaar * XXX: Handle multi-stage transformations here, too. 11813955d011SMarcel Moolenaar */ 11823955d011SMarcel Moolenaar 118306b9b3e0SSimon J. Gerraty if (Lst_FindDatum(&suff->parents, targ->suff) != NULL) 11843955d011SMarcel Moolenaar break; 11853955d011SMarcel Moolenaar } 11863955d011SMarcel Moolenaar 1187956e45f6SSimon J. Gerraty if (gln == NULL) 1188956e45f6SSimon J. Gerraty return NULL; 1189956e45f6SSimon J. Gerraty 119006b9b3e0SSimon J. Gerraty ret = Candidate_New(bmake_strdup(sgn->name), targ->prefix, suff, targ, 119106b9b3e0SSimon J. Gerraty sgn); 1192e2eeea75SSimon J. Gerraty targ->numChildren++; 11933955d011SMarcel Moolenaar #ifdef DEBUG_SRC 119406b9b3e0SSimon J. Gerraty debug_printf("3 add targ %p:%s ret %p:%s\n", 119506b9b3e0SSimon J. Gerraty targ, targ->file, ret, ret->file); 119606b9b3e0SSimon J. Gerraty Lst_Append(&targ->childrenList, ret); 11973955d011SMarcel Moolenaar #endif 119806b9b3e0SSimon J. Gerraty CandidateSearcher_Add(cs, ret); 119906b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\tusing existing source %s\n", sgn->name); 12003841c287SSimon J. Gerraty return ret; 12013955d011SMarcel Moolenaar } 12023955d011SMarcel Moolenaar 12033955d011SMarcel Moolenaar static void 120406b9b3e0SSimon J. Gerraty ExpandWildcards(GNodeListNode *cln, GNode *pgn) 12053955d011SMarcel Moolenaar { 1206956e45f6SSimon J. Gerraty GNode *cgn = cln->datum; 120706b9b3e0SSimon J. Gerraty StringList expansions; 12083955d011SMarcel Moolenaar 120906b9b3e0SSimon J. Gerraty if (!Dir_HasWildcards(cgn->name)) 12103955d011SMarcel Moolenaar return; 12113955d011SMarcel Moolenaar 1212d5e0a182SSimon J. Gerraty /* Expand the word along the chosen path. */ 121306b9b3e0SSimon J. Gerraty Lst_Init(&expansions); 1214dba7b0efSSimon J. Gerraty SearchPath_Expand(Suff_FindPath(cgn), cgn->name, &expansions); 121506b9b3e0SSimon J. Gerraty 121606b9b3e0SSimon J. Gerraty while (!Lst_IsEmpty(&expansions)) { 121706b9b3e0SSimon J. Gerraty GNode *gn; 121806b9b3e0SSimon J. Gerraty /* 121906b9b3e0SSimon J. Gerraty * Fetch next expansion off the list and find its GNode 122006b9b3e0SSimon J. Gerraty */ 1221d5e0a182SSimon J. Gerraty char *name = Lst_Dequeue(&expansions); 122206b9b3e0SSimon J. Gerraty 1223d5e0a182SSimon J. Gerraty DEBUG1(SUFF, "%s...", name); 1224d5e0a182SSimon J. Gerraty gn = Targ_GetNode(name); 12258d5c8e21SSimon J. Gerraty free(name); 122606b9b3e0SSimon J. Gerraty 12279f45a3c8SSimon J. Gerraty /* Insert gn before the original child. */ 122806b9b3e0SSimon J. Gerraty Lst_InsertBefore(&pgn->children, cln, gn); 122906b9b3e0SSimon J. Gerraty Lst_Append(&gn->parents, pgn); 123006b9b3e0SSimon J. Gerraty pgn->unmade++; 12313955d011SMarcel Moolenaar } 12323955d011SMarcel Moolenaar 123306b9b3e0SSimon J. Gerraty Lst_Done(&expansions); 12343955d011SMarcel Moolenaar 123506b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "\n"); 123606b9b3e0SSimon J. Gerraty 123706b9b3e0SSimon J. Gerraty /* 1238d5e0a182SSimon J. Gerraty * Now that the source is expanded, remove it from the list of 1239d5e0a182SSimon J. Gerraty * children, to keep it from being processed. 124006b9b3e0SSimon J. Gerraty */ 124106b9b3e0SSimon J. Gerraty pgn->unmade--; 124206b9b3e0SSimon J. Gerraty Lst_Remove(&pgn->children, cln); 124306b9b3e0SSimon J. Gerraty Lst_Remove(&cgn->parents, Lst_FindDatum(&cgn->parents, pgn)); 124406b9b3e0SSimon J. Gerraty } 124506b9b3e0SSimon J. Gerraty 124606b9b3e0SSimon J. Gerraty /* 124706b9b3e0SSimon J. Gerraty * Break the result into a vector of strings whose nodes we can find, then 124806b9b3e0SSimon J. Gerraty * add those nodes to the members list. 124906b9b3e0SSimon J. Gerraty * 125006b9b3e0SSimon J. Gerraty * Unfortunately, we can't use Str_Words because it doesn't understand about 1251d5e0a182SSimon J. Gerraty * expressions with spaces in them. 125206b9b3e0SSimon J. Gerraty */ 125306b9b3e0SSimon J. Gerraty static void 1254d5e0a182SSimon J. Gerraty ExpandChildrenRegular(char *p, GNode *pgn, GNodeList *members) 12552c3632d1SSimon J. Gerraty { 12563955d011SMarcel Moolenaar char *start; 12573955d011SMarcel Moolenaar 1258d5e0a182SSimon J. Gerraty pp_skip_hspace(&p); 1259d5e0a182SSimon J. Gerraty start = p; 1260d5e0a182SSimon J. Gerraty while (*p != '\0') { 1261d5e0a182SSimon J. Gerraty if (*p == ' ' || *p == '\t') { 126206b9b3e0SSimon J. Gerraty GNode *gn; 12633955d011SMarcel Moolenaar /* 12643955d011SMarcel Moolenaar * White-space -- terminate element, find the node, 12653955d011SMarcel Moolenaar * add it, skip any further spaces. 12663955d011SMarcel Moolenaar */ 1267d5e0a182SSimon J. Gerraty *p++ = '\0'; 1268956e45f6SSimon J. Gerraty gn = Targ_GetNode(start); 12692c3632d1SSimon J. Gerraty Lst_Append(members, gn); 1270d5e0a182SSimon J. Gerraty pp_skip_hspace(&p); 127106b9b3e0SSimon J. Gerraty /* Continue at the next non-space. */ 1272d5e0a182SSimon J. Gerraty start = p; 1273d5e0a182SSimon J. Gerraty } else if (*p == '$') { 1274d5e0a182SSimon J. Gerraty /* Skip over the expression. */ 1275d5e0a182SSimon J. Gerraty const char *nested_p = p; 12768d5c8e21SSimon J. Gerraty FStr junk = Var_Parse(&nested_p, pgn, VARE_PARSE); 1277956e45f6SSimon J. Gerraty /* TODO: handle errors */ 127806b9b3e0SSimon J. Gerraty if (junk.str == var_Error) { 1279956e45f6SSimon J. Gerraty Parse_Error(PARSE_FATAL, 1280d5e0a182SSimon J. Gerraty "Malformed expression at \"%s\"", p); 1281d5e0a182SSimon J. Gerraty p++; 1282956e45f6SSimon J. Gerraty } else { 1283d5e0a182SSimon J. Gerraty p += nested_p - p; 12843955d011SMarcel Moolenaar } 12853955d011SMarcel Moolenaar 128606b9b3e0SSimon J. Gerraty FStr_Done(&junk); 1287d5e0a182SSimon J. Gerraty } else if (p[0] == '\\' && p[1] != '\0') { 128806b9b3e0SSimon J. Gerraty /* Escaped something -- skip over it. */ 12893955d011SMarcel Moolenaar /* 129006b9b3e0SSimon J. Gerraty * XXX: In other places, escaping at this syntactical 129106b9b3e0SSimon J. Gerraty * position is done by a '$', not a '\'. The '\' is 129206b9b3e0SSimon J. Gerraty * only used in variable modifiers. 12933955d011SMarcel Moolenaar */ 1294d5e0a182SSimon J. Gerraty p += 2; 1295956e45f6SSimon J. Gerraty } else { 1296d5e0a182SSimon J. Gerraty p++; 12973955d011SMarcel Moolenaar } 12983955d011SMarcel Moolenaar } 12993955d011SMarcel Moolenaar 1300d5e0a182SSimon J. Gerraty if (p != start) { 13013955d011SMarcel Moolenaar /* 13023955d011SMarcel Moolenaar * Stuff left over -- add it to the list too 13033955d011SMarcel Moolenaar */ 130406b9b3e0SSimon J. Gerraty GNode *gn = Targ_GetNode(start); 13052c3632d1SSimon J. Gerraty Lst_Append(members, gn); 13063955d011SMarcel Moolenaar } 130706b9b3e0SSimon J. Gerraty } 130806b9b3e0SSimon J. Gerraty 13093955d011SMarcel Moolenaar /* 1310d5e0a182SSimon J. Gerraty * Expand the names of any children of a given node that contain 131106b9b3e0SSimon J. Gerraty * expressions or file wildcards into actual targets. 131206b9b3e0SSimon J. Gerraty * 131306b9b3e0SSimon J. Gerraty * The expanded node is removed from the parent's list of children, and the 131406b9b3e0SSimon J. Gerraty * parent's unmade counter is decremented, but other nodes may be added. 131506b9b3e0SSimon J. Gerraty * 131606b9b3e0SSimon J. Gerraty * Input: 131706b9b3e0SSimon J. Gerraty * cln Child to examine 131806b9b3e0SSimon J. Gerraty * pgn Parent node being processed 13193955d011SMarcel Moolenaar */ 132006b9b3e0SSimon J. Gerraty static void 132106b9b3e0SSimon J. Gerraty ExpandChildren(GNodeListNode *cln, GNode *pgn) 132206b9b3e0SSimon J. Gerraty { 132306b9b3e0SSimon J. Gerraty GNode *cgn = cln->datum; 1324d5e0a182SSimon J. Gerraty char *expanded; 132506b9b3e0SSimon J. Gerraty 132606b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&cgn->order_pred) || !Lst_IsEmpty(&cgn->order_succ)) 132706b9b3e0SSimon J. Gerraty /* It is all too hard to process the result of .ORDER */ 132806b9b3e0SSimon J. Gerraty return; 132906b9b3e0SSimon J. Gerraty 133006b9b3e0SSimon J. Gerraty if (cgn->type & OP_WAIT) 133106b9b3e0SSimon J. Gerraty /* Ignore these (& OP_PHONY ?) */ 133206b9b3e0SSimon J. Gerraty return; 133306b9b3e0SSimon J. Gerraty 133406b9b3e0SSimon J. Gerraty /* 133506b9b3e0SSimon J. Gerraty * First do variable expansion -- this takes precedence over wildcard 133606b9b3e0SSimon J. Gerraty * expansion. If the result contains wildcards, they'll be gotten to 133706b9b3e0SSimon J. Gerraty * later since the resulting words are tacked on to the end of the 133806b9b3e0SSimon J. Gerraty * children list. 133906b9b3e0SSimon J. Gerraty */ 134006b9b3e0SSimon J. Gerraty if (strchr(cgn->name, '$') == NULL) { 134106b9b3e0SSimon J. Gerraty ExpandWildcards(cln, pgn); 134206b9b3e0SSimon J. Gerraty return; 134306b9b3e0SSimon J. Gerraty } 134406b9b3e0SSimon J. Gerraty 134506b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Expanding \"%s\"...", cgn->name); 13468d5c8e21SSimon J. Gerraty expanded = Var_Subst(cgn->name, pgn, VARE_EVAL_DEFINED); 134706b9b3e0SSimon J. Gerraty /* TODO: handle errors */ 134806b9b3e0SSimon J. Gerraty 134906b9b3e0SSimon J. Gerraty { 135006b9b3e0SSimon J. Gerraty GNodeList members = LST_INIT; 135106b9b3e0SSimon J. Gerraty 135206b9b3e0SSimon J. Gerraty if (cgn->type & OP_ARCHV) { 135306b9b3e0SSimon J. Gerraty /* 1354dba7b0efSSimon J. Gerraty * Node was an 'archive(member)' target, so 135506b9b3e0SSimon J. Gerraty * call on the Arch module to find the nodes for us, 1356dba7b0efSSimon J. Gerraty * expanding variables in the parent's scope. 135706b9b3e0SSimon J. Gerraty */ 1358d5e0a182SSimon J. Gerraty char *ap = expanded; 1359d5e0a182SSimon J. Gerraty (void)Arch_ParseArchive(&ap, &members, pgn); 136006b9b3e0SSimon J. Gerraty } else { 1361d5e0a182SSimon J. Gerraty ExpandChildrenRegular(expanded, pgn, &members); 13623955d011SMarcel Moolenaar } 13633955d011SMarcel Moolenaar 1364d5e0a182SSimon J. Gerraty /* Add all members to the parent node. */ 136506b9b3e0SSimon J. Gerraty while (!Lst_IsEmpty(&members)) { 136606b9b3e0SSimon J. Gerraty GNode *gn = Lst_Dequeue(&members); 13673955d011SMarcel Moolenaar 136806b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "%s...", gn->name); 136906b9b3e0SSimon J. Gerraty Lst_InsertBefore(&pgn->children, cln, gn); 137006b9b3e0SSimon J. Gerraty Lst_Append(&gn->parents, pgn); 13713955d011SMarcel Moolenaar pgn->unmade++; 137206b9b3e0SSimon J. Gerraty ExpandWildcards(cln->prev, pgn); 13733955d011SMarcel Moolenaar } 137406b9b3e0SSimon J. Gerraty Lst_Done(&members); 13753955d011SMarcel Moolenaar 1376d5e0a182SSimon J. Gerraty free(expanded); 13773955d011SMarcel Moolenaar } 13782c3632d1SSimon J. Gerraty 137906b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "\n"); 13803955d011SMarcel Moolenaar 13813955d011SMarcel Moolenaar /* 1382d5e0a182SSimon J. Gerraty * The source is expanded now, so remove it from the list of children, 1383d5e0a182SSimon J. Gerraty * to keep it from being processed. 13843955d011SMarcel Moolenaar */ 13853955d011SMarcel Moolenaar pgn->unmade--; 138606b9b3e0SSimon J. Gerraty Lst_Remove(&pgn->children, cln); 138706b9b3e0SSimon J. Gerraty Lst_Remove(&cgn->parents, Lst_FindDatum(&cgn->parents, pgn)); 13883955d011SMarcel Moolenaar } 13893955d011SMarcel Moolenaar 13903955d011SMarcel Moolenaar static void 139106b9b3e0SSimon J. Gerraty ExpandAllChildren(GNode *gn) 13923955d011SMarcel Moolenaar { 139306b9b3e0SSimon J. Gerraty GNodeListNode *ln, *nln; 13943955d011SMarcel Moolenaar 139506b9b3e0SSimon J. Gerraty for (ln = gn->children.first; ln != NULL; ln = nln) { 139606b9b3e0SSimon J. Gerraty nln = ln->next; 139706b9b3e0SSimon J. Gerraty ExpandChildren(ln, gn); 139806b9b3e0SSimon J. Gerraty } 13993955d011SMarcel Moolenaar } 14003955d011SMarcel Moolenaar 14013955d011SMarcel Moolenaar /* 1402d5e0a182SSimon J. Gerraty * Find a path along which to search or expand the node. 14033955d011SMarcel Moolenaar * 1404d5e0a182SSimon J. Gerraty * If the node has a known suffix, use that path, 1405d5e0a182SSimon J. Gerraty * otherwise use the default system search path. 14063955d011SMarcel Moolenaar */ 1407956e45f6SSimon J. Gerraty SearchPath * 14083955d011SMarcel Moolenaar Suff_FindPath(GNode *gn) 14093955d011SMarcel Moolenaar { 141006b9b3e0SSimon J. Gerraty Suffix *suff = gn->suffix; 14113955d011SMarcel Moolenaar 14123955d011SMarcel Moolenaar if (suff == NULL) { 1413956e45f6SSimon J. Gerraty char *name = gn->name; 1414956e45f6SSimon J. Gerraty size_t nameLen = strlen(gn->name); 141506b9b3e0SSimon J. Gerraty SuffixListNode *ln; 141606b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) 141706b9b3e0SSimon J. Gerraty if (Suffix_IsSuffix(ln->datum, nameLen, name + nameLen)) 1418956e45f6SSimon J. Gerraty break; 14193955d011SMarcel Moolenaar 142006b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "Wildcard expanding \"%s\"...", gn->name); 14213955d011SMarcel Moolenaar if (ln != NULL) 1422956e45f6SSimon J. Gerraty suff = ln->datum; 142306b9b3e0SSimon J. Gerraty /* 142406b9b3e0SSimon J. Gerraty * XXX: Here we can save the suffix so we don't have to do 142506b9b3e0SSimon J. Gerraty * this again. 142606b9b3e0SSimon J. Gerraty */ 14273955d011SMarcel Moolenaar } 14283955d011SMarcel Moolenaar 14293955d011SMarcel Moolenaar if (suff != NULL) { 143006b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "suffix is \"%s\"...\n", suff->name); 14313955d011SMarcel Moolenaar return suff->searchPath; 14323955d011SMarcel Moolenaar } else { 143306b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "\n"); 143406b9b3e0SSimon J. Gerraty return &dirSearchPath; /* Use default search path */ 14353955d011SMarcel Moolenaar } 14363955d011SMarcel Moolenaar } 14373955d011SMarcel Moolenaar 143806b9b3e0SSimon J. Gerraty /* 143906b9b3e0SSimon J. Gerraty * Apply a transformation rule, given the source and target nodes and 14402c3632d1SSimon J. Gerraty * suffixes. 14413955d011SMarcel Moolenaar * 1442e2eeea75SSimon J. Gerraty * The source and target are linked and the commands from the transformation 1443e2eeea75SSimon J. Gerraty * are added to the target node's commands list. The target also inherits all 1444e2eeea75SSimon J. Gerraty * the sources for the transformation rule. 14453955d011SMarcel Moolenaar * 14463955d011SMarcel Moolenaar * Results: 1447b0c40a00SSimon J. Gerraty * true if successful, false if not. 14483955d011SMarcel Moolenaar */ 1449b0c40a00SSimon J. Gerraty static bool 145006b9b3e0SSimon J. Gerraty ApplyTransform(GNode *tgn, GNode *sgn, Suffix *tsuff, Suffix *ssuff) 14513955d011SMarcel Moolenaar { 1452e2eeea75SSimon J. Gerraty GNodeListNode *ln; 14533955d011SMarcel Moolenaar char *tname; /* Name of transformation rule */ 145406b9b3e0SSimon J. Gerraty GNode *gn; /* Node for the transformation rule */ 14553955d011SMarcel Moolenaar 145606b9b3e0SSimon J. Gerraty /* Form the proper links between the target and source. */ 145706b9b3e0SSimon J. Gerraty Lst_Append(&tgn->children, sgn); 145806b9b3e0SSimon J. Gerraty Lst_Append(&sgn->parents, tgn); 1459e2eeea75SSimon J. Gerraty tgn->unmade++; 14603955d011SMarcel Moolenaar 146106b9b3e0SSimon J. Gerraty /* Locate the transformation rule itself. */ 1462e2eeea75SSimon J. Gerraty tname = str_concat2(ssuff->name, tsuff->name); 1463956e45f6SSimon J. Gerraty gn = FindTransformByName(tname); 14643955d011SMarcel Moolenaar free(tname); 14653955d011SMarcel Moolenaar 1466e2eeea75SSimon J. Gerraty /* This can happen when linking an OP_MEMBER and OP_ARCHV node. */ 146706b9b3e0SSimon J. Gerraty if (gn == NULL) 1468b0c40a00SSimon J. Gerraty return false; 14693955d011SMarcel Moolenaar 1470e2eeea75SSimon J. Gerraty DEBUG3(SUFF, "\tapplying %s -> %s to \"%s\"\n", 1471e2eeea75SSimon J. Gerraty ssuff->name, tsuff->name, tgn->name); 14723955d011SMarcel Moolenaar 1473e2eeea75SSimon J. Gerraty /* Record last child; Make_HandleUse may add child nodes. */ 147406b9b3e0SSimon J. Gerraty ln = tgn->children.last; 14753955d011SMarcel Moolenaar 1476e2eeea75SSimon J. Gerraty /* Apply the rule. */ 1477e2eeea75SSimon J. Gerraty Make_HandleUse(gn, tgn); 14783955d011SMarcel Moolenaar 1479d5e0a182SSimon J. Gerraty /* Deal with wildcards and expressions in any acquired sources. */ 1480e2eeea75SSimon J. Gerraty ln = ln != NULL ? ln->next : NULL; 1481e2eeea75SSimon J. Gerraty while (ln != NULL) { 1482e2eeea75SSimon J. Gerraty GNodeListNode *nln = ln->next; 148306b9b3e0SSimon J. Gerraty ExpandChildren(ln, tgn); 1484e2eeea75SSimon J. Gerraty ln = nln; 14853955d011SMarcel Moolenaar } 14863955d011SMarcel Moolenaar 14873955d011SMarcel Moolenaar /* 1488e2eeea75SSimon J. Gerraty * Keep track of another parent to which this node is transformed so 14893955d011SMarcel Moolenaar * the .IMPSRC variable can be set correctly for the parent. 14903955d011SMarcel Moolenaar */ 149106b9b3e0SSimon J. Gerraty Lst_Append(&sgn->implicitParents, tgn); 14923955d011SMarcel Moolenaar 1493b0c40a00SSimon J. Gerraty return true; 14943955d011SMarcel Moolenaar } 14953955d011SMarcel Moolenaar 149606b9b3e0SSimon J. Gerraty /* 149706b9b3e0SSimon J. Gerraty * Member has a known suffix, so look for a transformation rule from 149806b9b3e0SSimon J. Gerraty * it to a possible suffix of the archive. 149906b9b3e0SSimon J. Gerraty * 150006b9b3e0SSimon J. Gerraty * Rather than searching through the entire list, we just look at 150106b9b3e0SSimon J. Gerraty * suffixes to which the member's suffix may be transformed. 150206b9b3e0SSimon J. Gerraty */ 150306b9b3e0SSimon J. Gerraty static void 150406b9b3e0SSimon J. Gerraty ExpandMember(GNode *gn, const char *eoarch, GNode *mem, Suffix *memSuff) 150506b9b3e0SSimon J. Gerraty { 1506d5e0a182SSimon J. Gerraty SuffixListNode *ln; 150706b9b3e0SSimon J. Gerraty size_t nameLen = (size_t)(eoarch - gn->name); 15083955d011SMarcel Moolenaar 150906b9b3e0SSimon J. Gerraty /* Use first matching suffix... */ 151006b9b3e0SSimon J. Gerraty for (ln = memSuff->parents.first; ln != NULL; ln = ln->next) 151106b9b3e0SSimon J. Gerraty if (Suffix_IsSuffix(ln->datum, nameLen, eoarch)) 151206b9b3e0SSimon J. Gerraty break; 151306b9b3e0SSimon J. Gerraty 151406b9b3e0SSimon J. Gerraty if (ln != NULL) { 151506b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 151606b9b3e0SSimon J. Gerraty if (!ApplyTransform(gn, mem, suff, memSuff)) { 151706b9b3e0SSimon J. Gerraty DEBUG2(SUFF, "\tNo transformation from %s -> %s\n", 151806b9b3e0SSimon J. Gerraty memSuff->name, suff->name); 151906b9b3e0SSimon J. Gerraty } 152006b9b3e0SSimon J. Gerraty } 152106b9b3e0SSimon J. Gerraty } 152206b9b3e0SSimon J. Gerraty 152306b9b3e0SSimon J. Gerraty static void FindDeps(GNode *, CandidateSearcher *); 152406b9b3e0SSimon J. Gerraty 152506b9b3e0SSimon J. Gerraty /* 152606b9b3e0SSimon J. Gerraty * Locate dependencies for an OP_ARCHV node. 15273955d011SMarcel Moolenaar * 15283955d011SMarcel Moolenaar * Side Effects: 15293955d011SMarcel Moolenaar * Same as Suff_FindDeps 15303955d011SMarcel Moolenaar */ 15313955d011SMarcel Moolenaar static void 153206b9b3e0SSimon J. Gerraty FindDepsArchive(GNode *gn, CandidateSearcher *cs) 15333955d011SMarcel Moolenaar { 15343955d011SMarcel Moolenaar char *eoarch; /* End of archive portion */ 15353955d011SMarcel Moolenaar char *eoname; /* End of member portion */ 15363955d011SMarcel Moolenaar GNode *mem; /* Node for member */ 153706b9b3e0SSimon J. Gerraty Suffix *memSuff; 153806b9b3e0SSimon J. Gerraty const char *name; /* Start of member's name */ 15393955d011SMarcel Moolenaar 15403955d011SMarcel Moolenaar /* 1541d5e0a182SSimon J. Gerraty * The node is an 'archive(member)' pair, so we must find a 15423955d011SMarcel Moolenaar * suffix for both of them. 15433955d011SMarcel Moolenaar */ 15443955d011SMarcel Moolenaar eoarch = strchr(gn->name, '('); 15453955d011SMarcel Moolenaar eoname = strchr(eoarch, ')'); 15463955d011SMarcel Moolenaar 1547e1cee40dSSimon J. Gerraty /* 1548e1cee40dSSimon J. Gerraty * Caller guarantees the format `libname(member)', via 1549e1cee40dSSimon J. Gerraty * Arch_ParseArchive. 1550e1cee40dSSimon J. Gerraty */ 1551e1cee40dSSimon J. Gerraty assert(eoarch != NULL); 1552e1cee40dSSimon J. Gerraty assert(eoname != NULL); 1553e1cee40dSSimon J. Gerraty 15543955d011SMarcel Moolenaar *eoname = '\0'; /* Nuke parentheses during suffix search */ 15553955d011SMarcel Moolenaar *eoarch = '\0'; /* So a suffix can be found */ 15563955d011SMarcel Moolenaar 15573955d011SMarcel Moolenaar name = eoarch + 1; 15583955d011SMarcel Moolenaar 15593955d011SMarcel Moolenaar /* 156006b9b3e0SSimon J. Gerraty * To simplify things, call Suff_FindDeps recursively on the member 156106b9b3e0SSimon J. Gerraty * now, so we can simply compare the member's .PREFIX and .TARGET 156206b9b3e0SSimon J. Gerraty * variables to locate its suffix. This allows us to figure out the 156306b9b3e0SSimon J. Gerraty * suffix to use for the archive without having to do a quadratic 156406b9b3e0SSimon J. Gerraty * search over the suffix list, backtracking for each one. 15653955d011SMarcel Moolenaar */ 1566956e45f6SSimon J. Gerraty mem = Targ_GetNode(name); 156706b9b3e0SSimon J. Gerraty FindDeps(mem, cs); 15683955d011SMarcel Moolenaar 156906b9b3e0SSimon J. Gerraty /* Create the link between the two nodes right off. */ 157006b9b3e0SSimon J. Gerraty Lst_Append(&gn->children, mem); 157106b9b3e0SSimon J. Gerraty Lst_Append(&mem->parents, gn); 1572956e45f6SSimon J. Gerraty gn->unmade++; 15733955d011SMarcel Moolenaar 157406b9b3e0SSimon J. Gerraty /* Copy in the variables from the member node to this one. */ 1575dba7b0efSSimon J. Gerraty Var_Set(gn, PREFIX, GNode_VarPrefix(mem)); 1576dba7b0efSSimon J. Gerraty Var_Set(gn, TARGET, GNode_VarTarget(mem)); 15773955d011SMarcel Moolenaar 157806b9b3e0SSimon J. Gerraty memSuff = mem->suffix; 157906b9b3e0SSimon J. Gerraty if (memSuff == NULL) { /* Didn't know what it was. */ 158006b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "using null suffix\n"); 158106b9b3e0SSimon J. Gerraty memSuff = nullSuff; 15823955d011SMarcel Moolenaar } 15833955d011SMarcel Moolenaar 15843955d011SMarcel Moolenaar 158506b9b3e0SSimon J. Gerraty /* Set the other two local variables required for this target. */ 1586dba7b0efSSimon J. Gerraty Var_Set(gn, MEMBER, name); 1587dba7b0efSSimon J. Gerraty Var_Set(gn, ARCHIVE, gn->name); 158806b9b3e0SSimon J. Gerraty /* Set $@ for compatibility with other makes. */ 1589dba7b0efSSimon J. Gerraty Var_Set(gn, TARGET, gn->name); 15903bebe729SSimon J. Gerraty 15913bebe729SSimon J. Gerraty /* 15923bebe729SSimon J. Gerraty * Now we've got the important local variables set, expand any sources 15933bebe729SSimon J. Gerraty * that still contain variables or wildcards in their names. 15943bebe729SSimon J. Gerraty */ 159506b9b3e0SSimon J. Gerraty ExpandAllChildren(gn); 15963bebe729SSimon J. Gerraty 159706b9b3e0SSimon J. Gerraty if (memSuff != NULL) 159806b9b3e0SSimon J. Gerraty ExpandMember(gn, eoarch, mem, memSuff); 15993955d011SMarcel Moolenaar 16003955d011SMarcel Moolenaar /* 160106b9b3e0SSimon J. Gerraty * Replace the opening and closing parens now we've no need of the 160206b9b3e0SSimon J. Gerraty * separate pieces. 16033955d011SMarcel Moolenaar */ 1604e2eeea75SSimon J. Gerraty *eoarch = '('; 1605e2eeea75SSimon J. Gerraty *eoname = ')'; 16063955d011SMarcel Moolenaar 16073955d011SMarcel Moolenaar /* 160806b9b3e0SSimon J. Gerraty * Pretend gn appeared to the left of a dependency operator so the 160906b9b3e0SSimon J. Gerraty * user needn't provide a transformation from the member to the 16103955d011SMarcel Moolenaar * archive. 16113955d011SMarcel Moolenaar */ 1612e2eeea75SSimon J. Gerraty if (!GNode_IsTarget(gn)) 16133955d011SMarcel Moolenaar gn->type |= OP_DEPENDS; 16143955d011SMarcel Moolenaar 16153955d011SMarcel Moolenaar /* 16163955d011SMarcel Moolenaar * Flag the member as such so we remember to look in the archive for 161706b9b3e0SSimon J. Gerraty * its modification time. The OP_JOIN | OP_MADE is needed because 161806b9b3e0SSimon J. Gerraty * this target should never get made. 16193955d011SMarcel Moolenaar */ 16203bebe729SSimon J. Gerraty mem->type |= OP_MEMBER | OP_JOIN | OP_MADE; 16213955d011SMarcel Moolenaar } 16223955d011SMarcel Moolenaar 162306b9b3e0SSimon J. Gerraty /* 162406b9b3e0SSimon J. Gerraty * If the node is a library, it is the arch module's job to find it 162506b9b3e0SSimon J. Gerraty * and set the TARGET variable accordingly. We merely provide the 162606b9b3e0SSimon J. Gerraty * search path, assuming all libraries end in ".a" (if the suffix 162706b9b3e0SSimon J. Gerraty * hasn't been defined, there's nothing we can do for it, so we just 162806b9b3e0SSimon J. Gerraty * set the TARGET variable to the node's name in order to give it a 162906b9b3e0SSimon J. Gerraty * value). 163006b9b3e0SSimon J. Gerraty */ 1631956e45f6SSimon J. Gerraty static void 163206b9b3e0SSimon J. Gerraty FindDepsLib(GNode *gn) 1633956e45f6SSimon J. Gerraty { 163406b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(LIBSUFF); 163506b9b3e0SSimon J. Gerraty if (suff != NULL) { 163606b9b3e0SSimon J. Gerraty Suffix_Reassign(&gn->suffix, suff); 163706b9b3e0SSimon J. Gerraty Arch_FindLib(gn, suff->searchPath); 163806b9b3e0SSimon J. Gerraty } else { 163906b9b3e0SSimon J. Gerraty Suffix_Unassign(&gn->suffix); 1640dba7b0efSSimon J. Gerraty Var_Set(gn, TARGET, gn->name); 164106b9b3e0SSimon J. Gerraty } 164206b9b3e0SSimon J. Gerraty 164306b9b3e0SSimon J. Gerraty /* 164406b9b3e0SSimon J. Gerraty * Because a library (-lfoo) target doesn't follow the standard 164506b9b3e0SSimon J. Gerraty * filesystem conventions, we don't set the regular variables for 164606b9b3e0SSimon J. Gerraty * the thing. .PREFIX is simply made empty. 164706b9b3e0SSimon J. Gerraty */ 1648dba7b0efSSimon J. Gerraty Var_Set(gn, PREFIX, ""); 164906b9b3e0SSimon J. Gerraty } 165006b9b3e0SSimon J. Gerraty 165106b9b3e0SSimon J. Gerraty static void 165206b9b3e0SSimon J. Gerraty FindDepsRegularKnown(const char *name, size_t nameLen, GNode *gn, 165306b9b3e0SSimon J. Gerraty CandidateList *srcs, CandidateList *targs) 165406b9b3e0SSimon J. Gerraty { 165506b9b3e0SSimon J. Gerraty SuffixListNode *ln; 165606b9b3e0SSimon J. Gerraty Candidate *targ; 1657956e45f6SSimon J. Gerraty char *pref; 1658956e45f6SSimon J. Gerraty 165906b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 166006b9b3e0SSimon J. Gerraty Suffix *suff = ln->datum; 166106b9b3e0SSimon J. Gerraty if (!Suffix_IsSuffix(suff, nameLen, name + nameLen)) 1662956e45f6SSimon J. Gerraty continue; 1663956e45f6SSimon J. Gerraty 1664956e45f6SSimon J. Gerraty pref = bmake_strldup(name, (size_t)(nameLen - suff->nameLen)); 166506b9b3e0SSimon J. Gerraty targ = Candidate_New(bmake_strdup(gn->name), pref, suff, NULL, 166606b9b3e0SSimon J. Gerraty gn); 1667956e45f6SSimon J. Gerraty 166806b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(srcs, targ); 1669956e45f6SSimon J. Gerraty 167006b9b3e0SSimon J. Gerraty /* Record the target so we can nuke it. */ 1671956e45f6SSimon J. Gerraty Lst_Append(targs, targ); 1672956e45f6SSimon J. Gerraty } 1673956e45f6SSimon J. Gerraty } 1674956e45f6SSimon J. Gerraty 1675956e45f6SSimon J. Gerraty static void 167606b9b3e0SSimon J. Gerraty FindDepsRegularUnknown(GNode *gn, const char *sopref, 167706b9b3e0SSimon J. Gerraty CandidateList *srcs, CandidateList *targs) 1678956e45f6SSimon J. Gerraty { 167906b9b3e0SSimon J. Gerraty Candidate *targ; 1680956e45f6SSimon J. Gerraty 168106b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(targs) || nullSuff == NULL) 1682956e45f6SSimon J. Gerraty return; 1683956e45f6SSimon J. Gerraty 168406b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name); 1685956e45f6SSimon J. Gerraty 168606b9b3e0SSimon J. Gerraty targ = Candidate_New(bmake_strdup(gn->name), bmake_strdup(sopref), 168706b9b3e0SSimon J. Gerraty nullSuff, NULL, gn); 1688956e45f6SSimon J. Gerraty 1689956e45f6SSimon J. Gerraty /* 1690956e45f6SSimon J. Gerraty * Only use the default suffix rules if we don't have commands 169106b9b3e0SSimon J. Gerraty * defined for this gnode; traditional make programs used to not 169206b9b3e0SSimon J. Gerraty * define suffix rules if the gnode had children but we don't do 169306b9b3e0SSimon J. Gerraty * this anymore. 1694956e45f6SSimon J. Gerraty */ 169506b9b3e0SSimon J. Gerraty if (Lst_IsEmpty(&gn->commands)) 169606b9b3e0SSimon J. Gerraty CandidateList_AddCandidatesFor(srcs, targ); 1697956e45f6SSimon J. Gerraty else { 169806b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "not "); 1699956e45f6SSimon J. Gerraty } 1700956e45f6SSimon J. Gerraty 170106b9b3e0SSimon J. Gerraty DEBUG0(SUFF, "adding suffix rules\n"); 1702956e45f6SSimon J. Gerraty 1703956e45f6SSimon J. Gerraty Lst_Append(targs, targ); 1704956e45f6SSimon J. Gerraty } 1705956e45f6SSimon J. Gerraty 1706956e45f6SSimon J. Gerraty /* 170706b9b3e0SSimon J. Gerraty * Deal with finding the thing on the default search path. We always do 170806b9b3e0SSimon J. Gerraty * that, not only if the node is only a source (not on the lhs of a 170906b9b3e0SSimon J. Gerraty * dependency operator or [XXX] it has neither children or commands) as 171006b9b3e0SSimon J. Gerraty * the old pmake did. 1711956e45f6SSimon J. Gerraty */ 1712956e45f6SSimon J. Gerraty static void 171306b9b3e0SSimon J. Gerraty FindDepsRegularPath(GNode *gn, Candidate *targ) 1714956e45f6SSimon J. Gerraty { 1715956e45f6SSimon J. Gerraty if (gn->type & (OP_PHONY | OP_NOPATH)) 1716956e45f6SSimon J. Gerraty return; 1717956e45f6SSimon J. Gerraty 1718956e45f6SSimon J. Gerraty free(gn->path); 1719956e45f6SSimon J. Gerraty gn->path = Dir_FindFile(gn->name, 17209f45a3c8SSimon J. Gerraty targ == NULL ? &dirSearchPath : targ->suff->searchPath); 1721956e45f6SSimon J. Gerraty if (gn->path == NULL) 1722956e45f6SSimon J. Gerraty return; 1723956e45f6SSimon J. Gerraty 1724dba7b0efSSimon J. Gerraty Var_Set(gn, TARGET, gn->path); 1725956e45f6SSimon J. Gerraty 1726956e45f6SSimon J. Gerraty if (targ != NULL) { 1727956e45f6SSimon J. Gerraty /* 1728956e45f6SSimon J. Gerraty * Suffix known for the thing -- trim the suffix off 1729956e45f6SSimon J. Gerraty * the path to form the proper .PREFIX variable. 1730956e45f6SSimon J. Gerraty */ 1731956e45f6SSimon J. Gerraty size_t savep = strlen(gn->path) - targ->suff->nameLen; 1732956e45f6SSimon J. Gerraty char savec; 1733956e45f6SSimon J. Gerraty 173406b9b3e0SSimon J. Gerraty Suffix_Reassign(&gn->suffix, targ->suff); 1735956e45f6SSimon J. Gerraty 1736956e45f6SSimon J. Gerraty savec = gn->path[savep]; 1737956e45f6SSimon J. Gerraty gn->path[savep] = '\0'; 1738956e45f6SSimon J. Gerraty 1739dba7b0efSSimon J. Gerraty Var_Set(gn, PREFIX, str_basename(gn->path)); 1740956e45f6SSimon J. Gerraty 1741956e45f6SSimon J. Gerraty gn->path[savep] = savec; 1742956e45f6SSimon J. Gerraty } else { 174306b9b3e0SSimon J. Gerraty /* 174406b9b3e0SSimon J. Gerraty * The .PREFIX gets the full path if the target has no 174506b9b3e0SSimon J. Gerraty * known suffix. 174606b9b3e0SSimon J. Gerraty */ 174706b9b3e0SSimon J. Gerraty Suffix_Unassign(&gn->suffix); 1748dba7b0efSSimon J. Gerraty Var_Set(gn, PREFIX, str_basename(gn->path)); 1749956e45f6SSimon J. Gerraty } 1750956e45f6SSimon J. Gerraty } 1751956e45f6SSimon J. Gerraty 175206b9b3e0SSimon J. Gerraty /* 175306b9b3e0SSimon J. Gerraty * Locate implicit dependencies for regular targets. 17543955d011SMarcel Moolenaar * 17553955d011SMarcel Moolenaar * Input: 17563955d011SMarcel Moolenaar * gn Node for which to find sources 17573955d011SMarcel Moolenaar * 17583955d011SMarcel Moolenaar * Side Effects: 17592c3632d1SSimon J. Gerraty * Same as Suff_FindDeps 17603955d011SMarcel Moolenaar */ 17613955d011SMarcel Moolenaar static void 176206b9b3e0SSimon J. Gerraty FindDepsRegular(GNode *gn, CandidateSearcher *cs) 17633955d011SMarcel Moolenaar { 176406b9b3e0SSimon J. Gerraty /* List of sources at which to look */ 176506b9b3e0SSimon J. Gerraty CandidateList srcs = LST_INIT; 176606b9b3e0SSimon J. Gerraty /* 176706b9b3e0SSimon J. Gerraty * List of targets to which things can be transformed. 176806b9b3e0SSimon J. Gerraty * They all have the same file, but different suff and prefix fields. 176906b9b3e0SSimon J. Gerraty */ 177006b9b3e0SSimon J. Gerraty CandidateList targs = LST_INIT; 177106b9b3e0SSimon J. Gerraty Candidate *bottom; /* Start of found transformation path */ 177206b9b3e0SSimon J. Gerraty Candidate *src; 177306b9b3e0SSimon J. Gerraty Candidate *targ; 17743955d011SMarcel Moolenaar 1775956e45f6SSimon J. Gerraty const char *name = gn->name; 1776956e45f6SSimon J. Gerraty size_t nameLen = strlen(name); 17773955d011SMarcel Moolenaar 177806b9b3e0SSimon J. Gerraty #ifdef DEBUG_SRC 177906b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "FindDepsRegular \"%s\"\n", gn->name); 178006b9b3e0SSimon J. Gerraty #endif 17813955d011SMarcel Moolenaar 17823955d011SMarcel Moolenaar /* 178306b9b3e0SSimon J. Gerraty * We're caught in a catch-22 here. On the one hand, we want to use 178406b9b3e0SSimon J. Gerraty * any transformation implied by the target's sources, but we can't 178506b9b3e0SSimon J. Gerraty * examine the sources until we've expanded any variables/wildcards 178606b9b3e0SSimon J. Gerraty * they may hold, and we can't do that until we've set up the 178706b9b3e0SSimon J. Gerraty * target's local variables and we can't do that until we know what 178806b9b3e0SSimon J. Gerraty * the proper suffix for the target is (in case there are two 178906b9b3e0SSimon J. Gerraty * suffixes one of which is a suffix of the other) and we can't know 179006b9b3e0SSimon J. Gerraty * that until we've found its implied source, which we may not want 179106b9b3e0SSimon J. Gerraty * to use if there's an existing source that implies a different 179206b9b3e0SSimon J. Gerraty * transformation. 17933955d011SMarcel Moolenaar * 17943955d011SMarcel Moolenaar * In an attempt to get around this, which may not work all the time, 179506b9b3e0SSimon J. Gerraty * but should work most of the time, we look for implied sources 179606b9b3e0SSimon J. Gerraty * first, checking transformations to all possible suffixes of the 179706b9b3e0SSimon J. Gerraty * target, use what we find to set the target's local variables, 179806b9b3e0SSimon J. Gerraty * expand the children, then look for any overriding transformations 179906b9b3e0SSimon J. Gerraty * they imply. Should we find one, we discard the one we found before. 18003955d011SMarcel Moolenaar */ 18014fc82fe4SSimon J. Gerraty bottom = NULL; 18024fc82fe4SSimon J. Gerraty targ = NULL; 18034fc82fe4SSimon J. Gerraty 18044fc82fe4SSimon J. Gerraty if (!(gn->type & OP_PHONY)) { 18053955d011SMarcel Moolenaar 180606b9b3e0SSimon J. Gerraty FindDepsRegularKnown(name, nameLen, gn, &srcs, &targs); 18073955d011SMarcel Moolenaar 1808956e45f6SSimon J. Gerraty /* Handle target of unknown suffix... */ 180906b9b3e0SSimon J. Gerraty FindDepsRegularUnknown(gn, name, &srcs, &targs); 18103955d011SMarcel Moolenaar 18113955d011SMarcel Moolenaar /* 181252d86256SSimon J. Gerraty * Using the list of possible sources built up from the target 181306b9b3e0SSimon J. Gerraty * suffix(es), try and find an existing file/target that 181406b9b3e0SSimon J. Gerraty * matches. 18153955d011SMarcel Moolenaar */ 181606b9b3e0SSimon J. Gerraty bottom = FindThem(&srcs, cs); 18173955d011SMarcel Moolenaar 18183955d011SMarcel Moolenaar if (bottom == NULL) { 18193955d011SMarcel Moolenaar /* 182006b9b3e0SSimon J. Gerraty * No known transformations -- use the first suffix 182106b9b3e0SSimon J. Gerraty * found for setting the local variables. 18223955d011SMarcel Moolenaar */ 182306b9b3e0SSimon J. Gerraty if (targs.first != NULL) 182406b9b3e0SSimon J. Gerraty targ = targs.first->datum; 1825e2eeea75SSimon J. Gerraty else 18263955d011SMarcel Moolenaar targ = NULL; 18273955d011SMarcel Moolenaar } else { 18283955d011SMarcel Moolenaar /* 182906b9b3e0SSimon J. Gerraty * Work up the transformation path to find the suffix 183006b9b3e0SSimon J. Gerraty * of the target to which the transformation was made. 18313955d011SMarcel Moolenaar */ 183206b9b3e0SSimon J. Gerraty for (targ = bottom; 183306b9b3e0SSimon J. Gerraty targ->parent != NULL; targ = targ->parent) 18343955d011SMarcel Moolenaar continue; 18353955d011SMarcel Moolenaar } 18364fc82fe4SSimon J. Gerraty } 18373955d011SMarcel Moolenaar 1838dba7b0efSSimon J. Gerraty Var_Set(gn, TARGET, GNode_Path(gn)); 1839dba7b0efSSimon J. Gerraty Var_Set(gn, PREFIX, targ != NULL ? targ->prefix : gn->name); 18403955d011SMarcel Moolenaar 18413955d011SMarcel Moolenaar /* 18423955d011SMarcel Moolenaar * Now we've got the important local variables set, expand any sources 18433955d011SMarcel Moolenaar * that still contain variables or wildcards in their names. 18443955d011SMarcel Moolenaar */ 1845956e45f6SSimon J. Gerraty { 184606b9b3e0SSimon J. Gerraty GNodeListNode *ln, *nln; 184706b9b3e0SSimon J. Gerraty for (ln = gn->children.first; ln != NULL; ln = nln) { 1848956e45f6SSimon J. Gerraty nln = ln->next; 184906b9b3e0SSimon J. Gerraty ExpandChildren(ln, gn); 18503955d011SMarcel Moolenaar } 1851956e45f6SSimon J. Gerraty } 18523955d011SMarcel Moolenaar 18533955d011SMarcel Moolenaar if (targ == NULL) { 185406b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "\tNo valid suffix on %s\n", gn->name); 18553955d011SMarcel Moolenaar 18563955d011SMarcel Moolenaar sfnd_abort: 185706b9b3e0SSimon J. Gerraty FindDepsRegularPath(gn, targ); 18583955d011SMarcel Moolenaar goto sfnd_return; 18593955d011SMarcel Moolenaar } 18603955d011SMarcel Moolenaar 18613955d011SMarcel Moolenaar /* 18623955d011SMarcel Moolenaar * If the suffix indicates that the target is a library, mark that in 18633955d011SMarcel Moolenaar * the node's type field. 18643955d011SMarcel Moolenaar */ 186512904384SSimon J. Gerraty if (targ->suff->library) 18663955d011SMarcel Moolenaar gn->type |= OP_LIB; 18673955d011SMarcel Moolenaar 18683955d011SMarcel Moolenaar /* 18693955d011SMarcel Moolenaar * Check for overriding transformation rule implied by sources 18703955d011SMarcel Moolenaar */ 187106b9b3e0SSimon J. Gerraty if (!Lst_IsEmpty(&gn->children)) { 187206b9b3e0SSimon J. Gerraty src = FindCmds(targ, cs); 18733955d011SMarcel Moolenaar 18743955d011SMarcel Moolenaar if (src != NULL) { 18753955d011SMarcel Moolenaar /* 187606b9b3e0SSimon J. Gerraty * Free up all the candidates in the transformation 187706b9b3e0SSimon J. Gerraty * path, up to but not including the parent node. 18783955d011SMarcel Moolenaar */ 1879e2eeea75SSimon J. Gerraty while (bottom != NULL && bottom->parent != NULL) { 188006b9b3e0SSimon J. Gerraty CandidateSearcher_AddIfNew(cs, bottom); 18813955d011SMarcel Moolenaar bottom = bottom->parent; 18823955d011SMarcel Moolenaar } 18833955d011SMarcel Moolenaar bottom = src; 18843955d011SMarcel Moolenaar } 18853955d011SMarcel Moolenaar } 18863955d011SMarcel Moolenaar 18873955d011SMarcel Moolenaar if (bottom == NULL) { 188806b9b3e0SSimon J. Gerraty /* No idea from where it can come -- return now. */ 18893955d011SMarcel Moolenaar goto sfnd_abort; 18903955d011SMarcel Moolenaar } 18913955d011SMarcel Moolenaar 18923955d011SMarcel Moolenaar /* 189306b9b3e0SSimon J. Gerraty * We now have a list of candidates headed by 'bottom' and linked via 18943955d011SMarcel Moolenaar * their 'parent' pointers. What we do next is create links between 18953955d011SMarcel Moolenaar * source and target nodes (which may or may not have been created) 189606b9b3e0SSimon J. Gerraty * and set the necessary local variables in each target. 189706b9b3e0SSimon J. Gerraty * 189806b9b3e0SSimon J. Gerraty * The commands for each target are set from the commands of the 18993955d011SMarcel Moolenaar * transformation rule used to get from the src suffix to the targ 19003955d011SMarcel Moolenaar * suffix. Note that this causes the commands list of the original 190106b9b3e0SSimon J. Gerraty * node, gn, to be replaced with the commands of the final 190206b9b3e0SSimon J. Gerraty * transformation rule. 19033955d011SMarcel Moolenaar */ 1904e2eeea75SSimon J. Gerraty if (bottom->node == NULL) 1905956e45f6SSimon J. Gerraty bottom->node = Targ_GetNode(bottom->file); 19063955d011SMarcel Moolenaar 19073955d011SMarcel Moolenaar for (src = bottom; src->parent != NULL; src = src->parent) { 19083955d011SMarcel Moolenaar targ = src->parent; 19093955d011SMarcel Moolenaar 191006b9b3e0SSimon J. Gerraty Suffix_Reassign(&src->node->suffix, src->suff); 19113955d011SMarcel Moolenaar 1912e2eeea75SSimon J. Gerraty if (targ->node == NULL) 1913956e45f6SSimon J. Gerraty targ->node = Targ_GetNode(targ->file); 19143955d011SMarcel Moolenaar 1915d5e0a182SSimon J. Gerraty ApplyTransform(targ->node, src->node, targ->suff, src->suff); 19163955d011SMarcel Moolenaar 19173955d011SMarcel Moolenaar if (targ->node != gn) { 19183955d011SMarcel Moolenaar /* 191906b9b3e0SSimon J. Gerraty * Finish off the dependency-search process for any 192006b9b3e0SSimon J. Gerraty * nodes between bottom and gn (no point in questing 192106b9b3e0SSimon J. Gerraty * around the filesystem for their implicit source 192206b9b3e0SSimon J. Gerraty * when it's already known). Note that the node 192306b9b3e0SSimon J. Gerraty * can't have any sources that need expanding, since 192406b9b3e0SSimon J. Gerraty * SuffFindThem will stop on an existing node, so all 192506b9b3e0SSimon J. Gerraty * we need to do is set the standard variables. 19263955d011SMarcel Moolenaar */ 19273955d011SMarcel Moolenaar targ->node->type |= OP_DEPS_FOUND; 1928dba7b0efSSimon J. Gerraty Var_Set(targ->node, PREFIX, targ->prefix); 1929dba7b0efSSimon J. Gerraty Var_Set(targ->node, TARGET, targ->node->name); 19303955d011SMarcel Moolenaar } 19313955d011SMarcel Moolenaar } 19323955d011SMarcel Moolenaar 193306b9b3e0SSimon J. Gerraty Suffix_Reassign(&gn->suffix, src->suff); 19343955d011SMarcel Moolenaar 19353955d011SMarcel Moolenaar /* 193606b9b3e0SSimon J. Gerraty * Nuke the transformation path and the candidates left over in the 19373955d011SMarcel Moolenaar * two lists. 19383955d011SMarcel Moolenaar */ 19393955d011SMarcel Moolenaar sfnd_return: 194006b9b3e0SSimon J. Gerraty if (bottom != NULL) 194106b9b3e0SSimon J. Gerraty CandidateSearcher_AddIfNew(cs, bottom); 19423955d011SMarcel Moolenaar 194306b9b3e0SSimon J. Gerraty while (RemoveCandidate(&srcs) || RemoveCandidate(&targs)) 19443955d011SMarcel Moolenaar continue; 19453955d011SMarcel Moolenaar 194606b9b3e0SSimon J. Gerraty CandidateSearcher_MoveAll(cs, &srcs); 194706b9b3e0SSimon J. Gerraty CandidateSearcher_MoveAll(cs, &targs); 194806b9b3e0SSimon J. Gerraty } 194906b9b3e0SSimon J. Gerraty 195006b9b3e0SSimon J. Gerraty static void 195106b9b3e0SSimon J. Gerraty CandidateSearcher_CleanUp(CandidateSearcher *cs) 195206b9b3e0SSimon J. Gerraty { 195306b9b3e0SSimon J. Gerraty while (RemoveCandidate(&cs->list)) 195406b9b3e0SSimon J. Gerraty continue; 195506b9b3e0SSimon J. Gerraty assert(Lst_IsEmpty(&cs->list)); 19563955d011SMarcel Moolenaar } 19573955d011SMarcel Moolenaar 19583955d011SMarcel Moolenaar 195906b9b3e0SSimon J. Gerraty /* 196006b9b3e0SSimon J. Gerraty * Find implicit sources for the target. 19613955d011SMarcel Moolenaar * 196206b9b3e0SSimon J. Gerraty * Nodes are added to the graph as children of the passed-in node. The nodes 196306b9b3e0SSimon J. Gerraty * are marked to have their IMPSRC variable filled in. The PREFIX variable 196406b9b3e0SSimon J. Gerraty * is set for the given node and all its implied children. 19653955d011SMarcel Moolenaar * 19662c3632d1SSimon J. Gerraty * The path found by this target is the shortest path in the transformation 196706b9b3e0SSimon J. Gerraty * graph, which may pass through nonexistent targets, to an existing target. 19682c3632d1SSimon J. Gerraty * The search continues on all paths from the root suffix until a file is 19692c3632d1SSimon J. Gerraty * found. I.e. if there's a path .o -> .c -> .l -> .l,v from the root and the 19702c3632d1SSimon J. Gerraty * .l,v file exists but the .c and .l files don't, the search will branch out 19712c3632d1SSimon J. Gerraty * in all directions from .o and again from all the nodes on the next level 19722c3632d1SSimon J. Gerraty * until the .l,v node is encountered. 19733955d011SMarcel Moolenaar */ 19743955d011SMarcel Moolenaar void 19753955d011SMarcel Moolenaar Suff_FindDeps(GNode *gn) 19763955d011SMarcel Moolenaar { 197706b9b3e0SSimon J. Gerraty CandidateSearcher cs; 19783955d011SMarcel Moolenaar 197906b9b3e0SSimon J. Gerraty CandidateSearcher_Init(&cs); 198006b9b3e0SSimon J. Gerraty 198106b9b3e0SSimon J. Gerraty FindDeps(gn, &cs); 198206b9b3e0SSimon J. Gerraty 198306b9b3e0SSimon J. Gerraty CandidateSearcher_CleanUp(&cs); 198406b9b3e0SSimon J. Gerraty CandidateSearcher_Done(&cs); 19853955d011SMarcel Moolenaar } 19863955d011SMarcel Moolenaar 19873955d011SMarcel Moolenaar static void 198806b9b3e0SSimon J. Gerraty FindDeps(GNode *gn, CandidateSearcher *cs) 19893955d011SMarcel Moolenaar { 19902c3632d1SSimon J. Gerraty if (gn->type & OP_DEPS_FOUND) 19913955d011SMarcel Moolenaar return; 19923955d011SMarcel Moolenaar gn->type |= OP_DEPS_FOUND; 19932c3632d1SSimon J. Gerraty 199406b9b3e0SSimon J. Gerraty /* Make sure we have these set, may get revised below. */ 1995dba7b0efSSimon J. Gerraty Var_Set(gn, TARGET, GNode_Path(gn)); 1996dba7b0efSSimon J. Gerraty Var_Set(gn, PREFIX, gn->name); 19974fc82fe4SSimon J. Gerraty 199806b9b3e0SSimon J. Gerraty DEBUG1(SUFF, "SuffFindDeps \"%s\"\n", gn->name); 19993955d011SMarcel Moolenaar 200006b9b3e0SSimon J. Gerraty if (gn->type & OP_ARCHV) 200106b9b3e0SSimon J. Gerraty FindDepsArchive(gn, cs); 200206b9b3e0SSimon J. Gerraty else if (gn->type & OP_LIB) 200306b9b3e0SSimon J. Gerraty FindDepsLib(gn); 200406b9b3e0SSimon J. Gerraty else 200506b9b3e0SSimon J. Gerraty FindDepsRegular(gn, cs); 20063955d011SMarcel Moolenaar } 20073955d011SMarcel Moolenaar 200806b9b3e0SSimon J. Gerraty /* 200906b9b3e0SSimon J. Gerraty * Define which suffix is the null suffix. 20102c3632d1SSimon J. Gerraty * 20112c3632d1SSimon J. Gerraty * Need to handle the changing of the null suffix gracefully so the old 20122c3632d1SSimon J. Gerraty * transformation rules don't just go away. 20133955d011SMarcel Moolenaar */ 20143955d011SMarcel Moolenaar void 2015956e45f6SSimon J. Gerraty Suff_SetNull(const char *name) 20163955d011SMarcel Moolenaar { 201706b9b3e0SSimon J. Gerraty Suffix *suff = FindSuffixByName(name); 2018e2eeea75SSimon J. Gerraty if (suff == NULL) { 201906b9b3e0SSimon J. Gerraty Parse_Error(PARSE_WARNING, 202012904384SSimon J. Gerraty "Desired null suffix %s not defined", 2021956e45f6SSimon J. Gerraty name); 2022956e45f6SSimon J. Gerraty return; 2023956e45f6SSimon J. Gerraty } 20243955d011SMarcel Moolenaar 202506b9b3e0SSimon J. Gerraty if (nullSuff != NULL) 202612904384SSimon J. Gerraty nullSuff->isNull = false; 202712904384SSimon J. Gerraty suff->isNull = true; 202806b9b3e0SSimon J. Gerraty /* XXX: Here's where the transformation mangling would take place. */ 202906b9b3e0SSimon J. Gerraty nullSuff = suff; 20303955d011SMarcel Moolenaar } 20313955d011SMarcel Moolenaar 20322c3632d1SSimon J. Gerraty /* Initialize the suffixes module. */ 20333955d011SMarcel Moolenaar void 20343955d011SMarcel Moolenaar Suff_Init(void) 20353955d011SMarcel Moolenaar { 20363955d011SMarcel Moolenaar /* 203706b9b3e0SSimon J. Gerraty * Create null suffix for single-suffix rules (POSIX). The thing 203806b9b3e0SSimon J. Gerraty * doesn't actually go on the suffix list or everyone will think 203906b9b3e0SSimon J. Gerraty * that's its suffix. 20403955d011SMarcel Moolenaar */ 20416e050540SSimon J. Gerraty Suff_ClearSuffixes(); 20423955d011SMarcel Moolenaar } 20433955d011SMarcel Moolenaar 2044*22619282SSimon J. Gerraty #ifdef CLEANUP 20452c3632d1SSimon J. Gerraty /* Clean up the suffixes module. */ 20463955d011SMarcel Moolenaar void 20473955d011SMarcel Moolenaar Suff_End(void) 20483955d011SMarcel Moolenaar { 2049d5e0a182SSimon J. Gerraty SuffixListNode *ln; 2050d5e0a182SSimon J. Gerraty 2051d5e0a182SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) 2052d5e0a182SSimon J. Gerraty Suffix_Free(ln->datum); 2053d5e0a182SSimon J. Gerraty Lst_Done(&sufflist); 2054d5e0a182SSimon J. Gerraty for (ln = suffClean.first; ln != NULL; ln = ln->next) 2055d5e0a182SSimon J. Gerraty Suffix_Free(ln->datum); 2056d5e0a182SSimon J. Gerraty Lst_Done(&suffClean); 205706b9b3e0SSimon J. Gerraty if (nullSuff != NULL) 2058d5e0a182SSimon J. Gerraty Suffix_Free(nullSuff); 205906b9b3e0SSimon J. Gerraty Lst_Done(&transforms); 20603955d011SMarcel Moolenaar } 2061*22619282SSimon J. Gerraty #endif 20623955d011SMarcel Moolenaar 20633955d011SMarcel Moolenaar 2064956e45f6SSimon J. Gerraty static void 206512904384SSimon J. Gerraty PrintSuffNames(const char *prefix, const SuffixList *suffs) 20663955d011SMarcel Moolenaar { 206706b9b3e0SSimon J. Gerraty SuffixListNode *ln; 206895e3ed2cSSimon J. Gerraty 2069956e45f6SSimon J. Gerraty debug_printf("#\t%s: ", prefix); 2070956e45f6SSimon J. Gerraty for (ln = suffs->first; ln != NULL; ln = ln->next) { 207112904384SSimon J. Gerraty const Suffix *suff = ln->datum; 2072956e45f6SSimon J. Gerraty debug_printf("%s ", suff->name); 2073956e45f6SSimon J. Gerraty } 2074956e45f6SSimon J. Gerraty debug_printf("\n"); 20753955d011SMarcel Moolenaar } 20763955d011SMarcel Moolenaar 2077956e45f6SSimon J. Gerraty static void 207812904384SSimon J. Gerraty Suffix_Print(const Suffix *suff) 20793955d011SMarcel Moolenaar { 208012904384SSimon J. Gerraty Buffer buf; 208112904384SSimon J. Gerraty 2082d5e0a182SSimon J. Gerraty Buf_Init(&buf); 208312904384SSimon J. Gerraty Buf_AddFlag(&buf, suff->include, "SUFF_INCLUDE"); 208412904384SSimon J. Gerraty Buf_AddFlag(&buf, suff->library, "SUFF_LIBRARY"); 208512904384SSimon J. Gerraty Buf_AddFlag(&buf, suff->isNull, "SUFF_NULL"); 208612904384SSimon J. Gerraty 2087e2eeea75SSimon J. Gerraty debug_printf("# \"%s\" (num %d, ref %d)", 2088e2eeea75SSimon J. Gerraty suff->name, suff->sNum, suff->refCount); 208912904384SSimon J. Gerraty if (buf.len > 0) 209012904384SSimon J. Gerraty debug_printf(" (%s)", buf.data); 2091956e45f6SSimon J. Gerraty debug_printf("\n"); 2092956e45f6SSimon J. Gerraty 209312904384SSimon J. Gerraty Buf_Done(&buf); 209412904384SSimon J. Gerraty 209506b9b3e0SSimon J. Gerraty PrintSuffNames("To", &suff->parents); 209606b9b3e0SSimon J. Gerraty PrintSuffNames("From", &suff->children); 2097956e45f6SSimon J. Gerraty 2098956e45f6SSimon J. Gerraty debug_printf("#\tSearch Path: "); 209906b9b3e0SSimon J. Gerraty SearchPath_Print(suff->searchPath); 2100956e45f6SSimon J. Gerraty debug_printf("\n"); 21013955d011SMarcel Moolenaar } 21023955d011SMarcel Moolenaar 2103956e45f6SSimon J. Gerraty static void 2104956e45f6SSimon J. Gerraty PrintTransformation(GNode *t) 21053955d011SMarcel Moolenaar { 2106956e45f6SSimon J. Gerraty debug_printf("%-16s:", t->name); 21073955d011SMarcel Moolenaar Targ_PrintType(t->type); 2108956e45f6SSimon J. Gerraty debug_printf("\n"); 2109956e45f6SSimon J. Gerraty Targ_PrintCmds(t); 2110956e45f6SSimon J. Gerraty debug_printf("\n"); 21113955d011SMarcel Moolenaar } 21123955d011SMarcel Moolenaar 21133955d011SMarcel Moolenaar void 21143955d011SMarcel Moolenaar Suff_PrintAll(void) 21153955d011SMarcel Moolenaar { 2116956e45f6SSimon J. Gerraty debug_printf("#*** Suffixes:\n"); 2117956e45f6SSimon J. Gerraty { 211806b9b3e0SSimon J. Gerraty SuffixListNode *ln; 211906b9b3e0SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) 212006b9b3e0SSimon J. Gerraty Suffix_Print(ln->datum); 2121956e45f6SSimon J. Gerraty } 21223955d011SMarcel Moolenaar 2123956e45f6SSimon J. Gerraty debug_printf("#*** Transformations:\n"); 2124956e45f6SSimon J. Gerraty { 2125956e45f6SSimon J. Gerraty GNodeListNode *ln; 212606b9b3e0SSimon J. Gerraty for (ln = transforms.first; ln != NULL; ln = ln->next) 2127956e45f6SSimon J. Gerraty PrintTransformation(ln->datum); 2128956e45f6SSimon J. Gerraty } 21293955d011SMarcel Moolenaar } 213012904384SSimon J. Gerraty 21319f45a3c8SSimon J. Gerraty char * 213212904384SSimon J. Gerraty Suff_NamesStr(void) 213312904384SSimon J. Gerraty { 213412904384SSimon J. Gerraty Buffer buf; 213512904384SSimon J. Gerraty SuffixListNode *ln; 213612904384SSimon J. Gerraty Suffix *suff; 213712904384SSimon J. Gerraty 2138d5e0a182SSimon J. Gerraty Buf_Init(&buf); 213912904384SSimon J. Gerraty for (ln = sufflist.first; ln != NULL; ln = ln->next) { 214012904384SSimon J. Gerraty suff = ln->datum; 214112904384SSimon J. Gerraty if (ln != sufflist.first) 214212904384SSimon J. Gerraty Buf_AddByte(&buf, ' '); 214312904384SSimon J. Gerraty Buf_AddStr(&buf, suff->name); 214412904384SSimon J. Gerraty } 214512904384SSimon J. Gerraty return Buf_DoneData(&buf); 214612904384SSimon J. Gerraty } 2147