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++;

Reply via email to