Annotation of src/usr.bin/tmux/cmd-generic.c, Revision 1.4
1.4 ! nicm 1: /* $OpenBSD: cmd-generic.c,v 1.3 2009/07/13 23:11:35 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.3 nicm 26: int cmd_getopt(int, char **, const char *, uint64_t);
27: int cmd_flags(int, uint64_t, uint64_t *);
28: size_t cmd_print_flags(char *, size_t, size_t, uint64_t);
1.1 nicm 29: int cmd_fill_argument(int, char **, int, char **);
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.3 nicm 39: /* Prepend flags from chflags onto flagstr and call getopt. */
1.1 nicm 40: int
1.3 nicm 41: cmd_getopt(int argc, char **argv, const char *flagstr, uint64_t chflags)
1.1 nicm 42: {
1.3 nicm 43: u_char ch;
44: char buf[128];
45: size_t len, off;
46:
47: *buf = '\0';
48:
49: len = sizeof buf;
50: off = 0;
51:
52: for (ch = 0; ch < 26; ch++) {
53: if (chflags & CMD_CHFLAG('a' + ch))
54: off += xsnprintf(buf + off, len - off, "%c", 'a' + ch);
55: if (chflags & CMD_CHFLAG('A' + ch))
56: off += xsnprintf(buf + off, len - off, "%c", 'A' + ch);
57: }
58:
59: strlcat(buf, flagstr, sizeof buf);
60:
61: return (getopt(argc, argv, buf));
62: }
63:
64: /*
65: * If this option is expected (in ichflags), set it in ochflags, otherwise
66: * return -1.
67: */
68: int
69: cmd_flags(int opt, uint64_t ichflags, uint64_t *ochflags)
70: {
71: u_char ch;
72:
73: for (ch = 0; ch < 26; ch++) {
74: if (opt == 'a' + ch && ichflags & CMD_CHFLAG(opt)) {
75: (*ochflags) |= CMD_CHFLAG(opt);
1.1 nicm 76: return (0);
77: }
1.3 nicm 78: if (opt == 'A' + ch && ichflags & CMD_CHFLAG(opt)) {
79: (*ochflags) |= CMD_CHFLAG(opt);
1.1 nicm 80: return (0);
81: }
82: }
1.3 nicm 83: return (-1);
1.1 nicm 84: }
85:
1.3 nicm 86: /* Print the flags supported in chflags. */
1.1 nicm 87: size_t
1.3 nicm 88: cmd_print_flags(char *buf, size_t len, size_t off, uint64_t chflags)
1.1 nicm 89: {
1.3 nicm 90: u_char ch;
1.1 nicm 91: size_t boff = off;
92:
1.3 nicm 93: if (chflags == 0)
1.1 nicm 94: return (0);
95: off += xsnprintf(buf + off, len - off, " -");
1.3 nicm 96:
97: for (ch = 0; ch < 26; ch++) {
98: if (chflags & CMD_CHFLAG('a' + ch))
99: off += xsnprintf(buf + off, len - off, "%c", 'a' + ch);
100: if (chflags & CMD_CHFLAG('A' + ch))
101: off += xsnprintf(buf + off, len - off, "%c", 'A' + ch);
102: }
1.1 nicm 103: return (off - boff);
104: }
105:
106: int
107: cmd_fill_argument(int flags, char **arg, int argc, char **argv)
108: {
109: *arg = NULL;
110:
111: if (flags & CMD_ARG1) {
112: if (argc != 1)
113: return (-1);
114: *arg = xstrdup(argv[0]);
115: return (0);
116: }
117:
118: if (flags & CMD_ARG01) {
119: if (argc != 0 && argc != 1)
120: return (-1);
121: if (argc == 1)
122: *arg = xstrdup(argv[0]);
123: return (0);
124: }
125:
126: if (argc != 0)
127: return (-1);
128: return (0);
129: }
130:
131: void
132: cmd_target_init(struct cmd *self, unused int key)
133: {
134: struct cmd_target_data *data;
135:
136: self->data = data = xmalloc(sizeof *data);
1.3 nicm 137: data->chflags = 0;
1.1 nicm 138: data->target = NULL;
139: data->arg = NULL;
140: }
141:
142: int
143: cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
144: {
145: struct cmd_target_data *data;
1.3 nicm 146: const struct cmd_entry *entry = self->entry;
1.1 nicm 147: int opt;
148:
149: /* Don't use the entry version since it may be dependent on key. */
150: cmd_target_init(self, 0);
151: data = self->data;
152:
1.3 nicm 153: while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
154: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 155: continue;
156: switch (opt) {
157: case 't':
158: if (data->target == NULL)
159: data->target = xstrdup(optarg);
160: break;
161: default:
162: goto usage;
163: }
164: }
165: argc -= optind;
166: argv += optind;
167:
168: if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
169: goto usage;
170: return (0);
171:
172: usage:
173: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
174:
175: self->entry->free(self);
176: return (-1);
177: }
178:
179: void
180: cmd_target_free(struct cmd *self)
181: {
182: struct cmd_target_data *data = self->data;
183:
184: if (data->target != NULL)
185: xfree(data->target);
186: if (data->arg != NULL)
187: xfree(data->arg);
188: xfree(data);
189: }
190:
191: size_t
192: cmd_target_print(struct cmd *self, char *buf, size_t len)
193: {
194: struct cmd_target_data *data = self->data;
195: size_t off = 0;
196:
197: off += xsnprintf(buf, len, "%s", self->entry->name);
198: if (data == NULL)
199: return (off);
1.3 nicm 200: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 201: if (off < len && data->target != NULL)
202: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
203: if (off < len && data->arg != NULL)
204: off += cmd_prarg(buf + off, len - off, " ", data->arg);
205: return (off);
206: }
207:
208: void
209: cmd_srcdst_init(struct cmd *self, unused int key)
210: {
211: struct cmd_srcdst_data *data;
212:
213: self->data = data = xmalloc(sizeof *data);
1.3 nicm 214: data->chflags = 0;
1.1 nicm 215: data->src = NULL;
216: data->dst = NULL;
217: data->arg = NULL;
218: }
219:
220: int
221: cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
222: {
223: struct cmd_srcdst_data *data;
1.3 nicm 224: const struct cmd_entry *entry = self->entry;
1.1 nicm 225: int opt;
226:
227: cmd_srcdst_init(self, 0);
228: data = self->data;
229:
1.3 nicm 230: while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) {
231: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 232: continue;
233: switch (opt) {
234: case 's':
235: if (data->src == NULL)
236: data->src = xstrdup(optarg);
237: break;
238: case 't':
239: if (data->dst == NULL)
240: data->dst = xstrdup(optarg);
241: break;
242: default:
243: goto usage;
244: }
245: }
246: argc -= optind;
247: argv += optind;
248:
249: if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
250: goto usage;
251: return (0);
252:
253: usage:
254: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
255:
256: self->entry->free(self);
257: return (-1);
258: }
259:
260: void
261: cmd_srcdst_free(struct cmd *self)
262: {
263: struct cmd_srcdst_data *data = self->data;
264:
265: if (data->src != NULL)
266: xfree(data->src);
267: if (data->dst != NULL)
268: xfree(data->dst);
269: if (data->arg != NULL)
270: xfree(data->arg);
271: xfree(data);
272: }
273:
274: size_t
275: cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
276: {
277: struct cmd_srcdst_data *data = self->data;
278: size_t off = 0;
279:
280: off += xsnprintf(buf, len, "%s", self->entry->name);
281: if (data == NULL)
282: return (off);
1.3 nicm 283: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 284: if (off < len && data->src != NULL)
285: off += xsnprintf(buf + off, len - off, " -s %s", data->src);
286: if (off < len && data->dst != NULL)
287: off += xsnprintf(buf + off, len - off, " -t %s", data->dst);
288: if (off < len && data->arg != NULL)
289: off += cmd_prarg(buf + off, len - off, " ", data->arg);
290: return (off);
291: }
292:
293: void
294: cmd_buffer_init(struct cmd *self, unused int key)
295: {
296: struct cmd_buffer_data *data;
297:
298: self->data = data = xmalloc(sizeof *data);
1.3 nicm 299: data->chflags = 0;
1.1 nicm 300: data->target = NULL;
301: data->buffer = -1;
302: data->arg = NULL;
303: }
304:
305: int
306: cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
307: {
308: struct cmd_buffer_data *data;
1.3 nicm 309: const struct cmd_entry *entry = self->entry;
1.1 nicm 310: int opt, n;
311: const char *errstr;
312:
313: cmd_buffer_init(self, 0);
314: data = self->data;
315:
1.3 nicm 316: while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) {
317: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 318: continue;
319: switch (opt) {
320: case 'b':
321: if (data->buffer == -1) {
322: n = strtonum(optarg, 0, INT_MAX, &errstr);
323: if (errstr != NULL) {
324: xasprintf(cause, "buffer %s", errstr);
325: goto error;
326: }
327: data->buffer = n;
328: }
329: break;
330: case 't':
331: if (data->target == NULL)
332: data->target = xstrdup(optarg);
333: break;
334: default:
335: goto usage;
336: }
337: }
338: argc -= optind;
339: argv += optind;
340:
341: if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
342: goto usage;
343: return (0);
344:
345: usage:
346: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
347:
348: error:
349: self->entry->free(self);
350: return (-1);
351: }
352:
353: void
354: cmd_buffer_free(struct cmd *self)
355: {
356: struct cmd_buffer_data *data = self->data;
357:
358: if (data->target != NULL)
359: xfree(data->target);
360: if (data->arg != NULL)
361: xfree(data->arg);
362: xfree(data);
363: }
364:
365: size_t
366: cmd_buffer_print(struct cmd *self, char *buf, size_t len)
367: {
368: struct cmd_buffer_data *data = self->data;
369: size_t off = 0;
370:
371: off += xsnprintf(buf, len, "%s", self->entry->name);
372: if (data == NULL)
373: return (off);
1.3 nicm 374: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 375: if (off < len && data->buffer != -1)
376: off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
377: if (off < len && data->target != NULL)
378: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
379: if (off < len && data->arg != NULL)
380: off += cmd_prarg(buf + off, len - off, " ", data->arg);
381: return (off);
382: }
383:
384: void
385: cmd_option_init(struct cmd *self, unused int key)
386: {
387: struct cmd_option_data *data;
388:
389: self->data = data = xmalloc(sizeof *data);
1.3 nicm 390: data->chflags = 0;
1.1 nicm 391: data->target = NULL;
392: data->option = NULL;
393: data->value = NULL;
394: }
395:
396: int
397: cmd_option_parse(struct cmd *self, int argc, char **argv, char **cause)
398: {
399: struct cmd_option_data *data;
1.3 nicm 400: const struct cmd_entry *entry = self->entry;
1.1 nicm 401: int opt;
402:
403: /* Don't use the entry version since it may be dependent on key. */
404: cmd_option_init(self, 0);
405: data = self->data;
406:
1.3 nicm 407: while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
408: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 409: continue;
410: switch (opt) {
411: case 't':
412: if (data->target == NULL)
413: data->target = xstrdup(optarg);
414: break;
415: default:
416: goto usage;
417: }
418: }
419: argc -= optind;
420: argv += optind;
421:
422: if (argc == 2) {
423: data->option = xstrdup(argv[0]);
424: data->value = xstrdup(argv[1]);
425: } else if (argc == 1)
426: data->option = xstrdup(argv[0]);
427: else
428: goto usage;
429: return (0);
430:
431: usage:
432: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
433:
434: self->entry->free(self);
435: return (-1);
436: }
437:
438: void
439: cmd_option_free(struct cmd *self)
440: {
441: struct cmd_option_data *data = self->data;
442:
443: if (data->target != NULL)
444: xfree(data->target);
445: if (data->option != NULL)
446: xfree(data->option);
447: if (data->value != NULL)
448: xfree(data->value);
449: xfree(data);
450: }
451:
452: size_t
453: cmd_option_print(struct cmd *self, char *buf, size_t len)
454: {
455: struct cmd_option_data *data = self->data;
456: size_t off = 0;
457:
458: off += xsnprintf(buf, len, "%s", self->entry->name);
459: if (data == NULL)
460: return (off);
1.3 nicm 461: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 462: if (off < len && data->target != NULL)
463: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
464: if (off < len && data->option != NULL)
465: off += xsnprintf(buf + off, len - off, " %s", data->option);
466: if (off < len && data->value != NULL)
467: off += xsnprintf(buf + off, len - off, " %s", data->value);
468: return (off);
469: }
470:
471: void
472: cmd_pane_init(struct cmd *self, unused int key)
473: {
474: struct cmd_pane_data *data;
475:
476: self->data = data = xmalloc(sizeof *data);
1.3 nicm 477: data->chflags = 0;
1.1 nicm 478: data->target = NULL;
479: data->arg = NULL;
480: data->pane = -1;
481: }
482:
483: int
484: cmd_pane_parse(struct cmd *self, int argc, char **argv, char **cause)
485: {
486: struct cmd_pane_data *data;
1.3 nicm 487: const struct cmd_entry *entry = self->entry;
1.1 nicm 488: int opt, n;
489: const char *errstr;
490:
491: /* Don't use the entry version since it may be dependent on key. */
492: cmd_pane_init(self, 0);
493: data = self->data;
494:
1.3 nicm 495: while ((opt = cmd_getopt(argc, argv, "p:t:", entry->chflags)) != -1) {
496: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 497: continue;
498: switch (opt) {
499: case 'p':
500: if (data->pane == -1) {
501: n = strtonum(optarg, 0, INT_MAX, &errstr);
502: if (errstr != NULL) {
503: xasprintf(cause, "pane %s", errstr);
504: goto error;
505: }
506: data->pane = n;
507: }
508: break;
509: case 't':
510: if (data->target == NULL)
511: data->target = xstrdup(optarg);
512: break;
513: default:
514: goto usage;
515: }
516: }
517: argc -= optind;
518: argv += optind;
519:
520: if (cmd_fill_argument(self->entry->flags, &data->arg, argc, argv) != 0)
521: goto usage;
522: return (0);
523:
524: usage:
525: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
526:
527: error:
528: self->entry->free(self);
529: return (-1);
530: }
531:
532: void
533: cmd_pane_free(struct cmd *self)
534: {
535: struct cmd_pane_data *data = self->data;
536:
537: if (data->target != NULL)
538: xfree(data->target);
539: if (data->arg != NULL)
540: xfree(data->arg);
541: xfree(data);
542: }
543:
544: size_t
545: cmd_pane_print(struct cmd *self, char *buf, size_t len)
546: {
547: struct cmd_pane_data *data = self->data;
548: size_t off = 0;
549:
550: off += xsnprintf(buf, len, "%s", self->entry->name);
551: if (data == NULL)
552: return (off);
1.3 nicm 553: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 554: if (off < len && data->target != NULL)
555: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
556: if (off < len && data->arg != NULL)
557: off += cmd_prarg(buf + off, len - off, " ", data->arg);
558: return (off);
559: }