Annotation of embedaddon/tmux/cmd-string.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>