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