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