Add host_short format, from Tiago Cunha.
[tmux-openbsd.git] / arguments.c
blobca828f005fc51a98e4c46c1c3d7ab210d5b79837
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2010 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <string.h>
24 #include "tmux.h"
27 * Manipulate command arguments.
30 struct args_entry *args_find(struct args *, u_char);
32 RB_GENERATE(args_tree, args_entry, entry, args_cmp);
34 /* Arguments tree comparison function. */
35 int
36 args_cmp(struct args_entry *a1, struct args_entry *a2)
38 return (a1->flag - a2->flag);
41 /* Create an arguments set with no flags. */
42 struct args *
43 args_create(int argc, ...)
45 struct args *args;
46 va_list ap;
47 int i;
49 args = xcalloc(1, sizeof *args);
51 args->argc = argc;
52 if (argc == 0)
53 args->argv = NULL;
54 else
55 args->argv = xcalloc(argc, sizeof *args->argv);
57 va_start(ap, argc);
58 for (i = 0; i < argc; i++)
59 args->argv[i] = xstrdup(va_arg(ap, char *));
60 va_end(ap);
62 return (args);
65 /* Find a flag in the arguments tree. */
66 struct args_entry *
67 args_find(struct args *args, u_char ch)
69 struct args_entry entry;
71 entry.flag = ch;
72 return (RB_FIND(args_tree, &args->tree, &entry));
75 /* Parse an argv and argc into a new argument set. */
76 struct args *
77 args_parse(const char *template, int argc, char **argv)
79 struct args *args;
80 char *ptr;
81 int opt;
83 args = xcalloc(1, sizeof *args);
85 optreset = 1;
86 optind = 1;
88 while ((opt = getopt(argc, argv, template)) != -1) {
89 if (opt < 0)
90 continue;
91 if (opt == '?' || (ptr = strchr(template, opt)) == NULL) {
92 args_free(args);
93 return (NULL);
95 args_set(args, opt, optarg);
97 argc -= optind;
98 argv += optind;
100 args->argc = argc;
101 args->argv = cmd_copy_argv(argc, argv);
103 return (args);
106 /* Free an arguments set. */
107 void
108 args_free(struct args *args)
110 struct args_entry *entry;
111 struct args_entry *entry1;
113 cmd_free_argv(args->argc, args->argv);
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);
121 free(args);
124 /* Print a set of arguments. */
125 size_t
126 args_print(struct args *args, char *buf, size_t len)
128 size_t off;
129 int i;
130 const char *quotes;
131 struct args_entry *entry;
133 /* There must be at least one byte at the start. */
134 if (len == 0)
135 return (0);
136 off = 0;
138 /* Process the flags first. */
139 buf[off++] = '-';
140 RB_FOREACH(entry, args_tree, &args->tree) {
141 if (entry->value != NULL)
142 continue;
144 if (off == len - 1) {
145 buf[off] = '\0';
146 return (len);
148 buf[off++] = entry->flag;
149 buf[off] = '\0';
151 if (off == 1)
152 buf[--off] = '\0';
154 /* Then the flags with arguments. */
155 RB_FOREACH(entry, args_tree, &args->tree) {
156 if (entry->value == NULL)
157 continue;
159 if (off >= len) {
160 /* snprintf will have zero terminated. */
161 return (len);
164 if (strchr(entry->value, ' ') != NULL)
165 quotes = "\"";
166 else
167 quotes = "";
168 off += xsnprintf(buf + off, len - off, "%s-%c %s%s%s",
169 off != 0 ? " " : "", entry->flag, quotes, entry->value,
170 quotes);
173 /* And finally the argument vector. */
174 for (i = 0; i < args->argc; i++) {
175 if (off >= len) {
176 /* snprintf will have zero terminated. */
177 return (len);
180 if (strchr(args->argv[i], ' ') != NULL)
181 quotes = "\"";
182 else
183 quotes = "";
184 off += xsnprintf(buf + off, len - off, "%s%s%s%s",
185 off != 0 ? " " : "", quotes, args->argv[i], quotes);
188 return (off);
191 /* Return if an argument is present. */
193 args_has(struct args *args, u_char ch)
195 return (args_find(args, ch) == NULL ? 0 : 1);
198 /* Set argument value in the arguments tree. */
199 void
200 args_set(struct args *args, u_char ch, const char *value)
202 struct args_entry *entry;
204 /* Replace existing argument. */
205 if ((entry = args_find(args, ch)) != NULL) {
206 free(entry->value);
207 if (value != NULL)
208 entry->value = xstrdup(value);
209 else
210 entry->value = NULL;
211 return;
214 entry = xcalloc(1, sizeof *entry);
215 entry->flag = ch;
216 if (value != NULL)
217 entry->value = xstrdup(value);
219 RB_INSERT(args_tree, &args->tree, entry);
222 /* Get argument value. Will be NULL if it isn't present. */
223 const char *
224 args_get(struct args *args, u_char ch)
226 struct args_entry *entry;
228 if ((entry = args_find(args, ch)) == NULL)
229 return (NULL);
230 return (entry->value);
233 /* Convert an argument value to a number. */
234 long long
235 args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
236 char **cause)
238 const char *errstr;
239 long long ll;
240 struct args_entry *entry;
242 if ((entry = args_find(args, ch)) == NULL) {
243 *cause = xstrdup("missing");
244 return (0);
247 ll = strtonum(entry->value, minval, maxval, &errstr);
248 if (errstr != NULL) {
249 *cause = xstrdup(errstr);
250 return (0);
253 *cause = NULL;
254 return (ll);