Annotation of src/usr.bin/tmux/arguments.c, Revision 1.52
1.52 ! nicm 1: /* $OpenBSD: arguments.c,v 1.51 2021/09/09 21:55:03 nicm Exp $ */
1.1 nicm 2:
3: /*
1.13 nicm 4: * Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
1.1 nicm 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:
1.42 nicm 21: #include <ctype.h>
1.1 nicm 22: #include <stdlib.h>
23: #include <string.h>
1.16 nicm 24: #include <vis.h>
1.1 nicm 25:
26: #include "tmux.h"
27:
1.5 nicm 28: /*
29: * Manipulate command arguments.
30: */
1.11 nicm 31:
1.45 nicm 32: /* List of argument values. */
1.21 nicm 33: TAILQ_HEAD(args_values, args_value);
34:
1.45 nicm 35: /* Single arguments flag. */
1.11 nicm 36: struct args_entry {
37: u_char flag;
1.21 nicm 38: struct args_values values;
1.27 nicm 39: u_int count;
1.11 nicm 40: RB_ENTRY(args_entry) entry;
41: };
1.5 nicm 42:
1.45 nicm 43: /* Parsed argument flags and values. */
1.38 nicm 44: struct args {
1.44 nicm 45: struct args_tree tree;
1.43 nicm 46: u_int count;
47: struct args_value *values;
1.38 nicm 48: };
49:
1.45 nicm 50: /* Prepared command state. */
51: struct args_command_state {
52: struct cmd_list *cmdlist;
53: char *cmd;
54: struct cmd_parse_input pi;
55: };
56:
1.14 nicm 57: static struct args_entry *args_find(struct args *, u_char);
1.5 nicm 58:
1.14 nicm 59: static int args_cmp(struct args_entry *, struct args_entry *);
60: RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
1.5 nicm 61:
62: /* Arguments tree comparison function. */
1.14 nicm 63: static int
1.5 nicm 64: args_cmp(struct args_entry *a1, struct args_entry *a2)
65: {
66: return (a1->flag - a2->flag);
67: }
68:
69: /* Find a flag in the arguments tree. */
1.14 nicm 70: static struct args_entry *
1.32 nicm 71: args_find(struct args *args, u_char flag)
1.5 nicm 72: {
73: struct args_entry entry;
74:
1.32 nicm 75: entry.flag = flag;
1.5 nicm 76: return (RB_FIND(args_tree, &args->tree, &entry));
77: }
78:
1.43 nicm 79: /* Copy value. */
80: static void
81: args_copy_value(struct args_value *to, struct args_value *from)
82: {
83: to->type = from->type;
84: switch (from->type) {
85: case ARGS_NONE:
86: break;
87: case ARGS_COMMANDS:
88: to->cmdlist = from->cmdlist;
89: to->cmdlist->references++;
90: break;
91: case ARGS_STRING:
92: to->string = xstrdup(from->string);
93: break;
94: }
95: }
96:
1.42 nicm 97: /* Get value as string. */
1.43 nicm 98: static const char *
1.42 nicm 99: args_value_as_string(struct args_value *value)
100: {
101: switch (value->type) {
102: case ARGS_NONE:
1.43 nicm 103: return ("");
1.42 nicm 104: case ARGS_COMMANDS:
1.43 nicm 105: if (value->cached == NULL)
106: value->cached = cmd_list_print(value->cmdlist, 0);
107: return (value->cached);
1.42 nicm 108: case ARGS_STRING:
1.43 nicm 109: return (value->string);
1.42 nicm 110: }
1.52 ! nicm 111: fatalx("unexpected argument type");
1.42 nicm 112: }
113:
1.36 nicm 114: /* Create an empty arguments set. */
115: struct args *
116: args_create(void)
117: {
118: struct args *args;
119:
120: args = xcalloc(1, sizeof *args);
121: RB_INIT(&args->tree);
122: return (args);
123: }
124:
1.42 nicm 125: /* Parse arguments into a new argument set. */
1.1 nicm 126: struct args *
1.42 nicm 127: args_parse(const struct args_parse *parse, struct args_value *values,
1.47 nicm 128: u_int count, char **cause)
1.1 nicm 129: {
1.42 nicm 130: struct args *args;
1.46 nicm 131: u_int i;
1.47 nicm 132: enum args_parse_type type;
1.43 nicm 133: struct args_value *value, *new;
1.42 nicm 134: u_char flag, argument;
1.43 nicm 135: const char *found, *string, *s;
1.1 nicm 136:
1.42 nicm 137: if (count == 0)
138: return (args_create());
1.1 nicm 139:
1.36 nicm 140: args = args_create();
1.42 nicm 141: for (i = 1; i < count; /* nothing */) {
142: value = &values[i];
143: if (value->type != ARGS_STRING)
144: break;
145:
146: string = value->string;
147: if (*string++ != '-' || *string == '\0')
148: break;
149: i++;
150: if (string[0] == '-' && string[1] == '\0')
151: break;
152:
153: for (;;) {
154: flag = *string++;
155: if (flag == '\0')
156: break;
1.51 nicm 157: if (flag == '?') {
158: args_free(args);
159: return (NULL);
160: }
1.42 nicm 161: if (!isalnum(flag)) {
1.47 nicm 162: xasprintf(cause, "invalid flag -%c", flag);
1.42 nicm 163: args_free(args);
164: return (NULL);
165: }
166: found = strchr(parse->template, flag);
167: if (found == NULL) {
1.47 nicm 168: xasprintf(cause, "unknown flag -%c", flag);
1.42 nicm 169: args_free(args);
170: return (NULL);
171: }
172: argument = *++found;
173: if (argument != ':') {
1.48 nicm 174: log_debug("%s: -%c", __func__, flag);
1.42 nicm 175: args_set(args, flag, NULL);
176: continue;
177: }
1.47 nicm 178: new = xcalloc(1, sizeof *new);
1.43 nicm 179: if (*string != '\0') {
180: new->type = ARGS_STRING;
181: new->string = xstrdup(string);
182: } else {
1.42 nicm 183: if (i == count) {
1.47 nicm 184: xasprintf(cause,
185: "-%c expects an argument",
186: flag);
187: args_free(args);
188: return (NULL);
189: }
190: if (values[i].type != ARGS_STRING) {
191: xasprintf(cause,
192: "-%c argument must be a string",
193: flag);
1.42 nicm 194: args_free(args);
195: return (NULL);
196: }
1.43 nicm 197: args_copy_value(new, &values[i++]);
1.42 nicm 198: }
1.43 nicm 199: s = args_value_as_string(new);
1.48 nicm 200: log_debug("%s: -%c = %s", __func__, flag, s);
1.43 nicm 201: args_set(args, flag, new);
1.42 nicm 202: break;
203: }
204: }
205: log_debug("%s: flags end at %u of %u", __func__, i, count);
206: if (i != count) {
207: for (/* nothing */; i < count; i++) {
208: value = &values[i];
209:
210: s = args_value_as_string(value);
1.48 nicm 211: log_debug("%s: %u = %s (type %d)", __func__, i, s,
212: value->type);
1.43 nicm 213:
1.47 nicm 214: if (parse->cb != NULL) {
215: type = parse->cb(args, args->count, cause);
216: if (type == ARGS_PARSE_INVALID) {
217: args_free(args);
218: return (NULL);
219: }
220: } else
221: type = ARGS_PARSE_STRING;
222:
1.43 nicm 223: args->values = xrecallocarray(args->values,
224: args->count, args->count + 1, sizeof *args->values);
1.47 nicm 225: new = &args->values[args->count++];
226:
227: switch (type) {
228: case ARGS_PARSE_INVALID:
229: fatalx("unexpected argument type");
230: case ARGS_PARSE_STRING:
231: if (value->type != ARGS_STRING) {
232: xasprintf(cause,
233: "argument %u must be \"string\"",
234: args->count);
235: args_free(args);
236: return (NULL);
237: }
238: args_copy_value(new, value);
239: break;
240: case ARGS_PARSE_COMMANDS_OR_STRING:
241: args_copy_value(new, value);
242: break;
243: case ARGS_PARSE_COMMANDS:
244: if (value->type != ARGS_COMMANDS) {
245: xasprintf(cause,
246: "argument %u must be { commands }",
247: args->count);
248: args_free(args);
249: return (NULL);
250: }
251: args_copy_value(new, value);
252: break;
253: }
1.1 nicm 254: }
255: }
256:
1.47 nicm 257: if (parse->lower != -1 && args->count < (u_int)parse->lower) {
258: xasprintf(cause,
259: "too few arguments (need at least %u)",
260: parse->lower);
261: args_free(args);
262: return (NULL);
263: }
264: if (parse->upper != -1 && args->count > (u_int)parse->upper) {
265: xasprintf(cause,
266: "too many arguments (need at most %u)",
267: parse->upper);
1.38 nicm 268: args_free(args);
269: return (NULL);
270: }
1.1 nicm 271: return (args);
1.42 nicm 272: }
273:
1.48 nicm 274: /* Copy and expand a value. */
275: static void
276: args_copy_copy_value(struct args_value *to, struct args_value *from, int argc,
277: char **argv)
278: {
279: char *s, *expanded;
280: int i;
281:
282: to->type = from->type;
283: switch (from->type) {
284: case ARGS_NONE:
285: break;
286: case ARGS_STRING:
287: expanded = xstrdup(from->string);
288: for (i = 0; i < argc; i++) {
289: s = cmd_template_replace(expanded, argv[i], i + 1);
290: free(expanded);
291: expanded = s;
292: }
293: to->string = expanded;
294: break;
295: case ARGS_COMMANDS:
296: to->cmdlist = cmd_list_copy(from->cmdlist, argc, argv);
297: break;
298: }
299: }
300:
301: /* Copy an arguments set. */
302: struct args *
303: args_copy(struct args *args, int argc, char **argv)
304: {
305: struct args *new_args;
306: struct args_entry *entry;
307: struct args_value *value, *new_value;
308: u_int i;
309:
1.49 nicm 310: cmd_log_argv(argc, argv, "%s", __func__);
311:
1.48 nicm 312: new_args = args_create();
313: RB_FOREACH(entry, args_tree, &args->tree) {
1.49 nicm 314: if (TAILQ_EMPTY(&entry->values)) {
315: for (i = 0; i < entry->count; i++)
316: args_set(new_args, entry->flag, NULL);
1.48 nicm 317: continue;
318: }
319: TAILQ_FOREACH(value, &entry->values, entry) {
320: new_value = xcalloc(1, sizeof *new_value);
321: args_copy_copy_value(new_value, value, argc, argv);
322: args_set(new_args, entry->flag, new_value);
323: }
324: }
1.49 nicm 325: if (args->count == 0)
326: return (new_args);
1.48 nicm 327: new_args->count = args->count;
328: new_args->values = xcalloc(args->count, sizeof *new_args->values);
329: for (i = 0; i < args->count; i++) {
330: new_value = &new_args->values[i];
331: args_copy_copy_value(new_value, &args->values[i], argc, argv);
332: }
333: return (new_args);
334: }
335:
1.42 nicm 336: /* Free a value. */
337: void
338: args_free_value(struct args_value *value)
339: {
340: switch (value->type) {
341: case ARGS_NONE:
342: break;
343: case ARGS_STRING:
344: free(value->string);
345: break;
346: case ARGS_COMMANDS:
347: cmd_list_free(value->cmdlist);
348: break;
349: }
1.43 nicm 350: free(value->cached);
1.1 nicm 351: }
352:
1.48 nicm 353: /* Free values. */
354: void
355: args_free_values(struct args_value *values, u_int count)
356: {
357: u_int i;
358:
359: for (i = 0; i < count; i++)
360: args_free_value(&values[i]);
361: }
362:
1.1 nicm 363: /* Free an arguments set. */
364: void
365: args_free(struct args *args)
366: {
1.5 nicm 367: struct args_entry *entry;
368: struct args_entry *entry1;
1.21 nicm 369: struct args_value *value;
370: struct args_value *value1;
1.1 nicm 371:
1.48 nicm 372: args_free_values(args->values, args->count);
1.43 nicm 373: free(args->values);
1.1 nicm 374:
1.5 nicm 375: RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
376: RB_REMOVE(args_tree, &args->tree, entry);
1.21 nicm 377: TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
378: TAILQ_REMOVE(&entry->values, value, entry);
1.44 nicm 379: args_free_value(value);
1.21 nicm 380: free(value);
381: }
1.5 nicm 382: free(entry);
383: }
1.1 nicm 384:
1.4 nicm 385: free(args);
1.1 nicm 386: }
387:
1.38 nicm 388: /* Convert arguments to vector. */
389: void
1.48 nicm 390: args_to_vector(struct args *args, int *argc, char ***argv)
1.38 nicm 391: {
1.47 nicm 392: char *s;
393: u_int i;
1.43 nicm 394:
395: *argc = 0;
396: *argv = NULL;
397:
398: for (i = 0; i < args->count; i++) {
1.47 nicm 399: switch (args->values[i].type) {
400: case ARGS_NONE:
401: break;
402: case ARGS_STRING:
403: cmd_append_argv(argc, argv, args->values[i].string);
404: break;
405: case ARGS_COMMANDS:
406: s = cmd_list_print(args->values[i].cmdlist, 0);
407: cmd_append_argv(argc, argv, s);
408: free(s);
409: break;
410: }
1.43 nicm 411: }
1.38 nicm 412: }
413:
1.48 nicm 414: /* Convert arguments from vector. */
415: struct args_value *
416: args_from_vector(int argc, char **argv)
417: {
418: struct args_value *values;
419: int i;
420:
421: values = xcalloc(argc, sizeof *values);
422: for (i = 0; i < argc; i++) {
423: values[i].type = ARGS_STRING;
424: values[i].string = xstrdup(argv[i]);
425: }
426: return (values);
427: }
428:
1.12 nicm 429: /* Add to string. */
430: static void printflike(3, 4)
431: args_print_add(char **buf, size_t *len, const char *fmt, ...)
432: {
1.39 nicm 433: va_list ap;
1.12 nicm 434: char *s;
435: size_t slen;
436:
437: va_start(ap, fmt);
438: slen = xvasprintf(&s, fmt, ap);
439: va_end(ap);
440:
441: *len += slen;
442: *buf = xrealloc(*buf, *len);
443:
444: strlcat(*buf, s, *len);
445: free(s);
446: }
447:
1.43 nicm 448: /* Add value to string. */
1.21 nicm 449: static void
1.43 nicm 450: args_print_add_value(char **buf, size_t *len, struct args_value *value)
1.21 nicm 451: {
1.43 nicm 452: char *expanded = NULL;
1.21 nicm 453:
454: if (**buf != '\0')
455: args_print_add(buf, len, " ");
456:
1.43 nicm 457: switch (value->type) {
458: case ARGS_NONE:
459: break;
460: case ARGS_COMMANDS:
461: expanded = cmd_list_print(value->cmdlist, 0);
462: args_print_add(buf, len, "{ %s }", expanded);
463: break;
464: case ARGS_STRING:
465: expanded = args_escape(value->string);
466: args_print_add(buf, len, "%s", expanded);
467: break;
468: }
469: free(expanded);
1.21 nicm 470: }
471:
1.1 nicm 472: /* Print a set of arguments. */
1.12 nicm 473: char *
474: args_print(struct args *args)
1.1 nicm 475: {
1.39 nicm 476: size_t len;
1.21 nicm 477: char *buf;
1.43 nicm 478: u_int i, j;
1.5 nicm 479: struct args_entry *entry;
1.21 nicm 480: struct args_value *value;
1.1 nicm 481:
1.12 nicm 482: len = 1;
483: buf = xcalloc(1, len);
1.1 nicm 484:
485: /* Process the flags first. */
1.5 nicm 486: RB_FOREACH(entry, args_tree, &args->tree) {
1.21 nicm 487: if (!TAILQ_EMPTY(&entry->values))
1.1 nicm 488: continue;
489:
1.12 nicm 490: if (*buf == '\0')
491: args_print_add(&buf, &len, "-");
1.27 nicm 492: for (j = 0; j < entry->count; j++)
493: args_print_add(&buf, &len, "%c", entry->flag);
1.1 nicm 494: }
495:
496: /* Then the flags with arguments. */
1.5 nicm 497: RB_FOREACH(entry, args_tree, &args->tree) {
1.38 nicm 498: TAILQ_FOREACH(value, &entry->values, entry) {
499: if (*buf != '\0')
500: args_print_add(&buf, &len, " -%c", entry->flag);
501: else
502: args_print_add(&buf, &len, "-%c", entry->flag);
1.43 nicm 503: args_print_add_value(&buf, &len, value);
1.38 nicm 504: }
1.1 nicm 505: }
506:
507: /* And finally the argument vector. */
1.43 nicm 508: for (i = 0; i < args->count; i++)
509: args_print_add_value(&buf, &len, &args->values[i]);
1.1 nicm 510:
1.12 nicm 511: return (buf);
1.22 nicm 512: }
513:
514: /* Escape an argument. */
515: char *
516: args_escape(const char *s)
517: {
1.48 nicm 518: static const char dquoted[] = " #';${}%";
1.35 nicm 519: static const char squoted[] = " \"";
1.22 nicm 520: char *escaped, *result;
1.35 nicm 521: int flags, quotes = 0;
1.22 nicm 522:
1.30 nicm 523: if (*s == '\0') {
524: xasprintf(&result, "''");
525: return (result);
526: }
1.35 nicm 527: if (s[strcspn(s, dquoted)] != '\0')
528: quotes = '"';
529: else if (s[strcspn(s, squoted)] != '\0')
530: quotes = '\'';
531:
1.26 nicm 532: if (s[0] != ' ' &&
1.35 nicm 533: s[1] == '\0' &&
534: (quotes != 0 || s[0] == '~')) {
1.22 nicm 535: xasprintf(&escaped, "\\%c", s[0]);
1.34 nicm 536: return (escaped);
537: }
538:
1.25 nicm 539: flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
1.35 nicm 540: if (quotes == '"')
1.22 nicm 541: flags |= VIS_DQ;
542: utf8_stravis(&escaped, s, flags);
543:
1.35 nicm 544: if (quotes == '\'')
545: xasprintf(&result, "'%s'", escaped);
546: else if (quotes == '"') {
1.22 nicm 547: if (*escaped == '~')
548: xasprintf(&result, "\"\\%s\"", escaped);
549: else
550: xasprintf(&result, "\"%s\"", escaped);
551: } else {
552: if (*escaped == '~')
553: xasprintf(&result, "\\%s", escaped);
554: else
555: result = xstrdup(escaped);
556: }
557: free(escaped);
558: return (result);
1.1 nicm 559: }
560:
561: /* Return if an argument is present. */
562: int
1.32 nicm 563: args_has(struct args *args, u_char flag)
1.1 nicm 564: {
1.27 nicm 565: struct args_entry *entry;
566:
1.32 nicm 567: entry = args_find(args, flag);
1.27 nicm 568: if (entry == NULL)
569: return (0);
570: return (entry->count);
1.1 nicm 571: }
572:
1.5 nicm 573: /* Set argument value in the arguments tree. */
1.19 nicm 574: void
1.43 nicm 575: args_set(struct args *args, u_char flag, struct args_value *value)
1.1 nicm 576: {
1.5 nicm 577: struct args_entry *entry;
578:
1.32 nicm 579: entry = args_find(args, flag);
1.21 nicm 580: if (entry == NULL) {
1.7 nicm 581: entry = xcalloc(1, sizeof *entry);
1.32 nicm 582: entry->flag = flag;
1.27 nicm 583: entry->count = 1;
1.21 nicm 584: TAILQ_INIT(&entry->values);
1.7 nicm 585: RB_INSERT(args_tree, &args->tree, entry);
1.27 nicm 586: } else
587: entry->count++;
1.43 nicm 588: if (value != NULL && value->type != ARGS_NONE)
1.21 nicm 589: TAILQ_INSERT_TAIL(&entry->values, value, entry);
1.1 nicm 590: }
591:
592: /* Get argument value. Will be NULL if it isn't present. */
593: const char *
1.32 nicm 594: args_get(struct args *args, u_char flag)
1.1 nicm 595: {
1.5 nicm 596: struct args_entry *entry;
597:
1.32 nicm 598: if ((entry = args_find(args, flag)) == NULL)
599: return (NULL);
600: if (TAILQ_EMPTY(&entry->values))
1.5 nicm 601: return (NULL);
1.41 nicm 602: return (TAILQ_LAST(&entry->values, args_values)->string);
1.21 nicm 603: }
604:
1.32 nicm 605: /* Get first argument. */
606: u_char
607: args_first(struct args *args, struct args_entry **entry)
608: {
609: *entry = RB_MIN(args_tree, &args->tree);
610: if (*entry == NULL)
611: return (0);
612: return ((*entry)->flag);
613: }
614:
615: /* Get next argument. */
616: u_char
617: args_next(struct args_entry **entry)
618: {
619: *entry = RB_NEXT(args_tree, &args->tree, *entry);
620: if (*entry == NULL)
621: return (0);
622: return ((*entry)->flag);
1.38 nicm 623: }
624:
625: /* Get argument count. */
626: u_int
627: args_count(struct args *args)
628: {
1.43 nicm 629: return (args->count);
630: }
631:
1.48 nicm 632: /* Get argument values. */
633: struct args_value *
634: args_values(struct args *args)
635: {
636: return (args->values);
637: }
638:
1.43 nicm 639: /* Get argument value. */
640: struct args_value *
641: args_value(struct args *args, u_int idx)
642: {
643: if (idx >= args->count)
644: return (NULL);
645: return (&args->values[idx]);
1.38 nicm 646: }
647:
648: /* Return argument as string. */
649: const char *
650: args_string(struct args *args, u_int idx)
651: {
1.44 nicm 652: if (idx >= args->count)
1.38 nicm 653: return (NULL);
1.43 nicm 654: return (args_value_as_string(&args->values[idx]));
1.45 nicm 655: }
656:
657: /* Make a command now. */
658: struct cmd_list *
1.50 nicm 659: args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx,
660: int expand)
1.45 nicm 661: {
662: struct args_command_state *state;
663: char *error;
664: struct cmd_list *cmdlist;
665:
1.50 nicm 666: state = args_make_commands_prepare(self, item, idx, NULL, 0, expand);
1.45 nicm 667: cmdlist = args_make_commands(state, 0, NULL, &error);
668: if (cmdlist == NULL) {
669: cmdq_error(item, "%s", error);
670: free(error);
671: }
1.48 nicm 672: else
673: cmdlist->references++;
1.46 nicm 674: args_make_commands_free(state);
1.45 nicm 675: return (cmdlist);
676: }
677:
678: /* Save bits to make a command later. */
679: struct args_command_state *
680: args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
681: const char *default_command, int wait, int expand)
682: {
683: struct args *args = cmd_get_args(self);
684: struct cmd_find_state *target = cmdq_get_target(item);
685: struct client *tc = cmdq_get_target_client(item);
686: struct args_value *value;
687: struct args_command_state *state;
688: const char *cmd;
689:
690: state = xcalloc(1, sizeof *state);
691:
692: if (idx < args->count) {
693: value = &args->values[idx];
694: if (value->type == ARGS_COMMANDS) {
695: state->cmdlist = value->cmdlist;
696: state->cmdlist->references++;
697: return (state);
698: }
699: cmd = value->string;
700: } else {
701: if (default_command == NULL)
702: fatalx("argument out of range");
703: cmd = default_command;
704: }
705:
706:
707: if (expand)
708: state->cmd = format_single_from_target(item, cmd);
709: else
710: state->cmd = xstrdup(cmd);
711: log_debug("%s: %s", __func__, state->cmd);
712:
713: if (wait)
714: state->pi.item = item;
715: cmd_get_source(self, &state->pi.file, &state->pi.line);
716: state->pi.c = tc;
717: if (state->pi.c != NULL)
718: state->pi.c->references++;
719: cmd_find_copy_state(&state->pi.fs, target);
720:
721: return (state);
722: }
723:
724: /* Return argument as command. */
725: struct cmd_list *
726: args_make_commands(struct args_command_state *state, int argc, char **argv,
727: char **error)
728: {
729: struct cmd_parse_result *pr;
730: char *cmd, *new_cmd;
731: int i;
732:
1.48 nicm 733: if (state->cmdlist != NULL) {
734: if (argc == 0)
735: return (state->cmdlist);
736: return (cmd_list_copy(state->cmdlist, argc, argv));
737: }
1.45 nicm 738:
739: cmd = xstrdup(state->cmd);
740: for (i = 0; i < argc; i++) {
741: new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
742: log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
743: free(cmd);
744: cmd = new_cmd;
745: }
746: log_debug("%s: %s", __func__, cmd);
747:
748: pr = cmd_parse_from_string(cmd, &state->pi);
749: free(cmd);
750: switch (pr->status) {
751: case CMD_PARSE_ERROR:
752: *error = pr->error;
753: return (NULL);
754: case CMD_PARSE_SUCCESS:
755: return (pr->cmdlist);
756: }
1.52 ! nicm 757: fatalx("invalid parse return state");
1.45 nicm 758: }
759:
760: /* Free commands state. */
761: void
762: args_make_commands_free(struct args_command_state *state)
763: {
764: if (state->cmdlist != NULL)
765: cmd_list_free(state->cmdlist);
766: if (state->pi.c != NULL)
767: server_client_unref(state->pi.c);
768: free(state->cmd);
769: free(state);
770: }
771:
772: /* Get prepared command. */
773: char *
774: args_make_commands_get_command(struct args_command_state *state)
775: {
776: struct cmd *first;
777: int n;
778: char *s;
779:
780: if (state->cmdlist != NULL) {
781: first = cmd_list_first(state->cmdlist);
782: if (first == NULL)
783: return (xstrdup(""));
784: return (xstrdup(cmd_get_entry(first)->name));
785: }
786: n = strcspn(state->cmd, " ,");
787: xasprintf(&s, "%.*s", n, state->cmd);
788: return (s);
1.32 nicm 789: }
790:
1.21 nicm 791: /* Get first value in argument. */
1.37 nicm 792: struct args_value *
793: args_first_value(struct args *args, u_char flag)
1.21 nicm 794: {
795: struct args_entry *entry;
796:
1.32 nicm 797: if ((entry = args_find(args, flag)) == NULL)
1.21 nicm 798: return (NULL);
1.37 nicm 799: return (TAILQ_FIRST(&entry->values));
1.21 nicm 800: }
801:
802: /* Get next value in argument. */
1.37 nicm 803: struct args_value *
804: args_next_value(struct args_value *value)
1.21 nicm 805: {
1.37 nicm 806: return (TAILQ_NEXT(value, entry));
1.1 nicm 807: }
808:
809: /* Convert an argument value to a number. */
810: long long
1.32 nicm 811: args_strtonum(struct args *args, u_char flag, long long minval,
812: long long maxval, char **cause)
1.1 nicm 813: {
1.5 nicm 814: const char *errstr;
1.39 nicm 815: long long ll;
1.5 nicm 816: struct args_entry *entry;
1.21 nicm 817: struct args_value *value;
1.1 nicm 818:
1.32 nicm 819: if ((entry = args_find(args, flag)) == NULL) {
1.1 nicm 820: *cause = xstrdup("missing");
821: return (0);
822: }
1.21 nicm 823: value = TAILQ_LAST(&entry->values, args_values);
1.1 nicm 824:
1.41 nicm 825: ll = strtonum(value->string, minval, maxval, &errstr);
1.1 nicm 826: if (errstr != NULL) {
827: *cause = xstrdup(errstr);
828: return (0);
1.29 nicm 829: }
830:
831: *cause = NULL;
832: return (ll);
833: }
834:
835: /* Convert an argument to a number which may be a percentage. */
836: long long
1.32 nicm 837: args_percentage(struct args *args, u_char flag, long long minval,
1.29 nicm 838: long long maxval, long long curval, char **cause)
839: {
1.31 nicm 840: const char *value;
1.29 nicm 841: struct args_entry *entry;
842:
1.32 nicm 843: if ((entry = args_find(args, flag)) == NULL) {
1.29 nicm 844: *cause = xstrdup("missing");
845: return (0);
846: }
1.41 nicm 847: value = TAILQ_LAST(&entry->values, args_values)->string;
1.31 nicm 848: return (args_string_percentage(value, minval, maxval, curval, cause));
849: }
850:
851: /* Convert a string to a number which may be a percentage. */
852: long long
853: args_string_percentage(const char *value, long long minval, long long maxval,
854: long long curval, char **cause)
855: {
856: const char *errstr;
1.39 nicm 857: long long ll;
1.31 nicm 858: size_t valuelen = strlen(value);
859: char *copy;
1.29 nicm 860:
1.31 nicm 861: if (value[valuelen - 1] == '%') {
862: copy = xstrdup(value);
1.29 nicm 863: copy[valuelen - 1] = '\0';
864:
865: ll = strtonum(copy, 0, 100, &errstr);
866: free(copy);
867: if (errstr != NULL) {
868: *cause = xstrdup(errstr);
869: return (0);
870: }
871: ll = (curval * ll) / 100;
872: if (ll < minval) {
1.33 nicm 873: *cause = xstrdup("too small");
1.29 nicm 874: return (0);
875: }
876: if (ll > maxval) {
1.33 nicm 877: *cause = xstrdup("too large");
1.29 nicm 878: return (0);
879: }
880: } else {
1.31 nicm 881: ll = strtonum(value, minval, maxval, &errstr);
1.29 nicm 882: if (errstr != NULL) {
883: *cause = xstrdup(errstr);
884: return (0);
885: }
1.1 nicm 886: }
887:
888: *cause = NULL;
889: return (ll);
890: }