Annotation of src/usr.bin/tmux/cmd-string.c, Revision 1.3
1.3 ! nicm 1: /* $OpenBSD: cmd-string.c,v 1.2 2009/06/05 07:18:37 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);
1.3 ! nicm 117: xfree(t);
1.1 nicm 118:
119: have_arg = 1;
120: break;
121: case '#':
122: /* Comment: discard rest of line. */
123: while ((ch = cmd_string_getc(s, &p)) != EOF)
124: ;
125: /* FALLTHROUGH */
126: case EOF:
127: case ' ':
128: case '\t':
129: if (have_arg) {
130: buf = xrealloc(buf, 1, len + 1);
131: buf[len] = '\0';
132:
133: argv = xrealloc(argv, argc + 1, sizeof *argv);
134: argv[argc++] = buf;
135:
136: buf = NULL;
137: len = 0;
138:
139: have_arg = 0;
140: }
141:
142: if (ch != EOF)
143: break;
144: if (argc == 0)
145: goto out;
146:
147: *cmdlist = cmd_list_parse(argc, argv, cause);
148: if (*cmdlist == NULL)
149: goto out;
150:
151: do
152: xfree(argv[argc - 1]);
153: while (--argc > 0);
154:
155: rval = 0;
156: goto out;
157: default:
158: if (len >= SIZE_MAX - 2)
159: goto error;
160:
161: buf = xrealloc(buf, 1, len + 1);
162: buf[len++] = ch;
163:
164: have_arg = 1;
165: break;
166: }
167: }
168:
169: error:
170: xasprintf(cause, "invalid or unknown command: %s", s);
171:
172: out:
173: if (buf != NULL)
174: xfree(buf);
175:
176: while (--argc >= 0)
177: xfree(argv[argc]);
178: if (argv != NULL)
179: xfree(argv);
180:
181: return (rval);
182: }
183:
184: char *
185: cmd_string_string(const char *s, size_t *p, char endch, int esc)
186: {
187: int ch;
188: char *buf, *t;
189: size_t len;
190:
191: buf = NULL;
192: len = 0;
193:
194: while ((ch = cmd_string_getc(s, p)) != endch) {
195: switch (ch) {
196: case EOF:
197: goto error;
198: case '\\':
199: if (!esc)
200: break;
201: switch (ch = cmd_string_getc(s, p)) {
202: case EOF:
203: goto error;
204: case 'r':
205: ch = '\r';
206: break;
207: case 'n':
208: ch = '\n';
209: break;
210: case 't':
211: ch = '\t';
212: break;
213: }
214: break;
215: case '$':
216: if (!esc)
217: break;
218: if ((t = cmd_string_variable(s, p)) == NULL)
219: goto error;
220: buf = xrealloc(buf, 1, len + strlen(t) + 1);
221: strlcpy(buf + len, t, strlen(t) + 1);
222: len += strlen(t);
1.3 ! nicm 223: xfree(t);
1.1 nicm 224: continue;
225: }
226:
227: if (len >= SIZE_MAX - 2)
228: goto error;
229: buf = xrealloc(buf, 1, len + 1);
230: buf[len++] = ch;
231: }
232:
233: buf = xrealloc(buf, 1, len + 1);
234: buf[len] = '\0';
235: return (buf);
236:
237: error:
238: if (buf != NULL)
239: xfree(buf);
240: return (NULL);
241: }
242:
243: char *
244: cmd_string_variable(const char *s, size_t *p)
245: {
246: int ch, fch;
247: char *buf, *t;
248: size_t len;
249:
250: #define cmd_string_first(ch) ((ch) == '_' || \
251: ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
252: #define cmd_string_other(ch) ((ch) == '_' || \
253: ((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
254: ((ch) >= '0' && (ch) <= '9'))
255:
256: buf = NULL;
257: len = 0;
258:
259: fch = EOF;
260: switch (ch = cmd_string_getc(s, p)) {
261: case EOF:
262: goto error;
263: case '{':
264: fch = '{';
265:
266: ch = cmd_string_getc(s, p);
267: if (!cmd_string_first(ch))
268: goto error;
269: /* FALLTHROUGH */
270: default:
271: if (!cmd_string_first(ch)) {
272: xasprintf(&t, "$%c", ch);
273: return (t);
274: }
275:
276: buf = xrealloc(buf, 1, len + 1);
277: buf[len++] = ch;
278:
279: for (;;) {
280: ch = cmd_string_getc(s, p);
281: if (ch == EOF || !cmd_string_other(ch))
282: break;
283: else {
284: if (len >= SIZE_MAX - 3)
285: goto error;
286: buf = xrealloc(buf, 1, len + 1);
287: buf[len++] = ch;
288: }
289: }
290: }
291:
292: if (fch == '{' && ch != '}')
293: goto error;
294: if (ch != EOF && fch != '{')
295: cmd_string_ungetc(s, p); /* ch */
296:
297: buf = xrealloc(buf, 1, len + 1);
298: buf[len] = '\0';
299:
300: if ((t = getenv(buf)) == NULL) {
301: xfree(buf);
302: return (xstrdup(""));
303: }
304: xfree(buf);
305: return (xstrdup(t));
306:
307: error:
308: if (buf != NULL)
309: xfree(buf);
310: return (NULL);
311: }