Annotation of src/usr.bin/tmux/cmd-generic.c, Revision 1.8
1.8 ! nicm 1: /* $OpenBSD: cmd-generic.c,v 1.7 2009/08/26 18:09:52 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2008 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>
23:
24: #include "tmux.h"
25:
1.8 ! nicm 26: int cmd_getopt(int, char **, const char *, const char *);
! 27: int cmd_parse_flags(int, const char *, uint64_t *);
1.3 nicm 28: size_t cmd_print_flags(char *, size_t, size_t, uint64_t);
1.6 nicm 29: int cmd_fill_argument(int, char **, char **, int, char **);
1.1 nicm 30:
31: size_t
32: cmd_prarg(char *buf, size_t len, const char *prefix, char *arg)
33: {
34: if (strchr(arg, ' ') != NULL)
35: return (xsnprintf(buf, len, "%s\"%s\"", prefix, arg));
36: return (xsnprintf(buf, len, "%s%s", prefix, arg));
37: }
38:
1.8 ! nicm 39: /* Append two flag strings together and call getopt. */
1.1 nicm 40: int
1.8 ! nicm 41: cmd_getopt(int argc, char **argv, const char *flagstr, const char *chflagstr)
1.1 nicm 42: {
1.8 ! nicm 43: char tmp[BUFSIZ];
1.3 nicm 44:
1.8 ! nicm 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));
! 50: }
1.3 nicm 51:
1.8 ! nicm 52: /* Return if flag character is set. */
! 53: int
! 54: cmd_check_flag(uint64_t chflags, int flag)
! 55: {
! 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);
! 63: }
1.3 nicm 64:
1.8 ! nicm 65: /* Set flag character. */
! 66: void
! 67: cmd_set_flag(uint64_t *chflags, int flag)
! 68: {
! 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);
1.3 nicm 76: }
77:
1.8 ! nicm 78: /* If this option is expected, set it in chflags, otherwise return -1. */
1.3 nicm 79: int
1.8 ! nicm 80: cmd_parse_flags(int opt, const char *chflagstr, uint64_t *chflags)
1.3 nicm 81: {
1.8 ! nicm 82: if (strchr(chflagstr, opt) == NULL)
! 83: return (-1);
! 84: cmd_set_flag(chflags, opt);
! 85: return (0);
1.1 nicm 86: }
87:
1.3 nicm 88: /* Print the flags supported in chflags. */
1.1 nicm 89: size_t
1.3 nicm 90: cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags)
1.1 nicm 91: {
1.3 nicm 92: u_char ch;
1.1 nicm 93: size_t boff = off;
94:
1.3 nicm 95: if (chflags == 0)
1.1 nicm 96: return (0);
97: off += xsnprintf(buf + off, len - off, " -");
1.3 nicm 98:
99: for (ch = 0; ch < 26; ch++) {
1.8 ! nicm 100: if (cmd_check_flag(chflags, 'a' + ch))
1.3 nicm 101: off += xsnprintf(buf + off, len - off, "%c", 'a' + ch);
1.8 ! nicm 102: if (cmd_check_flag(chflags, 'A' + ch))
1.3 nicm 103: off += xsnprintf(buf + off, len - off, "%c", 'A' + ch);
104: }
1.1 nicm 105: return (off - boff);
106: }
107:
108: int
1.6 nicm 109: cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv)
1.1 nicm 110: {
111: *arg = NULL;
1.6 nicm 112: *arg2 = NULL;
1.1 nicm 113:
114: if (flags & CMD_ARG1) {
115: if (argc != 1)
116: return (-1);
117: *arg = xstrdup(argv[0]);
118: return (0);
119: }
120:
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);
127: }
128:
1.6 nicm 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);
135: }
136:
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);
144: }
145:
1.1 nicm 146: if (argc != 0)
147: return (-1);
148: return (0);
149: }
150:
151: void
152: cmd_target_init(struct cmd *self, unused int key)
153: {
154: struct cmd_target_data *data;
155:
156: self->data = data = xmalloc(sizeof *data);
1.3 nicm 157: data->chflags = 0;
1.1 nicm 158: data->target = NULL;
159: data->arg = NULL;
1.7 nicm 160: data->arg2 = NULL;
1.1 nicm 161: }
162:
163: int
164: cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
165: {
166: struct cmd_target_data *data;
1.3 nicm 167: const struct cmd_entry *entry = self->entry;
1.1 nicm 168: int opt;
169:
170: /* Don't use the entry version since it may be dependent on key. */
171: cmd_target_init(self, 0);
172: data = self->data;
173:
1.3 nicm 174: while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
1.8 ! nicm 175: if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 176: continue;
177: switch (opt) {
178: case 't':
179: if (data->target == NULL)
180: data->target = xstrdup(optarg);
181: break;
182: default:
183: goto usage;
184: }
185: }
186: argc -= optind;
187: argv += optind;
188:
1.6 nicm 189: if (cmd_fill_argument(
190: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 191: goto usage;
192: return (0);
193:
194: usage:
195: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
196:
197: self->entry->free(self);
198: return (-1);
199: }
200:
201: void
202: cmd_target_free(struct cmd *self)
203: {
204: struct cmd_target_data *data = self->data;
205:
206: if (data->target != NULL)
207: xfree(data->target);
208: if (data->arg != NULL)
209: xfree(data->arg);
1.7 nicm 210: if (data->arg2 != NULL)
211: xfree(data->arg2);
1.1 nicm 212: xfree(data);
213: }
214:
215: size_t
216: cmd_target_print(struct cmd *self, char *buf, size_t len)
217: {
218: struct cmd_target_data *data = self->data;
219: size_t off = 0;
220:
221: off += xsnprintf(buf, len, "%s", self->entry->name);
222: if (data == NULL)
223: return (off);
1.3 nicm 224: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 225: if (off < len && data->target != NULL)
226: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
227: if (off < len && data->arg != NULL)
228: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.6 nicm 229: if (off < len && data->arg2 != NULL)
230: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 231: return (off);
232: }
233:
234: void
235: cmd_srcdst_init(struct cmd *self, unused int key)
236: {
237: struct cmd_srcdst_data *data;
238:
239: self->data = data = xmalloc(sizeof *data);
1.3 nicm 240: data->chflags = 0;
1.1 nicm 241: data->src = NULL;
242: data->dst = NULL;
243: data->arg = NULL;
1.7 nicm 244: data->arg2 = NULL;
1.1 nicm 245: }
246:
247: int
248: cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
249: {
250: struct cmd_srcdst_data *data;
1.3 nicm 251: const struct cmd_entry *entry = self->entry;
1.1 nicm 252: int opt;
253:
254: cmd_srcdst_init(self, 0);
255: data = self->data;
256:
1.3 nicm 257: while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) {
1.8 ! nicm 258: if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 259: continue;
260: switch (opt) {
261: case 's':
262: if (data->src == NULL)
263: data->src = xstrdup(optarg);
264: break;
265: case 't':
266: if (data->dst == NULL)
267: data->dst = xstrdup(optarg);
268: break;
269: default:
270: goto usage;
271: }
272: }
273: argc -= optind;
274: argv += optind;
275:
1.6 nicm 276: if (cmd_fill_argument(
277: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 278: goto usage;
279: return (0);
280:
281: usage:
282: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
283:
284: self->entry->free(self);
285: return (-1);
286: }
287:
288: void
289: cmd_srcdst_free(struct cmd *self)
290: {
291: struct cmd_srcdst_data *data = self->data;
292:
293: if (data->src != NULL)
294: xfree(data->src);
295: if (data->dst != NULL)
296: xfree(data->dst);
297: if (data->arg != NULL)
298: xfree(data->arg);
1.7 nicm 299: if (data->arg2 != NULL)
300: xfree(data->arg2);
1.1 nicm 301: xfree(data);
302: }
303:
304: size_t
305: cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
306: {
307: struct cmd_srcdst_data *data = self->data;
308: size_t off = 0;
309:
310: off += xsnprintf(buf, len, "%s", self->entry->name);
311: if (data == NULL)
312: return (off);
1.3 nicm 313: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 314: if (off < len && data->src != NULL)
315: off += xsnprintf(buf + off, len - off, " -s %s", data->src);
316: if (off < len && data->dst != NULL)
317: off += xsnprintf(buf + off, len - off, " -t %s", data->dst);
318: if (off < len && data->arg != NULL)
319: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.6 nicm 320: if (off < len && data->arg2 != NULL)
321: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 322: return (off);
323: }
324:
325: void
326: cmd_buffer_init(struct cmd *self, unused int key)
327: {
328: struct cmd_buffer_data *data;
329:
330: self->data = data = xmalloc(sizeof *data);
1.3 nicm 331: data->chflags = 0;
1.1 nicm 332: data->target = NULL;
333: data->buffer = -1;
334: data->arg = NULL;
1.7 nicm 335: data->arg2 = NULL;
1.1 nicm 336: }
337:
338: int
339: cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
340: {
341: struct cmd_buffer_data *data;
1.3 nicm 342: const struct cmd_entry *entry = self->entry;
1.1 nicm 343: int opt, n;
344: const char *errstr;
345:
346: cmd_buffer_init(self, 0);
347: data = self->data;
348:
1.3 nicm 349: while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) {
1.8 ! nicm 350: if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 351: continue;
352: switch (opt) {
353: case 'b':
354: if (data->buffer == -1) {
355: n = strtonum(optarg, 0, INT_MAX, &errstr);
356: if (errstr != NULL) {
357: xasprintf(cause, "buffer %s", errstr);
358: goto error;
359: }
360: data->buffer = n;
361: }
362: break;
363: case 't':
364: if (data->target == NULL)
365: data->target = xstrdup(optarg);
366: break;
367: default:
368: goto usage;
369: }
370: }
371: argc -= optind;
372: argv += optind;
373:
1.6 nicm 374: if (cmd_fill_argument(
375: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 376: goto usage;
377: return (0);
378:
379: usage:
380: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
381:
382: error:
383: self->entry->free(self);
384: return (-1);
385: }
386:
387: void
388: cmd_buffer_free(struct cmd *self)
389: {
390: struct cmd_buffer_data *data = self->data;
391:
392: if (data->target != NULL)
393: xfree(data->target);
394: if (data->arg != NULL)
395: xfree(data->arg);
1.7 nicm 396: if (data->arg2 != NULL)
397: xfree(data->arg2);
1.1 nicm 398: xfree(data);
399: }
400:
401: size_t
402: cmd_buffer_print(struct cmd *self, char *buf, size_t len)
403: {
404: struct cmd_buffer_data *data = self->data;
405: size_t off = 0;
406:
407: off += xsnprintf(buf, len, "%s", self->entry->name);
408: if (data == NULL)
409: return (off);
1.3 nicm 410: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 411: if (off < len && data->buffer != -1)
412: off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
413: if (off < len && data->target != NULL)
414: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
415: if (off < len && data->arg != NULL)
416: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.6 nicm 417: if (off < len && data->arg2 != NULL)
418: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 419: return (off);
420: }