Annotation of src/usr.bin/tmux/arguments.c, Revision 1.20
1.20 ! nicm 1: /* $OpenBSD: arguments.c,v 1.19 2017/05/30 21:44: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:
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:
32: struct args_entry {
33: u_char flag;
34: char *value;
35: RB_ENTRY(args_entry) entry;
36: };
1.5 nicm 37:
1.14 nicm 38: static struct args_entry *args_find(struct args *, u_char);
1.5 nicm 39:
1.14 nicm 40: static int args_cmp(struct args_entry *, struct args_entry *);
41: RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
1.5 nicm 42:
43: /* Arguments tree comparison function. */
1.14 nicm 44: static int
1.5 nicm 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. */
1.14 nicm 51: static struct args_entry *
1.5 nicm 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:
1.1 nicm 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) {
1.5 nicm 73: if (opt < 0)
1.1 nicm 74: continue;
1.8 nicm 75: if (opt == '?' || strchr(template, opt) == NULL) {
1.5 nicm 76: args_free(args);
1.1 nicm 77: return (NULL);
78: }
1.5 nicm 79: args_set(args, opt, optarg);
1.1 nicm 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: {
1.5 nicm 94: struct args_entry *entry;
95: struct args_entry *entry1;
1.1 nicm 96:
97: cmd_free_argv(args->argc, args->argv);
98:
1.5 nicm 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: }
1.1 nicm 104:
1.4 nicm 105: free(args);
1.1 nicm 106: }
107:
1.12 nicm 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:
1.1 nicm 127: /* Print a set of arguments. */
1.12 nicm 128: char *
129: args_print(struct args *args)
1.1 nicm 130: {
1.12 nicm 131: size_t len;
1.16 nicm 132: char *buf, *escaped;
133: int i, flags;
1.5 nicm 134: struct args_entry *entry;
1.16 nicm 135: static const char quoted[] = " #\"';$";
1.1 nicm 136:
1.12 nicm 137: len = 1;
138: buf = xcalloc(1, len);
1.1 nicm 139:
140: /* Process the flags first. */
1.5 nicm 141: RB_FOREACH(entry, args_tree, &args->tree) {
142: if (entry->value != NULL)
1.1 nicm 143: continue;
144:
1.12 nicm 145: if (*buf == '\0')
146: args_print_add(&buf, &len, "-");
147: args_print_add(&buf, &len, "%c", entry->flag);
1.1 nicm 148: }
149:
150: /* Then the flags with arguments. */
1.5 nicm 151: RB_FOREACH(entry, args_tree, &args->tree) {
152: if (entry->value == NULL)
1.1 nicm 153: continue;
154:
1.12 nicm 155: if (*buf != '\0')
156: args_print_add(&buf, &len, " -%c ", entry->flag);
157: else
158: args_print_add(&buf, &len, "-%c ", entry->flag);
1.16 nicm 159:
160: flags = VIS_OCTAL|VIS_TAB|VIS_NL;
161: if (entry->value[strcspn(entry->value, quoted)] != '\0')
162: flags |= VIS_DQ;
1.17 nicm 163: utf8_stravis(&escaped, entry->value, flags);
1.16 nicm 164: if (flags & VIS_DQ)
165: args_print_add(&buf, &len, "\"%s\"", escaped);
1.1 nicm 166: else
1.16 nicm 167: args_print_add(&buf, &len, "%s", escaped);
168: free(escaped);
1.1 nicm 169: }
170:
171: /* And finally the argument vector. */
172: for (i = 0; i < args->argc; i++) {
1.12 nicm 173: if (*buf != '\0')
174: args_print_add(&buf, &len, " ");
1.16 nicm 175:
176: flags = VIS_OCTAL|VIS_TAB|VIS_NL;
177: if (args->argv[i][strcspn(args->argv[i], quoted)] != '\0')
178: flags |= VIS_DQ;
1.17 nicm 179: utf8_stravis(&escaped, args->argv[i], flags);
1.16 nicm 180: if (flags & VIS_DQ)
181: args_print_add(&buf, &len, "\"%s\"", escaped);
1.1 nicm 182: else
1.16 nicm 183: args_print_add(&buf, &len, "%s", escaped);
184: free(escaped);
1.1 nicm 185: }
186:
1.12 nicm 187: return (buf);
1.1 nicm 188: }
189:
190: /* Return if an argument is present. */
191: int
192: args_has(struct args *args, u_char ch)
193: {
1.20 ! nicm 194: return (args_find(args, ch) != NULL);
1.1 nicm 195: }
196:
1.5 nicm 197: /* Set argument value in the arguments tree. */
1.19 nicm 198: void
1.1 nicm 199: args_set(struct args *args, u_char ch, const char *value)
200: {
1.5 nicm 201: struct args_entry *entry;
202:
203: /* Replace existing argument. */
204: if ((entry = args_find(args, ch)) != NULL) {
205: free(entry->value);
1.7 nicm 206: entry->value = NULL;
207: } else {
208: entry = xcalloc(1, sizeof *entry);
209: entry->flag = ch;
210: RB_INSERT(args_tree, &args->tree, entry);
1.5 nicm 211: }
212:
1.2 nicm 213: if (value != NULL)
1.5 nicm 214: entry->value = xstrdup(value);
1.1 nicm 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: {
1.5 nicm 221: struct args_entry *entry;
222:
223: if ((entry = args_find(args, ch)) == NULL)
224: return (NULL);
225: return (entry->value);
1.1 nicm 226: }
227:
228: /* Convert an argument value to a number. */
229: long long
1.5 nicm 230: args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
231: char **cause)
1.1 nicm 232: {
1.5 nicm 233: const char *errstr;
234: long long ll;
235: struct args_entry *entry;
1.1 nicm 236:
1.5 nicm 237: if ((entry = args_find(args, ch)) == NULL) {
1.1 nicm 238: *cause = xstrdup("missing");
239: return (0);
240: }
241:
1.5 nicm 242: ll = strtonum(entry->value, minval, maxval, &errstr);
1.1 nicm 243: if (errstr != NULL) {
244: *cause = xstrdup(errstr);
245: return (0);
246: }
247:
248: *cause = NULL;
249: return (ll);
250: }