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>