[BACK]Return to arguments.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tmux

Annotation of src/usr.bin/tmux/arguments.c, Revision 1.28

1.28    ! nicm        1: /* $OpenBSD: arguments.c,v 1.27 2019/07/09 14:03:12 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:
                     21: #include <stdlib.h>
                     22: #include <string.h>
1.6       okan       23: #include <unistd.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.21      nicm       32: struct args_value {
                     33:        char                    *value;
                     34:        TAILQ_ENTRY(args_value)  entry;
                     35: };
                     36: TAILQ_HEAD(args_values, args_value);
                     37:
1.11      nicm       38: struct args_entry {
                     39:        u_char                   flag;
1.21      nicm       40:        struct args_values       values;
1.27      nicm       41:        u_int                    count;
1.11      nicm       42:        RB_ENTRY(args_entry)     entry;
                     43: };
1.5       nicm       44:
1.14      nicm       45: static struct args_entry       *args_find(struct args *, u_char);
1.5       nicm       46:
1.14      nicm       47: static int     args_cmp(struct args_entry *, struct args_entry *);
                     48: RB_GENERATE_STATIC(args_tree, args_entry, entry, args_cmp);
1.5       nicm       49:
                     50: /* Arguments tree comparison function. */
1.14      nicm       51: static int
1.5       nicm       52: args_cmp(struct args_entry *a1, struct args_entry *a2)
                     53: {
                     54:        return (a1->flag - a2->flag);
                     55: }
                     56:
                     57: /* Find a flag in the arguments tree. */
1.14      nicm       58: static struct args_entry *
1.5       nicm       59: args_find(struct args *args, u_char ch)
                     60: {
                     61:        struct args_entry       entry;
                     62:
                     63:        entry.flag = ch;
                     64:        return (RB_FIND(args_tree, &args->tree, &entry));
                     65: }
                     66:
1.1       nicm       67: /* Parse an argv and argc into a new argument set. */
                     68: struct args *
                     69: args_parse(const char *template, int argc, char **argv)
                     70: {
                     71:        struct args     *args;
                     72:        int              opt;
                     73:
                     74:        args = xcalloc(1, sizeof *args);
                     75:
                     76:        optreset = 1;
                     77:        optind = 1;
1.28    ! nicm       78:        optarg = NULL;
1.1       nicm       79:
                     80:        while ((opt = getopt(argc, argv, template)) != -1) {
1.5       nicm       81:                if (opt < 0)
1.1       nicm       82:                        continue;
1.8       nicm       83:                if (opt == '?' || strchr(template, opt) == NULL) {
1.5       nicm       84:                        args_free(args);
1.1       nicm       85:                        return (NULL);
                     86:                }
1.5       nicm       87:                args_set(args, opt, optarg);
1.28    ! nicm       88:                optarg = NULL;
1.1       nicm       89:        }
                     90:        argc -= optind;
                     91:        argv += optind;
                     92:
                     93:        args->argc = argc;
                     94:        args->argv = cmd_copy_argv(argc, argv);
                     95:
                     96:        return (args);
                     97: }
                     98:
                     99: /* Free an arguments set. */
                    100: void
                    101: args_free(struct args *args)
                    102: {
1.5       nicm      103:        struct args_entry       *entry;
                    104:        struct args_entry       *entry1;
1.21      nicm      105:        struct args_value       *value;
                    106:        struct args_value       *value1;
1.1       nicm      107:
                    108:        cmd_free_argv(args->argc, args->argv);
                    109:
1.5       nicm      110:        RB_FOREACH_SAFE(entry, args_tree, &args->tree, entry1) {
                    111:                RB_REMOVE(args_tree, &args->tree, entry);
1.21      nicm      112:                TAILQ_FOREACH_SAFE(value, &entry->values, entry, value1) {
                    113:                        TAILQ_REMOVE(&entry->values, value, entry);
                    114:                        free(value->value);
                    115:                        free(value);
                    116:                }
1.5       nicm      117:                free(entry);
                    118:        }
1.1       nicm      119:
1.4       nicm      120:        free(args);
1.1       nicm      121: }
                    122:
1.12      nicm      123: /* Add to string. */
                    124: static void printflike(3, 4)
                    125: args_print_add(char **buf, size_t *len, const char *fmt, ...)
                    126: {
                    127:        va_list  ap;
                    128:        char    *s;
                    129:        size_t   slen;
                    130:
                    131:        va_start(ap, fmt);
                    132:        slen = xvasprintf(&s, fmt, ap);
                    133:        va_end(ap);
                    134:
                    135:        *len += slen;
                    136:        *buf = xrealloc(*buf, *len);
                    137:
                    138:        strlcat(*buf, s, *len);
                    139:        free(s);
                    140: }
                    141:
1.21      nicm      142: /* Add value to string. */
                    143: static void
                    144: args_print_add_value(char **buf, size_t *len, struct args_entry *entry,
                    145:     struct args_value *value)
                    146: {
1.22      nicm      147:        char    *escaped;
1.21      nicm      148:
                    149:        if (**buf != '\0')
                    150:                args_print_add(buf, len, " -%c ", entry->flag);
                    151:        else
                    152:                args_print_add(buf, len, "-%c ", entry->flag);
                    153:
1.22      nicm      154:        escaped = args_escape(value->value);
                    155:        args_print_add(buf, len, "%s", escaped);
1.21      nicm      156:        free(escaped);
                    157: }
                    158:
                    159: /* Add argument to string. */
                    160: static void
                    161: args_print_add_argument(char **buf, size_t *len, const char *argument)
                    162: {
1.22      nicm      163:        char    *escaped;
1.21      nicm      164:
                    165:        if (**buf != '\0')
                    166:                args_print_add(buf, len, " ");
                    167:
1.22      nicm      168:        escaped = args_escape(argument);
                    169:        args_print_add(buf, len, "%s", escaped);
1.21      nicm      170:        free(escaped);
                    171: }
                    172:
1.1       nicm      173: /* Print a set of arguments. */
1.12      nicm      174: char *
                    175: args_print(struct args *args)
1.1       nicm      176: {
1.12      nicm      177:        size_t                   len;
1.21      nicm      178:        char                    *buf;
                    179:        int                      i;
1.27      nicm      180:        u_int                    j;
1.5       nicm      181:        struct args_entry       *entry;
1.21      nicm      182:        struct args_value       *value;
1.1       nicm      183:
1.12      nicm      184:        len = 1;
                    185:        buf = xcalloc(1, len);
1.1       nicm      186:
                    187:        /* Process the flags first. */
1.5       nicm      188:        RB_FOREACH(entry, args_tree, &args->tree) {
1.21      nicm      189:                if (!TAILQ_EMPTY(&entry->values))
1.1       nicm      190:                        continue;
                    191:
1.12      nicm      192:                if (*buf == '\0')
                    193:                        args_print_add(&buf, &len, "-");
1.27      nicm      194:                for (j = 0; j < entry->count; j++)
                    195:                        args_print_add(&buf, &len, "%c", entry->flag);
1.1       nicm      196:        }
                    197:
                    198:        /* Then the flags with arguments. */
1.5       nicm      199:        RB_FOREACH(entry, args_tree, &args->tree) {
1.21      nicm      200:                TAILQ_FOREACH(value, &entry->values, entry)
                    201:                        args_print_add_value(&buf, &len, entry, value);
1.1       nicm      202:        }
                    203:
                    204:        /* And finally the argument vector. */
1.21      nicm      205:        for (i = 0; i < args->argc; i++)
                    206:                args_print_add_argument(&buf, &len, args->argv[i]);
1.1       nicm      207:
1.12      nicm      208:        return (buf);
1.22      nicm      209: }
                    210:
                    211: /* Escape an argument. */
                    212: char *
                    213: args_escape(const char *s)
                    214: {
1.23      nicm      215:        static const char        quoted[] = " #\"';${}";
1.22      nicm      216:        char                    *escaped, *result;
                    217:        int                      flags;
                    218:
1.24      nicm      219:        if (*s == '\0')
                    220:                return (xstrdup(s));
1.26      nicm      221:        if (s[0] != ' ' &&
                    222:            (strchr(quoted, s[0]) != NULL || s[0] == '~') &&
                    223:            s[1] == '\0') {
1.22      nicm      224:                xasprintf(&escaped, "\\%c", s[0]);
                    225:                return (escaped);
                    226:        }
                    227:
1.25      nicm      228:        flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
1.22      nicm      229:        if (s[strcspn(s, quoted)] != '\0')
                    230:                flags |= VIS_DQ;
                    231:        utf8_stravis(&escaped, s, flags);
                    232:
                    233:        if (flags & VIS_DQ) {
                    234:                if (*escaped == '~')
                    235:                        xasprintf(&result, "\"\\%s\"", escaped);
                    236:                else
                    237:                        xasprintf(&result, "\"%s\"", escaped);
                    238:        } else {
                    239:                if (*escaped == '~')
                    240:                        xasprintf(&result, "\\%s", escaped);
                    241:                else
                    242:                        result = xstrdup(escaped);
                    243:        }
                    244:        free(escaped);
                    245:        return (result);
1.1       nicm      246: }
                    247:
                    248: /* Return if an argument is present. */
                    249: int
                    250: args_has(struct args *args, u_char ch)
                    251: {
1.27      nicm      252:        struct args_entry       *entry;
                    253:
                    254:        entry = args_find(args, ch);
                    255:        if (entry == NULL)
                    256:                return (0);
                    257:        return (entry->count);
1.1       nicm      258: }
                    259:
1.5       nicm      260: /* Set argument value in the arguments tree. */
1.19      nicm      261: void
1.21      nicm      262: args_set(struct args *args, u_char ch, const char *s)
1.1       nicm      263: {
1.5       nicm      264:        struct args_entry       *entry;
1.21      nicm      265:        struct args_value       *value;
1.5       nicm      266:
1.21      nicm      267:        entry = args_find(args, ch);
                    268:        if (entry == NULL) {
1.7       nicm      269:                entry = xcalloc(1, sizeof *entry);
                    270:                entry->flag = ch;
1.27      nicm      271:                entry->count = 1;
1.21      nicm      272:                TAILQ_INIT(&entry->values);
1.7       nicm      273:                RB_INSERT(args_tree, &args->tree, entry);
1.27      nicm      274:        } else
                    275:                entry->count++;
1.5       nicm      276:
1.21      nicm      277:        if (s != NULL) {
                    278:                value = xcalloc(1, sizeof *value);
                    279:                value->value = xstrdup(s);
                    280:                TAILQ_INSERT_TAIL(&entry->values, value, entry);
                    281:        }
1.1       nicm      282: }
                    283:
                    284: /* Get argument value. Will be NULL if it isn't present. */
                    285: const char *
                    286: args_get(struct args *args, u_char ch)
                    287: {
1.5       nicm      288:        struct args_entry       *entry;
                    289:
                    290:        if ((entry = args_find(args, ch)) == NULL)
                    291:                return (NULL);
1.21      nicm      292:        return (TAILQ_LAST(&entry->values, args_values)->value);
                    293: }
                    294:
                    295: /* Get first value in argument. */
                    296: const char *
                    297: args_first_value(struct args *args, u_char ch, struct args_value **value)
                    298: {
                    299:        struct args_entry       *entry;
                    300:
                    301:        if ((entry = args_find(args, ch)) == NULL)
                    302:                return (NULL);
                    303:
                    304:        *value = TAILQ_FIRST(&entry->values);
                    305:        if (*value == NULL)
                    306:                return (NULL);
                    307:        return ((*value)->value);
                    308: }
                    309:
                    310: /* Get next value in argument. */
                    311: const char *
                    312: args_next_value(struct args_value **value)
                    313: {
                    314:        if (*value == NULL)
                    315:                return (NULL);
                    316:        *value = TAILQ_NEXT(*value, entry);
                    317:        if (*value == NULL)
                    318:                return (NULL);
                    319:        return ((*value)->value);
1.1       nicm      320: }
                    321:
                    322: /* Convert an argument value to a number. */
                    323: long long
1.5       nicm      324: args_strtonum(struct args *args, u_char ch, long long minval, long long maxval,
                    325:     char **cause)
1.1       nicm      326: {
1.5       nicm      327:        const char              *errstr;
                    328:        long long                ll;
                    329:        struct args_entry       *entry;
1.21      nicm      330:        struct args_value       *value;
1.1       nicm      331:
1.5       nicm      332:        if ((entry = args_find(args, ch)) == NULL) {
1.1       nicm      333:                *cause = xstrdup("missing");
                    334:                return (0);
                    335:        }
1.21      nicm      336:        value = TAILQ_LAST(&entry->values, args_values);
1.1       nicm      337:
1.21      nicm      338:        ll = strtonum(value->value, minval, maxval, &errstr);
1.1       nicm      339:        if (errstr != NULL) {
                    340:                *cause = xstrdup(errstr);
                    341:                return (0);
                    342:        }
                    343:
                    344:        *cause = NULL;
                    345:        return (ll);
                    346: }