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

Annotation of src/usr.bin/tmux/cmd-string.c, Revision 1.27

1.26      nicm        1: /* $OpenBSD: cmd-string.c,v 1.25 2017/01/15 22:00:56 nicm Exp $ */
1.1       nicm        2:
                      3: /*
1.22      nicm        4:  * Copyright (c) 2008 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 <errno.h>
1.4       nicm       22: #include <pwd.h>
1.1       nicm       23: #include <stdio.h>
                     24: #include <string.h>
                     25: #include <stdlib.h>
1.4       nicm       26: #include <unistd.h>
1.1       nicm       27:
                     28: #include "tmux.h"
                     29:
                     30: /*
                     31:  * Parse a command from a string.
                     32:  */
                     33:
1.23      nicm       34: static int      cmd_string_getc(const char *, size_t *);
                     35: static void     cmd_string_ungetc(size_t *);
                     36: static void     cmd_string_copy(char **, char *, size_t *);
                     37: static char    *cmd_string_string(const char *, size_t *, char, int);
                     38: static char    *cmd_string_variable(const char *, size_t *);
                     39: static char    *cmd_string_expand_tilde(const char *, size_t *);
1.1       nicm       40:
1.23      nicm       41: static int
1.1       nicm       42: cmd_string_getc(const char *s, size_t *p)
                     43: {
1.11      nicm       44:        const u_char    *ucs = s;
                     45:
                     46:        if (ucs[*p] == '\0')
1.1       nicm       47:                return (EOF);
1.11      nicm       48:        return (ucs[(*p)++]);
1.1       nicm       49: }
                     50:
1.23      nicm       51: static void
1.11      nicm       52: cmd_string_ungetc(size_t *p)
1.1       nicm       53: {
                     54:        (*p)--;
                     55: }
                     56:
1.27    ! nicm       57: struct cmd_list *
        !            58: cmd_string_parse(const char *s, const char *file, u_int line, char **cause)
1.1       nicm       59: {
1.27    ! nicm       60:        size_t            p = 0;
        !            61:        int               ch, i, argc = 0;
        !            62:        char            **argv = NULL, *buf = NULL, *t;
        !            63:        const char       *whitespace, *equals;
        !            64:        size_t            len = 0;
        !            65:        struct cmd_list  *cmdlist = NULL;
1.1       nicm       66:
1.27    ! nicm       67:        *cause = NULL;
1.1       nicm       68:        for (;;) {
                     69:                ch = cmd_string_getc(s, &p);
                     70:                switch (ch) {
                     71:                case '\'':
                     72:                        if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
                     73:                                goto error;
1.17      nicm       74:                        cmd_string_copy(&buf, t, &len);
1.1       nicm       75:                        break;
                     76:                case '"':
                     77:                        if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
                     78:                                goto error;
1.17      nicm       79:                        cmd_string_copy(&buf, t, &len);
1.1       nicm       80:                        break;
                     81:                case '$':
                     82:                        if ((t = cmd_string_variable(s, &p)) == NULL)
                     83:                                goto error;
1.17      nicm       84:                        cmd_string_copy(&buf, t, &len);
1.1       nicm       85:                        break;
                     86:                case '#':
                     87:                        /* Comment: discard rest of line. */
                     88:                        while ((ch = cmd_string_getc(s, &p)) != EOF)
                     89:                                ;
                     90:                        /* FALLTHROUGH */
                     91:                case EOF:
                     92:                case ' ':
                     93:                case '\t':
1.14      nicm       94:                        if (buf != NULL) {
1.20      nicm       95:                                buf = xrealloc(buf, len + 1);
1.1       nicm       96:                                buf[len] = '\0';
                     97:
1.20      nicm       98:                                argv = xreallocarray(argv, argc + 1,
                     99:                                    sizeof *argv);
1.1       nicm      100:                                argv[argc++] = buf;
                    101:
                    102:                                buf = NULL;
                    103:                                len = 0;
                    104:                        }
                    105:
                    106:                        if (ch != EOF)
                    107:                                break;
1.6       nicm      108:
1.8       nicm      109:                        while (argc != 0) {
                    110:                                equals = strchr(argv[0], '=');
                    111:                                whitespace = argv[0] + strcspn(argv[0], " \t");
1.6       nicm      112:                                if (equals == NULL || equals > whitespace)
                    113:                                        break;
1.21      nicm      114:                                environ_put(global_environ, argv[0]);
1.6       nicm      115:                                argc--;
1.8       nicm      116:                                memmove(argv, argv + 1, argc * (sizeof *argv));
1.6       nicm      117:                        }
1.27    ! nicm      118:                        if (argc == 0)
        !           119:                                goto out;
        !           120:
        !           121:                        cmdlist = cmd_list_parse(argc, argv, file, line, cause);
        !           122:                        goto out;
1.4       nicm      123:                case '~':
1.27    ! nicm      124:                        if (buf == NULL) {
        !           125:                                t = cmd_string_expand_tilde(s, &p);
        !           126:                                if (t == NULL)
        !           127:                                        goto error;
        !           128:                                cmd_string_copy(&buf, t, &len);
1.4       nicm      129:                                break;
                    130:                        }
1.27    ! nicm      131:                        /* FALLTHROUGH */
1.1       nicm      132:                default:
                    133:                        if (len >= SIZE_MAX - 2)
                    134:                                goto error;
1.27    ! nicm      135:
1.20      nicm      136:                        buf = xrealloc(buf, len + 1);
1.1       nicm      137:                        buf[len++] = ch;
1.27    ! nicm      138:                        break;
1.1       nicm      139:                }
                    140:        }
                    141:
1.27    ! nicm      142: error:
        !           143:        xasprintf(cause, "invalid or unknown command: %s", s);
1.26      nicm      144:
1.27    ! nicm      145: out:
1.26      nicm      146:        free(buf);
                    147:
1.27    ! nicm      148:        if (argv != NULL) {
        !           149:                for (i = 0; i < argc; i++)
        !           150:                        free(argv[i]);
        !           151:                free(argv);
        !           152:        }
1.1       nicm      153:
1.26      nicm      154:        return (cmdlist);
1.1       nicm      155: }
                    156:
1.23      nicm      157: static void
1.17      nicm      158: cmd_string_copy(char **dst, char *src, size_t *len)
                    159: {
                    160:        size_t srclen;
                    161:
                    162:        srclen = strlen(src);
                    163:
1.20      nicm      164:        *dst = xrealloc(*dst, *len + srclen + 1);
1.17      nicm      165:        strlcpy(*dst + *len, src, srclen + 1);
                    166:
                    167:        *len += srclen;
                    168:        free(src);
                    169: }
                    170:
1.23      nicm      171: static char *
1.1       nicm      172: cmd_string_string(const char *s, size_t *p, char endch, int esc)
                    173: {
                    174:        int     ch;
                    175:        char   *buf, *t;
                    176:        size_t  len;
                    177:
1.7       deraadt   178:        buf = NULL;
1.1       nicm      179:        len = 0;
                    180:
1.7       deraadt   181:        while ((ch = cmd_string_getc(s, p)) != endch) {
                    182:                switch (ch) {
1.1       nicm      183:                case EOF:
                    184:                        goto error;
1.7       deraadt   185:                case '\\':
1.1       nicm      186:                        if (!esc)
                    187:                                break;
1.7       deraadt   188:                        switch (ch = cmd_string_getc(s, p)) {
1.1       nicm      189:                        case EOF:
                    190:                                goto error;
1.5       nicm      191:                        case 'e':
                    192:                                ch = '\033';
                    193:                                break;
1.7       deraadt   194:                        case 'r':
                    195:                                ch = '\r';
                    196:                                break;
                    197:                        case 'n':
                    198:                                ch = '\n';
                    199:                                break;
                    200:                        case 't':
                    201:                                ch = '\t';
                    202:                                break;
                    203:                        }
                    204:                        break;
1.1       nicm      205:                case '$':
                    206:                        if (!esc)
                    207:                                break;
                    208:                        if ((t = cmd_string_variable(s, p)) == NULL)
                    209:                                goto error;
1.17      nicm      210:                        cmd_string_copy(&buf, t, &len);
1.1       nicm      211:                        continue;
1.7       deraadt   212:                }
1.1       nicm      213:
                    214:                if (len >= SIZE_MAX - 2)
                    215:                        goto error;
1.20      nicm      216:                buf = xrealloc(buf, len + 1);
1.7       deraadt   217:                buf[len++] = ch;
                    218:        }
1.1       nicm      219:
1.20      nicm      220:        buf = xrealloc(buf, len + 1);
1.1       nicm      221:        buf[len] = '\0';
                    222:        return (buf);
                    223:
                    224: error:
1.16      nicm      225:        free(buf);
1.1       nicm      226:        return (NULL);
                    227: }
                    228:
1.23      nicm      229: static char *
1.1       nicm      230: cmd_string_variable(const char *s, size_t *p)
                    231: {
1.15      nicm      232:        int                     ch, fch;
                    233:        char                   *buf, *t;
                    234:        size_t                  len;
                    235:        struct environ_entry   *envent;
1.1       nicm      236:
                    237: #define cmd_string_first(ch) ((ch) == '_' || \
                    238:        ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
                    239: #define cmd_string_other(ch) ((ch) == '_' || \
                    240:        ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
                    241:        ((ch) >= '0' && (ch) <= '9'))
                    242:
1.7       deraadt   243:        buf = NULL;
1.1       nicm      244:        len = 0;
                    245:
                    246:        fch = EOF;
                    247:        switch (ch = cmd_string_getc(s, p)) {
                    248:        case EOF:
                    249:                goto error;
                    250:        case '{':
                    251:                fch = '{';
                    252:
                    253:                ch = cmd_string_getc(s, p);
                    254:                if (!cmd_string_first(ch))
                    255:                        goto error;
                    256:                /* FALLTHROUGH */
                    257:        default:
                    258:                if (!cmd_string_first(ch)) {
                    259:                        xasprintf(&t, "$%c", ch);
                    260:                        return (t);
                    261:                }
                    262:
1.20      nicm      263:                buf = xrealloc(buf, len + 1);
1.1       nicm      264:                buf[len++] = ch;
                    265:
                    266:                for (;;) {
                    267:                        ch = cmd_string_getc(s, p);
                    268:                        if (ch == EOF || !cmd_string_other(ch))
                    269:                                break;
                    270:                        else {
                    271:                                if (len >= SIZE_MAX - 3)
                    272:                                        goto error;
1.20      nicm      273:                                buf = xrealloc(buf, len + 1);
1.1       nicm      274:                                buf[len++] = ch;
                    275:                        }
                    276:                }
                    277:        }
                    278:
                    279:        if (fch == '{' && ch != '}')
                    280:                goto error;
                    281:        if (ch != EOF && fch != '{')
1.11      nicm      282:                cmd_string_ungetc(p); /* ch */
1.1       nicm      283:
1.20      nicm      284:        buf = xrealloc(buf, len + 1);
1.1       nicm      285:        buf[len] = '\0';
                    286:
1.21      nicm      287:        envent = environ_find(global_environ, buf);
1.16      nicm      288:        free(buf);
1.15      nicm      289:        if (envent == NULL)
1.1       nicm      290:                return (xstrdup(""));
1.15      nicm      291:        return (xstrdup(envent->value));
1.1       nicm      292:
                    293: error:
1.16      nicm      294:        free(buf);
1.1       nicm      295:        return (NULL);
1.4       nicm      296: }
                    297:
1.23      nicm      298: static char *
1.4       nicm      299: cmd_string_expand_tilde(const char *s, size_t *p)
                    300: {
1.15      nicm      301:        struct passwd           *pw;
                    302:        struct environ_entry    *envent;
1.19      nicm      303:        char                    *home, *path, *user, *cp;
                    304:        int                      last;
1.4       nicm      305:
                    306:        home = NULL;
1.19      nicm      307:
                    308:        last = cmd_string_getc(s, p);
                    309:        if (last == EOF || last == '/' || last == ' '|| last == '\t') {
1.21      nicm      310:                envent = environ_find(global_environ, "HOME");
1.15      nicm      311:                if (envent != NULL && *envent->value != '\0')
                    312:                        home = envent->value;
                    313:                else if ((pw = getpwuid(getuid())) != NULL)
                    314:                        home = pw->pw_dir;
1.4       nicm      315:        } else {
1.11      nicm      316:                cmd_string_ungetc(p);
1.19      nicm      317:
                    318:                cp = user = xmalloc(strlen(s));
                    319:                for (;;) {
                    320:                        last = cmd_string_getc(s, p);
1.23      nicm      321:                        if (last == EOF ||
                    322:                            last == '/' ||
                    323:                            last == ' '||
                    324:                            last == '\t')
1.19      nicm      325:                                break;
                    326:                        *cp++ = last;
                    327:                }
                    328:                *cp = '\0';
                    329:
                    330:                if ((pw = getpwnam(user)) != NULL)
1.4       nicm      331:                        home = pw->pw_dir;
1.19      nicm      332:                free(user);
1.4       nicm      333:        }
1.19      nicm      334:
1.4       nicm      335:        if (home == NULL)
                    336:                return (NULL);
                    337:
1.19      nicm      338:        if (last != EOF)
                    339:                xasprintf(&path, "%s%c", home, last);
                    340:        else
                    341:                xasprintf(&path, "%s", home);
1.4       nicm      342:        return (path);
1.1       nicm      343: }