⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
    } else if (specType == 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 == ExShell) {	if (Job_ParseShell (line) != SUCCESS) {	    Parse_Error (PARSE_FATAL, "improper shell specification");	    return;	}	*line = '\0';    } else if ((specType == NotParallel) || (specType == SingleShell)) {	*line = '\0';    }        /*     * NOW GO FOR THE SOURCES      */    if ((specType == Suffixes) || (specType == ExPath) ||	(specType == Includes) || (specType == Libs) ||	(specType == Null))    {	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.	     */	    char  savec;	    while (*cp && !isspace (*cp)) {		cp++;	    }	    savec = *cp;	    *cp = '\0';	    switch (specType) {		case Suffixes:		    Suff_AddSuffix (line);		    break;		case ExPath:		    Lst_ForEach(paths, ParseAddDir, (ClientData)line);		    break;		case Includes:		    Suff_AddInclude (line);		    break;		case Libs:		    Suff_AddLib (line);		    break;		case Null:		    Suff_SetNull (line);		    break;		default:		    break;	    }	    *cp = savec;	    if (savec != '\0') {		cp++;	    }	    while (*cp && isspace (*cp)) {		cp++;	    }	    line = cp;	}	if (paths) {	    Lst_Destroy(paths, NOFREE);	}    } else {	while (*line) {	    /*	     * The targets take real sources, so we must beware of archive	     * specifications (i.e. things with left parentheses in them)	     * and handle them accordingly.	     */	    while (*cp && !isspace (*cp)) {		if ((*cp == '(') && (cp > line) && (cp[-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;		} else {		    cp++;		}	    }	    if (*cp == '(') {		GNode	  *gn;		sources = Lst_Init (FALSE);		if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {		    Parse_Error (PARSE_FATAL,				 "Error in source archive spec \"%s\"", line);		    return;		}		while (!Lst_IsEmpty (sources)) {		    gn = (GNode *) Lst_DeQueue (sources);		    ParseDoSrc (tOp, gn->name);		}		Lst_Destroy (sources, NOFREE);		cp = line;	    } else {		if (*cp) {		    *cp = '\0';		    cp += 1;		}		ParseDoSrc (tOp, line);	    }	    while (*cp && isspace (*cp)) {		cp++;	    }	    line = cp;	}    }        if (mainNode == NILGNODE) {	/*	 * 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.	 */	Lst_ForEach (targets, ParseFindMain, (ClientData)0);    }}/*- *--------------------------------------------------------------------- * Parse_IsVar  -- *	Return TRUE if the passed line is a variable assignment. A variable *	assignment consists of a single word followed by optional whitespace *	followed by either a += or an = operator. *	This function is used both by the Parse_File function and main when *	parsing the command-line arguments. * * Results: *	TRUE if it is. FALSE if it ain't * * Side Effects: *	none *--------------------------------------------------------------------- */BooleanParse_IsVar (line)    register char  *line;	/* the line to check */{    register Boolean wasSpace = FALSE;	/* set TRUE if found a space */    register Boolean haveName = FALSE;	/* Set TRUE if have a variable name */    /*     * Skip to variable name     */    while ((*line == ' ') || (*line == '\t')) {	line++;    }    while (*line != '=') {	if (*line == '\0') {	    /*	     * end-of-line -- can't be a variable assignment.	     */	    return (FALSE);	} else if ((*line == ' ') || (*line == '\t')) {	    /*	     * there can be as much white space as desired so long as there is	     * only one word before the operator 	     */	    wasSpace = TRUE;	} else if (wasSpace && haveName) {	    /*	     * Stop when an = operator is found.	     */	    if ((*line == '+') || (*line == ':') || (*line == '?') || 		(*line == '!')) {		break;    	    }	    /*	     * This is the start of another word, so not assignment.	     */	    return (FALSE);	} else {	    haveName = TRUE; 	    wasSpace = FALSE;	}	line++;    }    /*     * A final check: if we stopped on a +, ?, ! or :, the next character must     * be an = or it ain't a valid assignment      */    if (((*line == '+') ||	 (*line == '?') ||	 (*line == ':') ||	 (*line == '!')) &&	(line[1] != '='))    {	return (FALSE);    } else {	return (haveName);    }}/*- *--------------------------------------------------------------------- * Parse_DoVar  -- *	Take the variable assignment in the passed line and do it in the *	global context. * *	Note: There is a lexical ambiguity with assignment modifier characters *	in variable names. This routine interprets the character before the = *	as a modifier. Therefore, an assignment like *	    C++=/usr/bin/CC *	is interpreted as "C+ +=" instead of "C++ =". * * Results: *	none * * Side Effects: *	the variable structure of the given variable name is altered in the *	global context. *--------------------------------------------------------------------- */voidParse_DoVar (line, ctxt)    char            *line;	/* a line guaranteed to be a variable				 * assignment. This reduces error checks */    GNode   	    *ctxt;    	/* Context in which to do the assignment */{    char   	    *cp;	/* pointer into line */    enum {	VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL    }	    	    type;   	/* Type of assignment */    char            *opc;	/* ptr to operator character to 				 * null-terminate the variable name */    /*       * Avoid clobbered variable warnings by forcing the compiler     * to ``unregister'' variables     */ #if __GNUC__    (void) &cp;     (void) &line; #endif     /*     * Skip to variable name     */    while ((*line == ' ') || (*line == '\t')) {	line++;    }    /*     * Skip to operator character, nulling out whitespace as we go     */    for (cp = line + 1; *cp != '='; cp++) {	if (isspace (*cp)) {	    *cp = '\0';	}    }    opc = cp-1;		/* operator is the previous character */    *cp++ = '\0';	/* nuke the = */    /*     * Check operator type     */    switch (*opc) {	case '+':	    type = VAR_APPEND;	    *opc = '\0';	    break;	case '?':	    /*	     * If the variable already has a value, we don't do anything.	     */	    *opc = '\0';	    if (Var_Exists(line, ctxt)) {		return;	    } else {		type = VAR_NORMAL;	    }	    break;	case ':':	    type = VAR_SUBST;	    *opc = '\0';	    break;	case '!':	    type = VAR_SHELL;	    *opc = '\0';	    break;	default:	    type = VAR_NORMAL;	    break;    }    while (isspace (*cp)) {	cp++;    }    if (type == VAR_APPEND) {	Var_Append (line, cp, ctxt);    } else if (type == VAR_SUBST) {	/*	 * Allow variables in the old value to be undefined, but leave their	 * invocation alone -- this is done by forcing oldVars to be false.	 * XXX: This can cause recursive variables, but that's not hard to do,	 * and this allows someone to do something like	 *	 *  CFLAGS = $(.INCLUDES)	 *  CFLAGS := -I.. $(CFLAGS)	 *	 * And not get an error.	 */	Boolean	  oldOldVars = oldVars;	oldVars = FALSE;	cp = Var_Subst(NULL, cp, ctxt, FALSE);	oldVars = oldOldVars;	Var_Set(line, cp, ctxt);	free(cp);    } else if (type == VAR_SHELL) {	char	*args[4];   	/* Args for invoking the shell */	int 	fds[2];	    	/* Pipe streams */	int 	cpid;	    	/* Child PID */	int 	pid;	    	/* PID from wait() */	Boolean	freeCmd;    	/* TRUE if the command needs to be freed, i.e.				 * if any variable expansion was performed */	/*  	 * Avoid clobbered variable warnings by forcing the compiler	 * to ``unregister'' variables	 */ #if __GNUC__	(void) &freeCmd;#endif 	/*	 * Set up arguments for shell	 */	args[0] = "sh";	args[1] = "-c";	if (strchr(cp, '$') != (char *)NULL) {	    /*	     * There's a dollar sign in the command, so perform variable	     * expansion on the whole thing. The resulting string will need	     * freeing when we're done, so set freeCmd to TRUE.	     */	    args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE);	    freeCmd = TRUE;	} else {	    args[2] = cp;	    freeCmd = FALSE;	}	args[3] = (char *)NULL;	/*	 * Open a pipe for fetching its output	 */	pipe(fds);	/*	 * Fork	 */	cpid = vfork();	if (cpid == 0) {	    /*	     * Close input side of pipe	     */	    close(fds[0]);	    /*	     * Duplicate the output stream to the shell's output, then	     * shut the extra thing down. Note we don't fetch the error	     * stream...why not? Why?	     */	    dup2(fds[1], 1);	    close(fds[1]);	    	    execv("/bin/sh", args);	    _exit(1);	} else if (cpid < 0) {	    /*	     * Couldn't fork -- tell the user and make the variable null	     */	    Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp);	    Var_Set(line, "", ctxt);	} else {	    int	status;	    int cc;	    Buffer buf;	    char *res;	    /*	     * No need for the writing half	     */	    close(fds[1]);	    	    buf = Buf_Init (MAKE_BSIZE);	    do {		char   result[BUFSIZ];		cc = read(fds[0], result, sizeof(result));		if (cc > 0) 		    Buf_AddBytes(buf, cc, (unsigned char *) result);	    }	    while (cc > 0 || (cc == -1 && errno == EINTR));	    /*	     * Close the input side of the pipe.	     */	    close(fds[0]);	    /*	     * Wait for the process to exit.	     */	    while(((pid = wait(&status)) != cpid) && (pid >= 0))		continue;	    res = (char *)Buf_GetAll (buf, &cc);	    Buf_Destroy (buf, FALSE);	    if (cc == 0) {		/*		 * Couldn't read the child's output -- tell the user and		 * set the variable to null		 */		Parse_Error(PARSE_WARNING, "Couldn't read shell's output");	    }	    if (status) {		/*		 * Child returned an error -- tell the user but still use		 * the result.		 */		Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp);	    }	    /*	     * Null-terminate the result, convert newlines to spaces and	     * install it in the variable.	     */	    res[cc] = '\0';	    cp = &res[cc] - 1;	    if (*cp == '\n') {		/*		 * A final newline is just stripped		 */		*cp-- = '\0';	    }	    while (cp >= res) {		if (*cp == '\n') {		    *cp = ' ';		}		cp--;	    }	    Var_Set(line, res, ctxt);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -