mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 01:34:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			180 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Id: cmd-string.c,v 1.3 2008-06-19 21:20:27 nicm Exp $ */
 | 
						|
 | 
						|
/*
 | 
						|
 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, and distribute this software for any
 | 
						|
 * purpose with or without fee is hereby granted, provided that the above
 | 
						|
 * copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
 | 
						|
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 | 
						|
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
#include "tmux.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Parse a command from a string.
 | 
						|
 */
 | 
						|
 | 
						|
int	cmd_string_getc(const char *, size_t *);
 | 
						|
char   *cmd_string_string(const char *, size_t *, char, int);
 | 
						|
 | 
						|
int
 | 
						|
cmd_string_getc(const char *s, size_t *p)
 | 
						|
{
 | 
						|
	if (s[*p] == '\0')
 | 
						|
		return (EOF);
 | 
						|
	return (s[(*p)++]);
 | 
						|
}
 | 
						|
 | 
						|
/* 
 | 
						|
 * Parse command string. Return command or NULL on error. If returning NULL,
 | 
						|
 * cause is error string, or NULL for empty command.
 | 
						|
 */ 
 | 
						|
struct cmd *
 | 
						|
cmd_string_parse(const char *s, char **cause)
 | 
						|
{
 | 
						|
	size_t	p;
 | 
						|
	int		ch, argc;
 | 
						|
	char	      **argv, *buf, *t;
 | 
						|
	size_t		len;
 | 
						|
	struct cmd     *cmd;
 | 
						|
 | 
						|
	argv = NULL;
 | 
						|
	argc = 0;
 | 
						|
 | 
						|
	buf = NULL;
 | 
						|
	len = 0;
 | 
						|
 | 
						|
	cmd = NULL;
 | 
						|
 | 
						|
	*cause = NULL;
 | 
						|
	
 | 
						|
	p = 0;
 | 
						|
	for (;;) {
 | 
						|
		ch = cmd_string_getc(s, &p);
 | 
						|
		switch (ch) {
 | 
						|
		case '\'':
 | 
						|
			if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
 | 
						|
				goto error;
 | 
						|
			argv = xrealloc(argv, argc + 1, sizeof *argv);
 | 
						|
			argv[argc++] = t;
 | 
						|
			break;
 | 
						|
		case '"':
 | 
						|
			if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
 | 
						|
				goto error;
 | 
						|
			argv = xrealloc(argv, argc + 1, sizeof *argv);
 | 
						|
			argv[argc++] = t;
 | 
						|
			break;
 | 
						|
		case '#':
 | 
						|
			/* Comment: discard rest of line. */
 | 
						|
			while ((ch = cmd_string_getc(s, &p)) != EOF)
 | 
						|
				;
 | 
						|
			/* FALLTHROUGH */
 | 
						|
		case EOF:
 | 
						|
		case ' ':
 | 
						|
		case '\t':
 | 
						|
 			if (len != 0) {
 | 
						|
				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;
 | 
						|
			if (argc == 0)
 | 
						|
				goto out;
 | 
						|
				
 | 
						|
			cmd = cmd_parse(argc, argv, cause);
 | 
						|
			goto out;
 | 
						|
		default:
 | 
						|
			if (len >= SIZE_MAX - 2)
 | 
						|
				goto error;
 | 
						|
 | 
						|
			buf = xrealloc(buf, 1, len + 1);
 | 
						|
			buf[len++] = ch;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	
 | 
						|
error:
 | 
						|
	xasprintf(cause, "bad command: %s", s);
 | 
						|
	
 | 
						|
out:
 | 
						|
	if (buf != NULL)
 | 
						|
		xfree(buf);
 | 
						|
 | 
						|
	while (--argc >= 0)
 | 
						|
		xfree(argv[argc]);
 | 
						|
	if (argv != NULL)
 | 
						|
		xfree(argv);
 | 
						|
 | 
						|
	return (cmd);
 | 
						|
}
 | 
						|
 | 
						|
char *
 | 
						|
cmd_string_string(const char *s, size_t *p, char endch, int esc)
 | 
						|
{
 | 
						|
	int	ch;
 | 
						|
	char   *buf;
 | 
						|
	size_t	len;
 | 
						|
 | 
						|
        buf = NULL;
 | 
						|
	len = 0;
 | 
						|
 | 
						|
        while ((ch = cmd_string_getc(s, p)) != endch) {
 | 
						|
                switch (ch) {
 | 
						|
		case EOF:
 | 
						|
			goto error;
 | 
						|
                case '\\':
 | 
						|
			if (!esc)
 | 
						|
				break;
 | 
						|
                        switch (ch = cmd_string_getc(s, p)) {
 | 
						|
			case EOF:
 | 
						|
				goto error;
 | 
						|
                        case 'r':
 | 
						|
                                ch = '\r';
 | 
						|
                                break;
 | 
						|
                        case 'n':
 | 
						|
                                ch = '\n';
 | 
						|
                                break;
 | 
						|
                        case 't':
 | 
						|
                                ch = '\t';
 | 
						|
                                break;
 | 
						|
                        }
 | 
						|
                        break;
 | 
						|
                }
 | 
						|
 | 
						|
		if (len >= SIZE_MAX - 2)
 | 
						|
			goto error;
 | 
						|
		buf = xrealloc(buf, 1, len + 1);
 | 
						|
                buf[len++] = ch;
 | 
						|
        }
 | 
						|
 | 
						|
	buf = xrealloc(buf, 1, len + 1);
 | 
						|
	buf[len] = '\0';
 | 
						|
	return (buf);
 | 
						|
 | 
						|
error:
 | 
						|
	if (buf != NULL)
 | 
						|
		xfree(buf);
 | 
						|
	return (NULL);
 | 
						|
}
 |