File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / tmux / arguments.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) 2010 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 <stdlib.h>
   22: #include <string.h>
   23: #include <unistd.h>
   24: 
   25: #include "tmux.h"
   26: 
   27: /*
   28:  * Manipulate command arguments.
   29:  */
   30: 
   31: struct args_entry {
   32: 	u_char			 flag;
   33: 	char			*value;
   34: 	RB_ENTRY(args_entry)	 entry;
   35: };
   36: 
   37: static void			 args_set(struct args *, u_char, const char *);
   38: static struct args_entry	*args_find(struct args *, u_char);
   39: 
   40: static int	args_cmp(struct args_entry *, struct args_entry *);
   41: RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
   42: 
   43: /* Arguments tree comparison function. */
   44: static int
   45: args_cmp(struct args_entry *a1, struct args_entry *a2)
   46: {
   47: 	return (a1->flag - a2->flag);
   48: }
   49: 
   50: /* Find a flag in the arguments tree. */
   51: static struct args_entry *
   52: args_find(struct args *args, u_char ch)
   53: {
   54: 	struct args_entry	entry;
   55: 
   56: 	entry.flag = ch;
   57: 	return (RB_FIND(args_tree, &args->tree, &entry));
   58: }
   59: 
   60: /* Parse an argv and argc into a new argument set. */
   61: struct args *
   62: args_parse(const char *template, int argc, char **argv)
   63: {
   64: 	struct args	*args;
   65: 	int		 opt;
   66: 
   67: 	args = xcalloc(1, sizeof *args);
   68: 
   69: 	optreset = 1;
   70: 	optind = 1;
   71: 
   72: 	while ((opt = getopt(argc, argv, template)) != -1) {
   73: 		if (opt < 0)
   74: 			continue;
   75: 		if (opt == '?' || strchr(template, opt) == NULL) {
   76: 			args_free(args);
   77: 			return (NULL);
   78: 		}
   79: 		args_set(args, opt, optarg);
   80: 	}
   81: 	argc -= optind;
   82: 	argv += optind;
   83: 
   84: 	args->argc = argc;
   85: 	args->argv = cmd_copy_argv(argc, argv);
   86: 
   87: 	return (args);
   88: }
   89: 
   90: /* Free an arguments set. */
   91: void
   92: args_free(struct args *args)
   93: {
   94: 	struct args_entry	*entry;
   95: 	struct args_entry	*entry1;
   96: 
   97: 	cmd_free_argv(args->argc, args->argv);
   98: 
   99: 	RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
  100: 		RB_REMOVE(args_tree, &args->tree, entry);
  101: 		free(entry->value);
  102: 		free(entry);
  103: 	}
  104: 
  105: 	free(args);
  106: }
  107: 
  108: /* Add to string. */
  109: static void printflike(3, 4)
  110: args_print_add(char **buf, size_t *len, const char *fmt, ...)
  111: {
  112: 	va_list  ap;
  113: 	char	*s;
  114: 	size_t	 slen;
  115: 
  116: 	va_start(ap, fmt);
  117: 	slen = xvasprintf(&s, fmt, ap);
  118: 	va_end(ap);
  119: 
  120: 	*len += slen;
  121: 	*buf = xrealloc(*buf, *len);
  122: 
  123: 	strlcat(*buf, s, *len);
  124: 	free(s);
  125: }
  126: 
  127: /* Print a set of arguments. */
  128: char *
  129: args_print(struct args *args)
  130: {
  131: 	size_t		 	 len;
  132: 	char			*buf, *escaped;
  133: 	int			 i, flags;
  134: 	struct args_entry	*entry;
  135: 	static const char	 quoted[] = " #\"';$";
  136: 
  137: 	len = 1;
  138: 	buf = xcalloc(1, len);
  139: 
  140: 	/* Process the flags first. */
  141: 	RB_FOREACH(entry, args_tree, &args->tree) {
  142: 		if (entry->value != NULL)
  143: 			continue;
  144: 
  145: 		if (*buf == '\0')
  146: 			args_print_add(&buf, &len, "-");
  147: 		args_print_add(&buf, &len, "%c", entry->flag);
  148: 	}
  149: 
  150: 	/* Then the flags with arguments. */
  151: 	RB_FOREACH(entry, args_tree, &args->tree) {
  152: 		if (entry->value == NULL)
  153: 			continue;
  154: 
  155: 		if (*buf != '\0')
  156: 			args_print_add(&buf, &len, " -%c ", entry->flag);
  157: 		else
  158: 			args_print_add(&buf, &len, "-%c ", entry->flag);
  159: 
  160: 		flags = VIS_OCTAL|VIS_TAB|VIS_NL;
  161: 		if (entry->value[strcspn(entry->value, quoted)] != '\0')
  162: 			flags |= VIS_DQ;
  163: 		utf8_stravis(&escaped, entry->value, flags);
  164: 		if (flags & VIS_DQ)
  165: 			args_print_add(&buf, &len, "\"%s\"", escaped);
  166: 		else
  167: 			args_print_add(&buf, &len, "%s", escaped);
  168: 		free(escaped);
  169: 	}
  170: 
  171: 	/* And finally the argument vector. */
  172: 	for (i = 0; i < args->argc; i++) {
  173: 		if (*buf != '\0')
  174: 			args_print_add(&buf, &len, " ");
  175: 
  176: 		flags = VIS_OCTAL|VIS_TAB|VIS_NL;
  177: 		if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0')
  178: 			flags |= VIS_DQ;
  179: 		utf8_stravis(&escaped, args->argv[i], flags);
  180: 		if (flags & VIS_DQ)
  181: 			args_print_add(&buf, &len, "\"%s\"", escaped);
  182: 		else
  183: 			args_print_add(&buf, &len, "%s", escaped);
  184: 		free(escaped);
  185: 	}
  186: 
  187: 	return (buf);
  188: }
  189: 
  190: /* Return if an argument is present. */
  191: int
  192: args_has(struct args *args, u_char ch)
  193: {
  194: 	return (args_find(args, ch) == NULL ? 0 : 1);
  195: }
  196: 
  197: /* Set argument value in the arguments tree. */
  198: static void
  199: args_set(struct args *args, u_char ch, const char *value)
  200: {
  201: 	struct args_entry	*entry;
  202: 
  203: 	/* Replace existing argument. */
  204: 	if ((entry = args_find(args, ch)) != NULL) {
  205: 		free(entry->value);
  206: 		entry->value = NULL;
  207: 	} else {
  208: 		entry = xcalloc(1, sizeof *entry);
  209: 		entry->flag = ch;
  210: 		RB_INSERT(args_tree, &args->tree, entry);
  211: 	}
  212: 
  213: 	if (value != NULL)
  214: 		entry->value = xstrdup(value);
  215: }
  216: 
  217: /* Get argument value. Will be NULL if it isn't present. */
  218: const char *
  219: args_get(struct args *args, u_char ch)
  220: {
  221: 	struct args_entry	*entry;
  222: 
  223: 	if ((entry = args_find(args, ch)) == NULL)
  224: 		return (NULL);
  225: 	return (entry->value);
  226: }
  227: 
  228: /* Convert an argument value to a number. */
  229: long long
  230: args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
  231:     char **cause)
  232: {
  233: 	const char		*errstr;
  234: 	long long 	 	 ll;
  235: 	struct args_entry	*entry;
  236: 
  237: 	if ((entry = args_find(args, ch)) == NULL) {
  238: 		*cause = xstrdup("missing");
  239: 		return (0);
  240: 	}
  241: 
  242: 	ll = strtonum(entry->value, minval, maxval, &errstr);
  243: 	if (errstr != NULL) {
  244: 		*cause = xstrdup(errstr);
  245: 		return (0);
  246: 	}
  247: 
  248: 	*cause = NULL;
  249: 	return (ll);
  250: }

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