Exemple #1
0
void
MAKEFLAGS_break(ArgArray *aa, const char str[])
{
	char	*arg;
	char	*start;

	ArgArray_Init(aa);

	aa->buffer = strdup(str);

	arg = aa->buffer;
	start = NULL;

	for (;;) {
		switch (str[0]) {
		case ' ':
		case '\t':
			/* word separator */
			if (start == NULL) {
				/* not in a word */
				str++;
				continue;
			}
			/* FALLTHRU */
		case '\0':
			if (aa->argc == aa->size) {
				aa->size *= 2;
				aa->argv = erealloc(aa->argv,
 				    (aa->size + 1) * sizeof(char *));
			}

			*arg++ = '\0';
			if (start == NULL) {
				aa->argv[aa->argc] = start;
				return;
			}
			if (str[0] == '\0') {
				aa->argv[aa->argc++] = start;
				aa->argv[aa->argc] = NULL;
				return;
			} else {
				aa->argv[aa->argc++] = start;
				start = NULL;
				str++;
				continue;
			}

		case '\\':
			if (str[1] == ' ' || str[1] == '\t')
				str++;
			break;

		default:
			break;
		}
		if (start == NULL)
			start = arg;
		*arg++ = *str++;
	}
}
Exemple #2
0
/**
 * Fracture a string into an array of words (as delineated by tabs or
 * spaces) taking quotation marks into account.  Leading tabs/spaces
 * are ignored.
 */
void
brk_string(ArgArray *aa, const char str[], Boolean expand)
{
	char	inquote;
	char	*start;
	char	*arg;

	/* skip leading space chars. */
	for (; *str == ' ' || *str == '\t'; ++str)
		continue;

	ArgArray_Init(aa);

	aa->buffer = estrdup(str);

	arg = aa->buffer;
	start = arg;
	inquote = '\0';

	/*
	 * copy the string; at the same time, parse backslashes,
	 * quotes and build the argument list.
	 */
	for (;;) {
		switch (str[0]) {
		case '"':
		case '\'':
			if (inquote == '\0') {
				inquote = str[0];
				if (expand)
					break;
				if (start == NULL)
					start = arg;
			} else if (inquote == str[0]) {
				inquote = '\0';
				/* Don't miss "" or '' */
				if (start == NULL)
					start = arg;
				if (expand)
					break;
			} else {
				/* other type of quote found */
				if (start == NULL)
					start = arg;
			}
			*arg++ = str[0];
			break;
		case ' ':
		case '\t':
		case '\n':
			if (inquote) {
				if (start == NULL)
					start = arg;
				*arg++ = str[0];
				break;
			}
			if (start == NULL)
				break;
			/* FALLTHROUGH */
		case '\0':
			/*
			 * end of a token -- make sure there's enough argv
			 * space and save off a pointer.
			 */
			if (aa->argc == aa->size) {
				aa->size *= 2;		/* ramp up fast */
				aa->argv = erealloc(aa->argv,
				    (aa->size + 1) * sizeof(char *));
			}

			*arg++ = '\0';
			if (start == NULL) {
				aa->argv[aa->argc] = start;
				return;
			}
			if (str[0] == '\n' || str[0] == '\0') {
				aa->argv[aa->argc++] = start;
				aa->argv[aa->argc] = NULL;
				return;
			} else {
				aa->argv[aa->argc++] = start;
				start = NULL;
				break;
			}
		case '\\':
			if (start == NULL)
				start = arg;
			if (expand) {
				switch (str[1]) {
				case '\0':
				case '\n':
					/* hmmm; fix it up as best we can */
					*arg++ = '\\';
					break;
				case 'b':
					*arg++ = '\b';
					++str;
					break;
				case 'f':
					*arg++ = '\f';
					++str;
					break;
				case 'n':
					*arg++ = '\n';
					++str;
					break;
				case 'r':
					*arg++ = '\r';
					++str;
					break;
				case 't':
					*arg++ = '\t';
					++str;
					break;
				default:
					*arg++ = str[1];
					++str;
					break;
				}
			} else {
				*arg++ = str[0];
				if (str[1] != '\0') {
					++str;
					*arg++ = str[0];
				}
			}
			break;
		default:
			if (start == NULL)
				start = arg;
			*arg++ = str[0];
			break;
		}
		++str;
	}
}
Exemple #3
0
/**
 * Parse a shell specification line and return the new Shell structure.
 * In case of an error a message is printed and NULL is returned.
 *
 * Notes:
 *	A shell specification consists of a .SHELL target, with dependency
 *	operator, followed by a series of blank-separated words. Double
 *	quotes can be used to use blanks in words. A backslash escapes
 *	anything (most notably a double-quote and a space) and
 *	provides the functionality it does in C. Each word consists of
 *	keyword and value separated by an equal sign. There should be no
 *	unnecessary spaces in the word. The keywords are as follows:
 *	    name	    Name of shell.
 *	    path	    Location of shell. Overrides "name" if given
 *	    quiet	    Command to turn off echoing.
 *	    echo	    Command to turn echoing on
 *	    filter	    Result of turning off echoing that shouldn't be
 *			    printed.
 *	    echoFlag	    Flag to turn echoing on at the start
 *	    errFlag	    Flag to turn error checking on at the start
 *	    hasErrCtl	    True if shell has error checking control
 *	    check	    Command to turn on error checking if hasErrCtl
 *			    is true or template of command to echo a command
 *			    for which error checking is off if hasErrCtl is
 *			    false.
 *	    ignore	    Command to turn off error checking if hasErrCtl
 *			    is true or template of command to execute a
 *			    command so as to ignore any errors it returns if
 *			    hasErrCtl is false.
 *	    builtins	    A space separated list of builtins. If one
 *			    of these builtins is detected when make wants
 *			    to execute a command line, the command line is
 *			    handed to the shell. Otherwise make may try to
 *			    execute the command directly. If this list is empty
 *			    it is assumed, that the command must always be
 *			    handed over to the shell.
 *	    meta	    The shell meta characters. If this is not specified
 *			    or empty, commands are alway passed to the shell.
 *			    Otherwise they are not passed when they contain
 *			    neither a meta character nor a builtin command.
 */
static Shell *
ShellParseSpec(const char spec[], bool *fullSpec)
{
	ArgArray	aa;
	Shell		*sh;
	char		*eq;
	char		*keyw;
	int		arg;

	*fullSpec = false;

	sh = emalloc(sizeof(*sh));
	memset(sh, 0, sizeof(*sh));
	ArgArray_Init(&sh->builtins);

	/*
	 * Parse the specification by keyword but skip the first word
	 */
	brk_string(&aa, spec, true);

	for (arg = 1; arg < aa.argc; arg++) {
		/*
		 * Split keyword and value
		 */
		keyw = aa.argv[arg];
		if ((eq = strchr(keyw, '=')) == NULL) {
			Parse_Error(PARSE_FATAL, "missing '=' in shell "
			    "specification keyword '%s'", keyw);
			ArgArray_Done(&aa);
			Shell_Destroy(sh);
			return (NULL);
		}
		*eq++ = '\0';

		if (strcmp(keyw, "path") == 0) {
			free(sh->path);
			sh->path = estrdup(eq);
		} else if (strcmp(keyw, "name") == 0) {
			free(sh->name);
			sh->name = estrdup(eq);
		} else if (strcmp(keyw, "quiet") == 0) {
			free(sh->echoOff);
			sh->echoOff = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "echo") == 0) {
			free(sh->echoOn);
			sh->echoOn = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "filter") == 0) {
			free(sh->noPrint);
			sh->noPrint = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "echoFlag") == 0) {
			free(sh->echo);
			sh->echo = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "errFlag") == 0) {
			free(sh->exit);
			sh->exit = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "hasErrCtl") == 0) {
			sh->hasErrCtl = (
			    *eq == 'Y' || *eq == 'y' ||
			    *eq == 'T' || *eq == 't');
			*fullSpec = true;
		} else if (strcmp(keyw, "check") == 0) {
			free(sh->errCheck);
			sh->errCheck = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "ignore") == 0) {
			free(sh->ignErr);
			sh->ignErr = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "builtins") == 0) {
			ArgArray_Done(&sh->builtins);
			brk_string(&sh->builtins, eq, true);
			qsort(sh->builtins.argv + 1, sh->builtins.argc - 1,
			    sizeof(char *), sort_builtins);
			*fullSpec = true;
		} else if (strcmp(keyw, "meta") == 0) {
			free(sh->meta);
			sh->meta = estrdup(eq);
			*fullSpec = true;
		} else if (strcmp(keyw, "unsetenv") == 0) {
			sh->unsetenv = (
			    *eq == 'Y' || *eq == 'y' ||
			    *eq == 'T' || *eq == 't');
			*fullSpec = true;
		} else {
			Parse_Error(PARSE_FATAL, "unknown keyword in shell "
			    "specification '%s'", keyw);
			ArgArray_Done(&aa);
			Shell_Destroy(sh);
			return (NULL);
		}
	}
	ArgArray_Done(&aa);

	/*
	 * Some checks (could be more)
	 */
	if (*fullSpec) {
		if ((sh->echoOn != NULL) ^ (sh->echoOff != NULL)) {
			Parse_Error(PARSE_FATAL, "Shell must have either both "
			    "echoOff and echoOn or none of them");
			Shell_Destroy(sh);
			return (NULL);
		}

		if (sh->echoOn != NULL && sh->echoOff != NULL)
			sh->hasEchoCtl = true;
	}

	return (sh);
}