xref: /minix3/external/bsd/tmux/dist/cmd-string.c (revision eda6f5931d42c77e1480347b1fc3eef2f8d33806)
1*eda6f593SDavid van Moolenbroek /* $Id: cmd-string.c,v 1.4 2011/10/07 10:38:02 joerg Exp $ */
2*eda6f593SDavid van Moolenbroek 
3*eda6f593SDavid van Moolenbroek /*
4*eda6f593SDavid van Moolenbroek  * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
5*eda6f593SDavid van Moolenbroek  *
6*eda6f593SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
7*eda6f593SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
8*eda6f593SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
9*eda6f593SDavid van Moolenbroek  *
10*eda6f593SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*eda6f593SDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*eda6f593SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*eda6f593SDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*eda6f593SDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15*eda6f593SDavid van Moolenbroek  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16*eda6f593SDavid van Moolenbroek  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*eda6f593SDavid van Moolenbroek  */
18*eda6f593SDavid van Moolenbroek 
19*eda6f593SDavid van Moolenbroek #include <sys/types.h>
20*eda6f593SDavid van Moolenbroek 
21*eda6f593SDavid van Moolenbroek #include <errno.h>
22*eda6f593SDavid van Moolenbroek #include <pwd.h>
23*eda6f593SDavid van Moolenbroek #include <stdio.h>
24*eda6f593SDavid van Moolenbroek #include <string.h>
25*eda6f593SDavid van Moolenbroek #include <stdlib.h>
26*eda6f593SDavid van Moolenbroek #include <unistd.h>
27*eda6f593SDavid van Moolenbroek 
28*eda6f593SDavid van Moolenbroek #include "tmux.h"
29*eda6f593SDavid van Moolenbroek 
30*eda6f593SDavid van Moolenbroek /*
31*eda6f593SDavid van Moolenbroek  * Parse a command from a string.
32*eda6f593SDavid van Moolenbroek  */
33*eda6f593SDavid van Moolenbroek 
34*eda6f593SDavid van Moolenbroek int	cmd_string_getc(const char *, size_t *);
35*eda6f593SDavid van Moolenbroek void	cmd_string_ungetc(size_t *);
36*eda6f593SDavid van Moolenbroek char   *cmd_string_string(const char *, size_t *, char, int);
37*eda6f593SDavid van Moolenbroek char   *cmd_string_variable(const char *, size_t *);
38*eda6f593SDavid van Moolenbroek char   *cmd_string_expand_tilde(const char *, size_t *);
39*eda6f593SDavid van Moolenbroek 
40*eda6f593SDavid van Moolenbroek int
41*eda6f593SDavid van Moolenbroek cmd_string_getc(const char *s, size_t *p)
42*eda6f593SDavid van Moolenbroek {
43*eda6f593SDavid van Moolenbroek 	const char	*ucs = s;
44*eda6f593SDavid van Moolenbroek 
45*eda6f593SDavid van Moolenbroek 	if (ucs[*p] == '\0')
46*eda6f593SDavid van Moolenbroek 		return (EOF);
47*eda6f593SDavid van Moolenbroek 	return (u_char)(ucs[(*p)++]);
48*eda6f593SDavid van Moolenbroek }
49*eda6f593SDavid van Moolenbroek 
50*eda6f593SDavid van Moolenbroek void
51*eda6f593SDavid van Moolenbroek cmd_string_ungetc(size_t *p)
52*eda6f593SDavid van Moolenbroek {
53*eda6f593SDavid van Moolenbroek 	(*p)--;
54*eda6f593SDavid van Moolenbroek }
55*eda6f593SDavid van Moolenbroek 
56*eda6f593SDavid van Moolenbroek /*
57*eda6f593SDavid van Moolenbroek  * Parse command string. Returns -1 on error. If returning -1, cause is error
58*eda6f593SDavid van Moolenbroek  * string, or NULL for empty command.
59*eda6f593SDavid van Moolenbroek  */
60*eda6f593SDavid van Moolenbroek int
61*eda6f593SDavid van Moolenbroek cmd_string_parse(const char *s, struct cmd_list **cmdlist, char **cause)
62*eda6f593SDavid van Moolenbroek {
63*eda6f593SDavid van Moolenbroek 	size_t		p;
64*eda6f593SDavid van Moolenbroek 	int		ch, i, argc, rval;
65*eda6f593SDavid van Moolenbroek 	char	      **argv, *buf, *t;
66*eda6f593SDavid van Moolenbroek 	const char     *whitespace, *equals;
67*eda6f593SDavid van Moolenbroek 	size_t		len, len2;
68*eda6f593SDavid van Moolenbroek 
69*eda6f593SDavid van Moolenbroek 	argv = NULL;
70*eda6f593SDavid van Moolenbroek 	argc = 0;
71*eda6f593SDavid van Moolenbroek 
72*eda6f593SDavid van Moolenbroek 	buf = NULL;
73*eda6f593SDavid van Moolenbroek 	len = 0;
74*eda6f593SDavid van Moolenbroek 
75*eda6f593SDavid van Moolenbroek 	*cause = NULL;
76*eda6f593SDavid van Moolenbroek 
77*eda6f593SDavid van Moolenbroek 	*cmdlist = NULL;
78*eda6f593SDavid van Moolenbroek 	rval = -1;
79*eda6f593SDavid van Moolenbroek 
80*eda6f593SDavid van Moolenbroek 	p = 0;
81*eda6f593SDavid van Moolenbroek 	for (;;) {
82*eda6f593SDavid van Moolenbroek 		ch = cmd_string_getc(s, &p);
83*eda6f593SDavid van Moolenbroek 		switch (ch) {
84*eda6f593SDavid van Moolenbroek 		case '\'':
85*eda6f593SDavid van Moolenbroek 			if ((t = cmd_string_string(s, &p, '\'', 0)) == NULL)
86*eda6f593SDavid van Moolenbroek 				goto error;
87*eda6f593SDavid van Moolenbroek 			len2 = strlen(t);
88*eda6f593SDavid van Moolenbroek 			buf = xrealloc(buf, 1, len + len2 + 1);
89*eda6f593SDavid van Moolenbroek 			memcpy(buf + len, t, len2 + 1);
90*eda6f593SDavid van Moolenbroek 			len += len2;
91*eda6f593SDavid van Moolenbroek 			xfree(t);
92*eda6f593SDavid van Moolenbroek 			break;
93*eda6f593SDavid van Moolenbroek 		case '"':
94*eda6f593SDavid van Moolenbroek 			if ((t = cmd_string_string(s, &p, '"', 1)) == NULL)
95*eda6f593SDavid van Moolenbroek 				goto error;
96*eda6f593SDavid van Moolenbroek 			len2 = strlen(t);
97*eda6f593SDavid van Moolenbroek 			buf = xrealloc(buf, 1, len + len2 + 1);
98*eda6f593SDavid van Moolenbroek 			memcpy(buf + len, t, len2 + 1);
99*eda6f593SDavid van Moolenbroek 			len += len2;
100*eda6f593SDavid van Moolenbroek 			xfree(t);
101*eda6f593SDavid van Moolenbroek 			break;
102*eda6f593SDavid van Moolenbroek 		case '$':
103*eda6f593SDavid van Moolenbroek 			if ((t = cmd_string_variable(s, &p)) == NULL)
104*eda6f593SDavid van Moolenbroek 				goto error;
105*eda6f593SDavid van Moolenbroek 			len2 = strlen(t);
106*eda6f593SDavid van Moolenbroek 			buf = xrealloc(buf, 1, len + len2 + 1);
107*eda6f593SDavid van Moolenbroek 			strlcpy(buf + len, t, len2 + 1);
108*eda6f593SDavid van Moolenbroek 			len += len2;
109*eda6f593SDavid van Moolenbroek 			xfree(t);
110*eda6f593SDavid van Moolenbroek 			break;
111*eda6f593SDavid van Moolenbroek 		case '#':
112*eda6f593SDavid van Moolenbroek 			/* Comment: discard rest of line. */
113*eda6f593SDavid van Moolenbroek 			while ((ch = cmd_string_getc(s, &p)) != EOF)
114*eda6f593SDavid van Moolenbroek 				;
115*eda6f593SDavid van Moolenbroek 			/* FALLTHROUGH */
116*eda6f593SDavid van Moolenbroek 		case EOF:
117*eda6f593SDavid van Moolenbroek 		case ' ':
118*eda6f593SDavid van Moolenbroek 		case '\t':
119*eda6f593SDavid van Moolenbroek 			if (buf != NULL) {
120*eda6f593SDavid van Moolenbroek 				buf = xrealloc(buf, 1, len + 1);
121*eda6f593SDavid van Moolenbroek 				buf[len] = '\0';
122*eda6f593SDavid van Moolenbroek 
123*eda6f593SDavid van Moolenbroek 				argv = xrealloc(argv, argc + 1, sizeof *argv);
124*eda6f593SDavid van Moolenbroek 				argv[argc++] = buf;
125*eda6f593SDavid van Moolenbroek 
126*eda6f593SDavid van Moolenbroek 				buf = NULL;
127*eda6f593SDavid van Moolenbroek 				len = 0;
128*eda6f593SDavid van Moolenbroek 			}
129*eda6f593SDavid van Moolenbroek 
130*eda6f593SDavid van Moolenbroek 			if (ch != EOF)
131*eda6f593SDavid van Moolenbroek 				break;
132*eda6f593SDavid van Moolenbroek 
133*eda6f593SDavid van Moolenbroek 			while (argc != 0) {
134*eda6f593SDavid van Moolenbroek 				equals = strchr(argv[0], '=');
135*eda6f593SDavid van Moolenbroek 				whitespace = argv[0] + strcspn(argv[0], " \t");
136*eda6f593SDavid van Moolenbroek 				if (equals == NULL || equals > whitespace)
137*eda6f593SDavid van Moolenbroek 					break;
138*eda6f593SDavid van Moolenbroek 				environ_put(&global_environ, argv[0]);
139*eda6f593SDavid van Moolenbroek 				argc--;
140*eda6f593SDavid van Moolenbroek 				memmove(argv, argv + 1, argc * (sizeof *argv));
141*eda6f593SDavid van Moolenbroek 			}
142*eda6f593SDavid van Moolenbroek 			if (argc == 0)
143*eda6f593SDavid van Moolenbroek 				goto out;
144*eda6f593SDavid van Moolenbroek 
145*eda6f593SDavid van Moolenbroek 			*cmdlist = cmd_list_parse(argc, argv, cause);
146*eda6f593SDavid van Moolenbroek 			if (*cmdlist == NULL)
147*eda6f593SDavid van Moolenbroek 				goto out;
148*eda6f593SDavid van Moolenbroek 
149*eda6f593SDavid van Moolenbroek 			rval = 0;
150*eda6f593SDavid van Moolenbroek 			goto out;
151*eda6f593SDavid van Moolenbroek 		case '~':
152*eda6f593SDavid van Moolenbroek 			if (buf == NULL) {
153*eda6f593SDavid van Moolenbroek 				if ((t = cmd_string_expand_tilde(s, &p)) == NULL)
154*eda6f593SDavid van Moolenbroek 					goto error;
155*eda6f593SDavid van Moolenbroek 				len2 = strlen(t);
156*eda6f593SDavid van Moolenbroek 				buf = xrealloc(buf, 1, len + len2 + 1);
157*eda6f593SDavid van Moolenbroek 				memcpy(buf + len, t, len2 + 1);
158*eda6f593SDavid van Moolenbroek 				len += len2;
159*eda6f593SDavid van Moolenbroek 				xfree(t);
160*eda6f593SDavid van Moolenbroek 				break;
161*eda6f593SDavid van Moolenbroek 			}
162*eda6f593SDavid van Moolenbroek 			/* FALLTHROUGH */
163*eda6f593SDavid van Moolenbroek 		default:
164*eda6f593SDavid van Moolenbroek 			if (len >= SIZE_MAX - 2)
165*eda6f593SDavid van Moolenbroek 				goto error;
166*eda6f593SDavid van Moolenbroek 
167*eda6f593SDavid van Moolenbroek 			buf = xrealloc(buf, 1, len + 1);
168*eda6f593SDavid van Moolenbroek 			buf[len++] = ch;
169*eda6f593SDavid van Moolenbroek 			break;
170*eda6f593SDavid van Moolenbroek 		}
171*eda6f593SDavid van Moolenbroek 	}
172*eda6f593SDavid van Moolenbroek 
173*eda6f593SDavid van Moolenbroek error:
174*eda6f593SDavid van Moolenbroek 	xasprintf(cause, "invalid or unknown command: %s", s);
175*eda6f593SDavid van Moolenbroek 
176*eda6f593SDavid van Moolenbroek out:
177*eda6f593SDavid van Moolenbroek 	if (buf != NULL)
178*eda6f593SDavid van Moolenbroek 		xfree(buf);
179*eda6f593SDavid van Moolenbroek 
180*eda6f593SDavid van Moolenbroek 	if (argv != NULL) {
181*eda6f593SDavid van Moolenbroek 		for (i = 0; i < argc; i++)
182*eda6f593SDavid van Moolenbroek 			xfree(argv[i]);
183*eda6f593SDavid van Moolenbroek 		xfree(argv);
184*eda6f593SDavid van Moolenbroek 	}
185*eda6f593SDavid van Moolenbroek 
186*eda6f593SDavid van Moolenbroek 	return (rval);
187*eda6f593SDavid van Moolenbroek }
188*eda6f593SDavid van Moolenbroek 
189*eda6f593SDavid van Moolenbroek char *
190*eda6f593SDavid van Moolenbroek cmd_string_string(const char *s, size_t *p, char endch, int esc)
191*eda6f593SDavid van Moolenbroek {
192*eda6f593SDavid van Moolenbroek 	int	ch;
193*eda6f593SDavid van Moolenbroek 	char   *buf, *t;
194*eda6f593SDavid van Moolenbroek 	size_t	len, len2;
195*eda6f593SDavid van Moolenbroek 
196*eda6f593SDavid van Moolenbroek 	buf = NULL;
197*eda6f593SDavid van Moolenbroek 	len = 0;
198*eda6f593SDavid van Moolenbroek 
199*eda6f593SDavid van Moolenbroek 	while ((ch = cmd_string_getc(s, p)) != endch) {
200*eda6f593SDavid van Moolenbroek 		switch (ch) {
201*eda6f593SDavid van Moolenbroek 		case EOF:
202*eda6f593SDavid van Moolenbroek 			goto error;
203*eda6f593SDavid van Moolenbroek 		case '\\':
204*eda6f593SDavid van Moolenbroek 			if (!esc)
205*eda6f593SDavid van Moolenbroek 				break;
206*eda6f593SDavid van Moolenbroek 			switch (ch = cmd_string_getc(s, p)) {
207*eda6f593SDavid van Moolenbroek 			case EOF:
208*eda6f593SDavid van Moolenbroek 				goto error;
209*eda6f593SDavid van Moolenbroek 			case 'e':
210*eda6f593SDavid van Moolenbroek 				ch = '\033';
211*eda6f593SDavid van Moolenbroek 				break;
212*eda6f593SDavid van Moolenbroek 			case 'r':
213*eda6f593SDavid van Moolenbroek 				ch = '\r';
214*eda6f593SDavid van Moolenbroek 				break;
215*eda6f593SDavid van Moolenbroek 			case 'n':
216*eda6f593SDavid van Moolenbroek 				ch = '\n';
217*eda6f593SDavid van Moolenbroek 				break;
218*eda6f593SDavid van Moolenbroek 			case 't':
219*eda6f593SDavid van Moolenbroek 				ch = '\t';
220*eda6f593SDavid van Moolenbroek 				break;
221*eda6f593SDavid van Moolenbroek 			}
222*eda6f593SDavid van Moolenbroek 			break;
223*eda6f593SDavid van Moolenbroek 		case '$':
224*eda6f593SDavid van Moolenbroek 			if (!esc)
225*eda6f593SDavid van Moolenbroek 				break;
226*eda6f593SDavid van Moolenbroek 			if ((t = cmd_string_variable(s, p)) == NULL)
227*eda6f593SDavid van Moolenbroek 				goto error;
228*eda6f593SDavid van Moolenbroek 			len2 = strlen(t);
229*eda6f593SDavid van Moolenbroek 			buf = xrealloc(buf, 1, len + len2 + 1);
230*eda6f593SDavid van Moolenbroek 			memcpy(buf + len, t, len2 + 1);
231*eda6f593SDavid van Moolenbroek 			len += len2;
232*eda6f593SDavid van Moolenbroek 			xfree(t);
233*eda6f593SDavid van Moolenbroek 			continue;
234*eda6f593SDavid van Moolenbroek 		}
235*eda6f593SDavid van Moolenbroek 
236*eda6f593SDavid van Moolenbroek 		if (len >= SIZE_MAX - 2)
237*eda6f593SDavid van Moolenbroek 			goto error;
238*eda6f593SDavid van Moolenbroek 		buf = xrealloc(buf, 1, len + 1);
239*eda6f593SDavid van Moolenbroek 		buf[len++] = ch;
240*eda6f593SDavid van Moolenbroek 	}
241*eda6f593SDavid van Moolenbroek 
242*eda6f593SDavid van Moolenbroek 	buf = xrealloc(buf, 1, len + 1);
243*eda6f593SDavid van Moolenbroek 	buf[len] = '\0';
244*eda6f593SDavid van Moolenbroek 	return (buf);
245*eda6f593SDavid van Moolenbroek 
246*eda6f593SDavid van Moolenbroek error:
247*eda6f593SDavid van Moolenbroek 	if (buf != NULL)
248*eda6f593SDavid van Moolenbroek 		xfree(buf);
249*eda6f593SDavid van Moolenbroek 	return (NULL);
250*eda6f593SDavid van Moolenbroek }
251*eda6f593SDavid van Moolenbroek 
252*eda6f593SDavid van Moolenbroek char *
253*eda6f593SDavid van Moolenbroek cmd_string_variable(const char *s, size_t *p)
254*eda6f593SDavid van Moolenbroek {
255*eda6f593SDavid van Moolenbroek 	int			ch, fch;
256*eda6f593SDavid van Moolenbroek 	char		       *buf, *t;
257*eda6f593SDavid van Moolenbroek 	size_t			len;
258*eda6f593SDavid van Moolenbroek 	struct environ_entry   *envent;
259*eda6f593SDavid van Moolenbroek 
260*eda6f593SDavid van Moolenbroek #define cmd_string_first(ch) ((ch) == '_' || \
261*eda6f593SDavid van Moolenbroek 	((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z'))
262*eda6f593SDavid van Moolenbroek #define cmd_string_other(ch) ((ch) == '_' || \
263*eda6f593SDavid van Moolenbroek 	((ch) >= 'a' && (ch) <= 'z') || ((ch) >= 'A' && (ch) <= 'Z') || \
264*eda6f593SDavid van Moolenbroek 	((ch) >= '0' && (ch) <= '9'))
265*eda6f593SDavid van Moolenbroek 
266*eda6f593SDavid van Moolenbroek 	buf = NULL;
267*eda6f593SDavid van Moolenbroek 	len = 0;
268*eda6f593SDavid van Moolenbroek 
269*eda6f593SDavid van Moolenbroek 	fch = EOF;
270*eda6f593SDavid van Moolenbroek 	switch (ch = cmd_string_getc(s, p)) {
271*eda6f593SDavid van Moolenbroek 	case EOF:
272*eda6f593SDavid van Moolenbroek 		goto error;
273*eda6f593SDavid van Moolenbroek 	case '{':
274*eda6f593SDavid van Moolenbroek 		fch = '{';
275*eda6f593SDavid van Moolenbroek 
276*eda6f593SDavid van Moolenbroek 		ch = cmd_string_getc(s, p);
277*eda6f593SDavid van Moolenbroek 		if (!cmd_string_first(ch))
278*eda6f593SDavid van Moolenbroek 			goto error;
279*eda6f593SDavid van Moolenbroek 		/* FALLTHROUGH */
280*eda6f593SDavid van Moolenbroek 	default:
281*eda6f593SDavid van Moolenbroek 		if (!cmd_string_first(ch)) {
282*eda6f593SDavid van Moolenbroek 			xasprintf(&t, "$%c", ch);
283*eda6f593SDavid van Moolenbroek 			return (t);
284*eda6f593SDavid van Moolenbroek 		}
285*eda6f593SDavid van Moolenbroek 
286*eda6f593SDavid van Moolenbroek 		buf = xrealloc(buf, 1, len + 1);
287*eda6f593SDavid van Moolenbroek 		buf[len++] = ch;
288*eda6f593SDavid van Moolenbroek 
289*eda6f593SDavid van Moolenbroek 		for (;;) {
290*eda6f593SDavid van Moolenbroek 			ch = cmd_string_getc(s, p);
291*eda6f593SDavid van Moolenbroek 			if (ch == EOF || !cmd_string_other(ch))
292*eda6f593SDavid van Moolenbroek 				break;
293*eda6f593SDavid van Moolenbroek 			else {
294*eda6f593SDavid van Moolenbroek 				if (len >= SIZE_MAX - 3)
295*eda6f593SDavid van Moolenbroek 					goto error;
296*eda6f593SDavid van Moolenbroek 				buf = xrealloc(buf, 1, len + 1);
297*eda6f593SDavid van Moolenbroek 				buf[len++] = ch;
298*eda6f593SDavid van Moolenbroek 			}
299*eda6f593SDavid van Moolenbroek 		}
300*eda6f593SDavid van Moolenbroek 	}
301*eda6f593SDavid van Moolenbroek 
302*eda6f593SDavid van Moolenbroek 	if (fch == '{' && ch != '}')
303*eda6f593SDavid van Moolenbroek 		goto error;
304*eda6f593SDavid van Moolenbroek 	if (ch != EOF && fch != '{')
305*eda6f593SDavid van Moolenbroek 		cmd_string_ungetc(p); /* ch */
306*eda6f593SDavid van Moolenbroek 
307*eda6f593SDavid van Moolenbroek 	buf = xrealloc(buf, 1, len + 1);
308*eda6f593SDavid van Moolenbroek 	buf[len] = '\0';
309*eda6f593SDavid van Moolenbroek 
310*eda6f593SDavid van Moolenbroek 	envent = environ_find(&global_environ, buf);
311*eda6f593SDavid van Moolenbroek 	xfree(buf);
312*eda6f593SDavid van Moolenbroek 	if (envent == NULL)
313*eda6f593SDavid van Moolenbroek 		return (xstrdup(""));
314*eda6f593SDavid van Moolenbroek 	return (xstrdup(envent->value));
315*eda6f593SDavid van Moolenbroek 
316*eda6f593SDavid van Moolenbroek error:
317*eda6f593SDavid van Moolenbroek 	if (buf != NULL)
318*eda6f593SDavid van Moolenbroek 		xfree(buf);
319*eda6f593SDavid van Moolenbroek 	return (NULL);
320*eda6f593SDavid van Moolenbroek }
321*eda6f593SDavid van Moolenbroek 
322*eda6f593SDavid van Moolenbroek char *
323*eda6f593SDavid van Moolenbroek cmd_string_expand_tilde(const char *s, size_t *p)
324*eda6f593SDavid van Moolenbroek {
325*eda6f593SDavid van Moolenbroek 	struct passwd		*pw;
326*eda6f593SDavid van Moolenbroek 	struct environ_entry	*envent;
327*eda6f593SDavid van Moolenbroek 	char			*home, *path, *username;
328*eda6f593SDavid van Moolenbroek 
329*eda6f593SDavid van Moolenbroek 	home = NULL;
330*eda6f593SDavid van Moolenbroek 	if (cmd_string_getc(s, p) == '/') {
331*eda6f593SDavid van Moolenbroek 		envent = environ_find(&global_environ, "HOME");
332*eda6f593SDavid van Moolenbroek 		if (envent != NULL && *envent->value != '\0')
333*eda6f593SDavid van Moolenbroek 			home = envent->value;
334*eda6f593SDavid van Moolenbroek 		else if ((pw = getpwuid(getuid())) != NULL)
335*eda6f593SDavid van Moolenbroek 			home = pw->pw_dir;
336*eda6f593SDavid van Moolenbroek 	} else {
337*eda6f593SDavid van Moolenbroek 		cmd_string_ungetc(p);
338*eda6f593SDavid van Moolenbroek 		if ((username = cmd_string_string(s, p, '/', 0)) == NULL)
339*eda6f593SDavid van Moolenbroek 			return (NULL);
340*eda6f593SDavid van Moolenbroek 		if ((pw = getpwnam(username)) != NULL)
341*eda6f593SDavid van Moolenbroek 			home = pw->pw_dir;
342*eda6f593SDavid van Moolenbroek 		xfree(username);
343*eda6f593SDavid van Moolenbroek 	}
344*eda6f593SDavid van Moolenbroek 	if (home == NULL)
345*eda6f593SDavid van Moolenbroek 		return (NULL);
346*eda6f593SDavid van Moolenbroek 
347*eda6f593SDavid van Moolenbroek 	xasprintf(&path, "%s/", home);
348*eda6f593SDavid van Moolenbroek 	return (path);
349*eda6f593SDavid van Moolenbroek }
350