Module Name: src Committed By: rillig Date: Mon Oct 5 16:33:20 UTC 2020
Modified Files: src/usr.bin/make: parse.c Log Message: make(1): split ParseDoDependency into several smaller functions To generate a diff of this commit: cvs rdiff -u -r1.363 -r1.364 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.363 src/usr.bin/make/parse.c:1.364 --- src/usr.bin/make/parse.c:1.363 Mon Oct 5 15:43:32 2020 +++ src/usr.bin/make/parse.c Mon Oct 5 16:33:20 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.363 2020/10/05 15:43:32 rillig Exp $ */ +/* $NetBSD: parse.c,v 1.364 2020/10/05 16:33:20 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -131,7 +131,7 @@ #include "pathnames.h" /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: parse.c,v 1.363 2020/10/05 15:43:32 rillig Exp $"); +MAKE_RCSID("$NetBSD: parse.c,v 1.364 2020/10/05 16:33:20 rillig Exp $"); /* types and constants */ @@ -204,6 +204,8 @@ typedef enum { Attribute /* Generic attribute */ } ParseSpecial; +typedef List SearchPathList; + /* result data */ /* @@ -1110,6 +1112,357 @@ ParseDependencyTargetWord(/*const*/ char *pp = cp; } +/* + * Certain special targets have special semantics: + * .PATH Have to set the dirSearchPath + * variable too + * .MAIN Its sources are only used if + * nothing has been specified to + * create. + * .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, so we + * create it, set OP_NOTMAIN and + * add it to the list, setting + * DEFAULT to the new node for + * later use. 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. + * .PHONY The list of targets + * .NOPATH Don't search for file in the path + * .STALE + * .BEGIN + * .END + * .ERROR + * .DELETE_ON_ERROR + * .INTERRUPT Are not to be considered the + * main target. + * .NOTPARALLEL Make only one target at a time. + * .SINGLESHELL Create a shell for each command. + * .ORDER Must set initial predecessor to NULL + */ +static void +ParseDoDependencyTargetSpecial(ParseSpecial *const inout_specType, + const char *const line, + SearchPathList **const inout_paths) +{ + switch (*inout_specType) { + case ExPath: + if (*inout_paths == NULL) { + *inout_paths = Lst_Init(); + } + Lst_Append(*inout_paths, dirSearchPath); + break; + case Main: + if (!Lst_IsEmpty(create)) { + *inout_specType = Not; + } + break; + case Begin: + case End: + case Stale: + case dotError: + case Interrupt: { + GNode *gn = Targ_GetNode(line); + if (doing_depend) + ParseMark(gn); + gn->type |= OP_NOTMAIN|OP_SPECIAL; + Lst_Append(targets, gn); + break; + } + case Default: { + GNode *gn = Targ_NewGN(".DEFAULT"); + gn->type |= OP_NOTMAIN|OP_TRANSFORM; + Lst_Append(targets, gn); + DEFAULT = gn; + break; + } + case DeleteOnError: + deleteOnError = TRUE; + break; + case NotParallel: + maxJobs = 1; + break; + case SingleShell: + compatMake = TRUE; + break; + case Order: + predecessor = NULL; + break; + default: + break; + } +} + +/* + * .PATH<suffix> has to be handled specially. + * Call on the suffix module to give us a path to modify. + */ +static Boolean +ParseDoDependencyTargetPath(const char *const line, + SearchPathList **const inout_paths) +{ + SearchPath *path; + + path = Suff_GetPath(&line[5]); + if (path == NULL) { + Parse_Error(PARSE_FATAL, + "Suffix '%s' not defined (yet)", + &line[5]); + return FALSE; + } else { + if (*inout_paths == NULL) { + *inout_paths = Lst_Init(); + } + Lst_Append(*inout_paths, path); + } + return TRUE; +} + +/* + * See if it's a special target and if so set specType to match it. + */ +static Boolean +ParseDoDependencyTarget(const char *const line, + ParseSpecial *const inout_specType, + GNodeType *out_tOp, + SearchPathList **inout_paths) +{ + int keywd; + + 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 == ExPath && parseKeywords[keywd].spec != ExPath) { + 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 = ExPath; + if (!ParseDoDependencyTargetPath(line, inout_paths)) + return FALSE; + } + return TRUE; +} + +static void +ParseDoDependencyTargetMundane(char *const line, + StringList *const 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 = Lst_Init(); + + Dir_Expand(line, emptyPath, curTargs); + + Lst_Destroy(emptyPath, Dir_Destroy); + } 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. */ + + 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); + + Lst_Append(targets, gn); + } +} + +static void +ParseDoDependencyTargetExtraWarn(char **pp, const char *lstart) +{ + Boolean warning = FALSE; + char *cp = *pp; + + while (*cp && (ParseIsEscaped(lstart, cp) || + (*cp != '!' && *cp != ':'))) { + if (ParseIsEscaped(lstart, cp) || + (*cp != ' ' && *cp != '\t')) { + warning = TRUE; + } + cp++; + } + if (warning) { + Parse_Error(PARSE_WARNING, "Extra target ignored"); + } + *pp = cp; +} + +static void +ParseDoDependencyCheckSpec(ParseSpecial const specType) +{ + switch(specType) { + default: + Parse_Error(PARSE_WARNING, + "Special and mundane targets don't mix. Mundane ones ignored"); + break; + case Default: + case Stale: + case Begin: + case End: + case dotError: + case Interrupt: + /* + * These four create nodes on which to hang commands, so + * targets shouldn't be empty... + */ + case Not: + /* + * Nothing special here -- targets can be empty if it wants. + */ + break; + } +} + +static Boolean +ParseDoDependencyParseOp(char **const pp, const char *const lstart, + GNodeType *const out_op) +{ + const char *cp = *pp; + + 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)++; + } + return TRUE; + } + + { + const char *msg = lstart[0] == '.' ? "Unknown directive" + : "Missing dependency operator"; + Parse_Error(PARSE_FATAL, "%s", msg); + return FALSE; + } +} + +static void +ParseDoDependencySourcesEmpty(ParseSpecial const specType, + SearchPathList *const paths) +{ + switch (specType) { + case Suffixes: + Suff_ClearSuffixes(); + break; + case Precious: + allPrecious = TRUE; + break; + case Ignore: + ignoreErrors = TRUE; + break; + case Silent: + beSilent = TRUE; + break; + case ExPath: + if (paths != NULL) + Lst_ForEach(paths, ParseClearPath, NULL); + Dir_SetPATH(); + break; +#ifdef POSIX + case Posix: + Var_Set("%POSIX", "1003.2", VAR_GLOBAL); + break; +#endif + default: + break; + } +} + +/* + * If the target was one that doesn't take files as its sources + * but takes something like suffixes, we take each + * space-separated word on the line as a something and deal + * with it accordingly. + * + * If the target was .SUFFIXES, we take each source as a + * suffix and add it to the list of suffixes maintained by the + * Suff module. + * + * If the target was a .PATH, we add the source as a directory + * to search on the search path. + * + * If it was .INCLUDES, the source is taken to be the suffix of + * files which will be #included and whose search path should + * be present in the .INCLUDES variable. + * + * If it was .LIBS, the source is taken to be the suffix of + * files which are considered libraries and whose search path + * should be present in the .LIBS variable. + * + * If it was .NULL, the source is the suffix to use when a file + * has no valid suffix. + * + * If it was .OBJDIR, the source is a new definition for .OBJDIR, + * and will cause make to do a new chdir to that path. + */ +static void +ParseDoDependencySourceSpecial(ParseSpecial const specType, char *const line, + SearchPathList *const paths) +{ + switch (specType) { + case Suffixes: + Suff_AddSuffix(line, &mainNode); + break; + case ExPath: + if (paths != NULL) + Lst_ForEach(paths, ParseAddDir, line); + break; + case Includes: + Suff_AddInclude(line); + break; + case Libs: + Suff_AddLib(line); + break; + case Null: + Suff_SetNull(line); + break; + case ExObjdir: + Main_SetObjdir("%s", line); + break; + default: + break; + } +} + /* Parse a dependency line consisting of targets, followed by a dependency * operator, optionally followed by sources. * @@ -1138,8 +1491,6 @@ ParseDependencyTargetWord(/*const*/ char static void ParseDoDependency(char *line) { - typedef List SearchPathList; - char *cp; /* our current position */ GNodeType op; /* the operator on the line */ char savec; /* a place to save a character */ @@ -1214,164 +1565,15 @@ ParseDoDependency(char *line) savec = *cp; *cp = '\0'; - /* - * Got the word. See if it's a special target and if so set - * specType to match it. - */ - if (*line == '.' && ch_isupper(line[1])) { - /* - * See if the target is a special target that must have it - * or its sources handled specially. - */ - int keywd = ParseFindKeyword(line); - if (keywd != -1) { - if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { - Parse_Error(PARSE_FATAL, "Mismatched special targets"); - goto out; - } - - specType = parseKeywords[keywd].spec; - tOp = parseKeywords[keywd].op; - - /* - * Certain special targets have special semantics: - * .PATH Have to set the dirSearchPath - * variable too - * .MAIN Its sources are only used if - * nothing has been specified to - * create. - * .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, so we - * create it, set OP_NOTMAIN and - * add it to the list, setting - * DEFAULT to the new node for - * later use. 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. - * .PHONY The list of targets - * .NOPATH Don't search for file in the path - * .STALE - * .BEGIN - * .END - * .ERROR - * .DELETE_ON_ERROR - * .INTERRUPT Are not to be considered the - * main target. - * .NOTPARALLEL Make only one target at a time. - * .SINGLESHELL Create a shell for each command. - * .ORDER Must set initial predecessor to NULL - */ - switch (specType) { - case ExPath: - if (paths == NULL) { - paths = Lst_Init(); - } - Lst_Append(paths, dirSearchPath); - break; - case Main: - if (!Lst_IsEmpty(create)) { - specType = Not; - } - break; - case Begin: - case End: - case Stale: - case dotError: - case Interrupt: { - GNode *gn = Targ_GetNode(line); - if (doing_depend) - ParseMark(gn); - gn->type |= OP_NOTMAIN|OP_SPECIAL; - Lst_Append(targets, gn); - break; - } - case Default: { - GNode *gn = Targ_NewGN(".DEFAULT"); - gn->type |= OP_NOTMAIN|OP_TRANSFORM; - Lst_Append(targets, gn); - DEFAULT = gn; - break; - } - case DeleteOnError: - deleteOnError = TRUE; - break; - case NotParallel: - maxJobs = 1; - break; - case SingleShell: - compatMake = TRUE; - break; - case Order: - predecessor = NULL; - break; - default: - break; - } - } else if (strncmp(line, ".PATH", 5) == 0) { - /* - * .PATH<suffix> has to be handled specially. - * Call on the suffix module to give us a path to - * modify. - */ - SearchPath *path; - - specType = ExPath; - path = Suff_GetPath(&line[5]); - if (path == NULL) { - Parse_Error(PARSE_FATAL, - "Suffix '%s' not defined (yet)", - &line[5]); - goto out; - } else { - if (paths == NULL) { - paths = Lst_Init(); - } - Lst_Append(paths, path); - } - } - } + if (!ParseDoDependencyTarget(line, &specType, &tOp, &paths)) + goto out; /* * Have word in line. Get or create its node and stick it at * the end of the targets list */ if (specType == Not && *line != '\0') { - 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 = Lst_Init(); - - Dir_Expand(line, emptyPath, curTargs); - - Lst_Destroy(emptyPath, Dir_Destroy); - } 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. */ - - 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); - - Lst_Append(targets, gn); - } + ParseDoDependencyTargetMundane(line, curTargs); } else if (specType == ExPath && *line != '.' && *line != '\0') { Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); } @@ -1384,19 +1586,7 @@ ParseDoDependency(char *line) * allow on this line... */ if (specType != Not && specType != ExPath) { - Boolean warning = FALSE; - - while (*cp && (ParseIsEscaped(lstart, cp) || - (*cp != '!' && *cp != ':'))) { - if (ParseIsEscaped(lstart, cp) || - (*cp != ' ' && *cp != '\t')) { - warning = TRUE; - } - cp++; - } - if (warning) { - Parse_Error(PARSE_WARNING, "Extra target ignored"); - } + ParseDoDependencyTargetExtraWarn(&cp, lstart); } else { pp_skip_whitespace(&cp); } @@ -1413,50 +1603,14 @@ ParseDoDependency(char *line) Lst_Free(curTargs); curTargs = NULL; - if (!Lst_IsEmpty(targets)) { - switch(specType) { - default: - Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); - break; - case Default: - case Stale: - case Begin: - case End: - case dotError: - case Interrupt: - /* - * These four create nodes on which to hang commands, so - * targets shouldn't be empty... - */ - case Not: - /* - * Nothing special here -- targets can be empty if it wants. - */ - break; - } - } + if (!Lst_IsEmpty(targets)) + ParseDoDependencyCheckSpec(specType); /* - * Have now parsed all the target names. Must parse the operator next. The - * result is left in op . + * Have now parsed all the target names. Must parse the operator next. */ - if (*cp == '!') { - op = OP_FORCE; - } else if (*cp == ':') { - if (cp[1] == ':') { - op = OP_DOUBLEDEP; - cp++; - } else { - op = OP_DEPENDS; - } - } else { - Parse_Error(PARSE_FATAL, lstart[0] == '.' ? "Unknown directive" - : "Missing dependency operator"); - goto out; - } - - /* Advance beyond the operator */ - cp++; + if (!ParseDoDependencyParseOp(&cp, lstart, &op)) + goto out; /* * Apply the operator to the target. This is how we remember which @@ -1484,32 +1638,7 @@ ParseDoDependency(char *line) * a .PATH removes all directories from the search path(s). */ if (!*line) { - switch (specType) { - case Suffixes: - Suff_ClearSuffixes(); - break; - case Precious: - allPrecious = TRUE; - break; - case Ignore: - ignoreErrors = TRUE; - break; - case Silent: - beSilent = TRUE; - break; - case ExPath: - if (paths != NULL) - Lst_ForEach(paths, ParseClearPath, NULL); - Dir_SetPATH(); - break; -#ifdef POSIX - case Posix: - Var_Set("%POSIX", "1003.2", VAR_GLOBAL); - break; -#endif - default: - break; - } + ParseDoDependencySourcesEmpty(specType, paths); } else if (specType == MFlags) { /* * Call on functions in main.c to deal with these arguments and @@ -1537,61 +1666,12 @@ ParseDoDependency(char *line) specType == Null || specType == ExObjdir) { while (*line) { - /* - * If the target was one that doesn't take files as its sources - * but takes something like suffixes, we take each - * space-separated word on the line as a something and deal - * with it accordingly. - * - * If the target was .SUFFIXES, we take each source as a - * suffix and add it to the list of suffixes maintained by the - * Suff module. - * - * If the target was a .PATH, we add the source as a directory - * to search on the search path. - * - * If it was .INCLUDES, the source is taken to be the suffix of - * files which will be #included and whose search path should - * be present in the .INCLUDES variable. - * - * If it was .LIBS, the source is taken to be the suffix of - * files which are considered libraries and whose search path - * should be present in the .LIBS variable. - * - * If it was .NULL, the source is the suffix to use when a file - * has no valid suffix. - * - * If it was .OBJDIR, the source is a new definition for .OBJDIR, - * and will cause make to do a new chdir to that path. - */ while (*cp && !ch_isspace(*cp)) { cp++; } savec = *cp; *cp = '\0'; - switch (specType) { - case Suffixes: - Suff_AddSuffix(line, &mainNode); - break; - case ExPath: - if (paths != NULL) - Lst_ForEach(paths, ParseAddDir, line); - break; - case Includes: - Suff_AddInclude(line); - break; - case Libs: - Suff_AddLib(line); - break; - case Null: - Suff_SetNull(line); - break; - case ExObjdir: - Main_SetObjdir("%s", line); - break; - default: - break; - } + ParseDoDependencySourceSpecial(specType, line, paths); *cp = savec; if (savec != '\0') { cp++;