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

1.33    ! nicm        1: /* $OpenBSD: arguments.c,v 1.32 2020/05/16 15:40:04 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.32      nicm       59: args_find(struct args *args, u_char flag)
1.5       nicm       60: {
                     61:        struct args_entry       entry;
                     62:
1.32      nicm       63:        entry.flag = flag;
1.5       nicm       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.30      nicm      219:        if (*s == '\0') {
                    220:                xasprintf(&result, "''");
                    221:                return (result);
                    222:        }
1.26      nicm      223:        if (s[0] != ' ' &&
                    224:            (strchr(quoted, s[0]) != NULL || s[0] == '~') &&
                    225:            s[1] == '\0') {
1.22      nicm      226:                xasprintf(&escaped, "\\%c", s[0]);
                    227:                return (escaped);
                    228:        }
                    229:
1.25      nicm      230:        flags = VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL;
1.22      nicm      231:        if (s[strcspn(s, quoted)] != '\0')
                    232:                flags |= VIS_DQ;
                    233:        utf8_stravis(&escaped, s, flags);
                    234:
                    235:        if (flags & VIS_DQ) {
                    236:                if (*escaped == '~')
                    237:                        xasprintf(&result, "\"\\%s\"", escaped);
                    238:                else
                    239:                        xasprintf(&result, "\"%s\"", escaped);
                    240:        } else {
                    241:                if (*escaped == '~')
                    242:                        xasprintf(&result, "\\%s", escaped);
                    243:                else
                    244:                        result = xstrdup(escaped);
                    245:        }
                    246:        free(escaped);
                    247:        return (result);
1.1       nicm      248: }
                    249:
                    250: /* Return if an argument is present. */
                    251: int
1.32      nicm      252: args_has(struct args *args, u_char flag)
1.1       nicm      253: {
1.27      nicm      254:        struct args_entry       *entry;
                    255:
1.32      nicm      256:        entry = args_find(args, flag);
1.27      nicm      257:        if (entry == NULL)
                    258:                return (0);
                    259:        return (entry->count);
1.1       nicm      260: }
                    261:
1.5       nicm      262: /* Set argument value in the arguments tree. */
1.19      nicm      263: void
1.32      nicm      264: args_set(struct args *args, u_char flag, const char *s)
1.1       nicm      265: {
1.5       nicm      266:        struct args_entry       *entry;
1.21      nicm      267:        struct args_value       *value;
1.5       nicm      268:
1.32      nicm      269:        entry = args_find(args, flag);
1.21      nicm      270:        if (entry == NULL) {
1.7       nicm      271:                entry = xcalloc(1, sizeof *entry);
1.32      nicm      272:                entry->flag = flag;
1.27      nicm      273:                entry->count = 1;
1.21      nicm      274:                TAILQ_INIT(&entry->values);
1.7       nicm      275:                RB_INSERT(args_tree, &args->tree, entry);
1.27      nicm      276:        } else
                    277:                entry->count++;
1.5       nicm      278:
1.21      nicm      279:        if (s != NULL) {
                    280:                value = xcalloc(1, sizeof *value);
                    281:                value->value = xstrdup(s);
                    282:                TAILQ_INSERT_TAIL(&entry->values, value, entry);
                    283:        }
1.1       nicm      284: }
                    285:
                    286: /* Get argument value. Will be NULL if it isn't present. */
                    287: const char *
1.32      nicm      288: args_get(struct args *args, u_char flag)
1.1       nicm      289: {
1.5       nicm      290:        struct args_entry       *entry;
                    291:
1.32      nicm      292:        if ((entry = args_find(args, flag)) == NULL)
                    293:                return (NULL);
                    294:        if (TAILQ_EMPTY(&entry->values))
1.5       nicm      295:                return (NULL);
1.21      nicm      296:        return (TAILQ_LAST(&entry->values, args_values)->value);
                    297: }
                    298:
1.32      nicm      299: /* Get first argument. */
                    300: u_char
                    301: args_first(struct args *args, struct args_entry **entry)
                    302: {
                    303:        *entry = RB_MIN(args_tree, &args->tree);
                    304:        if (*entry == NULL)
                    305:                return (0);
                    306:        return ((*entry)->flag);
                    307: }
                    308:
                    309: /* Get next argument. */
                    310: u_char
                    311: args_next(struct args_entry **entry)
                    312: {
                    313:        *entry = RB_NEXT(args_tree, &args->tree, *entry);
                    314:        if (*entry == NULL)
                    315:                return (0);
                    316:        return ((*entry)->flag);
                    317: }
                    318:
1.21      nicm      319: /* Get first value in argument. */
                    320: const char *
1.32      nicm      321: args_first_value(struct args *args, u_char flag, struct args_value **value)
1.21      nicm      322: {
                    323:        struct args_entry       *entry;
                    324:
1.32      nicm      325:        if ((entry = args_find(args, flag)) == NULL)
1.21      nicm      326:                return (NULL);
                    327:
                    328:        *value = TAILQ_FIRST(&entry->values);
                    329:        if (*value == NULL)
                    330:                return (NULL);
                    331:        return ((*value)->value);
                    332: }
                    333:
                    334: /* Get next value in argument. */
                    335: const char *
                    336: args_next_value(struct args_value **value)
                    337: {
                    338:        if (*value == NULL)
                    339:                return (NULL);
                    340:        *value = TAILQ_NEXT(*value, entry);
                    341:        if (*value == NULL)
                    342:                return (NULL);
                    343:        return ((*value)->value);
1.1       nicm      344: }
                    345:
                    346: /* Convert an argument value to a number. */
                    347: long long
1.32      nicm      348: args_strtonum(struct args *args, u_char flag, long long minval,
                    349:     long long maxval, char **cause)
1.1       nicm      350: {
1.5       nicm      351:        const char              *errstr;
                    352:        long long                ll;
                    353:        struct args_entry       *entry;
1.21      nicm      354:        struct args_value       *value;
1.1       nicm      355:
1.32      nicm      356:        if ((entry = args_find(args, flag)) == NULL) {
1.1       nicm      357:                *cause = xstrdup("missing");
                    358:                return (0);
                    359:        }
1.21      nicm      360:        value = TAILQ_LAST(&entry->values, args_values);
1.1       nicm      361:
1.21      nicm      362:        ll = strtonum(value->value, minval, maxval, &errstr);
1.1       nicm      363:        if (errstr != NULL) {
                    364:                *cause = xstrdup(errstr);
                    365:                return (0);
1.29      nicm      366:        }
                    367:
                    368:        *cause = NULL;
                    369:        return (ll);
                    370: }
                    371:
                    372: /* Convert an argument to a number which may be a percentage. */
                    373: long long
1.32      nicm      374: args_percentage(struct args *args, u_char flag, long long minval,
1.29      nicm      375:     long long maxval, long long curval, char **cause)
                    376: {
1.31      nicm      377:        const char              *value;
1.29      nicm      378:        struct args_entry       *entry;
                    379:
1.32      nicm      380:        if ((entry = args_find(args, flag)) == NULL) {
1.29      nicm      381:                *cause = xstrdup("missing");
                    382:                return (0);
                    383:        }
1.31      nicm      384:        value = TAILQ_LAST(&entry->values, args_values)->value;
                    385:        return (args_string_percentage(value, minval, maxval, curval, cause));
                    386: }
                    387:
                    388: /* Convert a string to a number which may be a percentage. */
                    389: long long
                    390: args_string_percentage(const char *value, long long minval, long long maxval,
                    391:     long long curval, char **cause)
                    392: {
                    393:        const char      *errstr;
                    394:        long long        ll;
                    395:        size_t           valuelen = strlen(value);
                    396:        char            *copy;
1.29      nicm      397:
1.31      nicm      398:        if (value[valuelen - 1] == '%') {
                    399:                copy = xstrdup(value);
1.29      nicm      400:                copy[valuelen - 1] = '\0';
                    401:
                    402:                ll = strtonum(copy, 0, 100, &errstr);
                    403:                free(copy);
                    404:                if (errstr != NULL) {
                    405:                        *cause = xstrdup(errstr);
                    406:                        return (0);
                    407:                }
                    408:                ll = (curval * ll) / 100;
                    409:                if (ll < minval) {
1.33    ! nicm      410:                        *cause = xstrdup("too small");
1.29      nicm      411:                        return (0);
                    412:                }
                    413:                if (ll > maxval) {
1.33    ! nicm      414:                        *cause = xstrdup("too large");
1.29      nicm      415:                        return (0);
                    416:                }
                    417:        } else {
1.31      nicm      418:                ll = strtonum(value, minval, maxval, &errstr);
1.29      nicm      419:                if (errstr != NULL) {
                    420:                        *cause = xstrdup(errstr);
                    421:                        return (0);
                    422:                }
1.1       nicm      423:        }
                    424:
                    425:        *cause = NULL;
                    426:        return (ll);
                    427: }