15155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*	$OpenBSD: misc.c,v 1.37 2009/04/19 20:34:05 sthen Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*	$OpenBSD: path.c,v 1.12 2005/03/30 17:16:37 deraadt Exp $	*/
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
45155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
65155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Thorsten Glaser <tg@mirbsd.org>
75155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
85155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Provided that these terms and disclaimer and all copyright notices
95155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * are retained or reproduced in an accompanying document, permission
105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * is granted to deal in this work without restriction, including un-
115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * limited rights to use, publicly perform, distribute, sell, modify,
125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * merge, give away, or sublicence.
135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the utmost extent permitted by applicable law, neither express nor
165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * implied; without malicious intent or gross negligence. In no event
175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * may a licensor, author or contributor be held liable for indirect,
185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * direct, other damage, loss, or other issues arising in any way out
195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of dealing in the work, even if advised of the possibility of such
205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * damage or existence of a defect, except proven that it results out
215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * of said person's immediate fault when using the work as intended.
225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh.h"
255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !HAVE_GETRUSAGE
265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include <sys/times.h>
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_GRP_H
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include <grp.h>
305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.172 2011/09/07 15:24:18 tg Exp $");
335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* type bits for unsigned char */
3503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraunsigned char chtypes[UCHAR_MAX + 1];
365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic const unsigned char *pat_scan(const unsigned char *,
3803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    const unsigned char *, bool);
395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int do_gmatch(const unsigned char *, const unsigned char *,
405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    const unsigned char *, const unsigned char *);
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const unsigned char *cclass(const unsigned char *, int);
425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef TIOCSCTTY
435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void chvt(const char *);
445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*XXX this should go away */
4703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int make_path(const char *, const char *, char **, XString *, int *);
4803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
4903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifdef SETUID_CAN_FAIL_WITH_EAGAIN
5003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* we don't need to check for other codes, EPERM won't happen */
5103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define DO_SETUID(func, argvec) do {					\
5203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if ((func argvec) && errno == EAGAIN)				\
5303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errorf("%s failed with EAGAIN, probably due to a"	\
5403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    " too low process limit; aborting", #func);		\
5503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra} while (/* CONSTCOND */ 0)
5603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#else
5703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define DO_SETUID(func, argvec) func argvec
5803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
5903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Fast character classes
625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetctypes(const char *s, int t)
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned int i;
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (t & C_IFS) {
695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; i < UCHAR_MAX + 1; i++)
705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			chtypes[i] &= ~C_IFS;
7103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* include \0 in C_IFS */
7203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		chtypes[0] |= C_IFS;
735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (*s != 0)
755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		chtypes[(unsigned char)*s++] |= t;
765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinitctypes(void)
805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (c = 'a'; c <= 'z'; c++)
845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		chtypes[c] |= C_ALPHA;
855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (c = 'A'; c <= 'Z'; c++)
865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		chtypes[c] |= C_ALPHA;
875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	chtypes['_'] |= C_ALPHA;
885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setctypes("0123456789", C_DIGIT);
8903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* \0 added automatically */
9003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	setctypes(" \t\n|&;<>()", C_LEX1);
915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setctypes("*@#!$-?", C_VAR1);
925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setctypes(" \t\n", C_IFSWS);
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setctypes("=-+?", C_SUBOP1);
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	setctypes("\t\n \"#$&'()*;<=>?[\\]`|", C_QUOTE);
955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* called from XcheckN() to grow buffer */
985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
9903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy CondraXcheck_grow_(XString *xsp, const char *xp, size_t more)
1005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *old_beg = xsp->beg;
1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (more < xsp->len)
10403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		more = xsp->len;
10503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* (xsp->len + X_EXTRA) never overflows */
10603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	checkoktoadd(more, xsp->len + X_EXTRA);
10703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	xsp->beg = aresize(xsp->beg, (xsp->len += more) + X_EXTRA, xsp->areap);
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	xsp->end = xsp->beg + xsp->len;
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (xsp->beg + (xp - old_beg));
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define SHFLAGS_DEFNS
1135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh_flags.h"
1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruconst struct shoption options[] = {
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define SHFLAGS_ITEMS
1175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "sh_flags.h"
1185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
1195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
1215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * translate -o option into F* constant (also used for test -o option)
1225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusize_t
1245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruoption(const char *n)
1255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t i;
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((n[0] == '-' || n[0] == '+') && n[1] && !n[2]) {
1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; i < NELEM(options); i++)
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (options[i].c == n[1])
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (i);
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else for (i = 0; i < NELEM(options); i++)
1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (options[i].name && strcmp(options[i].name, n) == 0)
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (i);
1355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return ((size_t)-1);
1375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct options_info {
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int opt_width;
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int opts[NELEM(options)];
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic char *options_fmt_entry(char *, size_t, int, const void *);
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void printoptions(bool);
1465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* format a single select menu item */
1485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *
14903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraoptions_fmt_entry(char *buf, size_t buflen, int i, const void *arg)
1505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const struct options_info *oi = (const struct options_info *)arg;
1525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	shf_snprintf(buf, buflen, "%-*s %s",
1545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    oi->opt_width, options[oi->opts[i]].name,
1555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    Flag(oi->opts[i]) ? "on" : "off");
1565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (buf);
1575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
1605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruprintoptions(bool verbose)
1615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
16203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t i = 0;
1635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (verbose) {
16503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		ssize_t n = 0, len, octs = 0;
1665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct options_info oi;
1675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* verbose version */
1695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_puts("Current option settings\n", shl_stdout);
1705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		oi.opt_width = 0;
17203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (i < NELEM(options)) {
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (options[i].name) {
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				oi.opts[n++] = i;
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				len = strlen(options[i].name);
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (len > octs)
1775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					octs = len;
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				len = utf_mbswidth(options[i].name);
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (len > oi.opt_width)
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					oi.opt_width = len;
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++i;
1835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		print_columns(shl_stdout, n, options_fmt_entry, &oi,
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    octs + 4, oi.opt_width + 4, true);
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
18703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* short version like AT&T ksh93 */
18803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shf_puts(Tset, shl_stdout);
1895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (i < (int)NELEM(options)) {
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (Flag(i) && options[i].name)
19103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				shprintf("%s %s %s", null, "-o",
19203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				    options[i].name);
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			++i;
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_putc('\n', shl_stdout);
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querugetoptions(void)
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
20203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t i;
20303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char m[(int)FNFLAGS + 1];
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *cp = m;
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (i = 0; i < NELEM(options); i++)
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (options[i].c && Flag(i))
2085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cp++ = options[i].c;
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	strndupx(cp, m, cp - m, ATEMP);
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (cp);
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* change a Flag(*) value; takes care of special actions */
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchange_flag(enum sh_flag f, int what, unsigned int newval)
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	unsigned char oldval;
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	oldval = Flag(f);
22003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* needed for tristates */
22103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Flag(f) = newval ? 1 : 0;
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_UNEMPLOYED
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (f == FMONITOR) {
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (what != OF_CMDLINE && newval != oldval)
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			j_change();
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	  if ((
2295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !MKSH_S_NOVI
2305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    f == FVI ||
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    f == FEMACS || f == FGMACS) && newval) {
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !MKSH_S_NOVI
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Flag(FVI) =
2355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
2365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    Flag(FEMACS) = Flag(FGMACS) = 0;
2375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Flag(f) = (unsigned char)newval;
2385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (f == FPRIVILEGED && oldval && !newval) {
2395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Turning off -p? */
2405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
24103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*XXX this can probably be optimised */
24203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		kshegid = kshgid = getgid();
24303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#if HAVE_SETRESUGID
24403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		DO_SETUID(setresgid, (kshegid, kshegid, kshegid));
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_SETGROUPS
24603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* setgroups doesn't EAGAIN on Linux */
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setgroups(1, &kshegid);
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
24903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		DO_SETUID(setresuid, (ksheuid, ksheuid, ksheuid));
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#else
25103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* seteuid, setegid, setgid don't EAGAIN on Linux */
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		seteuid(ksheuid = kshuid = getuid());
25303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		DO_SETUID(setuid, (ksheuid));
25403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		setegid(kshegid);
2555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setgid(kshegid);
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if ((f == FPOSIX || f == FSH) && newval) {
2585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Flag(FPOSIX) = Flag(FSH) = Flag(FBRACEEXPAND) = 0;
2595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Flag(f) = (unsigned char)newval;
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Changing interactive flag? */
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (f == FTALKING) {
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((what == OF_CMDLINE || what == OF_SET) && procpid == kshpid)
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			Flag(FTALKING_I) = (unsigned char)newval;
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
26803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
26903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Parse command line and set command arguments. Returns the index of
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * non-option arguments, -1 if there is an error.
2715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruparse_args(const char **argv,
27403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* OF_CMDLINE or OF_SET */
27503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    int what,
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    bool *setargsp)
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static char cmd_opts[NELEM(options) + 5]; /* o:T:\0 */
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static char set_opts[NELEM(options) + 6]; /* A:o;s\0 */
2805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char set, *opts;
2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *array = NULL;
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	Getopt go;
2835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t i;
28403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int optc, arrayset = 0;
28503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool sortargs = false;
2865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* First call? Build option strings... */
2885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (cmd_opts[0] == '\0') {
2895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *p = cmd_opts, *q = set_opts;
2905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* see cmd_opts[] declaration */
2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*p++ = 'o';
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*p++ = ':';
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !defined(MKSH_SMALL) || defined(TIOCSCTTY)
2955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*p++ = 'T';
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*p++ = ':';
2975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
2985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* see set_opts[] declaration */
2995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*q++ = 'A';
3005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*q++ = ':';
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*q++ = 'o';
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*q++ = ';';
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*q++ = 's';
3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; i < NELEM(options); i++) {
3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (options[i].c) {
3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (options[i].flags & OF_CMDLINE)
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*p++ = options[i].c;
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (options[i].flags & OF_SET)
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*q++ = options[i].c;
3115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*p = '\0';
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*q = '\0';
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (what == OF_CMDLINE) {
3185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		const char *p = argv[0], *q;
31903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
32003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Set FLOGIN before parsing options so user can clear
3215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * flag using +l.
3225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*p != '-')
3245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (q = p; *q; )
3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (*q++ == '/')
3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					p = q;
3275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		Flag(FLOGIN) = (*p == '-');
3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		opts = cmd_opts;
3295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (what == OF_FIRSTTIME) {
3305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		opts = cmd_opts;
3315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
3325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		opts = set_opts;
3335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ksh_getopt_reset(&go, GF_ERROR|GF_PLUSOPT);
3345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((optc = ksh_getopt(argv, &go, opts)) != -1) {
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		set = (go.info & GI_PLUS) ? 0 : 1;
3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (optc) {
3375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'A':
3385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (what == OF_FIRSTTIME)
3395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			arrayset = set ? 1 : -1;
3415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			array = go.optarg;
3425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'o':
3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (what == OF_FIRSTTIME)
3465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (go.optarg == NULL) {
34803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
34903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * lone -o: print options
3505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 *
3515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * Note that on the command line, -o requires
3525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * an option (ie, can't get here if what is
3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * OF_CMDLINE).
3545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
3555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				printoptions(set);
3565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			i = option(go.optarg);
3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((i != (size_t)-1) && set == Flag(i))
36003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/*
36103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				 * Don't check the context if the flag
3625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * isn't changing - makes "set -o interactive"
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * work if you're already interactive. Needed
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 * if the output of "set +o" is to be used.
3655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				 */
3665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				;
3675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else if ((i != (size_t)-1) && (options[i].flags & what))
3685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				change_flag((enum sh_flag)i, what, set);
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
37003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				bi_errorf("%s: %s", go.optarg, "bad option");
3715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (-1);
3725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
3745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !defined(MKSH_SMALL) || defined(TIOCSCTTY)
3765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case 'T':
3775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (what != OF_FIRSTTIME)
3785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef TIOCSCTTY
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errorf("no TIOCSCTTY ioctl");
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#else
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			change_flag(FTALKING, OF_CMDLINE, 1);
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			chvt(go.optarg);
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
3865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
3875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '?':
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
3905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (what == OF_FIRSTTIME)
3935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* -s: sort positional params (AT&T ksh stupidity) */
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (what == OF_SET && optc == 's') {
39603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				sortargs = true;
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (i = 0; i < NELEM(options); i++)
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (optc == options[i].c &&
4015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    (what & options[i].flags)) {
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					change_flag((enum sh_flag)i, what, set);
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (i == NELEM(options))
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				internal_errorf("parse_args: '%c'", optc);
4075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(go.info & GI_MINUSMINUS) && argv[go.optind] &&
4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') &&
4115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    argv[go.optind][1] == '\0') {
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* lone - clears -v and -x flags */
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (argv[go.optind][0] == '-')
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			Flag(FVERBOSE) = Flag(FXTRACE) = 0;
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* set skips lone - or + option */
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go.optind++;
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (setargsp)
4195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* -- means set $#/$* even if there are no arguments */
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*setargsp = !arrayset && ((go.info & GI_MINUSMINUS) ||
4215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    argv[go.optind]);
4225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
42303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (arrayset) {
42403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		const char *ccp = NULL;
42503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
42603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (*array)
42703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ccp = skip_varname(array, false);
42803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!ccp || !(!ccp[0] || (ccp[0] == '+' && !ccp[1]))) {
42903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("%s: %s", array, "is not an identifier");
43003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (-1);
43103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
4325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (sortargs) {
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = go.optind; argv[i]; i++)
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			;
4365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		qsort(&argv[go.optind], i - go.optind, sizeof(void *),
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    xstrcmp);
4385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (arrayset)
44003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		go.optind += set_array(array, tobool(arrayset > 0),
4415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    argv + go.optind);
4425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (go.optind);
4445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* parse a decimal number: returns 0 if string isn't a number, 1 otherwise */
4475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querugetn(const char *s, int *ai)
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i, c, rv = 0;
4515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool neg = false;
4525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	do {
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = *s++;
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} while (ksh_isspace(c));
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == '-') {
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		neg = true;
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = *s++;
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (c == '+')
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = *s++;
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*ai = i = 0;
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	do {
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!ksh_isdigit(c))
4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto getn_out;
4655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i *= 10;
4665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (i < *ai)
4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* overflow */
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto getn_out;
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i += c - '0';
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*ai = i;
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} while ((c = *s++));
4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	rv = 1;
4735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru getn_out:
4755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (neg)
4765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*ai = -*ai;
4775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* getn() that prints error */
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querubi_getn(const char *as, int *ai)
4835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int rv;
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(rv = getn(as, ai)))
48703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		bi_errorf("%s: %s", as, "bad number");
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
49103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/**
49203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * pattern simplifications:
49303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * - @(x) -> x (not @(x|y) though)
49403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * - ** -> *
49503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra */
49603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic void *
49703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasimplify_gmatch_pattern(const unsigned char *sp)
49803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
49903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	uint8_t c;
50003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	unsigned char *cp, *dp;
50103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	const unsigned char *ps, *se;
50203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
50303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	cp = alloc(strlen((const void *)sp) + 1, ATEMP);
50403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	goto simplify_gmatch_pat1a;
50503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
50603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* foo@(b@(a)r)b@(a|a)z -> foobarb@(a|a)z */
50703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra simplify_gmatch_pat1:
50803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	sp = cp;
50903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra simplify_gmatch_pat1a:
51003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	dp = cp;
51103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	se = sp + strlen((const void *)sp);
51203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while ((c = *sp++)) {
51303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!ISMAGIC(c)) {
51403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*dp++ = c;
51503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			continue;
51603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
51703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		switch ((c = *sp++)) {
51803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|'@':
51903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* simile for @ */
52003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|' ':
52103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* check whether it has only one clause */
52203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ps = pat_scan(sp, se, true);
52303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!ps || ps[-1] != /*(*/ ')')
52403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* nope */
52503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				break;
52603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* copy inner clause until matching close */
52703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ps -= 2;
52803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			while ((const unsigned char *)sp < ps)
52903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				*dp++ = *sp++;
53003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* skip MAGIC and closing parenthesis */
53103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			sp += 2;
53203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* copy the rest of the pattern */
53303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			memmove(dp, sp, strlen((const void *)sp) + 1);
53403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* redo from start */
53503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto simplify_gmatch_pat1;
53603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
53703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*dp++ = MAGIC;
53803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*dp++ = c;
53903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
54003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	*dp = '\0';
54103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
54203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* collapse adjacent asterisk wildcards */
54303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	sp = dp = cp;
54403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while ((c = *sp++)) {
54503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!ISMAGIC(c)) {
54603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*dp++ = c;
54703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			continue;
54803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
54903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		switch ((c = *sp++)) {
55003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case '*':
55103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			while (ISMAGIC(sp[0]) && sp[1] == c)
55203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				sp += 2;
55303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
55403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
55503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*dp++ = MAGIC;
55603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*dp++ = c;
55703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
55803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	*dp = '\0';
55903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
56003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* return the result, allocated from ATEMP */
56103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (cp);
56203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
56303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
5645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* -------- gmatch.c -------- */
5655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * int gmatch(string, pattern)
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * char *string, *pattern;
5695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
5705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Match a pattern as in sh(1).
5715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * pattern character are prefixed with MAGIC by expand.
5725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
5745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querugmatchx(const char *s, const char *p, bool isfile)
5755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *se, *pe;
57703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *pnew;
57803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int rv;
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (s == NULL || p == NULL)
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
5825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	se = s + strlen(s);
5845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	pe = p + strlen(p);
58503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
58603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * isfile is false iff no syntax check has been done on
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * the pattern. If check fails, just to a strcmp().
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!isfile && !has_globbing(p, pe)) {
5905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		size_t len = pe - p + 1;
5915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char tbuf[64];
5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *t = len <= sizeof(tbuf) ? tbuf : alloc(len, ATEMP);
5935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		debunk(t, p, len);
5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (!strcmp(t, s));
5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
59603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
59703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
59803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * since the do_gmatch() engine sucks so much, we must do some
59903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * pattern simplifications
60003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 */
60103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	pnew = simplify_gmatch_pattern((const unsigned char *)p);
60203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	pe = pnew + strlen(pnew);
60303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
60403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	rv = do_gmatch((const unsigned char *)s, (const unsigned char *)se,
60503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    (const unsigned char *)pnew, (const unsigned char *)pe);
60603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(pnew, ATEMP);
60703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (rv);
6085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
61003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/**
61103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Returns if p is a syntacticly correct globbing pattern, false
6125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * if it contains no pattern characters or if there is a syntax error.
6135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Syntax errors are:
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- [ with no closing ]
6155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- imbalanced $(...) expression
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- [...] and *(...) not nested (eg, [a$(b|]c), *(a[b|c]d))
6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*XXX
61903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * - if no magic,
62003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *	if dest given, copy to dst
62103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *	return ?
62203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * - if magic && (no globbing || syntax error)
62303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *	debunk to dst
62403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *	return ?
62503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * - return ?
62603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra */
6275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
6285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruhas_globbing(const char *xp, const char *xpe)
6295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const unsigned char *p = (const unsigned char *) xp;
6315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const unsigned char *pe = (const unsigned char *) xpe;
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
6335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int nest = 0, bnest = 0;
63403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool saw_glob = false;
63503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* inside [...] */
63603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool in_bracket = false;
6375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (; p < pe; p++) {
6395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!ISMAGIC(*p))
6405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
6415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((c = *++p) == '*' || c == '?')
64203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			saw_glob = true;
6435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (c == '[') {
6445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!in_bracket) {
64503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				saw_glob = true;
64603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				in_bracket = true;
6475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (ISMAGIC(p[1]) && p[2] == NOT)
6485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					p += 2;
6495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (ISMAGIC(p[1]) && p[2] == ']')
6505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					p += 2;
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
65203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*XXX Do we need to check ranges here? POSIX Q */
6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (c == ']') {
6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (in_bracket) {
65503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (bnest)
65603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* [a*(b]) */
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (0);
65803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				in_bracket = false;
6595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if ((c & 0x80) && vstrchr("*+?@! ", c & 0x7f)) {
66103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			saw_glob = true;
6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (in_bracket)
6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				bnest++;
6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
6655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				nest++;
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (c == '|') {
66703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (in_bracket && !bnest)
66803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* *(a[foo|bar]) */
6695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
6705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (c == /*(*/ ')') {
6715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (in_bracket) {
67203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (!bnest--)
67303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* *(a[b)c] */
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (0);
6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else if (nest)
6765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				nest--;
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
6785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
6795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * else must be a MAGIC-MAGIC, or MAGIC-!,
6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * MAGIC--, MAGIC-], MAGIC-{, MAGIC-, MAGIC-}
6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (saw_glob && !in_bracket && !nest);
6845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Function must return either 0 or 1 (assumed by code for 0x80|'!') */
6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
6885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querudo_gmatch(const unsigned char *s, const unsigned char *se,
6895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    const unsigned char *p, const unsigned char *pe)
6905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int sc, pc;
6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const unsigned char *prest, *psub, *pnext;
6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const unsigned char *srest;
6945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (s == NULL || p == NULL)
6965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (p < pe) {
6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		pc = *p++;
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sc = s < se ? *s : '\0';
7005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s++;
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!ISMAGIC(pc)) {
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (sc != pc)
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (*p++) {
7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '[':
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (sc == 0 || (p = cclass(p, sc)) == NULL)
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '?':
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (sc == 0)
7145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
7155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (UTFMODE) {
7165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				--s;
7175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				s += utf_ptradj((const void *)s);
7185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
7205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '*':
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (p == pe)
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (1);
7245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s--;
7255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			do {
7265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (do_gmatch(s, se, p, pe))
7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (1);
7285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} while (s++ < se);
7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (0);
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/**
7325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * [*+?@!](pattern|pattern|..)
7335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * This is also needed for ${..%..}, etc.
7345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
73503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
73603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* matches one or more times */
73703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|'+':
73803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* matches zero or more times */
73903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|'*':
74003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!(prest = pat_scan(p, pe, false)))
7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s--;
7435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* take care of zero matches */
7445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (p[-1] == (0x80 | '*') &&
7455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    do_gmatch(s, se, prest, pe))
7465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (1);
7475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (psub = p; ; psub = pnext) {
74803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				pnext = pat_scan(psub, pe, true);
7495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				for (srest = s; srest <= se; srest++) {
7505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (do_gmatch(s, srest, psub, pnext - 2) &&
7515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    (do_gmatch(srest, se, prest, pe) ||
7525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    (s != srest && do_gmatch(srest,
7535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    se, p - 2, pe))))
7545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						return (1);
7555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
7565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (pnext == prest)
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
7585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (0);
7605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
76103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* matches zero or once */
76203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|'?':
76303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* matches one of the patterns */
76403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|'@':
76503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* simile for @ */
76603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|' ':
76703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!(prest = pat_scan(p, pe, false)))
7685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
7695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s--;
7705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* Take care of zero matches */
7715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (p[-1] == (0x80 | '?') &&
7725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    do_gmatch(s, se, prest, pe))
7735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (1);
7745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (psub = p; ; psub = pnext) {
77503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				pnext = pat_scan(psub, pe, true);
7765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				srest = prest == pe ? se : s;
7775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				for (; srest <= se; srest++) {
7785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (do_gmatch(s, srest, psub, pnext - 2) &&
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    do_gmatch(srest, se, prest, pe))
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						return (1);
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (pnext == prest)
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
7855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (0);
7865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
78703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* matches none of the patterns */
78803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 0x80|'!':
78903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!(prest = pat_scan(p, pe, false)))
7905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
7915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s--;
7925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (srest = s; srest <= se; srest++) {
7935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				int matched = 0;
7945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				for (psub = p; ; psub = pnext) {
79603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					pnext = pat_scan(psub, pe, true);
7975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (do_gmatch(s, srest, psub,
7985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    pnext - 2)) {
7995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						matched = 1;
8005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						break;
8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
8025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (pnext == prest)
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						break;
8045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
8055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (!matched &&
8065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    do_gmatch(srest, se, prest, pe))
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (1);
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (0);
8105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
8125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (sc != p[-1])
8135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (0);
8145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
8155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (s == se);
8185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const unsigned char *
8215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querucclass(const unsigned char *p, int sub)
8225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c, d, notp, found = 0;
8245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const unsigned char *orig_p = p;
8255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((notp = (ISMAGIC(*p) && *++p == NOT)))
8275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		p++;
8285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	do {
8295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = *p++;
8305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ISMAGIC(c)) {
8315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			c = *p++;
8325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((c & 0x80) && !ISMAGIC(c)) {
83303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* extended pattern matching: *+?@! */
83403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				c &= 0x7F;
8355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* XXX the ( char isn't handled as part of [] */
83603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (c == ' ')
83703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* simile for @: plain (..) */
8385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					c = '(' /*)*/;
8395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == '\0')
8425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* No closing ] - act as if the opening [ was quoted */
8435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (sub == '[' ? orig_p : NULL);
8445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ISMAGIC(p[0]) && p[1] == '-' &&
8455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (!ISMAGIC(p[2]) || p[3] != ']')) {
84603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* MAGIC- */
84703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			p += 2;
8485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			d = *p++;
8495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ISMAGIC(d)) {
8505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				d = *p++;
8515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((d & 0x80) && !ISMAGIC(d))
8525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					d &= 0x7f;
8535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* POSIX says this is an invalid expression */
8555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (c > d)
8565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (NULL);
8575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
8585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			d = c;
8595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == sub || (c <= sub && sub <= d))
8605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			found = 1;
8615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} while (!(ISMAGIC(p[0]) && p[1] == ']'));
8625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return ((found != notp) ? p+2 : NULL);
8645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Look for next ) or | (if match_sep) in *(foo|bar) pattern */
86703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic const unsigned char *
86803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrapat_scan(const unsigned char *p, const unsigned char *pe, bool match_sep)
8695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int nest = 0;
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (; p < pe; p++) {
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!ISMAGIC(*p))
8745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
8755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((*++p == /*(*/ ')' && nest-- == 0) ||
8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (*p == '|' && match_sep && nest == 0))
8775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (p + 1);
8785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((*p & 0x80) && vstrchr("*+?@! ", *p & 0x7f))
8795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			nest++;
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (NULL);
8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
8855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruxstrcmp(const void *p1, const void *p2)
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (strcmp(*(const char * const *)p1, *(const char * const *)p2));
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Initialise a Getopt structure */
8915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
8925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruksh_getopt_reset(Getopt *go, int flags)
8935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
8945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->optind = 1;
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->optarg = NULL;
8965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->p = 0;
8975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->flags = flags;
8985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->info = 0;
8995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->buf[1] = '\0';
9005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
9015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
90303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/**
90403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * getopt() used for shell built-in commands, the getopts command, and
9055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * command line options.
9065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * A leading ':' in options means don't print errors, instead return '?'
9075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * or ':' and set go->optarg to the offending option character.
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * If GF_ERROR is set (and option doesn't start with :), errors result in
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * a call to bi_errorf().
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
9115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Non-standard features:
9125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- ';' is like ':' in options, except the argument is optional
9135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  (if it isn't present, optarg is set to 0).
9145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  Used for 'set -o'.
9155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- ',' is like ':' in options, except the argument always immediately
9165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  follows the option character (optarg is set to the null string if
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  the option is missing).
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  Used for 'read -u2', 'print -u2' and fc -40.
9195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- '#' is like ':' in options, expect that the argument is optional
9205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  and must start with a digit. If the argument doesn't start with a
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  digit, it is assumed to be missing and normal option processing
9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  continues (optarg is set to 0 if the option is missing).
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  Used for 'typeset -LZ4'.
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- accepts +c as well as -c IF the GF_PLUSOPT flag is present. If an
9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  option starting with + is accepted, the GI_PLUS flag will be set
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  in go->info.
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruksh_getopt(const char **argv, Getopt *go, const char *optionsp)
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char c;
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *o;
9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (go->p == 0 || (c = argv[go->optind - 1][go->p]) == '\0') {
9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		const char *arg = argv[go->optind], flag = arg ? *arg : '\0';
9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->p = 1;
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (flag == '-' && arg[1] == '-' && arg[2] == '\0') {
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->optind++;
9405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->p = 0;
9415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->info |= GI_MINUSMINUS;
9425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
9435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (arg == NULL ||
94503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    ((flag != '-' ) &&
94603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    /* neither a - nor a + (if + allowed) */
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (!(go->flags & GF_PLUSOPT) || flag != '+')) ||
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (c = arg[1]) == '\0') {
9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->p = 0;
9505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
9515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->optind++;
9535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->info &= ~(GI_MINUS|GI_PLUS);
9545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->info |= flag == '-' ? GI_MINUS : GI_PLUS;
9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	go->p++;
9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (c == '?' || c == ':' || c == ';' || c == ',' || c == '#' ||
9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    !(o = cstrchr(optionsp, c))) {
9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (optionsp[0] == ':') {
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->buf[0] = c;
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->optarg = go->buf;
9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
96303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s%s-%c: %s",
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (go->flags & GF_NONAME) ? "" : argv[0],
96503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    (go->flags & GF_NONAME) ? "" : ": ", c,
96603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "unknown option");
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (go->flags & GF_ERROR)
9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				bi_errorfz();
9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return ('?');
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
97203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/**
97303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * : means argument must be present, may be part of option argument
9745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 *   or the next argument
9755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * ; same as : but argument may be missing
9765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * , means argument is part of option argument, and may be null.
9775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
9785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (*++o == ':' || *o == ';') {
9795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (argv[go->optind - 1][go->p])
9805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->optarg = argv[go->optind - 1] + go->p;
9815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (argv[go->optind])
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->optarg = argv[go->optind++];
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (*o == ';')
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			go->optarg = NULL;
9855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (optionsp[0] == ':') {
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->buf[0] = c;
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->optarg = go->buf;
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (':');
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
99103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(true, "%s%s-%c: %s",
9925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (go->flags & GF_NONAME) ? "" : argv[0],
99303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    (go->flags & GF_NONAME) ? "" : ": ", c,
99403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "requires an argument");
9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (go->flags & GF_ERROR)
9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				bi_errorfz();
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return ('?');
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->p = 0;
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (*o == ',') {
10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* argument is attached to option character, even if null */
10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->optarg = argv[go->optind - 1] + go->p;
10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		go->p = 0;
10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (*o == '#') {
100503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
100603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * argument is optional and may be attached or unattached
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * but must start with a digit. optarg is set to 0 if the
10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * argument is missing.
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (argv[go->optind - 1][go->p]) {
10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ksh_isdigit(argv[go->optind - 1][go->p])) {
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->optarg = argv[go->optind - 1] + go->p;
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->p = 0;
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->optarg = NULL;
10165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (argv[go->optind] && ksh_isdigit(argv[go->optind][0])) {
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->optarg = argv[go->optind++];
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->p = 0;
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				go->optarg = NULL;
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (c);
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
102703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
102803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * print variable/alias value using necessary quotes
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * (POSIX says they should be suitable for re-entry...)
10305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * No trailing newline is printed.
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
10335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruprint_value_quoted(const char *s)
10345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p;
103603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool inquote = false;
10375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
103803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* first, check whether any quotes are needed */
10395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = s; *p; p++)
10405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ctype(*p, C_QUOTE))
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!*p) {
104303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* nope, use the shortcut */
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_puts(s, shl_stdout);
10455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
104703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
104803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* quote via state machine */
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (p = s; *p; p++) {
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*p == '\'') {
105103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
105203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * multiple '''s or any ' at beginning of string
105303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * look nicer this way than when simply substituting
105403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 */
105503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (inquote) {
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_putc('\'', shl_stdout);
105703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				inquote = false;
105803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
10595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_putc('\\', shl_stdout);
10605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else if (!inquote) {
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_putc('\'', shl_stdout);
106203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			inquote = true;
10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_putc(*p, shl_stdout);
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (inquote)
10675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_putc('\'', shl_stdout);
10685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
10715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Print things in columns and rows - func() is called to format
10725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * the i-th element
10735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruprint_columns(struct shf *shf, int n,
107603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    char *(*func)(char *, size_t, int, const void *),
107703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    const void *arg, size_t max_oct, size_t max_colz, bool prefcol)
10785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
107903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int i, r, c, rows, cols, nspace, max_col;
10805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *str;
10815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (n <= 0) {
10835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifndef MKSH_SMALL
10845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		internal_warningf("print_columns called with n=%d <= 0", n);
10855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
10865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
10875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
108903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (max_colz > 2147483647) {
109003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifndef MKSH_SMALL
109103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		internal_warningf("print_columns called with max_col=%zu > INT_MAX",
109203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    max_colz);
109303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
109403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return;
109503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
109603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	max_col = (int)max_colz;
109703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
10985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	++max_oct;
10995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	str = alloc(max_oct, ATEMP);
11005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* ensure x_cols is valid first */
11025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (x_cols < MIN_COLS)
11035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		change_winsz();
11045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/*
11065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * We use (max_col + 1) to consider the space separator.
11075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * Note that no space is printed after the last column
11085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * to avoid problems with terminals that have auto-wrap.
11095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
11105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	cols = x_cols / (max_col + 1);
11115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* if we can only print one column anyway, skip the goo */
11135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (cols < 2) {
11145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (i = 0; i < n; ++i)
11155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_fprintf(shf, "%s \n",
11165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (*func)(str, max_oct, i, arg));
11175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto out;
11185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	rows = (n + cols - 1) / cols;
11215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (prefcol && cols > rows) {
11225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = rows;
11235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		rows = cols > n ? n : cols;
11245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		cols = i;
11255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	max_col = -max_col;
11285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	nspace = (x_cols + max_col * cols) / cols;
11295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (nspace <= 0)
11305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nspace = 1;
11315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (r = 0; r < rows; r++) {
11325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (c = 0; c < cols; c++) {
11335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			i = c * rows + r;
11345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (i < n) {
11355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				shf_fprintf(shf, "%*s", max_col,
11365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    (*func)(str, max_oct, i, arg));
11375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (c + 1 < cols)
11385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					shf_fprintf(shf, "%*s", nspace, null);
11395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
11405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		shf_putchar('\n', shf);
11425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru out:
11445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afree(str, ATEMP);
11455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Strip any nul bytes from buf - returns new length (nbytes - # of nuls) */
11485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
11495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustrip_nuls(char *buf, int nbytes)
11505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *dst;
11525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
115303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
115403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * nbytes check because some systems (older FreeBSDs) have a
115503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * buggy memchr()
11565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (nbytes && (dst = memchr(buf, '\0', nbytes))) {
11585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *end = buf + nbytes;
11595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *p, *q;
11605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (p = dst; p < end; p = q) {
11625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* skip a block of nulls */
11635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (++p < end && *p == '\0')
11645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				;
11655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* find end of non-null block */
11665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(q = memchr(p, '\0', end - p)))
11675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				q = end;
11685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memmove(dst, p, q - p);
11695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			dst += q - p;
11705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*dst = '\0';
11725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
117503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
117603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Like read(2), but if read fails due to non-blocking flag,
117703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * resets flag and restarts read.
11785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
117903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrassize_t
118003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrablocking_read(int fd, char *buf, size_t nbytes)
11815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
118203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t ret;
118303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool tried_reset = false;
11845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((ret = read(fd, buf, nbytes)) < 0) {
11865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!tried_reset && errno == EAGAIN) {
11875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (reset_nonblock(fd) > 0) {
118803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				tried_reset = true;
11895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
11905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
11915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errno = EAGAIN;
11925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
11935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
11945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
11955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (ret);
11965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
119803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
119903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Reset the non-blocking flag on the specified file descriptor.
12005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Returns -1 if there was an error, 0 if non-blocking wasn't set,
12015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * 1 if it was.
12025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
12035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
12045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querureset_nonblock(int fd)
12055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int flags;
12075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
12095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
12105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(flags & O_NONBLOCK))
12115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
12125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	flags &= ~O_NONBLOCK;
12135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (fcntl(fd, F_SETFL, flags) < 0)
12145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
12155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (1);
12165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
121803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* getcwd(3) equivalent, allocates from ATEMP but doesn't resize */
12195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
122003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraksh_get_wd(void)
12215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
12225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef NO_PATH_MAX
122303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *rv, *cp;
122403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
122503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if ((cp = get_current_dir_name())) {
122603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strdupx(rv, cp, ATEMP);
122703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		free_gnu_gcdn(cp);
12285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
122903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rv = NULL;
12305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#else
123103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *rv;
123203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
123303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (!getcwd((rv = alloc(PATH_MAX + 1, ATEMP)), PATH_MAX)) {
123403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		afree(rv, ATEMP);
123503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rv = NULL;
123603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
12375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
12385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
123903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (rv);
12405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
124203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrachar *
124303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrado_realpath(const char *upath)
124403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
124503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *xp, *ip, *tp, *ipath, *ldest = NULL;
124603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	XString xs;
124703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ptrdiff_t pos;
124803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t len;
124903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int llen;
125003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct stat sb;
125103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifdef NO_PATH_MAX
125203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t ldestlen = 0;
125303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define pathlen sb.st_size
125403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define pathcnd (ldestlen < (pathlen + 1))
125503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#else
125603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define pathlen PATH_MAX
125703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define pathcnd (!ldest)
125803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
125903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* max. recursion depth */
126003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int symlinks = 32;
126103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
126203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (upath[0] == '/') {
126303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* upath is an absolute pathname */
126403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strdupx(ipath, upath, ATEMP);
126503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else {
126603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* upath is a relative pathname, prepend cwd */
126703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((tp = ksh_get_wd()) == NULL || tp[0] != '/')
126803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (NULL);
126903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		ipath = shf_smprintf("%s%s%s", tp, "/", upath);
127003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		afree(tp, ATEMP);
127103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
127203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
127303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* ipath and upath are in memory at the same time -> unchecked */
127403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Xinit(xs, xp, strlen(ip = ipath) + 1, ATEMP);
127503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
127603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* now jump into the deep of the loop */
127703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	goto beginning_of_a_pathname;
127803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
127903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (*ip) {
128003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* skip slashes in input */
128103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (*ip == '/')
128203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			++ip;
128303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!*ip)
128403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
128503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
128603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* get next pathname component from input */
128703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tp = ip;
128803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (*ip && *ip != '/')
128903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			++ip;
129003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		len = ip - tp;
129103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
129203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* check input for "." and ".." */
129303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (tp[0] == '.') {
129403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (len == 1)
129503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* just continue with the next one */
129603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				continue;
129703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else if (len == 2 && tp[1] == '.') {
129803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* strip off last pathname component */
129903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				while (xp > Xstring(xs, xp))
130003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					if (*--xp == '/')
130103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						break;
130203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* then continue with the next one */
130303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				continue;
130403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
130503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
130603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
130703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* store output position away, then append slash to output */
130803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		pos = Xsavepos(xs, xp);
130903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* 1 for the '/' and len + 1 for tp and the NUL from below */
131003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		XcheckN(xs, xp, 1 + len + 1);
131103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		Xput(xs, xp, '/');
131203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
131303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* append next pathname component to output */
131403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		memcpy(xp, tp, len);
131503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		xp += len;
131603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*xp = '\0';
131703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
131803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* lstat the current output, see if it's a symlink */
131903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (lstat(Xstring(xs, xp), &sb)) {
132003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* lstat failed */
132103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (errno == ENOENT) {
132203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* because the pathname does not exist */
132303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				while (*ip == '/')
132403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* skip any trailing slashes */
132503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					++ip;
132603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* no more components left? */
132703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (!*ip)
132803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* we can still return successfully */
132903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					break;
133003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* more components left? fall through */
133103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
133203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* not ENOENT or not at the end of ipath */
133303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto notfound;
133403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
133503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
133603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* check if we encountered a symlink? */
133703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (S_ISLNK(sb.st_mode)) {
133803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* reached maximum recursion depth? */
133903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!symlinks--) {
134003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* yep, prevent infinite loops */
134103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				errno = ELOOP;
134203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				goto notfound;
134303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
134403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
134503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* get symlink(7) target */
134603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (pathcnd) {
134703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifdef NO_PATH_MAX
134803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (notoktoadd(pathlen, 1)) {
134903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					errno = ENAMETOOLONG;
135003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					goto notfound;
135103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				}
135203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
135303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				ldest = aresize(ldest, pathlen + 1, ATEMP);
135403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
135503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			llen = readlink(Xstring(xs, xp), ldest, pathlen);
135603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (llen < 0)
135703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* oops... */
135803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				goto notfound;
135903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ldest[llen] = '\0';
136003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
136103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
136203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * restart if symlink target is an absolute path,
136303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * otherwise continue with currently resolved prefix
136403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 */
136503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* append rest of current input path to link target */
136603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tp = shf_smprintf("%s%s%s", ldest, *ip ? "/" : "", ip);
136703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			afree(ipath, ATEMP);
136803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			ip = ipath = tp;
136903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (ldest[0] != '/') {
137003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* symlink target is a relative path */
137103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				xp = Xrestpos(xs, xp, pos);
137203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			} else {
137303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* symlink target is an absolute path */
137403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				xp = Xstring(xs, xp);
137503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra beginning_of_a_pathname:
137603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* assert: (ip == ipath)[0] == '/' */
137703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* assert: xp == xs.beg => start of path */
137803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
137903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* exactly two leading slashes? (SUSv4 3.266) */
138003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (ip[1] == '/' && ip[2] != '/') {
138103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* keep them, e.g. for UNC pathnames */
138203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					Xput(xs, xp, '/');
138303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				}
138403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
138503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
138603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* otherwise (no symlink) merely go on */
138703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
138803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
138903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
139003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * either found the target and successfully resolved it,
139103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * or found its parent directory and may create it
139203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 */
139303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (Xlength(xs, xp) == 0)
139403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
139503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * if the resolved pathname is "", make it "/",
139603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * otherwise do not add a trailing slash
139703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 */
139803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		Xput(xs, xp, '/');
139903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Xput(xs, xp, '\0');
140003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
140103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
140203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * if source path had a trailing slash, check if target path
140303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * is not a non-directory existing file
140403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 */
140503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (ip > ipath && ip[-1] == '/') {
140603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (stat(Xstring(xs, xp), &sb)) {
140703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (errno != ENOENT)
140803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				goto notfound;
140903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else if (!S_ISDIR(sb.st_mode)) {
141003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errno = ENOTDIR;
141103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto notfound;
141203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
141303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* target now either does not exist or is a directory */
141403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
141503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
141603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* return target path */
141703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (ldest != NULL)
141803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		afree(ldest, ATEMP);
141903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(ipath, ATEMP);
142003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (Xclose(xs, xp));
142103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
142203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra notfound:
142303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* save; freeing memory might trash it */
142403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	llen = errno;
142503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (ldest != NULL)
142603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		afree(ldest, ATEMP);
142703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(ipath, ATEMP);
142803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Xfree(xs, xp);
142903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	errno = llen;
143003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (NULL);
143103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
143203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#undef pathlen
143303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#undef pathcnd
143403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
143503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
143603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/**
14375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	Makes a filename into result using the following algorithm.
14385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- make result NULL
14395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- if file starts with '/', append file to result & set cdpathp to NULL
14405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- if file starts with ./ or ../ append cwd and file to result
14415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  and set cdpathp to NULL
14425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- if the first element of cdpathp doesnt start with a '/' xx or '.' xx
14435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  then cwd is appended to result.
14445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- the first element of cdpathp is appended to result
14455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- file is appended to result
14465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	- cdpathp is set to the start of the next element in cdpathp (or NULL
14475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	  if there are no more elements.
14485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	The return value indicates whether a non-null element from cdpathp
14495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *	was appended to result.
14505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
145103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastatic int
14525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querumake_path(const char *cwd, const char *file,
145303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* pointer to colon-separated list */
145403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    char **cdpathp,
14555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    XString *xsp,
14565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru    int *phys_pathp)
14575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
14585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int rval = 0;
14595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool use_cdpath = true;
14605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *plist;
146103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t len, plen = 0;
14625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *xp = Xstring(*xsp, xp);
14635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!file)
14655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		file = null;
14665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (file[0] == '/') {
14685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*phys_pathp = 0;
14695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		use_cdpath = false;
14705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
14715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (file[0] == '.') {
14725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char c = file[1];
14735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (c == '.')
14755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				c = file[2];
14765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (c == '/' || c == '\0')
14775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				use_cdpath = false;
14785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
14795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		plist = *cdpathp;
14815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!plist)
14825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			use_cdpath = false;
14835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else if (use_cdpath) {
14845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char *pend;
14855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (pend = plist; *pend && *pend != ':'; pend++)
14875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				;
14885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			plen = pend - plist;
14895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*cdpathp = *pend ? pend + 1 : NULL;
14905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
14915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((!use_cdpath || !plen || plist[0] != '/') &&
14935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    (cwd && *cwd)) {
14945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			len = strlen(cwd);
14955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XcheckN(*xsp, xp, len);
14965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(xp, cwd, len);
14975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp += len;
14985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (cwd[len - 1] != '/')
14995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				Xput(*xsp, xp, '/');
15005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*phys_pathp = Xlength(*xsp, xp);
15025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (use_cdpath && plen) {
15035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			XcheckN(*xsp, xp, plen);
15045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(xp, plist, plen);
15055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			xp += plen;
15065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (plist[plen - 1] != '/')
15075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				Xput(*xsp, xp, '/');
15085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			rval = 1;
15095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	len = strlen(file) + 1;
15135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XcheckN(*xsp, xp, len);
15145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	memcpy(xp, file, len);
15155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!use_cdpath)
15175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*cdpathp = NULL;
15185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rval);
15205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
152203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*-
15235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Simplify pathnames containing "." and ".." entries.
152403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra *
152503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * simplify_path(this)			= that
152603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * /a/b/c/./../d/..			/a/b
152703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * //./C/foo/bar/../baz			//C/foo/baz
152803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * /foo/				/foo
152903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * /foo/../../bar			/bar
153003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * /foo/./blah/..			/foo
153103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * .					.
153203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * ..					..
153303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * ./foo				foo
153403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * foo/../../../bar			../../bar
15355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
15365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
153703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasimplify_path(char *p)
15385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
153903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *dp, *ip, *sp, *tp;
154003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t len;
154103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool needslash;
15425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
154303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	switch (*p) {
154403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case 0:
15455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
154603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case '/':
154703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* exactly two leading slashes? (SUSv4 3.266) */
154803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (p[1] == '/' && p[2] != '/')
154903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* keep them, e.g. for UNC pathnames */
155003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			++p;
155103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		needslash = true;
155203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		break;
155303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	default:
155403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		needslash = false;
155503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
155603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	dp = ip = sp = p;
15575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
155803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (*ip) {
155903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* skip slashes in input */
156003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (*ip == '/')
156103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			++ip;
156203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!*ip)
15635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
15645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
156503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* get next pathname component from input */
156603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		tp = ip;
156703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (*ip && *ip != '/')
156803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			++ip;
156903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		len = ip - tp;
157003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
157103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* check input for "." and ".." */
157203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (tp[0] == '.') {
157303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (len == 1)
157403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* just continue with the next one */
15755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
157603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			else if (len == 2 && tp[1] == '.') {
157703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* parent level, but how? */
157803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				if (*p == '/')
157903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* absolute path, only one way */
158003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					goto strip_last_component;
158103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				else if (dp > sp) {
158203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* relative path, with subpaths */
158303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					needslash = false;
158403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra strip_last_component:
158503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* strip off last pathname component */
158603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					while (dp > sp)
158703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						if (*--dp == '/')
158803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra							break;
158903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				} else {
159003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* relative path, at its beginning */
159103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					if (needslash)
159203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						/* or already dotdot-slash'd */
159303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra						*dp++ = '/';
159403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/* keep dotdot-slash if not absolute */
159503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					*dp++ = '.';
159603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					*dp++ = '.';
159703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					needslash = true;
159803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					sp = dp;
159903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				}
160003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				/* then continue with the next one */
16015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				continue;
16025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
16035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
16045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
160503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (needslash)
160603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			*dp++ = '/';
16075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
160803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* append next pathname component to output */
160903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		memmove(dp, tp, len);
161003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		dp += len;
161103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
161203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* append slash if we continue */
161303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		needslash = true;
161403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* try next component */
16155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
161603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (dp == p)
161703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* empty path -> dot */
161803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		*dp++ = needslash ? '/' : '.';
161903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	*dp = '\0';
16205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
162303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraset_current_wd(const char *nwd)
16245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
162503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *allocd = NULL;
16265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
162703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (nwd == NULL) {
162803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		allocd = ksh_get_wd();
162903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		nwd = allocd ? allocd : null;
163003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
163103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
163203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(current_wd, APERM);
163303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	strdupx(current_wd, nwd, APERM);
163403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
163503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(allocd, ATEMP);
163603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
163703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
163803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraint
163903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrac_cd(const char **wp)
164003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
164103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int optc, rv, phys_path;
164203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool physical = tobool(Flag(FPHYSICAL));
164303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* was a node from cdpath added in? */
164403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	int cdnode;
164503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* show where we went?, error for $PWD */
164603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool printpath = false, eflag = false;
164703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	struct tbl *pwd_s, *oldpwd_s;
164803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	XString xs;
164903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;
165003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
165103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while ((optc = ksh_getopt(wp, &builtin_opt, "eLP")) != -1)
165203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		switch (optc) {
165303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 'e':
165403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			eflag = true;
165503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
165603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 'L':
165703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			physical = false;
165803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
165903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case 'P':
166003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			physical = true;
166103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			break;
166203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		case '?':
166303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (2);
166403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
166503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	wp += builtin_opt.optind;
166603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
166703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (Flag(FRESTRICTED)) {
166803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		bi_errorf("restricted shell - can't cd");
166903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (2);
167003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
167103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
167203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	pwd_s = global("PWD");
167303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	oldpwd_s = global("OLDPWD");
167403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
167503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (!wp[0]) {
167603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* No arguments - go home */
167703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((dir = str_val(global("HOME"))) == null) {
167803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("no home directory (HOME not set)");
167903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (2);
168003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
168103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else if (!wp[1]) {
168203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* One argument: - or dir */
168303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strdupx(allocd, wp[0], ATEMP);
168403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (ksh_isdash((dir = allocd))) {
168503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			afree(allocd, ATEMP);
168603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			allocd = NULL;
168703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			dir = str_val(oldpwd_s);
168803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (dir == null) {
168903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				bi_errorf("no OLDPWD");
169003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				return (2);
169103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			}
169203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			printpath = true;
169303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
169403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else if (!wp[2]) {
169503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Two arguments - substitute arg1 in PWD for arg2 */
169603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		size_t ilen, olen, nlen, elen;
169703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		char *cp;
169803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
169903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!current_wd[0]) {
170003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("can't determine current directory");
170103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (2);
170203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
170303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
170403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * substitute arg1 for arg2 in current path.
170503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * if the first substitution fails because the cd fails
170603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * we could try to find another substitution. For now
170703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * we don't
170803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 */
170903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((cp = strstr(current_wd, wp[0])) == NULL) {
171003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("bad substitution");
171103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			return (2);
171203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
171303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*-
171403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * ilen = part of current_wd before wp[0]
171503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * elen = part of current_wd after wp[0]
171603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * because current_wd and wp[1] need to be in memory at the
171703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * same time beforehand the addition can stay unchecked
171803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 */
171903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		ilen = cp - current_wd;
172003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		olen = strlen(wp[0]);
172103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		nlen = strlen(wp[1]);
172203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		elen = strlen(current_wd + ilen + olen) + 1;
172303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		dir = allocd = alloc(ilen + nlen + elen, ATEMP);
172403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		memcpy(dir, current_wd, ilen);
172503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		memcpy(dir + ilen, wp[1], nlen);
172603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
172703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		printpath = true;
172803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else {
172903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		bi_errorf("too many arguments");
173003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (2);
173103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
173203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
173303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#ifdef NO_PATH_MAX
173403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* only a first guess; make_path will enlarge xs if necessary */
173503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	XinitN(xs, 1024, ATEMP);
173603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#else
173703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	XinitN(xs, PATH_MAX, ATEMP);
173803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
173903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
174003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	cdpath = str_val(global("CDPATH"));
174103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	do {
174203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
174303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (physical)
174403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			rv = chdir(tryp = Xstring(xs, xp) + phys_path);
174503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		else {
174603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			simplify_path(Xstring(xs, xp));
174703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			rv = chdir(tryp = Xstring(xs, xp));
174803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
174903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} while (rv < 0 && cdpath != NULL);
175003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
175103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (rv < 0) {
175203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (cdnode)
175303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("%s: %s", dir, "bad directory");
175403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		else
175503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			bi_errorf("%s: %s", tryp, strerror(errno));
175603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		afree(allocd, ATEMP);
175703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		Xfree(xs, xp);
175803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return (2);
175903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
176003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
176103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	rv = 0;
176203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
176303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* allocd (above) => dir, which is no longer used */
176403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(allocd, ATEMP);
176503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	allocd = NULL;
176603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
176703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* Clear out tracked aliases with relative paths */
176803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	flushcom(false);
176903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
177003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
177103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * Set OLDPWD (note: unsetting OLDPWD does not disable this
177203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * setting in AT&T ksh)
177303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 */
177403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (current_wd[0])
177503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Ignore failure (happens if readonly or integer) */
177603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);
177703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
177803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (Xstring(xs, xp)[0] != '/') {
177903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		pwd = NULL;
178003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else if (!physical) {
178103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		goto norealpath_PWD;
178203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else if ((pwd = allocd = do_realpath(Xstring(xs, xp))) == NULL) {
178303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (eflag)
178403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			rv = 1;
178503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra norealpath_PWD:
178603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		pwd = Xstring(xs, xp);
178703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
178803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
178903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* Set PWD */
179003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (pwd) {
179103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		char *ptmp = pwd;
17925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
179303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		set_current_wd(ptmp);
179403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* Ignore failure (happens if readonly or integer) */
179503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
179603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else {
179703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		set_current_wd(null);
179803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		pwd = Xstring(xs, xp);
179903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* XXX unset $PWD? */
180003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (eflag)
180103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			rv = 1;
18025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
180303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (printpath || cdnode)
180403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		shprintf("%s\n", pwd);
180503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
180603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	afree(allocd, ATEMP);
180703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	Xfree(xs, xp);
180803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (rv);
18095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
18105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
181103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
18125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef TIOCSCTTY
18135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruextern void chvt_reinit(void);
18145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
18165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchvt(const char *fn)
18175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
18185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char dv[20];
18195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct stat sb;
18205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int fd;
18215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (*fn == '-') {
18235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(dv, "-/dev/null", sizeof("-/dev/null"));
18245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		fn = dv + 1;
18255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
18265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (stat(fn, &sb)) {
18275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			memcpy(dv, "/dev/ttyC", 9);
18285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			strlcpy(dv + 9, fn, sizeof(dv) - 9);
18295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (stat(dv, &sb)) {
18305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				strlcpy(dv + 8, fn, sizeof(dv) - 8);
18315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (stat(dv, &sb))
183203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					errorf("%s: %s %s", "chvt",
183303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					    "can't find tty", fn);
18345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
18355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			fn = dv;
18365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
18375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!(sb.st_mode & S_IFCHR))
183803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errorf("%s %s %s", "chvt: not a char", "device", fn);
18395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((sb.st_uid != 0) && chown(fn, 0, 0))
184003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(false, "%s: %s %s", "chvt", "can't chown root", fn);
18415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (((sb.st_mode & 07777) != 0600) && chmod(fn, (mode_t)0600))
184203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(false, "%s: %s %s", "chvt", "can't chmod 0600", fn);
18435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if HAVE_REVOKE
18445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (revoke(fn))
18455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
184603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			warningf(false, "%s: %s %s", "chvt",
184703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "new shell is potentially insecure, can't revoke",
184803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    fn);
18495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
18505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((fd = open(fn, O_RDWR)) == -1) {
18515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sleep(1);
18525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((fd = open(fn, O_RDWR)) == -1)
185303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errorf("%s: %s %s", "chvt", "can't open", fn);
18545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
18555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (fork()) {
18565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case -1:
185703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errorf("%s: %s %s", "chvt", "fork", "failed");
18585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 0:
18595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
18605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
18615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		exit(0);
18625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
18635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (setsid() == -1)
186403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errorf("%s: %s %s", "chvt", "setsid", "failed");
18655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (fn != dv + 1) {
18665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ioctl(fd, TIOCSCTTY, NULL) == -1)
186703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errorf("%s: %s %s", "chvt", "TIOCSCTTY", "failed");
18685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tcflush(fd, TCIOFLUSH))
186903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errorf("%s: %s %s", "chvt", "TCIOFLUSH", "failed");
18705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
18715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ksh_dup2(fd, 0, false);
18725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ksh_dup2(fd, 1, false);
18735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	ksh_dup2(fd, 2, false);
18745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (fd > 2)
18755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		close(fd);
187603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	{
187703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		register uint32_t h;
187803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
187903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		NZATInit(h);
188003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		NZATUpdateMem(h, &rndsetupstate, sizeof(rndsetupstate));
188103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		NZAATFinish(h);
188203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		rndset((long)h);
188303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
18845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	chvt_reinit();
18855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
18865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
18875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
18885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef DEBUG
188903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define assert_eq(name, a, b) char name[a == b ? 1 : -1]
189003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#define assert_ge(name, a, b) char name[a >= b ? 1 : -1]
189103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_ge(intsize_is_okay, sizeof(int), 4);
189203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_eq(intsizes_are_okay, sizeof(int), sizeof(unsigned int));
189303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_ge(longsize_is_okay, sizeof(long), sizeof(int));
189403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_eq(arisize_is_okay, sizeof(mksh_ari_t), 4);
189503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_eq(uarisize_is_okay, sizeof(mksh_uari_t), 4);
189603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_eq(sizesizes_are_okay, sizeof(size_t), sizeof(ssize_t));
189703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_eq(ptrsizes_are_okay, sizeof(ptrdiff_t), sizeof(void *));
189803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_eq(ptrsize_is_sizet, sizeof(ptrdiff_t), sizeof(size_t));
189903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* formatting routines assume this */
190003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condraassert_ge(ptr_fits_in_long, sizeof(long), sizeof(size_t));
19015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
19035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustrchr(char *p, int ch)
19045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
19055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	for (;; ++p) {
19065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*p == ch)
19075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (p);
19085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!*p)
19095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
19105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
19115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* NOTREACHED */
19125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
19135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
19155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustrstr(char *b, const char *l)
19165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
19175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char first, c;
19185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t n;
19195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((first = *l++) == '\0')
19215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (b);
19225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	n = strlen(l);
19235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru strstr_look:
19245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((c = *b++) != first)
19255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == '\0')
19265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
19275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (strncmp(b, l, n))
19285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto strstr_look;
19295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (b - 1);
19305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
19315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
19325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !HAVE_STRCASESTR
19345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruconst char *
19355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustristr(const char *b, const char *l)
19365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
19375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char first, c;
19385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t n;
19395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((first = *l++), ((first = ksh_tolower(first)) == '\0'))
19415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (b);
19425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	n = strlen(l);
19435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru stristr_look:
19445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((c = *b++), ((c = ksh_tolower(c)) != first))
19455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == '\0')
19465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
19475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (strncasecmp(b, l, n))
19485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		goto stristr_look;
19495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (b - 1);
19505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
19515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
19525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef MKSH_SMALL
19545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
19555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustrndup_(const char *src, size_t len, Area *ap)
19565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
19575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *dst = NULL;
19585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (src != NULL) {
19605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		dst = alloc(len + 1, ap);
19615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(dst, src, len);
19625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		dst[len] = '\0';
19635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
19645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (dst);
19655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
19665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
19685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustrdup_(const char *src, Area *ap)
19695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
19705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (src == NULL ? NULL : strndup_(src, strlen(src), ap));
19715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
19725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
19735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if !HAVE_GETRUSAGE
19755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define INVTCK(r,t)	do {						\
19765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	r.tv_usec = ((t) % (1000000 / CLK_TCK)) * (1000000 / CLK_TCK);	\
19775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	r.tv_sec = (t) / CLK_TCK;					\
19785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru} while (/* CONSTCOND */ 0)
19795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
19815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querugetrusage(int what, struct rusage *ru)
19825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
19835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tms tms;
19845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	clock_t u, s;
19855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (/* ru == NULL || */ times(&tms) == (clock_t)-1)
19875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
19885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
19895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (what) {
19905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case RUSAGE_SELF:
19915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		u = tms.tms_utime;
19925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = tms.tms_stime;
19935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
19945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case RUSAGE_CHILDREN:
19955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		u = tms.tms_cutime;
19965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = tms.tms_cstime;
19975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
19985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
19995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		errno = EINVAL;
20005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
20015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
20025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	INVTCK(ru->ru_utime, u);
20035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	INVTCK(ru->ru_stime, s);
20045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (0);
20055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
20065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
20075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
20085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
20095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * process the string available via fg (get a char)
20105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * and fp (put back a char) for backslash escapes,
20115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * assuming the first call to *fg gets the char di-
20125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * rectly after the backslash; return the character
20135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * (0..0xFF), Unicode (wc + 0x100), or -1 if no known
20145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * escape sequence was found
20155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
20165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
20175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruunbksl(bool cstyle, int (*fg)(void), void (*fp)(int))
20185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
20195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int wc, i, c, fc;
20205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
20215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	fc = (*fg)();
20225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (fc) {
20235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'a':
20245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
20255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * according to the comments in pdksh, \007 seems
20265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * to be more portable than \a (due to HP-UX cc,
20275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * Ultrix cc, old pcc, etc.) so we avoid the escape
20285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * sequence altogether in mksh and assume ASCII
20295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
20305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = 7;
20315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'b':
20335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\b';
20345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'c':
20365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!cstyle)
20375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto unknown_escape;
20385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		c = (*fg)();
20395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = CTRL(c);
20405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'E':
20425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'e':
20435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = 033;
20445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'f':
20465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\f';
20475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'n':
20495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\n';
20505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'r':
20525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\r';
20535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 't':
20555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\t';
20565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'v':
20585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* assume ASCII here as well */
20595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = 11;
20605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '1':
20625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '2':
20635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '3':
20645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '4':
20655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '5':
20665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '6':
20675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '7':
20685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!cstyle)
20695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto unknown_escape;
20705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* FALLTHROUGH */
20715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '0':
20725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (cstyle)
20735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			(*fp)(fc);
20745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
20755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * look for an octal number with up to three
20765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * digits, not counting the leading zero;
20775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * convert it to a raw octet
20785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
20795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = 0;
20805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = 3;
20815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (i--)
20825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((c = (*fg)()) >= '0' && c <= '7')
20835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				wc = (wc << 3) + (c - '0');
20845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
20855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				(*fp)(c);
20865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
20875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
20885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
20895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'U':
20905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = 8;
209103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (/* CONSTCOND */ 0)
20925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* FALLTHROUGH */
20935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'u':
20945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = 4;
209503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (/* CONSTCOND */ 0)
20965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* FALLTHROUGH */
20975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case 'x':
20985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i = cstyle ? -1 : 2;
209903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/**
21005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * x:	look for a hexadecimal number with up to
21015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	two (C style: arbitrary) digits; convert
21025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	to raw octet (C style: Unicode if >0xFF)
21035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * u/U:	look for a hexadecimal number with up to
21045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 *	four (U: eight) digits; convert to Unicode
21055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
21065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = 0;
21075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (i--) {
21085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			wc <<= 4;
21095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((c = (*fg)()) >= '0' && c <= '9')
21105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				wc += c - '0';
21115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else if (c >= 'A' && c <= 'F')
21125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				wc += c - 'A' + 10;
21135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else if (c >= 'a' && c <= 'f')
21145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				wc += c - 'a' + 10;
21155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else {
21165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				wc >>= 4;
21175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				(*fp)(c);
21185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				break;
21195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
21205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
21215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((cstyle && wc > 0xFF) || fc != 'x')
21225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* Unicode marker */
21235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			wc += 0x100;
21245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
21255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '\'':
21265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!cstyle)
21275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto unknown_escape;
21285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\'';
21295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
21305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case '\\':
21315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		wc = '\\';
21325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
21335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
21345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru unknown_escape:
21355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		(*fp)(fc);
21365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
21375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
21385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
21395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (wc);
21405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2141