xref: /aosp_15_r20/external/mksh/src/misc.c (revision 7c356e860f31eadd15fd599fcfdb9fd21f16a9d4)
1*7c356e86SAndroid Build Coastguard Worker /*	$OpenBSD: misc.c,v 1.41 2015/09/10 22:48:58 nicm Exp $	*/
2*7c356e86SAndroid Build Coastguard Worker /*	$OpenBSD: path.c,v 1.13 2015/09/05 09:47:08 jsg Exp $	*/
3*7c356e86SAndroid Build Coastguard Worker 
4*7c356e86SAndroid Build Coastguard Worker /*-
5*7c356e86SAndroid Build Coastguard Worker  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
6*7c356e86SAndroid Build Coastguard Worker  *		 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
7*7c356e86SAndroid Build Coastguard Worker  *		 2020
8*7c356e86SAndroid Build Coastguard Worker  *	mirabilos <[email protected]>
9*7c356e86SAndroid Build Coastguard Worker  * Copyright (c) 2015
10*7c356e86SAndroid Build Coastguard Worker  *	Daniel Richard G. <[email protected]>
11*7c356e86SAndroid Build Coastguard Worker  *
12*7c356e86SAndroid Build Coastguard Worker  * Provided that these terms and disclaimer and all copyright notices
13*7c356e86SAndroid Build Coastguard Worker  * are retained or reproduced in an accompanying document, permission
14*7c356e86SAndroid Build Coastguard Worker  * is granted to deal in this work without restriction, including un-
15*7c356e86SAndroid Build Coastguard Worker  * limited rights to use, publicly perform, distribute, sell, modify,
16*7c356e86SAndroid Build Coastguard Worker  * merge, give away, or sublicence.
17*7c356e86SAndroid Build Coastguard Worker  *
18*7c356e86SAndroid Build Coastguard Worker  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
19*7c356e86SAndroid Build Coastguard Worker  * the utmost extent permitted by applicable law, neither express nor
20*7c356e86SAndroid Build Coastguard Worker  * implied; without malicious intent or gross negligence. In no event
21*7c356e86SAndroid Build Coastguard Worker  * may a licensor, author or contributor be held liable for indirect,
22*7c356e86SAndroid Build Coastguard Worker  * direct, other damage, loss, or other issues arising in any way out
23*7c356e86SAndroid Build Coastguard Worker  * of dealing in the work, even if advised of the possibility of such
24*7c356e86SAndroid Build Coastguard Worker  * damage or existence of a defect, except proven that it results out
25*7c356e86SAndroid Build Coastguard Worker  * of said person's immediate fault when using the work as intended.
26*7c356e86SAndroid Build Coastguard Worker  */
27*7c356e86SAndroid Build Coastguard Worker 
28*7c356e86SAndroid Build Coastguard Worker #include "sh.h"
29*7c356e86SAndroid Build Coastguard Worker #if !HAVE_GETRUSAGE
30*7c356e86SAndroid Build Coastguard Worker #include <sys/times.h>
31*7c356e86SAndroid Build Coastguard Worker #endif
32*7c356e86SAndroid Build Coastguard Worker #if HAVE_GRP_H
33*7c356e86SAndroid Build Coastguard Worker #include <grp.h>
34*7c356e86SAndroid Build Coastguard Worker #endif
35*7c356e86SAndroid Build Coastguard Worker 
36*7c356e86SAndroid Build Coastguard Worker __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.302 2020/08/27 19:52:45 tg Exp $");
37*7c356e86SAndroid Build Coastguard Worker 
38*7c356e86SAndroid Build Coastguard Worker #define KSH_CHVT_FLAG
39*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_SMALL
40*7c356e86SAndroid Build Coastguard Worker #undef KSH_CHVT_FLAG
41*7c356e86SAndroid Build Coastguard Worker #endif
42*7c356e86SAndroid Build Coastguard Worker #ifdef TIOCSCTTY
43*7c356e86SAndroid Build Coastguard Worker #define KSH_CHVT_CODE
44*7c356e86SAndroid Build Coastguard Worker #define KSH_CHVT_FLAG
45*7c356e86SAndroid Build Coastguard Worker #endif
46*7c356e86SAndroid Build Coastguard Worker 
47*7c356e86SAndroid Build Coastguard Worker /* type bits for unsigned char */
48*7c356e86SAndroid Build Coastguard Worker unsigned char chtypes[UCHAR_MAX + 1];
49*7c356e86SAndroid Build Coastguard Worker 
50*7c356e86SAndroid Build Coastguard Worker static const unsigned char *pat_scan(const unsigned char *,
51*7c356e86SAndroid Build Coastguard Worker     const unsigned char *, bool) MKSH_A_PURE;
52*7c356e86SAndroid Build Coastguard Worker static int do_gmatch(const unsigned char *, const unsigned char *,
53*7c356e86SAndroid Build Coastguard Worker     const unsigned char *, const unsigned char *,
54*7c356e86SAndroid Build Coastguard Worker     const unsigned char *) MKSH_A_PURE;
55*7c356e86SAndroid Build Coastguard Worker static const unsigned char *gmatch_cclass(const unsigned char *, unsigned char)
56*7c356e86SAndroid Build Coastguard Worker     MKSH_A_PURE;
57*7c356e86SAndroid Build Coastguard Worker #ifdef KSH_CHVT_CODE
58*7c356e86SAndroid Build Coastguard Worker static void chvt(const Getopt *);
59*7c356e86SAndroid Build Coastguard Worker #endif
60*7c356e86SAndroid Build Coastguard Worker 
61*7c356e86SAndroid Build Coastguard Worker /*XXX this should go away */
62*7c356e86SAndroid Build Coastguard Worker static int make_path(const char *, const char *, char **, XString *, int *);
63*7c356e86SAndroid Build Coastguard Worker 
64*7c356e86SAndroid Build Coastguard Worker #ifdef SETUID_CAN_FAIL_WITH_EAGAIN
65*7c356e86SAndroid Build Coastguard Worker /* we don't need to check for other codes, EPERM won't happen */
66*7c356e86SAndroid Build Coastguard Worker #define DO_SETUID(func,argvec) do {					\
67*7c356e86SAndroid Build Coastguard Worker 	if ((func argvec) && errno == EAGAIN)				\
68*7c356e86SAndroid Build Coastguard Worker 		errorf("%s failed with EAGAIN, probably due to a"	\
69*7c356e86SAndroid Build Coastguard Worker 		    " too low process limit; aborting", #func);		\
70*7c356e86SAndroid Build Coastguard Worker } while (/* CONSTCOND */ 0)
71*7c356e86SAndroid Build Coastguard Worker #else
72*7c356e86SAndroid Build Coastguard Worker #define DO_SETUID(func,argvec) func argvec
73*7c356e86SAndroid Build Coastguard Worker #endif
74*7c356e86SAndroid Build Coastguard Worker 
75*7c356e86SAndroid Build Coastguard Worker 
76*7c356e86SAndroid Build Coastguard Worker /* called from XcheckN() to grow buffer */
77*7c356e86SAndroid Build Coastguard Worker char *
Xcheck_grow(XString * xsp,const char * xp,size_t more)78*7c356e86SAndroid Build Coastguard Worker Xcheck_grow(XString *xsp, const char *xp, size_t more)
79*7c356e86SAndroid Build Coastguard Worker {
80*7c356e86SAndroid Build Coastguard Worker 	const char *old_beg = xsp->beg;
81*7c356e86SAndroid Build Coastguard Worker 
82*7c356e86SAndroid Build Coastguard Worker 	if (more < xsp->len)
83*7c356e86SAndroid Build Coastguard Worker 		more = xsp->len;
84*7c356e86SAndroid Build Coastguard Worker 	/* (xsp->len + X_EXTRA) never overflows */
85*7c356e86SAndroid Build Coastguard Worker 	checkoktoadd(more, xsp->len + X_EXTRA);
86*7c356e86SAndroid Build Coastguard Worker 	xsp->beg = aresize(xsp->beg, (xsp->len += more) + X_EXTRA, xsp->areap);
87*7c356e86SAndroid Build Coastguard Worker 	xsp->end = xsp->beg + xsp->len;
88*7c356e86SAndroid Build Coastguard Worker 	return (xsp->beg + (xp - old_beg));
89*7c356e86SAndroid Build Coastguard Worker }
90*7c356e86SAndroid Build Coastguard Worker 
91*7c356e86SAndroid Build Coastguard Worker 
92*7c356e86SAndroid Build Coastguard Worker #define SHFLAGS_DEFNS
93*7c356e86SAndroid Build Coastguard Worker #define FN(sname,cname,flags,ochar)		\
94*7c356e86SAndroid Build Coastguard Worker 	static const struct {			\
95*7c356e86SAndroid Build Coastguard Worker 		/* character flag (if any) */	\
96*7c356e86SAndroid Build Coastguard Worker 		char c;				\
97*7c356e86SAndroid Build Coastguard Worker 		/* OF_* */			\
98*7c356e86SAndroid Build Coastguard Worker 		unsigned char optflags;		\
99*7c356e86SAndroid Build Coastguard Worker 		/* long name of option */	\
100*7c356e86SAndroid Build Coastguard Worker 		char name[sizeof(sname)];	\
101*7c356e86SAndroid Build Coastguard Worker 	} shoptione_ ## cname = {		\
102*7c356e86SAndroid Build Coastguard Worker 		ochar, flags, sname		\
103*7c356e86SAndroid Build Coastguard Worker 	};
104*7c356e86SAndroid Build Coastguard Worker #include "sh_flags.gen"
105*7c356e86SAndroid Build Coastguard Worker 
106*7c356e86SAndroid Build Coastguard Worker #define OFC(i) (options[i][-2])
107*7c356e86SAndroid Build Coastguard Worker #define OFF(i) (((const unsigned char *)options[i])[-1])
108*7c356e86SAndroid Build Coastguard Worker #define OFN(i) (options[i])
109*7c356e86SAndroid Build Coastguard Worker 
110*7c356e86SAndroid Build Coastguard Worker const char * const options[] = {
111*7c356e86SAndroid Build Coastguard Worker #define SHFLAGS_ITEMS
112*7c356e86SAndroid Build Coastguard Worker #include "sh_flags.gen"
113*7c356e86SAndroid Build Coastguard Worker };
114*7c356e86SAndroid Build Coastguard Worker 
115*7c356e86SAndroid Build Coastguard Worker /*
116*7c356e86SAndroid Build Coastguard Worker  * translate -o option into F* constant (also used for test -o option)
117*7c356e86SAndroid Build Coastguard Worker  */
118*7c356e86SAndroid Build Coastguard Worker size_t
option(const char * n)119*7c356e86SAndroid Build Coastguard Worker option(const char *n)
120*7c356e86SAndroid Build Coastguard Worker {
121*7c356e86SAndroid Build Coastguard Worker 	size_t i = 0;
122*7c356e86SAndroid Build Coastguard Worker 
123*7c356e86SAndroid Build Coastguard Worker 	if (ctype(n[0], C_MINUS | C_PLUS) && n[1] && !n[2])
124*7c356e86SAndroid Build Coastguard Worker 		while (i < NELEM(options)) {
125*7c356e86SAndroid Build Coastguard Worker 			if (OFC(i) == n[1])
126*7c356e86SAndroid Build Coastguard Worker 				return (i);
127*7c356e86SAndroid Build Coastguard Worker 			++i;
128*7c356e86SAndroid Build Coastguard Worker 		}
129*7c356e86SAndroid Build Coastguard Worker 	else
130*7c356e86SAndroid Build Coastguard Worker 		while (i < NELEM(options)) {
131*7c356e86SAndroid Build Coastguard Worker 			if (!strcmp(OFN(i), n))
132*7c356e86SAndroid Build Coastguard Worker 				return (i);
133*7c356e86SAndroid Build Coastguard Worker 			++i;
134*7c356e86SAndroid Build Coastguard Worker 		}
135*7c356e86SAndroid Build Coastguard Worker 
136*7c356e86SAndroid Build Coastguard Worker 	return ((size_t)-1);
137*7c356e86SAndroid Build Coastguard Worker }
138*7c356e86SAndroid Build Coastguard Worker 
139*7c356e86SAndroid Build Coastguard Worker struct options_info {
140*7c356e86SAndroid Build Coastguard Worker 	int opt_width;
141*7c356e86SAndroid Build Coastguard Worker 	int opts[NELEM(options)];
142*7c356e86SAndroid Build Coastguard Worker };
143*7c356e86SAndroid Build Coastguard Worker 
144*7c356e86SAndroid Build Coastguard Worker static void options_fmt_entry(char *, size_t, unsigned int, const void *);
145*7c356e86SAndroid Build Coastguard Worker static int printoptions(bool);
146*7c356e86SAndroid Build Coastguard Worker static int printoption(size_t);
147*7c356e86SAndroid Build Coastguard Worker 
148*7c356e86SAndroid Build Coastguard Worker /* format a single select menu item */
149*7c356e86SAndroid Build Coastguard Worker static void
options_fmt_entry(char * buf,size_t buflen,unsigned int i,const void * arg)150*7c356e86SAndroid Build Coastguard Worker options_fmt_entry(char *buf, size_t buflen, unsigned int i, const void *arg)
151*7c356e86SAndroid Build Coastguard Worker {
152*7c356e86SAndroid Build Coastguard Worker 	const struct options_info *oi = (const struct options_info *)arg;
153*7c356e86SAndroid Build Coastguard Worker 
154*7c356e86SAndroid Build Coastguard Worker 	shf_snprintf(buf, buflen, "%-*s %s",
155*7c356e86SAndroid Build Coastguard Worker 	    oi->opt_width, OFN(oi->opts[i]),
156*7c356e86SAndroid Build Coastguard Worker 	    Flag(oi->opts[i]) ? "on" : "off");
157*7c356e86SAndroid Build Coastguard Worker }
158*7c356e86SAndroid Build Coastguard Worker 
159*7c356e86SAndroid Build Coastguard Worker static int
printoption(size_t i)160*7c356e86SAndroid Build Coastguard Worker printoption(size_t i)
161*7c356e86SAndroid Build Coastguard Worker {
162*7c356e86SAndroid Build Coastguard Worker 	if (Flag(i) == baseline_flags[i])
163*7c356e86SAndroid Build Coastguard Worker 		return (0);
164*7c356e86SAndroid Build Coastguard Worker 	if (!OFN(i)[0]) {
165*7c356e86SAndroid Build Coastguard Worker #if !defined(MKSH_SMALL) || defined(DEBUG)
166*7c356e86SAndroid Build Coastguard Worker 		bi_errorf(Tf_sd, "change in unnamed option", (int)i);
167*7c356e86SAndroid Build Coastguard Worker #endif
168*7c356e86SAndroid Build Coastguard Worker 		return (1);
169*7c356e86SAndroid Build Coastguard Worker 	}
170*7c356e86SAndroid Build Coastguard Worker 	if (Flag(i) != 0 && Flag(i) != 1) {
171*7c356e86SAndroid Build Coastguard Worker #if !defined(MKSH_SMALL) || defined(DEBUG)
172*7c356e86SAndroid Build Coastguard Worker 		bi_errorf(Tf_s_sD_s, Tdo, OFN(i), "not 0 or 1");
173*7c356e86SAndroid Build Coastguard Worker #endif
174*7c356e86SAndroid Build Coastguard Worker 		return (1);
175*7c356e86SAndroid Build Coastguard Worker 	}
176*7c356e86SAndroid Build Coastguard Worker 	shprintf(Tf__s_s, Flag(i) ? Tdo : Tpo, OFN(i));
177*7c356e86SAndroid Build Coastguard Worker 	return (0);
178*7c356e86SAndroid Build Coastguard Worker }
179*7c356e86SAndroid Build Coastguard Worker 
180*7c356e86SAndroid Build Coastguard Worker static int
printoptions(bool verbose)181*7c356e86SAndroid Build Coastguard Worker printoptions(bool verbose)
182*7c356e86SAndroid Build Coastguard Worker {
183*7c356e86SAndroid Build Coastguard Worker 	size_t i = 0;
184*7c356e86SAndroid Build Coastguard Worker 	int rv = 0;
185*7c356e86SAndroid Build Coastguard Worker 
186*7c356e86SAndroid Build Coastguard Worker 	if (verbose) {
187*7c356e86SAndroid Build Coastguard Worker 		size_t n = 0, len, octs = 0;
188*7c356e86SAndroid Build Coastguard Worker 		struct options_info oi;
189*7c356e86SAndroid Build Coastguard Worker 		struct columnise_opts co;
190*7c356e86SAndroid Build Coastguard Worker 
191*7c356e86SAndroid Build Coastguard Worker 		/* verbose version */
192*7c356e86SAndroid Build Coastguard Worker 		shf_puts("Current option settings\n", shl_stdout);
193*7c356e86SAndroid Build Coastguard Worker 
194*7c356e86SAndroid Build Coastguard Worker 		oi.opt_width = 0;
195*7c356e86SAndroid Build Coastguard Worker 		while (i < NELEM(options)) {
196*7c356e86SAndroid Build Coastguard Worker 			if ((len = strlen(OFN(i)))) {
197*7c356e86SAndroid Build Coastguard Worker 				oi.opts[n++] = i;
198*7c356e86SAndroid Build Coastguard Worker 				if (len > octs)
199*7c356e86SAndroid Build Coastguard Worker 					octs = len;
200*7c356e86SAndroid Build Coastguard Worker 				len = utf_mbswidth(OFN(i));
201*7c356e86SAndroid Build Coastguard Worker 				if ((int)len > oi.opt_width)
202*7c356e86SAndroid Build Coastguard Worker 					oi.opt_width = (int)len;
203*7c356e86SAndroid Build Coastguard Worker 			}
204*7c356e86SAndroid Build Coastguard Worker 			++i;
205*7c356e86SAndroid Build Coastguard Worker 		}
206*7c356e86SAndroid Build Coastguard Worker 		co.shf = shl_stdout;
207*7c356e86SAndroid Build Coastguard Worker 		co.linesep = '\n';
208*7c356e86SAndroid Build Coastguard Worker 		co.prefcol = co.do_last = true;
209*7c356e86SAndroid Build Coastguard Worker 		print_columns(&co, n, options_fmt_entry, &oi,
210*7c356e86SAndroid Build Coastguard Worker 		    octs + 4, oi.opt_width + 4);
211*7c356e86SAndroid Build Coastguard Worker 	} else {
212*7c356e86SAndroid Build Coastguard Worker 		/* short version like AT&T ksh93 */
213*7c356e86SAndroid Build Coastguard Worker 		shf_puts(Tset, shl_stdout);
214*7c356e86SAndroid Build Coastguard Worker 		shf_puts(To_o_reset, shl_stdout);
215*7c356e86SAndroid Build Coastguard Worker 		printoption(FSH);
216*7c356e86SAndroid Build Coastguard Worker 		printoption(FPOSIX);
217*7c356e86SAndroid Build Coastguard Worker 		while (i < FNFLAGS) {
218*7c356e86SAndroid Build Coastguard Worker 			if (i != FSH && i != FPOSIX)
219*7c356e86SAndroid Build Coastguard Worker 				rv |= printoption(i);
220*7c356e86SAndroid Build Coastguard Worker 			++i;
221*7c356e86SAndroid Build Coastguard Worker 		}
222*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\n', shl_stdout);
223*7c356e86SAndroid Build Coastguard Worker 	}
224*7c356e86SAndroid Build Coastguard Worker 	return (rv);
225*7c356e86SAndroid Build Coastguard Worker }
226*7c356e86SAndroid Build Coastguard Worker 
227*7c356e86SAndroid Build Coastguard Worker char *
getoptions(void)228*7c356e86SAndroid Build Coastguard Worker getoptions(void)
229*7c356e86SAndroid Build Coastguard Worker {
230*7c356e86SAndroid Build Coastguard Worker 	size_t i = 0;
231*7c356e86SAndroid Build Coastguard Worker 	char c, m[(int)FNFLAGS + 1];
232*7c356e86SAndroid Build Coastguard Worker 	char *cp = m;
233*7c356e86SAndroid Build Coastguard Worker 
234*7c356e86SAndroid Build Coastguard Worker 	while (i < NELEM(options)) {
235*7c356e86SAndroid Build Coastguard Worker 		if ((c = OFC(i)) && Flag(i))
236*7c356e86SAndroid Build Coastguard Worker 			*cp++ = c;
237*7c356e86SAndroid Build Coastguard Worker 		++i;
238*7c356e86SAndroid Build Coastguard Worker 	}
239*7c356e86SAndroid Build Coastguard Worker 	strndupx(cp, m, cp - m, ATEMP);
240*7c356e86SAndroid Build Coastguard Worker 	return (cp);
241*7c356e86SAndroid Build Coastguard Worker }
242*7c356e86SAndroid Build Coastguard Worker 
243*7c356e86SAndroid Build Coastguard Worker /* change a Flag(*) value; takes care of special actions */
244*7c356e86SAndroid Build Coastguard Worker void
change_flag(enum sh_flag f,int what,bool newset)245*7c356e86SAndroid Build Coastguard Worker change_flag(enum sh_flag f, int what, bool newset)
246*7c356e86SAndroid Build Coastguard Worker {
247*7c356e86SAndroid Build Coastguard Worker 	unsigned char oldval = Flag(f);
248*7c356e86SAndroid Build Coastguard Worker 	unsigned char newval = (newset ? 1 : 0);
249*7c356e86SAndroid Build Coastguard Worker 
250*7c356e86SAndroid Build Coastguard Worker 	if (f == FXTRACE) {
251*7c356e86SAndroid Build Coastguard Worker 		change_xtrace(newval, true);
252*7c356e86SAndroid Build Coastguard Worker 		return;
253*7c356e86SAndroid Build Coastguard Worker 	} else if (f == FPRIVILEGED) {
254*7c356e86SAndroid Build Coastguard Worker 		if (!oldval)
255*7c356e86SAndroid Build Coastguard Worker 			/* no getting back dropped privs */
256*7c356e86SAndroid Build Coastguard Worker 			return;
257*7c356e86SAndroid Build Coastguard Worker 		else if (!newval) {
258*7c356e86SAndroid Build Coastguard Worker 			/* turning off -p */
259*7c356e86SAndroid Build Coastguard Worker 			kshegid = kshgid;
260*7c356e86SAndroid Build Coastguard Worker 			ksheuid = kshuid;
261*7c356e86SAndroid Build Coastguard Worker 		} else if (oldval != 3)
262*7c356e86SAndroid Build Coastguard Worker 			/* nor going full sugid */
263*7c356e86SAndroid Build Coastguard Worker 			goto change_flag;
264*7c356e86SAndroid Build Coastguard Worker 
265*7c356e86SAndroid Build Coastguard Worker 		/* +++ set group IDs +++ */
266*7c356e86SAndroid Build Coastguard Worker #if HAVE_SETRESUGID
267*7c356e86SAndroid Build Coastguard Worker 		DO_SETUID(setresgid, (kshegid, kshegid, kshgid));
268*7c356e86SAndroid Build Coastguard Worker #else /* !HAVE_SETRESUGID */
269*7c356e86SAndroid Build Coastguard Worker 		/* setgid, setegid don't EAGAIN on Linux */
270*7c356e86SAndroid Build Coastguard Worker 		setgid(kshegid);
271*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH__NO_SETEUGID
272*7c356e86SAndroid Build Coastguard Worker 		setegid(kshegid);
273*7c356e86SAndroid Build Coastguard Worker #endif /* !MKSH__NO_SETEUGID */
274*7c356e86SAndroid Build Coastguard Worker #endif /* !HAVE_SETRESUGID */
275*7c356e86SAndroid Build Coastguard Worker 
276*7c356e86SAndroid Build Coastguard Worker 		/* +++ wipe groups vector +++ */
277*7c356e86SAndroid Build Coastguard Worker #if HAVE_SETGROUPS
278*7c356e86SAndroid Build Coastguard Worker 		/* setgroups doesn't EAGAIN on Linux */
279*7c356e86SAndroid Build Coastguard Worker 		setgroups(0, NULL);
280*7c356e86SAndroid Build Coastguard Worker #endif /* HAVE_SETGROUPS */
281*7c356e86SAndroid Build Coastguard Worker 
282*7c356e86SAndroid Build Coastguard Worker 		/* +++ set user IDs +++ */
283*7c356e86SAndroid Build Coastguard Worker #if HAVE_SETRESUGID
284*7c356e86SAndroid Build Coastguard Worker 		DO_SETUID(setresuid, (ksheuid, ksheuid, kshuid));
285*7c356e86SAndroid Build Coastguard Worker #else /* !HAVE_SETRESUGID */
286*7c356e86SAndroid Build Coastguard Worker 		/* seteuid doesn't EAGAIN on Linux */
287*7c356e86SAndroid Build Coastguard Worker 		DO_SETUID(setuid, (ksheuid));
288*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH__NO_SETEUGID
289*7c356e86SAndroid Build Coastguard Worker 		seteuid(ksheuid);
290*7c356e86SAndroid Build Coastguard Worker #endif /* !MKSH__NO_SETEUGID */
291*7c356e86SAndroid Build Coastguard Worker #endif /* !HAVE_SETRESUGID */
292*7c356e86SAndroid Build Coastguard Worker 
293*7c356e86SAndroid Build Coastguard Worker 		/* +++ privs changed +++ */
294*7c356e86SAndroid Build Coastguard Worker 	} else if ((f == FPOSIX || f == FSH) && newval) {
295*7c356e86SAndroid Build Coastguard Worker 		/* Turning on -o posix? */
296*7c356e86SAndroid Build Coastguard Worker 		if (f == FPOSIX)
297*7c356e86SAndroid Build Coastguard Worker 			/* C locale required for compliance */
298*7c356e86SAndroid Build Coastguard Worker 			UTFMODE = 0;
299*7c356e86SAndroid Build Coastguard Worker 		/* Turning on -o posix or -o sh? */
300*7c356e86SAndroid Build Coastguard Worker 		Flag(FBRACEEXPAND) = 0;
301*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH_NO_CMDLINE_EDITING
302*7c356e86SAndroid Build Coastguard Worker 	} else if ((f == FEMACS ||
303*7c356e86SAndroid Build Coastguard Worker #if !MKSH_S_NOVI
304*7c356e86SAndroid Build Coastguard Worker 	    f == FVI ||
305*7c356e86SAndroid Build Coastguard Worker #endif
306*7c356e86SAndroid Build Coastguard Worker 	    f == FGMACS) && newval) {
307*7c356e86SAndroid Build Coastguard Worker #if !MKSH_S_NOVI
308*7c356e86SAndroid Build Coastguard Worker 		Flag(FVI) = 0;
309*7c356e86SAndroid Build Coastguard Worker #endif
310*7c356e86SAndroid Build Coastguard Worker 		Flag(FEMACS) = Flag(FGMACS) = 0;
311*7c356e86SAndroid Build Coastguard Worker #endif
312*7c356e86SAndroid Build Coastguard Worker 	}
313*7c356e86SAndroid Build Coastguard Worker 
314*7c356e86SAndroid Build Coastguard Worker  change_flag:
315*7c356e86SAndroid Build Coastguard Worker 	Flag(f) = newval;
316*7c356e86SAndroid Build Coastguard Worker 
317*7c356e86SAndroid Build Coastguard Worker 	if (f == FTALKING) {
318*7c356e86SAndroid Build Coastguard Worker 		/* Changing interactive flag? */
319*7c356e86SAndroid Build Coastguard Worker 		if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
320*7c356e86SAndroid Build Coastguard Worker 			Flag(FTALKING_I) = newval;
321*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH_UNEMPLOYED
322*7c356e86SAndroid Build Coastguard Worker 	} else if (f == FMONITOR) {
323*7c356e86SAndroid Build Coastguard Worker 		if (what != OF_CMDLINE && newval != oldval)
324*7c356e86SAndroid Build Coastguard Worker 			j_change();
325*7c356e86SAndroid Build Coastguard Worker #endif
326*7c356e86SAndroid Build Coastguard Worker 	}
327*7c356e86SAndroid Build Coastguard Worker }
328*7c356e86SAndroid Build Coastguard Worker 
329*7c356e86SAndroid Build Coastguard Worker void
change_xtrace(unsigned char newval,bool dosnapshot)330*7c356e86SAndroid Build Coastguard Worker change_xtrace(unsigned char newval, bool dosnapshot)
331*7c356e86SAndroid Build Coastguard Worker {
332*7c356e86SAndroid Build Coastguard Worker 	static bool in_xtrace;
333*7c356e86SAndroid Build Coastguard Worker 
334*7c356e86SAndroid Build Coastguard Worker 	if (in_xtrace)
335*7c356e86SAndroid Build Coastguard Worker 		return;
336*7c356e86SAndroid Build Coastguard Worker 
337*7c356e86SAndroid Build Coastguard Worker 	if (!dosnapshot && newval == Flag(FXTRACE))
338*7c356e86SAndroid Build Coastguard Worker 		return;
339*7c356e86SAndroid Build Coastguard Worker 
340*7c356e86SAndroid Build Coastguard Worker 	if (Flag(FXTRACE) == 2) {
341*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\n', shl_xtrace);
342*7c356e86SAndroid Build Coastguard Worker 		Flag(FXTRACE) = 1;
343*7c356e86SAndroid Build Coastguard Worker 		shf_flush(shl_xtrace);
344*7c356e86SAndroid Build Coastguard Worker 	}
345*7c356e86SAndroid Build Coastguard Worker 
346*7c356e86SAndroid Build Coastguard Worker 	if (!dosnapshot && Flag(FXTRACE) == 1)
347*7c356e86SAndroid Build Coastguard Worker 		switch (newval) {
348*7c356e86SAndroid Build Coastguard Worker 		case 1:
349*7c356e86SAndroid Build Coastguard Worker 			return;
350*7c356e86SAndroid Build Coastguard Worker 		case 2:
351*7c356e86SAndroid Build Coastguard Worker 			goto changed_xtrace;
352*7c356e86SAndroid Build Coastguard Worker 		}
353*7c356e86SAndroid Build Coastguard Worker 
354*7c356e86SAndroid Build Coastguard Worker 	shf_flush(shl_xtrace);
355*7c356e86SAndroid Build Coastguard Worker 	if (shl_xtrace->fd != 2)
356*7c356e86SAndroid Build Coastguard Worker 		close(shl_xtrace->fd);
357*7c356e86SAndroid Build Coastguard Worker 	if (!newval || (shl_xtrace->fd = savefd(2)) == -1)
358*7c356e86SAndroid Build Coastguard Worker 		shl_xtrace->fd = 2;
359*7c356e86SAndroid Build Coastguard Worker 
360*7c356e86SAndroid Build Coastguard Worker  changed_xtrace:
361*7c356e86SAndroid Build Coastguard Worker 	if ((Flag(FXTRACE) = newval) == 2) {
362*7c356e86SAndroid Build Coastguard Worker 		in_xtrace = true;
363*7c356e86SAndroid Build Coastguard Worker 		Flag(FXTRACE) = 0;
364*7c356e86SAndroid Build Coastguard Worker 		shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace);
365*7c356e86SAndroid Build Coastguard Worker 		Flag(FXTRACE) = 2;
366*7c356e86SAndroid Build Coastguard Worker 		in_xtrace = false;
367*7c356e86SAndroid Build Coastguard Worker 	}
368*7c356e86SAndroid Build Coastguard Worker }
369*7c356e86SAndroid Build Coastguard Worker 
370*7c356e86SAndroid Build Coastguard Worker /*
371*7c356e86SAndroid Build Coastguard Worker  * Parse command line and set command arguments. Returns the index of
372*7c356e86SAndroid Build Coastguard Worker  * non-option arguments, -1 if there is an error.
373*7c356e86SAndroid Build Coastguard Worker  */
374*7c356e86SAndroid Build Coastguard Worker int
parse_args(const char ** argv,int what,bool * setargsp)375*7c356e86SAndroid Build Coastguard Worker parse_args(const char **argv,
376*7c356e86SAndroid Build Coastguard Worker     /* OF_FIRSTTIME, OF_CMDLINE, or OF_SET */
377*7c356e86SAndroid Build Coastguard Worker     int what,
378*7c356e86SAndroid Build Coastguard Worker     bool *setargsp)
379*7c356e86SAndroid Build Coastguard Worker {
380*7c356e86SAndroid Build Coastguard Worker 	static const char cmd_opts[] =
381*7c356e86SAndroid Build Coastguard Worker #define SHFLAGS_NOT_SET
382*7c356e86SAndroid Build Coastguard Worker #define SHFLAGS_OPTCS
383*7c356e86SAndroid Build Coastguard Worker #include "sh_flags.gen"
384*7c356e86SAndroid Build Coastguard Worker #undef SHFLAGS_NOT_SET
385*7c356e86SAndroid Build Coastguard Worker 	    ;
386*7c356e86SAndroid Build Coastguard Worker 	static const char set_opts[] =
387*7c356e86SAndroid Build Coastguard Worker #define SHFLAGS_NOT_CMD
388*7c356e86SAndroid Build Coastguard Worker #define SHFLAGS_OPTCS
389*7c356e86SAndroid Build Coastguard Worker #include "sh_flags.gen"
390*7c356e86SAndroid Build Coastguard Worker #undef SHFLAGS_NOT_CMD
391*7c356e86SAndroid Build Coastguard Worker 	    ;
392*7c356e86SAndroid Build Coastguard Worker 	bool set;
393*7c356e86SAndroid Build Coastguard Worker 	const char *opts = what == OF_CMDLINE || what == OF_FIRSTTIME ?
394*7c356e86SAndroid Build Coastguard Worker 	    cmd_opts : set_opts;
395*7c356e86SAndroid Build Coastguard Worker 	const char *array = NULL;
396*7c356e86SAndroid Build Coastguard Worker 	Getopt go;
397*7c356e86SAndroid Build Coastguard Worker 	size_t i;
398*7c356e86SAndroid Build Coastguard Worker 	int optc, arrayset = 0;
399*7c356e86SAndroid Build Coastguard Worker 	bool sortargs = false;
400*7c356e86SAndroid Build Coastguard Worker 	bool fcompatseen = false;
401*7c356e86SAndroid Build Coastguard Worker 
402*7c356e86SAndroid Build Coastguard Worker 	ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT);
403*7c356e86SAndroid Build Coastguard Worker 	while ((optc = ksh_getopt(argv, &go, opts)) != -1) {
404*7c356e86SAndroid Build Coastguard Worker 		set = tobool(!(go.info & GI_PLUS));
405*7c356e86SAndroid Build Coastguard Worker 		switch (optc) {
406*7c356e86SAndroid Build Coastguard Worker 		case 'A':
407*7c356e86SAndroid Build Coastguard Worker 			if (what == OF_FIRSTTIME)
408*7c356e86SAndroid Build Coastguard Worker 				break;
409*7c356e86SAndroid Build Coastguard Worker 			arrayset = set ? 1 : -1;
410*7c356e86SAndroid Build Coastguard Worker 			array = go.optarg;
411*7c356e86SAndroid Build Coastguard Worker 			break;
412*7c356e86SAndroid Build Coastguard Worker 
413*7c356e86SAndroid Build Coastguard Worker 		case 'o':
414*7c356e86SAndroid Build Coastguard Worker 			if (what == OF_FIRSTTIME)
415*7c356e86SAndroid Build Coastguard Worker 				break;
416*7c356e86SAndroid Build Coastguard Worker 			if (go.optarg == NULL) {
417*7c356e86SAndroid Build Coastguard Worker 				/*
418*7c356e86SAndroid Build Coastguard Worker 				 * lone -o: print options
419*7c356e86SAndroid Build Coastguard Worker 				 *
420*7c356e86SAndroid Build Coastguard Worker 				 * Note that on the command line, -o requires
421*7c356e86SAndroid Build Coastguard Worker 				 * an option (ie, can't get here if what is
422*7c356e86SAndroid Build Coastguard Worker 				 * OF_CMDLINE).
423*7c356e86SAndroid Build Coastguard Worker 				 */
424*7c356e86SAndroid Build Coastguard Worker #if !defined(MKSH_SMALL) || defined(DEBUG)
425*7c356e86SAndroid Build Coastguard Worker 				if (!set && !baseline_flags[(int)FNFLAGS]) {
426*7c356e86SAndroid Build Coastguard Worker 					bi_errorf(Tf_s_s, "too early",
427*7c356e86SAndroid Build Coastguard Worker 					    Tset_po);
428*7c356e86SAndroid Build Coastguard Worker 					return (-1);
429*7c356e86SAndroid Build Coastguard Worker 				}
430*7c356e86SAndroid Build Coastguard Worker #endif
431*7c356e86SAndroid Build Coastguard Worker 				if (printoptions(set))
432*7c356e86SAndroid Build Coastguard Worker 					return (-1);
433*7c356e86SAndroid Build Coastguard Worker 				break;
434*7c356e86SAndroid Build Coastguard Worker 			}
435*7c356e86SAndroid Build Coastguard Worker 			i = option(go.optarg);
436*7c356e86SAndroid Build Coastguard Worker 			if ((i == FPOSIX || i == FSH) && set && !fcompatseen) {
437*7c356e86SAndroid Build Coastguard Worker 				/*
438*7c356e86SAndroid Build Coastguard Worker 				 * If running 'set -o posix' or
439*7c356e86SAndroid Build Coastguard Worker 				 * 'set -o sh', turn off the other;
440*7c356e86SAndroid Build Coastguard Worker 				 * if running 'set -o posix -o sh'
441*7c356e86SAndroid Build Coastguard Worker 				 * allow both to be set though.
442*7c356e86SAndroid Build Coastguard Worker 				 */
443*7c356e86SAndroid Build Coastguard Worker 				Flag(FPOSIX) = 0;
444*7c356e86SAndroid Build Coastguard Worker 				Flag(FSH) = 0;
445*7c356e86SAndroid Build Coastguard Worker 				fcompatseen = true;
446*7c356e86SAndroid Build Coastguard Worker 			}
447*7c356e86SAndroid Build Coastguard Worker 			if ((i != (size_t)-1) && (set ? 1U : 0U) == Flag(i))
448*7c356e86SAndroid Build Coastguard Worker 				/*
449*7c356e86SAndroid Build Coastguard Worker 				 * Don't check the context if the flag
450*7c356e86SAndroid Build Coastguard Worker 				 * isn't changing - makes "set -o interactive"
451*7c356e86SAndroid Build Coastguard Worker 				 * work if you're already interactive. Needed
452*7c356e86SAndroid Build Coastguard Worker 				 * if the output of "set +o" is to be used.
453*7c356e86SAndroid Build Coastguard Worker 				 */
454*7c356e86SAndroid Build Coastguard Worker 				;
455*7c356e86SAndroid Build Coastguard Worker 			else if ((i != (size_t)-1) && (OFF(i) & what))
456*7c356e86SAndroid Build Coastguard Worker 				change_flag((enum sh_flag)i, what, set);
457*7c356e86SAndroid Build Coastguard Worker 			else if (!strcmp(go.optarg, To_reset)) {
458*7c356e86SAndroid Build Coastguard Worker #if !defined(MKSH_SMALL) || defined(DEBUG)
459*7c356e86SAndroid Build Coastguard Worker 				if (!baseline_flags[(int)FNFLAGS]) {
460*7c356e86SAndroid Build Coastguard Worker 					bi_errorf(Tf_ss, "too early",
461*7c356e86SAndroid Build Coastguard Worker 					    To_o_reset);
462*7c356e86SAndroid Build Coastguard Worker 					return (-1);
463*7c356e86SAndroid Build Coastguard Worker 				}
464*7c356e86SAndroid Build Coastguard Worker #endif
465*7c356e86SAndroid Build Coastguard Worker 				/*
466*7c356e86SAndroid Build Coastguard Worker 				 * ordering, with respect to side effects,
467*7c356e86SAndroid Build Coastguard Worker 				 * was ensured above by printoptions
468*7c356e86SAndroid Build Coastguard Worker 				 */
469*7c356e86SAndroid Build Coastguard Worker 				for (i = 0; i < FNFLAGS; ++i)
470*7c356e86SAndroid Build Coastguard Worker 					if (Flag(i) != baseline_flags[i])
471*7c356e86SAndroid Build Coastguard Worker 						change_flag((enum sh_flag)i,
472*7c356e86SAndroid Build Coastguard Worker 						    what, baseline_flags[i]);
473*7c356e86SAndroid Build Coastguard Worker 			} else {
474*7c356e86SAndroid Build Coastguard Worker 				bi_errorf(Tf_sD_s, go.optarg,
475*7c356e86SAndroid Build Coastguard Worker 				    Tunknown_option);
476*7c356e86SAndroid Build Coastguard Worker 				return (-1);
477*7c356e86SAndroid Build Coastguard Worker 			}
478*7c356e86SAndroid Build Coastguard Worker 			break;
479*7c356e86SAndroid Build Coastguard Worker 
480*7c356e86SAndroid Build Coastguard Worker #ifdef KSH_CHVT_FLAG
481*7c356e86SAndroid Build Coastguard Worker 		case 'T':
482*7c356e86SAndroid Build Coastguard Worker 			if (what != OF_FIRSTTIME)
483*7c356e86SAndroid Build Coastguard Worker 				break;
484*7c356e86SAndroid Build Coastguard Worker #ifndef KSH_CHVT_CODE
485*7c356e86SAndroid Build Coastguard Worker 			errorf("no TIOCSCTTY ioctl");
486*7c356e86SAndroid Build Coastguard Worker #else
487*7c356e86SAndroid Build Coastguard Worker 			change_flag(FTALKING, OF_CMDLINE, true);
488*7c356e86SAndroid Build Coastguard Worker 			chvt(&go);
489*7c356e86SAndroid Build Coastguard Worker 			break;
490*7c356e86SAndroid Build Coastguard Worker #endif
491*7c356e86SAndroid Build Coastguard Worker #endif
492*7c356e86SAndroid Build Coastguard Worker 
493*7c356e86SAndroid Build Coastguard Worker 		case '?':
494*7c356e86SAndroid Build Coastguard Worker 			return (-1);
495*7c356e86SAndroid Build Coastguard Worker 
496*7c356e86SAndroid Build Coastguard Worker 		default:
497*7c356e86SAndroid Build Coastguard Worker 			if (what == OF_FIRSTTIME)
498*7c356e86SAndroid Build Coastguard Worker 				break;
499*7c356e86SAndroid Build Coastguard Worker 			/* -s: sort positional params (AT&T ksh stupidity) */
500*7c356e86SAndroid Build Coastguard Worker 			if (what == OF_SET && optc == 's') {
501*7c356e86SAndroid Build Coastguard Worker 				sortargs = true;
502*7c356e86SAndroid Build Coastguard Worker 				break;
503*7c356e86SAndroid Build Coastguard Worker 			}
504*7c356e86SAndroid Build Coastguard Worker 			for (i = 0; i < NELEM(options); i++)
505*7c356e86SAndroid Build Coastguard Worker 				if (optc == OFC(i) &&
506*7c356e86SAndroid Build Coastguard Worker 				    (what & OFF(i))) {
507*7c356e86SAndroid Build Coastguard Worker 					change_flag((enum sh_flag)i, what, set);
508*7c356e86SAndroid Build Coastguard Worker 					break;
509*7c356e86SAndroid Build Coastguard Worker 				}
510*7c356e86SAndroid Build Coastguard Worker 			if (i == NELEM(options))
511*7c356e86SAndroid Build Coastguard Worker 				internal_errorf("parse_args: '%c'", optc);
512*7c356e86SAndroid Build Coastguard Worker 		}
513*7c356e86SAndroid Build Coastguard Worker 	}
514*7c356e86SAndroid Build Coastguard Worker 	if (!(go.info & GI_MINUSMINUS) && argv[go.optind] &&
515*7c356e86SAndroid Build Coastguard Worker 	    ctype(argv[go.optind][0], C_MINUS | C_PLUS) &&
516*7c356e86SAndroid Build Coastguard Worker 	    argv[go.optind][1] == '\0') {
517*7c356e86SAndroid Build Coastguard Worker 		/* lone - clears -v and -x flags */
518*7c356e86SAndroid Build Coastguard Worker 		if (argv[go.optind][0] == '-') {
519*7c356e86SAndroid Build Coastguard Worker 			Flag(FVERBOSE) = 0;
520*7c356e86SAndroid Build Coastguard Worker 			change_xtrace(0, false);
521*7c356e86SAndroid Build Coastguard Worker 		}
522*7c356e86SAndroid Build Coastguard Worker 		/* set skips lone - or + option */
523*7c356e86SAndroid Build Coastguard Worker 		go.optind++;
524*7c356e86SAndroid Build Coastguard Worker 	}
525*7c356e86SAndroid Build Coastguard Worker 	if (setargsp)
526*7c356e86SAndroid Build Coastguard Worker 		/* -- means set $#/$* even if there are no arguments */
527*7c356e86SAndroid Build Coastguard Worker 		*setargsp = !arrayset && ((go.info & GI_MINUSMINUS) ||
528*7c356e86SAndroid Build Coastguard Worker 		    argv[go.optind]);
529*7c356e86SAndroid Build Coastguard Worker 
530*7c356e86SAndroid Build Coastguard Worker 	if (arrayset) {
531*7c356e86SAndroid Build Coastguard Worker 		const char *ccp = NULL;
532*7c356e86SAndroid Build Coastguard Worker 
533*7c356e86SAndroid Build Coastguard Worker 		if (array && *array)
534*7c356e86SAndroid Build Coastguard Worker 			ccp = skip_varname(array, false);
535*7c356e86SAndroid Build Coastguard Worker 		if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) {
536*7c356e86SAndroid Build Coastguard Worker 			bi_errorf(Tf_sD_s, array, Tnot_ident);
537*7c356e86SAndroid Build Coastguard Worker 			return (-1);
538*7c356e86SAndroid Build Coastguard Worker 		}
539*7c356e86SAndroid Build Coastguard Worker 	}
540*7c356e86SAndroid Build Coastguard Worker 	if (sortargs) {
541*7c356e86SAndroid Build Coastguard Worker 		for (i = go.optind; argv[i]; i++)
542*7c356e86SAndroid Build Coastguard Worker 			;
543*7c356e86SAndroid Build Coastguard Worker 		qsort(&argv[go.optind], i - go.optind, sizeof(void *),
544*7c356e86SAndroid Build Coastguard Worker 		    ascpstrcmp);
545*7c356e86SAndroid Build Coastguard Worker 	}
546*7c356e86SAndroid Build Coastguard Worker 	if (arrayset)
547*7c356e86SAndroid Build Coastguard Worker 		go.optind += set_array(array, tobool(arrayset > 0),
548*7c356e86SAndroid Build Coastguard Worker 		    argv + go.optind);
549*7c356e86SAndroid Build Coastguard Worker 
550*7c356e86SAndroid Build Coastguard Worker 	return (go.optind);
551*7c356e86SAndroid Build Coastguard Worker }
552*7c356e86SAndroid Build Coastguard Worker 
553*7c356e86SAndroid Build Coastguard Worker /* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */
554*7c356e86SAndroid Build Coastguard Worker int
getn(const char * s,int * ai)555*7c356e86SAndroid Build Coastguard Worker getn(const char *s, int *ai)
556*7c356e86SAndroid Build Coastguard Worker {
557*7c356e86SAndroid Build Coastguard Worker 	char c;
558*7c356e86SAndroid Build Coastguard Worker 	mksh_ari_u num;
559*7c356e86SAndroid Build Coastguard Worker 	bool neg = false;
560*7c356e86SAndroid Build Coastguard Worker 
561*7c356e86SAndroid Build Coastguard Worker 	num.u = 0;
562*7c356e86SAndroid Build Coastguard Worker 
563*7c356e86SAndroid Build Coastguard Worker 	do {
564*7c356e86SAndroid Build Coastguard Worker 		c = *s++;
565*7c356e86SAndroid Build Coastguard Worker 	} while (ctype(c, C_SPACE));
566*7c356e86SAndroid Build Coastguard Worker 
567*7c356e86SAndroid Build Coastguard Worker 	switch (c) {
568*7c356e86SAndroid Build Coastguard Worker 	case '-':
569*7c356e86SAndroid Build Coastguard Worker 		neg = true;
570*7c356e86SAndroid Build Coastguard Worker 		/* FALLTHROUGH */
571*7c356e86SAndroid Build Coastguard Worker 	case '+':
572*7c356e86SAndroid Build Coastguard Worker 		c = *s++;
573*7c356e86SAndroid Build Coastguard Worker 		break;
574*7c356e86SAndroid Build Coastguard Worker 	}
575*7c356e86SAndroid Build Coastguard Worker 
576*7c356e86SAndroid Build Coastguard Worker 	do {
577*7c356e86SAndroid Build Coastguard Worker 		if (!ctype(c, C_DIGIT))
578*7c356e86SAndroid Build Coastguard Worker 			/* not numeric */
579*7c356e86SAndroid Build Coastguard Worker 			return (0);
580*7c356e86SAndroid Build Coastguard Worker 		if (num.u > 214748364U)
581*7c356e86SAndroid Build Coastguard Worker 			/* overflow on multiplication */
582*7c356e86SAndroid Build Coastguard Worker 			return (0);
583*7c356e86SAndroid Build Coastguard Worker 		num.u = num.u * 10U + (unsigned int)ksh_numdig(c);
584*7c356e86SAndroid Build Coastguard Worker 		/* now: num.u <= 2147483649U */
585*7c356e86SAndroid Build Coastguard Worker 	} while ((c = *s++));
586*7c356e86SAndroid Build Coastguard Worker 
587*7c356e86SAndroid Build Coastguard Worker 	if (num.u > (neg ? 2147483648U : 2147483647U))
588*7c356e86SAndroid Build Coastguard Worker 		/* overflow for signed 32-bit int */
589*7c356e86SAndroid Build Coastguard Worker 		return (0);
590*7c356e86SAndroid Build Coastguard Worker 
591*7c356e86SAndroid Build Coastguard Worker 	if (neg)
592*7c356e86SAndroid Build Coastguard Worker 		num.u = -num.u;
593*7c356e86SAndroid Build Coastguard Worker 	*ai = num.i;
594*7c356e86SAndroid Build Coastguard Worker 	return (1);
595*7c356e86SAndroid Build Coastguard Worker }
596*7c356e86SAndroid Build Coastguard Worker 
597*7c356e86SAndroid Build Coastguard Worker /**
598*7c356e86SAndroid Build Coastguard Worker  * pattern simplifications:
599*7c356e86SAndroid Build Coastguard Worker  * - @(x) -> x (not @(x|y) though)
600*7c356e86SAndroid Build Coastguard Worker  * - ** -> *
601*7c356e86SAndroid Build Coastguard Worker  */
602*7c356e86SAndroid Build Coastguard Worker static void *
simplify_gmatch_pattern(const unsigned char * sp)603*7c356e86SAndroid Build Coastguard Worker simplify_gmatch_pattern(const unsigned char *sp)
604*7c356e86SAndroid Build Coastguard Worker {
605*7c356e86SAndroid Build Coastguard Worker 	uint8_t c;
606*7c356e86SAndroid Build Coastguard Worker 	unsigned char *cp, *dp;
607*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *ps, *se;
608*7c356e86SAndroid Build Coastguard Worker 
609*7c356e86SAndroid Build Coastguard Worker 	cp = alloc(strlen((const void *)sp) + 1, ATEMP);
610*7c356e86SAndroid Build Coastguard Worker 	goto simplify_gmatch_pat1a;
611*7c356e86SAndroid Build Coastguard Worker 
612*7c356e86SAndroid Build Coastguard Worker 	/* foo@(b@(a)r)b@(a|a)z -> foobarb@(a|a)z */
613*7c356e86SAndroid Build Coastguard Worker  simplify_gmatch_pat1:
614*7c356e86SAndroid Build Coastguard Worker 	sp = cp;
615*7c356e86SAndroid Build Coastguard Worker  simplify_gmatch_pat1a:
616*7c356e86SAndroid Build Coastguard Worker 	dp = cp;
617*7c356e86SAndroid Build Coastguard Worker 	se = strnul(sp);
618*7c356e86SAndroid Build Coastguard Worker 	while ((c = *sp++)) {
619*7c356e86SAndroid Build Coastguard Worker 		if (!ISMAGIC(c)) {
620*7c356e86SAndroid Build Coastguard Worker 			*dp++ = c;
621*7c356e86SAndroid Build Coastguard Worker 			continue;
622*7c356e86SAndroid Build Coastguard Worker 		}
623*7c356e86SAndroid Build Coastguard Worker 		switch ((c = *sp++)) {
624*7c356e86SAndroid Build Coastguard Worker 		case 0x80|'@':
625*7c356e86SAndroid Build Coastguard Worker 		/* simile for @ */
626*7c356e86SAndroid Build Coastguard Worker 		case 0x80|' ':
627*7c356e86SAndroid Build Coastguard Worker 			/* check whether it has only one clause */
628*7c356e86SAndroid Build Coastguard Worker 			ps = pat_scan(sp, se, true);
629*7c356e86SAndroid Build Coastguard Worker 			if (!ps || ps[-1] != /*(*/ ')')
630*7c356e86SAndroid Build Coastguard Worker 				/* nope */
631*7c356e86SAndroid Build Coastguard Worker 				break;
632*7c356e86SAndroid Build Coastguard Worker 			/* copy inner clause until matching close */
633*7c356e86SAndroid Build Coastguard Worker 			ps -= 2;
634*7c356e86SAndroid Build Coastguard Worker 			while ((const unsigned char *)sp < ps)
635*7c356e86SAndroid Build Coastguard Worker 				*dp++ = *sp++;
636*7c356e86SAndroid Build Coastguard Worker 			/* skip MAGIC and closing parenthesis */
637*7c356e86SAndroid Build Coastguard Worker 			sp += 2;
638*7c356e86SAndroid Build Coastguard Worker 			/* copy the rest of the pattern */
639*7c356e86SAndroid Build Coastguard Worker 			memmove(dp, sp, strlen((const void *)sp) + 1);
640*7c356e86SAndroid Build Coastguard Worker 			/* redo from start */
641*7c356e86SAndroid Build Coastguard Worker 			goto simplify_gmatch_pat1;
642*7c356e86SAndroid Build Coastguard Worker 		}
643*7c356e86SAndroid Build Coastguard Worker 		*dp++ = MAGIC;
644*7c356e86SAndroid Build Coastguard Worker 		*dp++ = c;
645*7c356e86SAndroid Build Coastguard Worker 	}
646*7c356e86SAndroid Build Coastguard Worker 	*dp = '\0';
647*7c356e86SAndroid Build Coastguard Worker 
648*7c356e86SAndroid Build Coastguard Worker 	/* collapse adjacent asterisk wildcards */
649*7c356e86SAndroid Build Coastguard Worker 	sp = dp = cp;
650*7c356e86SAndroid Build Coastguard Worker 	while ((c = *sp++)) {
651*7c356e86SAndroid Build Coastguard Worker 		if (!ISMAGIC(c)) {
652*7c356e86SAndroid Build Coastguard Worker 			*dp++ = c;
653*7c356e86SAndroid Build Coastguard Worker 			continue;
654*7c356e86SAndroid Build Coastguard Worker 		}
655*7c356e86SAndroid Build Coastguard Worker 		switch ((c = *sp++)) {
656*7c356e86SAndroid Build Coastguard Worker 		case '*':
657*7c356e86SAndroid Build Coastguard Worker 			while (ISMAGIC(sp[0]) && sp[1] == c)
658*7c356e86SAndroid Build Coastguard Worker 				sp += 2;
659*7c356e86SAndroid Build Coastguard Worker 			break;
660*7c356e86SAndroid Build Coastguard Worker 		}
661*7c356e86SAndroid Build Coastguard Worker 		*dp++ = MAGIC;
662*7c356e86SAndroid Build Coastguard Worker 		*dp++ = c;
663*7c356e86SAndroid Build Coastguard Worker 	}
664*7c356e86SAndroid Build Coastguard Worker 	*dp = '\0';
665*7c356e86SAndroid Build Coastguard Worker 
666*7c356e86SAndroid Build Coastguard Worker 	/* return the result, allocated from ATEMP */
667*7c356e86SAndroid Build Coastguard Worker 	return (cp);
668*7c356e86SAndroid Build Coastguard Worker }
669*7c356e86SAndroid Build Coastguard Worker 
670*7c356e86SAndroid Build Coastguard Worker /* -------- gmatch.c -------- */
671*7c356e86SAndroid Build Coastguard Worker 
672*7c356e86SAndroid Build Coastguard Worker /*
673*7c356e86SAndroid Build Coastguard Worker  * int gmatch(string, pattern)
674*7c356e86SAndroid Build Coastguard Worker  * char *string, *pattern;
675*7c356e86SAndroid Build Coastguard Worker  *
676*7c356e86SAndroid Build Coastguard Worker  * Match a pattern as in sh(1).
677*7c356e86SAndroid Build Coastguard Worker  * pattern character are prefixed with MAGIC by expand.
678*7c356e86SAndroid Build Coastguard Worker  */
679*7c356e86SAndroid Build Coastguard Worker int
gmatchx(const char * s,const char * p,bool isfile)680*7c356e86SAndroid Build Coastguard Worker gmatchx(const char *s, const char *p, bool isfile)
681*7c356e86SAndroid Build Coastguard Worker {
682*7c356e86SAndroid Build Coastguard Worker 	const char *se, *pe;
683*7c356e86SAndroid Build Coastguard Worker 	char *pnew;
684*7c356e86SAndroid Build Coastguard Worker 	int rv;
685*7c356e86SAndroid Build Coastguard Worker 
686*7c356e86SAndroid Build Coastguard Worker 	if (s == NULL || p == NULL)
687*7c356e86SAndroid Build Coastguard Worker 		return (0);
688*7c356e86SAndroid Build Coastguard Worker 
689*7c356e86SAndroid Build Coastguard Worker 	pe = strnul(p);
690*7c356e86SAndroid Build Coastguard Worker 	/*
691*7c356e86SAndroid Build Coastguard Worker 	 * isfile is false iff no syntax check has been done on
692*7c356e86SAndroid Build Coastguard Worker 	 * the pattern. If check fails, just do a strcmp().
693*7c356e86SAndroid Build Coastguard Worker 	 */
694*7c356e86SAndroid Build Coastguard Worker 	if (!isfile && !has_globbing(p)) {
695*7c356e86SAndroid Build Coastguard Worker 		size_t len = pe - p + 1;
696*7c356e86SAndroid Build Coastguard Worker 		char tbuf[64];
697*7c356e86SAndroid Build Coastguard Worker 		char *t = len <= sizeof(tbuf) ? tbuf : alloc(len, ATEMP);
698*7c356e86SAndroid Build Coastguard Worker 		debunk(t, p, len);
699*7c356e86SAndroid Build Coastguard Worker 		return (!strcmp(t, s));
700*7c356e86SAndroid Build Coastguard Worker 	}
701*7c356e86SAndroid Build Coastguard Worker 	se = strnul(s);
702*7c356e86SAndroid Build Coastguard Worker 
703*7c356e86SAndroid Build Coastguard Worker 	/*
704*7c356e86SAndroid Build Coastguard Worker 	 * since the do_gmatch() engine sucks so much, we must do some
705*7c356e86SAndroid Build Coastguard Worker 	 * pattern simplifications
706*7c356e86SAndroid Build Coastguard Worker 	 */
707*7c356e86SAndroid Build Coastguard Worker 	pnew = simplify_gmatch_pattern((const unsigned char *)p);
708*7c356e86SAndroid Build Coastguard Worker 	pe = strnul(pnew);
709*7c356e86SAndroid Build Coastguard Worker 
710*7c356e86SAndroid Build Coastguard Worker 	rv = do_gmatch((const unsigned char *)s, (const unsigned char *)se,
711*7c356e86SAndroid Build Coastguard Worker 	    (const unsigned char *)pnew, (const unsigned char *)pe,
712*7c356e86SAndroid Build Coastguard Worker 	    (const unsigned char *)s);
713*7c356e86SAndroid Build Coastguard Worker 	afree(pnew, ATEMP);
714*7c356e86SAndroid Build Coastguard Worker 	return (rv);
715*7c356e86SAndroid Build Coastguard Worker }
716*7c356e86SAndroid Build Coastguard Worker 
717*7c356e86SAndroid Build Coastguard Worker /**
718*7c356e86SAndroid Build Coastguard Worker  * Returns if p is a syntacticly correct globbing pattern, false
719*7c356e86SAndroid Build Coastguard Worker  * if it contains no pattern characters or if there is a syntax error.
720*7c356e86SAndroid Build Coastguard Worker  * Syntax errors are:
721*7c356e86SAndroid Build Coastguard Worker  *	- [ with no closing ]
722*7c356e86SAndroid Build Coastguard Worker  *	- imbalanced $(...) expression
723*7c356e86SAndroid Build Coastguard Worker  *	- [...] and *(...) not nested (eg, @(a[b|)c], *(a[b|c]d))
724*7c356e86SAndroid Build Coastguard Worker  */
725*7c356e86SAndroid Build Coastguard Worker /*XXX
726*7c356e86SAndroid Build Coastguard Worker  * - if no magic,
727*7c356e86SAndroid Build Coastguard Worker  *	if dest given, copy to dst
728*7c356e86SAndroid Build Coastguard Worker  *	return ?
729*7c356e86SAndroid Build Coastguard Worker  * - if magic && (no globbing || syntax error)
730*7c356e86SAndroid Build Coastguard Worker  *	debunk to dst
731*7c356e86SAndroid Build Coastguard Worker  *	return ?
732*7c356e86SAndroid Build Coastguard Worker  * - return ?
733*7c356e86SAndroid Build Coastguard Worker  */
734*7c356e86SAndroid Build Coastguard Worker bool
has_globbing(const char * pat)735*7c356e86SAndroid Build Coastguard Worker has_globbing(const char *pat)
736*7c356e86SAndroid Build Coastguard Worker {
737*7c356e86SAndroid Build Coastguard Worker 	unsigned char c, subc;
738*7c356e86SAndroid Build Coastguard Worker 	bool saw_glob = false;
739*7c356e86SAndroid Build Coastguard Worker 	unsigned int nest = 0;
740*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *p = (const unsigned char *)pat;
741*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *s;
742*7c356e86SAndroid Build Coastguard Worker 
743*7c356e86SAndroid Build Coastguard Worker 	while ((c = *p++)) {
744*7c356e86SAndroid Build Coastguard Worker 		/* regular character? ok. */
745*7c356e86SAndroid Build Coastguard Worker 		if (!ISMAGIC(c))
746*7c356e86SAndroid Build Coastguard Worker 			continue;
747*7c356e86SAndroid Build Coastguard Worker 		/* MAGIC + NUL? abort. */
748*7c356e86SAndroid Build Coastguard Worker 		if (!(c = *p++))
749*7c356e86SAndroid Build Coastguard Worker 			return (false);
750*7c356e86SAndroid Build Coastguard Worker 		/* some specials */
751*7c356e86SAndroid Build Coastguard Worker 		if (ord(c) == ORD('*') || ord(c) == ORD('?')) {
752*7c356e86SAndroid Build Coastguard Worker 			/* easy glob, accept */
753*7c356e86SAndroid Build Coastguard Worker 			saw_glob = true;
754*7c356e86SAndroid Build Coastguard Worker 		} else if (ord(c) == ORD('[')) {
755*7c356e86SAndroid Build Coastguard Worker 			/* bracket expression; eat negation and initial ] */
756*7c356e86SAndroid Build Coastguard Worker 			if (ISMAGIC(p[0]) && ord(p[1]) == ORD('!'))
757*7c356e86SAndroid Build Coastguard Worker 				p += 2;
758*7c356e86SAndroid Build Coastguard Worker 			if (ISMAGIC(p[0]) && ord(p[1]) == ORD(']'))
759*7c356e86SAndroid Build Coastguard Worker 				p += 2;
760*7c356e86SAndroid Build Coastguard Worker 			/* check next string part */
761*7c356e86SAndroid Build Coastguard Worker 			s = p;
762*7c356e86SAndroid Build Coastguard Worker 			while ((c = *s++)) {
763*7c356e86SAndroid Build Coastguard Worker 				/* regular chars are ok */
764*7c356e86SAndroid Build Coastguard Worker 				if (!ISMAGIC(c))
765*7c356e86SAndroid Build Coastguard Worker 					continue;
766*7c356e86SAndroid Build Coastguard Worker 				/* MAGIC + NUL cannot happen */
767*7c356e86SAndroid Build Coastguard Worker 				if (!(c = *s++))
768*7c356e86SAndroid Build Coastguard Worker 					return (false);
769*7c356e86SAndroid Build Coastguard Worker 				/* terminating bracket? */
770*7c356e86SAndroid Build Coastguard Worker 				if (ord(c) == ORD(']')) {
771*7c356e86SAndroid Build Coastguard Worker 					/* accept and continue */
772*7c356e86SAndroid Build Coastguard Worker 					p = s;
773*7c356e86SAndroid Build Coastguard Worker 					saw_glob = true;
774*7c356e86SAndroid Build Coastguard Worker 					break;
775*7c356e86SAndroid Build Coastguard Worker 				}
776*7c356e86SAndroid Build Coastguard Worker 				/* sub-bracket expressions */
777*7c356e86SAndroid Build Coastguard Worker 				if (ord(c) == ORD('[') && (
778*7c356e86SAndroid Build Coastguard Worker 				    /* collating element? */
779*7c356e86SAndroid Build Coastguard Worker 				    ord(*s) == ORD('.') ||
780*7c356e86SAndroid Build Coastguard Worker 				    /* equivalence class? */
781*7c356e86SAndroid Build Coastguard Worker 				    ord(*s) == ORD('=') ||
782*7c356e86SAndroid Build Coastguard Worker 				    /* character class? */
783*7c356e86SAndroid Build Coastguard Worker 				    ord(*s) == ORD(':'))) {
784*7c356e86SAndroid Build Coastguard Worker 					/* must stop with exactly the same c */
785*7c356e86SAndroid Build Coastguard Worker 					subc = *s++;
786*7c356e86SAndroid Build Coastguard Worker 					/* arbitrarily many chars in betwixt */
787*7c356e86SAndroid Build Coastguard Worker 					while ((c = *s++))
788*7c356e86SAndroid Build Coastguard Worker 						/* but only this sequence... */
789*7c356e86SAndroid Build Coastguard Worker 						if (c == subc && ISMAGIC(*s) &&
790*7c356e86SAndroid Build Coastguard Worker 						    ord(s[1]) == ORD(']')) {
791*7c356e86SAndroid Build Coastguard Worker 							/* accept, terminate */
792*7c356e86SAndroid Build Coastguard Worker 							s += 2;
793*7c356e86SAndroid Build Coastguard Worker 							break;
794*7c356e86SAndroid Build Coastguard Worker 						}
795*7c356e86SAndroid Build Coastguard Worker 					/* EOS without: reject bracket expr */
796*7c356e86SAndroid Build Coastguard Worker 					if (!c)
797*7c356e86SAndroid Build Coastguard Worker 						break;
798*7c356e86SAndroid Build Coastguard Worker 					/* continue; */
799*7c356e86SAndroid Build Coastguard Worker 				}
800*7c356e86SAndroid Build Coastguard Worker 				/* anything else just goes on */
801*7c356e86SAndroid Build Coastguard Worker 			}
802*7c356e86SAndroid Build Coastguard Worker 		} else if ((c & 0x80) && ctype(c & 0x7F, C_PATMO | C_SPC)) {
803*7c356e86SAndroid Build Coastguard Worker 			/* opening pattern */
804*7c356e86SAndroid Build Coastguard Worker 			saw_glob = true;
805*7c356e86SAndroid Build Coastguard Worker 			++nest;
806*7c356e86SAndroid Build Coastguard Worker 		} else if (ord(c) == ORD(/*(*/ ')')) {
807*7c356e86SAndroid Build Coastguard Worker 			/* closing pattern */
808*7c356e86SAndroid Build Coastguard Worker 			if (nest)
809*7c356e86SAndroid Build Coastguard Worker 				--nest;
810*7c356e86SAndroid Build Coastguard Worker 		}
811*7c356e86SAndroid Build Coastguard Worker 	}
812*7c356e86SAndroid Build Coastguard Worker 	return (saw_glob && !nest);
813*7c356e86SAndroid Build Coastguard Worker }
814*7c356e86SAndroid Build Coastguard Worker 
815*7c356e86SAndroid Build Coastguard Worker /* Function must return either 0 or 1 (assumed by code for 0x80|'!') */
816*7c356e86SAndroid Build Coastguard Worker static int
do_gmatch(const unsigned char * s,const unsigned char * se,const unsigned char * p,const unsigned char * pe,const unsigned char * smin)817*7c356e86SAndroid Build Coastguard Worker do_gmatch(const unsigned char *s, const unsigned char *se,
818*7c356e86SAndroid Build Coastguard Worker     const unsigned char *p, const unsigned char *pe,
819*7c356e86SAndroid Build Coastguard Worker     const unsigned char *smin)
820*7c356e86SAndroid Build Coastguard Worker {
821*7c356e86SAndroid Build Coastguard Worker 	unsigned char sc, pc, sl = 0;
822*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *prest, *psub, *pnext;
823*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *srest;
824*7c356e86SAndroid Build Coastguard Worker 
825*7c356e86SAndroid Build Coastguard Worker 	if (s == NULL || p == NULL)
826*7c356e86SAndroid Build Coastguard Worker 		return (0);
827*7c356e86SAndroid Build Coastguard Worker 	if (s > smin && s <= se)
828*7c356e86SAndroid Build Coastguard Worker 		sl = s[-1];
829*7c356e86SAndroid Build Coastguard Worker 	while (p < pe) {
830*7c356e86SAndroid Build Coastguard Worker 		pc = *p++;
831*7c356e86SAndroid Build Coastguard Worker 		sc = s < se ? *s : '\0';
832*7c356e86SAndroid Build Coastguard Worker 		s++;
833*7c356e86SAndroid Build Coastguard Worker 		if (!ISMAGIC(pc)) {
834*7c356e86SAndroid Build Coastguard Worker 			if (sc != pc)
835*7c356e86SAndroid Build Coastguard Worker 				return (0);
836*7c356e86SAndroid Build Coastguard Worker 			sl = sc;
837*7c356e86SAndroid Build Coastguard Worker 			continue;
838*7c356e86SAndroid Build Coastguard Worker 		}
839*7c356e86SAndroid Build Coastguard Worker 		switch (ord(*p++)) {
840*7c356e86SAndroid Build Coastguard Worker 		case ORD('['):
841*7c356e86SAndroid Build Coastguard Worker 			/* BSD cclass extension? */
842*7c356e86SAndroid Build Coastguard Worker 			if (ISMAGIC(p[0]) && ord(p[1]) == ORD('[') &&
843*7c356e86SAndroid Build Coastguard Worker 			    ord(p[2]) == ORD(':') &&
844*7c356e86SAndroid Build Coastguard Worker 			    ctype((pc = p[3]), C_ANGLE) &&
845*7c356e86SAndroid Build Coastguard Worker 			    ord(p[4]) == ORD(':') &&
846*7c356e86SAndroid Build Coastguard Worker 			    ISMAGIC(p[5]) && ord(p[6]) == ORD(']') &&
847*7c356e86SAndroid Build Coastguard Worker 			    ISMAGIC(p[7]) && ord(p[8]) == ORD(']')) {
848*7c356e86SAndroid Build Coastguard Worker 				/* zero-length match */
849*7c356e86SAndroid Build Coastguard Worker 				--s;
850*7c356e86SAndroid Build Coastguard Worker 				p += 9;
851*7c356e86SAndroid Build Coastguard Worker 				/* word begin? */
852*7c356e86SAndroid Build Coastguard Worker 				if (ord(pc) == ORD('<') &&
853*7c356e86SAndroid Build Coastguard Worker 				    !ctype(sl, C_ALNUX) &&
854*7c356e86SAndroid Build Coastguard Worker 				    ctype(sc, C_ALNUX))
855*7c356e86SAndroid Build Coastguard Worker 					break;
856*7c356e86SAndroid Build Coastguard Worker 				/* word end? */
857*7c356e86SAndroid Build Coastguard Worker 				if (ord(pc) == ORD('>') &&
858*7c356e86SAndroid Build Coastguard Worker 				    ctype(sl, C_ALNUX) &&
859*7c356e86SAndroid Build Coastguard Worker 				    !ctype(sc, C_ALNUX))
860*7c356e86SAndroid Build Coastguard Worker 					break;
861*7c356e86SAndroid Build Coastguard Worker 				/* neither */
862*7c356e86SAndroid Build Coastguard Worker 				return (0);
863*7c356e86SAndroid Build Coastguard Worker 			}
864*7c356e86SAndroid Build Coastguard Worker 			if (sc == 0 || (p = gmatch_cclass(p, sc)) == NULL)
865*7c356e86SAndroid Build Coastguard Worker 				return (0);
866*7c356e86SAndroid Build Coastguard Worker 			break;
867*7c356e86SAndroid Build Coastguard Worker 
868*7c356e86SAndroid Build Coastguard Worker 		case ORD('?'):
869*7c356e86SAndroid Build Coastguard Worker 			if (sc == 0)
870*7c356e86SAndroid Build Coastguard Worker 				return (0);
871*7c356e86SAndroid Build Coastguard Worker 			if (UTFMODE) {
872*7c356e86SAndroid Build Coastguard Worker 				--s;
873*7c356e86SAndroid Build Coastguard Worker 				s += utf_ptradj((const void *)s);
874*7c356e86SAndroid Build Coastguard Worker 			}
875*7c356e86SAndroid Build Coastguard Worker 			break;
876*7c356e86SAndroid Build Coastguard Worker 
877*7c356e86SAndroid Build Coastguard Worker 		case ORD('*'):
878*7c356e86SAndroid Build Coastguard Worker 			if (p == pe)
879*7c356e86SAndroid Build Coastguard Worker 				return (1);
880*7c356e86SAndroid Build Coastguard Worker 			s--;
881*7c356e86SAndroid Build Coastguard Worker 			do {
882*7c356e86SAndroid Build Coastguard Worker 				if (do_gmatch(s, se, p, pe, smin))
883*7c356e86SAndroid Build Coastguard Worker 					return (1);
884*7c356e86SAndroid Build Coastguard Worker 			} while (s++ < se);
885*7c356e86SAndroid Build Coastguard Worker 			return (0);
886*7c356e86SAndroid Build Coastguard Worker 
887*7c356e86SAndroid Build Coastguard Worker 		/**
888*7c356e86SAndroid Build Coastguard Worker 		 * [+*?@!](pattern|pattern|..)
889*7c356e86SAndroid Build Coastguard Worker 		 * This is also needed for ${..%..}, etc.
890*7c356e86SAndroid Build Coastguard Worker 		 */
891*7c356e86SAndroid Build Coastguard Worker 
892*7c356e86SAndroid Build Coastguard Worker 		/* matches one or more times */
893*7c356e86SAndroid Build Coastguard Worker 		case ORD('+') | 0x80:
894*7c356e86SAndroid Build Coastguard Worker 		/* matches zero or more times */
895*7c356e86SAndroid Build Coastguard Worker 		case ORD('*') | 0x80:
896*7c356e86SAndroid Build Coastguard Worker 			if (!(prest = pat_scan(p, pe, false)))
897*7c356e86SAndroid Build Coastguard Worker 				return (0);
898*7c356e86SAndroid Build Coastguard Worker 			s--;
899*7c356e86SAndroid Build Coastguard Worker 			/* take care of zero matches */
900*7c356e86SAndroid Build Coastguard Worker 			if (ord(p[-1]) == (0x80 | ORD('*')) &&
901*7c356e86SAndroid Build Coastguard Worker 			    do_gmatch(s, se, prest, pe, smin))
902*7c356e86SAndroid Build Coastguard Worker 				return (1);
903*7c356e86SAndroid Build Coastguard Worker 			for (psub = p; ; psub = pnext) {
904*7c356e86SAndroid Build Coastguard Worker 				pnext = pat_scan(psub, pe, true);
905*7c356e86SAndroid Build Coastguard Worker 				for (srest = s; srest <= se; srest++) {
906*7c356e86SAndroid Build Coastguard Worker 					if (do_gmatch(s, srest, psub, pnext - 2, smin) &&
907*7c356e86SAndroid Build Coastguard Worker 					    (do_gmatch(srest, se, prest, pe, smin) ||
908*7c356e86SAndroid Build Coastguard Worker 					    (s != srest &&
909*7c356e86SAndroid Build Coastguard Worker 					    do_gmatch(srest, se, p - 2, pe, smin))))
910*7c356e86SAndroid Build Coastguard Worker 						return (1);
911*7c356e86SAndroid Build Coastguard Worker 				}
912*7c356e86SAndroid Build Coastguard Worker 				if (pnext == prest)
913*7c356e86SAndroid Build Coastguard Worker 					break;
914*7c356e86SAndroid Build Coastguard Worker 			}
915*7c356e86SAndroid Build Coastguard Worker 			return (0);
916*7c356e86SAndroid Build Coastguard Worker 
917*7c356e86SAndroid Build Coastguard Worker 		/* matches zero or once */
918*7c356e86SAndroid Build Coastguard Worker 		case ORD('?') | 0x80:
919*7c356e86SAndroid Build Coastguard Worker 		/* matches one of the patterns */
920*7c356e86SAndroid Build Coastguard Worker 		case ORD('@') | 0x80:
921*7c356e86SAndroid Build Coastguard Worker 		/* simile for @ */
922*7c356e86SAndroid Build Coastguard Worker 		case ORD(' ') | 0x80:
923*7c356e86SAndroid Build Coastguard Worker 			if (!(prest = pat_scan(p, pe, false)))
924*7c356e86SAndroid Build Coastguard Worker 				return (0);
925*7c356e86SAndroid Build Coastguard Worker 			s--;
926*7c356e86SAndroid Build Coastguard Worker 			/* Take care of zero matches */
927*7c356e86SAndroid Build Coastguard Worker 			if (ord(p[-1]) == (0x80 | ORD('?')) &&
928*7c356e86SAndroid Build Coastguard Worker 			    do_gmatch(s, se, prest, pe, smin))
929*7c356e86SAndroid Build Coastguard Worker 				return (1);
930*7c356e86SAndroid Build Coastguard Worker 			for (psub = p; ; psub = pnext) {
931*7c356e86SAndroid Build Coastguard Worker 				pnext = pat_scan(psub, pe, true);
932*7c356e86SAndroid Build Coastguard Worker 				srest = prest == pe ? se : s;
933*7c356e86SAndroid Build Coastguard Worker 				for (; srest <= se; srest++) {
934*7c356e86SAndroid Build Coastguard Worker 					if (do_gmatch(s, srest, psub, pnext - 2, smin) &&
935*7c356e86SAndroid Build Coastguard Worker 					    do_gmatch(srest, se, prest, pe, smin))
936*7c356e86SAndroid Build Coastguard Worker 						return (1);
937*7c356e86SAndroid Build Coastguard Worker 				}
938*7c356e86SAndroid Build Coastguard Worker 				if (pnext == prest)
939*7c356e86SAndroid Build Coastguard Worker 					break;
940*7c356e86SAndroid Build Coastguard Worker 			}
941*7c356e86SAndroid Build Coastguard Worker 			return (0);
942*7c356e86SAndroid Build Coastguard Worker 
943*7c356e86SAndroid Build Coastguard Worker 		/* matches none of the patterns */
944*7c356e86SAndroid Build Coastguard Worker 		case ORD('!') | 0x80:
945*7c356e86SAndroid Build Coastguard Worker 			if (!(prest = pat_scan(p, pe, false)))
946*7c356e86SAndroid Build Coastguard Worker 				return (0);
947*7c356e86SAndroid Build Coastguard Worker 			s--;
948*7c356e86SAndroid Build Coastguard Worker 			for (srest = s; srest <= se; srest++) {
949*7c356e86SAndroid Build Coastguard Worker 				int matched = 0;
950*7c356e86SAndroid Build Coastguard Worker 
951*7c356e86SAndroid Build Coastguard Worker 				for (psub = p; ; psub = pnext) {
952*7c356e86SAndroid Build Coastguard Worker 					pnext = pat_scan(psub, pe, true);
953*7c356e86SAndroid Build Coastguard Worker 					if (do_gmatch(s, srest, psub,
954*7c356e86SAndroid Build Coastguard Worker 					    pnext - 2, smin)) {
955*7c356e86SAndroid Build Coastguard Worker 						matched = 1;
956*7c356e86SAndroid Build Coastguard Worker 						break;
957*7c356e86SAndroid Build Coastguard Worker 					}
958*7c356e86SAndroid Build Coastguard Worker 					if (pnext == prest)
959*7c356e86SAndroid Build Coastguard Worker 						break;
960*7c356e86SAndroid Build Coastguard Worker 				}
961*7c356e86SAndroid Build Coastguard Worker 				if (!matched &&
962*7c356e86SAndroid Build Coastguard Worker 				    do_gmatch(srest, se, prest, pe, smin))
963*7c356e86SAndroid Build Coastguard Worker 					return (1);
964*7c356e86SAndroid Build Coastguard Worker 			}
965*7c356e86SAndroid Build Coastguard Worker 			return (0);
966*7c356e86SAndroid Build Coastguard Worker 
967*7c356e86SAndroid Build Coastguard Worker 		default:
968*7c356e86SAndroid Build Coastguard Worker 			if (sc != p[-1])
969*7c356e86SAndroid Build Coastguard Worker 				return (0);
970*7c356e86SAndroid Build Coastguard Worker 			break;
971*7c356e86SAndroid Build Coastguard Worker 		}
972*7c356e86SAndroid Build Coastguard Worker 		sl = sc;
973*7c356e86SAndroid Build Coastguard Worker 	}
974*7c356e86SAndroid Build Coastguard Worker 	return (s == se);
975*7c356e86SAndroid Build Coastguard Worker }
976*7c356e86SAndroid Build Coastguard Worker 
977*7c356e86SAndroid Build Coastguard Worker /*XXX this is a prime example for bsearch or a const hashtable */
978*7c356e86SAndroid Build Coastguard Worker static const struct cclass {
979*7c356e86SAndroid Build Coastguard Worker 	const char *name;
980*7c356e86SAndroid Build Coastguard Worker 	uint32_t value;
981*7c356e86SAndroid Build Coastguard Worker } cclasses[] = {
982*7c356e86SAndroid Build Coastguard Worker 	/* POSIX */
983*7c356e86SAndroid Build Coastguard Worker 	{ "alnum",	C_ALNUM	},
984*7c356e86SAndroid Build Coastguard Worker 	{ "alpha",	C_ALPHA	},
985*7c356e86SAndroid Build Coastguard Worker 	{ "blank",	C_BLANK	},
986*7c356e86SAndroid Build Coastguard Worker 	{ "cntrl",	C_CNTRL	},
987*7c356e86SAndroid Build Coastguard Worker 	{ "digit",	C_DIGIT	},
988*7c356e86SAndroid Build Coastguard Worker 	{ "graph",	C_GRAPH	},
989*7c356e86SAndroid Build Coastguard Worker 	{ "lower",	C_LOWER	},
990*7c356e86SAndroid Build Coastguard Worker 	{ "print",	C_PRINT	},
991*7c356e86SAndroid Build Coastguard Worker 	{ "punct",	C_PUNCT	},
992*7c356e86SAndroid Build Coastguard Worker 	{ "space",	C_SPACE	},
993*7c356e86SAndroid Build Coastguard Worker 	{ "upper",	C_UPPER	},
994*7c356e86SAndroid Build Coastguard Worker 	{ "xdigit",	C_SEDEC	},
995*7c356e86SAndroid Build Coastguard Worker 	/* BSD */
996*7c356e86SAndroid Build Coastguard Worker 	/* "<" and ">" are handled inline */
997*7c356e86SAndroid Build Coastguard Worker 	/* GNU bash */
998*7c356e86SAndroid Build Coastguard Worker 	{ "ascii",	C_ASCII	},
999*7c356e86SAndroid Build Coastguard Worker 	{ "word",	C_ALNUX	},
1000*7c356e86SAndroid Build Coastguard Worker 	/* mksh */
1001*7c356e86SAndroid Build Coastguard Worker 	{ "sh_alias",	C_ALIAS	},
1002*7c356e86SAndroid Build Coastguard Worker 	{ "sh_edq",	C_EDQ	},
1003*7c356e86SAndroid Build Coastguard Worker 	{ "sh_ifs",	C_IFS	},
1004*7c356e86SAndroid Build Coastguard Worker 	{ "sh_ifsws",	C_IFSWS	},
1005*7c356e86SAndroid Build Coastguard Worker 	{ "sh_nl",	C_NL	},
1006*7c356e86SAndroid Build Coastguard Worker 	{ "sh_quote",	C_QUOTE	},
1007*7c356e86SAndroid Build Coastguard Worker 	/* sentinel */
1008*7c356e86SAndroid Build Coastguard Worker 	{ NULL,		0	}
1009*7c356e86SAndroid Build Coastguard Worker };
1010*7c356e86SAndroid Build Coastguard Worker 
1011*7c356e86SAndroid Build Coastguard Worker static const unsigned char *
gmatch_cclass(const unsigned char * pat,unsigned char sc)1012*7c356e86SAndroid Build Coastguard Worker gmatch_cclass(const unsigned char *pat, unsigned char sc)
1013*7c356e86SAndroid Build Coastguard Worker {
1014*7c356e86SAndroid Build Coastguard Worker 	unsigned char c, subc, lc;
1015*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *p = pat, *s;
1016*7c356e86SAndroid Build Coastguard Worker 	bool found = false;
1017*7c356e86SAndroid Build Coastguard Worker 	bool negated = false;
1018*7c356e86SAndroid Build Coastguard Worker 	char *subp;
1019*7c356e86SAndroid Build Coastguard Worker 
1020*7c356e86SAndroid Build Coastguard Worker 	/* check for negation */
1021*7c356e86SAndroid Build Coastguard Worker 	if (ISMAGIC(p[0]) && ord(p[1]) == ORD('!')) {
1022*7c356e86SAndroid Build Coastguard Worker 		p += 2;
1023*7c356e86SAndroid Build Coastguard Worker 		negated = true;
1024*7c356e86SAndroid Build Coastguard Worker 	}
1025*7c356e86SAndroid Build Coastguard Worker 	/* make initial ] non-MAGIC */
1026*7c356e86SAndroid Build Coastguard Worker 	if (ISMAGIC(p[0]) && ord(p[1]) == ORD(']'))
1027*7c356e86SAndroid Build Coastguard Worker 		++p;
1028*7c356e86SAndroid Build Coastguard Worker 	/* iterate over bracket expression, debunk()ing on the fly */
1029*7c356e86SAndroid Build Coastguard Worker 	while ((c = *p++)) {
1030*7c356e86SAndroid Build Coastguard Worker  nextc:
1031*7c356e86SAndroid Build Coastguard Worker 		/* non-regular character? */
1032*7c356e86SAndroid Build Coastguard Worker 		if (ISMAGIC(c)) {
1033*7c356e86SAndroid Build Coastguard Worker 			/* MAGIC + NUL cannot happen */
1034*7c356e86SAndroid Build Coastguard Worker 			if (!(c = *p++))
1035*7c356e86SAndroid Build Coastguard Worker 				break;
1036*7c356e86SAndroid Build Coastguard Worker 			/* terminating bracket? */
1037*7c356e86SAndroid Build Coastguard Worker 			if (ord(c) == ORD(']')) {
1038*7c356e86SAndroid Build Coastguard Worker 				/* accept and return */
1039*7c356e86SAndroid Build Coastguard Worker 				return (found != negated ? p : NULL);
1040*7c356e86SAndroid Build Coastguard Worker 			}
1041*7c356e86SAndroid Build Coastguard Worker 			/* sub-bracket expressions */
1042*7c356e86SAndroid Build Coastguard Worker 			if (ord(c) == ORD('[') && (
1043*7c356e86SAndroid Build Coastguard Worker 			    /* collating element? */
1044*7c356e86SAndroid Build Coastguard Worker 			    ord(*p) == ORD('.') ||
1045*7c356e86SAndroid Build Coastguard Worker 			    /* equivalence class? */
1046*7c356e86SAndroid Build Coastguard Worker 			    ord(*p) == ORD('=') ||
1047*7c356e86SAndroid Build Coastguard Worker 			    /* character class? */
1048*7c356e86SAndroid Build Coastguard Worker 			    ord(*p) == ORD(':'))) {
1049*7c356e86SAndroid Build Coastguard Worker 				/* must stop with exactly the same c */
1050*7c356e86SAndroid Build Coastguard Worker 				subc = *p++;
1051*7c356e86SAndroid Build Coastguard Worker 				/* save away start of substring */
1052*7c356e86SAndroid Build Coastguard Worker 				s = p;
1053*7c356e86SAndroid Build Coastguard Worker 				/* arbitrarily many chars in betwixt */
1054*7c356e86SAndroid Build Coastguard Worker 				while ((c = *p++))
1055*7c356e86SAndroid Build Coastguard Worker 					/* but only this sequence... */
1056*7c356e86SAndroid Build Coastguard Worker 					if (c == subc && ISMAGIC(*p) &&
1057*7c356e86SAndroid Build Coastguard Worker 					    ord(p[1]) == ORD(']')) {
1058*7c356e86SAndroid Build Coastguard Worker 						/* accept, terminate */
1059*7c356e86SAndroid Build Coastguard Worker 						p += 2;
1060*7c356e86SAndroid Build Coastguard Worker 						break;
1061*7c356e86SAndroid Build Coastguard Worker 					}
1062*7c356e86SAndroid Build Coastguard Worker 				/* EOS without: reject bracket expr */
1063*7c356e86SAndroid Build Coastguard Worker 				if (!c)
1064*7c356e86SAndroid Build Coastguard Worker 					break;
1065*7c356e86SAndroid Build Coastguard Worker 				/* debunk substring */
1066*7c356e86SAndroid Build Coastguard Worker 				strndupx(subp, s, p - s - 3, ATEMP);
1067*7c356e86SAndroid Build Coastguard Worker 				debunk(subp, subp, p - s - 3 + 1);
1068*7c356e86SAndroid Build Coastguard Worker  cclass_common:
1069*7c356e86SAndroid Build Coastguard Worker 				/* whither subexpression */
1070*7c356e86SAndroid Build Coastguard Worker 				if (ord(subc) == ORD(':')) {
1071*7c356e86SAndroid Build Coastguard Worker 					const struct cclass *cls = cclasses;
1072*7c356e86SAndroid Build Coastguard Worker 
1073*7c356e86SAndroid Build Coastguard Worker 					/* search for name in cclass list */
1074*7c356e86SAndroid Build Coastguard Worker 					while (cls->name)
1075*7c356e86SAndroid Build Coastguard Worker 						if (!strcmp(subp, cls->name)) {
1076*7c356e86SAndroid Build Coastguard Worker 							/* found, match? */
1077*7c356e86SAndroid Build Coastguard Worker 							if (ctype(sc,
1078*7c356e86SAndroid Build Coastguard Worker 							    cls->value))
1079*7c356e86SAndroid Build Coastguard Worker 								found = true;
1080*7c356e86SAndroid Build Coastguard Worker 							/* break either way */
1081*7c356e86SAndroid Build Coastguard Worker 							break;
1082*7c356e86SAndroid Build Coastguard Worker 						} else
1083*7c356e86SAndroid Build Coastguard Worker 							++cls;
1084*7c356e86SAndroid Build Coastguard Worker 					/* that's all here */
1085*7c356e86SAndroid Build Coastguard Worker 					afree(subp, ATEMP);
1086*7c356e86SAndroid Build Coastguard Worker 					continue;
1087*7c356e86SAndroid Build Coastguard Worker 				}
1088*7c356e86SAndroid Build Coastguard Worker 				/* collating element or equivalence class */
1089*7c356e86SAndroid Build Coastguard Worker 				/* Note: latter are treated as former */
1090*7c356e86SAndroid Build Coastguard Worker 				if (ctype(subp[0], C_ASCII) && !subp[1])
1091*7c356e86SAndroid Build Coastguard Worker 					/* [.a.] where a is one ASCII char */
1092*7c356e86SAndroid Build Coastguard Worker 					c = subp[0];
1093*7c356e86SAndroid Build Coastguard Worker 				else
1094*7c356e86SAndroid Build Coastguard Worker 					/* force no match */
1095*7c356e86SAndroid Build Coastguard Worker 					c = 0;
1096*7c356e86SAndroid Build Coastguard Worker 				/* no longer needed */
1097*7c356e86SAndroid Build Coastguard Worker 				afree(subp, ATEMP);
1098*7c356e86SAndroid Build Coastguard Worker 			} else if (!ISMAGIC(c) && (c & 0x80)) {
1099*7c356e86SAndroid Build Coastguard Worker 				/* 0x80|' ' is plain (...) */
1100*7c356e86SAndroid Build Coastguard Worker 				if ((c &= 0x7F) != ' ') {
1101*7c356e86SAndroid Build Coastguard Worker 					/* check single match NOW */
1102*7c356e86SAndroid Build Coastguard Worker 					if (sc == c)
1103*7c356e86SAndroid Build Coastguard Worker 						found = true;
1104*7c356e86SAndroid Build Coastguard Worker 					/* next character is (...) */
1105*7c356e86SAndroid Build Coastguard Worker 				}
1106*7c356e86SAndroid Build Coastguard Worker 				c = '(' /*)*/;
1107*7c356e86SAndroid Build Coastguard Worker 			}
1108*7c356e86SAndroid Build Coastguard Worker 		}
1109*7c356e86SAndroid Build Coastguard Worker 		/* range expression? */
1110*7c356e86SAndroid Build Coastguard Worker 		if (!(ISMAGIC(p[0]) && ord(p[1]) == ORD('-') &&
1111*7c356e86SAndroid Build Coastguard Worker 		    /* not terminating bracket? */
1112*7c356e86SAndroid Build Coastguard Worker 		    (!ISMAGIC(p[2]) || ord(p[3]) != ORD(']')))) {
1113*7c356e86SAndroid Build Coastguard Worker 			/* no, check single match */
1114*7c356e86SAndroid Build Coastguard Worker 			if (sc == c)
1115*7c356e86SAndroid Build Coastguard Worker 				/* note: sc is never NUL */
1116*7c356e86SAndroid Build Coastguard Worker 				found = true;
1117*7c356e86SAndroid Build Coastguard Worker 			/* do the next "first" character */
1118*7c356e86SAndroid Build Coastguard Worker 			continue;
1119*7c356e86SAndroid Build Coastguard Worker 		}
1120*7c356e86SAndroid Build Coastguard Worker 		/* save lower range bound */
1121*7c356e86SAndroid Build Coastguard Worker 		lc = c;
1122*7c356e86SAndroid Build Coastguard Worker 		/* skip over the range operator */
1123*7c356e86SAndroid Build Coastguard Worker 		p += 2;
1124*7c356e86SAndroid Build Coastguard Worker 		/* do the same shit as above... almost */
1125*7c356e86SAndroid Build Coastguard Worker 		subc = 0;
1126*7c356e86SAndroid Build Coastguard Worker 		if (!(c = *p++))
1127*7c356e86SAndroid Build Coastguard Worker 			break;
1128*7c356e86SAndroid Build Coastguard Worker 		/* non-regular character? */
1129*7c356e86SAndroid Build Coastguard Worker 		if (ISMAGIC(c)) {
1130*7c356e86SAndroid Build Coastguard Worker 			/* MAGIC + NUL cannot happen */
1131*7c356e86SAndroid Build Coastguard Worker 			if (!(c = *p++))
1132*7c356e86SAndroid Build Coastguard Worker 				break;
1133*7c356e86SAndroid Build Coastguard Worker 			/* sub-bracket expressions */
1134*7c356e86SAndroid Build Coastguard Worker 			if (ord(c) == ORD('[') && (
1135*7c356e86SAndroid Build Coastguard Worker 			    /* collating element? */
1136*7c356e86SAndroid Build Coastguard Worker 			    ord(*p) == ORD('.') ||
1137*7c356e86SAndroid Build Coastguard Worker 			    /* equivalence class? */
1138*7c356e86SAndroid Build Coastguard Worker 			    ord(*p) == ORD('=') ||
1139*7c356e86SAndroid Build Coastguard Worker 			    /* character class? */
1140*7c356e86SAndroid Build Coastguard Worker 			    ord(*p) == ORD(':'))) {
1141*7c356e86SAndroid Build Coastguard Worker 				/* must stop with exactly the same c */
1142*7c356e86SAndroid Build Coastguard Worker 				subc = *p++;
1143*7c356e86SAndroid Build Coastguard Worker 				/* save away start of substring */
1144*7c356e86SAndroid Build Coastguard Worker 				s = p;
1145*7c356e86SAndroid Build Coastguard Worker 				/* arbitrarily many chars in betwixt */
1146*7c356e86SAndroid Build Coastguard Worker 				while ((c = *p++))
1147*7c356e86SAndroid Build Coastguard Worker 					/* but only this sequence... */
1148*7c356e86SAndroid Build Coastguard Worker 					if (c == subc && ISMAGIC(*p) &&
1149*7c356e86SAndroid Build Coastguard Worker 					    ord(p[1]) == ORD(']')) {
1150*7c356e86SAndroid Build Coastguard Worker 						/* accept, terminate */
1151*7c356e86SAndroid Build Coastguard Worker 						p += 2;
1152*7c356e86SAndroid Build Coastguard Worker 						break;
1153*7c356e86SAndroid Build Coastguard Worker 					}
1154*7c356e86SAndroid Build Coastguard Worker 				/* EOS without: reject bracket expr */
1155*7c356e86SAndroid Build Coastguard Worker 				if (!c)
1156*7c356e86SAndroid Build Coastguard Worker 					break;
1157*7c356e86SAndroid Build Coastguard Worker 				/* debunk substring */
1158*7c356e86SAndroid Build Coastguard Worker 				strndupx(subp, s, p - s - 3, ATEMP);
1159*7c356e86SAndroid Build Coastguard Worker 				debunk(subp, subp, p - s - 3 + 1);
1160*7c356e86SAndroid Build Coastguard Worker 				/* whither subexpression */
1161*7c356e86SAndroid Build Coastguard Worker 				if (ord(subc) == ORD(':')) {
1162*7c356e86SAndroid Build Coastguard Worker 					/* oops, not a range */
1163*7c356e86SAndroid Build Coastguard Worker 
1164*7c356e86SAndroid Build Coastguard Worker 					/* match single previous char */
1165*7c356e86SAndroid Build Coastguard Worker 					if (lc && (sc == lc))
1166*7c356e86SAndroid Build Coastguard Worker 						found = true;
1167*7c356e86SAndroid Build Coastguard Worker 					/* match hyphen-minus */
1168*7c356e86SAndroid Build Coastguard Worker 					if (ord(sc) == ORD('-'))
1169*7c356e86SAndroid Build Coastguard Worker 						found = true;
1170*7c356e86SAndroid Build Coastguard Worker 					/* handle cclass common part */
1171*7c356e86SAndroid Build Coastguard Worker 					goto cclass_common;
1172*7c356e86SAndroid Build Coastguard Worker 				}
1173*7c356e86SAndroid Build Coastguard Worker 				/* collating element or equivalence class */
1174*7c356e86SAndroid Build Coastguard Worker 				/* Note: latter are treated as former */
1175*7c356e86SAndroid Build Coastguard Worker 				if (ctype(subp[0], C_ASCII) && !subp[1])
1176*7c356e86SAndroid Build Coastguard Worker 					/* [.a.] where a is one ASCII char */
1177*7c356e86SAndroid Build Coastguard Worker 					c = subp[0];
1178*7c356e86SAndroid Build Coastguard Worker 				else
1179*7c356e86SAndroid Build Coastguard Worker 					/* force no match */
1180*7c356e86SAndroid Build Coastguard Worker 					c = 0;
1181*7c356e86SAndroid Build Coastguard Worker 				/* no longer needed */
1182*7c356e86SAndroid Build Coastguard Worker 				afree(subp, ATEMP);
1183*7c356e86SAndroid Build Coastguard Worker 				/* other meaning below */
1184*7c356e86SAndroid Build Coastguard Worker 				subc = 0;
1185*7c356e86SAndroid Build Coastguard Worker 			} else if (c == (0x80 | ' ')) {
1186*7c356e86SAndroid Build Coastguard Worker 				/* 0x80|' ' is plain (...) */
1187*7c356e86SAndroid Build Coastguard Worker 				c = '(' /*)*/;
1188*7c356e86SAndroid Build Coastguard Worker 			} else if (!ISMAGIC(c) && (c & 0x80)) {
1189*7c356e86SAndroid Build Coastguard Worker 				c &= 0x7F;
1190*7c356e86SAndroid Build Coastguard Worker 				subc = '(' /*)*/;
1191*7c356e86SAndroid Build Coastguard Worker 			}
1192*7c356e86SAndroid Build Coastguard Worker 		}
1193*7c356e86SAndroid Build Coastguard Worker 		/* now do the actual range match check */
1194*7c356e86SAndroid Build Coastguard Worker 		if (lc != 0 /* && c != 0 */ &&
1195*7c356e86SAndroid Build Coastguard Worker 		    asciibetical(lc) <= asciibetical(sc) &&
1196*7c356e86SAndroid Build Coastguard Worker 		    asciibetical(sc) <= asciibetical(c))
1197*7c356e86SAndroid Build Coastguard Worker 			found = true;
1198*7c356e86SAndroid Build Coastguard Worker 		/* forced next character? */
1199*7c356e86SAndroid Build Coastguard Worker 		if (subc) {
1200*7c356e86SAndroid Build Coastguard Worker 			c = subc;
1201*7c356e86SAndroid Build Coastguard Worker 			goto nextc;
1202*7c356e86SAndroid Build Coastguard Worker 		}
1203*7c356e86SAndroid Build Coastguard Worker 		/* otherwise, just go on with the pattern string */
1204*7c356e86SAndroid Build Coastguard Worker 	}
1205*7c356e86SAndroid Build Coastguard Worker 	/* if we broke here, the bracket expression was invalid */
1206*7c356e86SAndroid Build Coastguard Worker 	if (ord(sc) == ORD('['))
1207*7c356e86SAndroid Build Coastguard Worker 		/* initial opening bracket as literal match */
1208*7c356e86SAndroid Build Coastguard Worker 		return (pat);
1209*7c356e86SAndroid Build Coastguard Worker 	/* or rather no match */
1210*7c356e86SAndroid Build Coastguard Worker 	return (NULL);
1211*7c356e86SAndroid Build Coastguard Worker }
1212*7c356e86SAndroid Build Coastguard Worker 
1213*7c356e86SAndroid Build Coastguard Worker /* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
1214*7c356e86SAndroid Build Coastguard Worker static const unsigned char *
pat_scan(const unsigned char * p,const unsigned char * pe,bool match_sep)1215*7c356e86SAndroid Build Coastguard Worker pat_scan(const unsigned char *p, const unsigned char *pe, bool match_sep)
1216*7c356e86SAndroid Build Coastguard Worker {
1217*7c356e86SAndroid Build Coastguard Worker 	int nest = 0;
1218*7c356e86SAndroid Build Coastguard Worker 
1219*7c356e86SAndroid Build Coastguard Worker 	for (; p < pe; p++) {
1220*7c356e86SAndroid Build Coastguard Worker 		if (!ISMAGIC(*p))
1221*7c356e86SAndroid Build Coastguard Worker 			continue;
1222*7c356e86SAndroid Build Coastguard Worker 		if ((*++p == /*(*/ ')' && nest-- == 0) ||
1223*7c356e86SAndroid Build Coastguard Worker 		    (*p == '|' && match_sep && nest == 0))
1224*7c356e86SAndroid Build Coastguard Worker 			return (p + 1);
1225*7c356e86SAndroid Build Coastguard Worker 		if ((*p & 0x80) && ctype(*p & 0x7F, C_PATMO | C_SPC))
1226*7c356e86SAndroid Build Coastguard Worker 			nest++;
1227*7c356e86SAndroid Build Coastguard Worker 	}
1228*7c356e86SAndroid Build Coastguard Worker 	return (NULL);
1229*7c356e86SAndroid Build Coastguard Worker }
1230*7c356e86SAndroid Build Coastguard Worker 
1231*7c356e86SAndroid Build Coastguard Worker int
ascstrcmp(const void * s1,const void * s2)1232*7c356e86SAndroid Build Coastguard Worker ascstrcmp(const void *s1, const void *s2)
1233*7c356e86SAndroid Build Coastguard Worker {
1234*7c356e86SAndroid Build Coastguard Worker 	const uint8_t *cp1 = s1, *cp2 = s2;
1235*7c356e86SAndroid Build Coastguard Worker 
1236*7c356e86SAndroid Build Coastguard Worker 	while (*cp1 == *cp2) {
1237*7c356e86SAndroid Build Coastguard Worker 		if (*cp1++ == '\0')
1238*7c356e86SAndroid Build Coastguard Worker 			return (0);
1239*7c356e86SAndroid Build Coastguard Worker 		++cp2;
1240*7c356e86SAndroid Build Coastguard Worker 	}
1241*7c356e86SAndroid Build Coastguard Worker 	return ((int)asciibetical(*cp1) - (int)asciibetical(*cp2));
1242*7c356e86SAndroid Build Coastguard Worker }
1243*7c356e86SAndroid Build Coastguard Worker 
1244*7c356e86SAndroid Build Coastguard Worker int
ascpstrcmp(const void * pstr1,const void * pstr2)1245*7c356e86SAndroid Build Coastguard Worker ascpstrcmp(const void *pstr1, const void *pstr2)
1246*7c356e86SAndroid Build Coastguard Worker {
1247*7c356e86SAndroid Build Coastguard Worker 	return (ascstrcmp(*(const char * const *)pstr1,
1248*7c356e86SAndroid Build Coastguard Worker 	    *(const char * const *)pstr2));
1249*7c356e86SAndroid Build Coastguard Worker }
1250*7c356e86SAndroid Build Coastguard Worker 
1251*7c356e86SAndroid Build Coastguard Worker /* Initialise a Getopt structure */
1252*7c356e86SAndroid Build Coastguard Worker void
ksh_getopt_reset(Getopt * go,int flags)1253*7c356e86SAndroid Build Coastguard Worker ksh_getopt_reset(Getopt *go, int flags)
1254*7c356e86SAndroid Build Coastguard Worker {
1255*7c356e86SAndroid Build Coastguard Worker 	go->optind = 1;
1256*7c356e86SAndroid Build Coastguard Worker 	go->optarg = NULL;
1257*7c356e86SAndroid Build Coastguard Worker 	go->p = 0;
1258*7c356e86SAndroid Build Coastguard Worker 	go->flags = flags;
1259*7c356e86SAndroid Build Coastguard Worker 	go->info = 0;
1260*7c356e86SAndroid Build Coastguard Worker 	go->buf[1] = '\0';
1261*7c356e86SAndroid Build Coastguard Worker }
1262*7c356e86SAndroid Build Coastguard Worker 
1263*7c356e86SAndroid Build Coastguard Worker 
1264*7c356e86SAndroid Build Coastguard Worker /**
1265*7c356e86SAndroid Build Coastguard Worker  * getopt() used for shell built-in commands, the getopts command, and
1266*7c356e86SAndroid Build Coastguard Worker  * command line options.
1267*7c356e86SAndroid Build Coastguard Worker  * A leading ':' in options means don't print errors, instead return '?'
1268*7c356e86SAndroid Build Coastguard Worker  * or ':' and set go->optarg to the offending option character.
1269*7c356e86SAndroid Build Coastguard Worker  * If GF_ERROR is set (and option doesn't start with :), errors result in
1270*7c356e86SAndroid Build Coastguard Worker  * a call to bi_errorf().
1271*7c356e86SAndroid Build Coastguard Worker  *
1272*7c356e86SAndroid Build Coastguard Worker  * Non-standard features:
1273*7c356e86SAndroid Build Coastguard Worker  *	- ';' is like ':' in options, except the argument is optional
1274*7c356e86SAndroid Build Coastguard Worker  *	  (if it isn't present, optarg is set to 0).
1275*7c356e86SAndroid Build Coastguard Worker  *	  Used for 'set -o'.
1276*7c356e86SAndroid Build Coastguard Worker  *	- ',' is like ':' in options, except the argument always immediately
1277*7c356e86SAndroid Build Coastguard Worker  *	  follows the option character (optarg is set to the null string if
1278*7c356e86SAndroid Build Coastguard Worker  *	  the option is missing).
1279*7c356e86SAndroid Build Coastguard Worker  *	  Used for 'read -u2', 'print -u2' and fc -40.
1280*7c356e86SAndroid Build Coastguard Worker  *	- '#' is like ':' in options, expect that the argument is optional
1281*7c356e86SAndroid Build Coastguard Worker  *	  and must start with a digit. If the argument doesn't start with a
1282*7c356e86SAndroid Build Coastguard Worker  *	  digit, it is assumed to be missing and normal option processing
1283*7c356e86SAndroid Build Coastguard Worker  *	  continues (optarg is set to 0 if the option is missing).
1284*7c356e86SAndroid Build Coastguard Worker  *	  Used for 'typeset -LZ4'.
1285*7c356e86SAndroid Build Coastguard Worker  *	- accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an
1286*7c356e86SAndroid Build Coastguard Worker  *	  option starting with + is accepted, the GI_PLUS flag will be set
1287*7c356e86SAndroid Build Coastguard Worker  *	  in go->info.
1288*7c356e86SAndroid Build Coastguard Worker  */
1289*7c356e86SAndroid Build Coastguard Worker int
ksh_getopt(const char ** argv,Getopt * go,const char * optionsp)1290*7c356e86SAndroid Build Coastguard Worker ksh_getopt(const char **argv, Getopt *go, const char *optionsp)
1291*7c356e86SAndroid Build Coastguard Worker {
1292*7c356e86SAndroid Build Coastguard Worker 	char c;
1293*7c356e86SAndroid Build Coastguard Worker 	const char *o;
1294*7c356e86SAndroid Build Coastguard Worker 
1295*7c356e86SAndroid Build Coastguard Worker 	if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') {
1296*7c356e86SAndroid Build Coastguard Worker 		const char *arg = argv[go->optind], flag = arg ? *arg : '\0';
1297*7c356e86SAndroid Build Coastguard Worker 
1298*7c356e86SAndroid Build Coastguard Worker 		go->p = 1;
1299*7c356e86SAndroid Build Coastguard Worker 		if (flag == '-' && ksh_isdash(arg + 1)) {
1300*7c356e86SAndroid Build Coastguard Worker 			go->optind++;
1301*7c356e86SAndroid Build Coastguard Worker 			go->p = 0;
1302*7c356e86SAndroid Build Coastguard Worker 			go->info |= GI_MINUSMINUS;
1303*7c356e86SAndroid Build Coastguard Worker 			return (-1);
1304*7c356e86SAndroid Build Coastguard Worker 		}
1305*7c356e86SAndroid Build Coastguard Worker 		if (arg == NULL ||
1306*7c356e86SAndroid Build Coastguard Worker 		    ((flag != '-' ) &&
1307*7c356e86SAndroid Build Coastguard Worker 		    /* neither a - nor a + (if + allowed) */
1308*7c356e86SAndroid Build Coastguard Worker 		    (!(go->flags & GF_PLUSOPT) || flag != '+')) ||
1309*7c356e86SAndroid Build Coastguard Worker 		    (c = arg[1]) == '\0') {
1310*7c356e86SAndroid Build Coastguard Worker 			go->p = 0;
1311*7c356e86SAndroid Build Coastguard Worker 			return (-1);
1312*7c356e86SAndroid Build Coastguard Worker 		}
1313*7c356e86SAndroid Build Coastguard Worker 		go->optind++;
1314*7c356e86SAndroid Build Coastguard Worker 		go->info &= ~(GI_MINUS|GI_PLUS);
1315*7c356e86SAndroid Build Coastguard Worker 		go->info |= flag == '-' ? GI_MINUS : GI_PLUS;
1316*7c356e86SAndroid Build Coastguard Worker 	}
1317*7c356e86SAndroid Build Coastguard Worker 	go->p++;
1318*7c356e86SAndroid Build Coastguard Worker 	if (ctype(c, C_QUEST | C_COLON | C_HASH) || c == ';' || c == ',' ||
1319*7c356e86SAndroid Build Coastguard Worker 	    !(o = cstrchr(optionsp, c))) {
1320*7c356e86SAndroid Build Coastguard Worker 		if (optionsp[0] == ':') {
1321*7c356e86SAndroid Build Coastguard Worker 			go->buf[0] = c;
1322*7c356e86SAndroid Build Coastguard Worker 			go->optarg = go->buf;
1323*7c356e86SAndroid Build Coastguard Worker 		} else {
1324*7c356e86SAndroid Build Coastguard Worker 			warningf(true, Tf_optfoo,
1325*7c356e86SAndroid Build Coastguard Worker 			    (go->flags & GF_NONAME) ? "" : argv[0],
1326*7c356e86SAndroid Build Coastguard Worker 			    (go->flags & GF_NONAME) ? "" : Tcolsp,
1327*7c356e86SAndroid Build Coastguard Worker 			    c, Tunknown_option);
1328*7c356e86SAndroid Build Coastguard Worker 			if (go->flags & GF_ERROR)
1329*7c356e86SAndroid Build Coastguard Worker 				bi_errorfz();
1330*7c356e86SAndroid Build Coastguard Worker 		}
1331*7c356e86SAndroid Build Coastguard Worker 		return (ORD('?'));
1332*7c356e86SAndroid Build Coastguard Worker 	}
1333*7c356e86SAndroid Build Coastguard Worker 	/**
1334*7c356e86SAndroid Build Coastguard Worker 	 * : means argument must be present, may be part of option argument
1335*7c356e86SAndroid Build Coastguard Worker 	 *   or the next argument
1336*7c356e86SAndroid Build Coastguard Worker 	 * ; same as : but argument may be missing
1337*7c356e86SAndroid Build Coastguard Worker 	 * , means argument is part of option argument, and may be null.
1338*7c356e86SAndroid Build Coastguard Worker 	 */
1339*7c356e86SAndroid Build Coastguard Worker 	if (*++o == ':' || *o == ';') {
1340*7c356e86SAndroid Build Coastguard Worker 		if (argv[go->optind - 1][go->p])
1341*7c356e86SAndroid Build Coastguard Worker 			go->optarg = argv[go->optind - 1] + go->p;
1342*7c356e86SAndroid Build Coastguard Worker 		else if (argv[go->optind])
1343*7c356e86SAndroid Build Coastguard Worker 			go->optarg = argv[go->optind++];
1344*7c356e86SAndroid Build Coastguard Worker 		else if (*o == ';')
1345*7c356e86SAndroid Build Coastguard Worker 			go->optarg = NULL;
1346*7c356e86SAndroid Build Coastguard Worker 		else {
1347*7c356e86SAndroid Build Coastguard Worker 			if (optionsp[0] == ':') {
1348*7c356e86SAndroid Build Coastguard Worker 				go->buf[0] = c;
1349*7c356e86SAndroid Build Coastguard Worker 				go->optarg = go->buf;
1350*7c356e86SAndroid Build Coastguard Worker 				return (ORD(':'));
1351*7c356e86SAndroid Build Coastguard Worker 			}
1352*7c356e86SAndroid Build Coastguard Worker 			warningf(true, Tf_optfoo,
1353*7c356e86SAndroid Build Coastguard Worker 			    (go->flags & GF_NONAME) ? "" : argv[0],
1354*7c356e86SAndroid Build Coastguard Worker 			    (go->flags & GF_NONAME) ? "" : Tcolsp,
1355*7c356e86SAndroid Build Coastguard Worker 			    c, Treq_arg);
1356*7c356e86SAndroid Build Coastguard Worker 			if (go->flags & GF_ERROR)
1357*7c356e86SAndroid Build Coastguard Worker 				bi_errorfz();
1358*7c356e86SAndroid Build Coastguard Worker 			return (ORD('?'));
1359*7c356e86SAndroid Build Coastguard Worker 		}
1360*7c356e86SAndroid Build Coastguard Worker 		go->p = 0;
1361*7c356e86SAndroid Build Coastguard Worker 	} else if (*o == ',') {
1362*7c356e86SAndroid Build Coastguard Worker 		/* argument is attached to option character, even if null */
1363*7c356e86SAndroid Build Coastguard Worker 		go->optarg = argv[go->optind - 1] + go->p;
1364*7c356e86SAndroid Build Coastguard Worker 		go->p = 0;
1365*7c356e86SAndroid Build Coastguard Worker 	} else if (*o == '#') {
1366*7c356e86SAndroid Build Coastguard Worker 		/*
1367*7c356e86SAndroid Build Coastguard Worker 		 * argument is optional and may be attached or unattached
1368*7c356e86SAndroid Build Coastguard Worker 		 * but must start with a digit. optarg is set to 0 if the
1369*7c356e86SAndroid Build Coastguard Worker 		 * argument is missing.
1370*7c356e86SAndroid Build Coastguard Worker 		 */
1371*7c356e86SAndroid Build Coastguard Worker 		if (argv[go->optind - 1][go->p]) {
1372*7c356e86SAndroid Build Coastguard Worker 			if (ctype(argv[go->optind - 1][go->p], C_DIGIT)) {
1373*7c356e86SAndroid Build Coastguard Worker 				go->optarg = argv[go->optind - 1] + go->p;
1374*7c356e86SAndroid Build Coastguard Worker 				go->p = 0;
1375*7c356e86SAndroid Build Coastguard Worker 			} else
1376*7c356e86SAndroid Build Coastguard Worker 				go->optarg = NULL;
1377*7c356e86SAndroid Build Coastguard Worker 		} else {
1378*7c356e86SAndroid Build Coastguard Worker 			if (argv[go->optind] &&
1379*7c356e86SAndroid Build Coastguard Worker 			    ctype(argv[go->optind][0], C_DIGIT)) {
1380*7c356e86SAndroid Build Coastguard Worker 				go->optarg = argv[go->optind++];
1381*7c356e86SAndroid Build Coastguard Worker 				go->p = 0;
1382*7c356e86SAndroid Build Coastguard Worker 			} else
1383*7c356e86SAndroid Build Coastguard Worker 				go->optarg = NULL;
1384*7c356e86SAndroid Build Coastguard Worker 		}
1385*7c356e86SAndroid Build Coastguard Worker 	}
1386*7c356e86SAndroid Build Coastguard Worker 	return (ord(c));
1387*7c356e86SAndroid Build Coastguard Worker }
1388*7c356e86SAndroid Build Coastguard Worker 
1389*7c356e86SAndroid Build Coastguard Worker /*
1390*7c356e86SAndroid Build Coastguard Worker  * print variable/alias value using necessary quotes
1391*7c356e86SAndroid Build Coastguard Worker  * (POSIX says they should be suitable for re-entry...)
1392*7c356e86SAndroid Build Coastguard Worker  * No trailing newline is printed.
1393*7c356e86SAndroid Build Coastguard Worker  */
1394*7c356e86SAndroid Build Coastguard Worker void
print_value_quoted(struct shf * shf,const char * s)1395*7c356e86SAndroid Build Coastguard Worker print_value_quoted(struct shf *shf, const char *s)
1396*7c356e86SAndroid Build Coastguard Worker {
1397*7c356e86SAndroid Build Coastguard Worker 	unsigned char c;
1398*7c356e86SAndroid Build Coastguard Worker 	const unsigned char *p = (const unsigned char *)s;
1399*7c356e86SAndroid Build Coastguard Worker 	bool inquote = true;
1400*7c356e86SAndroid Build Coastguard Worker 
1401*7c356e86SAndroid Build Coastguard Worker 	/* first, special-case empty strings (for re-entrancy) */
1402*7c356e86SAndroid Build Coastguard Worker 	if (!*s) {
1403*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\'', shf);
1404*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\'', shf);
1405*7c356e86SAndroid Build Coastguard Worker 		return;
1406*7c356e86SAndroid Build Coastguard Worker 	}
1407*7c356e86SAndroid Build Coastguard Worker 
1408*7c356e86SAndroid Build Coastguard Worker 	/* non-empty; check whether any quotes are needed */
1409*7c356e86SAndroid Build Coastguard Worker 	while (rtt2asc(c = *p++) >= 32)
1410*7c356e86SAndroid Build Coastguard Worker 		if (ctype(c, C_QUOTE | C_SPC))
1411*7c356e86SAndroid Build Coastguard Worker 			inquote = false;
1412*7c356e86SAndroid Build Coastguard Worker 
1413*7c356e86SAndroid Build Coastguard Worker 	p = (const unsigned char *)s;
1414*7c356e86SAndroid Build Coastguard Worker 	if (c == 0) {
1415*7c356e86SAndroid Build Coastguard Worker 		if (inquote) {
1416*7c356e86SAndroid Build Coastguard Worker 			/* nope, use the shortcut */
1417*7c356e86SAndroid Build Coastguard Worker 			shf_puts(s, shf);
1418*7c356e86SAndroid Build Coastguard Worker 			return;
1419*7c356e86SAndroid Build Coastguard Worker 		}
1420*7c356e86SAndroid Build Coastguard Worker 
1421*7c356e86SAndroid Build Coastguard Worker 		/* otherwise, quote nicely via state machine */
1422*7c356e86SAndroid Build Coastguard Worker 		while ((c = *p++) != 0) {
1423*7c356e86SAndroid Build Coastguard Worker 			if (c == '\'') {
1424*7c356e86SAndroid Build Coastguard Worker 				/*
1425*7c356e86SAndroid Build Coastguard Worker 				 * multiple single quotes or any of them
1426*7c356e86SAndroid Build Coastguard Worker 				 * at the beginning of a string look nicer
1427*7c356e86SAndroid Build Coastguard Worker 				 * this way than when simply substituting
1428*7c356e86SAndroid Build Coastguard Worker 				 */
1429*7c356e86SAndroid Build Coastguard Worker 				if (inquote) {
1430*7c356e86SAndroid Build Coastguard Worker 					shf_putc('\'', shf);
1431*7c356e86SAndroid Build Coastguard Worker 					inquote = false;
1432*7c356e86SAndroid Build Coastguard Worker 				}
1433*7c356e86SAndroid Build Coastguard Worker 				shf_putc('\\', shf);
1434*7c356e86SAndroid Build Coastguard Worker 			} else if (!inquote) {
1435*7c356e86SAndroid Build Coastguard Worker 				shf_putc('\'', shf);
1436*7c356e86SAndroid Build Coastguard Worker 				inquote = true;
1437*7c356e86SAndroid Build Coastguard Worker 			}
1438*7c356e86SAndroid Build Coastguard Worker 			shf_putc(c, shf);
1439*7c356e86SAndroid Build Coastguard Worker 		}
1440*7c356e86SAndroid Build Coastguard Worker 	} else {
1441*7c356e86SAndroid Build Coastguard Worker 		unsigned int wc;
1442*7c356e86SAndroid Build Coastguard Worker 		size_t n;
1443*7c356e86SAndroid Build Coastguard Worker 
1444*7c356e86SAndroid Build Coastguard Worker 		/* use $'...' quote format */
1445*7c356e86SAndroid Build Coastguard Worker 		shf_putc('$', shf);
1446*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\'', shf);
1447*7c356e86SAndroid Build Coastguard Worker 		while ((c = *p) != 0) {
1448*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH_EBCDIC
1449*7c356e86SAndroid Build Coastguard Worker 			if (c >= 0xC2) {
1450*7c356e86SAndroid Build Coastguard Worker 				n = utf_mbtowc(&wc, (const char *)p);
1451*7c356e86SAndroid Build Coastguard Worker 				if (n != (size_t)-1) {
1452*7c356e86SAndroid Build Coastguard Worker 					p += n;
1453*7c356e86SAndroid Build Coastguard Worker 					shf_fprintf(shf, "\\u%04X", wc);
1454*7c356e86SAndroid Build Coastguard Worker 					continue;
1455*7c356e86SAndroid Build Coastguard Worker 				}
1456*7c356e86SAndroid Build Coastguard Worker 			}
1457*7c356e86SAndroid Build Coastguard Worker #endif
1458*7c356e86SAndroid Build Coastguard Worker 			++p;
1459*7c356e86SAndroid Build Coastguard Worker 			switch (c) {
1460*7c356e86SAndroid Build Coastguard Worker 			/* see unbksl() in this file for comments */
1461*7c356e86SAndroid Build Coastguard Worker 			case KSH_BEL:
1462*7c356e86SAndroid Build Coastguard Worker 				c = 'a';
1463*7c356e86SAndroid Build Coastguard Worker 				if (0)
1464*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1465*7c356e86SAndroid Build Coastguard Worker 			case '\b':
1466*7c356e86SAndroid Build Coastguard Worker 				  c = 'b';
1467*7c356e86SAndroid Build Coastguard Worker 				if (0)
1468*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1469*7c356e86SAndroid Build Coastguard Worker 			case '\f':
1470*7c356e86SAndroid Build Coastguard Worker 				  c = 'f';
1471*7c356e86SAndroid Build Coastguard Worker 				if (0)
1472*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1473*7c356e86SAndroid Build Coastguard Worker 			case '\n':
1474*7c356e86SAndroid Build Coastguard Worker 				  c = 'n';
1475*7c356e86SAndroid Build Coastguard Worker 				if (0)
1476*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1477*7c356e86SAndroid Build Coastguard Worker 			case '\r':
1478*7c356e86SAndroid Build Coastguard Worker 				  c = 'r';
1479*7c356e86SAndroid Build Coastguard Worker 				if (0)
1480*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1481*7c356e86SAndroid Build Coastguard Worker 			case '\t':
1482*7c356e86SAndroid Build Coastguard Worker 				  c = 't';
1483*7c356e86SAndroid Build Coastguard Worker 				if (0)
1484*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1485*7c356e86SAndroid Build Coastguard Worker 			case KSH_VTAB:
1486*7c356e86SAndroid Build Coastguard Worker 				  c = 'v';
1487*7c356e86SAndroid Build Coastguard Worker 				if (0)
1488*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1489*7c356e86SAndroid Build Coastguard Worker 			case KSH_ESC:
1490*7c356e86SAndroid Build Coastguard Worker 				/* take E not e because \e is \ in *roff */
1491*7c356e86SAndroid Build Coastguard Worker 				  c = 'E';
1492*7c356e86SAndroid Build Coastguard Worker 				/* FALLTHROUGH */
1493*7c356e86SAndroid Build Coastguard Worker 			case '\\':
1494*7c356e86SAndroid Build Coastguard Worker 				shf_putc('\\', shf);
1495*7c356e86SAndroid Build Coastguard Worker 
1496*7c356e86SAndroid Build Coastguard Worker 				if (0)
1497*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1498*7c356e86SAndroid Build Coastguard Worker 			default:
1499*7c356e86SAndroid Build Coastguard Worker #if defined(MKSH_EBCDIC) || defined(MKSH_FAUX_EBCDIC)
1500*7c356e86SAndroid Build Coastguard Worker 				  if (ksh_isctrl(c))
1501*7c356e86SAndroid Build Coastguard Worker #else
1502*7c356e86SAndroid Build Coastguard Worker 				  if (!ctype(c, C_PRINT))
1503*7c356e86SAndroid Build Coastguard Worker #endif
1504*7c356e86SAndroid Build Coastguard Worker 				    {
1505*7c356e86SAndroid Build Coastguard Worker 					/* FALLTHROUGH */
1506*7c356e86SAndroid Build Coastguard Worker 			case '\'':
1507*7c356e86SAndroid Build Coastguard Worker 					shf_fprintf(shf, "\\%03o", c);
1508*7c356e86SAndroid Build Coastguard Worker 					break;
1509*7c356e86SAndroid Build Coastguard Worker 				}
1510*7c356e86SAndroid Build Coastguard Worker 
1511*7c356e86SAndroid Build Coastguard Worker 				shf_putc(c, shf);
1512*7c356e86SAndroid Build Coastguard Worker 				break;
1513*7c356e86SAndroid Build Coastguard Worker 			}
1514*7c356e86SAndroid Build Coastguard Worker 		}
1515*7c356e86SAndroid Build Coastguard Worker 		inquote = true;
1516*7c356e86SAndroid Build Coastguard Worker 	}
1517*7c356e86SAndroid Build Coastguard Worker 	if (inquote)
1518*7c356e86SAndroid Build Coastguard Worker 		shf_putc('\'', shf);
1519*7c356e86SAndroid Build Coastguard Worker }
1520*7c356e86SAndroid Build Coastguard Worker 
1521*7c356e86SAndroid Build Coastguard Worker /*
1522*7c356e86SAndroid Build Coastguard Worker  * Print things in columns and rows - func() is called to format
1523*7c356e86SAndroid Build Coastguard Worker  * the i-th element
1524*7c356e86SAndroid Build Coastguard Worker  */
1525*7c356e86SAndroid Build Coastguard Worker void
print_columns(struct columnise_opts * opts,unsigned int n,void (* func)(char *,size_t,unsigned int,const void *),const void * arg,size_t max_oct,size_t max_colz)1526*7c356e86SAndroid Build Coastguard Worker print_columns(struct columnise_opts *opts, unsigned int n,
1527*7c356e86SAndroid Build Coastguard Worker     void (*func)(char *, size_t, unsigned int, const void *),
1528*7c356e86SAndroid Build Coastguard Worker     const void *arg, size_t max_oct, size_t max_colz)
1529*7c356e86SAndroid Build Coastguard Worker {
1530*7c356e86SAndroid Build Coastguard Worker 	unsigned int i, r = 0, c, rows, cols, nspace, max_col;
1531*7c356e86SAndroid Build Coastguard Worker 	char *str;
1532*7c356e86SAndroid Build Coastguard Worker 
1533*7c356e86SAndroid Build Coastguard Worker 	if (!n)
1534*7c356e86SAndroid Build Coastguard Worker 		return;
1535*7c356e86SAndroid Build Coastguard Worker 
1536*7c356e86SAndroid Build Coastguard Worker 	if (max_colz > 2147483646) {
1537*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH_SMALL
1538*7c356e86SAndroid Build Coastguard Worker 		internal_warningf("print_columns called with %s=%zu >= INT_MAX",
1539*7c356e86SAndroid Build Coastguard Worker 		    "max_col", max_colz);
1540*7c356e86SAndroid Build Coastguard Worker #endif
1541*7c356e86SAndroid Build Coastguard Worker 		return;
1542*7c356e86SAndroid Build Coastguard Worker 	}
1543*7c356e86SAndroid Build Coastguard Worker 	max_col = (unsigned int)max_colz;
1544*7c356e86SAndroid Build Coastguard Worker 
1545*7c356e86SAndroid Build Coastguard Worker 	if (max_oct > 2147483646) {
1546*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH_SMALL
1547*7c356e86SAndroid Build Coastguard Worker 		internal_warningf("print_columns called with %s=%zu >= INT_MAX",
1548*7c356e86SAndroid Build Coastguard Worker 		    "max_oct", max_oct);
1549*7c356e86SAndroid Build Coastguard Worker #endif
1550*7c356e86SAndroid Build Coastguard Worker 		return;
1551*7c356e86SAndroid Build Coastguard Worker 	}
1552*7c356e86SAndroid Build Coastguard Worker 	++max_oct;
1553*7c356e86SAndroid Build Coastguard Worker 	str = alloc(max_oct, ATEMP);
1554*7c356e86SAndroid Build Coastguard Worker 
1555*7c356e86SAndroid Build Coastguard Worker 	/*
1556*7c356e86SAndroid Build Coastguard Worker 	 * We use (max_col + 2) to consider the separator space.
1557*7c356e86SAndroid Build Coastguard Worker 	 * Note that no spaces are printed after the last column
1558*7c356e86SAndroid Build Coastguard Worker 	 * to avoid problems with terminals that have auto-wrap,
1559*7c356e86SAndroid Build Coastguard Worker 	 * but we need to also take this into account in x_cols.
1560*7c356e86SAndroid Build Coastguard Worker 	 */
1561*7c356e86SAndroid Build Coastguard Worker 	cols = (x_cols + 1) / (max_col + 2);
1562*7c356e86SAndroid Build Coastguard Worker 
1563*7c356e86SAndroid Build Coastguard Worker 	/* if we can only print one column anyway, skip the goo */
1564*7c356e86SAndroid Build Coastguard Worker 	if (cols < 2) {
1565*7c356e86SAndroid Build Coastguard Worker 		goto prcols_easy;
1566*7c356e86SAndroid Build Coastguard Worker 		while (r < n) {
1567*7c356e86SAndroid Build Coastguard Worker 			shf_putc(opts->linesep, opts->shf);
1568*7c356e86SAndroid Build Coastguard Worker  prcols_easy:
1569*7c356e86SAndroid Build Coastguard Worker 			(*func)(str, max_oct, r++, arg);
1570*7c356e86SAndroid Build Coastguard Worker 			shf_puts(str, opts->shf);
1571*7c356e86SAndroid Build Coastguard Worker 		}
1572*7c356e86SAndroid Build Coastguard Worker 		goto out;
1573*7c356e86SAndroid Build Coastguard Worker 	}
1574*7c356e86SAndroid Build Coastguard Worker 
1575*7c356e86SAndroid Build Coastguard Worker 	rows = (n + cols - 1) / cols;
1576*7c356e86SAndroid Build Coastguard Worker 	if (opts->prefcol && cols > rows) {
1577*7c356e86SAndroid Build Coastguard Worker 		cols = rows;
1578*7c356e86SAndroid Build Coastguard Worker 		rows = (n + cols - 1) / cols;
1579*7c356e86SAndroid Build Coastguard Worker 	}
1580*7c356e86SAndroid Build Coastguard Worker 
1581*7c356e86SAndroid Build Coastguard Worker 	nspace = (x_cols - max_col * cols) / cols;
1582*7c356e86SAndroid Build Coastguard Worker 	if (nspace < 2)
1583*7c356e86SAndroid Build Coastguard Worker 		nspace = 2;
1584*7c356e86SAndroid Build Coastguard Worker 	max_col = -max_col;
1585*7c356e86SAndroid Build Coastguard Worker 	goto prcols_hard;
1586*7c356e86SAndroid Build Coastguard Worker 	while (r < rows) {
1587*7c356e86SAndroid Build Coastguard Worker 		shf_putchar(opts->linesep, opts->shf);
1588*7c356e86SAndroid Build Coastguard Worker  prcols_hard:
1589*7c356e86SAndroid Build Coastguard Worker 		for (c = 0; c < cols; c++) {
1590*7c356e86SAndroid Build Coastguard Worker 			if ((i = c * rows + r) >= n)
1591*7c356e86SAndroid Build Coastguard Worker 				break;
1592*7c356e86SAndroid Build Coastguard Worker 			(*func)(str, max_oct, i, arg);
1593*7c356e86SAndroid Build Coastguard Worker 			if (i + rows >= n)
1594*7c356e86SAndroid Build Coastguard Worker 				shf_puts(str, opts->shf);
1595*7c356e86SAndroid Build Coastguard Worker 			else
1596*7c356e86SAndroid Build Coastguard Worker 				shf_fprintf(opts->shf, "%*s%*s",
1597*7c356e86SAndroid Build Coastguard Worker 				    (int)max_col, str, (int)nspace, null);
1598*7c356e86SAndroid Build Coastguard Worker 		}
1599*7c356e86SAndroid Build Coastguard Worker 		++r;
1600*7c356e86SAndroid Build Coastguard Worker 	}
1601*7c356e86SAndroid Build Coastguard Worker  out:
1602*7c356e86SAndroid Build Coastguard Worker 	if (opts->do_last)
1603*7c356e86SAndroid Build Coastguard Worker 		shf_putchar(opts->linesep, opts->shf);
1604*7c356e86SAndroid Build Coastguard Worker 	afree(str, ATEMP);
1605*7c356e86SAndroid Build Coastguard Worker }
1606*7c356e86SAndroid Build Coastguard Worker 
1607*7c356e86SAndroid Build Coastguard Worker /* strip all NUL bytes from buf; output is NUL-terminated if stripped */
1608*7c356e86SAndroid Build Coastguard Worker void
strip_nuls(char * buf,size_t len)1609*7c356e86SAndroid Build Coastguard Worker strip_nuls(char *buf, size_t len)
1610*7c356e86SAndroid Build Coastguard Worker {
1611*7c356e86SAndroid Build Coastguard Worker 	char *cp, *dp, *ep;
1612*7c356e86SAndroid Build Coastguard Worker 
1613*7c356e86SAndroid Build Coastguard Worker 	if (!len || !(dp = memchr(buf, '\0', len)))
1614*7c356e86SAndroid Build Coastguard Worker 		return;
1615*7c356e86SAndroid Build Coastguard Worker 
1616*7c356e86SAndroid Build Coastguard Worker 	ep = buf + len;
1617*7c356e86SAndroid Build Coastguard Worker 	cp = dp;
1618*7c356e86SAndroid Build Coastguard Worker 
1619*7c356e86SAndroid Build Coastguard Worker  cp_has_nul_byte:
1620*7c356e86SAndroid Build Coastguard Worker 	while (cp++ < ep && *cp == '\0')
1621*7c356e86SAndroid Build Coastguard Worker 		;	/* nothing */
1622*7c356e86SAndroid Build Coastguard Worker 	while (cp < ep && *cp != '\0')
1623*7c356e86SAndroid Build Coastguard Worker 		*dp++ = *cp++;
1624*7c356e86SAndroid Build Coastguard Worker 	if (cp < ep)
1625*7c356e86SAndroid Build Coastguard Worker 		goto cp_has_nul_byte;
1626*7c356e86SAndroid Build Coastguard Worker 
1627*7c356e86SAndroid Build Coastguard Worker 	*dp = '\0';
1628*7c356e86SAndroid Build Coastguard Worker }
1629*7c356e86SAndroid Build Coastguard Worker 
1630*7c356e86SAndroid Build Coastguard Worker /*
1631*7c356e86SAndroid Build Coastguard Worker  * Like read(2), but if read fails due to non-blocking flag,
1632*7c356e86SAndroid Build Coastguard Worker  * resets flag and restarts read.
1633*7c356e86SAndroid Build Coastguard Worker  */
1634*7c356e86SAndroid Build Coastguard Worker ssize_t
blocking_read(int fd,char * buf,size_t nbytes)1635*7c356e86SAndroid Build Coastguard Worker blocking_read(int fd, char *buf, size_t nbytes)
1636*7c356e86SAndroid Build Coastguard Worker {
1637*7c356e86SAndroid Build Coastguard Worker 	ssize_t ret;
1638*7c356e86SAndroid Build Coastguard Worker 	bool tried_reset = false;
1639*7c356e86SAndroid Build Coastguard Worker 
1640*7c356e86SAndroid Build Coastguard Worker 	while ((ret = read(fd, buf, nbytes)) < 0) {
1641*7c356e86SAndroid Build Coastguard Worker 		if (!tried_reset && errno == EAGAIN) {
1642*7c356e86SAndroid Build Coastguard Worker 			if (reset_nonblock(fd) > 0) {
1643*7c356e86SAndroid Build Coastguard Worker 				tried_reset = true;
1644*7c356e86SAndroid Build Coastguard Worker 				continue;
1645*7c356e86SAndroid Build Coastguard Worker 			}
1646*7c356e86SAndroid Build Coastguard Worker 			errno = EAGAIN;
1647*7c356e86SAndroid Build Coastguard Worker 		}
1648*7c356e86SAndroid Build Coastguard Worker 		break;
1649*7c356e86SAndroid Build Coastguard Worker 	}
1650*7c356e86SAndroid Build Coastguard Worker 	return (ret);
1651*7c356e86SAndroid Build Coastguard Worker }
1652*7c356e86SAndroid Build Coastguard Worker 
1653*7c356e86SAndroid Build Coastguard Worker /*
1654*7c356e86SAndroid Build Coastguard Worker  * Reset the non-blocking flag on the specified file descriptor.
1655*7c356e86SAndroid Build Coastguard Worker  * Returns -1 if there was an error, 0 if non-blocking wasn't set,
1656*7c356e86SAndroid Build Coastguard Worker  * 1 if it was.
1657*7c356e86SAndroid Build Coastguard Worker  */
1658*7c356e86SAndroid Build Coastguard Worker int
reset_nonblock(int fd)1659*7c356e86SAndroid Build Coastguard Worker reset_nonblock(int fd)
1660*7c356e86SAndroid Build Coastguard Worker {
1661*7c356e86SAndroid Build Coastguard Worker 	int flags;
1662*7c356e86SAndroid Build Coastguard Worker 
1663*7c356e86SAndroid Build Coastguard Worker 	if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
1664*7c356e86SAndroid Build Coastguard Worker 		return (-1);
1665*7c356e86SAndroid Build Coastguard Worker 	if (!(flags & O_NONBLOCK))
1666*7c356e86SAndroid Build Coastguard Worker 		return (0);
1667*7c356e86SAndroid Build Coastguard Worker 	flags &= ~O_NONBLOCK;
1668*7c356e86SAndroid Build Coastguard Worker 	if (fcntl(fd, F_SETFL, flags) < 0)
1669*7c356e86SAndroid Build Coastguard Worker 		return (-1);
1670*7c356e86SAndroid Build Coastguard Worker 	return (1);
1671*7c356e86SAndroid Build Coastguard Worker }
1672*7c356e86SAndroid Build Coastguard Worker 
1673*7c356e86SAndroid Build Coastguard Worker /* getcwd(3) equivalent, allocates from ATEMP but doesn't resize */
1674*7c356e86SAndroid Build Coastguard Worker char *
ksh_get_wd(void)1675*7c356e86SAndroid Build Coastguard Worker ksh_get_wd(void)
1676*7c356e86SAndroid Build Coastguard Worker {
1677*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH__NO_PATH_MAX
1678*7c356e86SAndroid Build Coastguard Worker 	char *rv, *cp;
1679*7c356e86SAndroid Build Coastguard Worker 
1680*7c356e86SAndroid Build Coastguard Worker 	if ((cp = get_current_dir_name())) {
1681*7c356e86SAndroid Build Coastguard Worker 		strdupx(rv, cp, ATEMP);
1682*7c356e86SAndroid Build Coastguard Worker 		free_gnu_gcdn(cp);
1683*7c356e86SAndroid Build Coastguard Worker 	} else
1684*7c356e86SAndroid Build Coastguard Worker 		rv = NULL;
1685*7c356e86SAndroid Build Coastguard Worker #else
1686*7c356e86SAndroid Build Coastguard Worker 	char *rv;
1687*7c356e86SAndroid Build Coastguard Worker 
1688*7c356e86SAndroid Build Coastguard Worker 	if (!getcwd((rv = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX)) {
1689*7c356e86SAndroid Build Coastguard Worker 		afree(rv, ATEMP);
1690*7c356e86SAndroid Build Coastguard Worker 		rv = NULL;
1691*7c356e86SAndroid Build Coastguard Worker 	}
1692*7c356e86SAndroid Build Coastguard Worker #endif
1693*7c356e86SAndroid Build Coastguard Worker 
1694*7c356e86SAndroid Build Coastguard Worker 	return (rv);
1695*7c356e86SAndroid Build Coastguard Worker }
1696*7c356e86SAndroid Build Coastguard Worker 
1697*7c356e86SAndroid Build Coastguard Worker #ifndef ELOOP
1698*7c356e86SAndroid Build Coastguard Worker #define ELOOP		E2BIG
1699*7c356e86SAndroid Build Coastguard Worker #endif
1700*7c356e86SAndroid Build Coastguard Worker 
1701*7c356e86SAndroid Build Coastguard Worker char *
do_realpath(const char * upath)1702*7c356e86SAndroid Build Coastguard Worker do_realpath(const char *upath)
1703*7c356e86SAndroid Build Coastguard Worker {
1704*7c356e86SAndroid Build Coastguard Worker 	char *xp, *ip, *tp, *ipath, *ldest = NULL;
1705*7c356e86SAndroid Build Coastguard Worker 	XString xs;
1706*7c356e86SAndroid Build Coastguard Worker 	size_t pos, len;
1707*7c356e86SAndroid Build Coastguard Worker 	int llen;
1708*7c356e86SAndroid Build Coastguard Worker 	struct stat sb;
1709*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH__NO_PATH_MAX
1710*7c356e86SAndroid Build Coastguard Worker 	size_t ldestlen = 0;
1711*7c356e86SAndroid Build Coastguard Worker #define pathlen sb.st_size
1712*7c356e86SAndroid Build Coastguard Worker #define pathcnd (ldestlen < (pathlen + 1))
1713*7c356e86SAndroid Build Coastguard Worker #else
1714*7c356e86SAndroid Build Coastguard Worker #define pathlen PATH_MAX
1715*7c356e86SAndroid Build Coastguard Worker #define pathcnd (!ldest)
1716*7c356e86SAndroid Build Coastguard Worker #endif
1717*7c356e86SAndroid Build Coastguard Worker 	/* max. recursion depth */
1718*7c356e86SAndroid Build Coastguard Worker 	int symlinks = 32;
1719*7c356e86SAndroid Build Coastguard Worker 
1720*7c356e86SAndroid Build Coastguard Worker 	if (mksh_abspath(upath)) {
1721*7c356e86SAndroid Build Coastguard Worker 		/* upath is an absolute pathname */
1722*7c356e86SAndroid Build Coastguard Worker 		strdupx(ipath, upath, ATEMP);
1723*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
1724*7c356e86SAndroid Build Coastguard Worker 	} else if (mksh_drvltr(upath)) {
1725*7c356e86SAndroid Build Coastguard Worker 		/* upath is a drive-relative pathname */
1726*7c356e86SAndroid Build Coastguard Worker 		if (getdrvwd(&ldest, ord(*upath)))
1727*7c356e86SAndroid Build Coastguard Worker 			return (NULL);
1728*7c356e86SAndroid Build Coastguard Worker 		/* A:foo -> A:/cwd/foo; A: -> A:/cwd */
1729*7c356e86SAndroid Build Coastguard Worker 		strpathx(ipath, ldest, upath + 2, 0);
1730*7c356e86SAndroid Build Coastguard Worker #endif
1731*7c356e86SAndroid Build Coastguard Worker 	} else {
1732*7c356e86SAndroid Build Coastguard Worker 		/* upath is a relative pathname, prepend cwd */
1733*7c356e86SAndroid Build Coastguard Worker 		if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp))
1734*7c356e86SAndroid Build Coastguard Worker 			return (NULL);
1735*7c356e86SAndroid Build Coastguard Worker 		strpathx(ipath, tp, upath, 1);
1736*7c356e86SAndroid Build Coastguard Worker 		afree(tp, ATEMP);
1737*7c356e86SAndroid Build Coastguard Worker 	}
1738*7c356e86SAndroid Build Coastguard Worker 
1739*7c356e86SAndroid Build Coastguard Worker 	/* ipath and upath are in memory at the same time -> unchecked */
1740*7c356e86SAndroid Build Coastguard Worker 	Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP);
1741*7c356e86SAndroid Build Coastguard Worker 
1742*7c356e86SAndroid Build Coastguard Worker 	/* now jump into the deep of the loop */
1743*7c356e86SAndroid Build Coastguard Worker 	goto beginning_of_a_pathname;
1744*7c356e86SAndroid Build Coastguard Worker 
1745*7c356e86SAndroid Build Coastguard Worker 	while (*ip) {
1746*7c356e86SAndroid Build Coastguard Worker 		/* skip slashes in input */
1747*7c356e86SAndroid Build Coastguard Worker 		while (mksh_cdirsep(*ip))
1748*7c356e86SAndroid Build Coastguard Worker 			++ip;
1749*7c356e86SAndroid Build Coastguard Worker 		if (!*ip)
1750*7c356e86SAndroid Build Coastguard Worker 			break;
1751*7c356e86SAndroid Build Coastguard Worker 
1752*7c356e86SAndroid Build Coastguard Worker 		/* get next pathname component from input */
1753*7c356e86SAndroid Build Coastguard Worker 		tp = ip;
1754*7c356e86SAndroid Build Coastguard Worker 		while (*ip && !mksh_cdirsep(*ip))
1755*7c356e86SAndroid Build Coastguard Worker 			++ip;
1756*7c356e86SAndroid Build Coastguard Worker 		len = ip - tp;
1757*7c356e86SAndroid Build Coastguard Worker 
1758*7c356e86SAndroid Build Coastguard Worker 		/* check input for "." and ".." */
1759*7c356e86SAndroid Build Coastguard Worker 		if (tp[0] == '.') {
1760*7c356e86SAndroid Build Coastguard Worker 			if (len == 1)
1761*7c356e86SAndroid Build Coastguard Worker 				/* just continue with the next one */
1762*7c356e86SAndroid Build Coastguard Worker 				continue;
1763*7c356e86SAndroid Build Coastguard Worker 			else if (len == 2 && tp[1] == '.') {
1764*7c356e86SAndroid Build Coastguard Worker 				/* strip off last pathname component */
1765*7c356e86SAndroid Build Coastguard Worker 				/*XXX consider a rooted pathname */
1766*7c356e86SAndroid Build Coastguard Worker 				while (xp > Xstring(xs, xp))
1767*7c356e86SAndroid Build Coastguard Worker 					if (mksh_cdirsep(*--xp))
1768*7c356e86SAndroid Build Coastguard Worker 						break;
1769*7c356e86SAndroid Build Coastguard Worker 				/* then continue with the next one */
1770*7c356e86SAndroid Build Coastguard Worker 				continue;
1771*7c356e86SAndroid Build Coastguard Worker 			}
1772*7c356e86SAndroid Build Coastguard Worker 		}
1773*7c356e86SAndroid Build Coastguard Worker 
1774*7c356e86SAndroid Build Coastguard Worker 		/* store output position away, then append slash to output */
1775*7c356e86SAndroid Build Coastguard Worker 		pos = Xsavepos(xs, xp);
1776*7c356e86SAndroid Build Coastguard Worker 		/* 1 for the '/' and len + 1 for tp and the NUL from below */
1777*7c356e86SAndroid Build Coastguard Worker 		XcheckN(xs, xp, 1 + len + 1);
1778*7c356e86SAndroid Build Coastguard Worker 		Xput(xs, xp, '/');
1779*7c356e86SAndroid Build Coastguard Worker 
1780*7c356e86SAndroid Build Coastguard Worker 		/* append next pathname component to output */
1781*7c356e86SAndroid Build Coastguard Worker 		memcpy(xp, tp, len);
1782*7c356e86SAndroid Build Coastguard Worker 		xp += len;
1783*7c356e86SAndroid Build Coastguard Worker 		*xp = '\0';
1784*7c356e86SAndroid Build Coastguard Worker 
1785*7c356e86SAndroid Build Coastguard Worker 		/* lstat the current output, see if it's a symlink */
1786*7c356e86SAndroid Build Coastguard Worker 		if (mksh_lstat(Xstring(xs, xp), &sb)) {
1787*7c356e86SAndroid Build Coastguard Worker 			/* lstat failed */
1788*7c356e86SAndroid Build Coastguard Worker 			if (errno == ENOENT) {
1789*7c356e86SAndroid Build Coastguard Worker 				/* because the pathname does not exist */
1790*7c356e86SAndroid Build Coastguard Worker 				while (mksh_cdirsep(*ip))
1791*7c356e86SAndroid Build Coastguard Worker 					/* skip any trailing slashes */
1792*7c356e86SAndroid Build Coastguard Worker 					++ip;
1793*7c356e86SAndroid Build Coastguard Worker 				/* no more components left? */
1794*7c356e86SAndroid Build Coastguard Worker 				if (!*ip)
1795*7c356e86SAndroid Build Coastguard Worker 					/* we can still return successfully */
1796*7c356e86SAndroid Build Coastguard Worker 					break;
1797*7c356e86SAndroid Build Coastguard Worker 				/* more components left? fall through */
1798*7c356e86SAndroid Build Coastguard Worker 			}
1799*7c356e86SAndroid Build Coastguard Worker 			/* not ENOENT or not at the end of ipath */
1800*7c356e86SAndroid Build Coastguard Worker 			goto notfound;
1801*7c356e86SAndroid Build Coastguard Worker 		}
1802*7c356e86SAndroid Build Coastguard Worker 
1803*7c356e86SAndroid Build Coastguard Worker 		/* check if we encountered a symlink? */
1804*7c356e86SAndroid Build Coastguard Worker 		if (S_ISLNK(sb.st_mode)) {
1805*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH__NO_SYMLINK
1806*7c356e86SAndroid Build Coastguard Worker 			/* reached maximum recursion depth? */
1807*7c356e86SAndroid Build Coastguard Worker 			if (!symlinks--) {
1808*7c356e86SAndroid Build Coastguard Worker 				/* yep, prevent infinite loops */
1809*7c356e86SAndroid Build Coastguard Worker 				errno = ELOOP;
1810*7c356e86SAndroid Build Coastguard Worker 				goto notfound;
1811*7c356e86SAndroid Build Coastguard Worker 			}
1812*7c356e86SAndroid Build Coastguard Worker 
1813*7c356e86SAndroid Build Coastguard Worker 			/* get symlink(7) target */
1814*7c356e86SAndroid Build Coastguard Worker 			if (pathcnd) {
1815*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH__NO_PATH_MAX
1816*7c356e86SAndroid Build Coastguard Worker 				if (notoktoadd(pathlen, 1)) {
1817*7c356e86SAndroid Build Coastguard Worker 					errno = ENAMETOOLONG;
1818*7c356e86SAndroid Build Coastguard Worker 					goto notfound;
1819*7c356e86SAndroid Build Coastguard Worker 				}
1820*7c356e86SAndroid Build Coastguard Worker #endif
1821*7c356e86SAndroid Build Coastguard Worker 				ldest = aresize(ldest, pathlen + 1, ATEMP);
1822*7c356e86SAndroid Build Coastguard Worker 			}
1823*7c356e86SAndroid Build Coastguard Worker 			llen = readlink(Xstring(xs, xp), ldest, pathlen);
1824*7c356e86SAndroid Build Coastguard Worker 			if (llen < 0)
1825*7c356e86SAndroid Build Coastguard Worker 				/* oops... */
1826*7c356e86SAndroid Build Coastguard Worker 				goto notfound;
1827*7c356e86SAndroid Build Coastguard Worker 			ldest[llen] = '\0';
1828*7c356e86SAndroid Build Coastguard Worker 
1829*7c356e86SAndroid Build Coastguard Worker 			/*
1830*7c356e86SAndroid Build Coastguard Worker 			 * restart if symlink target is an absolute path,
1831*7c356e86SAndroid Build Coastguard Worker 			 * otherwise continue with currently resolved prefix
1832*7c356e86SAndroid Build Coastguard Worker 			 */
1833*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
1834*7c356e86SAndroid Build Coastguard Worker  assemble_symlink:
1835*7c356e86SAndroid Build Coastguard Worker #endif
1836*7c356e86SAndroid Build Coastguard Worker 			/* append rest of current input path to link target */
1837*7c356e86SAndroid Build Coastguard Worker 			strpathx(tp, ldest, ip, 0);
1838*7c356e86SAndroid Build Coastguard Worker 			afree(ipath, ATEMP);
1839*7c356e86SAndroid Build Coastguard Worker 			ip = ipath = tp;
1840*7c356e86SAndroid Build Coastguard Worker 			if (!mksh_abspath(ipath)) {
1841*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
1842*7c356e86SAndroid Build Coastguard Worker 				/* symlink target might be drive-relative */
1843*7c356e86SAndroid Build Coastguard Worker 				if (mksh_drvltr(ipath)) {
1844*7c356e86SAndroid Build Coastguard Worker 					if (getdrvwd(&ldest, ord(*ipath)))
1845*7c356e86SAndroid Build Coastguard Worker 						goto notfound;
1846*7c356e86SAndroid Build Coastguard Worker 					ip += 2;
1847*7c356e86SAndroid Build Coastguard Worker 					goto assemble_symlink;
1848*7c356e86SAndroid Build Coastguard Worker 				}
1849*7c356e86SAndroid Build Coastguard Worker #endif
1850*7c356e86SAndroid Build Coastguard Worker 				/* symlink target is a relative path */
1851*7c356e86SAndroid Build Coastguard Worker 				xp = Xrestpos(xs, xp, pos);
1852*7c356e86SAndroid Build Coastguard Worker 			} else
1853*7c356e86SAndroid Build Coastguard Worker #endif
1854*7c356e86SAndroid Build Coastguard Worker 			  {
1855*7c356e86SAndroid Build Coastguard Worker 				/* symlink target is an absolute path */
1856*7c356e86SAndroid Build Coastguard Worker 				xp = Xstring(xs, xp);
1857*7c356e86SAndroid Build Coastguard Worker  beginning_of_a_pathname:
1858*7c356e86SAndroid Build Coastguard Worker 				/* assert: mksh_abspath(ip == ipath) */
1859*7c356e86SAndroid Build Coastguard Worker 				/* assert: xp == xs.beg => start of path */
1860*7c356e86SAndroid Build Coastguard Worker 
1861*7c356e86SAndroid Build Coastguard Worker 				/* exactly two leading slashes? (SUSv4 3.266) */
1862*7c356e86SAndroid Build Coastguard Worker 				if (ip[1] == ip[0] && !mksh_cdirsep(ip[2])) {
1863*7c356e86SAndroid Build Coastguard Worker 					/* keep them, e.g. for UNC pathnames */
1864*7c356e86SAndroid Build Coastguard Worker 					Xput(xs, xp, '/');
1865*7c356e86SAndroid Build Coastguard Worker 				}
1866*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
1867*7c356e86SAndroid Build Coastguard Worker 				/* drive letter? */
1868*7c356e86SAndroid Build Coastguard Worker 				if (mksh_drvltr(ip)) {
1869*7c356e86SAndroid Build Coastguard Worker 					/* keep it */
1870*7c356e86SAndroid Build Coastguard Worker 					Xput(xs, xp, *ip++);
1871*7c356e86SAndroid Build Coastguard Worker 					Xput(xs, xp, *ip++);
1872*7c356e86SAndroid Build Coastguard Worker 				}
1873*7c356e86SAndroid Build Coastguard Worker #endif
1874*7c356e86SAndroid Build Coastguard Worker 			}
1875*7c356e86SAndroid Build Coastguard Worker 		}
1876*7c356e86SAndroid Build Coastguard Worker 		/* otherwise (no symlink) merely go on */
1877*7c356e86SAndroid Build Coastguard Worker 	}
1878*7c356e86SAndroid Build Coastguard Worker 
1879*7c356e86SAndroid Build Coastguard Worker 	/*
1880*7c356e86SAndroid Build Coastguard Worker 	 * either found the target and successfully resolved it,
1881*7c356e86SAndroid Build Coastguard Worker 	 * or found its parent directory and may create it
1882*7c356e86SAndroid Build Coastguard Worker 	 */
1883*7c356e86SAndroid Build Coastguard Worker 	if (Xlength(xs, xp) == 0)
1884*7c356e86SAndroid Build Coastguard Worker 		/*
1885*7c356e86SAndroid Build Coastguard Worker 		 * if the resolved pathname is "", make it "/",
1886*7c356e86SAndroid Build Coastguard Worker 		 * otherwise do not add a trailing slash
1887*7c356e86SAndroid Build Coastguard Worker 		 */
1888*7c356e86SAndroid Build Coastguard Worker 		Xput(xs, xp, '/');
1889*7c356e86SAndroid Build Coastguard Worker 	Xput(xs, xp, '\0');
1890*7c356e86SAndroid Build Coastguard Worker 
1891*7c356e86SAndroid Build Coastguard Worker 	/*
1892*7c356e86SAndroid Build Coastguard Worker 	 * if source path had a trailing slash, check if target path
1893*7c356e86SAndroid Build Coastguard Worker 	 * is not a non-directory existing file
1894*7c356e86SAndroid Build Coastguard Worker 	 */
1895*7c356e86SAndroid Build Coastguard Worker 	if (ip > ipath && mksh_cdirsep(ip[-1])) {
1896*7c356e86SAndroid Build Coastguard Worker 		if (stat(Xstring(xs, xp), &sb)) {
1897*7c356e86SAndroid Build Coastguard Worker 			if (errno != ENOENT)
1898*7c356e86SAndroid Build Coastguard Worker 				goto notfound;
1899*7c356e86SAndroid Build Coastguard Worker 		} else if (!S_ISDIR(sb.st_mode)) {
1900*7c356e86SAndroid Build Coastguard Worker 			errno = ENOTDIR;
1901*7c356e86SAndroid Build Coastguard Worker 			goto notfound;
1902*7c356e86SAndroid Build Coastguard Worker 		}
1903*7c356e86SAndroid Build Coastguard Worker 		/* target now either does not exist or is a directory */
1904*7c356e86SAndroid Build Coastguard Worker 	}
1905*7c356e86SAndroid Build Coastguard Worker 
1906*7c356e86SAndroid Build Coastguard Worker 	/* return target path */
1907*7c356e86SAndroid Build Coastguard Worker 	afree(ldest, ATEMP);
1908*7c356e86SAndroid Build Coastguard Worker 	afree(ipath, ATEMP);
1909*7c356e86SAndroid Build Coastguard Worker 	return (Xclose(xs, xp));
1910*7c356e86SAndroid Build Coastguard Worker 
1911*7c356e86SAndroid Build Coastguard Worker  notfound:
1912*7c356e86SAndroid Build Coastguard Worker 	/* save; freeing memory might trash it */
1913*7c356e86SAndroid Build Coastguard Worker 	llen = errno;
1914*7c356e86SAndroid Build Coastguard Worker 	afree(ldest, ATEMP);
1915*7c356e86SAndroid Build Coastguard Worker 	afree(ipath, ATEMP);
1916*7c356e86SAndroid Build Coastguard Worker 	Xfree(xs, xp);
1917*7c356e86SAndroid Build Coastguard Worker 	errno = llen;
1918*7c356e86SAndroid Build Coastguard Worker 	return (NULL);
1919*7c356e86SAndroid Build Coastguard Worker 
1920*7c356e86SAndroid Build Coastguard Worker #undef pathlen
1921*7c356e86SAndroid Build Coastguard Worker #undef pathcnd
1922*7c356e86SAndroid Build Coastguard Worker }
1923*7c356e86SAndroid Build Coastguard Worker 
1924*7c356e86SAndroid Build Coastguard Worker /**
1925*7c356e86SAndroid Build Coastguard Worker  *	Makes a filename into result using the following algorithm.
1926*7c356e86SAndroid Build Coastguard Worker  *	- make result NULL
1927*7c356e86SAndroid Build Coastguard Worker  *	- if file starts with '/', append file to result & set cdpathp to NULL
1928*7c356e86SAndroid Build Coastguard Worker  *	- if file starts with ./ or ../ append cwd and file to result
1929*7c356e86SAndroid Build Coastguard Worker  *	  and set cdpathp to NULL
1930*7c356e86SAndroid Build Coastguard Worker  *	- if the first element of cdpathp doesn't start with a '/' xx or '.' xx
1931*7c356e86SAndroid Build Coastguard Worker  *	  then cwd is appended to result.
1932*7c356e86SAndroid Build Coastguard Worker  *	- the first element of cdpathp is appended to result
1933*7c356e86SAndroid Build Coastguard Worker  *	- file is appended to result
1934*7c356e86SAndroid Build Coastguard Worker  *	- cdpathp is set to the start of the next element in cdpathp (or NULL
1935*7c356e86SAndroid Build Coastguard Worker  *	  if there are no more elements.
1936*7c356e86SAndroid Build Coastguard Worker  *	The return value indicates whether a non-null element from cdpathp
1937*7c356e86SAndroid Build Coastguard Worker  *	was appended to result.
1938*7c356e86SAndroid Build Coastguard Worker  */
1939*7c356e86SAndroid Build Coastguard Worker static int
make_path(const char * cwd,const char * file,char ** cdpathp,XString * xsp,int * phys_pathp)1940*7c356e86SAndroid Build Coastguard Worker make_path(const char *cwd, const char *file,
1941*7c356e86SAndroid Build Coastguard Worker     /* pointer to colon-separated list */
1942*7c356e86SAndroid Build Coastguard Worker     char **cdpathp,
1943*7c356e86SAndroid Build Coastguard Worker     XString *xsp,
1944*7c356e86SAndroid Build Coastguard Worker     int *phys_pathp)
1945*7c356e86SAndroid Build Coastguard Worker {
1946*7c356e86SAndroid Build Coastguard Worker 	int rval = 0;
1947*7c356e86SAndroid Build Coastguard Worker 	bool use_cdpath = true;
1948*7c356e86SAndroid Build Coastguard Worker 	char *plist;
1949*7c356e86SAndroid Build Coastguard Worker 	size_t len, plen = 0;
1950*7c356e86SAndroid Build Coastguard Worker 	char *xp = Xstring(*xsp, xp);
1951*7c356e86SAndroid Build Coastguard Worker 
1952*7c356e86SAndroid Build Coastguard Worker 	if (!file)
1953*7c356e86SAndroid Build Coastguard Worker 		file = null;
1954*7c356e86SAndroid Build Coastguard Worker 
1955*7c356e86SAndroid Build Coastguard Worker 	if (mksh_abspath(file)) {
1956*7c356e86SAndroid Build Coastguard Worker 		*phys_pathp = 0;
1957*7c356e86SAndroid Build Coastguard Worker 		use_cdpath = false;
1958*7c356e86SAndroid Build Coastguard Worker 	} else {
1959*7c356e86SAndroid Build Coastguard Worker 		if (file[0] == '.') {
1960*7c356e86SAndroid Build Coastguard Worker 			char c = file[1];
1961*7c356e86SAndroid Build Coastguard Worker 
1962*7c356e86SAndroid Build Coastguard Worker 			if (c == '.')
1963*7c356e86SAndroid Build Coastguard Worker 				c = file[2];
1964*7c356e86SAndroid Build Coastguard Worker 			if (mksh_cdirsep(c) || c == '\0')
1965*7c356e86SAndroid Build Coastguard Worker 				use_cdpath = false;
1966*7c356e86SAndroid Build Coastguard Worker 		}
1967*7c356e86SAndroid Build Coastguard Worker 
1968*7c356e86SAndroid Build Coastguard Worker 		plist = *cdpathp;
1969*7c356e86SAndroid Build Coastguard Worker 		if (!plist)
1970*7c356e86SAndroid Build Coastguard Worker 			use_cdpath = false;
1971*7c356e86SAndroid Build Coastguard Worker 		else if (use_cdpath) {
1972*7c356e86SAndroid Build Coastguard Worker 			char *pend = plist;
1973*7c356e86SAndroid Build Coastguard Worker 
1974*7c356e86SAndroid Build Coastguard Worker 			while (*pend && *pend != MKSH_PATHSEPC)
1975*7c356e86SAndroid Build Coastguard Worker 				++pend;
1976*7c356e86SAndroid Build Coastguard Worker 			plen = pend - plist;
1977*7c356e86SAndroid Build Coastguard Worker 			*cdpathp = *pend ? pend + 1 : NULL;
1978*7c356e86SAndroid Build Coastguard Worker 		}
1979*7c356e86SAndroid Build Coastguard Worker 
1980*7c356e86SAndroid Build Coastguard Worker 		if ((!use_cdpath || !plen || !mksh_abspath(plist)) &&
1981*7c356e86SAndroid Build Coastguard Worker 		    (cwd && *cwd)) {
1982*7c356e86SAndroid Build Coastguard Worker 			len = strlen(cwd);
1983*7c356e86SAndroid Build Coastguard Worker 			XcheckN(*xsp, xp, len);
1984*7c356e86SAndroid Build Coastguard Worker 			memcpy(xp, cwd, len);
1985*7c356e86SAndroid Build Coastguard Worker 			xp += len;
1986*7c356e86SAndroid Build Coastguard Worker 			if (mksh_cdirsep(xp[-1]))
1987*7c356e86SAndroid Build Coastguard Worker 				xp--;
1988*7c356e86SAndroid Build Coastguard Worker 			*xp++ = '/';
1989*7c356e86SAndroid Build Coastguard Worker 		}
1990*7c356e86SAndroid Build Coastguard Worker 		*phys_pathp = Xlength(*xsp, xp);
1991*7c356e86SAndroid Build Coastguard Worker 		if (use_cdpath && plen) {
1992*7c356e86SAndroid Build Coastguard Worker 			XcheckN(*xsp, xp, plen);
1993*7c356e86SAndroid Build Coastguard Worker 			memcpy(xp, plist, plen);
1994*7c356e86SAndroid Build Coastguard Worker 			xp += plen;
1995*7c356e86SAndroid Build Coastguard Worker 			if (mksh_cdirsep(xp[-1]))
1996*7c356e86SAndroid Build Coastguard Worker 				xp--;
1997*7c356e86SAndroid Build Coastguard Worker 			*xp++ = '/';
1998*7c356e86SAndroid Build Coastguard Worker 			rval = 1;
1999*7c356e86SAndroid Build Coastguard Worker 		}
2000*7c356e86SAndroid Build Coastguard Worker 	}
2001*7c356e86SAndroid Build Coastguard Worker 
2002*7c356e86SAndroid Build Coastguard Worker 	len = strlen(file) + 1;
2003*7c356e86SAndroid Build Coastguard Worker 	XcheckN(*xsp, xp, len);
2004*7c356e86SAndroid Build Coastguard Worker 	memcpy(xp, file, len);
2005*7c356e86SAndroid Build Coastguard Worker 
2006*7c356e86SAndroid Build Coastguard Worker 	if (!use_cdpath)
2007*7c356e86SAndroid Build Coastguard Worker 		*cdpathp = NULL;
2008*7c356e86SAndroid Build Coastguard Worker 
2009*7c356e86SAndroid Build Coastguard Worker 	return (rval);
2010*7c356e86SAndroid Build Coastguard Worker }
2011*7c356e86SAndroid Build Coastguard Worker 
2012*7c356e86SAndroid Build Coastguard Worker /*-
2013*7c356e86SAndroid Build Coastguard Worker  * Simplify pathnames containing "." and ".." entries.
2014*7c356e86SAndroid Build Coastguard Worker  *
2015*7c356e86SAndroid Build Coastguard Worker  * simplify_path(this)			= that
2016*7c356e86SAndroid Build Coastguard Worker  * /a/b/c/./../d/..			/a/b
2017*7c356e86SAndroid Build Coastguard Worker  * //./C/foo/bar/../baz			//C/foo/baz
2018*7c356e86SAndroid Build Coastguard Worker  * /foo/				/foo
2019*7c356e86SAndroid Build Coastguard Worker  * /foo/../../bar			/bar
2020*7c356e86SAndroid Build Coastguard Worker  * /foo/./blah/..			/foo
2021*7c356e86SAndroid Build Coastguard Worker  * .					.
2022*7c356e86SAndroid Build Coastguard Worker  * ..					..
2023*7c356e86SAndroid Build Coastguard Worker  * ./foo				foo
2024*7c356e86SAndroid Build Coastguard Worker  * foo/../../../bar			../../bar
2025*7c356e86SAndroid Build Coastguard Worker  * C:/foo/../..				C:/
2026*7c356e86SAndroid Build Coastguard Worker  * C:.					C:
2027*7c356e86SAndroid Build Coastguard Worker  * C:..					C:..
2028*7c356e86SAndroid Build Coastguard Worker  * C:foo/../../blah			C:../blah
2029*7c356e86SAndroid Build Coastguard Worker  *
2030*7c356e86SAndroid Build Coastguard Worker  * XXX consider a rooted pathname: we cannot really 'cd ..' for
2031*7c356e86SAndroid Build Coastguard Worker  * pathnames like: '/', 'c:/', '//foo', '//foo/', '/@unixroot/'
2032*7c356e86SAndroid Build Coastguard Worker  * (no effect), 'c:', 'c:.' (effect is retaining the '../') but
2033*7c356e86SAndroid Build Coastguard Worker  * we need to honour this throughout the shell
2034*7c356e86SAndroid Build Coastguard Worker  */
2035*7c356e86SAndroid Build Coastguard Worker void
simplify_path(char * p)2036*7c356e86SAndroid Build Coastguard Worker simplify_path(char *p)
2037*7c356e86SAndroid Build Coastguard Worker {
2038*7c356e86SAndroid Build Coastguard Worker 	char *dp, *ip, *sp, *tp;
2039*7c356e86SAndroid Build Coastguard Worker 	size_t len;
2040*7c356e86SAndroid Build Coastguard Worker 	bool needslash;
2041*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
2042*7c356e86SAndroid Build Coastguard Worker 	bool needdot = true;
2043*7c356e86SAndroid Build Coastguard Worker 
2044*7c356e86SAndroid Build Coastguard Worker 	/* keep drive letter */
2045*7c356e86SAndroid Build Coastguard Worker 	if (mksh_drvltr(p)) {
2046*7c356e86SAndroid Build Coastguard Worker 		p += 2;
2047*7c356e86SAndroid Build Coastguard Worker 		needdot = false;
2048*7c356e86SAndroid Build Coastguard Worker 	}
2049*7c356e86SAndroid Build Coastguard Worker #else
2050*7c356e86SAndroid Build Coastguard Worker #define needdot true
2051*7c356e86SAndroid Build Coastguard Worker #endif
2052*7c356e86SAndroid Build Coastguard Worker 
2053*7c356e86SAndroid Build Coastguard Worker 	switch (*p) {
2054*7c356e86SAndroid Build Coastguard Worker 	case 0:
2055*7c356e86SAndroid Build Coastguard Worker 		return;
2056*7c356e86SAndroid Build Coastguard Worker 	case '/':
2057*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
2058*7c356e86SAndroid Build Coastguard Worker 	case '\\':
2059*7c356e86SAndroid Build Coastguard Worker #endif
2060*7c356e86SAndroid Build Coastguard Worker 		/* exactly two leading slashes? (SUSv4 3.266) */
2061*7c356e86SAndroid Build Coastguard Worker 		if (p[1] == p[0] && !mksh_cdirsep(p[2])) {
2062*7c356e86SAndroid Build Coastguard Worker 			/* keep them, e.g. for UNC pathnames */
2063*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
2064*7c356e86SAndroid Build Coastguard Worker 			*p++ = '/';
2065*7c356e86SAndroid Build Coastguard Worker #else
2066*7c356e86SAndroid Build Coastguard Worker 			++p;
2067*7c356e86SAndroid Build Coastguard Worker #endif
2068*7c356e86SAndroid Build Coastguard Worker 		}
2069*7c356e86SAndroid Build Coastguard Worker 		needslash = true;
2070*7c356e86SAndroid Build Coastguard Worker 		break;
2071*7c356e86SAndroid Build Coastguard Worker 	default:
2072*7c356e86SAndroid Build Coastguard Worker 		needslash = false;
2073*7c356e86SAndroid Build Coastguard Worker 	}
2074*7c356e86SAndroid Build Coastguard Worker 	dp = ip = sp = p;
2075*7c356e86SAndroid Build Coastguard Worker 
2076*7c356e86SAndroid Build Coastguard Worker 	while (*ip) {
2077*7c356e86SAndroid Build Coastguard Worker 		/* skip slashes in input */
2078*7c356e86SAndroid Build Coastguard Worker 		while (mksh_cdirsep(*ip))
2079*7c356e86SAndroid Build Coastguard Worker 			++ip;
2080*7c356e86SAndroid Build Coastguard Worker 		if (!*ip)
2081*7c356e86SAndroid Build Coastguard Worker 			break;
2082*7c356e86SAndroid Build Coastguard Worker 
2083*7c356e86SAndroid Build Coastguard Worker 		/* get next pathname component from input */
2084*7c356e86SAndroid Build Coastguard Worker 		tp = ip;
2085*7c356e86SAndroid Build Coastguard Worker 		while (*ip && !mksh_cdirsep(*ip))
2086*7c356e86SAndroid Build Coastguard Worker 			++ip;
2087*7c356e86SAndroid Build Coastguard Worker 		len = ip - tp;
2088*7c356e86SAndroid Build Coastguard Worker 
2089*7c356e86SAndroid Build Coastguard Worker 		/* check input for "." and ".." */
2090*7c356e86SAndroid Build Coastguard Worker 		if (tp[0] == '.') {
2091*7c356e86SAndroid Build Coastguard Worker 			if (len == 1)
2092*7c356e86SAndroid Build Coastguard Worker 				/* just continue with the next one */
2093*7c356e86SAndroid Build Coastguard Worker 				continue;
2094*7c356e86SAndroid Build Coastguard Worker 			else if (len == 2 && tp[1] == '.') {
2095*7c356e86SAndroid Build Coastguard Worker 				/* parent level, but how? (see above) */
2096*7c356e86SAndroid Build Coastguard Worker 				if (mksh_abspath(p))
2097*7c356e86SAndroid Build Coastguard Worker 					/* absolute path, only one way */
2098*7c356e86SAndroid Build Coastguard Worker 					goto strip_last_component;
2099*7c356e86SAndroid Build Coastguard Worker 				else if (dp > sp) {
2100*7c356e86SAndroid Build Coastguard Worker 					/* relative path, with subpaths */
2101*7c356e86SAndroid Build Coastguard Worker 					needslash = false;
2102*7c356e86SAndroid Build Coastguard Worker  strip_last_component:
2103*7c356e86SAndroid Build Coastguard Worker 					/* strip off last pathname component */
2104*7c356e86SAndroid Build Coastguard Worker 					while (dp > sp)
2105*7c356e86SAndroid Build Coastguard Worker 						if (mksh_cdirsep(*--dp))
2106*7c356e86SAndroid Build Coastguard Worker 							break;
2107*7c356e86SAndroid Build Coastguard Worker 				} else {
2108*7c356e86SAndroid Build Coastguard Worker 					/* relative path, at its beginning */
2109*7c356e86SAndroid Build Coastguard Worker 					if (needslash)
2110*7c356e86SAndroid Build Coastguard Worker 						/* or already dotdot-slash'd */
2111*7c356e86SAndroid Build Coastguard Worker 						*dp++ = '/';
2112*7c356e86SAndroid Build Coastguard Worker 					/* keep dotdot-slash if not absolute */
2113*7c356e86SAndroid Build Coastguard Worker 					*dp++ = '.';
2114*7c356e86SAndroid Build Coastguard Worker 					*dp++ = '.';
2115*7c356e86SAndroid Build Coastguard Worker 					needslash = true;
2116*7c356e86SAndroid Build Coastguard Worker 					sp = dp;
2117*7c356e86SAndroid Build Coastguard Worker 				}
2118*7c356e86SAndroid Build Coastguard Worker 				/* then continue with the next one */
2119*7c356e86SAndroid Build Coastguard Worker 				continue;
2120*7c356e86SAndroid Build Coastguard Worker 			}
2121*7c356e86SAndroid Build Coastguard Worker 		}
2122*7c356e86SAndroid Build Coastguard Worker 
2123*7c356e86SAndroid Build Coastguard Worker 		if (needslash)
2124*7c356e86SAndroid Build Coastguard Worker 			*dp++ = '/';
2125*7c356e86SAndroid Build Coastguard Worker 
2126*7c356e86SAndroid Build Coastguard Worker 		/* append next pathname component to output */
2127*7c356e86SAndroid Build Coastguard Worker 		memmove(dp, tp, len);
2128*7c356e86SAndroid Build Coastguard Worker 		dp += len;
2129*7c356e86SAndroid Build Coastguard Worker 
2130*7c356e86SAndroid Build Coastguard Worker 		/* append slash if we continue */
2131*7c356e86SAndroid Build Coastguard Worker 		needslash = true;
2132*7c356e86SAndroid Build Coastguard Worker 		/* try next component */
2133*7c356e86SAndroid Build Coastguard Worker 	}
2134*7c356e86SAndroid Build Coastguard Worker 	if (dp == p) {
2135*7c356e86SAndroid Build Coastguard Worker 		/* empty path -> dot (or slash, when absolute) */
2136*7c356e86SAndroid Build Coastguard Worker 		if (needslash)
2137*7c356e86SAndroid Build Coastguard Worker 			*dp++ = '/';
2138*7c356e86SAndroid Build Coastguard Worker 		else if (needdot)
2139*7c356e86SAndroid Build Coastguard Worker 			*dp++ = '.';
2140*7c356e86SAndroid Build Coastguard Worker 	}
2141*7c356e86SAndroid Build Coastguard Worker 	*dp = '\0';
2142*7c356e86SAndroid Build Coastguard Worker #undef needdot
2143*7c356e86SAndroid Build Coastguard Worker }
2144*7c356e86SAndroid Build Coastguard Worker 
2145*7c356e86SAndroid Build Coastguard Worker void
set_current_wd(const char * nwd)2146*7c356e86SAndroid Build Coastguard Worker set_current_wd(const char *nwd)
2147*7c356e86SAndroid Build Coastguard Worker {
2148*7c356e86SAndroid Build Coastguard Worker 	char *allocd = NULL;
2149*7c356e86SAndroid Build Coastguard Worker 
2150*7c356e86SAndroid Build Coastguard Worker 	if (nwd == NULL) {
2151*7c356e86SAndroid Build Coastguard Worker 		allocd = ksh_get_wd();
2152*7c356e86SAndroid Build Coastguard Worker 		nwd = allocd ? allocd : null;
2153*7c356e86SAndroid Build Coastguard Worker 	}
2154*7c356e86SAndroid Build Coastguard Worker 
2155*7c356e86SAndroid Build Coastguard Worker 	afree(current_wd, APERM);
2156*7c356e86SAndroid Build Coastguard Worker 	strdupx(current_wd, nwd, APERM);
2157*7c356e86SAndroid Build Coastguard Worker 
2158*7c356e86SAndroid Build Coastguard Worker 	afree(allocd, ATEMP);
2159*7c356e86SAndroid Build Coastguard Worker }
2160*7c356e86SAndroid Build Coastguard Worker 
2161*7c356e86SAndroid Build Coastguard Worker int
c_cd(const char ** wp)2162*7c356e86SAndroid Build Coastguard Worker c_cd(const char **wp)
2163*7c356e86SAndroid Build Coastguard Worker {
2164*7c356e86SAndroid Build Coastguard Worker 	int optc, rv, phys_path;
2165*7c356e86SAndroid Build Coastguard Worker 	bool physical = tobool(Flag(FPHYSICAL));
2166*7c356e86SAndroid Build Coastguard Worker 	/* was a node from cdpath added in? */
2167*7c356e86SAndroid Build Coastguard Worker 	int cdnode;
2168*7c356e86SAndroid Build Coastguard Worker 	/* show where we went?, error for $PWD */
2169*7c356e86SAndroid Build Coastguard Worker 	bool printpath = false, eflag = false;
2170*7c356e86SAndroid Build Coastguard Worker 	struct tbl *pwd_s, *oldpwd_s;
2171*7c356e86SAndroid Build Coastguard Worker 	XString xs;
2172*7c356e86SAndroid Build Coastguard Worker 	char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
2173*7c356e86SAndroid Build Coastguard Worker 
2174*7c356e86SAndroid Build Coastguard Worker 	while ((optc = ksh_getopt(wp, &builtin_opt, "eLP")) != -1)
2175*7c356e86SAndroid Build Coastguard Worker 		switch (optc) {
2176*7c356e86SAndroid Build Coastguard Worker 		case 'e':
2177*7c356e86SAndroid Build Coastguard Worker 			eflag = true;
2178*7c356e86SAndroid Build Coastguard Worker 			break;
2179*7c356e86SAndroid Build Coastguard Worker 		case 'L':
2180*7c356e86SAndroid Build Coastguard Worker 			physical = false;
2181*7c356e86SAndroid Build Coastguard Worker 			break;
2182*7c356e86SAndroid Build Coastguard Worker 		case 'P':
2183*7c356e86SAndroid Build Coastguard Worker 			physical = true;
2184*7c356e86SAndroid Build Coastguard Worker 			break;
2185*7c356e86SAndroid Build Coastguard Worker 		case '?':
2186*7c356e86SAndroid Build Coastguard Worker 			return (2);
2187*7c356e86SAndroid Build Coastguard Worker 		}
2188*7c356e86SAndroid Build Coastguard Worker 	wp += builtin_opt.optind;
2189*7c356e86SAndroid Build Coastguard Worker 
2190*7c356e86SAndroid Build Coastguard Worker 	if (Flag(FRESTRICTED)) {
2191*7c356e86SAndroid Build Coastguard Worker 		bi_errorf(Tcant_cd);
2192*7c356e86SAndroid Build Coastguard Worker 		return (2);
2193*7c356e86SAndroid Build Coastguard Worker 	}
2194*7c356e86SAndroid Build Coastguard Worker 
2195*7c356e86SAndroid Build Coastguard Worker 	pwd_s = global(TPWD);
2196*7c356e86SAndroid Build Coastguard Worker 	oldpwd_s = global(TOLDPWD);
2197*7c356e86SAndroid Build Coastguard Worker 
2198*7c356e86SAndroid Build Coastguard Worker 	if (!wp[0]) {
2199*7c356e86SAndroid Build Coastguard Worker 		/* no arguments; go home */
2200*7c356e86SAndroid Build Coastguard Worker 		if ((dir = str_val(global("HOME"))) == null) {
2201*7c356e86SAndroid Build Coastguard Worker 			bi_errorf("no home directory (HOME not set)");
2202*7c356e86SAndroid Build Coastguard Worker 			return (2);
2203*7c356e86SAndroid Build Coastguard Worker 		}
2204*7c356e86SAndroid Build Coastguard Worker 	} else if (!wp[1]) {
2205*7c356e86SAndroid Build Coastguard Worker 		/* one argument: - or dir */
2206*7c356e86SAndroid Build Coastguard Worker 		if (ksh_isdash(wp[0])) {
2207*7c356e86SAndroid Build Coastguard Worker 			dir = str_val(oldpwd_s);
2208*7c356e86SAndroid Build Coastguard Worker 			if (dir == null) {
2209*7c356e86SAndroid Build Coastguard Worker 				bi_errorf(Tno_OLDPWD);
2210*7c356e86SAndroid Build Coastguard Worker 				return (2);
2211*7c356e86SAndroid Build Coastguard Worker 			}
2212*7c356e86SAndroid Build Coastguard Worker 			printpath = true;
2213*7c356e86SAndroid Build Coastguard Worker 		} else {
2214*7c356e86SAndroid Build Coastguard Worker 			strdupx(allocd, wp[0], ATEMP);
2215*7c356e86SAndroid Build Coastguard Worker 			dir = allocd;
2216*7c356e86SAndroid Build Coastguard Worker 		}
2217*7c356e86SAndroid Build Coastguard Worker 	} else if (!wp[2]) {
2218*7c356e86SAndroid Build Coastguard Worker 		/* two arguments; substitute arg1 in PWD for arg2 */
2219*7c356e86SAndroid Build Coastguard Worker 		size_t ilen, olen, nlen, elen;
2220*7c356e86SAndroid Build Coastguard Worker 		char *cp;
2221*7c356e86SAndroid Build Coastguard Worker 
2222*7c356e86SAndroid Build Coastguard Worker 		if (!current_wd[0]) {
2223*7c356e86SAndroid Build Coastguard Worker 			bi_errorf("can't determine current directory");
2224*7c356e86SAndroid Build Coastguard Worker 			return (2);
2225*7c356e86SAndroid Build Coastguard Worker 		}
2226*7c356e86SAndroid Build Coastguard Worker 		/*
2227*7c356e86SAndroid Build Coastguard Worker 		 * Substitute arg1 for arg2 in current path. If the first
2228*7c356e86SAndroid Build Coastguard Worker 		 * substitution fails because the cd fails we could try to
2229*7c356e86SAndroid Build Coastguard Worker 		 * find another substitution. For now, we don't.
2230*7c356e86SAndroid Build Coastguard Worker 		 */
2231*7c356e86SAndroid Build Coastguard Worker 		if ((cp = strstr(current_wd, wp[0])) == NULL) {
2232*7c356e86SAndroid Build Coastguard Worker 			bi_errorf(Tbadsubst);
2233*7c356e86SAndroid Build Coastguard Worker 			return (2);
2234*7c356e86SAndroid Build Coastguard Worker 		}
2235*7c356e86SAndroid Build Coastguard Worker 		/*-
2236*7c356e86SAndroid Build Coastguard Worker 		 * ilen = part of current_wd before wp[0]
2237*7c356e86SAndroid Build Coastguard Worker 		 * elen = part of current_wd after wp[0]
2238*7c356e86SAndroid Build Coastguard Worker 		 * because current_wd and wp[1] need to be in memory at the
2239*7c356e86SAndroid Build Coastguard Worker 		 * same time beforehand the addition can stay unchecked
2240*7c356e86SAndroid Build Coastguard Worker 		 */
2241*7c356e86SAndroid Build Coastguard Worker 		ilen = cp - current_wd;
2242*7c356e86SAndroid Build Coastguard Worker 		olen = strlen(wp[0]);
2243*7c356e86SAndroid Build Coastguard Worker 		nlen = strlen(wp[1]);
2244*7c356e86SAndroid Build Coastguard Worker 		elen = strlen(current_wd + ilen + olen) + 1;
2245*7c356e86SAndroid Build Coastguard Worker 		dir = allocd = alloc(ilen + nlen + elen, ATEMP);
2246*7c356e86SAndroid Build Coastguard Worker 		memcpy(dir, current_wd, ilen);
2247*7c356e86SAndroid Build Coastguard Worker 		memcpy(dir + ilen, wp[1], nlen);
2248*7c356e86SAndroid Build Coastguard Worker 		memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
2249*7c356e86SAndroid Build Coastguard Worker 		printpath = true;
2250*7c356e86SAndroid Build Coastguard Worker 	} else {
2251*7c356e86SAndroid Build Coastguard Worker 		bi_errorf(Ttoo_many_args);
2252*7c356e86SAndroid Build Coastguard Worker 		return (2);
2253*7c356e86SAndroid Build Coastguard Worker 	}
2254*7c356e86SAndroid Build Coastguard Worker 
2255*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH_DOSPATH
2256*7c356e86SAndroid Build Coastguard Worker 	tryp = NULL;
2257*7c356e86SAndroid Build Coastguard Worker 	if (mksh_drvltr(dir) && !mksh_cdirsep(dir[2]) &&
2258*7c356e86SAndroid Build Coastguard Worker 	    !getdrvwd(&tryp, ord(*dir))) {
2259*7c356e86SAndroid Build Coastguard Worker 		strpathx(dir, tryp, dir + 2, 0);
2260*7c356e86SAndroid Build Coastguard Worker 		afree(tryp, ATEMP);
2261*7c356e86SAndroid Build Coastguard Worker 		afree(allocd, ATEMP);
2262*7c356e86SAndroid Build Coastguard Worker 		allocd = dir;
2263*7c356e86SAndroid Build Coastguard Worker 	}
2264*7c356e86SAndroid Build Coastguard Worker #endif
2265*7c356e86SAndroid Build Coastguard Worker 
2266*7c356e86SAndroid Build Coastguard Worker #ifdef MKSH__NO_PATH_MAX
2267*7c356e86SAndroid Build Coastguard Worker 	/* only a first guess; make_path will enlarge xs if necessary */
2268*7c356e86SAndroid Build Coastguard Worker 	XinitN(xs, 1024, ATEMP);
2269*7c356e86SAndroid Build Coastguard Worker #else
2270*7c356e86SAndroid Build Coastguard Worker 	XinitN(xs, PATH_MAX, ATEMP);
2271*7c356e86SAndroid Build Coastguard Worker #endif
2272*7c356e86SAndroid Build Coastguard Worker 
2273*7c356e86SAndroid Build Coastguard Worker 	cdpath = str_val(global("CDPATH"));
2274*7c356e86SAndroid Build Coastguard Worker 	do {
2275*7c356e86SAndroid Build Coastguard Worker 		cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
2276*7c356e86SAndroid Build Coastguard Worker 		if (physical)
2277*7c356e86SAndroid Build Coastguard Worker 			rv = chdir(tryp = Xstring(xs, xp) + phys_path);
2278*7c356e86SAndroid Build Coastguard Worker 		else {
2279*7c356e86SAndroid Build Coastguard Worker 			simplify_path(Xstring(xs, xp));
2280*7c356e86SAndroid Build Coastguard Worker 			rv = chdir(tryp = Xstring(xs, xp));
2281*7c356e86SAndroid Build Coastguard Worker 		}
2282*7c356e86SAndroid Build Coastguard Worker 	} while (rv < 0 && cdpath != NULL);
2283*7c356e86SAndroid Build Coastguard Worker 
2284*7c356e86SAndroid Build Coastguard Worker 	if (rv < 0) {
2285*7c356e86SAndroid Build Coastguard Worker 		if (cdnode)
2286*7c356e86SAndroid Build Coastguard Worker 			bi_errorf(Tf_sD_s, dir, "bad directory");
2287*7c356e86SAndroid Build Coastguard Worker 		else
2288*7c356e86SAndroid Build Coastguard Worker 			bi_errorf(Tf_sD_s, tryp, cstrerror(errno));
2289*7c356e86SAndroid Build Coastguard Worker 		afree(allocd, ATEMP);
2290*7c356e86SAndroid Build Coastguard Worker 		Xfree(xs, xp);
2291*7c356e86SAndroid Build Coastguard Worker 		return (2);
2292*7c356e86SAndroid Build Coastguard Worker 	}
2293*7c356e86SAndroid Build Coastguard Worker 
2294*7c356e86SAndroid Build Coastguard Worker 	rv = 0;
2295*7c356e86SAndroid Build Coastguard Worker 
2296*7c356e86SAndroid Build Coastguard Worker 	/* allocd (above) => dir, which is no longer used */
2297*7c356e86SAndroid Build Coastguard Worker 	afree(allocd, ATEMP);
2298*7c356e86SAndroid Build Coastguard Worker 	allocd = NULL;
2299*7c356e86SAndroid Build Coastguard Worker 
2300*7c356e86SAndroid Build Coastguard Worker 	/* Clear out tracked aliases with relative paths */
2301*7c356e86SAndroid Build Coastguard Worker 	flushcom(false);
2302*7c356e86SAndroid Build Coastguard Worker 
2303*7c356e86SAndroid Build Coastguard Worker 	/*
2304*7c356e86SAndroid Build Coastguard Worker 	 * Set OLDPWD (note: unsetting OLDPWD does not disable this
2305*7c356e86SAndroid Build Coastguard Worker 	 * setting in AT&T ksh)
2306*7c356e86SAndroid Build Coastguard Worker 	 */
2307*7c356e86SAndroid Build Coastguard Worker 	if (current_wd[0])
2308*7c356e86SAndroid Build Coastguard Worker 		/* Ignore failure (happens if readonly or integer) */
2309*7c356e86SAndroid Build Coastguard Worker 		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
2310*7c356e86SAndroid Build Coastguard Worker 
2311*7c356e86SAndroid Build Coastguard Worker 	if (!mksh_abspath(Xstring(xs, xp))) {
2312*7c356e86SAndroid Build Coastguard Worker 		pwd = NULL;
2313*7c356e86SAndroid Build Coastguard Worker 	} else if (!physical) {
2314*7c356e86SAndroid Build Coastguard Worker 		goto norealpath_PWD;
2315*7c356e86SAndroid Build Coastguard Worker 	} else if ((pwd = allocd = do_realpath(Xstring(xs, xp))) == NULL) {
2316*7c356e86SAndroid Build Coastguard Worker 		if (eflag)
2317*7c356e86SAndroid Build Coastguard Worker 			rv = 1;
2318*7c356e86SAndroid Build Coastguard Worker  norealpath_PWD:
2319*7c356e86SAndroid Build Coastguard Worker 		pwd = Xstring(xs, xp);
2320*7c356e86SAndroid Build Coastguard Worker 	}
2321*7c356e86SAndroid Build Coastguard Worker 
2322*7c356e86SAndroid Build Coastguard Worker 	/* Set PWD */
2323*7c356e86SAndroid Build Coastguard Worker 	if (pwd) {
2324*7c356e86SAndroid Build Coastguard Worker 		char *ptmp = pwd;
2325*7c356e86SAndroid Build Coastguard Worker 
2326*7c356e86SAndroid Build Coastguard Worker 		set_current_wd(ptmp);
2327*7c356e86SAndroid Build Coastguard Worker 		/* Ignore failure (happens if readonly or integer) */
2328*7c356e86SAndroid Build Coastguard Worker 		setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
2329*7c356e86SAndroid Build Coastguard Worker 	} else {
2330*7c356e86SAndroid Build Coastguard Worker 		set_current_wd(null);
2331*7c356e86SAndroid Build Coastguard Worker 		pwd = Xstring(xs, xp);
2332*7c356e86SAndroid Build Coastguard Worker 		/* XXX unset $PWD? */
2333*7c356e86SAndroid Build Coastguard Worker 		if (eflag)
2334*7c356e86SAndroid Build Coastguard Worker 			rv = 1;
2335*7c356e86SAndroid Build Coastguard Worker 	}
2336*7c356e86SAndroid Build Coastguard Worker 	if (printpath || cdnode)
2337*7c356e86SAndroid Build Coastguard Worker 		shprintf(Tf_sN, pwd);
2338*7c356e86SAndroid Build Coastguard Worker 
2339*7c356e86SAndroid Build Coastguard Worker 	afree(allocd, ATEMP);
2340*7c356e86SAndroid Build Coastguard Worker 	Xfree(xs, xp);
2341*7c356e86SAndroid Build Coastguard Worker 	return (rv);
2342*7c356e86SAndroid Build Coastguard Worker }
2343*7c356e86SAndroid Build Coastguard Worker 
2344*7c356e86SAndroid Build Coastguard Worker 
2345*7c356e86SAndroid Build Coastguard Worker #ifdef KSH_CHVT_CODE
2346*7c356e86SAndroid Build Coastguard Worker extern void chvt_reinit(void);
2347*7c356e86SAndroid Build Coastguard Worker 
2348*7c356e86SAndroid Build Coastguard Worker static void
chvt(const Getopt * go)2349*7c356e86SAndroid Build Coastguard Worker chvt(const Getopt *go)
2350*7c356e86SAndroid Build Coastguard Worker {
2351*7c356e86SAndroid Build Coastguard Worker 	const char *dv = go->optarg;
2352*7c356e86SAndroid Build Coastguard Worker 	char *cp = NULL;
2353*7c356e86SAndroid Build Coastguard Worker 	int fd;
2354*7c356e86SAndroid Build Coastguard Worker 
2355*7c356e86SAndroid Build Coastguard Worker 	switch (*dv) {
2356*7c356e86SAndroid Build Coastguard Worker 	case '-':
2357*7c356e86SAndroid Build Coastguard Worker 		dv = "/dev/null";
2358*7c356e86SAndroid Build Coastguard Worker 		break;
2359*7c356e86SAndroid Build Coastguard Worker 	case '!':
2360*7c356e86SAndroid Build Coastguard Worker 		++dv;
2361*7c356e86SAndroid Build Coastguard Worker 		/* FALLTHROUGH */
2362*7c356e86SAndroid Build Coastguard Worker 	default: {
2363*7c356e86SAndroid Build Coastguard Worker 		struct stat sb;
2364*7c356e86SAndroid Build Coastguard Worker 
2365*7c356e86SAndroid Build Coastguard Worker 		if (stat(dv, &sb)) {
2366*7c356e86SAndroid Build Coastguard Worker 			cp = shf_smprintf("/dev/ttyC%s", dv);
2367*7c356e86SAndroid Build Coastguard Worker 			dv = cp;
2368*7c356e86SAndroid Build Coastguard Worker 			if (stat(dv, &sb)) {
2369*7c356e86SAndroid Build Coastguard Worker 				memmove(cp + 1, cp, /* /dev/tty */ 8);
2370*7c356e86SAndroid Build Coastguard Worker 				dv = cp + 1;
2371*7c356e86SAndroid Build Coastguard Worker 				if (stat(dv, &sb)) {
2372*7c356e86SAndroid Build Coastguard Worker 					errorf(Tf_sD_sD_s, "chvt",
2373*7c356e86SAndroid Build Coastguard Worker 					    "can't find tty", go->optarg);
2374*7c356e86SAndroid Build Coastguard Worker 				}
2375*7c356e86SAndroid Build Coastguard Worker 			}
2376*7c356e86SAndroid Build Coastguard Worker 		}
2377*7c356e86SAndroid Build Coastguard Worker 		if (!(sb.st_mode & S_IFCHR))
2378*7c356e86SAndroid Build Coastguard Worker 			errorf(Tf_sD_sD_s, "chvt", "not a char device", dv);
2379*7c356e86SAndroid Build Coastguard Worker #ifndef MKSH_DISABLE_REVOKE_WARNING
2380*7c356e86SAndroid Build Coastguard Worker #if HAVE_REVOKE
2381*7c356e86SAndroid Build Coastguard Worker 		if (revoke(dv))
2382*7c356e86SAndroid Build Coastguard Worker #endif
2383*7c356e86SAndroid Build Coastguard Worker 			warningf(false, Tf_sD_s_s, "chvt",
2384*7c356e86SAndroid Build Coastguard Worker 			    "new shell is potentially insecure, can't revoke",
2385*7c356e86SAndroid Build Coastguard Worker 			    dv);
2386*7c356e86SAndroid Build Coastguard Worker #endif
2387*7c356e86SAndroid Build Coastguard Worker 	    }
2388*7c356e86SAndroid Build Coastguard Worker 	}
2389*7c356e86SAndroid Build Coastguard Worker 	if ((fd = binopen2(dv, O_RDWR)) < 0) {
2390*7c356e86SAndroid Build Coastguard Worker 		sleep(1);
2391*7c356e86SAndroid Build Coastguard Worker 		if ((fd = binopen2(dv, O_RDWR)) < 0) {
2392*7c356e86SAndroid Build Coastguard Worker 			errorf(Tf_sD_s_s, "chvt", Tcant_open, dv);
2393*7c356e86SAndroid Build Coastguard Worker 		}
2394*7c356e86SAndroid Build Coastguard Worker 	}
2395*7c356e86SAndroid Build Coastguard Worker 	if (go->optarg[0] != '!') {
2396*7c356e86SAndroid Build Coastguard Worker 		switch (fork()) {
2397*7c356e86SAndroid Build Coastguard Worker 		case -1:
2398*7c356e86SAndroid Build Coastguard Worker 			errorf(Tf_sD_s_s, "chvt", "fork", "failed");
2399*7c356e86SAndroid Build Coastguard Worker 		case 0:
2400*7c356e86SAndroid Build Coastguard Worker 			break;
2401*7c356e86SAndroid Build Coastguard Worker 		default:
2402*7c356e86SAndroid Build Coastguard Worker 			exit(0);
2403*7c356e86SAndroid Build Coastguard Worker 		}
2404*7c356e86SAndroid Build Coastguard Worker 	}
2405*7c356e86SAndroid Build Coastguard Worker 	if (setsid() == -1)
2406*7c356e86SAndroid Build Coastguard Worker 		errorf(Tf_sD_s_s, "chvt", "setsid", "failed");
2407*7c356e86SAndroid Build Coastguard Worker 	if (go->optarg[0] != '-') {
2408*7c356e86SAndroid Build Coastguard Worker 		if (ioctl(fd, TIOCSCTTY, NULL) == -1)
2409*7c356e86SAndroid Build Coastguard Worker 			errorf(Tf_sD_s_s, "chvt", "TIOCSCTTY", "failed");
2410*7c356e86SAndroid Build Coastguard Worker 		if (tcflush(fd, TCIOFLUSH))
2411*7c356e86SAndroid Build Coastguard Worker 			errorf(Tf_sD_s_s, "chvt", "TCIOFLUSH", "failed");
2412*7c356e86SAndroid Build Coastguard Worker 	}
2413*7c356e86SAndroid Build Coastguard Worker 	ksh_dup2(fd, 0, false);
2414*7c356e86SAndroid Build Coastguard Worker 	ksh_dup2(fd, 1, false);
2415*7c356e86SAndroid Build Coastguard Worker 	ksh_dup2(fd, 2, false);
2416*7c356e86SAndroid Build Coastguard Worker 	if (fd > 2)
2417*7c356e86SAndroid Build Coastguard Worker 		close(fd);
2418*7c356e86SAndroid Build Coastguard Worker 	rndset((unsigned long)chvt_rndsetup(go, sizeof(Getopt)));
2419*7c356e86SAndroid Build Coastguard Worker 	chvt_reinit();
2420*7c356e86SAndroid Build Coastguard Worker }
2421*7c356e86SAndroid Build Coastguard Worker #endif
2422*7c356e86SAndroid Build Coastguard Worker 
2423*7c356e86SAndroid Build Coastguard Worker #ifdef DEBUG
2424*7c356e86SAndroid Build Coastguard Worker char *
strchr(char * p,int ch)2425*7c356e86SAndroid Build Coastguard Worker strchr(char *p, int ch)
2426*7c356e86SAndroid Build Coastguard Worker {
2427*7c356e86SAndroid Build Coastguard Worker 	for (;; ++p) {
2428*7c356e86SAndroid Build Coastguard Worker 		if (*p == ch)
2429*7c356e86SAndroid Build Coastguard Worker 			return (p);
2430*7c356e86SAndroid Build Coastguard Worker 		if (!*p)
2431*7c356e86SAndroid Build Coastguard Worker 			return (NULL);
2432*7c356e86SAndroid Build Coastguard Worker 	}
2433*7c356e86SAndroid Build Coastguard Worker 	/* NOTREACHED */
2434*7c356e86SAndroid Build Coastguard Worker }
2435*7c356e86SAndroid Build Coastguard Worker 
2436*7c356e86SAndroid Build Coastguard Worker char *
strstr(char * b,const char * l)2437*7c356e86SAndroid Build Coastguard Worker strstr(char *b, const char *l)
2438*7c356e86SAndroid Build Coastguard Worker {
2439*7c356e86SAndroid Build Coastguard Worker 	char first, c;
2440*7c356e86SAndroid Build Coastguard Worker 	size_t n;
2441*7c356e86SAndroid Build Coastguard Worker 
2442*7c356e86SAndroid Build Coastguard Worker 	if ((first = *l++) == '\0')
2443*7c356e86SAndroid Build Coastguard Worker 		return (b);
2444*7c356e86SAndroid Build Coastguard Worker 	n = strlen(l);
2445*7c356e86SAndroid Build Coastguard Worker  strstr_look:
2446*7c356e86SAndroid Build Coastguard Worker 	while ((c = *b++) != first)
2447*7c356e86SAndroid Build Coastguard Worker 		if (c == '\0')
2448*7c356e86SAndroid Build Coastguard Worker 			return (NULL);
2449*7c356e86SAndroid Build Coastguard Worker 	if (strncmp(b, l, n))
2450*7c356e86SAndroid Build Coastguard Worker 		goto strstr_look;
2451*7c356e86SAndroid Build Coastguard Worker 	return (b - 1);
2452*7c356e86SAndroid Build Coastguard Worker }
2453*7c356e86SAndroid Build Coastguard Worker #endif
2454*7c356e86SAndroid Build Coastguard Worker 
2455*7c356e86SAndroid Build Coastguard Worker #if defined(MKSH_SMALL) && !defined(MKSH_SMALL_BUT_FAST)
2456*7c356e86SAndroid Build Coastguard Worker char *
strndup_i(const char * src,size_t len,Area * ap)2457*7c356e86SAndroid Build Coastguard Worker strndup_i(const char *src, size_t len, Area *ap)
2458*7c356e86SAndroid Build Coastguard Worker {
2459*7c356e86SAndroid Build Coastguard Worker 	char *dst = NULL;
2460*7c356e86SAndroid Build Coastguard Worker 
2461*7c356e86SAndroid Build Coastguard Worker 	if (src != NULL) {
2462*7c356e86SAndroid Build Coastguard Worker 		dst = alloc(len + 1, ap);
2463*7c356e86SAndroid Build Coastguard Worker 		memcpy(dst, src, len);
2464*7c356e86SAndroid Build Coastguard Worker 		dst[len] = '\0';
2465*7c356e86SAndroid Build Coastguard Worker 	}
2466*7c356e86SAndroid Build Coastguard Worker 	return (dst);
2467*7c356e86SAndroid Build Coastguard Worker }
2468*7c356e86SAndroid Build Coastguard Worker 
2469*7c356e86SAndroid Build Coastguard Worker char *
strdup_i(const char * src,Area * ap)2470*7c356e86SAndroid Build Coastguard Worker strdup_i(const char *src, Area *ap)
2471*7c356e86SAndroid Build Coastguard Worker {
2472*7c356e86SAndroid Build Coastguard Worker 	return (src == NULL ? NULL : strndup_i(src, strlen(src), ap));
2473*7c356e86SAndroid Build Coastguard Worker }
2474*7c356e86SAndroid Build Coastguard Worker #endif
2475*7c356e86SAndroid Build Coastguard Worker 
2476*7c356e86SAndroid Build Coastguard Worker #if !HAVE_GETRUSAGE
2477*7c356e86SAndroid Build Coastguard Worker #define INVTCK(r,t)	do {						\
2478*7c356e86SAndroid Build Coastguard Worker 	r.tv_usec = ((t) % (1000000 / CLK_TCK)) * (1000000 / CLK_TCK);	\
2479*7c356e86SAndroid Build Coastguard Worker 	r.tv_sec = (t) / CLK_TCK;					\
2480*7c356e86SAndroid Build Coastguard Worker } while (/* CONSTCOND */ 0)
2481*7c356e86SAndroid Build Coastguard Worker 
2482*7c356e86SAndroid Build Coastguard Worker int
getrusage(int what,struct rusage * ru)2483*7c356e86SAndroid Build Coastguard Worker getrusage(int what, struct rusage *ru)
2484*7c356e86SAndroid Build Coastguard Worker {
2485*7c356e86SAndroid Build Coastguard Worker 	struct tms tms;
2486*7c356e86SAndroid Build Coastguard Worker 	clock_t u, s;
2487*7c356e86SAndroid Build Coastguard Worker 
2488*7c356e86SAndroid Build Coastguard Worker 	if (/* ru == NULL || */ times(&tms) == (clock_t)-1)
2489*7c356e86SAndroid Build Coastguard Worker 		return (-1);
2490*7c356e86SAndroid Build Coastguard Worker 
2491*7c356e86SAndroid Build Coastguard Worker 	switch (what) {
2492*7c356e86SAndroid Build Coastguard Worker 	case RUSAGE_SELF:
2493*7c356e86SAndroid Build Coastguard Worker 		u = tms.tms_utime;
2494*7c356e86SAndroid Build Coastguard Worker 		s = tms.tms_stime;
2495*7c356e86SAndroid Build Coastguard Worker 		break;
2496*7c356e86SAndroid Build Coastguard Worker 	case RUSAGE_CHILDREN:
2497*7c356e86SAndroid Build Coastguard Worker 		u = tms.tms_cutime;
2498*7c356e86SAndroid Build Coastguard Worker 		s = tms.tms_cstime;
2499*7c356e86SAndroid Build Coastguard Worker 		break;
2500*7c356e86SAndroid Build Coastguard Worker 	default:
2501*7c356e86SAndroid Build Coastguard Worker 		errno = EINVAL;
2502*7c356e86SAndroid Build Coastguard Worker 		return (-1);
2503*7c356e86SAndroid Build Coastguard Worker 	}
2504*7c356e86SAndroid Build Coastguard Worker 	INVTCK(ru->ru_utime, u);
2505*7c356e86SAndroid Build Coastguard Worker 	INVTCK(ru->ru_stime, s);
2506*7c356e86SAndroid Build Coastguard Worker 	return (0);
2507*7c356e86SAndroid Build Coastguard Worker }
2508*7c356e86SAndroid Build Coastguard Worker #endif
2509*7c356e86SAndroid Build Coastguard Worker 
2510*7c356e86SAndroid Build Coastguard Worker /*
2511*7c356e86SAndroid Build Coastguard Worker  * process the string available via fg (get a char)
2512*7c356e86SAndroid Build Coastguard Worker  * and fp (put back a char) for backslash escapes,
2513*7c356e86SAndroid Build Coastguard Worker  * assuming the first call to *fg gets the char di-
2514*7c356e86SAndroid Build Coastguard Worker  * rectly after the backslash; return the character
2515*7c356e86SAndroid Build Coastguard Worker  * (0..0xFF), UCS (wc + 0x100), or -1 if no known
2516*7c356e86SAndroid Build Coastguard Worker  * escape sequence was found
2517*7c356e86SAndroid Build Coastguard Worker  */
2518*7c356e86SAndroid Build Coastguard Worker int
unbksl(bool cstyle,int (* fg)(void),void (* fp)(int))2519*7c356e86SAndroid Build Coastguard Worker unbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
2520*7c356e86SAndroid Build Coastguard Worker {
2521*7c356e86SAndroid Build Coastguard Worker 	int wc, i, c, fc, n;
2522*7c356e86SAndroid Build Coastguard Worker 
2523*7c356e86SAndroid Build Coastguard Worker 	fc = (*fg)();
2524*7c356e86SAndroid Build Coastguard Worker 	switch (fc) {
2525*7c356e86SAndroid Build Coastguard Worker 	case 'a':
2526*7c356e86SAndroid Build Coastguard Worker 		wc = KSH_BEL;
2527*7c356e86SAndroid Build Coastguard Worker 		break;
2528*7c356e86SAndroid Build Coastguard Worker 	case 'b':
2529*7c356e86SAndroid Build Coastguard Worker 		wc = '\b';
2530*7c356e86SAndroid Build Coastguard Worker 		break;
2531*7c356e86SAndroid Build Coastguard Worker 	case 'c':
2532*7c356e86SAndroid Build Coastguard Worker 		if (!cstyle)
2533*7c356e86SAndroid Build Coastguard Worker 			goto unknown_escape;
2534*7c356e86SAndroid Build Coastguard Worker 		c = (*fg)();
2535*7c356e86SAndroid Build Coastguard Worker 		wc = ksh_toctrl(c);
2536*7c356e86SAndroid Build Coastguard Worker 		break;
2537*7c356e86SAndroid Build Coastguard Worker 	case 'E':
2538*7c356e86SAndroid Build Coastguard Worker 	case 'e':
2539*7c356e86SAndroid Build Coastguard Worker 		wc = KSH_ESC;
2540*7c356e86SAndroid Build Coastguard Worker 		break;
2541*7c356e86SAndroid Build Coastguard Worker 	case 'f':
2542*7c356e86SAndroid Build Coastguard Worker 		wc = '\f';
2543*7c356e86SAndroid Build Coastguard Worker 		break;
2544*7c356e86SAndroid Build Coastguard Worker 	case 'n':
2545*7c356e86SAndroid Build Coastguard Worker 		wc = '\n';
2546*7c356e86SAndroid Build Coastguard Worker 		break;
2547*7c356e86SAndroid Build Coastguard Worker 	case 'r':
2548*7c356e86SAndroid Build Coastguard Worker 		wc = '\r';
2549*7c356e86SAndroid Build Coastguard Worker 		break;
2550*7c356e86SAndroid Build Coastguard Worker 	case 't':
2551*7c356e86SAndroid Build Coastguard Worker 		wc = '\t';
2552*7c356e86SAndroid Build Coastguard Worker 		break;
2553*7c356e86SAndroid Build Coastguard Worker 	case 'v':
2554*7c356e86SAndroid Build Coastguard Worker 		wc = KSH_VTAB;
2555*7c356e86SAndroid Build Coastguard Worker 		break;
2556*7c356e86SAndroid Build Coastguard Worker 	case '1':
2557*7c356e86SAndroid Build Coastguard Worker 	case '2':
2558*7c356e86SAndroid Build Coastguard Worker 	case '3':
2559*7c356e86SAndroid Build Coastguard Worker 	case '4':
2560*7c356e86SAndroid Build Coastguard Worker 	case '5':
2561*7c356e86SAndroid Build Coastguard Worker 	case '6':
2562*7c356e86SAndroid Build Coastguard Worker 	case '7':
2563*7c356e86SAndroid Build Coastguard Worker 		if (!cstyle)
2564*7c356e86SAndroid Build Coastguard Worker 			goto unknown_escape;
2565*7c356e86SAndroid Build Coastguard Worker 		/* FALLTHROUGH */
2566*7c356e86SAndroid Build Coastguard Worker 	case '0':
2567*7c356e86SAndroid Build Coastguard Worker 		if (cstyle)
2568*7c356e86SAndroid Build Coastguard Worker 			(*fp)(fc);
2569*7c356e86SAndroid Build Coastguard Worker 		/*
2570*7c356e86SAndroid Build Coastguard Worker 		 * look for an octal number with up to three
2571*7c356e86SAndroid Build Coastguard Worker 		 * digits, not counting the leading zero;
2572*7c356e86SAndroid Build Coastguard Worker 		 * convert it to a raw octet
2573*7c356e86SAndroid Build Coastguard Worker 		 */
2574*7c356e86SAndroid Build Coastguard Worker 		wc = 0;
2575*7c356e86SAndroid Build Coastguard Worker 		i = 3;
2576*7c356e86SAndroid Build Coastguard Worker 		while (i--)
2577*7c356e86SAndroid Build Coastguard Worker 			if (ctype((c = (*fg)()), C_OCTAL))
2578*7c356e86SAndroid Build Coastguard Worker 				wc = (wc << 3) + ksh_numdig(c);
2579*7c356e86SAndroid Build Coastguard Worker 			else {
2580*7c356e86SAndroid Build Coastguard Worker 				(*fp)(c);
2581*7c356e86SAndroid Build Coastguard Worker 				break;
2582*7c356e86SAndroid Build Coastguard Worker 			}
2583*7c356e86SAndroid Build Coastguard Worker 		break;
2584*7c356e86SAndroid Build Coastguard Worker 	case 'U':
2585*7c356e86SAndroid Build Coastguard Worker 		i = 8;
2586*7c356e86SAndroid Build Coastguard Worker 		if (/* CONSTCOND */ 0)
2587*7c356e86SAndroid Build Coastguard Worker 			/* FALLTHROUGH */
2588*7c356e86SAndroid Build Coastguard Worker 	case 'u':
2589*7c356e86SAndroid Build Coastguard Worker 		  i = 4;
2590*7c356e86SAndroid Build Coastguard Worker 		if (/* CONSTCOND */ 0)
2591*7c356e86SAndroid Build Coastguard Worker 			/* FALLTHROUGH */
2592*7c356e86SAndroid Build Coastguard Worker 	case 'x':
2593*7c356e86SAndroid Build Coastguard Worker 		  i = cstyle ? -1 : 2;
2594*7c356e86SAndroid Build Coastguard Worker 		/**
2595*7c356e86SAndroid Build Coastguard Worker 		 * x:	look for a hexadecimal number with up to
2596*7c356e86SAndroid Build Coastguard Worker 		 *	two (C style: arbitrary) digits; convert
2597*7c356e86SAndroid Build Coastguard Worker 		 *	to raw octet (C style: UCS if >0xFF)
2598*7c356e86SAndroid Build Coastguard Worker 		 * u/U:	look for a hexadecimal number with up to
2599*7c356e86SAndroid Build Coastguard Worker 		 *	four (U: eight) digits; convert to UCS
2600*7c356e86SAndroid Build Coastguard Worker 		 */
2601*7c356e86SAndroid Build Coastguard Worker 		wc = 0;
2602*7c356e86SAndroid Build Coastguard Worker 		n = 0;
2603*7c356e86SAndroid Build Coastguard Worker 		while (n < i || i == -1) {
2604*7c356e86SAndroid Build Coastguard Worker 			wc <<= 4;
2605*7c356e86SAndroid Build Coastguard Worker 			if (!ctype((c = (*fg)()), C_SEDEC)) {
2606*7c356e86SAndroid Build Coastguard Worker 				wc >>= 4;
2607*7c356e86SAndroid Build Coastguard Worker 				(*fp)(c);
2608*7c356e86SAndroid Build Coastguard Worker 				break;
2609*7c356e86SAndroid Build Coastguard Worker 			}
2610*7c356e86SAndroid Build Coastguard Worker 			if (ctype(c, C_DIGIT))
2611*7c356e86SAndroid Build Coastguard Worker 				wc += ksh_numdig(c);
2612*7c356e86SAndroid Build Coastguard Worker 			else if (ctype(c, C_UPPER))
2613*7c356e86SAndroid Build Coastguard Worker 				wc += ksh_numuc(c) + 10;
2614*7c356e86SAndroid Build Coastguard Worker 			else
2615*7c356e86SAndroid Build Coastguard Worker 				wc += ksh_numlc(c) + 10;
2616*7c356e86SAndroid Build Coastguard Worker 			++n;
2617*7c356e86SAndroid Build Coastguard Worker 		}
2618*7c356e86SAndroid Build Coastguard Worker 		if (!n)
2619*7c356e86SAndroid Build Coastguard Worker 			goto unknown_escape;
2620*7c356e86SAndroid Build Coastguard Worker 		if ((cstyle && wc > 0xFF) || fc != 'x')
2621*7c356e86SAndroid Build Coastguard Worker 			/* UCS marker */
2622*7c356e86SAndroid Build Coastguard Worker 			wc += 0x100;
2623*7c356e86SAndroid Build Coastguard Worker 		break;
2624*7c356e86SAndroid Build Coastguard Worker 	case '\'':
2625*7c356e86SAndroid Build Coastguard Worker 		if (!cstyle)
2626*7c356e86SAndroid Build Coastguard Worker 			goto unknown_escape;
2627*7c356e86SAndroid Build Coastguard Worker 		wc = '\'';
2628*7c356e86SAndroid Build Coastguard Worker 		break;
2629*7c356e86SAndroid Build Coastguard Worker 	case '\\':
2630*7c356e86SAndroid Build Coastguard Worker 		wc = '\\';
2631*7c356e86SAndroid Build Coastguard Worker 		break;
2632*7c356e86SAndroid Build Coastguard Worker 	default:
2633*7c356e86SAndroid Build Coastguard Worker  unknown_escape:
2634*7c356e86SAndroid Build Coastguard Worker 		(*fp)(fc);
2635*7c356e86SAndroid Build Coastguard Worker 		return (-1);
2636*7c356e86SAndroid Build Coastguard Worker 	}
2637*7c356e86SAndroid Build Coastguard Worker 
2638*7c356e86SAndroid Build Coastguard Worker 	return (wc);
2639*7c356e86SAndroid Build Coastguard Worker }
2640