Annotation of src/usr.bin/tmux/cmd-string.c, Revision 1.1
1.1 ! nicm 1: /* $OpenBSD$ */
! 2:
! 3: /*
! 4: * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
! 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 <stdio.h>
! 23: #include <string.h>
! 24: #include <stdlib.h>
! 25:
! 26: #include "tmux.h"
! 27:
! 28: /*
! 29: * Parse a command from a string.
! 30: */
! 31:
! 32: int cmd_string_getc(const char *, size_t *);
! 33: void cmd_string_ungetc(const char *, size_t *);
! 34: char *cmd_string_string(const char *, size_t *, char, int);
! 35: char *cmd_string_variable(const char *, size_t *);
! 36:
! 37: int
! 38: cmd_string_getc(const char *s, size_t *p)
! 39: {
! 40: if (s[*p] == '\0')
! 41: return (EOF);
! 42: return (s[(*p)++]);
! 43: }
! 44:
! 45: void
! 46: cmd_string_ungetc(unused const char *s, size_t *p)
! 47: {
! 48: (*p)--;
! 49: }
! 50:
! 51: /*
! 52: * Parse command string. Returns -1 on error. If returning -1, cause is error
! 53: * string, or NULL for empty command.
! 54: */
! 55: int
! 56: cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
! 57: {
! 58: size_t p;
! 59: int ch, argc, rval, have_arg;
! 60: char **argv, *buf, *t, *u;
! 61: size_t len;
! 62:
! 63: if ((t = strchr(s, ' ')) == NULL && (t = strchr(s, '\t')) == NULL)
! 64: t = strchr(s, '\0');
! 65: if ((u = strchr(s, '=')) != NULL && u < t) {
! 66: if (putenv((char *) s) != 0) {
! 67: xasprintf(cause, "assignment failed: %s", s);
! 68: return (-1);
! 69: }
! 70: *cmdlist = NULL;
! 71: return (0);
! 72: }
! 73:
! 74: argv = NULL;
! 75: argc = 0;
! 76:
! 77: buf = NULL;
! 78: len = 0;
! 79:
! 80: have_arg = 0;
! 81:
! 82: *cause = NULL;
! 83:
! 84: *cmdlist = NULL;
! 85: rval = -1;
! 86:
! 87: p = 0;
! 88: for (;;) {
! 89: ch = cmd_string_getc(s, &p);
! 90: switch (ch) {
! 91: case '\'':
! 92: if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
! 93: goto error;
! 94: buf = xrealloc(buf, 1, len + strlen(t) + 1);
! 95: strlcpy(buf + len, t, strlen(t) + 1);
! 96: len += strlen(t);
! 97: xfree(t);
! 98:
! 99: have_arg = 1;
! 100: break;
! 101: case '"':
! 102: if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
! 103: goto error;
! 104: buf = xrealloc(buf, 1, len + strlen(t) + 1);
! 105: strlcpy(buf + len, t, strlen(t) + 1);
! 106: len += strlen(t);
! 107: xfree(t);
! 108:
! 109: have_arg = 1;
! 110: break;
! 111: case '$':
! 112: if ((t = cmd_string_variable(s, &p)) == NULL)
! 113: goto error;
! 114: buf = xrealloc(buf, 1, len + strlen(t) + 1);
! 115: strlcpy(buf + len, t, strlen(t) + 1);
! 116: len += strlen(t);
! 117:
! 118: have_arg = 1;
! 119: break;
! 120: case '#':
! 121: /* Comment: discard rest of line. */
! 122: while ((ch = cmd_string_getc(s, &p)) != EOF)
! 123: ;
! 124: /* FALLTHROUGH */
! 125: case EOF:
! 126: case ' ':
! 127: case '\t':
! 128: if (have_arg) {
! 129: buf = xrealloc(buf, 1, len + 1);
! 130: buf[len] = '\0';
! 131:
! 132: argv = xrealloc(argv, argc + 1, sizeof *argv);
! 133: argv[argc++] = buf;
! 134:
! 135: buf = NULL;
! 136: len = 0;
! 137:
! 138: have_arg = 0;
! 139: }
! 140:
! 141: if (ch != EOF)
! 142: break;
! 143: if (argc == 0)
! 144: goto out;
! 145:
! 146: *cmdlist = cmd_list_parse(argc, argv, cause);
! 147: if (*cmdlist == NULL)
! 148: goto out;
! 149:
! 150: do
! 151: xfree(argv[argc - 1]);
! 152: while (--argc > 0);
! 153:
! 154: rval = 0;
! 155: goto out;
! 156: default:
! 157: if (len >= SIZE_MAX - 2)
! 158: goto error;
! 159:
! 160: buf = xrealloc(buf, 1, len + 1);
! 161: buf[len++] = ch;
! 162:
! 163: have_arg = 1;
! 164: break;
! 165: }
! 166: }
! 167:
! 168: error:
! 169: xasprintf(cause, "invalid or unknown command: %s", s);
! 170:
! 171: out:
! 172: if (buf != NULL)
! 173: xfree(buf);
! 174:
! 175: while (--argc >= 0)
! 176: xfree(argv[argc]);
! 177: if (argv != NULL)
! 178: xfree(argv);
! 179:
! 180: return (rval);
! 181: }
! 182:
! 183: char *
! 184: cmd_string_string(const char *s, size_t *p, char endch, int esc)
! 185: {
! 186: int ch;
! 187: char *buf, *t;
! 188: size_t len;
! 189:
! 190: buf = NULL;
! 191: len = 0;
! 192:
! 193: while ((ch = cmd_string_getc(s, p)) != endch) {
! 194: switch (ch) {
! 195: case EOF:
! 196: goto error;
! 197: case '\\':
! 198: if (!esc)
! 199: break;
! 200: switch (ch = cmd_string_getc(s, p)) {
! 201: case EOF:
! 202: goto error;
! 203: case 'r':
! 204: ch = '\r';
! 205: break;
! 206: case 'n':
! 207: ch = '\n';
! 208: break;
! 209: case 't':
! 210: ch = '\t';
! 211: break;
! 212: }
! 213: break;
! 214: case '$':
! 215: if (!esc)
! 216: break;
! 217: if ((t = cmd_string_variable(s, p)) == NULL)
! 218: goto error;
! 219: buf = xrealloc(buf, 1, len + strlen(t) + 1);
! 220: strlcpy(buf + len, t, strlen(t) + 1);
! 221: len += strlen(t);
! 222: continue;
! 223: }
! 224:
! 225: if (len >= SIZE_MAX - 2)
! 226: goto error;
! 227: buf = xrealloc(buf, 1, len + 1);
! 228: buf[len++] = ch;
! 229: }
! 230:
! 231: buf = xrealloc(buf, 1, len + 1);
! 232: buf[len] = '\0';
! 233: return (buf);
! 234:
! 235: error:
! 236: if (buf != NULL)
! 237: xfree(buf);
! 238: return (NULL);
! 239: }
! 240:
! 241: char *
! 242: cmd_string_variable(const char *s, size_t *p)
! 243: {
! 244: int ch, fch;
! 245: char *buf, *t;
! 246: size_t len;
! 247:
! 248: #define cmd_string_first(ch) ((ch) == '_' || \
! 249: ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
! 250: #define cmd_string_other(ch) ((ch) == '_' || \
! 251: ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
! 252: ((ch) >= '0' && (ch) <= '9'))
! 253:
! 254: buf = NULL;
! 255: len = 0;
! 256:
! 257: fch = EOF;
! 258: switch (ch = cmd_string_getc(s, p)) {
! 259: case EOF:
! 260: goto error;
! 261: case '{':
! 262: fch = '{';
! 263:
! 264: ch = cmd_string_getc(s, p);
! 265: if (!cmd_string_first(ch))
! 266: goto error;
! 267: /* FALLTHROUGH */
! 268: default:
! 269: if (!cmd_string_first(ch)) {
! 270: xasprintf(&t, "$%c", ch);
! 271: return (t);
! 272: }
! 273:
! 274: buf = xrealloc(buf, 1, len + 1);
! 275: buf[len++] = ch;
! 276:
! 277: for (;;) {
! 278: ch = cmd_string_getc(s, p);
! 279: if (ch == EOF || !cmd_string_other(ch))
! 280: break;
! 281: else {
! 282: if (len >= SIZE_MAX - 3)
! 283: goto error;
! 284: buf = xrealloc(buf, 1, len + 1);
! 285: buf[len++] = ch;
! 286: }
! 287: }
! 288: }
! 289:
! 290: if (fch == '{' && ch != '}')
! 291: goto error;
! 292: if (ch != EOF && fch != '{')
! 293: cmd_string_ungetc(s, p); /* ch */
! 294:
! 295: buf = xrealloc(buf, 1, len + 1);
! 296: buf[len] = '\0';
! 297:
! 298: if ((t = getenv(buf)) == NULL) {
! 299: xfree(buf);
! 300: return (xstrdup(""));
! 301: }
! 302: xfree(buf);
! 303: return (xstrdup(t));
! 304:
! 305: error:
! 306: if (buf != NULL)
! 307: xfree(buf);
! 308: return (NULL);
! 309: }