Module Name: src Committed By: rillig Date: Sat Dec 5 19:46:04 UTC 2020
Modified Files: src/usr.bin/make: parse.c Log Message: make(1): indent parse.c with tabs instead of spaces To generate a diff of this commit: cvs rdiff -u -r1.468 -r1.469 src/usr.bin/make/parse.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/make/parse.c diff -u src/usr.bin/make/parse.c:1.468 src/usr.bin/make/parse.c:1.469 --- src/usr.bin/make/parse.c:1.468 Sat Dec 5 19:06:51 2020 +++ src/usr.bin/make/parse.c Sat Dec 5 19:46:04 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.468 2020/12/05 19:06:51 rillig Exp $ */ +/* $NetBSD: parse.c,v 1.469 2020/12/05 19:46:04 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -117,7 +117,7 @@ #include "pathnames.h" /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: parse.c,v 1.468 2020/12/05 19:06:51 rillig Exp $"); +MAKE_RCSID("$NetBSD: parse.c,v 1.469 2020/12/05 19:46:04 rillig Exp $"); /* types and constants */ @@ -125,62 +125,62 @@ MAKE_RCSID("$NetBSD: parse.c,v 1.468 202 * Structure for a file being read ("included file") */ typedef struct IFile { - char *fname; /* name of file (relative? absolute?) */ - Boolean fromForLoop; /* simulated .include by the .for loop */ - int lineno; /* current line number in file */ - int first_lineno; /* line number of start of text */ - unsigned int cond_depth; /* 'if' nesting when file opened */ - Boolean depending; /* state of doing_depend on EOF */ - - /* The buffer from which the file's content is read. */ - char *buf_freeIt; - char *buf_ptr; /* next char to be read */ - char *buf_end; - - char *(*nextbuf)(void *, size_t *); /* Function to get more data */ - void *nextbuf_arg; /* Opaque arg for nextbuf() */ - struct loadedfile *lf; /* loadedfile object, if any */ + char *fname; /* name of file (relative? absolute?) */ + Boolean fromForLoop; /* simulated .include by the .for loop */ + int lineno; /* current line number in file */ + int first_lineno; /* line number of start of text */ + unsigned int cond_depth; /* 'if' nesting when file opened */ + Boolean depending; /* state of doing_depend on EOF */ + + /* The buffer from which the file's content is read. */ + char *buf_freeIt; + char *buf_ptr; /* next char to be read */ + char *buf_end; + + char *(*nextbuf)(void *, size_t *); /* Function to get more data */ + void *nextbuf_arg; /* Opaque arg for nextbuf() */ + struct loadedfile *lf; /* loadedfile object, if any */ } IFile; /* * Tokens for target attributes */ typedef enum ParseSpecial { - SP_ATTRIBUTE, /* Generic attribute */ - SP_BEGIN, /* .BEGIN */ - SP_DEFAULT, /* .DEFAULT */ - SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ - SP_END, /* .END */ - SP_ERROR, /* .ERROR */ - SP_IGNORE, /* .IGNORE */ - SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ - SP_INTERRUPT, /* .INTERRUPT */ - SP_LIBS, /* .LIBS; not mentioned in the manual page */ - SP_MAIN, /* .MAIN and we don't have anything user-specified to - * make */ - SP_META, /* .META */ - SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ - SP_NOMETA, /* .NOMETA */ - SP_NOMETA_CMP, /* .NOMETA_CMP */ - SP_NOPATH, /* .NOPATH */ - SP_NOT, /* Not special */ - SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ - SP_NULL, /* .NULL; not mentioned in the manual page */ - SP_OBJDIR, /* .OBJDIR */ - SP_ORDER, /* .ORDER */ - SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ - SP_PATH, /* .PATH or .PATH.suffix */ - SP_PHONY, /* .PHONY */ + SP_ATTRIBUTE, /* Generic attribute */ + SP_BEGIN, /* .BEGIN */ + SP_DEFAULT, /* .DEFAULT */ + SP_DELETE_ON_ERROR, /* .DELETE_ON_ERROR */ + SP_END, /* .END */ + SP_ERROR, /* .ERROR */ + SP_IGNORE, /* .IGNORE */ + SP_INCLUDES, /* .INCLUDES; not mentioned in the manual page */ + SP_INTERRUPT, /* .INTERRUPT */ + SP_LIBS, /* .LIBS; not mentioned in the manual page */ + /* .MAIN and we don't have anything user-specified to make */ + SP_MAIN, + SP_META, /* .META */ + SP_MFLAGS, /* .MFLAGS or .MAKEFLAGS */ + SP_NOMETA, /* .NOMETA */ + SP_NOMETA_CMP, /* .NOMETA_CMP */ + SP_NOPATH, /* .NOPATH */ + SP_NOT, /* Not special */ + SP_NOTPARALLEL, /* .NOTPARALLEL or .NO_PARALLEL */ + SP_NULL, /* .NULL; not mentioned in the manual page */ + SP_OBJDIR, /* .OBJDIR */ + SP_ORDER, /* .ORDER */ + SP_PARALLEL, /* .PARALLEL; not mentioned in the manual page */ + SP_PATH, /* .PATH or .PATH.suffix */ + SP_PHONY, /* .PHONY */ #ifdef POSIX - SP_POSIX, /* .POSIX; not mentioned in the manual page */ + SP_POSIX, /* .POSIX; not mentioned in the manual page */ #endif - SP_PRECIOUS, /* .PRECIOUS */ - SP_SHELL, /* .SHELL */ - SP_SILENT, /* .SILENT */ - SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ - SP_STALE, /* .STALE */ - SP_SUFFIXES, /* .SUFFIXES */ - SP_WAIT /* .WAIT */ + SP_PRECIOUS, /* .PRECIOUS */ + SP_SHELL, /* .SHELL */ + SP_SILENT, /* .SILENT */ + SP_SINGLESHELL, /* .SINGLESHELL; not mentioned in the manual page */ + SP_STALE, /* .STALE */ + SP_SUFFIXES, /* .SUFFIXES */ + SP_WAIT /* .WAIT */ } ParseSpecial; typedef List SearchPathList; @@ -270,14 +270,14 @@ static Vector /* of IFile */ includes; static IFile * GetInclude(size_t i) { - return Vector_Get(&includes, i); + return Vector_Get(&includes, i); } /* The file that is currently being read. */ static IFile * CurFile(void) { - return GetInclude(includes.len - 1); + return GetInclude(includes.len - 1); } /* include paths */ @@ -295,9 +295,9 @@ SearchPath *defSysIncPath; /* default fo * keyword is used as a source ("0" if the keyword isn't special as a source) */ static const struct { - const char *name; /* Name of keyword */ - ParseSpecial spec; /* Type when used as a target */ - GNodeType op; /* Operator when used as a source */ + const char *name; /* Name of keyword */ + ParseSpecial spec; /* Type when used as a target */ + GNodeType op; /* Operator when used as a source */ } parseKeywords[] = { { ".BEGIN", SP_BEGIN, OP_NONE }, { ".DEFAULT", SP_DEFAULT, OP_NONE }, @@ -349,11 +349,11 @@ static const struct { struct loadedfile { /* XXX: What is the lifetime of this path? Who manages the memory? */ - const char *path; /* name, for error reports */ - char *buf; /* contents buffer */ - size_t len; /* length of contents */ - size_t maplen; /* length of mmap area, or 0 */ - Boolean used; /* XXX: have we used the data yet */ + const char *path; /* name, for error reports */ + char *buf; /* contents buffer */ + size_t len; /* length of contents */ + size_t maplen; /* length of mmap area, or 0 */ + Boolean used; /* XXX: have we used the data yet */ }; /* XXX: What is the lifetime of the path? Who manages the memory? */ @@ -459,8 +459,8 @@ loadedfile_mmap(struct loadedfile *lf, i * FUTURE: remove PROT_WRITE when the parser no longer * needs to scribble on the input. */ - lf->buf = mmap(NULL, lf->maplen, PROT_READ|PROT_WRITE, - MAP_FILE|MAP_COPY, fd, 0); + lf->buf = mmap(NULL, lf->maplen, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_COPY, fd, 0); if (lf->buf == MAP_FAILED) return FALSE; @@ -521,7 +521,7 @@ loadfile(const char *path, int fd) for (;;) { assert(bufpos <= lf->len); if (bufpos == lf->len) { - if (lf->len > SIZE_MAX/2) { + if (lf->len > SIZE_MAX / 2) { errno = EFBIG; Error("%s: file too large", path); exit(1); @@ -565,14 +565,14 @@ done: static Boolean ParseIsEscaped(const char *line, const char *c) { - Boolean active = FALSE; - for (;;) { - if (line == c) - return active; - if (*--c != '\\') - return active; - active = !active; - } + Boolean active = FALSE; + for (;;) { + if (line == c) + return active; + if (*--c != '\\') + return active; + active = !active; + } } /* Add the filename and lineno to the GNode so that we remember where it @@ -580,9 +580,9 @@ ParseIsEscaped(const char *line, const c static void ParseMark(GNode *gn) { - IFile *curFile = CurFile(); - gn->fname = curFile->fname; - gn->lineno = curFile->lineno; + IFile *curFile = CurFile(); + gn->fname = curFile->fname; + gn->lineno = curFile->lineno; } /* Look in the table of keywords for one matching the given string. @@ -590,28 +590,28 @@ ParseMark(GNode *gn) static int ParseFindKeyword(const char *str) { - int start = 0; - int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; + int start = 0; + int end = sizeof parseKeywords / sizeof parseKeywords[0] - 1; - do { - int curr = start + (end - start) / 2; - int diff = strcmp(str, parseKeywords[curr].name); - - if (diff == 0) - return curr; - if (diff < 0) - end = curr - 1; - else - start = curr + 1; - } while (start <= end); + do { + int curr = start + (end - start) / 2; + int diff = strcmp(str, parseKeywords[curr].name); + + if (diff == 0) + return curr; + if (diff < 0) + end = curr - 1; + else + start = curr + 1; + } while (start <= end); - return -1; + return -1; } static void PrintLocation(FILE *f, const char *fname, size_t lineno) { - char dirbuf[MAXPATHLEN+1]; + char dirbuf[MAXPATHLEN + 1]; const char *dir, *base; void *dir_freeIt, *base_freeIt; @@ -680,7 +680,7 @@ ParseErrorInternal(const char *fname, si if (opts.debug_file != stderr && opts.debug_file != stdout) { va_start(ap, fmt); ParseVErrorInternal(opts.debug_file, fname, lineno, type, - fmt, ap); + fmt, ap); va_end(ap); } } @@ -715,7 +715,7 @@ Parse_Error(ParseErrorLevel type, const if (opts.debug_file != stderr && opts.debug_file != stdout) { va_start(ap, fmt); ParseVErrorInternal(opts.debug_file, fname, lineno, type, - fmt, ap); + fmt, ap); va_end(ap); } } @@ -726,28 +726,28 @@ Parse_Error(ParseErrorLevel type, const static Boolean ParseMessage(const char *directive) { - const char *p = directive; - ParseErrorLevel mtype = *p == 'i' ? PARSE_INFO : - *p == 'w' ? PARSE_WARNING : PARSE_FATAL; - char *arg; - - while (ch_isalpha(*p)) - p++; - if (!ch_isspace(*p)) - return FALSE; /* missing argument */ - - cpp_skip_whitespace(&p); - (void)Var_Subst(p, VAR_CMDLINE, VARE_WANTRES, &arg); - /* TODO: handle errors */ - - Parse_Error(mtype, "%s", arg); - free(arg); - - if (mtype == PARSE_FATAL) { - PrintOnError(NULL, NULL); - exit(1); - } - return TRUE; + const char *p = directive; + ParseErrorLevel mtype = *p == 'i' ? PARSE_INFO : + *p == 'w' ? PARSE_WARNING : PARSE_FATAL; + char *arg; + + while (ch_isalpha(*p)) + p++; + if (!ch_isspace(*p)) + return FALSE; /* missing argument */ + + cpp_skip_whitespace(&p); + (void)Var_Subst(p, VAR_CMDLINE, VARE_WANTRES, &arg); + /* TODO: handle errors */ + + Parse_Error(mtype, "%s", arg); + free(arg); + + if (mtype == PARSE_FATAL) { + PrintOnError(NULL, NULL); + exit(1); + } + return TRUE; } /* Add the child to the parent's children. @@ -758,101 +758,106 @@ ParseMessage(const char *directive) static void LinkSource(GNode *pgn, GNode *cgn, Boolean isSpecial) { - if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) - pgn = pgn->cohorts.last->datum; + if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&pgn->cohorts)) + pgn = pgn->cohorts.last->datum; - Lst_Append(&pgn->children, cgn); - pgn->unmade++; + Lst_Append(&pgn->children, cgn); + pgn->unmade++; - /* Special targets like .END don't need any children. */ - if (!isSpecial) - Lst_Append(&cgn->parents, pgn); - - if (DEBUG(PARSE)) { - debug_printf("# %s: added child %s - %s\n", - __func__, pgn->name, cgn->name); - Targ_PrintNode(pgn, 0); - Targ_PrintNode(cgn, 0); - } + /* Special targets like .END don't need any children. */ + if (!isSpecial) + Lst_Append(&cgn->parents, pgn); + + if (DEBUG(PARSE)) { + debug_printf("# %s: added child %s - %s\n", + __func__, pgn->name, cgn->name); + Targ_PrintNode(pgn, 0); + Targ_PrintNode(cgn, 0); + } } /* Add the node to each target from the current dependency group. */ static void LinkToTargets(GNode *gn, Boolean isSpecial) { - GNodeListNode *ln; - for (ln = targets->first; ln != NULL; ln = ln->next) - LinkSource(ln->datum, gn, isSpecial); + GNodeListNode *ln; + + for (ln = targets->first; ln != NULL; ln = ln->next) + LinkSource(ln->datum, gn, isSpecial); } static Boolean TryApplyDependencyOperator(GNode *gn, GNodeType op) { - /* - * If the node occurred on the left-hand side of a dependency and the - * operator also defines a dependency, they must match. - */ - if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && - ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) - { - Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name); - return FALSE; - } - - if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { /* - * If the node was of the left-hand side of a '::' operator, we need - * to create a new instance of it for the children and commands on - * this dependency line since each of these dependency groups has its - * own attributes and commands, separate from the others. - * - * The new instance is placed on the 'cohorts' list of the - * initial one (note the initial one is not on its own cohorts list) - * and the new instance is linked to all parents of the initial - * instance. + * If the node occurred on the left-hand side of a dependency and the + * operator also defines a dependency, they must match. */ - GNode *cohort; + if ((op & OP_OPMASK) && (gn->type & OP_OPMASK) && + ((op & OP_OPMASK) != (gn->type & OP_OPMASK))) { + Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", + gn->name); + return FALSE; + } - /* - * Propagate copied bits to the initial node. They'll be propagated - * back to the rest of the cohorts later. - */ - gn->type |= op & ~OP_OPMASK; + if (op == OP_DOUBLEDEP && (gn->type & OP_OPMASK) == OP_DOUBLEDEP) { + /* + * If the node was of the left-hand side of a '::' operator, + * we need to create a new instance of it for the children + * and commands on this dependency line since each of these + * dependency groups has its own attributes and commands, + * separate from the others. + * + * The new instance is placed on the 'cohorts' list of the + * initial one (note the initial one is not on its own + * cohorts list) and the new instance is linked to all + * parents of the initial instance. + */ + GNode *cohort; - cohort = Targ_NewInternalNode(gn->name); - if (doing_depend) - ParseMark(cohort); - /* - * Make the cohort invisible as well to avoid duplicating it into - * other variables. True, parents of this target won't tend to do - * anything with their local variables, but better safe than - * sorry. (I think this is pointless now, since the relevant list - * traversals will no longer see this node anyway. -mycroft) - */ - cohort->type = op | OP_INVISIBLE; - Lst_Append(&gn->cohorts, cohort); - cohort->centurion = gn; - gn->unmade_cohorts++; - snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", - (unsigned int)gn->unmade_cohorts % 1000000); - } else { - /* - * We don't want to nuke any previous flags (whatever they were) so we - * just OR the new operator into the old. - */ - gn->type |= op; - } + /* + * Propagate copied bits to the initial node. They'll be + * propagated back to the rest of the cohorts later. + */ + gn->type |= op & ~OP_OPMASK; + + cohort = Targ_NewInternalNode(gn->name); + if (doing_depend) + ParseMark(cohort); + /* + * Make the cohort invisible as well to avoid duplicating it + * into other variables. True, parents of this target won't + * tend to do anything with their local variables, but better + * safe than sorry. + * + * (I think this is pointless now, since the relevant list + * traversals will no longer see this node anyway. -mycroft) + */ + cohort->type = op | OP_INVISIBLE; + Lst_Append(&gn->cohorts, cohort); + cohort->centurion = gn; + gn->unmade_cohorts++; + snprintf(cohort->cohort_num, sizeof cohort->cohort_num, "#%d", + (unsigned int)gn->unmade_cohorts % 1000000); + } else { + /* + * We don't want to nuke any previous flags (whatever they + * were) so we just OR the new operator into the old. + */ + gn->type |= op; + } - return TRUE; + return TRUE; } static void ApplyDependencyOperator(GNodeType op) { - GNodeListNode *ln; - for (ln = targets->first; ln != NULL; ln = ln->next) - if (!TryApplyDependencyOperator(ln->datum, op)) - break; + GNodeListNode *ln; + + for (ln = targets->first; ln != NULL; ln = ln->next) + if (!TryApplyDependencyOperator(ln->datum, op)) + break; } /* @@ -907,80 +912,81 @@ ParseDependencySourceKeyword(const char static void ParseDependencySourceMain(const char *src) { - /* - * In a line like ".MAIN: source1 source2", it means we need to add - * the sources of said target to the list of things to create. - * - * Note that this will only be invoked if the user didn't specify a - * target on the command line and the .MAIN occurs for the first time. - * - * See ParseDoDependencyTargetSpecial, branch SP_MAIN. - * See unit-tests/cond-func-make-main.mk. - */ - Lst_Append(&opts.create, bmake_strdup(src)); - /* - * Add the name to the .TARGETS variable as well, so the user can - * employ that, if desired. - */ - Var_Append(".TARGETS", src, VAR_GLOBAL); + /* + * In a line like ".MAIN: source1 source2", it means we need to add + * the sources of said target to the list of things to create. + * + * Note that this will only be invoked if the user didn't specify a + * target on the command line and the .MAIN occurs for the first time. + * + * See ParseDoDependencyTargetSpecial, branch SP_MAIN. + * See unit-tests/cond-func-make-main.mk. + */ + Lst_Append(&opts.create, bmake_strdup(src)); + /* + * Add the name to the .TARGETS variable as well, so the user can + * employ that, if desired. + */ + Var_Append(".TARGETS", src, VAR_GLOBAL); } static void ParseDependencySourceOrder(const char *src) { - GNode *gn; - /* - * Create proper predecessor/successor links between the previous - * source and the current one. - */ - gn = Targ_GetNode(src); - if (doing_depend) - ParseMark(gn); - if (order_pred != NULL) { - Lst_Append(&order_pred->order_succ, gn); - Lst_Append(&gn->order_pred, order_pred); - if (DEBUG(PARSE)) { - debug_printf("# %s: added Order dependency %s - %s\n", - __func__, order_pred->name, gn->name); - Targ_PrintNode(order_pred, 0); - Targ_PrintNode(gn, 0); - } - } - /* - * The current source now becomes the predecessor for the next one. - */ - order_pred = gn; + GNode *gn; + /* + * Create proper predecessor/successor links between the previous + * source and the current one. + */ + gn = Targ_GetNode(src); + if (doing_depend) + ParseMark(gn); + if (order_pred != NULL) { + Lst_Append(&order_pred->order_succ, gn); + Lst_Append(&gn->order_pred, order_pred); + if (DEBUG(PARSE)) { + debug_printf("# %s: added Order dependency %s - %s\n", + __func__, order_pred->name, gn->name); + Targ_PrintNode(order_pred, 0); + Targ_PrintNode(gn, 0); + } + } + /* + * The current source now becomes the predecessor for the next one. + */ + order_pred = gn; } static void ParseDependencySourceOther(const char *src, GNodeType tOp, ParseSpecial specType) { - GNode *gn; + GNode *gn; + + /* + * If the source is not an attribute, we need to find/create + * a node for it. After that we can apply any operator to it + * from a special target or link it to its parents, as + * appropriate. + * + * In the case of a source that was the object of a :: operator, + * the attribute is applied to all of its instances (as kept in + * the 'cohorts' list of the node) or all the cohorts are linked + * to all the targets. + */ - /* - * If the source is not an attribute, we need to find/create - * a node for it. After that we can apply any operator to it - * from a special target or link it to its parents, as - * appropriate. - * - * In the case of a source that was the object of a :: operator, - * the attribute is applied to all of its instances (as kept in - * the 'cohorts' list of the node) or all the cohorts are linked - * to all the targets. - */ - - /* Find/create the 'src' node and attach to all targets */ - gn = Targ_GetNode(src); - if (doing_depend) - ParseMark(gn); - if (tOp != OP_NONE) - gn->type |= tOp; - else - LinkToTargets(gn, specType != SP_NOT); + /* Find/create the 'src' node and attach to all targets */ + gn = Targ_GetNode(src); + if (doing_depend) + ParseMark(gn); + if (tOp != OP_NONE) + gn->type |= tOp; + else + LinkToTargets(gn, specType != SP_NOT); } -/* Given the name of a source in a dependency line, figure out if it is an +/* + * Given the name of a source in a dependency line, figure out if it is an * attribute (such as .SILENT) and apply it to the targets if it is. Else * decide if there is some attribute which should be applied *to* the source * because of some special target (such as .PHONY) and apply it if so. @@ -993,37 +999,39 @@ ParseDependencySourceOther(const char *s static void ParseDependencySource(GNodeType tOp, const char *src, ParseSpecial specType) { - if (ParseDependencySourceKeyword(src, specType)) - return; + if (ParseDependencySourceKeyword(src, specType)) + return; - if (specType == SP_MAIN) - ParseDependencySourceMain(src); - else if (specType == SP_ORDER) - ParseDependencySourceOrder(src); - else - ParseDependencySourceOther(src, tOp, specType); + if (specType == SP_MAIN) + ParseDependencySourceMain(src); + else if (specType == SP_ORDER) + ParseDependencySourceOrder(src); + else + ParseDependencySourceOther(src, tOp, specType); } -/* If we have yet to decide on a main target to make, in the absence of any +/* + * If we have yet to decide on a main target to make, in the absence of any * user input, we want the first target on the first dependency line that is - * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. */ + * actually a real target (i.e. isn't a .USE or .EXEC rule) to be made. + */ static void FindMainTarget(void) { - GNodeListNode *ln; + GNodeListNode *ln; - if (mainNode != NULL) - return; + if (mainNode != NULL) + return; - for (ln = targets->first; ln != NULL; ln = ln->next) { - GNode *gn = ln->datum; - if (!(gn->type & OP_NOTARGET)) { - DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name); - mainNode = gn; - Targ_SetMain(gn); - return; + for (ln = targets->first; ln != NULL; ln = ln->next) { + GNode *gn = ln->datum; + if (!(gn->type & OP_NOTARGET)) { + DEBUG1(MAKE, "Setting main node to \"%s\"\n", gn->name); + mainNode = gn; + Targ_SetMain(gn); + return; + } } - } } /* @@ -1036,56 +1044,60 @@ FindMainTarget(void) static void ParseErrorNoDependency(const char *lstart) { - if ((strncmp(lstart, "<<<<<<", 6) == 0) || - (strncmp(lstart, "======", 6) == 0) || - (strncmp(lstart, ">>>>>>", 6) == 0)) - Parse_Error(PARSE_FATAL, + if ((strncmp(lstart, "<<<<<<", 6) == 0) || + (strncmp(lstart, "======", 6) == 0) || + (strncmp(lstart, ">>>>>>", 6) == 0)) + Parse_Error(PARSE_FATAL, "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts"); - else if (lstart[0] == '.') { - const char *dirstart = lstart + 1; - const char *dirend; - cpp_skip_whitespace(&dirstart); - dirend = dirstart; - while (ch_isalnum(*dirend) || *dirend == '-') - dirend++; - Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", + else if (lstart[0] == '.') { + const char *dirstart = lstart + 1; + const char *dirend; + cpp_skip_whitespace(&dirstart); + dirend = dirstart; + while (ch_isalnum(*dirend) || *dirend == '-') + dirend++; + Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"", (int)(dirend - dirstart), dirstart); - } else - Parse_Error(PARSE_FATAL, "Need an operator"); + } else + Parse_Error(PARSE_FATAL, "Need an operator"); } static void ParseDependencyTargetWord(const char **pp, const char *lstart) { - const char *cp = *pp; + const char *cp = *pp; + + while (*cp != '\0') { + if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || + *cp == '(') && + !ParseIsEscaped(lstart, cp)) + break; - while (*cp != '\0') { - if ((ch_isspace(*cp) || *cp == '!' || *cp == ':' || *cp == '(') && - !ParseIsEscaped(lstart, cp)) - break; - - if (*cp == '$') { - /* - * Must be a dynamic source (would have been expanded - * otherwise), so call the Var module to parse the puppy - * so we can safely advance beyond it...There should be - * no errors in this, as they would have been discovered - * in the initial Var_Subst and we wouldn't be here. - */ - const char *nested_p = cp; - const char *nested_val; - void *freeIt; + if (*cp == '$') { + /* + * Must be a dynamic source (would have been expanded + * otherwise), so call the Var module to parse the + * puppy so we can safely advance beyond it. + * + * There should be no errors in this, as they would + * have been discovered in the initial Var_Subst and + * we wouldn't be here. + */ + const char *nested_p = cp; + const char *nested_val; + void *freeIt; - (void)Var_Parse(&nested_p, VAR_CMDLINE, + /* XXX: Why VARE_WANTRES? */ + (void)Var_Parse(&nested_p, VAR_CMDLINE, VARE_WANTRES | VARE_UNDEFERR, &nested_val, &freeIt); - /* TODO: handle errors */ - free(freeIt); - cp += nested_p - cp; - } else - cp++; - } + /* TODO: handle errors */ + free(freeIt); + cp += nested_p - cp; + } else + cp++; + } - *pp = cp; + *pp = cp; } /* Handle special targets like .PATH, .DEFAULT, .BEGIN, .ORDER. */ @@ -1094,56 +1106,61 @@ ParseDoDependencyTargetSpecial(ParseSpec const char *line, SearchPathList **inout_paths) { - switch (*inout_specType) { - case SP_PATH: - if (*inout_paths == NULL) - *inout_paths = Lst_New(); - Lst_Append(*inout_paths, &dirSearchPath); - break; - case SP_MAIN: - /* Allow targets from the command line to override the .MAIN node. */ - if (!Lst_IsEmpty(&opts.create)) - *inout_specType = SP_NOT; - break; - case SP_BEGIN: - case SP_END: - case SP_STALE: - case SP_ERROR: - case SP_INTERRUPT: { - GNode *gn = Targ_GetNode(line); - if (doing_depend) - ParseMark(gn); - gn->type |= OP_NOTMAIN|OP_SPECIAL; - Lst_Append(targets, gn); - break; - } - case SP_DEFAULT: { - /* Need to create a node to hang commands on, but we don't want it - * in the graph, nor do we want it to be the Main Target. We claim - * the node is a transformation rule to make life easier later, - * when we'll use Make_HandleUse to actually apply the .DEFAULT - * commands. */ - GNode *gn = GNode_New(".DEFAULT"); - gn->type |= OP_NOTMAIN|OP_TRANSFORM; - Lst_Append(targets, gn); - defaultNode = gn; - break; - } - case SP_DELETE_ON_ERROR: - deleteOnError = TRUE; - break; - case SP_NOTPARALLEL: - opts.maxJobs = 1; - break; - case SP_SINGLESHELL: - opts.compatMake = TRUE; - break; - case SP_ORDER: - order_pred = NULL; - break; - default: - break; - } + switch (*inout_specType) { + case SP_PATH: + if (*inout_paths == NULL) + *inout_paths = Lst_New(); + Lst_Append(*inout_paths, &dirSearchPath); + break; + case SP_MAIN: + /* + * Allow targets from the command line to override the + * .MAIN node. + */ + if (!Lst_IsEmpty(&opts.create)) + *inout_specType = SP_NOT; + break; + case SP_BEGIN: + case SP_END: + case SP_STALE: + case SP_ERROR: + case SP_INTERRUPT: { + GNode *gn = Targ_GetNode(line); + if (doing_depend) + ParseMark(gn); + gn->type |= OP_NOTMAIN | OP_SPECIAL; + Lst_Append(targets, gn); + break; + } + case SP_DEFAULT: { + /* + * Need to create a node to hang commands on, but we don't + * want it in the graph, nor do we want it to be the Main + * Target. We claim the node is a transformation rule to make + * life easier later, when we'll use Make_HandleUse to + * actually apply the .DEFAULT commands. + */ + GNode *gn = GNode_New(".DEFAULT"); + gn->type |= OP_NOTMAIN | OP_TRANSFORM; + Lst_Append(targets, gn); + defaultNode = gn; + break; + } + case SP_DELETE_ON_ERROR: + deleteOnError = TRUE; + break; + case SP_NOTPARALLEL: + opts.maxJobs = 1; + break; + case SP_SINGLESHELL: + opts.compatMake = TRUE; + break; + case SP_ORDER: + order_pred = NULL; + break; + default: + break; + } } /* @@ -1153,21 +1170,20 @@ ParseDoDependencyTargetSpecial(ParseSpec static Boolean ParseDoDependencyTargetPath(const char *line, SearchPathList **inout_paths) { - SearchPath *path; + SearchPath *path; - path = Suff_GetPath(&line[5]); - if (path == NULL) { - Parse_Error(PARSE_FATAL, - "Suffix '%s' not defined (yet)", - &line[5]); - return FALSE; - } + path = Suff_GetPath(&line[5]); + if (path == NULL) { + Parse_Error(PARSE_FATAL, + "Suffix '%s' not defined (yet)", &line[5]); + return FALSE; + } - if (*inout_paths == NULL) - *inout_paths = Lst_New(); - Lst_Append(*inout_paths, path); + if (*inout_paths == NULL) + *inout_paths = Lst_New(); + Lst_Append(*inout_paths, path); - return TRUE; + return TRUE; } /* @@ -1177,195 +1193,197 @@ static Boolean ParseDoDependencyTarget(const char *line, ParseSpecial *inout_specType, GNodeType *out_tOp, SearchPathList **inout_paths) { - int keywd; + int keywd; - if (!(*line == '.' && ch_isupper(line[1]))) - return TRUE; + if (!(*line == '.' && ch_isupper(line[1]))) + return TRUE; + + /* + * See if the target is a special target that must have it + * or its sources handled specially. + */ + keywd = ParseFindKeyword(line); + if (keywd != -1) { + if (*inout_specType == SP_PATH && + parseKeywords[keywd].spec != SP_PATH) { + Parse_Error(PARSE_FATAL, "Mismatched special targets"); + return FALSE; + } + + *inout_specType = parseKeywords[keywd].spec; + *out_tOp = parseKeywords[keywd].op; + + ParseDoDependencyTargetSpecial(inout_specType, line, + inout_paths); - /* - * See if the target is a special target that must have it - * or its sources handled specially. - */ - keywd = ParseFindKeyword(line); - if (keywd != -1) { - if (*inout_specType == SP_PATH && parseKeywords[keywd].spec != SP_PATH) { - Parse_Error(PARSE_FATAL, "Mismatched special targets"); - return FALSE; - } - - *inout_specType = parseKeywords[keywd].spec; - *out_tOp = parseKeywords[keywd].op; - - ParseDoDependencyTargetSpecial(inout_specType, line, inout_paths); - - } else if (strncmp(line, ".PATH", 5) == 0) { - *inout_specType = SP_PATH; - if (!ParseDoDependencyTargetPath(line, inout_paths)) - return FALSE; - } - return TRUE; + } else if (strncmp(line, ".PATH", 5) == 0) { + *inout_specType = SP_PATH; + if (!ParseDoDependencyTargetPath(line, inout_paths)) + return FALSE; + } + return TRUE; } static void ParseDoDependencyTargetMundane(char *line, StringList *curTargs) { - if (Dir_HasWildcards(line)) { - /* - * Targets are to be sought only in the current directory, - * so create an empty path for the thing. Note we need to - * use Dir_Destroy in the destruction of the path as the - * Dir module could have added a directory to the path... - */ - SearchPath *emptyPath = SearchPath_New(); + if (Dir_HasWildcards(line)) { + /* + * Targets are to be sought only in the current directory, + * so create an empty path for the thing. Note we need to + * use Dir_Destroy in the destruction of the path as the + * Dir module could have added a directory to the path... + */ + SearchPath *emptyPath = SearchPath_New(); - Dir_Expand(line, emptyPath, curTargs); + Dir_Expand(line, emptyPath, curTargs); - SearchPath_Free(emptyPath); - } else { - /* - * No wildcards, but we want to avoid code duplication, - * so create a list with the word on it. - */ - Lst_Append(curTargs, line); - } + SearchPath_Free(emptyPath); + } else { + /* + * No wildcards, but we want to avoid code duplication, + * so create a list with the word on it. + */ + Lst_Append(curTargs, line); + } - /* Apply the targets. */ + /* Apply the targets. */ - while (!Lst_IsEmpty(curTargs)) { - char *targName = Lst_Dequeue(curTargs); - GNode *gn = Suff_IsTransform(targName) + while (!Lst_IsEmpty(curTargs)) { + char *targName = Lst_Dequeue(curTargs); + GNode *gn = Suff_IsTransform(targName) ? Suff_AddTransform(targName) : Targ_GetNode(targName); - if (doing_depend) - ParseMark(gn); + if (doing_depend) + ParseMark(gn); - Lst_Append(targets, gn); - } + Lst_Append(targets, gn); + } } static void ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) { - Boolean warning = FALSE; - char *cp = *pp; + Boolean warning = FALSE; + char *cp = *pp; - while (*cp != '\0') { - if (!ParseIsEscaped(lstart, cp) && (*cp == '!' || *cp == ':')) - break; - if (ParseIsEscaped(lstart, cp) || (*cp != ' ' && *cp != '\t')) - warning = TRUE; - cp++; - } - if (warning) - Parse_Error(PARSE_WARNING, "Extra target ignored"); + while (*cp != '\0') { + if (!ParseIsEscaped(lstart, cp) && (*cp == '!' || *cp == ':')) + break; + if (ParseIsEscaped(lstart, cp) || (*cp != ' ' && *cp != '\t')) + warning = TRUE; + cp++; + } + if (warning) + Parse_Error(PARSE_WARNING, "Extra target ignored"); - *pp = cp; + *pp = cp; } static void ParseDoDependencyCheckSpec(ParseSpecial specType) { - switch (specType) { - default: - Parse_Error(PARSE_WARNING, + switch (specType) { + default: + Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. " "Mundane ones ignored"); - break; - case SP_DEFAULT: - case SP_STALE: - case SP_BEGIN: - case SP_END: - case SP_ERROR: - case SP_INTERRUPT: - /* - * These create nodes on which to hang commands, so targets - * shouldn't be empty... - */ - case SP_NOT: - /* Nothing special here -- targets can be empty if it wants. */ - break; - } + break; + case SP_DEFAULT: + case SP_STALE: + case SP_BEGIN: + case SP_END: + case SP_ERROR: + case SP_INTERRUPT: + /* + * These create nodes on which to hang commands, so targets + * shouldn't be empty. + */ + case SP_NOT: + /* Nothing special here -- targets can be empty if it wants. */ + break; + } } static Boolean ParseDoDependencyParseOp(char **pp, const char *lstart, GNodeType *out_op) { - const char *cp = *pp; + const char *cp = *pp; - if (*cp == '!') { - *out_op = OP_FORCE; - (*pp)++; - return TRUE; - } + if (*cp == '!') { + *out_op = OP_FORCE; + (*pp)++; + return TRUE; + } - if (*cp == ':') { - if (cp[1] == ':') { - *out_op = OP_DOUBLEDEP; - (*pp) += 2; - } else { - *out_op = OP_DEPENDS; - (*pp)++; + if (*cp == ':') { + if (cp[1] == ':') { + *out_op = OP_DOUBLEDEP; + (*pp) += 2; + } else { + *out_op = OP_DEPENDS; + (*pp)++; + } + return TRUE; } - return TRUE; - } - { - const char *msg = lstart[0] == '.' ? "Unknown directive" - : "Missing dependency operator"; - Parse_Error(PARSE_FATAL, "%s", msg); - return FALSE; - } + { + const char *msg = lstart[0] == '.' + ? "Unknown directive" : "Missing dependency operator"; + Parse_Error(PARSE_FATAL, "%s", msg); + return FALSE; + } } static void ClearPaths(SearchPathList *paths) { - if (paths != NULL) { - SearchPathListNode *ln; - for (ln = paths->first; ln != NULL; ln = ln->next) - SearchPath_Clear(ln->datum); - } + if (paths != NULL) { + SearchPathListNode *ln; + for (ln = paths->first; ln != NULL; ln = ln->next) + SearchPath_Clear(ln->datum); + } - Dir_SetPATH(); + Dir_SetPATH(); } static void ParseDoDependencySourcesEmpty(ParseSpecial specType, SearchPathList *paths) { - switch (specType) { - case SP_SUFFIXES: - Suff_ClearSuffixes(); - break; - case SP_PRECIOUS: - allPrecious = TRUE; - break; - case SP_IGNORE: - opts.ignoreErrors = TRUE; - break; - case SP_SILENT: - opts.beSilent = TRUE; - break; - case SP_PATH: - ClearPaths(paths); - break; + switch (specType) { + case SP_SUFFIXES: + Suff_ClearSuffixes(); + break; + case SP_PRECIOUS: + allPrecious = TRUE; + break; + case SP_IGNORE: + opts.ignoreErrors = TRUE; + break; + case SP_SILENT: + opts.beSilent = TRUE; + break; + case SP_PATH: + ClearPaths(paths); + break; #ifdef POSIX - case SP_POSIX: - Var_Set("%POSIX", "1003.2", VAR_GLOBAL); - break; + case SP_POSIX: + Var_Set("%POSIX", "1003.2", VAR_GLOBAL); + break; #endif - default: - break; - } + default: + break; + } } static void AddToPaths(const char *dir, SearchPathList *paths) { - if (paths != NULL) { - SearchPathListNode *ln; - for (ln = paths->first; ln != NULL; ln = ln->next) - (void)Dir_AddDir(ln->datum, dir); - } + if (paths != NULL) { + SearchPathListNode *ln; + for (ln = paths->first; ln != NULL; ln = ln->next) + (void)Dir_AddDir(ln->datum, dir); + } } /* @@ -1399,28 +1417,28 @@ static void ParseDoDependencySourceSpecial(ParseSpecial specType, char *word, SearchPathList *paths) { - switch (specType) { - case SP_SUFFIXES: - Suff_AddSuffix(word, &mainNode); - break; - case SP_PATH: - AddToPaths(word, paths); - break; - case SP_INCLUDES: - Suff_AddInclude(word); - break; - case SP_LIBS: - Suff_AddLib(word); - break; - case SP_NULL: - Suff_SetNull(word); - break; - case SP_OBJDIR: - Main_SetObjdir(FALSE, "%s", word); - break; - default: - break; - } + switch (specType) { + case SP_SUFFIXES: + Suff_AddSuffix(word, &mainNode); + break; + case SP_PATH: + AddToPaths(word, paths); + break; + case SP_INCLUDES: + Suff_AddInclude(word); + break; + case SP_LIBS: + Suff_AddLib(word); + break; + case SP_NULL: + Suff_SetNull(word); + break; + case SP_OBJDIR: + Main_SetObjdir(FALSE, "%s", word); + break; + default: + break; + } } static Boolean @@ -1432,163 +1450,171 @@ ParseDoDependencyTargets(char **inout_cp SearchPathList **inout_paths, StringList *curTargs) { - char *cp; - char *tgt = *inout_line; - char savec; - const char *p; - - for (;;) { - /* - * Here LINE points to the beginning of the next word, and - * LSTART points to the actual beginning of the line. - */ - - /* Find the end of the next word. */ - cp = tgt; - p = cp; - ParseDependencyTargetWord(&p, lstart); - cp += p - cp; - - /* - * If the word is followed by a left parenthesis, it's the - * name of an object file inside an archive (ar file). - */ - if (!ParseIsEscaped(lstart, cp) && *cp == '(') { - /* - * Archives must be handled specially to make sure the OP_ARCHV - * flag is set in their 'type' field, for one thing, and because - * things like "archive(file1.o file2.o file3.o)" are permissible. - * Arch_ParseArchive will set 'line' to be the first non-blank - * after the archive-spec. It creates/finds nodes for the members - * and places them on the given list, returning TRUE if all - * went well and FALSE if there was an error in the - * specification. On error, line should remain untouched. - */ - if (!Arch_ParseArchive(&tgt, targets, VAR_CMDLINE)) { - Parse_Error(PARSE_FATAL, - "Error in archive specification: \"%s\"", - tgt); - return FALSE; - } + char *cp; + char *tgt = *inout_line; + char savec; + const char *p; - cp = tgt; - continue; - } + for (;;) { + /* + * Here LINE points to the beginning of the next word, and + * LSTART points to the actual beginning of the line. + */ - if (*cp == '\0') { - ParseErrorNoDependency(lstart); - return FALSE; - } + /* Find the end of the next word. */ + cp = tgt; + p = cp; + ParseDependencyTargetWord(&p, lstart); + cp += p - cp; - /* Insert a null terminator. */ - savec = *cp; - *cp = '\0'; + /* + * If the word is followed by a left parenthesis, it's the + * name of an object file inside an archive (ar file). + */ + if (!ParseIsEscaped(lstart, cp) && *cp == '(') { + /* + * Archives must be handled specially to make sure the + * OP_ARCHV flag is set in their 'type' field, for one + * thing, and because things like "archive(file1.o + * file2.o file3.o)" are permissible. + * + * Arch_ParseArchive will set 'line' to be the first + * non-blank after the archive-spec. It creates/finds + * nodes for the members and places them on the given + * list, returning TRUE if all went well and FALSE if + * there was an error in the specification. On error, + * line should remain untouched. + */ + if (!Arch_ParseArchive(&tgt, targets, VAR_CMDLINE)) { + Parse_Error(PARSE_FATAL, + "Error in archive specification: \"%s\"", + tgt); + return FALSE; + } - if (!ParseDoDependencyTarget(tgt, inout_specType, inout_tOp, - inout_paths)) - return FALSE; + cp = tgt; + continue; + } - /* - * Have word in line. Get or create its node and stick it at - * the end of the targets list - */ - if (*inout_specType == SP_NOT && *tgt != '\0') - ParseDoDependencyTargetMundane(tgt, curTargs); - else if (*inout_specType == SP_PATH && *tgt != '.' && *tgt != '\0') - Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", tgt); + if (*cp == '\0') { + ParseErrorNoDependency(lstart); + return FALSE; + } - /* Don't need the inserted null terminator any more. */ - *cp = savec; + /* Insert a null terminator. */ + savec = *cp; + *cp = '\0'; - /* - * If it is a special type and not .PATH, it's the only target we - * allow on this line... - */ - if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) - ParseDoDependencyTargetExtraWarn(&cp, lstart); - else - pp_skip_whitespace(&cp); + if (!ParseDoDependencyTarget(tgt, inout_specType, inout_tOp, + inout_paths)) + return FALSE; + + /* + * Have word in line. Get or create its node and stick it at + * the end of the targets list + */ + if (*inout_specType == SP_NOT && *tgt != '\0') + ParseDoDependencyTargetMundane(tgt, curTargs); + else if (*inout_specType == SP_PATH && *tgt != '.' && + *tgt != '\0') + Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", + tgt); + + /* Don't need the inserted null terminator any more. */ + *cp = savec; + + /* + * If it is a special type and not .PATH, it's the only target + * we allow on this line. + */ + if (*inout_specType != SP_NOT && *inout_specType != SP_PATH) + ParseDoDependencyTargetExtraWarn(&cp, lstart); + else + pp_skip_whitespace(&cp); - tgt = cp; - if (*tgt == '\0') - break; - if ((*tgt == '!' || *tgt == ':') && !ParseIsEscaped(lstart, tgt)) - break; - } - - *inout_cp = cp; - *inout_line = tgt; - return TRUE; + tgt = cp; + if (*tgt == '\0') + break; + if ((*tgt == '!' || *tgt == ':') && + !ParseIsEscaped(lstart, tgt)) + break; + } + + *inout_cp = cp; + *inout_line = tgt; + return TRUE; } static void ParseDoDependencySourcesSpecial(char *start, char *end, ParseSpecial specType, SearchPathList *paths) { - char savec; + char savec; - while (*start != '\0') { - while (*end != '\0' && !ch_isspace(*end)) - end++; - savec = *end; - *end = '\0'; - ParseDoDependencySourceSpecial(specType, start, paths); - *end = savec; - if (savec != '\0') - end++; - pp_skip_whitespace(&end); - start = end; - } + while (*start != '\0') { + while (*end != '\0' && !ch_isspace(*end)) + end++; + savec = *end; + *end = '\0'; + ParseDoDependencySourceSpecial(specType, start, paths); + *end = savec; + if (savec != '\0') + end++; + pp_skip_whitespace(&end); + start = end; + } } static Boolean ParseDoDependencySourcesMundane(char *start, char *end, ParseSpecial specType, GNodeType tOp) { - while (*start != '\0') { - /* - * The targets take real sources, so we must beware of archive - * specifications (i.e. things with left parentheses in them) - * and handle them accordingly. - */ - for (; *end != '\0' && !ch_isspace(*end); end++) { - if (*end == '(' && end > start && end[-1] != '$') { + while (*start != '\0') { /* - * Only stop for a left parenthesis if it isn't at the - * start of a word (that'll be for variable changes - * later) and isn't preceded by a dollar sign (a dynamic - * source). + * The targets take real sources, so we must beware of archive + * specifications (i.e. things with left parentheses in them) + * and handle them accordingly. */ - break; - } - } + for (; *end != '\0' && !ch_isspace(*end); end++) { + if (*end == '(' && end > start && end[-1] != '$') { + /* + * Only stop for a left parenthesis if it + * isn't at the start of a word (that'll be + * for variable changes later) and isn't + * preceded by a dollar sign (a dynamic + * source). + */ + break; + } + } - if (*end == '(') { - GNodeList sources = LST_INIT; - if (!Arch_ParseArchive(&start, &sources, VAR_CMDLINE)) { - Parse_Error(PARSE_FATAL, - "Error in source archive spec \"%s\"", start); - return FALSE; - } + if (*end == '(') { + GNodeList sources = LST_INIT; + if (!Arch_ParseArchive(&start, &sources, VAR_CMDLINE)) { + Parse_Error(PARSE_FATAL, + "Error in source archive spec \"%s\"", + start); + return FALSE; + } - while (!Lst_IsEmpty(&sources)) { - GNode *gn = Lst_Dequeue(&sources); - ParseDependencySource(tOp, gn->name, specType); - } - Lst_Done(&sources); - end = start; - } else { - if (*end != '\0') { - *end = '\0'; - end++; - } + while (!Lst_IsEmpty(&sources)) { + GNode *gn = Lst_Dequeue(&sources); + ParseDependencySource(tOp, gn->name, specType); + } + Lst_Done(&sources); + end = start; + } else { + if (*end != '\0') { + *end = '\0'; + end++; + } - ParseDependencySource(tOp, start, specType); + ParseDependencySource(tOp, start, specType); + } + pp_skip_whitespace(&end); + start = end; } - pp_skip_whitespace(&end); - start = end; - } - return TRUE; + return TRUE; } /* Parse a dependency line consisting of targets, followed by a dependency @@ -1620,174 +1646,180 @@ ParseDoDependencySourcesMundane(char *st static void ParseDoDependency(char *line) { - char *cp; /* our current position */ - GNodeType op; /* the operator on the line */ - SearchPathList *paths; /* search paths to alter when parsing + char *cp; /* our current position */ + GNodeType op; /* the operator on the line */ + SearchPathList *paths; /* search paths to alter when parsing * a list of .PATH targets */ - GNodeType tOp; /* operator from special target */ - /* target names to be found and added to the targets list */ - StringList curTargs = LST_INIT; - char *lstart = line; - - /* - * specType contains the SPECial TYPE of the current target. It is SP_NOT - * if the target is unspecial. If it *is* special, however, the children - * are linked as children of the parent but not vice versa. - */ - ParseSpecial specType = SP_NOT; - - DEBUG1(PARSE, "ParseDoDependency(%s)\n", line); - tOp = OP_NONE; - - paths = NULL; - - /* - * First, grind through the targets. - */ - if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, &paths, - &curTargs)) - goto out; - - /* Don't need the list of target names anymore. - * The targets themselves are now in the global variable 'targets'. */ - Lst_Done(&curTargs); - Lst_Init(&curTargs); - - if (!Lst_IsEmpty(targets)) - ParseDoDependencyCheckSpec(specType); - - /* - * Have now parsed all the target names. Must parse the operator next. - */ - if (!ParseDoDependencyParseOp(&cp, lstart, &op)) - goto out; - - /* - * Apply the operator to the target. This is how we remember which - * operator a target was defined with. It fails if the operator - * used isn't consistent across all references. - */ - ApplyDependencyOperator(op); - - /* - * Onward to the sources. - * - * LINE will now point to the first source word, if any, or the - * end of the string if not. - */ - pp_skip_whitespace(&cp); - line = cp; /* XXX: 'line' is an inappropriate name */ - - /* - * Several special targets take different actions if present with no - * sources: - * a .SUFFIXES line with no sources clears out all old suffixes - * a .PRECIOUS line makes all targets precious - * a .IGNORE line ignores errors for all targets - * a .SILENT line creates silence when making all targets - * a .PATH removes all directories from the search path(s). - */ - if (line[0] == '\0') { - ParseDoDependencySourcesEmpty(specType, paths); - } else if (specType == SP_MFLAGS) { - /* - * Call on functions in main.c to deal with these arguments and - * set the initial character to a null-character so the loop to - * get sources won't get anything - */ - Main_ParseArgLine(line); - *line = '\0'; - } else if (specType == SP_SHELL) { - if (!Job_ParseShell(line)) { - Parse_Error(PARSE_FATAL, "improper shell specification"); - goto out; - } - *line = '\0'; - } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL || - specType == SP_DELETE_ON_ERROR) { - *line = '\0'; - } - - /* Now go for the sources. */ - if (specType == SP_SUFFIXES || specType == SP_PATH || - specType == SP_INCLUDES || specType == SP_LIBS || - specType == SP_NULL || specType == SP_OBJDIR) - { - ParseDoDependencySourcesSpecial(line, cp, specType, paths); - if (paths != NULL) { - Lst_Free(paths); - paths = NULL; + GNodeType tOp; /* operator from special target */ + /* target names to be found and added to the targets list */ + StringList curTargs = LST_INIT; + char *lstart = line; + + /* + * specType contains the SPECial TYPE of the current target. It is + * SP_NOT if the target is unspecial. If it *is* special, however, the + * children are linked as children of the parent but not vice versa. + */ + ParseSpecial specType = SP_NOT; + + DEBUG1(PARSE, "ParseDoDependency(%s)\n", line); + tOp = OP_NONE; + + paths = NULL; + + /* + * First, grind through the targets. + */ + if (!ParseDoDependencyTargets(&cp, &line, lstart, &specType, &tOp, + &paths, &curTargs)) + goto out; + + /* + * Don't need the list of target names anymore. + * The targets themselves are now in the global variable 'targets'. + */ + Lst_Done(&curTargs); + Lst_Init(&curTargs); + + if (!Lst_IsEmpty(targets)) + ParseDoDependencyCheckSpec(specType); + + /* + * Have now parsed all the target names. Must parse the operator next. + */ + if (!ParseDoDependencyParseOp(&cp, lstart, &op)) + goto out; + + /* + * Apply the operator to the target. This is how we remember which + * operator a target was defined with. It fails if the operator + * used isn't consistent across all references. + */ + ApplyDependencyOperator(op); + + /* + * Onward to the sources. + * + * LINE will now point to the first source word, if any, or the + * end of the string if not. + */ + pp_skip_whitespace(&cp); + line = cp; /* XXX: 'line' is an inappropriate name */ + + /* + * Several special targets take different actions if present with no + * sources: + * a .SUFFIXES line with no sources clears out all old suffixes + * a .PRECIOUS line makes all targets precious + * a .IGNORE line ignores errors for all targets + * a .SILENT line creates silence when making all targets + * a .PATH removes all directories from the search path(s). + */ + if (line[0] == '\0') { + ParseDoDependencySourcesEmpty(specType, paths); + } else if (specType == SP_MFLAGS) { + /* + * Call on functions in main.c to deal with these arguments and + * set the initial character to a null-character so the loop to + * get sources won't get anything + */ + Main_ParseArgLine(line); + *line = '\0'; + } else if (specType == SP_SHELL) { + if (!Job_ParseShell(line)) { + Parse_Error(PARSE_FATAL, + "improper shell specification"); + goto out; + } + *line = '\0'; + } else if (specType == SP_NOTPARALLEL || specType == SP_SINGLESHELL || + specType == SP_DELETE_ON_ERROR) { + *line = '\0'; + } + + /* Now go for the sources. */ + if (specType == SP_SUFFIXES || specType == SP_PATH || + specType == SP_INCLUDES || specType == SP_LIBS || + specType == SP_NULL || specType == SP_OBJDIR) { + ParseDoDependencySourcesSpecial(line, cp, specType, paths); + if (paths != NULL) { + Lst_Free(paths); + paths = NULL; + } + if (specType == SP_PATH) + Dir_SetPATH(); + } else { + assert(paths == NULL); + if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp)) + goto out; } - if (specType == SP_PATH) - Dir_SetPATH(); - } else { - assert(paths == NULL); - if (!ParseDoDependencySourcesMundane(line, cp, specType, tOp)) - goto out; - } - FindMainTarget(); + FindMainTarget(); out: - if (paths != NULL) - Lst_Free(paths); - Lst_Done(&curTargs); + if (paths != NULL) + Lst_Free(paths); + Lst_Done(&curTargs); } typedef struct VarAssignParsed { - const char *nameStart; /* unexpanded */ - const char *nameEnd; /* before operator adjustment */ - const char *eq; /* the '=' of the assignment operator */ + const char *nameStart; /* unexpanded */ + const char *nameEnd; /* before operator adjustment */ + const char *eq; /* the '=' of the assignment operator */ } VarAssignParsed; -/* Determine the assignment operator and adjust the end of the variable - * name accordingly. */ -static void +/* + * Determine the assignment operator and adjust the end of the variable + * name accordingly. + */ +static void AdjustVarassignOp(const VarAssignParsed *pvar, const char *value, VarAssign *out_var) { - const char *op = pvar->eq; - const char * const name = pvar->nameStart; - VarAssignOp type; - - if (op > name && op[-1] == '+') { - type = VAR_APPEND; - op--; - - } else if (op > name && op[-1] == '?') { - op--; - type = VAR_DEFAULT; - - } else if (op > name && op[-1] == ':') { - op--; - type = VAR_SUBST; - - } else if (op > name && op[-1] == '!') { - op--; - type = VAR_SHELL; + const char *op = pvar->eq; + const char *const name = pvar->nameStart; + VarAssignOp type; + + if (op > name && op[-1] == '+') { + type = VAR_APPEND; + op--; + + } else if (op > name && op[-1] == '?') { + op--; + type = VAR_DEFAULT; + + } else if (op > name && op[-1] == ':') { + op--; + type = VAR_SUBST; + + } else if (op > name && op[-1] == '!') { + op--; + type = VAR_SHELL; - } else { - type = VAR_NORMAL; + } else { + type = VAR_NORMAL; #ifdef SUNSHCMD - while (op > name && ch_isspace(op[-1])) - op--; + while (op > name && ch_isspace(op[-1])) + op--; - if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && op[-1] == 'h') { - type = VAR_SHELL; - op -= 3; - } + if (op >= name + 3 && op[-3] == ':' && op[-2] == 's' && + op[-1] == 'h') { + type = VAR_SHELL; + op -= 3; + } #endif - } + } - { - const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op; - out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd); - out_var->op = type; - out_var->value = value; - } + { + const char *nameEnd = pvar->nameEnd < op ? pvar->nameEnd : op; + out_var->varname = bmake_strsedup(pvar->nameStart, nameEnd); + out_var->op = type; + out_var->value = value; + } } -/* Parse a variable assignment, consisting of a single-word variable name, +/* + * Parse a variable assignment, consisting of a single-word variable name, * optional whitespace, an assignment operator, optional whitespace and the * variable value. * @@ -1797,151 +1829,161 @@ AdjustVarassignOp(const VarAssignParsed * C++=/usr/bin/CC * is interpreted as "C+ +=" instead of "C++ =". * - * Used for both lines in a file and command line arguments. */ + * Used for both lines in a file and command line arguments. + */ Boolean Parse_IsVar(const char *p, VarAssign *out_var) { - VarAssignParsed pvar; - const char *firstSpace = NULL; - int level = 0; - - cpp_skip_hspace(&p); /* Skip to variable name */ - - /* During parsing, the '+' of the '+=' operator is initially parsed - * as part of the variable name. It is later corrected, as is the ':sh' - * modifier. Of these two (nameEnd and op), the earlier one determines the - * actual end of the variable name. */ - pvar.nameStart = p; + VarAssignParsed pvar; + const char *firstSpace = NULL; + int level = 0; + + cpp_skip_hspace(&p); /* Skip to variable name */ + + /* + * During parsing, the '+' of the '+=' operator is initially parsed + * as part of the variable name. It is later corrected, as is the + * ':sh' modifier. Of these two (nameEnd and op), the earlier one + * determines the actual end of the variable name. + */ + pvar.nameStart = p; #ifdef CLEANUP - pvar.nameEnd = NULL; - pvar.eq = NULL; + pvar.nameEnd = NULL; + pvar.eq = NULL; #endif - /* Scan for one of the assignment operators outside a variable expansion */ - while (*p != '\0') { - char ch = *p++; - if (ch == '(' || ch == '{') { - level++; - continue; - } - if (ch == ')' || ch == '}') { - level--; - continue; - } - - if (level != 0) - continue; - - if (ch == ' ' || ch == '\t') - if (firstSpace == NULL) - firstSpace = p - 1; - while (ch == ' ' || ch == '\t') - ch = *p++; + /* + * Scan for one of the assignment operators outside a variable + * expansion. + */ + while (*p != '\0') { + char ch = *p++; + if (ch == '(' || ch == '{') { + level++; + continue; + } + if (ch == ')' || ch == '}') { + level--; + continue; + } + + if (level != 0) + continue; + + if (ch == ' ' || ch == '\t') + if (firstSpace == NULL) + firstSpace = p - 1; + while (ch == ' ' || ch == '\t') + ch = *p++; #ifdef SUNSHCMD - if (ch == ':' && p[0] == 's' && p[1] == 'h') { - p += 2; - continue; - } + if (ch == ':' && p[0] == 's' && p[1] == 'h') { + p += 2; + continue; + } #endif - if (ch == '=') { - pvar.eq = p - 1; - pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1; - cpp_skip_whitespace(&p); - AdjustVarassignOp(&pvar, p, out_var); - return TRUE; - } - if (*p == '=' && (ch == '+' || ch == ':' || ch == '?' || ch == '!')) { - pvar.eq = p; - pvar.nameEnd = firstSpace != NULL ? firstSpace : p; - p++; - cpp_skip_whitespace(&p); - AdjustVarassignOp(&pvar, p, out_var); - return TRUE; - } - if (firstSpace != NULL) - return FALSE; - } + if (ch == '=') { + pvar.eq = p - 1; + pvar.nameEnd = firstSpace != NULL ? firstSpace : p - 1; + cpp_skip_whitespace(&p); + AdjustVarassignOp(&pvar, p, out_var); + return TRUE; + } + if (*p == '=' && + (ch == '+' || ch == ':' || ch == '?' || ch == '!')) { + pvar.eq = p; + pvar.nameEnd = firstSpace != NULL ? firstSpace : p; + p++; + cpp_skip_whitespace(&p); + AdjustVarassignOp(&pvar, p, out_var); + return TRUE; + } + if (firstSpace != NULL) + return FALSE; + } - return FALSE; + return FALSE; } +/* + * Check for syntax errors such as unclosed expressions or unknown modifiers. + */ static void VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt) { - if (opts.lint) { - if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { - /* Check for syntax errors such as unclosed expressions or - * unknown modifiers. */ - char *expandedValue; - - (void)Var_Subst(uvalue, ctxt, VARE_NONE, &expandedValue); - /* TODO: handle errors */ - free(expandedValue); + if (opts.lint) { + if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { + char *expandedValue; + + (void)Var_Subst(uvalue, ctxt, VARE_NONE, + &expandedValue); + /* TODO: handle errors */ + free(expandedValue); + } } - } } static void VarAssign_EvalSubst(const char *name, const char *uvalue, GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt) { - const char *avalue; - char *evalue; - Boolean savedPreserveUndefined = preserveUndefined; - - /* TODO: Can this assignment to preserveUndefined be moved further down - * to the actually interesting Var_Subst call, without affecting any - * edge cases? - * - * It might affect the implicit expansion of the variable name in the - * Var_Exists and Var_Set calls, even though it's unlikely that anyone - * cared about this edge case when adding this code. In addition, - * variable assignments should not refer to any undefined variables in - * the variable name. */ - preserveUndefined = TRUE; - - /* - * make sure that we set the variable the first time to nothing - * so that it gets substituted! - */ - if (!Var_Exists(name, ctxt)) - Var_Set(name, "", ctxt); - - (void)Var_Subst(uvalue, ctxt, VARE_WANTRES|VARE_KEEP_DOLLAR, &evalue); - /* TODO: handle errors */ - preserveUndefined = savedPreserveUndefined; - avalue = evalue; - Var_Set(name, avalue, ctxt); + const char *avalue; + char *evalue; + Boolean savedPreserveUndefined = preserveUndefined; + + /* TODO: Can this assignment to preserveUndefined be moved further down + * to the actually interesting Var_Subst call, without affecting any + * edge cases? + * + * It might affect the implicit expansion of the variable name in the + * Var_Exists and Var_Set calls, even though it's unlikely that anyone + * cared about this edge case when adding this code. In addition, + * variable assignments should not refer to any undefined variables in + * the variable name. */ + preserveUndefined = TRUE; + + /* + * make sure that we set the variable the first time to nothing + * so that it gets substituted! + */ + if (!Var_Exists(name, ctxt)) + Var_Set(name, "", ctxt); - *out_avalue = avalue; - *out_avalue_freeIt = evalue; + (void)Var_Subst(uvalue, ctxt, VARE_WANTRES | VARE_KEEP_DOLLAR, &evalue); + /* TODO: handle errors */ + preserveUndefined = savedPreserveUndefined; + avalue = evalue; + Var_Set(name, avalue, ctxt); + + *out_avalue = avalue; + *out_avalue_freeIt = evalue; } static void VarAssign_EvalShell(const char *name, const char *uvalue, GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt) { - const char *cmd, *errfmt; - char *cmdOut; - void *cmd_freeIt = NULL; - - cmd = uvalue; - if (strchr(cmd, '$') != NULL) { - char *ecmd; - (void)Var_Subst(cmd, VAR_CMDLINE, VARE_WANTRES | VARE_UNDEFERR, &ecmd); - /* TODO: handle errors */ - cmd = cmd_freeIt = ecmd; - } + const char *cmd, *errfmt; + char *cmdOut; + void *cmd_freeIt = NULL; + + cmd = uvalue; + if (strchr(cmd, '$') != NULL) { + char *ecmd; + (void)Var_Subst(cmd, VAR_CMDLINE, VARE_WANTRES | VARE_UNDEFERR, + &ecmd); + /* TODO: handle errors */ + cmd = cmd_freeIt = ecmd; + } + + cmdOut = Cmd_Exec(cmd, &errfmt); + Var_Set(name, cmdOut, ctxt); + *out_avalue = *out_avalue_freeIt = cmdOut; - cmdOut = Cmd_Exec(cmd, &errfmt); - Var_Set(name, cmdOut, ctxt); - *out_avalue = *out_avalue_freeIt = cmdOut; + if (errfmt != NULL) + Parse_Error(PARSE_WARNING, errfmt, cmd); - if (errfmt != NULL) - Parse_Error(PARSE_WARNING, errfmt, cmd); - - free(cmd_freeIt); + free(cmd_freeIt); } /* Perform a variable assignment. @@ -1956,63 +1998,65 @@ static Boolean VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, GNode *ctxt, const char **out_avalue, void **out_avalue_freeIt) { - const char *avalue = uvalue; - void *avalue_freeIt = NULL; + const char *avalue = uvalue; + void *avalue_freeIt = NULL; + + if (op == VAR_APPEND) + Var_Append(name, uvalue, ctxt); + else if (op == VAR_SUBST) + VarAssign_EvalSubst(name, uvalue, ctxt, &avalue, + &avalue_freeIt); + else if (op == VAR_SHELL) + VarAssign_EvalShell(name, uvalue, ctxt, &avalue, + &avalue_freeIt); + else { + if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) { + *out_avalue_freeIt = NULL; + return FALSE; + } + + /* Normal assignment -- just do it. */ + Var_Set(name, uvalue, ctxt); + } - if (op == VAR_APPEND) - Var_Append(name, uvalue, ctxt); - else if (op == VAR_SUBST) - VarAssign_EvalSubst(name, uvalue, ctxt, &avalue, &avalue_freeIt); - else if (op == VAR_SHELL) - VarAssign_EvalShell(name, uvalue, ctxt, &avalue, &avalue_freeIt); - else { - if (op == VAR_DEFAULT && Var_Exists(name, ctxt)) { - *out_avalue_freeIt = NULL; - return FALSE; - } - - /* Normal assignment -- just do it. */ - Var_Set(name, uvalue, ctxt); - } - - *out_avalue = avalue; - *out_avalue_freeIt = avalue_freeIt; - return TRUE; + *out_avalue = avalue; + *out_avalue_freeIt = avalue_freeIt; + return TRUE; } static void VarAssignSpecial(const char *name, const char *avalue) { - if (strcmp(name, MAKEOVERRIDES) == 0) - Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ - else if (strcmp(name, ".CURDIR") == 0) { - /* - * Someone is being (too?) clever... - * Let's pretend they know what they are doing and - * re-initialize the 'cur' CachedDir. - */ - Dir_InitCur(avalue); - Dir_SetPATH(); - } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) - Job_SetPrefix(); - else if (strcmp(name, MAKE_EXPORTED) == 0) - Var_Export(avalue, FALSE); + if (strcmp(name, MAKEOVERRIDES) == 0) + Main_ExportMAKEFLAGS(FALSE); /* re-export MAKEFLAGS */ + else if (strcmp(name, ".CURDIR") == 0) { + /* + * Someone is being (too?) clever... + * Let's pretend they know what they are doing and + * re-initialize the 'cur' CachedDir. + */ + Dir_InitCur(avalue); + Dir_SetPATH(); + } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) + Job_SetPrefix(); + else if (strcmp(name, MAKE_EXPORTED) == 0) + Var_Export(avalue, FALSE); } /* Perform the variable variable assignment in the given context. */ void Parse_DoVar(VarAssign *var, GNode *ctxt) { - const char *avalue; /* actual value (maybe expanded) */ - void *avalue_freeIt; + const char *avalue; /* actual value (maybe expanded) */ + void *avalue_freeIt; - VarCheckSyntax(var->op, var->value, ctxt); - if (VarAssign_Eval(var->varname, var->op, var->value, ctxt, - &avalue, &avalue_freeIt)) - VarAssignSpecial(var->varname, avalue); + VarCheckSyntax(var->op, var->value, ctxt); + if (VarAssign_Eval(var->varname, var->op, var->value, ctxt, + &avalue, &avalue_freeIt)) + VarAssignSpecial(var->varname, avalue); - free(avalue_freeIt); - free(var->varname); + free(avalue_freeIt); + free(var->varname); } @@ -2021,38 +2065,38 @@ Parse_DoVar(VarAssign *var, GNode *ctxt) static Boolean MaybeSubMake(const char *cmd) { - const char *start; + const char *start; - for (start = cmd; *start != '\0'; start++) { - const char *p = start; - char endc; - - /* XXX: What if progname != "make"? */ - if (p[0] == 'm' && p[1] == 'a' && p[2] == 'k' && p[3] == 'e') - if (start == cmd || !ch_isalnum(p[-1])) - if (!ch_isalnum(p[4])) - return TRUE; - - if (*p != '$') - continue; - p++; - - if (*p == '{') - endc = '}'; - else if (*p == '(') - endc = ')'; - else - continue; - p++; + for (start = cmd; *start != '\0'; start++) { + const char *p = start; + char endc; + + /* XXX: What if progname != "make"? */ + if (p[0] == 'm' && p[1] == 'a' && p[2] == 'k' && p[3] == 'e') + if (start == cmd || !ch_isalnum(p[-1])) + if (!ch_isalnum(p[4])) + return TRUE; + + if (*p != '$') + continue; + p++; + + if (*p == '{') + endc = '}'; + else if (*p == '(') + endc = ')'; + else + continue; + p++; - if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */ - p++; + if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */ + p++; - if (p[0] == 'M' && p[1] == 'A' && p[2] == 'K' && p[3] == 'E') - if (p[4] == endc) - return TRUE; - } - return FALSE; + if (p[0] == 'M' && p[1] == 'A' && p[2] == 'K' && p[3] == 'E') + if (p[4] == endc) + return TRUE; + } + return FALSE; } /* Append the command to the target node. @@ -2062,41 +2106,43 @@ MaybeSubMake(const char *cmd) static void ParseAddCmd(GNode *gn, char *cmd) { - /* Add to last (ie current) cohort for :: targets */ - if ((gn->type & OP_DOUBLEDEP) && gn->cohorts.last != NULL) - gn = gn->cohorts.last->datum; - - /* if target already supplied, ignore commands */ - if (!(gn->type & OP_HAS_COMMANDS)) { - Lst_Append(&gn->commands, cmd); - if (MaybeSubMake(cmd)) - gn->type |= OP_SUBMAKE; - ParseMark(gn); - } else { + /* Add to last (ie current) cohort for :: targets */ + if ((gn->type & OP_DOUBLEDEP) && gn->cohorts.last != NULL) + gn = gn->cohorts.last->datum; + + /* if target already supplied, ignore commands */ + if (!(gn->type & OP_HAS_COMMANDS)) { + Lst_Append(&gn->commands, cmd); + if (MaybeSubMake(cmd)) + gn->type |= OP_SUBMAKE; + ParseMark(gn); + } else { #if 0 - /* XXX: We cannot do this until we fix the tree */ - Lst_Append(gn->commands, cmd); - Parse_Error(PARSE_WARNING, - "overriding commands for target \"%s\"; " - "previous commands defined at %s: %d ignored", - gn->name, gn->fname, gn->lineno); + /* XXX: We cannot do this until we fix the tree */ + Lst_Append(&gn->commands, cmd); + Parse_Error(PARSE_WARNING, + "overriding commands for target \"%s\"; " + "previous commands defined at %s: %d ignored", + gn->name, gn->fname, gn->lineno); #else - Parse_Error(PARSE_WARNING, + Parse_Error(PARSE_WARNING, "duplicate script for target \"%s\" ignored", gn->name); - ParseErrorInternal(gn->fname, (size_t)gn->lineno, PARSE_WARNING, - "using previous script for \"%s\" defined here", - gn->name); + ParseErrorInternal(gn->fname, (size_t)gn->lineno, PARSE_WARNING, + "using previous script for \"%s\" defined here", + gn->name); #endif - } + } } -/* Add a directory to the path searched for included makefiles bracketed - * by double-quotes. */ +/* + * Add a directory to the path searched for included makefiles bracketed + * by double-quotes. + */ void Parse_AddIncludeDir(const char *dir) { - (void)Dir_AddDir(parseIncPath, dir); + (void)Dir_AddDir(parseIncPath, dir); } /* Handle one of the .[-ds]include directives by remembering the current file @@ -2111,148 +2157,157 @@ Parse_AddIncludeDir(const char *dir) static void Parse_include_file(char *file, Boolean isSystem, Boolean depinc, Boolean silent) { - struct loadedfile *lf; - char *fullname; /* full pathname of file */ - char *newName; - char *slash, *incdir; - int fd; - int i; - - fullname = file[0] == '/' ? bmake_strdup(file) : NULL; - - if (fullname == NULL && !isSystem) { - /* - * Include files contained in double-quotes are first searched - * relative to the including file's location. We don't want to - * cd there, of course, so we just tack on the old file's - * leading path components and call Dir_FindFile to see if - * we can locate the file. - */ - - incdir = bmake_strdup(CurFile()->fname); - slash = strrchr(incdir, '/'); - if (slash != NULL) { - *slash = '\0'; - /* Now do lexical processing of leading "../" on the filename */ - for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { - slash = strrchr(incdir + 1, '/'); - if (slash == NULL || strcmp(slash, "/..") == 0) - break; - *slash = '\0'; - } - newName = str_concat3(incdir, "/", file + i); - fullname = Dir_FindFile(newName, parseIncPath); - if (fullname == NULL) - fullname = Dir_FindFile(newName, &dirSearchPath); - free(newName); + struct loadedfile *lf; + char *fullname; /* full pathname of file */ + char *newName; + char *slash, *incdir; + int fd; + int i; + + fullname = file[0] == '/' ? bmake_strdup(file) : NULL; + + if (fullname == NULL && !isSystem) { + /* + * Include files contained in double-quotes are first searched + * relative to the including file's location. We don't want to + * cd there, of course, so we just tack on the old file's + * leading path components and call Dir_FindFile to see if + * we can locate the file. + */ + + incdir = bmake_strdup(CurFile()->fname); + slash = strrchr(incdir, '/'); + if (slash != NULL) { + *slash = '\0'; + /* + * Now do lexical processing of leading "../" on the + * filename. + */ + for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) { + slash = strrchr(incdir + 1, '/'); + if (slash == NULL || strcmp(slash, "/..") == 0) + break; + *slash = '\0'; + } + newName = str_concat3(incdir, "/", file + i); + fullname = Dir_FindFile(newName, parseIncPath); + if (fullname == NULL) + fullname = Dir_FindFile(newName, + &dirSearchPath); + free(newName); + } + free(incdir); + + if (fullname == NULL) { + /* + * Makefile wasn't found in same directory as included + * makefile. + * + * Search for it first on the -I search path, then on + * the .PATH search path, if not found in a -I + * directory. If we have a suffix-specific path, we + * should use that. + */ + const char *suff; + SearchPath *suffPath = NULL; + + if ((suff = strrchr(file, '.'))) { + suffPath = Suff_GetPath(suff); + if (suffPath != NULL) + fullname = Dir_FindFile(file, suffPath); + } + if (fullname == NULL) { + fullname = Dir_FindFile(file, parseIncPath); + if (fullname == NULL) + fullname = Dir_FindFile(file, + &dirSearchPath); + } + } } - free(incdir); + /* Looking for a system file or file still not found */ if (fullname == NULL) { - /* - * Makefile wasn't found in same directory as included makefile. - * Search for it first on the -I search path, - * then on the .PATH search path, if not found in a -I directory. - * If we have a suffix specific path we should use that. - */ - const char *suff; - SearchPath *suffPath = NULL; - - if ((suff = strrchr(file, '.'))) { - suffPath = Suff_GetPath(suff); - if (suffPath != NULL) - fullname = Dir_FindFile(file, suffPath); - } - if (fullname == NULL) { - fullname = Dir_FindFile(file, parseIncPath); - if (fullname == NULL) - fullname = Dir_FindFile(file, &dirSearchPath); - } - } - } - - /* Looking for a system file or file still not found */ - if (fullname == NULL) { - /* - * Look for it on the system path - */ - SearchPath *path = Lst_IsEmpty(sysIncPath) ? defSysIncPath : sysIncPath; - fullname = Dir_FindFile(file, path); - } - - if (fullname == NULL) { - if (!silent) - Parse_Error(PARSE_FATAL, "Could not find %s", file); - return; - } - - /* Actually open the file... */ - fd = open(fullname, O_RDONLY); - if (fd == -1) { - if (!silent) - Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); - free(fullname); - return; - } - - /* load it */ - lf = loadfile(fullname, fd); - - /* Start reading from this file next */ - Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); - CurFile()->lf = lf; - if (depinc) - doing_depend = depinc; /* only turn it on */ + /* + * Look for it on the system path + */ + SearchPath *path = Lst_IsEmpty(sysIncPath) ? defSysIncPath + : sysIncPath; + fullname = Dir_FindFile(file, path); + } + + if (fullname == NULL) { + if (!silent) + Parse_Error(PARSE_FATAL, "Could not find %s", file); + return; + } + + /* Actually open the file... */ + fd = open(fullname, O_RDONLY); + if (fd == -1) { + if (!silent) + Parse_Error(PARSE_FATAL, "Cannot open %s", fullname); + free(fullname); + return; + } + + /* load it */ + lf = loadfile(fullname, fd); + + /* Start reading from this file next */ + Parse_SetInput(fullname, 0, -1, loadedfile_nextbuf, lf); + CurFile()->lf = lf; + if (depinc) + doing_depend = depinc; /* only turn it on */ } static void ParseDoInclude(char *line) { - char endc; /* the character which ends the file spec */ - char *cp; /* current position in file spec */ - Boolean silent = *line != 'i'; - char *file = line + (silent ? 8 : 7); + char endc; /* the character which ends the file spec */ + char *cp; /* current position in file spec */ + Boolean silent = *line != 'i'; + char *file = line + (silent ? 8 : 7); - /* Skip to delimiter character so we know where to look */ - pp_skip_hspace(&file); + /* Skip to delimiter character so we know where to look */ + pp_skip_hspace(&file); - if (*file != '"' && *file != '<') { - Parse_Error(PARSE_FATAL, + if (*file != '"' && *file != '<') { + Parse_Error(PARSE_FATAL, ".include filename must be delimited by '\"' or '<'"); - return; - } + return; + } - /* - * Set the search path on which to find the include file based on the - * characters which bracket its name. Angle-brackets imply it's - * a system Makefile while double-quotes imply it's a user makefile - */ - if (*file == '<') - endc = '>'; - else - endc = '"'; - - /* Skip to matching delimiter */ - for (cp = ++file; *cp && *cp != endc; cp++) - continue; + /* + * Set the search path on which to find the include file based on the + * characters which bracket its name. Angle-brackets imply it's + * a system Makefile while double-quotes imply it's a user makefile + */ + if (*file == '<') + endc = '>'; + else + endc = '"'; - if (*cp != endc) { - Parse_Error(PARSE_FATAL, + /* Skip to matching delimiter */ + for (cp = ++file; *cp && *cp != endc; cp++) + continue; + + if (*cp != endc) { + Parse_Error(PARSE_FATAL, "Unclosed .include filename. '%c' expected", endc); - return; - } + return; + } - *cp = '\0'; + *cp = '\0'; - /* - * Substitute for any variables in the filename before trying to - * find the file. - */ - (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &file); - /* TODO: handle errors */ + /* + * Substitute for any variables in the filename before trying to + * find the file. + */ + (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &file); + /* TODO: handle errors */ - Parse_include_file(file, endc == '>', *line == 'd', silent); - free(file); + Parse_include_file(file, endc == '>', *line == 'd', silent); + free(file); } /* Split filename into dirname + basename, then assign these to the @@ -2260,96 +2315,101 @@ ParseDoInclude(char *line) static void SetFilenameVars(const char *filename, const char *dirvar, const char *filevar) { - const char *slash, *dirname, *basename; - void *freeIt; + const char *slash, *dirname, *basename; + void *freeIt; + + slash = strrchr(filename, '/'); + if (slash == NULL) { + dirname = curdir; + basename = filename; + freeIt = NULL; + } else { + dirname = freeIt = bmake_strsedup(filename, slash); + basename = slash + 1; + } + + Var_Set(dirvar, dirname, VAR_GLOBAL); + Var_Set(filevar, basename, VAR_GLOBAL); - slash = strrchr(filename, '/'); - if (slash == NULL) { - dirname = curdir; - basename = filename; - freeIt = NULL; - } else { - dirname = freeIt = bmake_strsedup(filename, slash); - basename = slash + 1; - } - - Var_Set(dirvar, dirname, VAR_GLOBAL); - Var_Set(filevar, basename, VAR_GLOBAL); - - DEBUG5(PARSE, "%s: ${%s} = `%s' ${%s} = `%s'\n", - __func__, dirvar, dirname, filevar, basename); - free(freeIt); + DEBUG5(PARSE, "%s: ${%s} = `%s' ${%s} = `%s'\n", + __func__, dirvar, dirname, filevar, basename); + free(freeIt); } -/* Return the immediately including file. +/* + * Return the immediately including file. * * This is made complicated since the .for loop is implemented as a special - * kind of .include; see For_Run. */ + * kind of .include; see For_Run. + */ static const char * GetActuallyIncludingFile(void) { - size_t i; - const IFile *incs = GetInclude(0); + size_t i; + const IFile *incs = GetInclude(0); - for (i = includes.len; i >= 2; i--) - if (!incs[i - 1].fromForLoop) - return incs[i - 2].fname; - return NULL; + for (i = includes.len; i >= 2; i--) + if (!incs[i - 1].fromForLoop) + return incs[i - 2].fname; + return NULL; } /* Set .PARSEDIR, .PARSEFILE, .INCLUDEDFROMDIR and .INCLUDEDFROMFILE. */ static void ParseSetParseFile(const char *filename) { - const char *including; + const char *including; - SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE"); + SetFilenameVars(filename, ".PARSEDIR", ".PARSEFILE"); - including = GetActuallyIncludingFile(); - if (including != NULL) { - SetFilenameVars(including, - ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE"); - } else { - Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); - Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); - } + including = GetActuallyIncludingFile(); + if (including != NULL) { + SetFilenameVars(including, + ".INCLUDEDFROMDIR", ".INCLUDEDFROMFILE"); + } else { + Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); + Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); + } } static Boolean StrContainsWord(const char *str, const char *word) { - size_t strLen = strlen(str); - size_t wordLen = strlen(word); - const char *p, *end; - - if (strLen < wordLen) - return FALSE; /* str is too short to contain word */ - - end = str + strLen - wordLen; - for (p = str; p != NULL; p = strchr(p, ' ')) { - if (*p == ' ') - p++; - if (p > end) - return FALSE; /* cannot contain word */ - - if (memcmp(p, word, wordLen) == 0 && - (p[wordLen] == '\0' || p[wordLen] == ' ')) - return TRUE; - } - return FALSE; -} - -/* XXX: Searching through a set of words with this linear search is - * inefficient for variables that contain thousands of words. */ -/* XXX: The paths in this list don't seem to be normalized in any way. */ + size_t strLen = strlen(str); + size_t wordLen = strlen(word); + const char *p, *end; + + if (strLen < wordLen) + return FALSE; /* str is too short to contain word */ + + end = str + strLen - wordLen; + for (p = str; p != NULL; p = strchr(p, ' ')) { + if (*p == ' ') + p++; + if (p > end) + return FALSE; /* cannot contain word */ + + if (memcmp(p, word, wordLen) == 0 && + (p[wordLen] == '\0' || p[wordLen] == ' ')) + return TRUE; + } + return FALSE; +} + +/* + * XXX: Searching through a set of words with this linear search is + * inefficient for variables that contain thousands of words. + * + * XXX: The paths in this list don't seem to be normalized in any way. + */ static Boolean VarContainsWord(const char *varname, const char *word) { - void *val_freeIt; - const char *val = Var_Value(varname, VAR_GLOBAL, &val_freeIt); - Boolean found = val != NULL && StrContainsWord(val, word); - bmake_free(val_freeIt); - return found; + void *val_freeIt; + const char *val = Var_Value(varname, VAR_GLOBAL, &val_freeIt); + Boolean found = val != NULL && StrContainsWord(val, word); + bmake_free(val_freeIt); + return found; } /* Track the makefiles we read - so makefiles can set dependencies on them. @@ -2360,65 +2420,69 @@ VarContainsWord(const char *varname, con static void ParseTrackInput(const char *name) { - if (!VarContainsWord(MAKE_MAKEFILES, name)) - Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL); + if (!VarContainsWord(MAKE_MAKEFILES, name)) + Var_Append(MAKE_MAKEFILES, name, VAR_GLOBAL); } -/* Start parsing from the given source. +/* + * Start parsing from the given source. * - * The given file is added to the includes stack. */ + * The given file is added to the includes stack. + */ void Parse_SetInput(const char *name, int line, int fd, char *(*nextbuf)(void *, size_t *), void *arg) { - IFile *curFile; - char *buf; - size_t len; - Boolean fromForLoop = name == NULL; - - if (fromForLoop) - name = CurFile()->fname; - else - ParseTrackInput(name); - - if (DEBUG(PARSE)) - debug_printf("%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n", - __func__, name, line, fd, - nextbuf == loadedfile_nextbuf ? "loadedfile" : "other", - arg); - - if (fd == -1 && nextbuf == NULL) - /* sanity */ - return; - - curFile = Vector_Push(&includes); - curFile->fname = bmake_strdup(name); - curFile->fromForLoop = fromForLoop; - curFile->lineno = line; - curFile->first_lineno = line; - curFile->nextbuf = nextbuf; - curFile->nextbuf_arg = arg; - curFile->lf = NULL; - curFile->depending = doing_depend; /* restore this on EOF */ - - assert(nextbuf != NULL); - - /* Get first block of input data */ - buf = curFile->nextbuf(curFile->nextbuf_arg, &len); - if (buf == NULL) { - /* Was all a waste of time ... */ - if (curFile->fname) - free(curFile->fname); - free(curFile); - return; - } - curFile->buf_freeIt = buf; - curFile->buf_ptr = buf; - curFile->buf_end = buf + len; + IFile *curFile; + char *buf; + size_t len; + Boolean fromForLoop = name == NULL; - curFile->cond_depth = Cond_save_depth(); - ParseSetParseFile(name); + if (fromForLoop) + name = CurFile()->fname; + else + ParseTrackInput(name); + + if (DEBUG(PARSE)) { + const char *caller = nextbuf == loadedfile_nextbuf + ? "loadedfile" : "other"; + debug_printf( + "%s: file %s, line %d, fd %d, nextbuf %s, arg %p\n", + __func__, name, line, fd, caller, arg); + } + + if (fd == -1 && nextbuf == NULL) + /* sanity */ + return; + + curFile = Vector_Push(&includes); + curFile->fname = bmake_strdup(name); + curFile->fromForLoop = fromForLoop; + curFile->lineno = line; + curFile->first_lineno = line; + curFile->nextbuf = nextbuf; + curFile->nextbuf_arg = arg; + curFile->lf = NULL; + curFile->depending = doing_depend; /* restore this on EOF */ + + assert(nextbuf != NULL); + + /* Get first block of input data */ + buf = curFile->nextbuf(curFile->nextbuf_arg, &len); + if (buf == NULL) { + /* Was all a waste of time ... */ + if (curFile->fname) + free(curFile->fname); + free(curFile); + return; + } + curFile->buf_freeIt = buf; + curFile->buf_ptr = buf; + curFile->buf_end = buf + len; + + curFile->cond_depth = Cond_save_depth(); + ParseSetParseFile(name); } /* Check if the directive is an include directive. */ @@ -2464,42 +2528,42 @@ IsSysVInclude(const char *line) static void ParseTraditionalInclude(char *line) { - char *cp; /* current position in file spec */ - Boolean done = FALSE; - Boolean silent = line[0] != 'i'; - char *file = line + (silent ? 8 : 7); - char *all_files; - - DEBUG2(PARSE, "%s: %s\n", __func__, file); - - pp_skip_whitespace(&file); - - /* - * Substitute for any variables in the file name before trying to - * find the thing. - */ - (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &all_files); - /* TODO: handle errors */ - - if (*file == '\0') { - Parse_Error(PARSE_FATAL, "Filename missing from \"include\""); - goto out; - } - - for (file = all_files; !done; file = cp + 1) { - /* Skip to end of line or next whitespace */ - for (cp = file; *cp != '\0' && !ch_isspace(*cp); cp++) - continue; + char *cp; /* current position in file spec */ + Boolean done = FALSE; + Boolean silent = line[0] != 'i'; + char *file = line + (silent ? 8 : 7); + char *all_files; - if (*cp != '\0') - *cp = '\0'; - else - done = TRUE; + DEBUG2(PARSE, "%s: %s\n", __func__, file); + + pp_skip_whitespace(&file); + + /* + * Substitute for any variables in the file name before trying to + * find the thing. + */ + (void)Var_Subst(file, VAR_CMDLINE, VARE_WANTRES, &all_files); + /* TODO: handle errors */ + + if (*file == '\0') { + Parse_Error(PARSE_FATAL, "Filename missing from \"include\""); + goto out; + } + + for (file = all_files; !done; file = cp + 1) { + /* Skip to end of line or next whitespace */ + for (cp = file; *cp != '\0' && !ch_isspace(*cp); cp++) + continue; - Parse_include_file(file, FALSE, FALSE, silent); - } + if (*cp != '\0') + *cp = '\0'; + else + done = TRUE; + + Parse_include_file(file, FALSE, FALSE, silent); + } out: - free(all_files); + free(all_files); } #endif @@ -2508,35 +2572,36 @@ out: static void ParseGmakeExport(char *line) { - char *variable = line + 6; - char *value; + char *variable = line + 6; + char *value; - DEBUG2(PARSE, "%s: %s\n", __func__, variable); + DEBUG2(PARSE, "%s: %s\n", __func__, variable); - pp_skip_whitespace(&variable); + pp_skip_whitespace(&variable); - for (value = variable; *value && *value != '='; value++) - continue; + for (value = variable; *value && *value != '='; value++) + continue; - if (*value != '=') { - Parse_Error(PARSE_FATAL, + if (*value != '=') { + Parse_Error(PARSE_FATAL, "Variable/Value missing from \"export\""); - return; - } - *value++ = '\0'; /* terminate variable */ - - /* - * Expand the value before putting it in the environment. - */ - (void)Var_Subst(value, VAR_CMDLINE, VARE_WANTRES, &value); - /* TODO: handle errors */ + return; + } + *value++ = '\0'; /* terminate variable */ - setenv(variable, value, 1); - free(value); + /* + * Expand the value before putting it in the environment. + */ + (void)Var_Subst(value, VAR_CMDLINE, VARE_WANTRES, &value); + /* TODO: handle errors */ + + setenv(variable, value, 1); + free(value); } #endif -/* Called when EOF is reached in the current file. If we were reading an +/* + * Called when EOF is reached in the current file. If we were reading an * include file or a .for loop, the includes stack is popped and things set * up to go back to reading the previous file at the previous location. * @@ -2547,221 +2612,246 @@ ParseGmakeExport(char *line) static Boolean ParseEOF(void) { - char *ptr; - size_t len; - IFile *curFile = CurFile(); - - assert(curFile->nextbuf != NULL); - - doing_depend = curFile->depending; /* restore this */ - /* get next input buffer, if any */ - ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); - curFile->buf_ptr = ptr; - curFile->buf_freeIt = ptr; - curFile->buf_end = ptr + len; /* XXX: undefined behavior if ptr == NULL */ - curFile->lineno = curFile->first_lineno; - if (ptr != NULL) - return TRUE; /* Iterate again */ - - /* Ensure the makefile (or loop) didn't have mismatched conditionals */ - Cond_restore_depth(curFile->cond_depth); - - if (curFile->lf != NULL) { - loadedfile_destroy(curFile->lf); - curFile->lf = NULL; - } + char *ptr; + size_t len; + IFile *curFile = CurFile(); + + assert(curFile->nextbuf != NULL); + + doing_depend = curFile->depending; /* restore this */ + /* get next input buffer, if any */ + ptr = curFile->nextbuf(curFile->nextbuf_arg, &len); + curFile->buf_ptr = ptr; + curFile->buf_freeIt = ptr; + curFile->buf_end = ptr + len; /* XXX: undefined behavior if ptr == NULL */ + curFile->lineno = curFile->first_lineno; + if (ptr != NULL) + return TRUE; /* Iterate again */ + + /* Ensure the makefile (or loop) didn't have mismatched conditionals */ + Cond_restore_depth(curFile->cond_depth); + + if (curFile->lf != NULL) { + loadedfile_destroy(curFile->lf); + curFile->lf = NULL; + } + + /* Dispose of curFile info */ + /* Leak curFile->fname because all the gnodes have pointers to it. */ + free(curFile->buf_freeIt); + Vector_Pop(&includes); - /* Dispose of curFile info */ - /* Leak curFile->fname because all the gnodes have pointers to it */ - free(curFile->buf_freeIt); - Vector_Pop(&includes); - - if (includes.len == 0) { - /* We've run out of input */ - Var_Delete(".PARSEDIR", VAR_GLOBAL); - Var_Delete(".PARSEFILE", VAR_GLOBAL); - Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); - Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); - return FALSE; - } + if (includes.len == 0) { + /* We've run out of input */ + Var_Delete(".PARSEDIR", VAR_GLOBAL); + Var_Delete(".PARSEFILE", VAR_GLOBAL); + Var_Delete(".INCLUDEDFROMDIR", VAR_GLOBAL); + Var_Delete(".INCLUDEDFROMFILE", VAR_GLOBAL); + return FALSE; + } - curFile = CurFile(); - DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n", - curFile->fname, curFile->lineno); + curFile = CurFile(); + DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n", + curFile->fname, curFile->lineno); - ParseSetParseFile(curFile->fname); - return TRUE; + ParseSetParseFile(curFile->fname); + return TRUE; } typedef enum GetLineMode { - PARSE_NORMAL, - PARSE_RAW, - PARSE_SKIP + PARSE_NORMAL, + PARSE_RAW, + PARSE_SKIP } GetLineMode; static char * ParseGetLine(GetLineMode mode) { - IFile *cf = CurFile(); - char *ptr; - char ch; - char *line; - char *line_end; - char *escaped; - char *comment; - char *tp; - - /* Loop through blank lines and comment lines */ - for (;;) { - cf->lineno++; - line = cf->buf_ptr; - ptr = line; - line_end = line; - escaped = NULL; - comment = NULL; + IFile *cf = CurFile(); + char *ptr; + char ch; + char *line; + char *line_end; + char *escaped; + char *comment; + char *tp; + + /* Loop through blank lines and comment lines */ for (;;) { - /* XXX: can buf_end ever be null? */ - if (cf->buf_end != NULL && ptr == cf->buf_end) { - /* end of buffer */ - ch = '\0'; - break; - } - ch = *ptr; - if (ch == '\0' || (ch == '\\' && ptr[1] == '\0')) { - /* XXX: can buf_end ever be null? */ - if (cf->buf_end == NULL) - /* End of string (aka for loop) data */ - break; - /* see if there is more we can parse */ - while (ptr++ < cf->buf_end) { - if ((ch = *ptr) == '\n') { - if (ptr > line && ptr[-1] == '\\') - continue; - Parse_Error(PARSE_WARNING, - "Zero byte read from file, " - "skipping rest of line."); - break; - } - } - /* XXX: Can cf->nextbuf ever be NULL? */ - if (cf->nextbuf != NULL) { - /* - * End of this buffer; return EOF and outer logic - * will get the next one. (eww) - */ - break; - } - Parse_Error(PARSE_FATAL, "Zero byte read from file"); - return NULL; - } + cf->lineno++; + line = cf->buf_ptr; + ptr = line; + line_end = line; + escaped = NULL; + comment = NULL; + for (;;) { + /* XXX: can buf_end ever be null? */ + if (cf->buf_end != NULL && ptr == cf->buf_end) { + /* end of buffer */ + ch = '\0'; + break; + } + ch = *ptr; + if (ch == '\0' || (ch == '\\' && ptr[1] == '\0')) { - if (ch == '\\') { - /* Don't treat next character as special, remember first one */ - if (escaped == NULL) - escaped = ptr; - if (ptr[1] == '\n') - cf->lineno++; - ptr += 2; - line_end = ptr; - continue; - } - if (ch == '#' && comment == NULL) { - /* Remember first '#' for comment stripping */ - /* Unless previous char was '[', as in modifier :[#] */ - if (!(ptr > line && ptr[-1] == '[')) - comment = line_end; - } - ptr++; - if (ch == '\n') - break; - if (!ch_isspace(ch)) - /* We are not interested in trailing whitespace */ - line_end = ptr; - } - - /* Save next 'to be processed' location */ - cf->buf_ptr = ptr; - - /* Check we have a non-comment, non-blank line */ - if (line_end == line || comment == line) { - if (ch == '\0') - /* At end of file */ - return NULL; - /* Parse another line */ - continue; - } + /* XXX: can buf_end ever be null? */ + if (cf->buf_end == NULL) + /* End of string (aka for loop) data */ + break; + + /* see if there is more we can parse */ + while (ptr++ < cf->buf_end) { + if ((ch = *ptr) == '\n') { + if (ptr > line && + ptr[-1] == '\\') + continue; + Parse_Error(PARSE_WARNING, + "Zero byte read from file, " + "skipping rest of line."); + break; + } + } + /* XXX: Can cf->nextbuf ever be NULL? */ + if (cf->nextbuf != NULL) { + /* + * End of this buffer; return EOF and + * outer logic will get the next one. + * (eww) + */ + break; + } + Parse_Error(PARSE_FATAL, + "Zero byte read from file"); + return NULL; + } - /* We now have a line of data */ - *line_end = '\0'; + if (ch == '\\') { + /* + * Don't treat next character as special, + * remember first one. + */ + if (escaped == NULL) + escaped = ptr; + if (ptr[1] == '\n') + cf->lineno++; + ptr += 2; + line_end = ptr; + continue; + } + if (ch == '#' && comment == NULL) { + /* + * Remember the first '#' for comment + * stripping, unless the previous char was + * '[', as in the modifier ':[#]'. + */ + if (!(ptr > line && ptr[-1] == '[')) + comment = line_end; + } + ptr++; + if (ch == '\n') + break; + if (!ch_isspace(ch)) { + /* + * We are not interested in trailing + * whitespace. + */ + line_end = ptr; + } + } - if (mode == PARSE_RAW) { - /* Leave '\' (etc) in line buffer (eg 'for' lines) */ - return line; - } + /* Save next 'to be processed' location */ + cf->buf_ptr = ptr; - if (mode == PARSE_SKIP) { - /* Completely ignore non-directives */ - if (line[0] != '.') - continue; - /* We could do more of the .else/.elif/.endif checks here */ - } - break; - } + /* Check we have a non-comment, non-blank line */ + if (line_end == line || comment == line) { + if (ch == '\0') + /* At end of file */ + return NULL; + /* Parse another line */ + continue; + } - /* Brutally ignore anything after a non-escaped '#' in non-commands */ - if (comment != NULL && line[0] != '\t') { - line_end = comment; - *line_end = '\0'; - } + /* We now have a line of data */ + *line_end = '\0'; - /* If we didn't see a '\\' then the in-situ data is fine */ - if (escaped == NULL) - return line; + if (mode == PARSE_RAW) { + /* Leave '\' (etc) in line buffer (eg 'for' lines) */ + return line; + } - /* Remove escapes from '\n' and '#' */ - tp = ptr = escaped; - escaped = line; - for (; ; *tp++ = ch) { - ch = *ptr++; - if (ch != '\\') { - if (ch == '\0') + if (mode == PARSE_SKIP) { + /* Completely ignore non-directives */ + if (line[0] != '.') + continue; + /* + * We could do more of the .else/.elif/.endif checks + * here. + */ + } break; - continue; } - ch = *ptr++; - if (ch == '\0') { - /* Delete '\\' at end of buffer */ - tp--; - break; - } + /* Brutally ignore anything after a non-escaped '#' in non-commands. */ + if (comment != NULL && line[0] != '\t') { + line_end = comment; + *line_end = '\0'; + } + + /* If we didn't see a '\\' then the in-situ data is fine. */ + if (escaped == NULL) + return line; + + /* Remove escapes from '\n' and '#' */ + tp = ptr = escaped; + escaped = line; + for (;; *tp++ = ch) { + ch = *ptr++; + if (ch != '\\') { + if (ch == '\0') + break; + continue; + } - if (ch == '#' && line[0] != '\t') - /* Delete '\\' from before '#' on non-command lines */ - continue; + ch = *ptr++; + if (ch == '\0') { + /* Delete '\\' at end of buffer */ + tp--; + break; + } - if (ch != '\n') { - /* Leave '\\' in buffer for later */ - *tp++ = '\\'; - /* Make sure we don't delete an escaped ' ' from the line end */ - escaped = tp + 1; - continue; - } + if (ch == '#' && line[0] != '\t') + /* Delete '\\' from before '#' on non-command lines */ + continue; + + if (ch != '\n') { + /* Leave '\\' in buffer for later */ + *tp++ = '\\'; + /* + * Make sure we don't delete an escaped ' ' from the + * line end. + */ + escaped = tp + 1; + continue; + } - /* Escaped '\n' -- replace following whitespace with a single ' '. */ - pp_skip_hspace(&ptr); - ch = ' '; - } + /* + * Escaped '\n' -- replace following whitespace with a single + * ' '. + */ + pp_skip_hspace(&ptr); + ch = ' '; + } - /* Delete any trailing spaces - eg from empty continuations */ - while (tp > escaped && ch_isspace(tp[-1])) - tp--; + /* Delete any trailing spaces - eg from empty continuations */ + while (tp > escaped && ch_isspace(tp[-1])) + tp--; - *tp = '\0'; - return line; + *tp = '\0'; + return line; } -/* Read an entire line from the input file. Called only by Parse_File. +/* + * Read an entire line from the input file. Called only by Parse_File. * * Results: * A line without its newline and without any trailing whitespace. @@ -2769,193 +2859,201 @@ ParseGetLine(GetLineMode mode) static char * ParseReadLine(void) { - char *line; /* Result */ - int lineno; /* Saved line # */ - int rval; - - for (;;) { - line = ParseGetLine(PARSE_NORMAL); - if (line == NULL) - return NULL; - - if (line[0] != '.') - return line; - - /* - * The line might be a conditional. Ask the conditional module - * about it and act accordingly - */ - switch (Cond_EvalLine(line)) { - case COND_SKIP: - /* Skip to next conditional that evaluates to COND_PARSE. */ - do { - line = ParseGetLine(PARSE_SKIP); - } while (line && Cond_EvalLine(line) != COND_PARSE); - if (line == NULL) - break; - continue; - case COND_PARSE: - continue; - case COND_INVALID: /* Not a conditional line */ - /* Check for .for loops */ - rval = For_Eval(line); - if (rval == 0) - /* Not a .for line */ - break; - if (rval < 0) - /* Syntax error - error printed, ignore line */ - continue; - /* Start of a .for loop */ - lineno = CurFile()->lineno; - /* Accumulate loop lines until matching .endfor */ - do { - line = ParseGetLine(PARSE_RAW); - if (line == NULL) { - Parse_Error(PARSE_FATAL, - "Unexpected end of file in for loop."); - break; - } - } while (For_Accum(line)); - /* Stash each iteration as a new 'input file' */ - For_Run(lineno); - /* Read next line from for-loop buffer */ - continue; + char *line; /* Result */ + int lineno; /* Saved line # */ + int rval; + + for (;;) { + line = ParseGetLine(PARSE_NORMAL); + if (line == NULL) + return NULL; + + if (line[0] != '.') + return line; + + /* + * The line might be a conditional. Ask the conditional module + * about it and act accordingly + */ + switch (Cond_EvalLine(line)) { + case COND_SKIP: + /* + * Skip to next conditional that evaluates to + * COND_PARSE. + */ + do { + line = ParseGetLine(PARSE_SKIP); + } while (line && Cond_EvalLine(line) != COND_PARSE); + if (line == NULL) + break; + continue; + case COND_PARSE: + continue; + case COND_INVALID: /* Not a conditional line */ + /* Check for .for loops */ + rval = For_Eval(line); + if (rval == 0) + /* Not a .for line */ + break; + if (rval < 0) + /* Syntax error - error printed, ignore line */ + continue; + /* Start of a .for loop */ + lineno = CurFile()->lineno; + /* Accumulate loop lines until matching .endfor */ + do { + line = ParseGetLine(PARSE_RAW); + if (line == NULL) { + Parse_Error(PARSE_FATAL, + "Unexpected end of file " + "in for loop."); + break; + } + } while (For_Accum(line)); + /* Stash each iteration as a new 'input file' */ + For_Run(lineno); + /* Read next line from for-loop buffer */ + continue; + } + return line; } - return line; - } } static void FinishDependencyGroup(void) { - GNodeListNode *ln; + GNodeListNode *ln; - if (targets == NULL) - return; + if (targets == NULL) + return; - for (ln = targets->first; ln != NULL; ln = ln->next) { - GNode *gn = ln->datum; + for (ln = targets->first; ln != NULL; ln = ln->next) { + GNode *gn = ln->datum; - Suff_EndTransform(gn); + Suff_EndTransform(gn); - /* Mark the target as already having commands if it does, to - * keep from having shell commands on multiple dependency lines. */ - if (!Lst_IsEmpty(&gn->commands)) - gn->type |= OP_HAS_COMMANDS; - } + /* + * Mark the target as already having commands if it does, to + * keep from having shell commands on multiple dependency + * lines. + */ + if (!Lst_IsEmpty(&gn->commands)) + gn->type |= OP_HAS_COMMANDS; + } - Lst_Free(targets); - targets = NULL; + Lst_Free(targets); + targets = NULL; } /* Add the command to each target from the current dependency spec. */ static void ParseLine_ShellCommand(const char *p) { - cpp_skip_whitespace(&p); - if (*p == '\0') - return; /* skip empty commands */ - - if (targets == NULL) { - Parse_Error(PARSE_FATAL, "Unassociated shell command \"%s\"", p); - return; - } - - { - char *cmd = bmake_strdup(p); - GNodeListNode *ln; + cpp_skip_whitespace(&p); + if (*p == '\0') + return; /* skip empty commands */ - for (ln = targets->first; ln != NULL; ln = ln->next) { - GNode *gn = ln->datum; - ParseAddCmd(gn, cmd); + if (targets == NULL) { + Parse_Error(PARSE_FATAL, + "Unassociated shell command \"%s\"", p); + return; } + + { + char *cmd = bmake_strdup(p); + GNodeListNode *ln; + + for (ln = targets->first; ln != NULL; ln = ln->next) { + GNode *gn = ln->datum; + ParseAddCmd(gn, cmd); + } #ifdef CLEANUP - Lst_Append(&targCmds, cmd); + Lst_Append(&targCmds, cmd); #endif - } + } } static Boolean ParseDirective(char *line) { - char *cp; + char *cp; - if (*line == '.') { - /* - * Lines that begin with '.' can be pretty much anything: - * - directives like '.include' or '.if', - * - suffix rules like '.c.o:', - * - dependencies for filenames that start with '.', - * - variable assignments like '.tmp=value'. - */ - cp = line + 1; - pp_skip_whitespace(&cp); - if (IsInclude(cp, FALSE)) { - ParseDoInclude(cp); - return TRUE; - } - if (strncmp(cp, "undef", 5) == 0) { - const char *varname; - cp += 5; - pp_skip_whitespace(&cp); - varname = cp; - for (; !ch_isspace(*cp) && *cp != '\0'; cp++) - continue; - *cp = '\0'; - Var_Delete(varname, VAR_GLOBAL); - /* TODO: undefine all variables, not only the first */ - /* TODO: use Str_Words, like everywhere else */ - return TRUE; - } else if (strncmp(cp, "export", 6) == 0) { - cp += 6; - pp_skip_whitespace(&cp); - Var_Export(cp, TRUE); - return TRUE; - } else if (strncmp(cp, "unexport", 8) == 0) { - Var_UnExport(cp); - return TRUE; - } else if (strncmp(cp, "info", 4) == 0 || - strncmp(cp, "error", 5) == 0 || - strncmp(cp, "warning", 7) == 0) { - if (ParseMessage(cp)) - return TRUE; + if (*line == '.') { + /* + * Lines that begin with '.' can be pretty much anything: + * - directives like '.include' or '.if', + * - suffix rules like '.c.o:', + * - dependencies for filenames that start with '.', + * - variable assignments like '.tmp=value'. + */ + cp = line + 1; + pp_skip_whitespace(&cp); + if (IsInclude(cp, FALSE)) { + ParseDoInclude(cp); + return TRUE; + } + if (strncmp(cp, "undef", 5) == 0) { + const char *varname; + cp += 5; + pp_skip_whitespace(&cp); + varname = cp; + for (; !ch_isspace(*cp) && *cp != '\0'; cp++) + continue; + *cp = '\0'; + Var_Delete(varname, VAR_GLOBAL); + /* TODO: undefine all variables, not only the first */ + /* TODO: use Str_Words, like everywhere else */ + return TRUE; + } else if (strncmp(cp, "export", 6) == 0) { + cp += 6; + pp_skip_whitespace(&cp); + Var_Export(cp, TRUE); + return TRUE; + } else if (strncmp(cp, "unexport", 8) == 0) { + Var_UnExport(cp); + return TRUE; + } else if (strncmp(cp, "info", 4) == 0 || + strncmp(cp, "error", 5) == 0 || + strncmp(cp, "warning", 7) == 0) { + if (ParseMessage(cp)) + return TRUE; + } } - } - return FALSE; + return FALSE; } static Boolean ParseVarassign(const char *line) { - VarAssign var; + VarAssign var; - if (!Parse_IsVar(line, &var)) - return FALSE; + if (!Parse_IsVar(line, &var)) + return FALSE; - FinishDependencyGroup(); - Parse_DoVar(&var, VAR_GLOBAL); - return TRUE; + FinishDependencyGroup(); + Parse_DoVar(&var, VAR_GLOBAL); + return TRUE; } static char * FindSemicolon(char *p) { - int level = 0; + int level = 0; + + for (; *p != '\0'; p++) { + if (*p == '\\' && p[1] != '\0') { + p++; + continue; + } - for (; *p != '\0'; p++) { - if (*p == '\\' && p[1] != '\0') { - p++; - continue; - } - - if (*p == '$' && (p[1] == '(' || p[1] == '{')) - level++; - else if (level > 0 && (*p == ')' || *p == '}')) - level--; - else if (level == 0 && *p == ';') - break; - } - return p; + if (*p == '$' && (p[1] == '(' || p[1] == '{')) + level++; + else if (level > 0 && (*p == ')' || *p == '}')) + level--; + else if (level == 0 && *p == ';') + break; + } + return p; } /* dependency -> target... op [source...] @@ -2963,112 +3061,113 @@ FindSemicolon(char *p) static void ParseDependency(char *line) { - VarEvalFlags eflags; - char *expanded_line; - const char *shellcmd = NULL; - - /* - * For some reason - probably to make the parser impossible - - * a ';' can be used to separate commands from dependencies. - * Attempt to avoid ';' inside substitution patterns. - */ - { - char *semicolon = FindSemicolon(line); - if (*semicolon != '\0') { - /* Terminate the dependency list at the ';' */ - *semicolon = '\0'; - shellcmd = semicolon + 1; - } - } - - /* - * We now know it's a dependency line so it needs to have all - * variables expanded before being parsed. - * - * XXX: Ideally the dependency line would first be split into - * its left-hand side, dependency operator and right-hand side, - * and then each side would be expanded on its own. This would - * allow for the left-hand side to allow only defined variables - * and to allow variables on the right-hand side to be undefined - * as well. - * - * Parsing the line first would also prevent that targets - * generated from variable expressions are interpreted as the - * dependency operator, such as in "target${:U\:} middle: source", - * in which the middle is interpreted as a source, not a target. - */ - - /* In lint mode, allow undefined variables to appear in - * dependency lines. - * - * Ideally, only the right-hand side would allow undefined - * variables since it is common to have optional dependencies. - * Having undefined variables on the left-hand side is more - * unusual though. Since both sides are expanded in a single - * pass, there is not much choice what to do here. - * - * In normal mode, it does not matter whether undefined - * variables are allowed or not since as of 2020-09-14, - * Var_Parse does not print any parse errors in such a case. - * It simply returns the special empty string var_Error, - * which cannot be detected in the result of Var_Subst. */ - eflags = opts.lint ? VARE_WANTRES : VARE_WANTRES | VARE_UNDEFERR; - (void)Var_Subst(line, VAR_CMDLINE, eflags, &expanded_line); - /* TODO: handle errors */ + VarEvalFlags eflags; + char *expanded_line; + const char *shellcmd = NULL; - /* Need a fresh list for the target nodes */ - if (targets != NULL) - Lst_Free(targets); - targets = Lst_New(); + /* + * For some reason - probably to make the parser impossible - + * a ';' can be used to separate commands from dependencies. + * Attempt to avoid ';' inside substitution patterns. + */ + { + char *semicolon = FindSemicolon(line); + if (*semicolon != '\0') { + /* Terminate the dependency list at the ';' */ + *semicolon = '\0'; + shellcmd = semicolon + 1; + } + } - ParseDoDependency(expanded_line); - free(expanded_line); + /* + * We now know it's a dependency line so it needs to have all + * variables expanded before being parsed. + * + * XXX: Ideally the dependency line would first be split into + * its left-hand side, dependency operator and right-hand side, + * and then each side would be expanded on its own. This would + * allow for the left-hand side to allow only defined variables + * and to allow variables on the right-hand side to be undefined + * as well. + * + * Parsing the line first would also prevent that targets + * generated from variable expressions are interpreted as the + * dependency operator, such as in "target${:U\:} middle: source", + * in which the middle is interpreted as a source, not a target. + */ - if (shellcmd != NULL) - ParseLine_ShellCommand(shellcmd); + /* In lint mode, allow undefined variables to appear in + * dependency lines. + * + * Ideally, only the right-hand side would allow undefined + * variables since it is common to have optional dependencies. + * Having undefined variables on the left-hand side is more + * unusual though. Since both sides are expanded in a single + * pass, there is not much choice what to do here. + * + * In normal mode, it does not matter whether undefined + * variables are allowed or not since as of 2020-09-14, + * Var_Parse does not print any parse errors in such a case. + * It simply returns the special empty string var_Error, + * which cannot be detected in the result of Var_Subst. */ + eflags = opts.lint ? VARE_WANTRES : VARE_WANTRES | VARE_UNDEFERR; + (void)Var_Subst(line, VAR_CMDLINE, eflags, &expanded_line); + /* TODO: handle errors */ + + /* Need a fresh list for the target nodes */ + if (targets != NULL) + Lst_Free(targets); + targets = Lst_New(); + + ParseDoDependency(expanded_line); + free(expanded_line); + + if (shellcmd != NULL) + ParseLine_ShellCommand(shellcmd); } static void ParseLine(char *line) { - if (ParseDirective(line)) - return; + if (ParseDirective(line)) + return; - if (*line == '\t') { - ParseLine_ShellCommand(line + 1); - return; - } + if (*line == '\t') { + ParseLine_ShellCommand(line + 1); + return; + } #ifdef SYSVINCLUDE - if (IsSysVInclude(line)) { - /* - * It's an S3/S5-style "include". - */ - ParseTraditionalInclude(line); - return; - } + if (IsSysVInclude(line)) { + /* + * It's an S3/S5-style "include". + */ + ParseTraditionalInclude(line); + return; + } #endif #ifdef GMAKEEXPORT - if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) && - strchr(line, ':') == NULL) { - /* - * It's a Gmake "export". - */ - ParseGmakeExport(line); - return; - } + if (strncmp(line, "export", 6) == 0 && ch_isspace(line[6]) && + strchr(line, ':') == NULL) { + /* + * It's a Gmake "export". + */ + ParseGmakeExport(line); + return; + } #endif - if (ParseVarassign(line)) - return; + if (ParseVarassign(line)) + return; - FinishDependencyGroup(); + FinishDependencyGroup(); - ParseDependency(line); + ParseDependency(line); } -/* Parse a top-level makefile, incorporating its content into the global +/* + * Parse a top-level makefile, incorporating its content into the global * dependency graph. * * Input: @@ -3078,51 +3177,49 @@ ParseLine(char *line) void Parse_File(const char *name, int fd) { - char *line; /* the line we're working on */ - struct loadedfile *lf; + char *line; /* the line we're working on */ + struct loadedfile *lf; - lf = loadfile(name, fd); + lf = loadfile(name, fd); - assert(targets == NULL); + assert(targets == NULL); - if (name == NULL) - name = "(stdin)"; + if (name == NULL) + name = "(stdin)"; - Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); - CurFile()->lf = lf; + Parse_SetInput(name, 0, -1, loadedfile_nextbuf, lf); + CurFile()->lf = lf; - do { - while ((line = ParseReadLine()) != NULL) { - DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n", - CurFile()->lineno, line); - ParseLine(line); - } - /* - * Reached EOF, but it may be just EOF of an include file... - */ - } while (ParseEOF()); + do { + while ((line = ParseReadLine()) != NULL) { + DEBUG2(PARSE, "ParseReadLine (%d): '%s'\n", + CurFile()->lineno, line); + ParseLine(line); + } + /* Reached EOF, but it may be just EOF of an include file. */ + } while (ParseEOF()); - FinishDependencyGroup(); + FinishDependencyGroup(); - if (fatals != 0) { - (void)fflush(stdout); - (void)fprintf(stderr, - "%s: Fatal errors encountered -- cannot continue", - progname); - PrintOnError(NULL, NULL); - exit(1); - } + if (fatals != 0) { + (void)fflush(stdout); + (void)fprintf(stderr, + "%s: Fatal errors encountered -- cannot continue", + progname); + PrintOnError(NULL, NULL); + exit(1); + } } /* Initialize the parsing module. */ void Parse_Init(void) { - mainNode = NULL; - parseIncPath = SearchPath_New(); - sysIncPath = SearchPath_New(); - defSysIncPath = SearchPath_New(); - Vector_Init(&includes, sizeof(IFile)); + mainNode = NULL; + parseIncPath = SearchPath_New(); + sysIncPath = SearchPath_New(); + defSysIncPath = SearchPath_New(); + Vector_Init(&includes, sizeof(IFile)); } /* Clean up the parsing module. */ @@ -3130,13 +3227,13 @@ void Parse_End(void) { #ifdef CLEANUP - Lst_DoneCall(&targCmds, free); - assert(targets == NULL); - SearchPath_Free(defSysIncPath); - SearchPath_Free(sysIncPath); - SearchPath_Free(parseIncPath); - assert(includes.len == 0); - Vector_Done(&includes); + Lst_DoneCall(&targCmds, free); + assert(targets == NULL); + SearchPath_Free(defSysIncPath); + SearchPath_Free(sysIncPath); + SearchPath_Free(parseIncPath); + assert(includes.len == 0); + Vector_Done(&includes); #endif } @@ -3148,20 +3245,20 @@ Parse_End(void) void Parse_MainName(GNodeList *mainList) { - if (mainNode == NULL) - Punt("no target to make."); + if (mainNode == NULL) + Punt("no target to make."); - if (mainNode->type & OP_DOUBLEDEP) { - Lst_Append(mainList, mainNode); - Lst_AppendAll(mainList, &mainNode->cohorts); - } else - Lst_Append(mainList, mainNode); + if (mainNode->type & OP_DOUBLEDEP) { + Lst_Append(mainList, mainNode); + Lst_AppendAll(mainList, &mainNode->cohorts); + } else + Lst_Append(mainList, mainNode); - Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); + Var_Append(".TARGETS", mainNode->name, VAR_GLOBAL); } int Parse_GetFatals(void) { - return fatals; + return fatals; }