File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / cmd-string.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 14 12:22:44 2017 UTC (7 years ago) by misho
Branches: tmux, MAIN
CVS tags: v2_4p0, v2_4, HEAD
tmux 2.4

    1: /* $OpenBSD$ */
    2: 
    3: /*
    4:  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
    5:  *
    6:  * Permission to use, copy, modify, and distribute this software for any
    7:  * purpose with or without fee is hereby granted, provided that the above
    8:  * copyright notice and this permission notice appear in all copies.
    9:  *
   10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14:  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
   15:  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   16:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17:  */
   18: 
   19: #include <sys/types.h>
   20: 
   21: #include <errno.h>
   22: #include <pwd.h>
   23: #include <stdio.h>
   24: #include <string.h>
   25: #include <stdlib.h>
   26: #include <unistd.h>
   27: 
   28: #include "tmux.h"
   29: 
   30: /*
   31:  * Parse a command from a string.
   32:  */
   33: 
   34: static int	 cmd_string_getc(const char *, size_t *);
   35: static void	 cmd_string_ungetc(size_t *);
   36: static void	 cmd_string_copy(char **, char *, size_t *);
   37: static char	*cmd_string_string(const char *, size_t *, char, int);
   38: static char	*cmd_string_variable(const char *, size_t *);
   39: static char	*cmd_string_expand_tilde(const char *, size_t *);
   40: 
   41: static int
   42: cmd_string_getc(const char *s, size_t *p)
   43: {
   44: 	const u_char	*ucs = s;
   45: 
   46: 	if (ucs[*p] == '\0')
   47: 		return (EOF);
   48: 	return (ucs[(*p)++]);
   49: }
   50: 
   51: static void
   52: cmd_string_ungetc(size_t *p)
   53: {
   54: 	(*p)--;
   55: }
   56: 
   57: int
   58: cmd_string_split(const char *s, int *rargc, char ***rargv)
   59: {
   60: 	size_t		p = 0;
   61: 	int		ch, argc = 0, append = 0;
   62: 	char	      **argv = NULL, *buf = NULL, *t;
   63: 	const char     *whitespace, *equals;
   64: 	size_t		len = 0;
   65: 
   66: 	for (;;) {
   67: 		ch = cmd_string_getc(s, &p);
   68: 		switch (ch) {
   69: 		case '\'':
   70: 			if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
   71: 				goto error;
   72: 			cmd_string_copy(&buf, t, &len);
   73: 			break;
   74: 		case '"':
   75: 			if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
   76: 				goto error;
   77: 			cmd_string_copy(&buf, t, &len);
   78: 			break;
   79: 		case '$':
   80: 			if ((t = cmd_string_variable(s, &p)) == NULL)
   81: 				goto error;
   82: 			cmd_string_copy(&buf, t, &len);
   83: 			break;
   84: 		case '#':
   85: 			/* Comment: discard rest of line. */
   86: 			while ((ch = cmd_string_getc(s, &p)) != EOF)
   87: 				;
   88: 			/* FALLTHROUGH */
   89: 		case EOF:
   90: 		case ' ':
   91: 		case '\t':
   92: 			if (buf != NULL) {
   93: 				buf = xrealloc(buf, len + 1);
   94: 				buf[len] = '\0';
   95: 
   96: 				argv = xreallocarray(argv, argc + 1,
   97: 				    sizeof *argv);
   98: 				argv[argc++] = buf;
   99: 
  100: 				buf = NULL;
  101: 				len = 0;
  102: 			}
  103: 
  104: 			if (ch != EOF)
  105: 				break;
  106: 
  107: 			while (argc != 0) {
  108: 				equals = strchr(argv[0], '=');
  109: 				whitespace = argv[0] + strcspn(argv[0], " \t");
  110: 				if (equals == NULL || equals > whitespace)
  111: 					break;
  112: 				environ_put(global_environ, argv[0]);
  113: 				argc--;
  114: 				memmove(argv, argv + 1, argc * (sizeof *argv));
  115: 			}
  116: 			goto done;
  117: 		case '~':
  118: 			if (buf != NULL) {
  119: 				append = 1;
  120: 				break;
  121: 			}
  122: 			t = cmd_string_expand_tilde(s, &p);
  123: 			if (t == NULL)
  124: 				goto error;
  125: 			cmd_string_copy(&buf, t, &len);
  126: 			break;
  127: 		default:
  128: 			append = 1;
  129: 			break;
  130: 		}
  131: 		if (append) {
  132: 			if (len >= SIZE_MAX - 2)
  133: 				goto error;
  134: 			buf = xrealloc(buf, len + 1);
  135: 			buf[len++] = ch;
  136: 		}
  137: 		append = 0;
  138: 	}
  139: 
  140: done:
  141: 	*rargc = argc;
  142: 	*rargv = argv;
  143: 
  144: 	free(buf);
  145: 	return (0);
  146: 
  147: error:
  148: 	if (argv != NULL)
  149: 		cmd_free_argv(argc, argv);
  150: 	free(buf);
  151: 	return (-1);
  152: }
  153: 
  154: struct cmd_list *
  155: cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
  156: {
  157: 	struct cmd_list	 *cmdlist = NULL;
  158: 	int		  argc;
  159: 	char		**argv;
  160: 
  161: 	*cause = NULL;
  162: 	if (cmd_string_split(s, &argc, &argv) != 0)
  163: 		goto error;
  164: 	if (argc != 0) {
  165: 		cmdlist = cmd_list_parse(argc, argv, file, line, cause);
  166: 		if (cmdlist == NULL) {
  167: 			cmd_free_argv(argc, argv);
  168: 			goto error;
  169: 		}
  170: 	}
  171: 	cmd_free_argv(argc, argv);
  172: 	return (cmdlist);
  173: 
  174: error:
  175: 	xasprintf(cause, "invalid or unknown command: %s", s);
  176: 	return (NULL);
  177: }
  178: 
  179: static void
  180: cmd_string_copy(char **dst, char *src, size_t *len)
  181: {
  182: 	size_t srclen;
  183: 
  184: 	srclen = strlen(src);
  185: 
  186: 	*dst = xrealloc(*dst, *len + srclen + 1);
  187: 	strlcpy(*dst + *len, src, srclen + 1);
  188: 
  189: 	*len += srclen;
  190: 	free(src);
  191: }
  192: 
  193: static char *
  194: cmd_string_string(const char *s, size_t *p, char endch, int esc)
  195: {
  196: 	int	ch;
  197: 	char   *buf, *t;
  198: 	size_t	len;
  199: 
  200: 	buf = NULL;
  201: 	len = 0;
  202: 
  203: 	while ((ch = cmd_string_getc(s, p)) != endch) {
  204: 		switch (ch) {
  205: 		case EOF:
  206: 			goto error;
  207: 		case '\\':
  208: 			if (!esc)
  209: 				break;
  210: 			switch (ch = cmd_string_getc(s, p)) {
  211: 			case EOF:
  212: 				goto error;
  213: 			case 'e':
  214: 				ch = '\033';
  215: 				break;
  216: 			case 'r':
  217: 				ch = '\r';
  218: 				break;
  219: 			case 'n':
  220: 				ch = '\n';
  221: 				break;
  222: 			case 't':
  223: 				ch = '\t';
  224: 				break;
  225: 			}
  226: 			break;
  227: 		case '$':
  228: 			if (!esc)
  229: 				break;
  230: 			if ((t = cmd_string_variable(s, p)) == NULL)
  231: 				goto error;
  232: 			cmd_string_copy(&buf, t, &len);
  233: 			continue;
  234: 		}
  235: 
  236: 		if (len >= SIZE_MAX - 2)
  237: 			goto error;
  238: 		buf = xrealloc(buf, len + 1);
  239: 		buf[len++] = ch;
  240: 	}
  241: 
  242: 	buf = xrealloc(buf, len + 1);
  243: 	buf[len] = '\0';
  244: 	return (buf);
  245: 
  246: error:
  247: 	free(buf);
  248: 	return (NULL);
  249: }
  250: 
  251: static char *
  252: cmd_string_variable(const char *s, size_t *p)
  253: {
  254: 	int			ch, fch;
  255: 	char		       *buf, *t;
  256: 	size_t			len;
  257: 	struct environ_entry   *envent;
  258: 
  259: #define cmd_string_first(ch) ((ch) == '_' || \
  260: 	((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
  261: #define cmd_string_other(ch) ((ch) == '_' || \
  262: 	((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
  263: 	((ch) >= '0' && (ch) <= '9'))
  264: 
  265: 	buf = NULL;
  266: 	len = 0;
  267: 
  268: 	fch = EOF;
  269: 	switch (ch = cmd_string_getc(s, p)) {
  270: 	case EOF:
  271: 		goto error;
  272: 	case '{':
  273: 		fch = '{';
  274: 
  275: 		ch = cmd_string_getc(s, p);
  276: 		if (!cmd_string_first(ch))
  277: 			goto error;
  278: 		/* FALLTHROUGH */
  279: 	default:
  280: 		if (!cmd_string_first(ch)) {
  281: 			xasprintf(&t, "$%c", ch);
  282: 			return (t);
  283: 		}
  284: 
  285: 		buf = xrealloc(buf, len + 1);
  286: 		buf[len++] = ch;
  287: 
  288: 		for (;;) {
  289: 			ch = cmd_string_getc(s, p);
  290: 			if (ch == EOF || !cmd_string_other(ch))
  291: 				break;
  292: 			else {
  293: 				if (len >= SIZE_MAX - 3)
  294: 					goto error;
  295: 				buf = xrealloc(buf, len + 1);
  296: 				buf[len++] = ch;
  297: 			}
  298: 		}
  299: 	}
  300: 
  301: 	if (fch == '{' && ch != '}')
  302: 		goto error;
  303: 	if (ch != EOF && fch != '{')
  304: 		cmd_string_ungetc(p); /* ch */
  305: 
  306: 	buf = xrealloc(buf, len + 1);
  307: 	buf[len] = '\0';
  308: 
  309: 	envent = environ_find(global_environ, buf);
  310: 	free(buf);
  311: 	if (envent == NULL)
  312: 		return (xstrdup(""));
  313: 	return (xstrdup(envent->value));
  314: 
  315: error:
  316: 	free(buf);
  317: 	return (NULL);
  318: }
  319: 
  320: static char *
  321: cmd_string_expand_tilde(const char *s, size_t *p)
  322: {
  323: 	struct passwd		*pw;
  324: 	struct environ_entry	*envent;
  325: 	char			*home, *path, *user, *cp;
  326: 	int			 last;
  327: 
  328: 	home = NULL;
  329: 
  330: 	last = cmd_string_getc(s, p);
  331: 	if (last == EOF || last == '/' || last == ' '|| last == '\t') {
  332: 		envent = environ_find(global_environ, "HOME");
  333: 		if (envent != NULL && *envent->value != '\0')
  334: 			home = envent->value;
  335: 		else if ((pw = getpwuid(getuid())) != NULL)
  336: 			home = pw->pw_dir;
  337: 	} else {
  338: 		cmd_string_ungetc(p);
  339: 
  340: 		cp = user = xmalloc(strlen(s));
  341: 		for (;;) {
  342: 			last = cmd_string_getc(s, p);
  343: 			if (last == EOF ||
  344: 			    last == '/' ||
  345: 			    last == ' '||
  346: 			    last == '\t')
  347: 				break;
  348: 			*cp++ = last;
  349: 		}
  350: 		*cp = '\0';
  351: 
  352: 		if ((pw = getpwnam(user)) != NULL)
  353: 			home = pw->pw_dir;
  354: 		free(user);
  355: 	}
  356: 
  357: 	if (home == NULL)
  358: 		return (NULL);
  359: 
  360: 	if (last != EOF)
  361: 		xasprintf(&path, "%s%c", home, last);
  362: 	else
  363: 		xasprintf(&path, "%s", home);
  364: 	return (path);
  365: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>