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