Annotation of src/usr.bin/tmux/arguments.c, Revision 1.27
1.27 ! nicm 1: /* $OpenBSD: arguments.c,v 1.26 2019/06/20 07:10:56 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:
21: #include <stdlib.h>
22: #include <string.h>
1.6 okan 23: #include <unistd.h>
1.16 nicm 24: #include <vis.h>
1.1 nicm 25:
26: #include "tmux.h"
27:
1.5 nicm 28: /*
29: * Manipulate command arguments.
30: */
1.11 nicm 31:
1.21 nicm 32: struct args_value {
33: char *value;
34: TAILQ_ENTRY(args_value) entry;
35: };
36: TAILQ_HEAD(args_values, args_value);
37:
1.11 nicm 38: struct args_entry {
39: u_char flag;
1.21 nicm 40: struct args_values values;
1.27 ! nicm 41: u_int count;
1.11 nicm 42: RB_ENTRY(args_entry) entry;
43: };
1.5 nicm 44:
1.14 nicm 45: static struct args_entry *args_find(struct args *, u_char);
1.5 nicm 46:
1.14 nicm 47: static int args_cmp(struct args_entry *, struct args_entry *);
48: RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
1.5 nicm 49:
50: /* Arguments tree comparison function. */
1.14 nicm 51: static int
1.5 nicm 52: args_cmp(struct args_entry *a1, struct args_entry *a2)
53: {
54: return (a1->flag - a2->flag);
55: }
56:
57: /* Find a flag in the arguments tree. */
1.14 nicm 58: static struct args_entry *
1.5 nicm 59: args_find(struct args *args, u_char ch)
60: {
61: struct args_entry entry;
62:
63: entry.flag = ch;
64: return (RB_FIND(args_tree, &args->tree, &entry));
65: }
66:
1.1 nicm 67: /* Parse an argv and argc into a new argument set. */
68: struct args *
69: args_parse(const char *template, int argc, char **argv)
70: {
71: struct args *args;
72: int opt;
73:
74: args = xcalloc(1, sizeof *args);
75:
76: optreset = 1;
77: optind = 1;
78:
79: while ((opt = getopt(argc, argv, template)) != -1) {
1.5 nicm 80: if (opt < 0)
1.1 nicm 81: continue;
1.8 nicm 82: if (opt == '?' || strchr(template, opt) == NULL) {
1.5 nicm 83: args_free(args);
1.1 nicm 84: return (NULL);
85: }
1.5 nicm 86: args_set(args, opt, optarg);
1.1 nicm 87: }
88: argc -= optind;
89: argv += optind;
90:
91: args->argc = argc;
92: args->argv = cmd_copy_argv(argc, argv);
93:
94: return (args);
95: }
96:
97: /* Free an arguments set. */
98: void
99: args_free(struct args *args)
100: {
1.5 nicm 101: struct args_entry *entry;
102: struct args_entry *entry1;
1.21 nicm 103: struct args_value *value;
104: struct args_value *value1;
1.1 nicm 105:
106: cmd_free_argv(args->argc, args->argv);
107:
1.5 nicm 108: RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
109: RB_REMOVE(args_tree, &args->tree, entry);
1.21 nicm 110: TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
111: TAILQ_REMOVE(&entry->values, value, entry);
112: free(value->value);
113: free(value);
114: }
1.5 nicm 115: free(entry);
116: }
1.1 nicm 117:
1.4 nicm 118: free(args);
1.1 nicm 119: }
120:
1.12 nicm 121: /* Add to string. */
122: static void printflike(3, 4)
123: args_print_add(char **buf, size_t *len, const char *fmt, ...)
124: {
125: va_list ap;
126: char *s;
127: size_t slen;
128:
129: va_start(ap, fmt);
130: slen = xvasprintf(&s, fmt, ap);
131: va_end(ap);
132:
133: *len += slen;
134: *buf = xrealloc(*buf, *len);
135:
136: strlcat(*buf, s, *len);
137: free(s);
138: }
139:
1.21 nicm 140: /* Add value to string. */
141: static void
142: args_print_add_value(char **buf, size_t *len, struct args_entry *entry,
143: struct args_value *value)
144: {
1.22 nicm 145: char *escaped;
1.21 nicm 146:
147: if (**buf != '\0')
148: args_print_add(buf, len, " -%c ", entry->flag);
149: else
150: args_print_add(buf, len, "-%c ", entry->flag);
151:
1.22 nicm 152: escaped = args_escape(value->value);
153: args_print_add(buf, len, "%s", escaped);
1.21 nicm 154: free(escaped);
155: }
156:
157: /* Add argument to string. */
158: static void
159: args_print_add_argument(char **buf, size_t *len, const char *argument)
160: {
1.22 nicm 161: char *escaped;
1.21 nicm 162:
163: if (**buf != '\0')
164: args_print_add(buf, len, " ");
165:
1.22 nicm 166: escaped = args_escape(argument);
167: args_print_add(buf, len, "%s", escaped);
1.21 nicm 168: free(escaped);
169: }
170:
1.1 nicm 171: /* Print a set of arguments. */
1.12 nicm 172: char *
173: args_print(struct args *args)
1.1 nicm 174: {
1.12 nicm 175: size_t len;
1.21 nicm 176: char *buf;
177: int i;
1.27 ! nicm 178: u_int j;
1.5 nicm 179: struct args_entry *entry;
1.21 nicm 180: struct args_value *value;
1.1 nicm 181:
1.12 nicm 182: len = 1;
183: buf = xcalloc(1, len);
1.1 nicm 184:
185: /* Process the flags first. */
1.5 nicm 186: RB_FOREACH(entry, args_tree, &args->tree) {
1.21 nicm 187: if (!TAILQ_EMPTY(&entry->values))
1.1 nicm 188: continue;
189:
1.12 nicm 190: if (*buf == '\0')
191: args_print_add(&buf, &len, "-");
1.27 ! nicm 192: for (j = 0; j < entry->count; j++)
! 193: args_print_add(&buf, &len, "%c", entry->flag);
1.1 nicm 194: }
195:
196: /* Then the flags with arguments. */
1.5 nicm 197: RB_FOREACH(entry, args_tree, &args->tree) {
1.21 nicm 198: TAILQ_FOREACH(value, &entry->values, entry)
199: args_print_add_value(&buf, &len, entry, value);
1.1 nicm 200: }
201:
202: /* And finally the argument vector. */
1.21 nicm 203: for (i = 0; i < args->argc; i++)
204: args_print_add_argument(&buf, &len, args->argv[i]);
1.1 nicm 205:
1.12 nicm 206: return (buf);
1.22 nicm 207: }
208:
209: /* Escape an argument. */
210: char *
211: args_escape(const char *s)
212: {
1.23 nicm 213: static const char quoted[] = " #\"';${}";
1.22 nicm 214: char *escaped, *result;
215: int flags;
216:
1.24 nicm 217: if (*s == '\0')
218: return (xstrdup(s));
1.26 nicm 219: if (s[0] != ' ' &&
220: (strchr(quoted, s[0]) != NULL || s[0] == '~') &&
221: s[1] == '\0') {
1.22 nicm 222: xasprintf(&escaped, "\\%c", s[0]);
223: return (escaped);
224: }
225:
1.25 nicm 226: flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
1.22 nicm 227: if (s[strcspn(s, quoted)] != '\0')
228: flags |= VIS_DQ;
229: utf8_stravis(&escaped, s, flags);
230:
231: if (flags & VIS_DQ) {
232: if (*escaped == '~')
233: xasprintf(&result, "\"\\%s\"", escaped);
234: else
235: xasprintf(&result, "\"%s\"", escaped);
236: } else {
237: if (*escaped == '~')
238: xasprintf(&result, "\\%s", escaped);
239: else
240: result = xstrdup(escaped);
241: }
242: free(escaped);
243: return (result);
1.1 nicm 244: }
245:
246: /* Return if an argument is present. */
247: int
248: args_has(struct args *args, u_char ch)
249: {
1.27 ! nicm 250: struct args_entry *entry;
! 251:
! 252: entry = args_find(args, ch);
! 253: if (entry == NULL)
! 254: return (0);
! 255: return (entry->count);
1.1 nicm 256: }
257:
1.5 nicm 258: /* Set argument value in the arguments tree. */
1.19 nicm 259: void
1.21 nicm 260: args_set(struct args *args, u_char ch, const char *s)
1.1 nicm 261: {
1.5 nicm 262: struct args_entry *entry;
1.21 nicm 263: struct args_value *value;
1.5 nicm 264:
1.21 nicm 265: entry = args_find(args, ch);
266: if (entry == NULL) {
1.7 nicm 267: entry = xcalloc(1, sizeof *entry);
268: entry->flag = ch;
1.27 ! nicm 269: entry->count = 1;
1.21 nicm 270: TAILQ_INIT(&entry->values);
1.7 nicm 271: RB_INSERT(args_tree, &args->tree, entry);
1.27 ! nicm 272: } else
! 273: entry->count++;
1.5 nicm 274:
1.21 nicm 275: if (s != NULL) {
276: value = xcalloc(1, sizeof *value);
277: value->value = xstrdup(s);
278: TAILQ_INSERT_TAIL(&entry->values, value, entry);
279: }
1.1 nicm 280: }
281:
282: /* Get argument value. Will be NULL if it isn't present. */
283: const char *
284: args_get(struct args *args, u_char ch)
285: {
1.5 nicm 286: struct args_entry *entry;
287:
288: if ((entry = args_find(args, ch)) == NULL)
289: return (NULL);
1.21 nicm 290: return (TAILQ_LAST(&entry->values, args_values)->value);
291: }
292:
293: /* Get first value in argument. */
294: const char *
295: args_first_value(struct args *args, u_char ch, struct args_value **value)
296: {
297: struct args_entry *entry;
298:
299: if ((entry = args_find(args, ch)) == NULL)
300: return (NULL);
301:
302: *value = TAILQ_FIRST(&entry->values);
303: if (*value == NULL)
304: return (NULL);
305: return ((*value)->value);
306: }
307:
308: /* Get next value in argument. */
309: const char *
310: args_next_value(struct args_value **value)
311: {
312: if (*value == NULL)
313: return (NULL);
314: *value = TAILQ_NEXT(*value, entry);
315: if (*value == NULL)
316: return (NULL);
317: return ((*value)->value);
1.1 nicm 318: }
319:
320: /* Convert an argument value to a number. */
321: long long
1.5 nicm 322: args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
323: char **cause)
1.1 nicm 324: {
1.5 nicm 325: const char *errstr;
326: long long ll;
327: struct args_entry *entry;
1.21 nicm 328: struct args_value *value;
1.1 nicm 329:
1.5 nicm 330: if ((entry = args_find(args, ch)) == NULL) {
1.1 nicm 331: *cause = xstrdup("missing");
332: return (0);
333: }
1.21 nicm 334: value = TAILQ_LAST(&entry->values, args_values);
1.1 nicm 335:
1.21 nicm 336: ll = strtonum(value->value, minval, maxval, &errstr);
1.1 nicm 337: if (errstr != NULL) {
338: *cause = xstrdup(errstr);
339: return (0);
340: }
341:
342: *cause = NULL;
343: return (ll);
344: }