Annotation of src/usr.bin/tmux/cmd-generic.c, Revision 1.7
1.7 ! nicm 1: /* $OpenBSD: cmd-generic.c,v 1.6 2009/08/11 12:53:37 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.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.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
1.6 nicm 107: cmd_fill_argument(int flags, char **arg, char **arg2, int argc, char **argv)
1.1 nicm 108: {
109: *arg = NULL;
1.6 nicm 110: *arg2 = NULL;
1.1 nicm 111:
112: if (flags & CMD_ARG1) {
113: if (argc != 1)
114: return (-1);
115: *arg = xstrdup(argv[0]);
116: return (0);
117: }
118:
119: if (flags & CMD_ARG01) {
120: if (argc != 0 && argc != 1)
121: return (-1);
122: if (argc == 1)
123: *arg = xstrdup(argv[0]);
124: return (0);
125: }
126:
1.6 nicm 127: if (flags & CMD_ARG2) {
128: if (argc != 2)
129: return (-1);
130: *arg = xstrdup(argv[0]);
131: *arg2 = xstrdup(argv[1]);
132: return (0);
133: }
134:
135: if (flags & CMD_ARG12) {
136: if (argc != 1 && argc != 2)
137: return (-1);
138: *arg = xstrdup(argv[0]);
139: if (argc == 2)
140: *arg2 = xstrdup(argv[1]);
141: return (0);
142: }
143:
1.1 nicm 144: if (argc != 0)
145: return (-1);
146: return (0);
147: }
148:
149: void
150: cmd_target_init(struct cmd *self, unused int key)
151: {
152: struct cmd_target_data *data;
153:
154: self->data = data = xmalloc(sizeof *data);
1.3 nicm 155: data->chflags = 0;
1.1 nicm 156: data->target = NULL;
157: data->arg = NULL;
1.7 ! nicm 158: data->arg2 = NULL;
1.1 nicm 159: }
160:
161: int
162: cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
163: {
164: struct cmd_target_data *data;
1.3 nicm 165: const struct cmd_entry *entry = self->entry;
1.1 nicm 166: int opt;
167:
168: /* Don't use the entry version since it may be dependent on key. */
169: cmd_target_init(self, 0);
170: data = self->data;
171:
1.3 nicm 172: while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
173: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 174: continue;
175: switch (opt) {
176: case 't':
177: if (data->target == NULL)
178: data->target = xstrdup(optarg);
179: break;
180: default:
181: goto usage;
182: }
183: }
184: argc -= optind;
185: argv += optind;
186:
1.6 nicm 187: if (cmd_fill_argument(
188: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 189: goto usage;
190: return (0);
191:
192: usage:
193: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
194:
195: self->entry->free(self);
196: return (-1);
197: }
198:
199: void
200: cmd_target_free(struct cmd *self)
201: {
202: struct cmd_target_data *data = self->data;
203:
204: if (data->target != NULL)
205: xfree(data->target);
206: if (data->arg != NULL)
207: xfree(data->arg);
1.7 ! nicm 208: if (data->arg2 != NULL)
! 209: xfree(data->arg2);
1.1 nicm 210: xfree(data);
211: }
212:
213: size_t
214: cmd_target_print(struct cmd *self, char *buf, size_t len)
215: {
216: struct cmd_target_data *data = self->data;
217: size_t off = 0;
218:
219: off += xsnprintf(buf, len, "%s", self->entry->name);
220: if (data == NULL)
221: return (off);
1.3 nicm 222: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 223: if (off < len && data->target != NULL)
224: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
225: if (off < len && data->arg != NULL)
226: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.6 nicm 227: if (off < len && data->arg2 != NULL)
228: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 229: return (off);
230: }
231:
232: void
233: cmd_srcdst_init(struct cmd *self, unused int key)
234: {
235: struct cmd_srcdst_data *data;
236:
237: self->data = data = xmalloc(sizeof *data);
1.3 nicm 238: data->chflags = 0;
1.1 nicm 239: data->src = NULL;
240: data->dst = NULL;
241: data->arg = NULL;
1.7 ! nicm 242: data->arg2 = NULL;
1.1 nicm 243: }
244:
245: int
246: cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
247: {
248: struct cmd_srcdst_data *data;
1.3 nicm 249: const struct cmd_entry *entry = self->entry;
1.1 nicm 250: int opt;
251:
252: cmd_srcdst_init(self, 0);
253: data = self->data;
254:
1.3 nicm 255: while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) {
256: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 257: continue;
258: switch (opt) {
259: case 's':
260: if (data->src == NULL)
261: data->src = xstrdup(optarg);
262: break;
263: case 't':
264: if (data->dst == NULL)
265: data->dst = xstrdup(optarg);
266: break;
267: default:
268: goto usage;
269: }
270: }
271: argc -= optind;
272: argv += optind;
273:
1.6 nicm 274: if (cmd_fill_argument(
275: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 276: goto usage;
277: return (0);
278:
279: usage:
280: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
281:
282: self->entry->free(self);
283: return (-1);
284: }
285:
286: void
287: cmd_srcdst_free(struct cmd *self)
288: {
289: struct cmd_srcdst_data *data = self->data;
290:
291: if (data->src != NULL)
292: xfree(data->src);
293: if (data->dst != NULL)
294: xfree(data->dst);
295: if (data->arg != NULL)
296: xfree(data->arg);
1.7 ! nicm 297: if (data->arg2 != NULL)
! 298: xfree(data->arg2);
1.1 nicm 299: xfree(data);
300: }
301:
302: size_t
303: cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
304: {
305: struct cmd_srcdst_data *data = self->data;
306: size_t off = 0;
307:
308: off += xsnprintf(buf, len, "%s", self->entry->name);
309: if (data == NULL)
310: return (off);
1.3 nicm 311: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 312: if (off < len && data->src != NULL)
313: off += xsnprintf(buf + off, len - off, " -s %s", data->src);
314: if (off < len && data->dst != NULL)
315: off += xsnprintf(buf + off, len - off, " -t %s", data->dst);
316: if (off < len && data->arg != NULL)
317: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.6 nicm 318: if (off < len && data->arg2 != NULL)
319: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 320: return (off);
321: }
322:
323: void
324: cmd_buffer_init(struct cmd *self, unused int key)
325: {
326: struct cmd_buffer_data *data;
327:
328: self->data = data = xmalloc(sizeof *data);
1.3 nicm 329: data->chflags = 0;
1.1 nicm 330: data->target = NULL;
331: data->buffer = -1;
332: data->arg = NULL;
1.7 ! nicm 333: data->arg2 = NULL;
1.1 nicm 334: }
335:
336: int
337: cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
338: {
339: struct cmd_buffer_data *data;
1.3 nicm 340: const struct cmd_entry *entry = self->entry;
1.1 nicm 341: int opt, n;
342: const char *errstr;
343:
344: cmd_buffer_init(self, 0);
345: data = self->data;
346:
1.3 nicm 347: while ((opt = cmd_getopt(argc, argv, "b:t:", entry->chflags)) != -1) {
348: if (cmd_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 349: continue;
350: switch (opt) {
351: case 'b':
352: if (data->buffer == -1) {
353: n = strtonum(optarg, 0, INT_MAX, &errstr);
354: if (errstr != NULL) {
355: xasprintf(cause, "buffer %s", errstr);
356: goto error;
357: }
358: data->buffer = n;
359: }
360: break;
361: case 't':
362: if (data->target == NULL)
363: data->target = xstrdup(optarg);
364: break;
365: default:
366: goto usage;
367: }
368: }
369: argc -= optind;
370: argv += optind;
371:
1.6 nicm 372: if (cmd_fill_argument(
373: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 374: goto usage;
375: return (0);
376:
377: usage:
378: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
379:
380: error:
381: self->entry->free(self);
382: return (-1);
383: }
384:
385: void
386: cmd_buffer_free(struct cmd *self)
387: {
388: struct cmd_buffer_data *data = self->data;
389:
390: if (data->target != NULL)
391: xfree(data->target);
392: if (data->arg != NULL)
393: xfree(data->arg);
1.7 ! nicm 394: if (data->arg2 != NULL)
! 395: xfree(data->arg2);
1.1 nicm 396: xfree(data);
397: }
398:
399: size_t
400: cmd_buffer_print(struct cmd *self, char *buf, size_t len)
401: {
402: struct cmd_buffer_data *data = self->data;
403: size_t off = 0;
404:
405: off += xsnprintf(buf, len, "%s", self->entry->name);
406: if (data == NULL)
407: return (off);
1.3 nicm 408: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 409: if (off < len && data->buffer != -1)
410: off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
411: if (off < len && data->target != NULL)
412: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
413: if (off < len && data->arg != NULL)
414: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.6 nicm 415: if (off < len && data->arg2 != NULL)
416: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 417: return (off);
418: }