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