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

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