1fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes/*	$OpenBSD: var.c,v 1.44 2015/09/10 11:37:42 jca Exp $	*/
25155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
35155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*-
4c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes *		 2011, 2012, 2013, 2014, 2015, 2016
6fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes *	mirabilos <m@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"
25737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#include "mirhash.h"
265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#if defined(__OpenBSD__)
285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include <sys/sysctl.h>
295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
31fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes__RCSID("$MirOS: src/bin/mksh/var.c,v 1.197 2016/01/14 22:49:33 tg Exp $");
325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*-
345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Variables
355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * WARNING: unreadable code, needs a rewrite
375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru *
385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * if (flag&INTEGER), val.i contains integer value, and type contains base.
395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * otherwise, (val.s + type) contains string value.
405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
4203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic struct table specials;
44737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesstatic uint32_t lcg_state = 5381, qh_state = 4711;
45737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes/* may only be set by typeset() just before call to array_index_calc() */
46737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesstatic enum namerefflag innermost_refflag = SRF_NOP;
4703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *formatstr(struct tbl *, const char *);
495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void exportprep(struct tbl *, const char *);
505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int special(const char *);
515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void unspecial(const char *);
525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void getspec(struct tbl *);
535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void setspec(struct tbl *);
545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void unsetspec(struct tbl *);
55811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserstatic int getint(struct tbl *, mksh_ari_u *, bool);
565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *array_index_calc(const char *, bool *, uint32_t *);
575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * create a new block for function calls and simple commands
605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * assume caller has allocated and set up e->loc
615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querunewblock(void)
645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l;
665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	static const char *empty[] = { null };
675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l = alloc(sizeof(struct block), ATEMP);
695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l->flags = 0;
7003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* TODO: could use e->area (l->area => l->areap) */
7103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ainit(&l->area);
725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!e->loc) {
735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		l->argc = 0;
745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		l->argv = empty;
755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else {
765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		l->argc = e->loc->argc;
775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		l->argv = e->loc->argv;
785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l->exit = l->error = NULL;
8003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ktinit(&l->area, &l->vars, 0);
8103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ktinit(&l->area, &l->funs, 0);
825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	l->next = e->loc;
835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	e->loc = l;
845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * pop a block handling special variables
885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querupopblock(void)
915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
9203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t i;
935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l = e->loc;
945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp, **vpp = l->vars.tbls, *vq;
955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* pop block */
9703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	e->loc = l->next;
9803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
9903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	i = 1 << (l->vars.tshift);
10003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	while (--i >= 0)
1015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL)) {
1025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((vq = global(vp->name))->flag & ISSET)
1035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setspec(vq);
1045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
1055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unsetspec(vq);
1065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (l->flags & BF_DOGETOPTS)
1085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		user_opt = l->getopts_state;
1095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afreeall(&l->area);
1105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afree(l, ATEMP);
1115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* called by main() to initialise variable data structures */
1145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define VARSPEC_DEFNS
1155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "var_spec.h"
1165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruenum var_specs {
1185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define VARSPEC_ENUMS
1195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "var_spec.h"
1205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	V_MAX
1215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
1225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* this is biased with -1 relative to VARSPEC_ENUMS */
1245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char * const initvar_names[] = {
1255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#define VARSPEC_ITEMS
1265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#include "var_spec.h"
1275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru};
1285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
1305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruinitvar(void)
1315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int i = 0;
1335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
1345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ktinit(APERM, &specials,
136c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    /* currently 14 specials: 75% of 32 = 2^5 */
137c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	    5);
1385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (i < V_MAX - 1) {
1395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp = ktenter(&specials, initvar_names[i],
1405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    hash(initvar_names[i]));
1415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->flag = DEFINED|ISSET;
1425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		tp->type = ++i;
1435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
1445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
146c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser/* common code for several functions below and c_typeset() */
147c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserstruct block *
14803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condravarsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h)
14903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
15003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	register struct tbl *vp;
15103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
15203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (l) {
15303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra varsearch_loop:
15403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((vp = ktsearch(&l->vars, vn, h)) != NULL)
15503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto varsearch_out;
15603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (l->next != NULL) {
15703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			l = l->next;
15803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			goto varsearch_loop;
15903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
16003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
16103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	vp = NULL;
16203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra varsearch_out:
16303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	*vpp = vp;
16403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (l);
16503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
16603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
16703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
16803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Used to calculate an array index for global()/local(). Sets *arrayp
16903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * to true if this is an array, sets *valp to the array index, returns
170737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes * the basename of the array. May only be called from global()/local()
171737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes * and must be their first callee.
1725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
1735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic const char *
1745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruarray_index_calc(const char *n, bool *arrayp, uint32_t *valp)
1755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p;
17703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t len;
1785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *ap = NULL;
1795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*arrayp = false;
1815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru redo_from_ref:
1825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	p = skip_varname(n, false);
183737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	if (innermost_refflag == SRF_NOP && (p != n) && ksh_isalphx(n[0])) {
1845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct tbl *vp;
1855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *vn;
1865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strndupx(vn, n, p - n, ATEMP);
1885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* check if this is a reference */
18903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		varsearch(e->loc, &vp, vn, hash(vn));
1905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(vn, ATEMP);
191737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		if (vp && (vp->flag & (DEFINED | ASSOC | ARRAY)) ==
192737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		    (DEFINED | ASSOC)) {
1935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char *cp;
1945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* gotcha! */
1965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			cp = shf_smprintf("%s%s", str_val(vp), p);
1975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			afree(ap, ATEMP);
1985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			n = ap = cp;
1995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			goto redo_from_ref;
2005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
202737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	innermost_refflag = SRF_NOP;
2035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
2045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (p != n && *p == '[' && (len = array_ref_len(p))) {
2055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char *sub, *tmp;
2065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		mksh_ari_t rval;
2075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
20803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* calculate the value of the subscript */
2095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*arrayp = true;
2105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strndupx(tmp, p + 1, len - 2, ATEMP);
2115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		sub = substitute(tmp, 0);
2125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(tmp, ATEMP);
2135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strndupx(n, n, p - n, ATEMP);
2145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		evaluate(sub, &rval, KSH_UNWIND_ERROR, true);
2155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*valp = (uint32_t)rval;
2165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(sub, ATEMP);
2175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
2185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (n);
2195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
2205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
221fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes#define vn vname.ro
2225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
2235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Search for variable, if not found create globally.
2245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
2255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
2265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruglobal(const char *n)
2275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
2285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp;
229fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	union mksh_cchack vname;
230fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	struct block *l = e->loc;
2315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int c;
2325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool array;
2335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uint32_t h, val;
2345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
235737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/*
236737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	 * check to see if this is an array;
237737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	 * dereference namerefs; must come first
238737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	 */
239fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	vn = array_index_calc(n, &array, &val);
240fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	h = hash(vn);
241fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	c = (unsigned char)vn[0];
2425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!ksh_isalphx(c)) {
2435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (array)
2445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errorf("bad substitution");
2455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp = &vtemp;
2465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag = DEFINED;
2475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->type = 0;
2485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->areap = ATEMP;
2495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		*vp->name = c;
2505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ksh_isdigit(c)) {
251fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			if (getn(vn, &c) && (c <= l->argc))
2525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* setstr can't fail here */
2535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				setstr(vp, l->argv[c], KSH_RETURN_ERROR);
2545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->flag |= RDONLY;
255fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			goto out;
2565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
2575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag |= RDONLY;
258fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		if (vn[1] != '\0')
259fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			goto out;
2605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag |= ISSET|INTEGER;
2615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		switch (c) {
2625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '$':
2635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->val.i = kshpid;
2645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
2655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '!':
26603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* if no job, expand to nothing */
2675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((vp->val.i = j_async()) == 0)
2685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				vp->flag &= ~(ISSET|INTEGER);
2695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
2705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '?':
271c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			vp->val.i = exstat & 0xFF;
2725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
2735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '#':
2745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->val.i = l->argc;
2755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
2765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		case '-':
2775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->flag &= ~INTEGER;
2785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->val.s = getoptions();
2795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			break;
2805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		default:
2815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->flag &= ~(ISSET|INTEGER);
2825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
283fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		goto out;
2845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
285fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	l = varsearch(e->loc, &vp, vn, h);
286fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (vp != NULL) {
287fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		if (array)
288fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes			vp = arraysearch(vp, val);
289fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		goto out;
290fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	}
291fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	vp = ktenter(&l->vars, vn, h);
2925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (array)
2935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp = arraysearch(vp, val);
2945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vp->flag |= DEFINED;
295fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (special(vn))
2965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag |= SPECIAL;
297fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes out:
298fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	last_lookup_was_array = array;
299fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (vn != n)
300fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		afree(vname.rw, ATEMP);
3015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (vp);
3025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
3035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
3055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Search for local variable, if not found create locally.
3065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
3075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
3085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querulocal(const char *n, bool copy)
3095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
3105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp;
311fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	union mksh_cchack vname;
312fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	struct block *l = e->loc;
3135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	bool array;
3145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	uint32_t h, val;
3155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
316737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/*
317737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	 * check to see if this is an array;
318737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	 * dereference namerefs; must come first
319737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	 */
320fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	vn = array_index_calc(n, &array, &val);
321fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	h = hash(vn);
322fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (!ksh_isalphx(*vn)) {
3235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp = &vtemp;
3245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag = DEFINED|RDONLY;
3255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->type = 0;
3265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->areap = ATEMP;
327fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		goto out;
3285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
329fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	vp = ktenter(&l->vars, vn, h);
3305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (copy && !(vp->flag & DEFINED)) {
33103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		struct tbl *vq;
3325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
333fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		varsearch(l->next, &vq, vn, h);
33403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (vq != NULL) {
3355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->flag |= vq->flag &
3365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (EXPORT | INTEGER | RDONLY | LJUST | RJUST |
3375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    ZEROFIL | LCASEV | UCASEV_AL | INT_U | INT_L);
3385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (vq->flag & INTEGER)
3395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				vp->type = vq->type;
3405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->u2.field = vq->u2.field;
3415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
3425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
3435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (array)
3445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp = arraysearch(vp, val);
3455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vp->flag |= DEFINED;
346fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (special(vn))
3475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag |= SPECIAL;
348fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes out:
349fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	last_lookup_was_array = array;
350fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (vn != n)
351fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		afree(vname.rw, ATEMP);
3525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (vp);
3535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
354fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes#undef vn
3555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* get variable string value */
3575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
3585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustr_val(struct tbl *vp)
3595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
3605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *s;
3615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vp->flag&SPECIAL))
3635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		getspec(vp);
3645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(vp->flag&ISSET))
36503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* special to dollar() */
36603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		s = null;
36703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	else if (!(vp->flag&INTEGER))
36803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* string source */
3695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = vp->val.s + vp->type;
37003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	else {
37103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* integer source */
37203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		mksh_uari_t n;
373811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		unsigned int base;
37403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/**
37503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * worst case number length is when base == 2:
37603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 *	1 (minus) + 2 (base, up to 36) + 1 ('#') +
37703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 *	number of bits in the mksh_uari_t + 1 (NUL)
37803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 */
3795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		char strbuf[1 + 2 + 1 + 8 * sizeof(mksh_uari_t) + 1];
3805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		const char *digits = (vp->flag & UCASEV_AL) ?
3815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		    digits_uc : digits_lc;
3825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = strbuf + sizeof(strbuf);
3845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (vp->flag & INT_U)
3855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			n = vp->val.u;
3865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
387811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			n = (vp->val.i < 0) ? -vp->val.u : vp->val.u;
388811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		base = (vp->type == 0) ? 10U : (unsigned int)vp->type;
3895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
39003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (base == 1 && n == 0)
39103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			base = 2;
3925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (base == 1) {
3935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			size_t sz = 1;
3945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
3955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*(s = strbuf) = '1';
3965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s[1] = '#';
3975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!UTFMODE || ((n & 0xFF80) == 0xEF80))
3985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* OPTU-16 -> raw octet */
3995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				s[2] = n & 0xFF;
4005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			else
4015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				sz = utf_wctomb(s + 2, n);
4025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s[2 + sz] = '\0';
4035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
4045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*--s = '\0';
4055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			do {
4065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*--s = digits[n % base];
4075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				n /= base;
4085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} while (n != 0);
4095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (base != 10) {
4105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*--s = '#';
4115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*--s = digits[base % 10];
4125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (base >= 10)
4135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					*--s = digits[base / 10];
4145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
4155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(vp->flag & INT_U) && vp->val.i < 0)
4165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				*--s = '-';
4175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
41803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (vp->flag & (RJUST|LJUST))
41903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* case already dealt with */
4205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = formatstr(vp, s);
4215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else
4225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			strdupx(s, s, ATEMP);
4235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (s);
4255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* set variable to string value */
4285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
4295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetstr(struct tbl *vq, const char *s, int error_ok)
4305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *salloc = NULL;
432c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	bool no_ro_check = tobool(error_ok & 0x4);
4335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	error_ok &= ~0x4;
4355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vq->flag & RDONLY) && !no_ro_check) {
436c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		warningf(true, "read-only: %s", vq->name);
4375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!error_ok)
43803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errorfxz(2);
4395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
4405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
44103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (!(vq->flag&INTEGER)) {
44203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* string dest */
4435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((vq->flag&ALLOC)) {
444c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#ifndef MKSH_SMALL
4455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* debugging */
4465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (s >= vq->val.s &&
447c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			    s <= vq->val.s + strlen(vq->val.s)) {
4485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				internal_errorf(
4495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    "setstr: %s=%s: assigning to self",
4505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    vq->name, s);
451c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			}
452c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
4535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			afree(vq->val.s, vq->areap);
4545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
4555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vq->flag &= ~(ISSET|ALLOC);
4565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vq->type = 0;
4575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (s && (vq->flag & (UCASEV_AL|LCASEV|LJUST|RJUST)))
4585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = salloc = formatstr(vq, s);
4595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if ((vq->flag&EXPORT))
4605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			exportprep(vq, s);
4615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		else {
4625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			strdupx(vq->val.s, s, vq->areap);
4635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vq->flag |= ALLOC;
4645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
46503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else {
46603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* integer dest */
4675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!v_evaluate(vq, s, error_ok, true))
4685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (0);
4695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
4705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vq->flag |= ISSET;
4715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vq->flag&SPECIAL))
4725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setspec(vq);
4735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afree(salloc, ATEMP);
4745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (1);
4755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* set variable to integer */
4785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
4795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetint(struct tbl *vq, mksh_ari_t n)
4805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
4815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(vq->flag&INTEGER)) {
4825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct tbl *vp = &vtemp;
4835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag = (ISSET|INTEGER);
4845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->type = 0;
4855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->areap = ATEMP;
4865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->val.i = n;
4875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* setstr can't fail here */
4885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setstr(vq, str_val(vp), KSH_RETURN_ERROR);
4895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
4905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vq->val.i = n;
4915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vq->flag |= ISSET;
4925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vq->flag&SPECIAL))
4935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setspec(vq);
4945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
4955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
4965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
497811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glasergetint(struct tbl *vp, mksh_ari_u *nump, bool arith)
4985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
499b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	mksh_uari_t c, num = 0, base = 10;
500c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	const char *s;
501811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	bool have_base = false, neg = false;
5025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
503b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	if (vp->flag & SPECIAL)
5045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		getspec(vp);
505811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	/* XXX is it possible for ISSET to be set and val.s to be NULL? */
506b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL))
5075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (-1);
508b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	if (vp->flag & INTEGER) {
509811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		nump->i = vp->val.i;
5105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (vp->type);
5115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
5125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	s = vp->val.s + vp->type;
513b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes
514b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	do {
515b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		c = (unsigned char)*s++;
516b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	} while (ksh_isspace(c));
517b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes
518b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	switch (c) {
519b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	case '-':
520b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		neg = true;
521b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		/* FALLTHROUGH */
522b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	case '+':
523b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		c = (unsigned char)*s++;
524b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		break;
5255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
526b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes
527b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	if (c == '0' && arith) {
52896b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		if (ksh_eq(s[0], 'X', 'x')) {
529b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			/* interpret as hexadecimal */
530b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			base = 16;
531b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			++s;
532b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			goto getint_c_style_base;
533b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		} else if (Flag(FPOSIX) && ksh_isdigit(s[0]) &&
534b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		    !(vp->flag & ZEROFIL)) {
535b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			/* interpret as octal (deprecated) */
536b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			base = 8;
537b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes getint_c_style_base:
538b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			have_base = true;
539b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			c = (unsigned char)*s++;
540b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		}
541c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
542b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes
543b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	do {
544b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		if (c == '#') {
545b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			/* ksh-style base determination */
546b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			if (have_base || num < 1)
5475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (-1);
548811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if ((base = num) == 1) {
549b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes				/* mksh-specific extension */
5505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				unsigned int wc;
5515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
5525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (!UTFMODE)
553c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					wc = *(const unsigned char *)s;
5545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else if (utf_mbtowc(&wc, s) == (size_t)-1)
5555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* OPTU-8 -> OPTU-16 */
5565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/*
5575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * (with a twist: 1#\uEF80 converts
5585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * the same as 1#\x80 does, thus is
5595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 * not round-tripping correctly XXX)
5605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
561c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					wc = 0xEF00 + *(const unsigned char *)s;
562811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				nump->u = (mksh_uari_t)wc;
5635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				return (1);
564b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes			} else if (base > 36)
56596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes				base = 10;
5665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			num = 0;
5675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			have_base = true;
5685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			continue;
569b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		}
570b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		if (ksh_isdigit(c))
57196b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			c = ksh_numdig(c);
57296b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		else if (ksh_isupper(c))
57396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			c = ksh_numuc(c) + 10;
57496b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		else if (ksh_islower(c))
57596b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			c = ksh_numlc(c) + 10;
57696b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes		else
57796b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			return (-1);
578811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (c >= base)
5795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (-1);
580b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		/* handle overflow as truncation */
5815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		num = num * base + c;
582b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	} while ((c = (unsigned char)*s++));
583b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes
584811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (neg)
585811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num = -num;
586811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	nump->u = num;
5875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (base);
5885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
5895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
59003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
59103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * convert variable vq to integer variable, setting its value from vp
5925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * (vq and vp may be the same)
5935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
5945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
5955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetint_v(struct tbl *vq, struct tbl *vp, bool arith)
5965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
5975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int base;
598811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	mksh_ari_u num;
5995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((base = getint(vp, &num, arith)) == -1)
6015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (NULL);
602811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	setint_n(vq, num.i, 0);
60303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (vq->type == 0)
60403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* default base */
60503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vq->type = base;
60603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (vq);
60703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
60803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
60903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/* convert variable vq to integer variable, setting its value to num */
61003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condravoid
611c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasersetint_n(struct tbl *vq, mksh_ari_t num, int newbase)
61203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
6135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!(vq->flag & INTEGER) && (vq->flag & ALLOC)) {
6145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vq->flag &= ~ALLOC;
61503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vq->type = 0;
6165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(vq->val.s, vq->areap);
6175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
6185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vq->val.i = num;
619c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (newbase != 0)
620c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		vq->type = newbase;
6215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vq->flag |= ISSET|INTEGER;
6225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vq->flag&SPECIAL)
6235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setspec(vq);
6245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
6255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic char *
6275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruformatstr(struct tbl *vp, const char *s)
6285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
6295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int olen, nlen;
6305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *p, *q;
6315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t psiz;
6325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
63303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	olen = (int)utf_mbswidth(s);
6345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vp->flag & (RJUST|LJUST)) {
63603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (!vp->u2.field)
63703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* default field width */
6385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->u2.field = olen;
6395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nlen = vp->u2.field;
6405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
6415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		nlen = olen;
6425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	p = alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP);
6445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vp->flag & (RJUST|LJUST)) {
6455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		int slen = olen, i = 0;
6465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (vp->flag & RJUST) {
6485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			const char *qq = s;
6495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			int n = 0;
6505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (i < slen)
6525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				i += utf_widthadj(qq, &qq);
6535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* strip trailing spaces (AT&T uses qq[-1] == ' ') */
6545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (qq > s && ksh_isspace(qq[-1])) {
6555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				--qq;
6565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				--slen;
6575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (vp->flag & ZEROFIL && vp->flag & INTEGER) {
659c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser				if (!s[0] || !s[1])
660c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser					goto uhm_no;
6615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (s[1] == '#')
6625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					n = 2;
6635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else if (s[2] == '#')
6645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					n = 3;
665c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser uhm_no:
6665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (vp->u2.field <= n)
6675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					n = 0;
6685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (n) {
6705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				memcpy(p, s, n);
6715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				s += n;
6725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
6735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (slen > vp->u2.field)
6745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				slen -= utf_widthadj(s, &s);
6755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (vp->u2.field - slen)
6765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				memset(p + n, (vp->flag & ZEROFIL) ? '0' : ' ',
6775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    vp->u2.field - slen);
6785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			slen -= n;
6795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_snprintf(p + vp->u2.field - slen,
6805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    psiz - (vp->u2.field - slen),
6815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    "%.*s", slen, s);
6825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else {
6835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* strip leading spaces/zeros */
6845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (ksh_isspace(*s))
6855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				s++;
6865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (vp->flag & ZEROFIL)
6875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				while (*s == '0')
6885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					s++;
6895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			shf_snprintf(p, nlen + 1, "%-*.*s",
6905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				vp->u2.field, vp->u2.field, s);
6915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
6925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
6935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(p, s, strlen(s) + 1);
6945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
6955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vp->flag & UCASEV_AL) {
6965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (q = p; *q; q++)
6975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*q = ksh_toupper(*q);
6985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else if (vp->flag & LCASEV) {
6995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (q = p; *q; q++)
7005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			*q = ksh_tolower(*q);
7015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
7025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (p);
7045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
7075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * make vp->val.s be "name=value" for quick exporting.
7085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
7095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
7105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruexportprep(struct tbl *vp, const char *val)
7115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *xp;
7135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
71403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t namelen, vallen;
71503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
71603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	namelen = strlen(vp->name);
71703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	vallen = strlen(val) + 1;
7185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vp->flag |= ALLOC;
72003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* since name+val are both in memory this can go unchecked */
7215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	xp = alloc(namelen + 1 + vallen, vp->areap);
7225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	memcpy(vp->val.s = xp, vp->name, namelen);
7235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	xp += namelen;
7245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	*xp++ = '=';
72503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* offset to value */
72603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	vp->type = xp - vp->val.s;
7275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	memcpy(xp, val, vallen);
728fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	afree(op, vp->areap);
7295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
7305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
73203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * lookup variable (according to (set&LOCAL)), set its attributes
73303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * (INTEGER, RDONLY, EXPORT, TRACE, LJUST, RJUST, ZEROFIL, LCASEV,
73403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * UCASEV_AL), and optionally set its value if an assignment.
7355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
7365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustruct tbl *
73703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condratypeset(const char *var, uint32_t set, uint32_t clr, int field, int base)
7385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
7395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp;
7405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vpbase, *t;
7415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *tvar;
7425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *val;
74303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t len;
74403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	bool vappend = false;
745737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	enum namerefflag new_refflag = SRF_NOP;
746737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
747737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	if ((set & (ARRAY | ASSOC)) == ASSOC) {
748737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		new_refflag = SRF_ENABLE;
749737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		set &= ~(ARRAY | ASSOC);
750737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	}
751737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	if ((clr & (ARRAY | ASSOC)) == ASSOC) {
752737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		new_refflag = SRF_DISABLE;
753737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		clr &= ~(ARRAY | ASSOC);
754737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	}
7555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
7565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* check for valid variable name, search for value */
7575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	val = skip_varname(var, false);
758811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	if (val == var) {
759811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* no variable name given */
760811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		return (NULL);
761811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	}
7625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (*val == '[') {
763737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		if (new_refflag != SRF_NOP)
76403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			errorf("%s: %s", var,
76503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			    "reference variable can't be an array");
7665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		len = array_ref_len(val);
7675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (len == 0)
7685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (NULL);
76903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
77003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * IMPORT is only used when the shell starts up and is
7715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * setting up its environment. Allow only simple array
77203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * references at this time since parameter/command
773c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * substitution is performed on the [expression] which
77403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * would be a major security hole.
7755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
7765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (set & IMPORT) {
77703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			size_t i;
77803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
7795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (i = 1; i < len - 1; i++)
7805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (!ksh_isdigit(val[i]))
7815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					return (NULL);
7825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
7835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		val += len;
7845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
78556b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes	if (val[0] == '=') {
78603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strndupx(tvar, var, val - var, ATEMP);
78756b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		++val;
78856b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes	} else if (set & IMPORT) {
78956b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		/* environment invalid variable name or no assignment */
79056b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		return (NULL);
79156b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes	} else if (val[0] == '+' && val[1] == '=') {
79256b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		strndupx(tvar, var, val - var, ATEMP);
79356b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		val += 2;
79456b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		vappend = true;
79556b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes	} else if (val[0] != '\0') {
79656b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		/* other invalid variable names (not from environment) */
797c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return (NULL);
79803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	} else {
799c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* just varname with no value part nor equals sign */
8005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(tvar, var, ATEMP);
8015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		val = NULL;
80203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* handle foo[*] => foo (whole array) mapping for R39b */
8035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		len = strlen(tvar);
80403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (len > 3 && tvar[len - 3] == '[' && tvar[len - 2] == '*' &&
80503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		    tvar[len - 1] == ']')
80603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tvar[len - 3] = '\0';
8075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
809737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	if (new_refflag == SRF_ENABLE) {
810737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		const char *qval, *ccp;
81103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
81203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* bail out on 'nameref foo+=bar' */
81303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (vappend)
814737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			errorf("appending not allowed for nameref");
81503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* find value if variable already exists */
81603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if ((qval = val) == NULL) {
81703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			varsearch(e->loc, &vp, tvar, hash(tvar));
818f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes			if (vp == NULL)
819f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes				goto nameref_empty;
820f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes			qval = str_val(vp);
82103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
822737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		/* check target value for being a valid variable name */
823737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		ccp = skip_varname(qval, false);
82456b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		if (ccp == qval) {
82556b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			if (ksh_isdigit(qval[0])) {
82656b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				int c;
82756b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes
82856b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				if (getn(qval, &c))
82956b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes					goto nameref_rhs_checked;
83056b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			} else if (qval[1] == '\0') switch (qval[0]) {
83156b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			case '$':
83256b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			case '!':
83356b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			case '?':
83456b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			case '#':
83556b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			case '-':
83656b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes				goto nameref_rhs_checked;
83756b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes			}
838f7f795644b6b1016c35b09d88c52f427473b3baeElliott Hughes nameref_empty:
839737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			errorf("%s: %s", var, "empty nameref target");
84056b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes		}
841737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		len = (*ccp == '[') ? array_ref_len(ccp) : 0;
842737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		if (ccp[len]) {
843737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			/*
844737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			 * works for cases "no array", "valid array with
845737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			 * junk after it" and "invalid array"; in the
846737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			 * latter case, len is also 0 and points to '['
847737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			 */
848737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			errorf("%s: %s", qval,
849737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			    "nameref target not a valid parameter name");
850737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		}
85156b517d46cdf4f6ccd6b62b207110e2afc3db30bElliott Hughes nameref_rhs_checked:
852811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		/* prevent nameref loops */
853811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		while (qval) {
854811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			if (!strcmp(qval, tvar))
855811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				errorf("%s: %s", qval,
856811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				    "expression recurses on parameter");
857811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			varsearch(e->loc, &vp, qval, hash(qval));
858811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			qval = NULL;
859737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes			if (vp && ((vp->flag & (ARRAY | ASSOC)) == ASSOC))
860811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser				qval = str_val(vp);
86103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
86203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
86303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
86403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* prevent typeset from creating a local PATH/ENV/SHELL */
8655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (Flag(FRESTRICTED) && (strcmp(tvar, "PATH") == 0 ||
8665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    strcmp(tvar, "ENV") == 0 || strcmp(tvar, "SHELL") == 0))
86703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		errorf("%s: %s", tvar, "restricted");
8685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
869737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	innermost_refflag = new_refflag;
870737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	vp = (set & LOCAL) ? local(tvar, tobool(set & LOCAL_COPY)) :
8715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    global(tvar);
872737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	if (new_refflag == SRF_DISABLE && (vp->flag & (ARRAY|ASSOC)) == ASSOC)
8735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag &= ~ASSOC;
874737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	else if (new_refflag == SRF_ENABLE) {
8755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (vp->flag & ARRAY) {
8765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			struct tbl *a, *tmp;
8775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
87803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* free up entire array */
8795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			for (a = vp->u.array; a; ) {
8805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				tmp = a;
8815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				a = a->u.array;
8825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (tmp->flag & ALLOC)
8835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					afree(tmp->val.s, tmp->areap);
8845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(tmp, tmp->areap);
8855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
8865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->u.array = NULL;
8875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			vp->flag &= ~ARRAY;
8885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
8895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag |= ASSOC;
8905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
8915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
8925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	set &= ~(LOCAL|LOCAL_COPY);
8935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
894737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	vpbase = (vp->flag & ARRAY) ? global(arrayname(tvar)) : vp;
8955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
89603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
89703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * only allow export flag to be set; AT&T ksh allows any
89803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * attribute to be changed which means it can be truncated or
89903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * modified (-L/-R/-Z/-i)
9005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
901737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	if ((vpbase->flag & RDONLY) &&
9025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    (val || clr || (set & ~EXPORT)))
9035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* XXX check calls - is error here ok by POSIX? */
904c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		errorfx(2, "read-only: %s", tvar);
9055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	afree(tvar, ATEMP);
9065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* most calls are with set/clr == 0 */
9085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (set | clr) {
9095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		bool ok = true;
9105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
91103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
91203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * XXX if x[0] isn't set, there will be problems: need
91303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * to have one copy of attributes for arrays...
9145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
9155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (t = vpbase; t; t = t->u.array) {
9165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			bool fake_assign;
9175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char *s = NULL;
9185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char *free_me = NULL;
9195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			fake_assign = (t->flag & ISSET) && (!val || t != vp) &&
9215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    ((set & (UCASEV_AL|LCASEV|LJUST|RJUST|ZEROFIL)) ||
9225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    ((t->flag & INTEGER) && (clr & INTEGER)) ||
9235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (!(t->flag & INTEGER) && (set & INTEGER)));
9245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (fake_assign) {
9255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (t->flag & INTEGER) {
9265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					s = str_val(t);
9275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					free_me = NULL;
9285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				} else {
9295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					s = t->val.s + t->type;
9305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					free_me = (t->flag & ALLOC) ? t->val.s :
9315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					    NULL;
9325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
9335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				t->flag &= ~ALLOC;
9345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (!(t->flag & INTEGER) && (set & INTEGER)) {
9365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				t->type = 0;
9375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				t->flag &= ~ALLOC;
9385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			t->flag = (t->flag | set) & ~clr;
94003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/*
94103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * Don't change base if assignment is to be
94203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			 * done, in case assignment fails.
9435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			 */
9445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((set & INTEGER) && base > 0 && (!val || t != vp))
9455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				t->type = base;
9465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (set & (LJUST|RJUST|ZEROFIL))
9475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				t->u2.field = field;
9485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (fake_assign) {
9495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (!setstr(t, s, KSH_RETURN_ERROR)) {
95003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					/*
95103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * Somewhat arbitrary action
95203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * here: zap contents of
95303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * variable, but keep the flag
95403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra					 * settings.
9555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					 */
9565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					ok = false;
9575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (t->flag & INTEGER)
9585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						t->flag &= ~ISSET;
9595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					else {
9605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						if (t->flag & ALLOC)
9615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru							afree(t->val.s, t->areap);
9625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						t->flag &= ~(ISSET|ALLOC);
9635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						t->type = 0;
9645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					}
9655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
966fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes				afree(free_me, t->areap);
9675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
9685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
9695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (!ok)
9705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			errorfz();
9715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (val != NULL) {
97403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		char *tval;
97503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
97603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		if (vappend) {
97703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tval = shf_smprintf("%s%s", str_val(vp), val);
97803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			val = tval;
97903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		} else
98003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			tval = NULL;
98103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
9825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (vp->flag&INTEGER) {
9835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* do not zero base before assignment */
9845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			setstr(vp, val, KSH_UNWIND_ERROR | 0x4);
98503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* done after assignment to override default */
9865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (base > 0)
9875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				vp->type = base;
9885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} else
9895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* setstr can't fail (readonly check already done) */
9905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			setstr(vp, val, KSH_RETURN_ERROR | 0x4);
99103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
992fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		afree(tval, ATEMP);
9935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
9945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
9955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* only x[0] is ever exported, so use vpbase */
9965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vpbase->flag&EXPORT) && !(vpbase->flag&INTEGER) &&
9975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	    vpbase->type == 0)
9985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		exportprep(vpbase, (vpbase->flag&ISSET) ? vpbase->val.s : null);
9995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (vp);
10015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/**
10045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Unset a variable. The flags can be:
10055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * |1	= tear down entire array
10065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * |2	= keep attributes, only unset content
10075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
10095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruunset(struct tbl *vp, int flags)
10105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vp->flag & ALLOC)
10125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		afree(vp->val.s, vp->areap);
10135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vp->flag & ARRAY) && (flags & 1)) {
10145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct tbl *a, *tmp;
10155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
101603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* free up entire array */
10175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		for (a = vp->u.array; a; ) {
10185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tmp = a;
10195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			a = a->u.array;
10205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (tmp->flag & ALLOC)
10215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(tmp->val.s, tmp->areap);
10225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			afree(tmp, tmp->areap);
10235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->u.array = NULL;
10255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (flags & 2) {
10275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag &= ~(ALLOC|ISSET);
10285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
10295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
103003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* if foo[0] is being unset, the remainder of the array is kept... */
10315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED);
10325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (vp->flag & SPECIAL)
103303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* responsible for 'unspecial'ing var */
103403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		unsetspec(vp);
10355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
103703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
103803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Return a pointer to the first char past a legal variable name
103903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * (returns the argument if there is no legal name, returns a pointer to
104003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * the terminating NUL if whole string is legal).
10415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
10425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruconst char *
1043737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesskip_varname(const char *s, bool aok)
10445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
104503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t alen;
10465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (s && ksh_isalphx(*s)) {
10485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		while (*++s && ksh_isalnux(*s))
10495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			;
10505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (aok && *s == '[' && (alen = array_ref_len(s)))
10515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s += alen;
10525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (s);
10545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Return a pointer to the first character past any legal variable name */
10575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruconst char *
10585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruskip_wdvarname(const char *s,
105903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    /* skip array de-reference? */
106003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra    bool aok)
10615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (s[0] == CHAR && ksh_isalphx(s[1])) {
10635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		do {
10645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s += 2;
10655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		} while (s[0] == CHAR && ksh_isalnux(s[1]));
10665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (aok && s[0] == CHAR && s[1] == '[') {
10675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			/* skip possible array de-reference */
10685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			const char *p = s;
10695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			char c;
10705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			int depth = 0;
10715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
107203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			while (/* CONSTCOND */ 1) {
10735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (p[0] != CHAR)
10745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
10755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				c = p[1];
10765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				p += 2;
10775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (c == '[')
10785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					depth++;
10795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				else if (c == ']' && --depth == 0) {
10805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					s = p;
10815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
10825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
10835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
10845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
10855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
10865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (s);
10875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Check if coded string s is a variable name */
10905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
109103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrais_wdvarname(const char *s, bool aok)
10925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
10935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p = skip_wdvarname(s, aok);
10945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (p != s && p[0] == EOS);
10965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
10975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
10985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Check if coded string s is a variable assignment */
10995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruint
11005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruis_wdvarassign(const char *s)
11015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p = skip_wdvarname(s, true);
11035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
110403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (p != s && p[0] == CHAR &&
110503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	    (p[1] == '=' || (p[1] == '+' && p[2] == CHAR && p[3] == '=')));
11065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Make the exported environment from the exported names in the dictionary.
11105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar **
11125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querumakenv(void)
11135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
111403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	ssize_t i;
11155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct block *l;
11165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPtrV denv;
11175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp, **vpp;
11185155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPinit(denv, 64);
112003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	for (l = e->loc; l != NULL; l = l->next) {
112103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		vpp = l->vars.tbls;
112203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		i = 1 << (l->vars.tshift);
112303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		while (--i >= 0)
11245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if ((vp = *vpp++) != NULL &&
11255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
11265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				struct block *l2;
11275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				struct tbl *vp2;
11285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				uint32_t h = hash(vp->name);
11295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				/* unexport any redefined instances */
11315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				for (l2 = l->next; l2 != NULL; l2 = l2->next) {
11325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					vp2 = ktsearch(&l2->vars, vp->name, h);
11335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					if (vp2 != NULL)
11345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru						vp2->flag &= ~EXPORT;
11355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
11365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if ((vp->flag&INTEGER)) {
11375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* integer to string */
11385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					char *val;
11395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					val = str_val(vp);
11405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					vp->flag &= ~(INTEGER|RDONLY|SPECIAL);
11415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					/* setstr can't fail here */
11425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					setstr(vp, val, KSH_RETURN_ERROR);
11435155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				}
11445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				XPput(denv, vp->val.s);
11455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
114650012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes		if (l->flags & BF_STOPENV)
114750012061ca3ad8e8a7f88c72130a5e22d797897eElliott Hughes			break;
114803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
11495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	XPput(denv, NULL);
11505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return ((char **)XPclose(denv));
11515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
11545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * handle special variables with side effects - PATH, SECONDS.
11555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
11565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Test if name is a special parameter */
11585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic int
11595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruspecial(const char *name)
11605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
11625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp = ktsearch(&specials, name, hash(name));
11645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (tp && (tp->flag & ISSET) ? tp->type : V_NONE);
11655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* Make a variable non-special */
11685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
11695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruunspecial(const char *name)
11705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
11715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *tp;
11725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	tp = ktsearch(&specials, name, hash(name));
11745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (tp)
11755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		ktdelete(tp);
11765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
11775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic time_t seconds;		/* time SECONDS last set */
1179b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughesstatic mksh_uari_t user_lineno;	/* what user set $LINENO to */
11805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
11825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querugetspec(struct tbl *vp)
11835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1184811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	mksh_ari_u num;
11855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int st;
1186c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	struct timeval tv;
11875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
11885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch ((st = special(vp->name))) {
1189c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_COLUMNS:
1190c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_LINES:
11915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
1192c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * Do NOT export COLUMNS/LINES. Many applications
1193c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * check COLUMNS/LINES before checking ws.ws_col/row,
1194c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * so if the app is started with C/L in the environ
1195c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * and the window is then resized, the app won't
1196c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * see the change cause the environ doesn't change.
11975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1198c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (got_winch)
1199c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			change_winsz();
12005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1201c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
1202c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	switch (st) {
1203c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_BASHPID:
1204811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num.u = (mksh_uari_t)procpid;
1205c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
1206c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_COLUMNS:
1207811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num.i = x_cols;
12085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
12095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_HISTSIZE:
1210811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num.i = histsize;
12115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
12125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_LINENO:
1213b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		num.u = (mksh_uari_t)current_lineno + user_lineno;
12145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
12155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_LINES:
1216811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num.i = x_lins;
1217c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
1218c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_EPOCHREALTIME: {
1219c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* 10(%u) + 1(.) + 6 + NUL */
1220c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		char buf[18];
1221c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
1222c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		vp->flag &= ~SPECIAL;
1223c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		mksh_TIME(tv);
1224c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		shf_snprintf(buf, sizeof(buf), "%u.%06u",
1225c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		    (unsigned)tv.tv_sec, (unsigned)tv.tv_usec);
1226c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		setstr(vp, buf, KSH_RETURN_ERROR | 0x4);
1227c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		vp->flag |= SPECIAL;
1228c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
1229c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
1230c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_OPTIND:
1231811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num.i = user_opt.uoptind;
1232c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
1233c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_RANDOM:
1234811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		num.i = rndget();
1235c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
1236c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_SECONDS:
12375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
1238c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * On start up the value of SECONDS is used before
1239c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * it has been set - don't do anything in this case
1240c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		 * (see initcoms[] in main.c).
12415155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1242c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (vp->flag & ISSET) {
1243c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			mksh_TIME(tv);
1244811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			num.i = tv.tv_sec - seconds;
1245c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		} else
1246c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			return;
12475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
12485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
12495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* do nothing, do not touch vp at all */
12505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
12515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
12525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vp->flag &= ~SPECIAL;
1253811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	setint_n(vp, num.i, 0);
12545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	vp->flag |= SPECIAL;
12555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
12565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
12585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querusetspec(struct tbl *vp)
12595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1260811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser	mksh_ari_u num;
12615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *s;
12625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int st;
12635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch ((st = special(vp->name))) {
1265c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#if HAVE_PERSISTENT_HISTORY
1266c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_HISTFILE:
1267c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		sethistfile(str_val(vp));
1268c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
1269c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser#endif
1270c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_IFS:
1271c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		setctypes(s = str_val(vp), C_IFS);
1272c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		ifs0 = *s;
1273c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		return;
12745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_PATH:
1275fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		afree(path, APERM);
12765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		s = str_val(vp);
12775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(path, s, APERM);
127803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* clear tracked aliases */
127903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		flushcom(true);
12805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
12815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_TMPDIR:
1282fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		afree(tmpdir, APERM);
1283fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		tmpdir = NULL;
128403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/*
128503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * Use tmpdir iff it is an absolute path, is writable
128603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		 * and searchable and is a directory...
12875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
12885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		{
12895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			struct stat statb;
12905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
12915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			s = str_val(vp);
129203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			/* LINTED use of access */
129396b43632c2aa206ac1ec0eb70b34847d58d52633Elliott Hughes			if (mksh_abspath(s) && access(s, W_OK|X_OK) == 0 &&
12945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			    stat(s, &statb) == 0 && S_ISDIR(statb.st_mode))
12955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				strdupx(tmpdir, s, APERM);
12965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
129703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		return;
12985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* common sub-cases */
12995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_COLUMNS:
13005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_LINES:
1301c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		if (vp->flag & IMPORT) {
1302c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			/* do not touch */
1303c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			unspecial(vp->name);
1304c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			vp->flag &= ~SPECIAL;
1305c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			return;
1306c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		}
1307c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* FALLTHROUGH */
1308c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_HISTSIZE:
1309c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_LINENO:
1310c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_OPTIND:
13115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_RANDOM:
13125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_SECONDS:
131303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case V_TMOUT:
13145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag &= ~SPECIAL;
1315811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (getint(vp, &num, false) == -1) {
131603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			s = str_val(vp);
131703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (st != V_RANDOM)
131803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				errorf("%s: %s: %s", vp->name, "bad number", s);
1319811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			num.u = hash(s);
132003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
13215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vp->flag |= SPECIAL;
13225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	default:
13245155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* do nothing, do not touch vp at all */
13255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return;
13265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* process the singular parts of the common cases */
13295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (st) {
13315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_COLUMNS:
1332811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (num.i >= MIN_COLS)
1333811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			x_cols = num.i;
13345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1335c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_HISTSIZE:
1336811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		sethistsize(num.i);
1337c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
1338c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_LINENO:
1339c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* The -1 is because line numbering starts at 1. */
1340b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		user_lineno = num.u - (mksh_uari_t)current_lineno - 1;
1341c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
13425155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_LINES:
1343811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		if (num.i >= MIN_LINS)
1344811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			x_lins = num.i;
13455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
1346c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_OPTIND:
1347811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		getopts_reset((int)num.i);
1348c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
13495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_RANDOM:
13505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/*
13515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * mksh R39d+ no longer has the traditional repeatability
13525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 * of $RANDOM sequences, but always retains state
13535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		 */
1354811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		rndset((unsigned long)num.u);
13555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_SECONDS:
13575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		{
13585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			struct timeval tv;
13595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1360c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser			mksh_TIME(tv);
1361811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser			seconds = tv.tv_sec - num.i;
13625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
13635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
136403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case V_TMOUT:
1365811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaser		ksh_tmout = num.i >= 0 ? num.i : 0;
136603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		break;
13675155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
13685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
13695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
13705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querustatic void
13715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruunsetspec(struct tbl *vp)
13725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1373c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/*
1374c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * AT&T ksh man page says OPTIND, OPTARG and _ lose special
1375c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * meaning, but OPTARG does not (still set by getopts) and _ is
1376c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * also still set in various places. Don't know what AT&T does
1377c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * for HISTSIZE, HISTFILE. Unsetting these in AT&T ksh does not
1378c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * loose the 'specialness': IFS, COLUMNS, PATH, TMPDIR
1379c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 */
1380c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
13815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	switch (special(vp->name)) {
1382b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes#if HAVE_PERSISTENT_HISTORY
1383b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes	case V_HISTFILE:
1384b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		sethistfile(NULL);
1385b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes		return;
1386b27ce95e41e941ad22b3dc392d8328251d3a057eElliott Hughes#endif
1387c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	case V_IFS:
1388c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		setctypes(TC_IFSWS, C_IFS);
1389c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		ifs0 = ' ';
1390c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		break;
13915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_PATH:
1392fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes		afree(path, APERM);
13935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(path, def_path, APERM);
139403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* clear tracked aliases */
139503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		flushcom(true);
13965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
13975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_TMPDIR:
13985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* should not become unspecial */
13995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (tmpdir) {
14005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			afree(tmpdir, APERM);
14015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			tmpdir = NULL;
14025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
14035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_LINENO:
14055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_RANDOM:
14065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	case V_SECONDS:
140703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	case V_TMOUT:
140803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* AT&T ksh leaves previous value in place */
14095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unspecial(vp->name);
14105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		break;
14115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14135155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
14155155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Search for (and possibly create) a table entry starting with
14165155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * vp, indexed by val.
14175155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
141803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrastruct tbl *
14195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruarraysearch(struct tbl *vp, uint32_t val)
14205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
14215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *prev, *curr, *news;
14225155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	size_t len;
14235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1424737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	vp->flag = (vp->flag | (ARRAY | DEFINED)) & ~ASSOC;
142503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/* the table entry is always [0] */
14265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (val == 0)
14275155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (vp);
14285155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	prev = vp;
14295155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	curr = vp->u.array;
14305155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while (curr && curr->ua.index < val) {
14315155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		prev = curr;
14325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		curr = curr->u.array;
14335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (curr && curr->ua.index == val) {
14355155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (curr->flag&ISSET)
14365155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			return (curr);
14375155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		news = curr;
14385155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	} else
14395155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		news = NULL;
14405155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!news) {
144103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		len = strlen(vp->name);
144203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		checkoktoadd(len, 1 + offsetof(struct tbl, name[0]));
144303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		news = alloc(offsetof(struct tbl, name[0]) + ++len, vp->areap);
14445155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		memcpy(news->name, vp->name, len);
14455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14465155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	news->flag = (vp->flag & ~(ALLOC|DEFINED|ISSET|SPECIAL)) | AINDEX;
14475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	news->type = vp->type;
14485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	news->areap = vp->areap;
14495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	news->u2.field = vp->u2.field;
14505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	news->ua.index = val;
14515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
145203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (curr != news) {
145303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* not reusing old array entry */
14545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		prev->u.array = news;
14555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		news->u.array = curr;
14565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
14575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (news);
14585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
146003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra/*
146103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * Return the length of an array reference (eg, [1+2]) - cp is assumed
146203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * to point to the open bracket. Returns 0 if there is no matching
146303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra * closing bracket.
1464737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes *
1465737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes * XXX this should parse the actual arithmetic syntax
14665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
146703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrasize_t
14685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruarray_ref_len(const char *cp)
14695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
14705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *s = cp;
147103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char c;
14725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	int depth = 0;
14735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((c = *s++) && (c != ']' || --depth))
14755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (c == '[')
14765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			depth++;
14775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (!c)
14785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		return (0);
14795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (s - cp);
14805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14825155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/*
14835155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru * Make a copy of the base of an array name
14845155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru */
14855155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchar *
14865155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruarrayname(const char *str)
14875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
14885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	const char *p;
14895155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	char *rv;
14905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1491fc0307d88e2ab13777f102dc63c0d1c968dc8bb2Elliott Hughes	if (!(p = cstrchr(str, '[')))
14925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* Shouldn't happen, but why worry? */
14935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strdupx(rv, str, ATEMP);
14945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	else
14955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		strndupx(rv, str, p - str, ATEMP);
14965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
14975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (rv);
14985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
14995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru/* set (or overwrite, if reset) the array variable var to the values in vals */
15015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Querumksh_uari_t
15025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruset_array(const char *var, bool reset, const char **vals)
15035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
15045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	struct tbl *vp, *vq;
150503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	mksh_uari_t i = 0, j = 0;
1506c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	const char *ccp = var;
150703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	char *cp = NULL;
150803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	size_t n;
15095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1510c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/* to get local array, use "local foo; set -A foo" */
151103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	n = strlen(var);
151203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (n > 0 && var[n - 1] == '+') {
151303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* append mode */
151403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		reset = false;
151503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		strndupx(cp, var, n - 1, ATEMP);
1516c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		ccp = cp;
151703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
1518c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	vp = global(ccp);
15195155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15205155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* Note: AT&T ksh allows set -A but not set +A of a read-only var */
15215155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if ((vp->flag&RDONLY))
1522c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		errorfx(2, "read-only: %s", ccp);
15235155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* This code is quite non-optimal */
1524c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (reset) {
15255155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* trash existing values and attributes */
15265155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		unset(vp, 1);
1527c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		/* allocate-by-access the [0] element to keep in scope */
1528c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser		arraysearch(vp, 0);
1529c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	}
153003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
153103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * TODO: would be nice for assignment to completely succeed or
15325155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * completely fail. Only really effects integer arrays:
15335155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 * evaluation of some of vals[] may fail...
15345155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	 */
153503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	if (cp != NULL) {
153603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		/* find out where to set when appending */
153703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		for (vq = vp; vq; vq = vq->u.array) {
153803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (!(vq->flag & ISSET))
153903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				continue;
154003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra			if (arrayindex(vq) >= j)
154103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra				j = arrayindex(vq) + 1;
154203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		}
154303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra		afree(cp, ATEMP);
154403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	}
15455155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	while ((ccp = vals[i])) {
1546737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#if 0 /* temporarily taken out due to regression */
15475155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (*ccp == '[') {
15485155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			int level = 0;
15495155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15505155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			while (*ccp) {
15515155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (*ccp == ']' && --level == 0)
15525155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					break;
15535155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				if (*ccp == '[')
15545155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru					++level;
15555155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				++ccp;
15565155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			}
15575155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (*ccp == ']' && level == 0 && ccp[1] == '=') {
15585155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				strndupx(cp, vals[i] + 1, ccp - (vals[i] + 1),
15595155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    ATEMP);
15605155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				evaluate(substitute(cp, 0), (mksh_ari_t *)&j,
15615155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				    KSH_UNWIND_ERROR, true);
15625155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				afree(cp, ATEMP);
15635155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				ccp += 2;
15645155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			} else
15655155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				ccp = vals[i];
15665155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
1567737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#endif
15685155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15695155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		vq = arraysearch(vp, j);
15705155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		/* would be nice to deal with errors here... (see above) */
15715155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		setstr(vq, ccp, KSH_RETURN_ERROR);
15725155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		i++;
15735155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		j++;
15745155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15755155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15765155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	return (i);
15775155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
15785155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15795155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruvoid
15805155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruchange_winsz(void)
15815155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
1582737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	struct timeval tv;
1583737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1584737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	mksh_TIME(tv);
1585737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_mem(qh_state, &tv, sizeof(tv));
1586737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
15875155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef TIOCGWINSZ
15885155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* check if window size has changed */
1589c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	if (tty_init_fd() < 2) {
15905155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		struct winsize ws;
15915155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
15925155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		if (ioctl(tty_fd, TIOCGWINSZ, &ws) >= 0) {
15935155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ws.ws_col)
15945155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				x_cols = ws.ws_col;
15955155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru			if (ws.ws_row)
15965155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru				x_lins = ws.ws_row;
15975155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		}
15985155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	}
15995155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
16005155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16015155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	/* bounds check for sane values, use defaults otherwise */
16025155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (x_cols < MIN_COLS)
16035155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		x_cols = 80;
16045155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	if (x_lins < MIN_LINS)
16055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru		x_lins = 24;
16065155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16075155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#ifdef SIGWINCH
16085155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru	got_winch = 0;
16095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru#endif
16105155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
16115155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
16125155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queruuint32_t
161303ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condrahash(const void *s)
16145155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru{
161503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	register uint32_t h;
161603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1617737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHInit(h);
1618737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateStr_reg(h, s);
1619737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(h);
1620737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	return (h);
1621737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes}
1622737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1623737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesuint32_t
1624737fdce098f804459a925438e48dd711c31bbc9eElliott Hugheschvt_rndsetup(const void *bp, size_t sz)
1625737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes{
1626737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	register uint32_t h;
1627737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1628737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/* use LCG as seed but try to get them to deviate immediately */
1629737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	h = lcg_state;
1630737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	(void)rndget();
1631737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(h);
1632737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/* variation through pid, ppid, and the works */
1633737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_reg(h, &rndsetupstate, sizeof(rndsetupstate));
1634737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/* some variation, some possibly entropy, depending on OE */
1635737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_reg(h, bp, sz);
1636737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/* mix them all up */
1637737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(h);
1638737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
163903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	return (h);
164003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra}
164103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1642c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glasermksh_ari_t
1643c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaserrndget(void)
1644c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser{
1645c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	/*
1646c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * this is the same Linear Congruential PRNG as Borland
1647c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 * C/C++ allegedly uses in its built-in rand() function
1648c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	 */
1649c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser	return (((lcg_state = 22695477 * lcg_state + 1) >> 16) & 0x7FFF);
1650c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser}
1651c2dc5def5e2273bb1d78b4ba032a3903dd0f980cThorsten Glaser
165203ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condravoid
1653811a575c0f6a5ef00a921d14c1830ef5ae1bd796Thorsten Glaserrndset(unsigned long v)
165403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra{
165503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	register uint32_t h;
1656737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
1657737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	register uint32_t t;
1658737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#endif
1659737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	struct {
1660737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		struct timeval tv;
1661737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		void *sp;
1662737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		uint32_t qh;
1663737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		pid_t pp;
1664737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes		short r;
1665737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	} z;
1666737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1667737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#ifdef DEBUG
1668737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	/* clear the allocated space, for valgrind */
1669737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	memset(&z, 0, sizeof(z));
1670737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#endif
167103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
1672737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	h = lcg_state;
1673737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(h);
1674737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_reg(h, &v, sizeof(v));
1675737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1676737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	mksh_TIME(z.tv);
1677737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	z.sp = &lcg_state;
1678737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	z.pp = procpid;
1679737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	z.r = (short)rndget();
168003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra
168103ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#if defined(arc4random_pushb_fast) || defined(MKSH_A4PB)
1682737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	t = qh_state;
1683737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(t);
1684737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	z.qh = (t & 0xFFFF8000) | rndget();
1685737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	lcg_state = (t << 15) | rndget();
168603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	/*
168703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * either we have very chap entropy get and push available,
168803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * with malloc() pulling in this code already anyway, or the
168903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 * user requested us to use the old functions
169003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	 */
1691737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	t = h;
1692737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_reg(t, &lcg_state, sizeof(lcg_state));
1693737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(t);
1694737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	lcg_state = t;
169503ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#if defined(arc4random_pushb_fast)
169603ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	arc4random_pushb_fast(&lcg_state, sizeof(lcg_state));
169703ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	lcg_state = arc4random();
169803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#else
169903ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	lcg_state = arc4random_pushb(&lcg_state, sizeof(lcg_state));
170003ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
1701737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_reg(h, &lcg_state, sizeof(lcg_state));
1702737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes#else
1703737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	z.qh = qh_state;
170403ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra#endif
17055155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru
1706737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateMem_reg(h, &z, sizeof(z));
1707737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHFinish_reg(h);
170803ebf06f4e1112a0e9533b93062d169232c4cbfeGeremy Condra	lcg_state = h;
17095155f1c7438ef540d7b25eb70aa1639579795b07Jean-Baptiste Queru}
1710737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1711737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesvoid
1712737fdce098f804459a925438e48dd711c31bbc9eElliott Hughesrndpush(const void *s)
1713737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes{
1714737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	register uint32_t h = qh_state;
1715737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes
1716737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateStr_reg(h, s);
1717737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	BAFHUpdateOctet_reg(h, 0);
1718737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes	qh_state = h;
1719737fdce098f804459a925438e48dd711c31bbc9eElliott Hughes}
1720