Annotation of src/usr.bin/tmux/arguments.c, Revision 1.15
1.15 ! nicm 1: /* $OpenBSD: arguments.c,v 1.14 2016/10/10 13:54:47 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.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.15 ! nicm 38: static void args_set(struct args *, u_char, const char *);
1.14 nicm 39: static struct args_entry *args_find(struct args *, u_char);
1.5 nicm 40:
1.14 nicm 41: static int args_cmp(struct args_entry *, struct args_entry *);
42: RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
1.5 nicm 43:
44: /* Arguments tree comparison function. */
1.14 nicm 45: static int
1.5 nicm 46: args_cmp(struct args_entry *a1, struct args_entry *a2)
47: {
48: return (a1->flag - a2->flag);
49: }
50:
51: /* Find a flag in the arguments tree. */
1.14 nicm 52: static struct args_entry *
1.5 nicm 53: args_find(struct args *args, u_char ch)
54: {
55: struct args_entry entry;
56:
57: entry.flag = ch;
58: return (RB_FIND(args_tree, &args->tree, &entry));
59: }
60:
1.1 nicm 61: /* Parse an argv and argc into a new argument set. */
62: struct args *
63: args_parse(const char *template, int argc, char **argv)
64: {
65: struct args *args;
66: int opt;
67:
68: args = xcalloc(1, sizeof *args);
69:
70: optreset = 1;
71: optind = 1;
72:
73: while ((opt = getopt(argc, argv, template)) != -1) {
1.5 nicm 74: if (opt < 0)
1.1 nicm 75: continue;
1.8 nicm 76: if (opt == '?' || strchr(template, opt) == NULL) {
1.5 nicm 77: args_free(args);
1.1 nicm 78: return (NULL);
79: }
1.5 nicm 80: args_set(args, opt, optarg);
1.1 nicm 81: }
82: argc -= optind;
83: argv += optind;
84:
85: args->argc = argc;
86: args->argv = cmd_copy_argv(argc, argv);
87:
88: return (args);
89: }
90:
91: /* Free an arguments set. */
92: void
93: args_free(struct args *args)
94: {
1.5 nicm 95: struct args_entry *entry;
96: struct args_entry *entry1;
1.1 nicm 97:
98: cmd_free_argv(args->argc, args->argv);
99:
1.5 nicm 100: RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
101: RB_REMOVE(args_tree, &args->tree, entry);
102: free(entry->value);
103: free(entry);
104: }
1.1 nicm 105:
1.4 nicm 106: free(args);
1.1 nicm 107: }
108:
1.12 nicm 109: /* Add to string. */
110: static void printflike(3, 4)
111: args_print_add(char **buf, size_t *len, const char *fmt, ...)
112: {
113: va_list ap;
114: char *s;
115: size_t slen;
116:
117: va_start(ap, fmt);
118: slen = xvasprintf(&s, fmt, ap);
119: va_end(ap);
120:
121: *len += slen;
122: *buf = xrealloc(*buf, *len);
123:
124: strlcat(*buf, s, *len);
125: free(s);
126: }
127:
1.1 nicm 128: /* Print a set of arguments. */
1.12 nicm 129: char *
130: args_print(struct args *args)
1.1 nicm 131: {
1.12 nicm 132: size_t len;
133: char *buf;
1.5 nicm 134: int i;
135: struct args_entry *entry;
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.5 nicm 159: if (strchr(entry->value, ' ') != NULL)
1.12 nicm 160: args_print_add(&buf, &len, "\"%s\"", entry->value);
1.1 nicm 161: else
1.12 nicm 162: args_print_add(&buf, &len, "%s", entry->value);
1.1 nicm 163: }
164:
165: /* And finally the argument vector. */
166: for (i = 0; i < args->argc; i++) {
1.12 nicm 167: if (*buf != '\0')
168: args_print_add(&buf, &len, " ");
1.1 nicm 169: if (strchr(args->argv[i], ' ') != NULL)
1.12 nicm 170: args_print_add(&buf, &len, "\"%s\"", args->argv[i]);
1.1 nicm 171: else
1.12 nicm 172: args_print_add(&buf, &len, "%s", args->argv[i]);
1.1 nicm 173: }
174:
1.12 nicm 175: return (buf);
1.1 nicm 176: }
177:
178: /* Return if an argument is present. */
179: int
180: args_has(struct args *args, u_char ch)
181: {
1.5 nicm 182: return (args_find(args, ch) == NULL ? 0 : 1);
1.1 nicm 183: }
184:
1.5 nicm 185: /* Set argument value in the arguments tree. */
1.15 ! nicm 186: static void
1.1 nicm 187: args_set(struct args *args, u_char ch, const char *value)
188: {
1.5 nicm 189: struct args_entry *entry;
190:
191: /* Replace existing argument. */
192: if ((entry = args_find(args, ch)) != NULL) {
193: free(entry->value);
1.7 nicm 194: entry->value = NULL;
195: } else {
196: entry = xcalloc(1, sizeof *entry);
197: entry->flag = ch;
198: RB_INSERT(args_tree, &args->tree, entry);
1.5 nicm 199: }
200:
1.2 nicm 201: if (value != NULL)
1.5 nicm 202: entry->value = xstrdup(value);
1.1 nicm 203: }
204:
205: /* Get argument value. Will be NULL if it isn't present. */
206: const char *
207: args_get(struct args *args, u_char ch)
208: {
1.5 nicm 209: struct args_entry *entry;
210:
211: if ((entry = args_find(args, ch)) == NULL)
212: return (NULL);
213: return (entry->value);
1.1 nicm 214: }
215:
216: /* Convert an argument value to a number. */
217: long long
1.5 nicm 218: args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
219: char **cause)
1.1 nicm 220: {
1.5 nicm 221: const char *errstr;
222: long long ll;
223: struct args_entry *entry;
1.1 nicm 224:
1.5 nicm 225: if ((entry = args_find(args, ch)) == NULL) {
1.1 nicm 226: *cause = xstrdup("missing");
227: return (0);
228: }
229:
1.5 nicm 230: ll = strtonum(entry->value, minval, maxval, &errstr);
1.1 nicm 231: if (errstr != NULL) {
232: *cause = xstrdup(errstr);
233: return (0);
234: }
235:
236: *cause = NULL;
237: return (ll);
238: }