Annotation of src/usr.bin/tmux/cmd-string.c, Revision 1.2
1.2 ! nicm 1: /* $OpenBSD: cmd-string.c,v 1.1 2009/06/01 22:58:49 nicm Exp $ */
1.1 nicm 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) {
1.2 ! nicm 66: if (putenv(xstrdup(s)) != 0) {
1.1 nicm 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: }