[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.27

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