Example #1
0
/*
 * Parse command string. Returns -1 on error. If returning -1, cause is error
 * string, or NULL for empty command.
 */
int
cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
{
	size_t		p;
	int		ch, i, argc, rval;
	char	      **argv, *buf, *t;
	const char     *whitespace, *equals;
	size_t		len;

	argv = NULL;
	argc = 0;

	buf = NULL;
	len = 0;

	*cause = NULL;

	*cmdlist = NULL;
	rval = -1;

	p = 0;
	for (;;) {
		ch = cmd_string_getc(s, &p);
		switch (ch) {
		case '\'':
			if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
				goto error;
			buf = xrealloc(buf, 1, len + strlen(t) + 1);
			strlcpy(buf + len, t, strlen(t) + 1);
			len += strlen(t);
			xfree(t);
			break;
		case '"':
			if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
				goto error;
			buf = xrealloc(buf, 1, len + strlen(t) + 1);
			strlcpy(buf + len, t, strlen(t) + 1);
			len += strlen(t);
			xfree(t);
			break;
		case '$':
			if ((t = cmd_string_variable(s, &p)) == NULL)
				goto error;
			buf = xrealloc(buf, 1, len + strlen(t) + 1);
			strlcpy(buf + len, t, strlen(t) + 1);
			len += strlen(t);
			xfree(t);
			break;
		case '#':
			/* Comment: discard rest of line. */
			while ((ch = cmd_string_getc(s, &p)) != EOF)
				;
			/* FALLTHROUGH */
		case EOF:
		case ' ':
		case '\t':
			if (buf != NULL) {
				buf = xrealloc(buf, 1, len + 1);
				buf[len] = '\0';

				argv = xrealloc(argv, argc + 1, sizeof *argv);
				argv[argc++] = buf;

				buf = NULL;
				len = 0;
			}

			if (ch != EOF)
				break;

			while (argc != 0) {
				equals = strchr(argv[0], '=');
				whitespace = argv[0] + strcspn(argv[0], " \t");
				if (equals == NULL || equals > whitespace)
					break;
				environ_put(&global_environ, argv[0]);
				argc--;
				memmove(argv, argv + 1, argc * (sizeof *argv));
			}
			if (argc == 0)
				goto out;

			*cmdlist = cmd_list_parse(argc, argv, cause);
			if (*cmdlist == NULL)
				goto out;

			rval = 0;
			goto out;
		case '~':
			if (buf == NULL) {
				if ((t = cmd_string_expand_tilde(s, &p)) == NULL)
					goto error;
				buf = xrealloc(buf, 1, len + strlen(t) + 1);
				strlcpy(buf + len, t, strlen(t) + 1);
				len += strlen(t);
				xfree(t);
				break;
			}
			/* FALLTHROUGH */
		default:
			if (len >= SIZE_MAX - 2)
				goto error;

			buf = xrealloc(buf, 1, len + 1);
			buf[len++] = ch;
			break;
		}
	}

error:
	xasprintf(cause, "invalid or unknown command: %s", s);

out:
	if (buf != NULL)
		xfree(buf);

	if (argv != NULL) {
		for (i = 0; i < argc; i++)
			xfree(argv[i]);
		xfree(argv);
	}

	return (rval);
}
Example #2
0
int
cmd_string_split(const char *s, int *rargc, char ***rargv)
{
	size_t		p = 0;
	int		ch, argc = 0, append = 0;
	char	      **argv = NULL, *buf = NULL, *t;
	const char     *whitespace, *equals;
	size_t		len = 0;

	for (;;) {
		ch = cmd_string_getc(s, &p);
		switch (ch) {
		case '\'':
			if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
				goto error;
			cmd_string_copy(&buf, t, &len);
			break;
		case '"':
			if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
				goto error;
			cmd_string_copy(&buf, t, &len);
			break;
		case '$':
			if ((t = cmd_string_variable(s, &p)) == NULL)
				goto error;
			cmd_string_copy(&buf, t, &len);
			break;
		case '#':
			/* Comment: discard rest of line. */
			while ((ch = cmd_string_getc(s, &p)) != EOF)
				;
			/* FALLTHROUGH */
		case EOF:
		case ' ':
		case '\t':
			if (buf != NULL) {
				buf = xrealloc(buf, len + 1);
				buf[len] = '\0';

				argv = xreallocarray(argv, argc + 1,
				    sizeof *argv);
				argv[argc++] = buf;

				buf = NULL;
				len = 0;
			}

			if (ch != EOF)
				break;

			while (argc != 0) {
				equals = strchr(argv[0], '=');
				whitespace = argv[0] + strcspn(argv[0], " \t");
				if (equals == NULL || equals > whitespace)
					break;
				environ_put(global_environ, argv[0]);
				argc--;
				memmove(argv, argv + 1, argc * (sizeof *argv));
			}
			goto done;
		case '~':
			if (buf != NULL) {
				append = 1;
				break;
			}
			t = cmd_string_expand_tilde(s, &p);
			if (t == NULL)
				goto error;
			cmd_string_copy(&buf, t, &len);
			break;
		default:
			append = 1;
			break;
		}
		if (append) {
			if (len >= SIZE_MAX - 2)
				goto error;
			buf = xrealloc(buf, len + 1);
			buf[len++] = ch;
		}
		append = 0;
	}

done:
	*rargc = argc;
	*rargv = argv;

	free(buf);
	return (0);

error:
	if (argv != NULL)
		cmd_free_argv(argc, argv);
	free(buf);
	return (-1);
}