Home | History | Annotate | Download | only in src
      1 /*	$OpenBSD: expr.c,v 1.22 2013/03/28 08:39:28 nicm Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
      5  *		 2011, 2012, 2013
      6  *	Thorsten Glaser <tg (at) mirbsd.org>
      7  *
      8  * Provided that these terms and disclaimer and all copyright notices
      9  * are retained or reproduced in an accompanying document, permission
     10  * is granted to deal in this work without restriction, including un-
     11  * limited rights to use, publicly perform, distribute, sell, modify,
     12  * merge, give away, or sublicence.
     13  *
     14  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
     15  * the utmost extent permitted by applicable law, neither express nor
     16  * implied; without malicious intent or gross negligence. In no event
     17  * may a licensor, author or contributor be held liable for indirect,
     18  * direct, other damage, loss, or other issues arising in any way out
     19  * of dealing in the work, even if advised of the possibility of such
     20  * damage or existence of a defect, except proven that it results out
     21  * of said person's immediate fault when using the work as intended.
     22  */
     23 
     24 #include "sh.h"
     25 
     26 __RCSID("$MirOS: src/bin/mksh/expr.c,v 1.72 2013/07/21 18:38:56 tg Exp $");
     27 
     28 /* the order of these enums is constrained by the order of opinfo[] */
     29 enum token {
     30 	/* some (long) unary operators */
     31 	O_PLUSPLUS = 0, O_MINUSMINUS,
     32 	/* binary operators */
     33 	O_EQ, O_NE,
     34 	/* assignments are assumed to be in range O_ASN .. O_BORASN */
     35 	O_ASN, O_TIMESASN, O_DIVASN, O_MODASN, O_PLUSASN, O_MINUSASN,
     36 #ifndef MKSH_LEGACY_MODE
     37 	O_ROLASN, O_RORASN,
     38 #endif
     39 	O_LSHIFTASN, O_RSHIFTASN, O_BANDASN, O_BXORASN, O_BORASN,
     40 	/* binary non-assignment operators */
     41 #ifndef MKSH_LEGACY_MODE
     42 	O_ROL, O_ROR,
     43 #endif
     44 	O_LSHIFT, O_RSHIFT,
     45 	O_LE, O_GE, O_LT, O_GT,
     46 	O_LAND,
     47 	O_LOR,
     48 	O_TIMES, O_DIV, O_MOD,
     49 	O_PLUS, O_MINUS,
     50 	O_BAND,
     51 	O_BXOR,
     52 	O_BOR,
     53 	O_TERN,
     54 	O_COMMA,
     55 	/* things after this aren't used as binary operators */
     56 	/* unary that are not also binaries */
     57 	O_BNOT, O_LNOT,
     58 	/* misc */
     59 	OPEN_PAREN, CLOSE_PAREN, CTERN,
     60 	/* things that don't appear in the opinfo[] table */
     61 	VAR, LIT, END, BAD
     62 };
     63 #define IS_ASSIGNOP(op)	((int)(op) >= (int)O_ASN && (int)(op) <= (int)O_BORASN)
     64 
     65 /* precisions; used to be enum prec but we do arithmetics on it */
     66 #define P_PRIMARY	0	/* VAR, LIT, (), ! ~ ++ -- */
     67 #define P_MULT		1	/* * / % */
     68 #define P_ADD		2	/* + - */
     69 #define P_SHIFT		3	/* <<< >>> << >> */
     70 #define P_RELATION	4	/* < <= > >= */
     71 #define P_EQUALITY	5	/* == != */
     72 #define P_BAND		6	/* & */
     73 #define P_BXOR		7	/* ^ */
     74 #define P_BOR		8	/* | */
     75 #define P_LAND		9	/* && */
     76 #define P_LOR		10	/* || */
     77 #define P_TERN		11	/* ?: */
     78 	/* = += -= *= /= %= <<<= >>>= <<= >>= &= ^= |= */
     79 #define P_ASSIGN	12
     80 #define P_COMMA		13	/* , */
     81 #define MAX_PREC	P_COMMA
     82 
     83 struct opinfo {
     84 	char name[5];
     85 	/* name length */
     86 	uint8_t len;
     87 	/* precedence: lower is higher */
     88 	uint8_t prec;
     89 };
     90 
     91 /*
     92  * Tokens in this table must be ordered so the longest are first
     93  * (eg, += before +). If you change something, change the order
     94  * of enum token too.
     95  */
     96 static const struct opinfo opinfo[] = {
     97 	{ "++",   2, P_PRIMARY },	/* before + */
     98 	{ "--",   2, P_PRIMARY },	/* before - */
     99 	{ "==",   2, P_EQUALITY },	/* before = */
    100 	{ "!=",   2, P_EQUALITY },	/* before ! */
    101 	{ "=",    1, P_ASSIGN },	/* keep assigns in a block */
    102 	{ "*=",   2, P_ASSIGN },
    103 	{ "/=",   2, P_ASSIGN },
    104 	{ "%=",   2, P_ASSIGN },
    105 	{ "+=",   2, P_ASSIGN },
    106 	{ "-=",   2, P_ASSIGN },
    107 #ifndef MKSH_LEGACY_MODE
    108 	{ "<<<=", 4, P_ASSIGN },	/* before <<< */
    109 	{ ">>>=", 4, P_ASSIGN },	/* before >>> */
    110 #endif
    111 	{ "<<=",  3, P_ASSIGN },
    112 	{ ">>=",  3, P_ASSIGN },
    113 	{ "&=",   2, P_ASSIGN },
    114 	{ "^=",   2, P_ASSIGN },
    115 	{ "|=",   2, P_ASSIGN },
    116 #ifndef MKSH_LEGACY_MODE
    117 	{ "<<<",  3, P_SHIFT },		/* before << */
    118 	{ ">>>",  3, P_SHIFT },		/* before >> */
    119 #endif
    120 	{ "<<",   2, P_SHIFT },
    121 	{ ">>",   2, P_SHIFT },
    122 	{ "<=",   2, P_RELATION },
    123 	{ ">=",   2, P_RELATION },
    124 	{ "<",    1, P_RELATION },
    125 	{ ">",    1, P_RELATION },
    126 	{ "&&",   2, P_LAND },
    127 	{ "||",   2, P_LOR },
    128 	{ "*",    1, P_MULT },
    129 	{ "/",    1, P_MULT },
    130 	{ "%",    1, P_MULT },
    131 	{ "+",    1, P_ADD },
    132 	{ "-",    1, P_ADD },
    133 	{ "&",    1, P_BAND },
    134 	{ "^",    1, P_BXOR },
    135 	{ "|",    1, P_BOR },
    136 	{ "?",    1, P_TERN },
    137 	{ ",",    1, P_COMMA },
    138 	{ "~",    1, P_PRIMARY },
    139 	{ "!",    1, P_PRIMARY },
    140 	{ "(",    1, P_PRIMARY },
    141 	{ ")",    1, P_PRIMARY },
    142 	{ ":",    1, P_PRIMARY },
    143 	{ "",     0, P_PRIMARY }
    144 };
    145 
    146 typedef struct expr_state {
    147 	/* expression being evaluated */
    148 	const char *expression;
    149 	/* lexical position */
    150 	const char *tokp;
    151 	/* value from token() */
    152 	struct tbl *val;
    153 	/* variable that is being recursively expanded (EXPRINEVAL flag set) */
    154 	struct tbl *evaling;
    155 	/* token from token() */
    156 	enum token tok;
    157 	/* don't do assignments (for ?:, &&, ||) */
    158 	uint8_t noassign;
    159 	/* evaluating an $(()) expression? */
    160 	bool arith;
    161 	/* unsigned arithmetic calculation */
    162 	bool natural;
    163 } Expr_state;
    164 
    165 enum error_type {
    166 	ET_UNEXPECTED, ET_BADLIT, ET_RECURSIVE,
    167 	ET_LVALUE, ET_RDONLY, ET_STR
    168 };
    169 
    170 static void evalerr(Expr_state *, enum error_type, const char *)
    171     MKSH_A_NORETURN;
    172 static struct tbl *evalexpr(Expr_state *, unsigned int);
    173 static void exprtoken(Expr_state *);
    174 static struct tbl *do_ppmm(Expr_state *, enum token, struct tbl *, bool);
    175 static void assign_check(Expr_state *, enum token, struct tbl *);
    176 static struct tbl *intvar(Expr_state *, struct tbl *);
    177 
    178 /*
    179  * parse and evaluate expression
    180  */
    181 int
    182 evaluate(const char *expr, mksh_ari_t *rval, int error_ok, bool arith)
    183 {
    184 	struct tbl v;
    185 	int ret;
    186 
    187 	v.flag = DEFINED | INTEGER;
    188 	v.type = 0;
    189 	ret = v_evaluate(&v, expr, error_ok, arith);
    190 	*rval = v.val.i;
    191 	return (ret);
    192 }
    193 
    194 /*
    195  * parse and evaluate expression, storing result in vp.
    196  */
    197 int
    198 v_evaluate(struct tbl *vp, const char *expr, volatile int error_ok,
    199     bool arith)
    200 {
    201 	struct tbl *v;
    202 	Expr_state curstate;
    203 	Expr_state * const es = &curstate;
    204 	int i;
    205 
    206 	/* save state to allow recursive calls */
    207 	memset(&curstate, 0, sizeof(curstate));
    208 	curstate.expression = curstate.tokp = expr;
    209 	curstate.tok = BAD;
    210 	curstate.arith = arith;
    211 
    212 	newenv(E_ERRH);
    213 	if ((i = kshsetjmp(e->jbuf))) {
    214 		/* Clear EXPRINEVAL in of any variables we were playing with */
    215 		if (curstate.evaling)
    216 			curstate.evaling->flag &= ~EXPRINEVAL;
    217 		quitenv(NULL);
    218 		if (i == LAEXPR) {
    219 			if (error_ok == KSH_RETURN_ERROR)
    220 				return (0);
    221 			errorfz();
    222 		}
    223 		unwind(i);
    224 		/* NOTREACHED */
    225 	}
    226 
    227 	exprtoken(es);
    228 	if (es->tok == END) {
    229 		es->tok = LIT;
    230 		es->val = tempvar();
    231 	}
    232 	v = intvar(es, evalexpr(es, MAX_PREC));
    233 
    234 	if (es->tok != END)
    235 		evalerr(es, ET_UNEXPECTED, NULL);
    236 
    237 	if (es->arith && es->natural)
    238 		vp->flag |= INT_U;
    239 	if (vp->flag & INTEGER)
    240 		setint_v(vp, v, es->arith);
    241 	else
    242 		/* can fail if readonly */
    243 		setstr(vp, str_val(v), error_ok);
    244 
    245 	quitenv(NULL);
    246 
    247 	return (1);
    248 }
    249 
    250 static void
    251 evalerr(Expr_state *es, enum error_type type, const char *str)
    252 {
    253 	char tbuf[2];
    254 	const char *s;
    255 
    256 	es->arith = false;
    257 	switch (type) {
    258 	case ET_UNEXPECTED:
    259 		switch (es->tok) {
    260 		case VAR:
    261 			s = es->val->name;
    262 			break;
    263 		case LIT:
    264 			s = str_val(es->val);
    265 			break;
    266 		case END:
    267 			s = "end of expression";
    268 			break;
    269 		case BAD:
    270 			tbuf[0] = *es->tokp;
    271 			tbuf[1] = '\0';
    272 			s = tbuf;
    273 			break;
    274 		default:
    275 			s = opinfo[(int)es->tok].name;
    276 		}
    277 		warningf(true, "%s: %s '%s'", es->expression,
    278 		    "unexpected", s);
    279 		break;
    280 
    281 	case ET_BADLIT:
    282 		warningf(true, "%s: %s '%s'", es->expression,
    283 		    "bad number", str);
    284 		break;
    285 
    286 	case ET_RECURSIVE:
    287 		warningf(true, "%s: %s '%s'", es->expression,
    288 		    "expression recurses on parameter", str);
    289 		break;
    290 
    291 	case ET_LVALUE:
    292 		warningf(true, "%s: %s %s",
    293 		    es->expression, str, "requires lvalue");
    294 		break;
    295 
    296 	case ET_RDONLY:
    297 		warningf(true, "%s: %s %s",
    298 		    es->expression, str, "applied to read-only variable");
    299 		break;
    300 
    301 	default: /* keep gcc happy */
    302 	case ET_STR:
    303 		warningf(true, "%s: %s", es->expression, str);
    304 		break;
    305 	}
    306 	unwind(LAEXPR);
    307 }
    308 
    309 /* do a ++ or -- operation */
    310 static struct tbl *
    311 do_ppmm(Expr_state *es, enum token op, struct tbl *vasn, bool is_prefix)
    312 {
    313 	struct tbl *vl;
    314 	mksh_uari_t oval;
    315 
    316 	assign_check(es, op, vasn);
    317 
    318 	vl = intvar(es, vasn);
    319 	oval = vl->val.u;
    320 	if (op == O_PLUSPLUS)
    321 		++vl->val.u;
    322 	else
    323 		--vl->val.u;
    324 	if (!es->noassign) {
    325 		if (vasn->flag & INTEGER)
    326 			setint_v(vasn, vl, es->arith);
    327 		else
    328 			setint(vasn, vl->val.i);
    329 	}
    330 	if (!is_prefix)
    331 		/* undo the increment/decrement */
    332 		vl->val.u = oval;
    333 
    334 	return (vl);
    335 }
    336 
    337 static struct tbl *
    338 evalexpr(Expr_state *es, unsigned int prec)
    339 {
    340 	struct tbl *vl, *vr = NULL, *vasn;
    341 	enum token op;
    342 	mksh_uari_t res = 0, t1, t2, t3;
    343 
    344 	if (prec == P_PRIMARY) {
    345 		switch ((int)(op = es->tok)) {
    346 		case O_BNOT:
    347 		case O_LNOT:
    348 		case O_MINUS:
    349 		case O_PLUS:
    350 			exprtoken(es);
    351 			vl = intvar(es, evalexpr(es, P_PRIMARY));
    352 			switch ((int)op) {
    353 			case O_BNOT:
    354 				vl->val.u = ~vl->val.u;
    355 				break;
    356 			case O_LNOT:
    357 				vl->val.u = !vl->val.u;
    358 				break;
    359 			case O_MINUS:
    360 				vl->val.u = -vl->val.u;
    361 				break;
    362 			case O_PLUS:
    363 				/* nop */
    364 				break;
    365 			}
    366 			break;
    367 
    368 		case OPEN_PAREN:
    369 			exprtoken(es);
    370 			vl = evalexpr(es, MAX_PREC);
    371 			if (es->tok != CLOSE_PAREN)
    372 				evalerr(es, ET_STR, "missing )");
    373 			exprtoken(es);
    374 			break;
    375 
    376 		case O_PLUSPLUS:
    377 		case O_MINUSMINUS:
    378 			exprtoken(es);
    379 			vl = do_ppmm(es, op, es->val, true);
    380 			exprtoken(es);
    381 			break;
    382 
    383 		case VAR:
    384 		case LIT:
    385 			vl = es->val;
    386 			exprtoken(es);
    387 			break;
    388 
    389 		default:
    390 			evalerr(es, ET_UNEXPECTED, NULL);
    391 			/* NOTREACHED */
    392 		}
    393 
    394 		if (es->tok == O_PLUSPLUS || es->tok == O_MINUSMINUS) {
    395 			vl = do_ppmm(es, es->tok, vl, false);
    396 			exprtoken(es);
    397 		}
    398 
    399 		return (vl);
    400 		/* prec == P_PRIMARY */
    401 	}
    402 
    403 	vl = evalexpr(es, prec - 1);
    404 	while ((int)(op = es->tok) >= (int)O_EQ && (int)op <= (int)O_COMMA &&
    405 	    opinfo[(int)op].prec == prec) {
    406 		exprtoken(es);
    407 		vasn = vl;
    408 		if (op != O_ASN)
    409 			/* vl may not have a value yet */
    410 			vl = intvar(es, vl);
    411 		if (IS_ASSIGNOP(op)) {
    412 			if (!es->noassign)
    413 				assign_check(es, op, vasn);
    414 			vr = intvar(es, evalexpr(es, P_ASSIGN));
    415 		} else if (op == O_TERN) {
    416 			bool ev = vl->val.u != 0;
    417 
    418 			if (!ev)
    419 				es->noassign++;
    420 			vl = evalexpr(es, MAX_PREC);
    421 			if (!ev)
    422 				es->noassign--;
    423 			if (es->tok != CTERN)
    424 				evalerr(es, ET_STR, "missing :");
    425 			exprtoken(es);
    426 			if (ev)
    427 				es->noassign++;
    428 			vr = evalexpr(es, P_TERN);
    429 			if (ev)
    430 				es->noassign--;
    431 			vl = ev ? vl : vr;
    432 			continue;
    433 		} else if (op != O_LAND && op != O_LOR)
    434 			vr = intvar(es, evalexpr(es, prec - 1));
    435 
    436 		/* common ops setup */
    437 		switch ((int)op) {
    438 		case O_DIV:
    439 		case O_DIVASN:
    440 		case O_MOD:
    441 		case O_MODASN:
    442 			if (vr->val.u == 0) {
    443 				if (!es->noassign)
    444 					evalerr(es, ET_STR, "zero divisor");
    445 				vr->val.u = 1;
    446 			}
    447 			/* calculate the absolute values */
    448 			t1 = vl->val.i < 0 ? -vl->val.u : vl->val.u;
    449 			t2 = vr->val.i < 0 ? -vr->val.u : vr->val.u;
    450 			break;
    451 #ifndef MKSH_LEGACY_MODE
    452 		case O_LSHIFT:
    453 		case O_LSHIFTASN:
    454 		case O_RSHIFT:
    455 		case O_RSHIFTASN:
    456 		case O_ROL:
    457 		case O_ROLASN:
    458 		case O_ROR:
    459 		case O_RORASN:
    460 			t1 = vl->val.u;
    461 			t2 = vr->val.u & 31;
    462 			break;
    463 #endif
    464 		case O_LAND:
    465 		case O_LOR:
    466 			t1 = vl->val.u;
    467 			t2 = 0;	/* gcc */
    468 			break;
    469 		default:
    470 			t1 = vl->val.u;
    471 			t2 = vr->val.u;
    472 			break;
    473 		}
    474 
    475 #define cmpop(op)	(es->natural ?			\
    476 	(mksh_uari_t)(vl->val.u op vr->val.u) :		\
    477 	(mksh_uari_t)(vl->val.i op vr->val.i)		\
    478 )
    479 
    480 		/* op calculation */
    481 		switch ((int)op) {
    482 		case O_TIMES:
    483 		case O_TIMESASN:
    484 			res = t1 * t2;
    485 			break;
    486 		case O_MOD:
    487 		case O_MODASN:
    488 			if (es->natural) {
    489 				res = vl->val.u % vr->val.u;
    490 				break;
    491 			}
    492 			goto signed_division;
    493 		case O_DIV:
    494 		case O_DIVASN:
    495 			if (es->natural) {
    496 				res = vl->val.u / vr->val.u;
    497 				break;
    498 			}
    499  signed_division:
    500 			/*
    501 			 * a / b = abs(a) / abs(b) * sgn((u)a^(u)b)
    502 			 */
    503 			t3 = t1 / t2;
    504 #ifndef MKSH_LEGACY_MODE
    505 			res = ((vl->val.u ^ vr->val.u) & 0x80000000) ? -t3 : t3;
    506 #else
    507 			res = ((t1 == vl->val.u ? 0 : 1) ^
    508 			    (t2 == vr->val.u ? 0 : 1)) ? -t3 : t3;
    509 #endif
    510 			if (op == O_MOD || op == O_MODASN) {
    511 				/*
    512 				 * primitive modulo, to get the sign of
    513 				 * the result correct:
    514 				 * (a % b) = a - ((a / b) * b)
    515 				 * the subtraction and multiplication
    516 				 * are, amazingly enough, sign ignorant
    517 				 */
    518 				res = vl->val.u - (res * vr->val.u);
    519 			}
    520 			break;
    521 		case O_PLUS:
    522 		case O_PLUSASN:
    523 			res = t1 + t2;
    524 			break;
    525 		case O_MINUS:
    526 		case O_MINUSASN:
    527 			res = t1 - t2;
    528 			break;
    529 #ifndef MKSH_LEGACY_MODE
    530 		case O_ROL:
    531 		case O_ROLASN:
    532 			res = (t1 << t2) | (t1 >> (32 - t2));
    533 			break;
    534 		case O_ROR:
    535 		case O_RORASN:
    536 			res = (t1 >> t2) | (t1 << (32 - t2));
    537 			break;
    538 #endif
    539 		case O_LSHIFT:
    540 		case O_LSHIFTASN:
    541 			res = t1 << t2;
    542 			break;
    543 		case O_RSHIFT:
    544 		case O_RSHIFTASN:
    545 			res = es->natural || vl->val.i >= 0 ?
    546 			    t1 >> t2 :
    547 			    ~(~t1 >> t2);
    548 			break;
    549 		case O_LT:
    550 			res = cmpop(<);
    551 			break;
    552 		case O_LE:
    553 			res = cmpop(<=);
    554 			break;
    555 		case O_GT:
    556 			res = cmpop(>);
    557 			break;
    558 		case O_GE:
    559 			res = cmpop(>=);
    560 			break;
    561 		case O_EQ:
    562 			res = t1 == t2;
    563 			break;
    564 		case O_NE:
    565 			res = t1 != t2;
    566 			break;
    567 		case O_BAND:
    568 		case O_BANDASN:
    569 			res = t1 & t2;
    570 			break;
    571 		case O_BXOR:
    572 		case O_BXORASN:
    573 			res = t1 ^ t2;
    574 			break;
    575 		case O_BOR:
    576 		case O_BORASN:
    577 			res = t1 | t2;
    578 			break;
    579 		case O_LAND:
    580 			if (!t1)
    581 				es->noassign++;
    582 			vr = intvar(es, evalexpr(es, prec - 1));
    583 			res = t1 && vr->val.u;
    584 			if (!t1)
    585 				es->noassign--;
    586 			break;
    587 		case O_LOR:
    588 			if (t1)
    589 				es->noassign++;
    590 			vr = intvar(es, evalexpr(es, prec - 1));
    591 			res = t1 || vr->val.u;
    592 			if (t1)
    593 				es->noassign--;
    594 			break;
    595 		case O_ASN:
    596 		case O_COMMA:
    597 			res = t2;
    598 			break;
    599 		}
    600 
    601 #undef cmpop
    602 
    603 		if (IS_ASSIGNOP(op)) {
    604 			vr->val.u = res;
    605 			if (!es->noassign) {
    606 				if (vasn->flag & INTEGER)
    607 					setint_v(vasn, vr, es->arith);
    608 				else
    609 					setint(vasn, vr->val.i);
    610 			}
    611 			vl = vr;
    612 		} else
    613 			vl->val.u = res;
    614 	}
    615 	return (vl);
    616 }
    617 
    618 static void
    619 exprtoken(Expr_state *es)
    620 {
    621 	const char *cp = es->tokp;
    622 	int c;
    623 	char *tvar;
    624 
    625 	/* skip whitespace */
    626  skip_spaces:
    627 	while ((c = *cp), ksh_isspace(c))
    628 		++cp;
    629 	if (es->tokp == es->expression && c == '#') {
    630 		/* expression begins with # */
    631 		/* switch to unsigned */
    632 		es->natural = true;
    633 		++cp;
    634 		goto skip_spaces;
    635 	}
    636 	es->tokp = cp;
    637 
    638 	if (c == '\0')
    639 		es->tok = END;
    640 	else if (ksh_isalphx(c)) {
    641 		for (; ksh_isalnux(c); c = *cp)
    642 			cp++;
    643 		if (c == '[') {
    644 			size_t len;
    645 
    646 			len = array_ref_len(cp);
    647 			if (len == 0)
    648 				evalerr(es, ET_STR, "missing ]");
    649 			cp += len;
    650 		}
    651 		if (es->noassign) {
    652 			es->val = tempvar();
    653 			es->val->flag |= EXPRLVALUE;
    654 		} else {
    655 			strndupx(tvar, es->tokp, cp - es->tokp, ATEMP);
    656 			es->val = global(tvar);
    657 			afree(tvar, ATEMP);
    658 		}
    659 		es->tok = VAR;
    660 	} else if (c == '1' && cp[1] == '#') {
    661 		cp += 2;
    662 		cp += utf_ptradj(cp);
    663 		strndupx(tvar, es->tokp, cp - es->tokp, ATEMP);
    664 		goto process_tvar;
    665 #ifndef MKSH_SMALL
    666 	} else if (c == '\'') {
    667 		++cp;
    668 		cp += utf_ptradj(cp);
    669 		if (*cp++ != '\'')
    670 			evalerr(es, ET_STR,
    671 			    "multi-character character constant");
    672 		/* 'x' -> 1#x (x = one multibyte character) */
    673 		c = cp - es->tokp;
    674 		tvar = alloc(c + /* NUL */ 1, ATEMP);
    675 		tvar[0] = '1';
    676 		tvar[1] = '#';
    677 		memcpy(tvar + 2, es->tokp + 1, c - 2);
    678 		tvar[c] = '\0';
    679 		goto process_tvar;
    680 #endif
    681 	} else if (ksh_isdigit(c)) {
    682 		while (c != '_' && (ksh_isalnux(c) || c == '#'))
    683 			c = *cp++;
    684 		strndupx(tvar, es->tokp, --cp - es->tokp, ATEMP);
    685  process_tvar:
    686 		es->val = tempvar();
    687 		es->val->flag &= ~INTEGER;
    688 		es->val->type = 0;
    689 		es->val->val.s = tvar;
    690 		if (setint_v(es->val, es->val, es->arith) == NULL)
    691 			evalerr(es, ET_BADLIT, tvar);
    692 		afree(tvar, ATEMP);
    693 		es->tok = LIT;
    694 	} else {
    695 		int i, n0;
    696 
    697 		for (i = 0; (n0 = opinfo[i].name[0]); i++)
    698 			if (c == n0 && strncmp(cp, opinfo[i].name,
    699 			    (size_t)opinfo[i].len) == 0) {
    700 				es->tok = (enum token)i;
    701 				cp += opinfo[i].len;
    702 				break;
    703 			}
    704 		if (!n0)
    705 			es->tok = BAD;
    706 	}
    707 	es->tokp = cp;
    708 }
    709 
    710 static void
    711 assign_check(Expr_state *es, enum token op, struct tbl *vasn)
    712 {
    713 	if (es->tok == END || !vasn ||
    714 	    (vasn->name[0] == '\0' && !(vasn->flag & EXPRLVALUE)))
    715 		evalerr(es, ET_LVALUE, opinfo[(int)op].name);
    716 	else if (vasn->flag & RDONLY)
    717 		evalerr(es, ET_RDONLY, opinfo[(int)op].name);
    718 }
    719 
    720 struct tbl *
    721 tempvar(void)
    722 {
    723 	struct tbl *vp;
    724 
    725 	vp = alloc(sizeof(struct tbl), ATEMP);
    726 	vp->flag = ISSET|INTEGER;
    727 	vp->type = 0;
    728 	vp->areap = ATEMP;
    729 	vp->ua.hval = 0;
    730 	vp->val.i = 0;
    731 	vp->name[0] = '\0';
    732 	return (vp);
    733 }
    734 
    735 /* cast (string) variable to temporary integer variable */
    736 static struct tbl *
    737 intvar(Expr_state *es, struct tbl *vp)
    738 {
    739 	struct tbl *vq;
    740 
    741 	/* try to avoid replacing a temp var with another temp var */
    742 	if (vp->name[0] == '\0' &&
    743 	    (vp->flag & (ISSET|INTEGER|EXPRLVALUE)) == (ISSET|INTEGER))
    744 		return (vp);
    745 
    746 	vq = tempvar();
    747 	if (setint_v(vq, vp, es->arith) == NULL) {
    748 		if (vp->flag & EXPRINEVAL)
    749 			evalerr(es, ET_RECURSIVE, vp->name);
    750 		es->evaling = vp;
    751 		vp->flag |= EXPRINEVAL;
    752 		v_evaluate(vq, str_val(vp), KSH_UNWIND_ERROR, es->arith);
    753 		vp->flag &= ~EXPRINEVAL;
    754 		es->evaling = NULL;
    755 	}
    756 	return (vq);
    757 }
    758 
    759 
    760 /*
    761  * UTF-8 support code: high-level functions
    762  */
    763 
    764 int
    765 utf_widthadj(const char *src, const char **dst)
    766 {
    767 	size_t len;
    768 	unsigned int wc;
    769 	int width;
    770 
    771 	if (!UTFMODE || (len = utf_mbtowc(&wc, src)) == (size_t)-1 ||
    772 	    wc == 0)
    773 		len = width = 1;
    774 	else if ((width = utf_wcwidth(wc)) < 0)
    775 		/* XXX use 2 for x_zotc3 here? */
    776 		width = 1;
    777 
    778 	if (dst)
    779 		*dst = src + len;
    780 	return (width);
    781 }
    782 
    783 size_t
    784 utf_mbswidth(const char *s)
    785 {
    786 	size_t len, width = 0;
    787 	unsigned int wc;
    788 	int cw;
    789 
    790 	if (!UTFMODE)
    791 		return (strlen(s));
    792 
    793 	while (*s)
    794 		if (((len = utf_mbtowc(&wc, s)) == (size_t)-1) ||
    795 		    ((cw = utf_wcwidth(wc)) == -1)) {
    796 			s++;
    797 			width += 1;
    798 		} else {
    799 			s += len;
    800 			width += cw;
    801 		}
    802 	return (width);
    803 }
    804 
    805 const char *
    806 utf_skipcols(const char *p, int cols)
    807 {
    808 	int c = 0;
    809 
    810 	while (c < cols) {
    811 		if (!*p)
    812 			return (p + cols - c);
    813 		c += utf_widthadj(p, &p);
    814 	}
    815 	return (p);
    816 }
    817 
    818 size_t
    819 utf_ptradj(const char *src)
    820 {
    821 	register size_t n;
    822 
    823 	if (!UTFMODE ||
    824 	    *(const unsigned char *)(src) < 0xC2 ||
    825 	    (n = utf_mbtowc(NULL, src)) == (size_t)-1)
    826 		n = 1;
    827 	return (n);
    828 }
    829 
    830 /*
    831  * UTF-8 support code: low-level functions
    832  */
    833 
    834 /* CESU-8 multibyte and wide character conversion crafted for mksh */
    835 
    836 size_t
    837 utf_mbtowc(unsigned int *dst, const char *src)
    838 {
    839 	const unsigned char *s = (const unsigned char *)src;
    840 	unsigned int c, wc;
    841 
    842 	if ((wc = *s++) < 0x80) {
    843  out:
    844 		if (dst != NULL)
    845 			*dst = wc;
    846 		return (wc ? ((const char *)s - src) : 0);
    847 	}
    848 	if (wc < 0xC2 || wc >= 0xF0)
    849 		/* < 0xC0: spurious second byte */
    850 		/* < 0xC2: non-minimalistic mapping error in 2-byte seqs */
    851 		/* > 0xEF: beyond BMP */
    852 		goto ilseq;
    853 
    854 	if (wc < 0xE0) {
    855 		wc = (wc & 0x1F) << 6;
    856 		if (((c = *s++) & 0xC0) != 0x80)
    857 			goto ilseq;
    858 		wc |= c & 0x3F;
    859 		goto out;
    860 	}
    861 
    862 	wc = (wc & 0x0F) << 12;
    863 
    864 	if (((c = *s++) & 0xC0) != 0x80)
    865 		goto ilseq;
    866 	wc |= (c & 0x3F) << 6;
    867 
    868 	if (((c = *s++) & 0xC0) != 0x80)
    869 		goto ilseq;
    870 	wc |= c & 0x3F;
    871 
    872 	/* Check for non-minimalistic mapping error in 3-byte seqs */
    873 	if (wc >= 0x0800 && wc <= 0xFFFD)
    874 		goto out;
    875  ilseq:
    876 	return ((size_t)(-1));
    877 }
    878 
    879 size_t
    880 utf_wctomb(char *dst, unsigned int wc)
    881 {
    882 	unsigned char *d;
    883 
    884 	if (wc < 0x80) {
    885 		*dst = wc;
    886 		return (1);
    887 	}
    888 
    889 	d = (unsigned char *)dst;
    890 	if (wc < 0x0800)
    891 		*d++ = (wc >> 6) | 0xC0;
    892 	else {
    893 		*d++ = ((wc = wc > 0xFFFD ? 0xFFFD : wc) >> 12) | 0xE0;
    894 		*d++ = ((wc >> 6) & 0x3F) | 0x80;
    895 	}
    896 	*d++ = (wc & 0x3F) | 0x80;
    897 	return ((char *)d - dst);
    898 }
    899 
    900 /*
    901  * Wrapper around access(2) because it says root can execute everything
    902  * on some operating systems. Does not set errno, no user needs it. Use
    903  * this iff mode can have the X_OK bit set, access otherwise.
    904  */
    905 int
    906 ksh_access(const char *fn, int mode)
    907 {
    908 	int rv;
    909 	struct stat sb;
    910 
    911 	if ((rv = access(fn, mode)) == 0 && kshuid == 0 && (mode & X_OK) &&
    912 	    (rv = stat(fn, &sb)) == 0 && !S_ISDIR(sb.st_mode) &&
    913 	    (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0)
    914 		rv = -1;
    915 
    916 	return (rv);
    917 }
    918 
    919 #ifndef MKSH_mirbsd_wcwidth
    920 /* From: X11/xc/programs/xterm/wcwidth.c,v 1.6 2013/05/31 23:27:09 tg Exp $ */
    921 
    922 struct mb_ucsrange {
    923 	unsigned short beg;
    924 	unsigned short end;
    925 };
    926 
    927 static int mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems,
    928     unsigned int val);
    929 
    930 /*
    931  * Generated by MirOS: contrib/code/Snippets/eawparse,v 1.1 2013/05/31 23:27:16 tg Exp $
    932  * from Unicode 6.2.0
    933  */
    934 
    935 static const struct mb_ucsrange mb_ucs_combining[] = {
    936 	{ 0x0300, 0x036F },
    937 	{ 0x0483, 0x0489 },
    938 	{ 0x0591, 0x05BD },
    939 	{ 0x05BF, 0x05BF },
    940 	{ 0x05C1, 0x05C2 },
    941 	{ 0x05C4, 0x05C5 },
    942 	{ 0x05C7, 0x05C7 },
    943 	{ 0x0600, 0x0604 },
    944 	{ 0x0610, 0x061A },
    945 	{ 0x064B, 0x065F },
    946 	{ 0x0670, 0x0670 },
    947 	{ 0x06D6, 0x06DD },
    948 	{ 0x06DF, 0x06E4 },
    949 	{ 0x06E7, 0x06E8 },
    950 	{ 0x06EA, 0x06ED },
    951 	{ 0x070F, 0x070F },
    952 	{ 0x0711, 0x0711 },
    953 	{ 0x0730, 0x074A },
    954 	{ 0x07A6, 0x07B0 },
    955 	{ 0x07EB, 0x07F3 },
    956 	{ 0x0816, 0x0819 },
    957 	{ 0x081B, 0x0823 },
    958 	{ 0x0825, 0x0827 },
    959 	{ 0x0829, 0x082D },
    960 	{ 0x0859, 0x085B },
    961 	{ 0x08E4, 0x08FE },
    962 	{ 0x0900, 0x0902 },
    963 	{ 0x093A, 0x093A },
    964 	{ 0x093C, 0x093C },
    965 	{ 0x0941, 0x0948 },
    966 	{ 0x094D, 0x094D },
    967 	{ 0x0951, 0x0957 },
    968 	{ 0x0962, 0x0963 },
    969 	{ 0x0981, 0x0981 },
    970 	{ 0x09BC, 0x09BC },
    971 	{ 0x09C1, 0x09C4 },
    972 	{ 0x09CD, 0x09CD },
    973 	{ 0x09E2, 0x09E3 },
    974 	{ 0x0A01, 0x0A02 },
    975 	{ 0x0A3C, 0x0A3C },
    976 	{ 0x0A41, 0x0A42 },
    977 	{ 0x0A47, 0x0A48 },
    978 	{ 0x0A4B, 0x0A4D },
    979 	{ 0x0A51, 0x0A51 },
    980 	{ 0x0A70, 0x0A71 },
    981 	{ 0x0A75, 0x0A75 },
    982 	{ 0x0A81, 0x0A82 },
    983 	{ 0x0ABC, 0x0ABC },
    984 	{ 0x0AC1, 0x0AC5 },
    985 	{ 0x0AC7, 0x0AC8 },
    986 	{ 0x0ACD, 0x0ACD },
    987 	{ 0x0AE2, 0x0AE3 },
    988 	{ 0x0B01, 0x0B01 },
    989 	{ 0x0B3C, 0x0B3C },
    990 	{ 0x0B3F, 0x0B3F },
    991 	{ 0x0B41, 0x0B44 },
    992 	{ 0x0B4D, 0x0B4D },
    993 	{ 0x0B56, 0x0B56 },
    994 	{ 0x0B62, 0x0B63 },
    995 	{ 0x0B82, 0x0B82 },
    996 	{ 0x0BC0, 0x0BC0 },
    997 	{ 0x0BCD, 0x0BCD },
    998 	{ 0x0C3E, 0x0C40 },
    999 	{ 0x0C46, 0x0C48 },
   1000 	{ 0x0C4A, 0x0C4D },
   1001 	{ 0x0C55, 0x0C56 },
   1002 	{ 0x0C62, 0x0C63 },
   1003 	{ 0x0CBC, 0x0CBC },
   1004 	{ 0x0CBF, 0x0CBF },
   1005 	{ 0x0CC6, 0x0CC6 },
   1006 	{ 0x0CCC, 0x0CCD },
   1007 	{ 0x0CE2, 0x0CE3 },
   1008 	{ 0x0D41, 0x0D44 },
   1009 	{ 0x0D4D, 0x0D4D },
   1010 	{ 0x0D62, 0x0D63 },
   1011 	{ 0x0DCA, 0x0DCA },
   1012 	{ 0x0DD2, 0x0DD4 },
   1013 	{ 0x0DD6, 0x0DD6 },
   1014 	{ 0x0E31, 0x0E31 },
   1015 	{ 0x0E34, 0x0E3A },
   1016 	{ 0x0E47, 0x0E4E },
   1017 	{ 0x0EB1, 0x0EB1 },
   1018 	{ 0x0EB4, 0x0EB9 },
   1019 	{ 0x0EBB, 0x0EBC },
   1020 	{ 0x0EC8, 0x0ECD },
   1021 	{ 0x0F18, 0x0F19 },
   1022 	{ 0x0F35, 0x0F35 },
   1023 	{ 0x0F37, 0x0F37 },
   1024 	{ 0x0F39, 0x0F39 },
   1025 	{ 0x0F71, 0x0F7E },
   1026 	{ 0x0F80, 0x0F84 },
   1027 	{ 0x0F86, 0x0F87 },
   1028 	{ 0x0F8D, 0x0F97 },
   1029 	{ 0x0F99, 0x0FBC },
   1030 	{ 0x0FC6, 0x0FC6 },
   1031 	{ 0x102D, 0x1030 },
   1032 	{ 0x1032, 0x1037 },
   1033 	{ 0x1039, 0x103A },
   1034 	{ 0x103D, 0x103E },
   1035 	{ 0x1058, 0x1059 },
   1036 	{ 0x105E, 0x1060 },
   1037 	{ 0x1071, 0x1074 },
   1038 	{ 0x1082, 0x1082 },
   1039 	{ 0x1085, 0x1086 },
   1040 	{ 0x108D, 0x108D },
   1041 	{ 0x109D, 0x109D },
   1042 	{ 0x1160, 0x11FF },
   1043 	{ 0x135D, 0x135F },
   1044 	{ 0x1712, 0x1714 },
   1045 	{ 0x1732, 0x1734 },
   1046 	{ 0x1752, 0x1753 },
   1047 	{ 0x1772, 0x1773 },
   1048 	{ 0x17B4, 0x17B5 },
   1049 	{ 0x17B7, 0x17BD },
   1050 	{ 0x17C6, 0x17C6 },
   1051 	{ 0x17C9, 0x17D3 },
   1052 	{ 0x17DD, 0x17DD },
   1053 	{ 0x180B, 0x180D },
   1054 	{ 0x18A9, 0x18A9 },
   1055 	{ 0x1920, 0x1922 },
   1056 	{ 0x1927, 0x1928 },
   1057 	{ 0x1932, 0x1932 },
   1058 	{ 0x1939, 0x193B },
   1059 	{ 0x1A17, 0x1A18 },
   1060 	{ 0x1A56, 0x1A56 },
   1061 	{ 0x1A58, 0x1A5E },
   1062 	{ 0x1A60, 0x1A60 },
   1063 	{ 0x1A62, 0x1A62 },
   1064 	{ 0x1A65, 0x1A6C },
   1065 	{ 0x1A73, 0x1A7C },
   1066 	{ 0x1A7F, 0x1A7F },
   1067 	{ 0x1B00, 0x1B03 },
   1068 	{ 0x1B34, 0x1B34 },
   1069 	{ 0x1B36, 0x1B3A },
   1070 	{ 0x1B3C, 0x1B3C },
   1071 	{ 0x1B42, 0x1B42 },
   1072 	{ 0x1B6B, 0x1B73 },
   1073 	{ 0x1B80, 0x1B81 },
   1074 	{ 0x1BA2, 0x1BA5 },
   1075 	{ 0x1BA8, 0x1BA9 },
   1076 	{ 0x1BAB, 0x1BAB },
   1077 	{ 0x1BE6, 0x1BE6 },
   1078 	{ 0x1BE8, 0x1BE9 },
   1079 	{ 0x1BED, 0x1BED },
   1080 	{ 0x1BEF, 0x1BF1 },
   1081 	{ 0x1C2C, 0x1C33 },
   1082 	{ 0x1C36, 0x1C37 },
   1083 	{ 0x1CD0, 0x1CD2 },
   1084 	{ 0x1CD4, 0x1CE0 },
   1085 	{ 0x1CE2, 0x1CE8 },
   1086 	{ 0x1CED, 0x1CED },
   1087 	{ 0x1CF4, 0x1CF4 },
   1088 	{ 0x1DC0, 0x1DE6 },
   1089 	{ 0x1DFC, 0x1DFF },
   1090 	{ 0x200B, 0x200F },
   1091 	{ 0x202A, 0x202E },
   1092 	{ 0x2060, 0x2064 },
   1093 	{ 0x206A, 0x206F },
   1094 	{ 0x20D0, 0x20F0 },
   1095 	{ 0x2CEF, 0x2CF1 },
   1096 	{ 0x2D7F, 0x2D7F },
   1097 	{ 0x2DE0, 0x2DFF },
   1098 	{ 0x302A, 0x302D },
   1099 	{ 0x3099, 0x309A },
   1100 	{ 0xA66F, 0xA672 },
   1101 	{ 0xA674, 0xA67D },
   1102 	{ 0xA69F, 0xA69F },
   1103 	{ 0xA6F0, 0xA6F1 },
   1104 	{ 0xA802, 0xA802 },
   1105 	{ 0xA806, 0xA806 },
   1106 	{ 0xA80B, 0xA80B },
   1107 	{ 0xA825, 0xA826 },
   1108 	{ 0xA8C4, 0xA8C4 },
   1109 	{ 0xA8E0, 0xA8F1 },
   1110 	{ 0xA926, 0xA92D },
   1111 	{ 0xA947, 0xA951 },
   1112 	{ 0xA980, 0xA982 },
   1113 	{ 0xA9B3, 0xA9B3 },
   1114 	{ 0xA9B6, 0xA9B9 },
   1115 	{ 0xA9BC, 0xA9BC },
   1116 	{ 0xAA29, 0xAA2E },
   1117 	{ 0xAA31, 0xAA32 },
   1118 	{ 0xAA35, 0xAA36 },
   1119 	{ 0xAA43, 0xAA43 },
   1120 	{ 0xAA4C, 0xAA4C },
   1121 	{ 0xAAB0, 0xAAB0 },
   1122 	{ 0xAAB2, 0xAAB4 },
   1123 	{ 0xAAB7, 0xAAB8 },
   1124 	{ 0xAABE, 0xAABF },
   1125 	{ 0xAAC1, 0xAAC1 },
   1126 	{ 0xAAEC, 0xAAED },
   1127 	{ 0xAAF6, 0xAAF6 },
   1128 	{ 0xABE5, 0xABE5 },
   1129 	{ 0xABE8, 0xABE8 },
   1130 	{ 0xABED, 0xABED },
   1131 	{ 0xFB1E, 0xFB1E },
   1132 	{ 0xFE00, 0xFE0F },
   1133 	{ 0xFE20, 0xFE26 },
   1134 	{ 0xFEFF, 0xFEFF },
   1135 	{ 0xFFF9, 0xFFFB }
   1136 };
   1137 
   1138 static const struct mb_ucsrange mb_ucs_fullwidth[] = {
   1139 	{ 0x1100, 0x115F },
   1140 	{ 0x2329, 0x232A },
   1141 	{ 0x2E80, 0x303E },
   1142 	{ 0x3040, 0xA4CF },
   1143 	{ 0xA960, 0xA97F },
   1144 	{ 0xAC00, 0xD7A3 },
   1145 	{ 0xF900, 0xFAFF },
   1146 	{ 0xFE10, 0xFE19 },
   1147 	{ 0xFE30, 0xFE6F },
   1148 	{ 0xFF00, 0xFF60 },
   1149 	{ 0xFFE0, 0xFFE6 }
   1150 };
   1151 
   1152 /* simple binary search in ranges, with bounds optimisation */
   1153 static int
   1154 mb_ucsbsearch(const struct mb_ucsrange arr[], size_t elems, unsigned int val)
   1155 {
   1156 	size_t min = 0, mid, max = elems;
   1157 
   1158 	if (val < arr[min].beg || val > arr[max - 1].end)
   1159 		return (0);
   1160 
   1161 	while (min < max) {
   1162 		mid = (min + max) / 2;
   1163 
   1164 		if (val < arr[mid].beg)
   1165 			max = mid;
   1166 		else if (val > arr[mid].end)
   1167 			min = mid + 1;
   1168 		else
   1169 			return (1);
   1170 	}
   1171 	return (0);
   1172 }
   1173 
   1174 /* Unix column width of a wide character (Unicode code point, really) */
   1175 int
   1176 utf_wcwidth(unsigned int wc)
   1177 {
   1178 	/* except NUL, C0/C1 control characters and DEL yield -1 */
   1179 	if (wc < 0x20 || (wc >= 0x7F && wc < 0xA0))
   1180 		return (wc ? -1 : 0);
   1181 
   1182 	/* combining characters use 0 screen columns */
   1183 	if (mb_ucsbsearch(mb_ucs_combining, NELEM(mb_ucs_combining), wc))
   1184 		return (0);
   1185 
   1186 	/* all others use 1 or 2 screen columns */
   1187 	if (mb_ucsbsearch(mb_ucs_fullwidth, NELEM(mb_ucs_fullwidth), wc))
   1188 		return (2);
   1189 	return (1);
   1190 }
   1191 #endif
   1192