/*** ACTION.C -- routines called by the parser ******************************* * * * Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved. * * Purpose: * This module contains the routines called during parsing of a makefile. * * Revision History: * 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*() * 10-May-1993 HV Add include file mbstring.h * Change the str* functions to STR* * 13-Feb-1990 SB nextComponent() missed out mixed case of quoted/non-quote list * 02-Feb-1990 SB Add nextComponent() for Longfilename handling * 08-Dec-1989 SB removed local used without initialization warnings for -Oes * 07-Dec-1989 SB removed register to compile using C6 -Oes (warning gone) * 06-Dec-1989 SB changed expandFileNames() type to void instead of void * * 22-Nov-1989 SB Changed free() to FREE() * 13-Nov-1989 SB Removed an unreferenced local in endNameList() * 02-Oct-1989 SB add dynamic inline file handling support * 04-Sep-1989 SB Add A_DEPENDENT and fix macro inheritance * 24-Aug-1989 SB Allow $* on dependency lines * 14-Jul-1989 SB Environment macro was getting updated even when CMDLINE * macro was present * 29-Jun-1989 SB addItemToList() now maintains Global inline file List * 26-Jun-1989 SB Fixed -e for recursive NMAKE * 22-May-1989 SB NZ options work independently. -NZ does both stuff now * 13-May-1989 SB Changed delList to contain just names of files and no "del " * 14-Apr-1989 SB made targetList NEAR, no 'del inlinefile' cmd for -n now * 05-Apr-1989 SB Added parameters to makeRule() & makeTarget(); this get rid * of globals * 03-Apr-1989 SB changed all functions to NEAR to get them into one module * 21-Mar-1989 SB changed assignDependents() and assignCommands() to handle * multiple target case correctly. * 20-Mar-1989 SB startNamelist() doesn't flag error if target macro is null * and >1 target given; commented startNameList() * 16-Feb-1989 SB addItemToList() now appends to delList instead of List so * that all 'del scriptFile' cmds can be at the end of the make * 29-Jan-1989 SB added targList but not used as yet * 19-Jan-1989 SB changed startNameList() to avoid GP fault, bug# 162 * 18-Jan-1989 SB modified endNameList(), added makeList() and makeBuildList() * and added a parameter to makeTarget() for bug# 161 * 21-Dec-1988 SB use scriptFileList to handle multiple scriptFiles * Improve KEEP/NOKEEP;each file can have its own action * 16-Dec-1988 SB addItemToList() is now equipped for KEEP/NOKEEP * 14-Dec-1988 SB addItemToList() modified for 'Z' option -- adds a delete * command for deleting temporary script files * 5-Nov-1988 RB Fixed macro inheritance for recursive definitions. * 27-Oct-1988 SB put malloc for allocate in putEnvStr() -- error checking * 23-Oct-1988 SB Using putEnvStr() for putenv() to simplify code * 21-Oct-1988 SB Added fInheritUserEnv flag modifications to makeMacro() * and putMacro() for macro inheritance * 19-Sep-1988 RB Remove warning for MAKE redefinition. * 22-Aug-1988 RB Clean up for !UNDEF'ed macros. * 17-Aug-1988 RB Clean up. * 14-Jul-1988 rj Added initialization of dateTime field of BUILDBLOCKs. * 7-Jul-1988 rj Added targetFlag parameter to hash() calls. * Fixed bug: redefined macros didn't get flags reset. * 09-May-1988 rb Don't swallow no-match wildcards. * ******************************************************************************/ #include "nmake.h" #include "nmmsg.h" #include "proto.h" #include "globals.h" #include "grammar.h" LOCAL void NEAR startNameList(void); LOCAL void NEAR makeRule(STRINGLIST *); LOCAL void NEAR makeTarget(char*, BOOL, BUILDBLOCK**); LOCAL void NEAR appendPseudoTargetList(STRINGLIST**, STRINGLIST*); LOCAL void NEAR clearSuffixes(void); LOCAL BOOL NEAR doSpecial(char*); LOCAL BUILDLIST * NEAR makeBuildList(BUILDBLOCK *); STRINGLIST * NEAR makeList(STRINGLIST *); LOCAL char * NEAR nextComponent(char **); /* Globals in this module */ /* created by endNameList() & freed by assignBuildCommands(). In use because * * although global 'list' has this list is used by too many routines and the * * complete sequence of actions on 'list' is unknown */ STRINGLIST * NEAR targetList; //corr to a dependency block /*** makeName -- create copy of a name seen by lexer *************************** * * Purpose: * Create a copy of a macro or 1st name in a target/dependency list. It also * does the groundwork for expansion of macros in name and saves values. * * Input: * * Output: * * Assumes: * That the lexical routines save the token in buf * * Modifies Globals: * name -- the pointer to the copy created, gets allocated memory * macros -- the list of macro values in name. Used later by startNameList() * to expand macros in name and get expanded target name. * * Uses Globals: * buf -- the lexical routines return a token in this * * Notes: * The token in buf could be part of a macrodefinition or a target list. The * next token determines if it is a macrodefn or a targetlist we are parsing. * The next token would overwrite the current token and so it is saved in name. * *******************************************************************************/ void NEAR makeName() { findMacroValues(buf, ¯os, NULL, NULL, 0, 0, 0); name = makeString(buf); } /* * don't expand build lines for rules now -- expand after everything read in * that way CC and CFLAGS used in rules from tools.ini but not defined until * the makefile will have appropriate values. Redefining macros for use * in targets w/o explicit build commands doesn't work. Macros in rules have * the value of their last definition in the makefile. */ void NEAR addItemToList() { STRINGLIST *p; /* from lexer */ STRINGLIST *new; if (name) { SET(actionFlags, A_TARGET); startNameList(); name = NULL; } if (ON(actionFlags, A_TARGET)) { if (isRule(buf)) { if (ON(actionFlags, A_RULE)) makeError(currentLine, TOO_MANY_RULE_NAMES); makeError(currentLine, MIXED_RULES); } } p = makeNewStrListElement(); if (ON(actionFlags, A_STRING)) { /* we collect macros */ p->text = string; /* for dependents & */ string = NULL; /* build lines for */ } /* non-implicit rules*/ else p->text = makeString(buf); new = p; /* build lines for */ if (OFF(actionFlags, A_RULE) /* rules get expanded*/ || ON(actionFlags, A_TARGET)) { /* after entire make-*/ findMacroValues(p->text, ¯os, NULL, NULL, 0, 0, 0); /* file parsed */ } if (ON(actionFlags, A_TARGET)) { p = macros; expandFileNames("$", &new, ¯os); expandFileNames("*?", &new, NULL); while (macros = p) { p = p->next; FREE_STRINGLIST(macros); } } appendItem(&list, new); } /*** startNameList -- puts in the first element into list ********************** * * Scope: * Local. * * Purpose: * Puts in the first name seen into a list * * Input: * * Output: * * Errors/Warnings: * TARGET_MACRO_IS_NULL -- if the macro used as a target expands to null * * Assumes: * The global 'list' is originally a null list, & the global 'macro' points to * a list of values used for expanding the macros in global 'name'. * * Modifies Globals: * list -- the list of names; set to contain the first name here or to a * list of values if 'name' contains a macro invocation. * macros -- the list of values reqd for macro expansion; the list is * freed and macros is made NULL * currentFlags -- the flags for current target; set to global flags * actionFlags -- determine actions to be done; if the name is a rule then set * the rule bit * * Uses Globals: * name -- the first name seen in a list of names. * flags -- the global flags setup by the options specified * actionFlags -- if handling targets then no error as we have > 1 target * * Notes: * If there is more than one target then actionFlags has A_TARGET flag set and * startNameList() is called from addItemToList. In this case don't flag error. * *******************************************************************************/ LOCAL void NEAR startNameList() { STRINGLIST *p; currentFlags = flags; //set flags for cur target p = makeNewStrListElement(); p->text = name; list = p; //list contains name p = macros; expandFileNames("$", &list, ¯os); //expand macros in name expandFileNames("*?", &list, NULL); //expand wildcards while (macros = p) { // free macro list p = p->next; FREE_STRINGLIST(macros); } if (!list && OFF(actionFlags, A_TARGET)) makeError(line, TARGET_MACRO_IS_NULL, name); //target null & 1 target if (list && isRule(list->text)) SET(actionFlags, A_RULE); } /*** endNameList -- semantic actions when a list is fully seen ***************** * * Purpose: * When the parser has seen an entire list then it needs to do some semantic * actions. It calls endNameList() to do these actions. The action depends on * the values in certain globals. * * Input: * * Output: * * Assumes: * Whatever it assumes * * Errors/Warnings: * * Modifies Globals: * actionFlags -- * * Uses Globals: * name -- The first element seen (if non null) * actionFlags -- The flag determining semantic & data structure actions * buf -- The delimiter seen after list * list -- The list of elements seen * * Notes: * explanations/comments etc * *******************************************************************************/ void NEAR endNameList() { if (name) { /* if only one name to left of : */ startNameList(); /* it hasn't been put in list yet*/ name = NULL; } else CLEAR(actionFlags, A_TARGET); /* clear target flag */ if (buf[1]) SET(currentFlags, F2_DOUBLECOLON); /* so addItemToList()*/ if (!list) /* won't expand names*/ makeError(currentLine, SYNTAX_NO_TARGET_NAME); /* of dependents */ if (ON(actionFlags, A_RULE)) { if (ON(currentFlags, F2_DOUBLECOLON)) makeError(currentLine, BAD_SEPARATOR); makeRule(list); FREE_STRINGLIST(list); } else if (!(list->next) /* special pseudotarget ... */ && doSpecial(list->text)) { FREE(list->text); /* don't need ".SUFFIXES" etc */ FREE_STRINGLIST(list); } else /* regular target */ targetList = list; list = NULL; //We are now looking for a dependent SET(actionFlags, A_DEPENDENT); } LOCAL BOOL NEAR doSpecial(s) char *s; { BOOL status = FALSE; if (!_ftcsicmp(s, silent)) { SET(actionFlags, A_SILENT); setFlags('s', TRUE); status = TRUE; } if (!_ftcsicmp(s, ignore)) { SET(actionFlags, A_IGNORE); setFlags('i', TRUE); status = TRUE; } else if (!_ftcscmp(s, suffixes)) { SET(actionFlags, A_SUFFIX); status = TRUE; } else if (!_ftcscmp(s, precious)) { SET(actionFlags, A_PRECIOUS); status = TRUE; } return(status); } void NEAR expandFileNames(string, sourceList, macroList) char *string; STRINGLIST **sourceList; STRINGLIST **macroList; { char *s, *t = NULL; STRINGLIST *p; /* Main list pointer */ STRINGLIST *pNew, /* Pointer to new list */ *pBack; /* Pointer to one element back */ char *saveText = NULL; for (pBack = NULL, p = *sourceList; p;) { /* * If no expand-character is found, continue to next list element. */ if (!_ftcspbrk(p->text, string)) { pBack = p; p = pBack->next; continue; } /* * Either expand macros or wildcards. */ if (*string == '$') { t = expandMacros(p->text, macroList); FREE(p->text); } else { /* * If the wildcard string does not expand to anything, go to * next list elment. Do not remove p from the original list * else we must check for null elsewhere. */ // CAVIAR 3912 -- do not attempt to expand wildcards that // occur in inference rules [rm] if (isRule(p->text) || (pNew = expandWildCards(p->text)) == NULL) { pBack = p; p = pBack->next; continue; } saveText = p->text; } /* * At this point we have a list of expanded names to replace p with. */ if (pBack) { pBack->next = p->next; FREE_STRINGLIST(p); p = pBack->next; } else { *sourceList = p->next; FREE_STRINGLIST(p); p = *sourceList; } if (*string == '$') { /* if expanding macros*/ char *str = t; if (s = nextComponent(&str)) { do { /* put expanded names */ pNew = makeNewStrListElement(); /* at front of list */ pNew->text = makeString(s); /* so we won't try to*/ prependItem(sourceList, pNew); /* re-expand them */ if (!pBack) pBack = pNew; } while (s = nextComponent(&str)); } FREE(t); continue; } else if (pNew) { /* if matches for * ? */ //BUGBUG : Wild cards within Quoted strings will fail if (!pBack) for (pBack = pNew; pBack->next; pBack = pBack->next); appendItem(&pNew, *sourceList); /* put at front of old*/ *sourceList = pNew; /* list */ } FREE(saveText); } } /*** nextComponent - returns next component from expanded name ***************** * * Scope: * Local (used by expandFilenames) * * Purpose: * Given a target string (target with macros expanded) this function returns a * name component. Previously _ftcstok(s, " \t") was used but with the advent of * quoted filenames this is no good. * * Input: * szExpStr - the target name with macros expanded * * Output: * Returns pointer to next Component; NULL means no more components left. * * Errors/Warnings: * * Assumes: * That that two quoted strings are seperated by whitespace. * * Modifies Globals: * * Uses Globals: * * Notes: * *******************************************************************************/ char * NEAR nextComponent(szExpStr) char **szExpStr; { char *t, *next; t = *szExpStr; while (WHITESPACE(*t)) t++; next = t; if (!*t) return(NULL); if (*t == '"') for (; *++t && *t != '"';) ; else for (; *t && *t != ' ' && *t != '\t'; t++) ; if (WHITESPACE(*t)) *t = '\0'; else if (*t == '"') { //Assume that quoted string is followed by Whitespace t++; *t = '\0'; } //If at end of string then backup a byte so that next time we don't go past else if (!*t) t--; *szExpStr = t+1; return(next); } void NEAR assignDependents() /* append dependents */ { /* to existing ones */ /* (if any) */ char *which = NULL; if (ON(actionFlags, A_DEPENDENT)) CLEAR(actionFlags, A_DEPENDENT); if (ON(actionFlags, A_RULE)) { if (list) makeError(currentLine, DEPENDENTS_ON_RULE); } else if (ON(actionFlags, A_SILENT) || ON(actionFlags, A_IGNORE)) { if (list) { if (ON(actionFlags, A_SILENT)) which = silent; else if (ON(actionFlags, A_IGNORE)) which = ignore; makeError(currentLine, DEPS_ON_PSEUDO, which); } } else if (ON(actionFlags, A_SUFFIX)) { if (!list) clearSuffixes(); else appendPseudoTargetList(&dotSuffixList, list); } else if (ON(actionFlags, A_PRECIOUS)) { if (list) appendPseudoTargetList(&dotPreciousList, list); } else { block = makeNewBuildBlock(); block->dependents = list; block->dependentMacros = macros; } list = NULL; macros = NULL; SET(actionFlags, A_STRING); /* expecting build cmd*/ } void NEAR assignBuildCommands() { BOOL okToFreeList = TRUE; BOOL fFirstTarg = (BOOL)TRUE; STRINGLIST *p; char *which = NULL; if (ON(actionFlags, A_RULE)) /* no macros found yet for*/ rules->buildCommands = list; /* inference rules */ else if (ON(actionFlags, A_SILENT) || ON(actionFlags, A_IGNORE) || ON(actionFlags, A_PRECIOUS) || ON(actionFlags, A_SUFFIX)) { if (list) { if (ON(actionFlags, A_SILENT)) which = silent; else if (ON(actionFlags, A_IGNORE)) which = ignore; else if (ON(actionFlags, A_PRECIOUS)) which = precious; else if (ON(actionFlags, A_SUFFIX)) which = suffixes; makeError(currentLine, CMDS_ON_PSEUDO, which); } } else { block->buildCommands = list; block->buildMacros = macros; block->flags = currentFlags; while (p = targetList) { /* make a struct for each targ*/ if (doSpecial(p->text)) /* in list, freeing list when */ makeError(currentLine, MIXED_TARGETS); makeTarget(p->text, fFirstTarg, &block); /* done, don't free name */ if (!makeTargets) { /* field -- it's still in use*/ makeTargets = p; /* if no targs given on cmdlin*/ okToFreeList = FALSE; /* put first target(s) from */ } /* mkfile in makeTargets list*/ targetList = p->next; /* (makeTargets defined in */ if (okToFreeList) /* nmake.c) */ FREE_STRINGLIST(p); if (fFirstTarg) fFirstTarg = (BOOL)FALSE; } } targetList = NULL; list = NULL; macros = NULL; block = NULL; actionFlags = 0; } /* makeMacro -- define macro with name and string taken from global variables * * Modifies: * fInheritUserEnv set to TRUE * * Notes: * Calls putMacro() to place expanded Macros in the NMAKE table. By setting * fInheritUserEnv those definitions that change Environment variables are * inherited by the environment. */ void NEAR makeMacro() { STRINGLIST *q; char *t; if (_ftcschr(name, '$')) { /* expand name */ q = macros; t = expandMacros(name, ¯os); /* name holds result */ if (!*t) /* if macro to left of*/ makeError(currentLine, SYNTAX_NO_MACRO_NAME);/* = undefined, error*/ while (macros = q) { q = q->next; FREE_STRINGLIST(macros); } FREE(name); name = t; } for (t = name; *t && MACRO_CHAR(*t); ++t); /* Check for illegal */ if (*t) makeError(currentLine, SYNTAX_BAD_CHAR, *t);/* chars. */ fInheritUserEnv = (BOOL)TRUE; /* Put Env Var in Env & macros in table. */ if (!putMacro(name, string, 0)) { FREE(name); FREE(string); } name = string = NULL; } /* defineMacro -- check macro's syntax for illegal chars., then define it * * actions: check all of macro's characters * if one's bad and it's an environment macro, bag it * else flag error * call putMacro to do the real work * * can't use macro invocation to left of = in macro def from commandline * it doesn't make sense to do that, because we're not in a makefile * the only way to get a comment char into the makefile w/o having it really * mark a comment is to define a macro A=# on the command line */ BOOL NEAR defineMacro(s, t, flags) /* commandline or env */ char *s; /* definitions */ char *t; UCHAR flags; { char *u; for (u = s; *u && MACRO_CHAR(*u); ++u); /* check for illegal */ if (*u) { if (ON(flags, M_ENVIRONMENT_DEF)) { /* ignore bad macros */ return(FALSE); } makeError(currentLine, SYNTAX_BAD_CHAR, *u); /* chars, bad syntax */ } return(putMacro(s, t, flags)); /* put macro in table */ } /*** putMacro - Put the macro definition into the Macro Table / Environmnet **** * * Scope: * Global. * * Purpose: * putMacro() inserts a macro definition into NMAKE's macro table and also into * the environment. If a macro name is also an environment variable than its * value is inherited into the environment. While replacing older values by new * values NMAKE needs to follow the precedence of macro definitions which is * as per the notes below. * * Input: * name - Name of the macro * value - Value of the macro * flags - Flags determining Precedence of Macro definitions (see Notes) * * Output: * * Errors/Warnings: * OUT_OF_ENV_SPACE - If putenv() returns failure in adding to the environment. * * Assumes: * Whatever it assumes * * Modifies Globals: * fInheritUserEnv - Set to False. * * Uses Globals: * fInheritUserEnv - If True then Inherit definition to the Environment. * gFlags - Global Options Flag. If -e specified then Environment Vars * take precedence. * macroTable - NMAKE's internal table of Macro Definitions. * * Notes: * 1> If the same macro is defined in more than one place then NMAKE uses the * following order of Precedence (highest to lowest) -- * * -1- Command line definitions * -2- Description file/Include file definitions * -3- Environment definitions * -4- TOOLS.INI definitions * -5- Predefined Values (e.g. for CC, AS, BC, RC) * If -e option is specified then -3- precedes -2-. * * 2> Check if the macro already exists in the Macro Table. If the macro is not * redefinable (use order of precedence) then return. Make a new string * element to hold macro's new value. If the macro does not exist then create * new entry in the Macro table. Set Macro's flag to be union of Old and new * values. Add the new value to macro's value entry. If a new macro then add * it to the macro table. Test for Cyclic definitions. * * Undone/Incomplete: * 1> Investigate into possibility of removing fInheritUserEnv variable. * Can be done. Use CANT_REDEFINE(p) || OFF((A)->flags,M_ENVIRONMENT_DEF) * 2> Probably should warn when $(MAKE) is being changed. * *******************************************************************************/ BOOL NEAR putMacro(name, value, flags) char *name; char *value; UCHAR flags; { MACRODEF *p; STRINGLIST *q; BOOL defined = FALSE; BOOL fSyntax = TRUE; /* * Inherit macro definitions. Call removeMacros() to expand sub-macro * definitions. Must be done before macro is put in table, else * recursive definitions won't work. */ if (ON(flags, M_NON_RESETTABLE)) { if (*value) if ((putEnvStr(name,removeMacros(value)) == -1)) makeError(currentLine, OUT_OF_ENV_SPACE); } else if (fInheritUserEnv && OFF(gFlags, F1_USE_ENVIRON_VARS) && getenv(name)) { if (p = findMacro(name)) { /* don't let user */ if (CANT_REDEFINE(p)) /* redefine cmdline */ return(FALSE); /* macros, MAKE, etc.*/ } if ((putEnvStr(name,removeMacros(value)) == -1)) makeError(currentLine, OUT_OF_ENV_SPACE); } fInheritUserEnv = (BOOL)FALSE; if (p = findMacro(name)) { /* don't let user */ if (CANT_REDEFINE(p)) /* redefine cmdline */ return(FALSE); /* macros, MAKE, etc.*/ } q = makeNewStrListElement(); q->text = value; if (!p) { p = makeNewMacro(); p->name = name; assert(p->flags == 0); assert(p->values == NULL); } else defined = TRUE; p->flags &= ~M_UNDEFINED; /* Is no longer undefined */ p->flags |= flags; /* Set flags to union of old and new */ prependItem((STRINGLIST**)&(p->values), (STRINGLIST*)q); if (!defined) insertMacro((STRINGLIST*)p); if (_ftcschr(value, '$')) { /* Check for cyclic Macro Definitions */ SET(p->flags, M_EXPANDING_THIS_ONE); /* NULL -> don't build list */ fSyntax = findMacroValues(value, NULL, NULL, name, 1, 0, flags); CLEAR(p->flags, M_EXPANDING_THIS_ONE); } if (!fSyntax) { p->values = NULL; p->flags &= M_UNDEFINED; return(FALSE); } return(TRUE); } /*** makeRule -- makes an inference rule *************************************** * * Scope: * Local * * Purpose: * Allocates space for an inference rule and adds rule to the beginning of the * doubly linked inference rule list. The name of the rule is also added. * * Input: * rule -- The name of the inference rule * * Output: * * Errors/Warnings: * * Assumes: * * Modifies Globals: * rules -- The doubly linked inference rule list to which the rule is added * * Uses Globals: * * Notes: * The syntax of an inference rule is -- * * {frompath}.fromext{topath}.toext: # Name of the inference rule * command ... # command block of the inference rule * *******************************************************************************/ LOCAL void NEAR makeRule(rule) STRINGLIST *rule; { RULELIST *rList; rList = makeNewRule(); rList->name = rule->text; prependItem((STRINGLIST**)&rules, (STRINGLIST*)rList); if (rList->next) rList->next->back = rList; } /* * makeTarget -- add target to targetTable * * actions: if no block defined, create one and initialize it * make new build list entry for this target * if the target's already in the table, * flag error if : and :: mixed * else add new buildlist object to target's current buildlist * else allocate new object, initialize it, and stick it in table */ /*** makeTarget -- make a target entry in the targetTable ********************** * * Scope: * Local. * * Purpose: * what it does and how * * Input: * param -- what for, etc * * Output: * Returns ... * * Errors/Warnings: * error/warning -- what and why * * Assumes: * Whatever it assumes * * Modifies Globals: * global -- how/what * * Uses Globals: * global used and why * * Notes: * explanations/comments etc * *******************************************************************************/ LOCAL void NEAR makeTarget(s, firstTarg, block) char *s; BOOL firstTarg; BUILDBLOCK **block; { BUILDLIST *build; MAKEOBJECT *object; if (!*block) *block = makeNewBuildBlock(); if (firstTarg) { build = makeNewBldListElement(); build->buildBlock = *block; } else build = makeBuildList(*block); if (object = findTarget(s)) { if (ON(object->flags2, F2_DOUBLECOLON) != ON(currentFlags, F2_DOUBLECOLON)) makeError(currentLine, MIXED_SEPARATORS); appendItem((STRINGLIST**)&(object->buildList), (STRINGLIST*)build); FREE(s); } else { build->next = NULL; object = makeNewObject(); object->name = s; object->buildList = build; object->flags2 = currentFlags; prependItem((STRINGLIST**)targetTable +hash(s, MAXTARGET, (BOOL)TRUE), (STRINGLIST*)object); } } LOCAL void NEAR clearSuffixes() { STRINGLIST *p; while (p = dotSuffixList) { dotSuffixList = dotSuffixList->next; FREE(p->text); FREE_STRINGLIST(p); } } LOCAL void NEAR appendPseudoTargetList(pseudo, list) STRINGLIST **pseudo; STRINGLIST *list; { STRINGLIST *p, *q, *r; char *t, *u; while (p = list) { if (!_ftcschr(p->text, '$')) { list = list->next; p->next = NULL; appendItem(pseudo, p); } else { r = macros; t = expandMacros(p->text, ¯os); while (r != macros) { q = r->next; FREE_STRINGLIST(r); r = q; } for (u = _ftcstok(t, " \t"); u; u = _ftcstok(NULL, " \t")) { q = makeNewStrListElement(); q->text = makeString(u); appendItem(pseudo, q); } FREE(t); FREE(p->text); list = list->next; FREE_STRINGLIST(p); } } } /*** putEnvStr -- Extends putenv() standard function * * Purpose: * Library function putenv() expects one string argument of the form * "NAME=value" * Most of the times when putenv() is to be used we have two strings * name -- of the variable to add to the environment, and * value -- to be set * putEnvStr takes these 2 parameters and calls putenv with the reqd * format * * Input: * name -- of var to add to the env * value -- reqd to be set * * Output: * Same as putenv() * *******************************************************/ int NEAR putEnvStr(name, value) char *name; char *value; { char *envPtr; envPtr = (char *)rallocate(_ftcslen(name)+1+_ftcslen(value)+1); /* ^ ^ * for '=' for '\0' */ return(PutEnv(_ftcscat(_ftcscat(_ftcscpy(envPtr, name), "="), value))); } /*** makeBuildList -- takes a build block and copies into a buildlist ****** * * Purpose: * Routine creates a copy of a buildlist and returns a pointer to a copy. * When multiple targets have the same description block then there is a * need for each of them to get seperate build blocks. makeBuildList() * helps achieve this by creating a copy for each target. * * Input: * bBlock -- the build block whose copy is to be added to a build block * * Output: * Returns a pointer to the copy of buildlist it creates * ***************************************************************************/ BUILDLIST * NEAR makeBuildList(bBlock) BUILDBLOCK *bBlock; { BUILDLIST *tList = makeNewBldListElement(); BUILDBLOCK *tBlock = makeNewBuildBlock(); tBlock->dependents = bBlock->dependents; tBlock->dependentMacros = bBlock->dependentMacros; tBlock->buildCommands = bBlock->buildCommands; tBlock->buildMacros = bBlock->buildMacros; tBlock->flags = bBlock->flags; tBlock->dateTime = bBlock->dateTime; tList->buildBlock = tBlock; return(tList); } /*** makeList -- creates a copy of a stringlist and returns a copy ********* * * Purpose: * Routine creates a copy of a stringlist and returns a pointer to a copy. * * Input: * list -- the list whose copy is to be made * * Output: * Returns a pointer to the copy of the list it creates * ***************************************************************************/ STRINGLIST * NEAR makeList(list) STRINGLIST *list; { STRINGLIST *t = list, *pList, *qList = NULL, *tList = NULL; for ( ; t; t = t->next) { pList = makeNewStrListElement(); pList->text = makeString(t->text); if (qList == NULL) { qList = tList = pList; } else { qList->next = pList; qList = pList; } } return(tList); }