Annotation of src/usr.bin/tmux/cmd-generic.c, Revision 1.12
1.12 ! nicm 1: /* $OpenBSD: cmd-generic.c,v 1.11 2009/12/03 22:50:10 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.9 nicm 88: /* Print the flags present 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);
1.11 nicm 144: }
1.6 nicm 145:
1.1 nicm 146: if (argc != 0)
147: return (-1);
148: return (0);
149: }
150:
1.10 nicm 151: /* ARGSUSED */
1.1 nicm 152: void
153: cmd_target_init(struct cmd *self, unused int key)
154: {
155: struct cmd_target_data *data;
156:
157: self->data = data = xmalloc(sizeof *data);
1.3 nicm 158: data->chflags = 0;
1.1 nicm 159: data->target = NULL;
160: data->arg = NULL;
1.7 nicm 161: data->arg2 = NULL;
1.1 nicm 162: }
163:
164: int
165: cmd_target_parse(struct cmd *self, int argc, char **argv, char **cause)
166: {
167: struct cmd_target_data *data;
1.3 nicm 168: const struct cmd_entry *entry = self->entry;
1.1 nicm 169: int opt;
170:
171: /* Don't use the entry version since it may be dependent on key. */
172: cmd_target_init(self, 0);
173: data = self->data;
174:
1.3 nicm 175: while ((opt = cmd_getopt(argc, argv, "t:", entry->chflags)) != -1) {
1.8 nicm 176: if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 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;
185: }
186: }
187: argc -= optind;
188: argv += optind;
189:
1.6 nicm 190: if (cmd_fill_argument(
191: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 192: goto usage;
193: return (0);
194:
195: usage:
196: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
197:
198: self->entry->free(self);
199: return (-1);
200: }
201:
202: void
203: cmd_target_free(struct cmd *self)
204: {
205: struct cmd_target_data *data = self->data;
206:
207: if (data->target != NULL)
208: xfree(data->target);
209: if (data->arg != NULL)
210: xfree(data->arg);
1.7 nicm 211: if (data->arg2 != NULL)
212: xfree(data->arg2);
1.1 nicm 213: xfree(data);
214: }
215:
216: size_t
217: cmd_target_print(struct cmd *self, char *buf, size_t len)
218: {
219: struct cmd_target_data *data = self->data;
220: size_t off = 0;
221:
222: off += xsnprintf(buf, len, "%s", self->entry->name);
223: if (data == NULL)
224: return (off);
1.3 nicm 225: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 226: if (off < len && data->target != NULL)
227: off += cmd_prarg(buf + off, len - off, " -t ", data->target);
1.11 nicm 228: if (off < len && data->arg != NULL)
1.1 nicm 229: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.11 nicm 230: if (off < len && data->arg2 != NULL)
1.6 nicm 231: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 232: return (off);
233: }
234:
1.10 nicm 235: /* ARGSUSED */
1.1 nicm 236: void
237: cmd_srcdst_init(struct cmd *self, unused int key)
238: {
239: struct cmd_srcdst_data *data;
240:
241: self->data = data = xmalloc(sizeof *data);
1.3 nicm 242: data->chflags = 0;
1.1 nicm 243: data->src = NULL;
244: data->dst = NULL;
245: data->arg = NULL;
1.7 nicm 246: data->arg2 = NULL;
1.1 nicm 247: }
248:
249: int
250: cmd_srcdst_parse(struct cmd *self, int argc, char **argv, char **cause)
251: {
252: struct cmd_srcdst_data *data;
1.3 nicm 253: const struct cmd_entry *entry = self->entry;
1.1 nicm 254: int opt;
255:
256: cmd_srcdst_init(self, 0);
257: data = self->data;
258:
1.3 nicm 259: while ((opt = cmd_getopt(argc, argv, "s:t:", entry->chflags)) != -1) {
1.8 nicm 260: if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 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;
273: }
274: }
275: argc -= optind;
276: argv += optind;
277:
1.6 nicm 278: if (cmd_fill_argument(
279: self->entry->flags, &data->arg, &data->arg2, argc, argv) != 0)
1.1 nicm 280: goto usage;
281: return (0);
282:
283: usage:
284: xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
285:
286: self->entry->free(self);
287: return (-1);
288: }
289:
290: void
291: cmd_srcdst_free(struct cmd *self)
292: {
293: struct cmd_srcdst_data *data = self->data;
294:
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);
1.7 nicm 301: if (data->arg2 != NULL)
302: xfree(data->arg2);
1.1 nicm 303: xfree(data);
304: }
305:
306: size_t
307: cmd_srcdst_print(struct cmd *self, char *buf, size_t len)
308: {
309: struct cmd_srcdst_data *data = self->data;
310: size_t off = 0;
311:
312: off += xsnprintf(buf, len, "%s", self->entry->name);
313: if (data == NULL)
314: return (off);
1.3 nicm 315: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 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);
1.11 nicm 320: if (off < len && data->arg != NULL)
1.1 nicm 321: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.11 nicm 322: if (off < len && data->arg2 != NULL)
1.6 nicm 323: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 324: return (off);
325: }
326:
1.10 nicm 327: /* ARGSUSED */
1.1 nicm 328: void
329: cmd_buffer_init(struct cmd *self, unused int key)
330: {
331: struct cmd_buffer_data *data;
332:
333: self->data = data = xmalloc(sizeof *data);
1.3 nicm 334: data->chflags = 0;
1.1 nicm 335: data->buffer = -1;
336: data->arg = NULL;
1.7 nicm 337: data->arg2 = NULL;
1.1 nicm 338: }
339:
340: int
341: cmd_buffer_parse(struct cmd *self, int argc, char **argv, char **cause)
342: {
343: struct cmd_buffer_data *data;
1.3 nicm 344: const struct cmd_entry *entry = self->entry;
1.1 nicm 345: int opt, n;
346: const char *errstr;
347:
348: cmd_buffer_init(self, 0);
349: data = self->data;
350:
1.12 ! nicm 351: while ((opt = cmd_getopt(argc, argv, "b:", entry->chflags)) != -1) {
1.8 nicm 352: if (cmd_parse_flags(opt, entry->chflags, &data->chflags) == 0)
1.1 nicm 353: continue;
354: switch (opt) {
355: case 'b':
356: if (data->buffer == -1) {
357: n = strtonum(optarg, 0, INT_MAX, &errstr);
358: if (errstr != NULL) {
359: xasprintf(cause, "buffer %s", errstr);
360: goto error;
361: }
362: data->buffer = n;
363: }
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->arg != NULL)
391: xfree(data->arg);
1.7 nicm 392: if (data->arg2 != NULL)
393: xfree(data->arg2);
1.1 nicm 394: xfree(data);
395: }
396:
397: size_t
398: cmd_buffer_print(struct cmd *self, char *buf, size_t len)
399: {
400: struct cmd_buffer_data *data = self->data;
401: size_t off = 0;
402:
403: off += xsnprintf(buf, len, "%s", self->entry->name);
404: if (data == NULL)
405: return (off);
1.3 nicm 406: off += cmd_print_flags(buf, len, off, data->chflags);
1.1 nicm 407: if (off < len && data->buffer != -1)
408: off += xsnprintf(buf + off, len - off, " -b %d", data->buffer);
1.11 nicm 409: if (off < len && data->arg != NULL)
1.1 nicm 410: off += cmd_prarg(buf + off, len - off, " ", data->arg);
1.11 nicm 411: if (off < len && data->arg2 != NULL)
1.6 nicm 412: off += cmd_prarg(buf + off, len - off, " ", data->arg2);
1.1 nicm 413: return (off);
414: }