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