Undo a change to next/previous session that got mixed in prematurely.
[tmux-openbsd.git] / cmd-generic.c
blob8b536fa085676f86b830d5e4558742b37580151e
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2008 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"
26 int cmd_getopt(int, char **, const char *, const char *);
27 int cmd_parse_flags(int, const char *, uint64_t *);
28 size_t cmd_print_flags(char *, size_t, size_t, uint64_t);
29 int cmd_fill_argument(int, char **, char **, int, char **);
31 size_t
32 cmd_prarg(char *buf, size_t len, const char *prefix, char *arg)
34 if (strchr(arg, ' ') != NULL)
35 return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg));
36 return (xsnprintf(buf, len, "%s%s", prefix, arg));
39 /* Append two flag strings together and call getopt. */
40 int
41 cmd_getopt(int argc, char **argv, const char *flagstr, const char *chflagstr)
43 char tmp[BUFSIZ];
45 if (strlcpy(tmp, flagstr, sizeof tmp) >= sizeof tmp)
46 fatalx("strlcpy overflow");
47 if (strlcat(tmp, chflagstr, sizeof tmp) >= sizeof tmp)
48 fatalx("strlcat overflow");
49 return (getopt(argc, argv, tmp));
52 /* Return if flag character is set. */
53 int
54 cmd_check_flag(uint64_t chflags, int flag)
56 if (flag >= 'A' && flag <= 'Z')
57 flag = 26 + flag - 'A';
58 else if (flag >= 'a' && flag <= 'z')
59 flag = flag - 'a';
60 else
61 return (0);
62 return ((chflags & (1ULL << flag)) != 0);
65 /* Set flag character. */
66 void
67 cmd_set_flag(uint64_t *chflags, int flag)
69 if (flag >= 'A' && flag <= 'Z')
70 flag = 26 + flag - 'A';
71 else if (flag >= 'a' && flag <= 'z')
72 flag = flag - 'a';
73 else
74 return;
75 (*chflags) |= (1ULL << flag);
78 /* If this option is expected, set it in chflags, otherwise return -1. */
79 int
80 cmd_parse_flags(int opt, const char *chflagstr, uint64_t *chflags)
82 if (strchr(chflagstr, opt) == NULL)
83 return (-1);
84 cmd_set_flag(chflags, opt);
85 return (0);
88 /* Print the flags present in chflags. */
89 size_t
90 cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags)
92 u_char ch;
93 size_t boff = off;
95 if (chflags == 0)
96 return (0);
97 off += xsnprintf(buf + off, len - off, " -");
99 for (ch = 0; ch < 26; ch++) {
100 if (cmd_check_flag(chflags, 'a' + ch))
101 off += xsnprintf(buf + off, len - off, "%c", 'a' + ch);
102 if (cmd_check_flag(chflags, 'A' + ch))
103 off += xsnprintf(buf + off, len - off, "%c", 'A' + ch);
105 return (off - boff);
109 cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv)
111 *arg = NULL;
112 *arg2 = NULL;
114 if (flags & CMD_ARG1) {
115 if (argc != 1)
116 return (-1);
117 *arg = xstrdup(argv[0]);
118 return (0);
121 if (flags & CMD_ARG01) {
122 if (argc != 0 && argc != 1)
123 return (-1);
124 if (argc == 1)
125 *arg = xstrdup(argv[0]);
126 return (0);
129 if (flags & CMD_ARG2) {
130 if (argc != 2)
131 return (-1);
132 *arg = xstrdup(argv[0]);
133 *arg2 = xstrdup(argv[1]);
134 return (0);
137 if (flags & CMD_ARG12) {
138 if (argc != 1 && argc != 2)
139 return (-1);
140 *arg = xstrdup(argv[0]);
141 if (argc == 2)
142 *arg2 = xstrdup(argv[1]);
143 return (0);
146 if (argc != 0)
147 return (-1);
148 return (0);
151 /* ARGSUSED */
152 void
153 cmd_target_init(struct cmd *self, unused int key)
155 struct cmd_target_data *data;
157 self->data = data = xmalloc(sizeof *data);
158 data->chflags = 0;
159 data->target = NULL;
160 data->arg = NULL;
161 data->arg2 = NULL;
165 cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
167 struct cmd_target_data *data;
168 const struct cmd_entry *entry = self->entry;
169 int opt;
171 /* Don't use the entry version since it may be dependent on key. */
172 cmd_target_init(self, 0);
173 data = self->data;
175 while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
176 if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
177 continue;
178 switch (opt) {
179 case 't':
180 if (data->target == NULL)
181 data->target = xstrdup(optarg);
182 break;
183 default:
184 goto usage;
187 argc -= optind;
188 argv += optind;
190 if (cmd_fill_argument(
191 self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
192 goto usage;
193 return (0);
195 usage:
196 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
198 self->entry->free(self);
199 return (-1);
202 void
203 cmd_target_free(struct cmd *self)
205 struct cmd_target_data *data = self->data;
207 if (data->target != NULL)
208 xfree(data->target);
209 if (data->arg != NULL)
210 xfree(data->arg);
211 if (data->arg2 != NULL)
212 xfree(data->arg2);
213 xfree(data);
216 size_t
217 cmd_target_print(struct cmd *self, char *buf, size_t len)
219 struct cmd_target_data *data = self->data;
220 size_t off = 0;
222 off += xsnprintf(buf, len, "%s", self->entry->name);
223 if (data == NULL)
224 return (off);
225 off += cmd_print_flags(buf, len, off, data->chflags);
226 if (off < len && data->target != NULL)
227 off += cmd_prarg(buf + off, len - off, " -t ", data->target);
228 if (off < len && data->arg != NULL)
229 off += cmd_prarg(buf + off, len - off, " ", data->arg);
230 if (off < len && data->arg2 != NULL)
231 off += cmd_prarg(buf + off, len - off, " ", data->arg2);
232 return (off);
235 /* ARGSUSED */
236 void
237 cmd_srcdst_init(struct cmd *self, unused int key)
239 struct cmd_srcdst_data *data;
241 self->data = data = xmalloc(sizeof *data);
242 data->chflags = 0;
243 data->src = NULL;
244 data->dst = NULL;
245 data->arg = NULL;
246 data->arg2 = NULL;
250 cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
252 struct cmd_srcdst_data *data;
253 const struct cmd_entry *entry = self->entry;
254 int opt;
256 cmd_srcdst_init(self, 0);
257 data = self->data;
259 while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) {
260 if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
261 continue;
262 switch (opt) {
263 case 's':
264 if (data->src == NULL)
265 data->src = xstrdup(optarg);
266 break;
267 case 't':
268 if (data->dst == NULL)
269 data->dst = xstrdup(optarg);
270 break;
271 default:
272 goto usage;
275 argc -= optind;
276 argv += optind;
278 if (cmd_fill_argument(
279 self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
280 goto usage;
281 return (0);
283 usage:
284 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
286 self->entry->free(self);
287 return (-1);
290 void
291 cmd_srcdst_free(struct cmd *self)
293 struct cmd_srcdst_data *data = self->data;
295 if (data->src != NULL)
296 xfree(data->src);
297 if (data->dst != NULL)
298 xfree(data->dst);
299 if (data->arg != NULL)
300 xfree(data->arg);
301 if (data->arg2 != NULL)
302 xfree(data->arg2);
303 xfree(data);
306 size_t
307 cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
309 struct cmd_srcdst_data *data = self->data;
310 size_t off = 0;
312 off += xsnprintf(buf, len, "%s", self->entry->name);
313 if (data == NULL)
314 return (off);
315 off += cmd_print_flags(buf, len, off, data->chflags);
316 if (off < len && data->src != NULL)
317 off += xsnprintf(buf + off, len - off, " -s %s", data->src);
318 if (off < len && data->dst != NULL)
319 off += xsnprintf(buf + off, len - off, " -t %s", data->dst);
320 if (off < len && data->arg != NULL)
321 off += cmd_prarg(buf + off, len - off, " ", data->arg);
322 if (off < len && data->arg2 != NULL)
323 off += cmd_prarg(buf + off, len - off, " ", data->arg2);
324 return (off);
327 /* ARGSUSED */
328 void
329 cmd_buffer_init(struct cmd *self, unused int key)
331 struct cmd_buffer_data *data;
333 self->data = data = xmalloc(sizeof *data);
334 data->chflags = 0;
335 data->target = NULL;
336 data->buffer = -1;
337 data->arg = NULL;
338 data->arg2 = NULL;
342 cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
344 struct cmd_buffer_data *data;
345 const struct cmd_entry *entry = self->entry;
346 int opt, n;
347 const char *errstr;
349 cmd_buffer_init(self, 0);
350 data = self->data;
352 while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) {
353 if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
354 continue;
355 switch (opt) {
356 case 'b':
357 if (data->buffer == -1) {
358 n = strtonum(optarg, 0, INT_MAX, &errstr);
359 if (errstr != NULL) {
360 xasprintf(cause, "buffer %s", errstr);
361 goto error;
363 data->buffer = n;
365 break;
366 case 't':
367 if (data->target == NULL)
368 data->target = xstrdup(optarg);
369 break;
370 default:
371 goto usage;
374 argc -= optind;
375 argv += optind;
377 if (cmd_fill_argument(
378 self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
379 goto usage;
380 return (0);
382 usage:
383 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
385 error:
386 self->entry->free(self);
387 return (-1);
390 void
391 cmd_buffer_free(struct cmd *self)
393 struct cmd_buffer_data *data = self->data;
395 if (data->target != NULL)
396 xfree(data->target);
397 if (data->arg != NULL)
398 xfree(data->arg);
399 if (data->arg2 != NULL)
400 xfree(data->arg2);
401 xfree(data);
404 size_t
405 cmd_buffer_print(struct cmd *self, char *buf, size_t len)
407 struct cmd_buffer_data *data = self->data;
408 size_t off = 0;
410 off += xsnprintf(buf, len, "%s", self->entry->name);
411 if (data == NULL)
412 return (off);
413 off += cmd_print_flags(buf, len, off, data->chflags);
414 if (off < len && data->buffer != -1)
415 off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
416 if (off < len && data->target != NULL)
417 off += cmd_prarg(buf + off, len - off, " -t ", data->target);
418 if (off < len && data->arg != NULL)
419 off += cmd_prarg(buf + off, len - off, " ", data->arg);
420 if (off < len && data->arg2 != NULL)
421 off += cmd_prarg(buf + off, len - off, " ", data->arg2);
422 return (off);