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