|  |  |  | @@ -116,10 +116,6 @@ | 
		
	
		
			
				|  |  |  |  | #include "libbb.h" | 
		
	
		
			
				|  |  |  |  | #include "math.h" | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | #define lookupvar (math_state->lookupvar) | 
		
	
		
			
				|  |  |  |  | #define setvar    (math_state->setvar   ) | 
		
	
		
			
				|  |  |  |  | //#define endofname (math_state->endofname) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | typedef unsigned char operator; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* An operator's token id is a bit of a bitfield. The lower 5 bits are the | 
		
	
	
		
			
				
					
					|  |  |  | @@ -258,7 +254,7 @@ static const char* | 
		
	
		
			
				|  |  |  |  | arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	if (t->var) { | 
		
	
		
			
				|  |  |  |  | 		const char *p = lookupvar(t->var); | 
		
	
		
			
				|  |  |  |  | 		const char *p = math_state->lookupvar(t->var); | 
		
	
		
			
				|  |  |  |  | 		if (p) { | 
		
	
		
			
				|  |  |  |  | 			remembered_name *cur; | 
		
	
		
			
				|  |  |  |  | 			remembered_name cur_save; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -445,16 +441,15 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (top_of_stack->var == NULL) { | 
		
	
		
			
				|  |  |  |  | 			/* Hmm, 1=2 ? */ | 
		
	
		
			
				|  |  |  |  | //TODO: actually, bash allows ++7 but for some reason it evals to 7, not 8 | 
		
	
		
			
				|  |  |  |  | 			goto err; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  | 		/* Save to shell variable */ | 
		
	
		
			
				|  |  |  |  | 		sprintf(buf, ARITH_FMT, rez); | 
		
	
		
			
				|  |  |  |  | 		setvar(top_of_stack->var, buf); | 
		
	
		
			
				|  |  |  |  | 		math_state->setvar(top_of_stack->var, buf); | 
		
	
		
			
				|  |  |  |  | 		/* After saving, make previous value for v++ or v-- */ | 
		
	
		
			
				|  |  |  |  | 		if (op == TOK_POST_INC) | 
		
	
		
			
				|  |  |  |  | 			rez--; | 
		
	
		
			
				|  |  |  |  | 		else if (op == TOK_POST_DEC) | 
		
	
		
			
				|  |  |  |  | 		if (op == TOK_POST_DEC) | 
		
	
		
			
				|  |  |  |  | 			rez++; | 
		
	
		
			
				|  |  |  |  | 	} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -607,11 +602,9 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 		const char *p; | 
		
	
		
			
				|  |  |  |  | 		operator op; | 
		
	
		
			
				|  |  |  |  | 		operator prec; | 
		
	
		
			
				|  |  |  |  | 		char arithval; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		expr = skip_whitespace(expr); | 
		
	
		
			
				|  |  |  |  | 		arithval = *expr; | 
		
	
		
			
				|  |  |  |  | 		if (arithval == '\0') { | 
		
	
		
			
				|  |  |  |  | 		if (*expr == '\0') { | 
		
	
		
			
				|  |  |  |  | 			if (expr == start_expr) { | 
		
	
		
			
				|  |  |  |  | 				/* Null expression */ | 
		
	
		
			
				|  |  |  |  | 				numstack->val = 0; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -628,6 +621,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 				 * append a closing right paren | 
		
	
		
			
				|  |  |  |  | 				 * and let the loop process it */ | 
		
	
		
			
				|  |  |  |  | 				expr = ptr_to_rparen; | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("expr=')'"); | 
		
	
		
			
				|  |  |  |  | 				continue; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			/* At this point, we're done with the expression */ | 
		
	
	
		
			
				
					
					|  |  |  | @@ -635,19 +629,16 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 				/* ...but if there isn't, it's bad */ | 
		
	
		
			
				|  |  |  |  | 				goto err; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			if (numstack->var) { | 
		
	
		
			
				|  |  |  |  | 				/* expression is $((var)) only, lookup now */ | 
		
	
		
			
				|  |  |  |  | 				errmsg = arith_lookup_val(math_state, numstack); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			goto ret; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		p = endofname(expr); | 
		
	
		
			
				|  |  |  |  | 		if (p != expr) { | 
		
	
		
			
				|  |  |  |  | 			/* Name */ | 
		
	
		
			
				|  |  |  |  | 			size_t var_name_size = (p-expr) + 1;  /* +1 for NUL */ | 
		
	
		
			
				|  |  |  |  | 			size_t var_name_size = (p - expr) + 1;  /* +1 for NUL */ | 
		
	
		
			
				|  |  |  |  | 			numstackptr->var = alloca(var_name_size); | 
		
	
		
			
				|  |  |  |  | 			safe_strncpy(numstackptr->var, expr, var_name_size); | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("var:'%s'", numstackptr->var); | 
		
	
		
			
				|  |  |  |  | 			expr = p; | 
		
	
		
			
				|  |  |  |  |  num: | 
		
	
		
			
				|  |  |  |  | 			numstackptr->second_val_present = 0; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -656,11 +647,12 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 			continue; | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		if (isdigit(arithval)) { | 
		
	
		
			
				|  |  |  |  | 		if (isdigit(*expr)) { | 
		
	
		
			
				|  |  |  |  | 			/* Number */ | 
		
	
		
			
				|  |  |  |  | 			numstackptr->var = NULL; | 
		
	
		
			
				|  |  |  |  | 			errno = 0; | 
		
	
		
			
				|  |  |  |  | 			numstackptr->val = strto_arith_t(expr, (char**) &expr); | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("val:%lld", numstackptr->val); | 
		
	
		
			
				|  |  |  |  | 			if (errno) | 
		
	
		
			
				|  |  |  |  | 				numstackptr->val = 0; /* bash compat */ | 
		
	
		
			
				|  |  |  |  | 			goto num; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -671,10 +663,10 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 		/* Special case: XYZ--, XYZ++, --XYZ, ++XYZ are recognized | 
		
	
		
			
				|  |  |  |  | 		 * only if XYZ is a variable name, not a number or EXPR. IOW: | 
		
	
		
			
				|  |  |  |  | 		 * "a+++v" is a++ + v. | 
		
	
		
			
				|  |  |  |  | 		 * "(a)+++7" is ( a ) + + + 7. | 
		
	
		
			
				|  |  |  |  | 		 * "7+++v" is 7 + ++v, not 7++ + v. | 
		
	
		
			
				|  |  |  |  | 		 * "--7" is - - 7, not --7. | 
		
	
		
			
				|  |  |  |  | 		 * "++++a" is + + ++a, not ++ ++ a. | 
		
	
		
			
				|  |  |  |  | 		 * (we still mishandle "(a)+++7", should be treated as (a) + + + 7, but we do increment a) | 
		
	
		
			
				|  |  |  |  | 		 * "++++a" is + + ++a, not ++ ++a. | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		if ((expr[0] == '+' || expr[0] == '-') | 
		
	
		
			
				|  |  |  |  | 		 && (expr[1] == expr[0]) | 
		
	
	
		
			
				
					
					|  |  |  | @@ -756,26 +748,40 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 		 * "applied" in this way. | 
		
	
		
			
				|  |  |  |  | 		 */ | 
		
	
		
			
				|  |  |  |  | 		prec = PREC(op); | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("prec:%02x", prec); | 
		
	
		
			
				|  |  |  |  | 		if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { | 
		
	
		
			
				|  |  |  |  | 			/* not left paren or unary */ | 
		
	
		
			
				|  |  |  |  | 			if (lasttok != TOK_NUM) { | 
		
	
		
			
				|  |  |  |  | 				/* binary op must be preceded by a num */ | 
		
	
		
			
				|  |  |  |  | 				goto err; | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			/* The algorithm employed here is simple: while we don't | 
		
	
		
			
				|  |  |  |  | 			 * hit an open paren nor the bottom of the stack, pop | 
		
	
		
			
				|  |  |  |  | 			 * tokens and apply them */ | 
		
	
		
			
				|  |  |  |  | 			while (stackptr != stack) { | 
		
	
		
			
				|  |  |  |  | 				operator prev_op = *--stackptr; | 
		
	
		
			
				|  |  |  |  | 				if (op == TOK_RPAREN) { | 
		
	
		
			
				|  |  |  |  | 					/* The algorithm employed here is simple: while we don't | 
		
	
		
			
				|  |  |  |  | 					 * hit an open paren nor the bottom of the stack, pop | 
		
	
		
			
				|  |  |  |  | 					 * tokens and apply them */ | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("op == TOK_RPAREN"); | 
		
	
		
			
				|  |  |  |  | 					if (prev_op == TOK_LPAREN) { | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("prev_op == TOK_LPAREN"); | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("  %p %p numstackptr[-1].var:'%s'", numstack, numstackptr-1, numstackptr[-1].var); | 
		
	
		
			
				|  |  |  |  | 						if (numstackptr[-1].var) { | 
		
	
		
			
				|  |  |  |  | 							/* Expression is (var), lookup now */ | 
		
	
		
			
				|  |  |  |  | 							errmsg = arith_lookup_val(math_state, &numstackptr[-1]); | 
		
	
		
			
				|  |  |  |  | 							if (errmsg) | 
		
	
		
			
				|  |  |  |  | 								goto err_with_custom_msg; | 
		
	
		
			
				|  |  |  |  | 							/* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */ | 
		
	
		
			
				|  |  |  |  | 							numstackptr[-1].var = NULL; | 
		
	
		
			
				|  |  |  |  | 						} | 
		
	
		
			
				|  |  |  |  | 						/* Any operator directly after a | 
		
	
		
			
				|  |  |  |  | 						 * close paren should consider itself binary */ | 
		
	
		
			
				|  |  |  |  | 						lasttok = TOK_NUM; | 
		
	
		
			
				|  |  |  |  | 						goto next; | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("prev_op != TOK_LPAREN"); | 
		
	
		
			
				|  |  |  |  | 				} else { | 
		
	
		
			
				|  |  |  |  | 					operator prev_prec = PREC(prev_op); | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("op != TOK_RPAREN"); | 
		
	
		
			
				|  |  |  |  | 					fix_assignment_prec(prec); | 
		
	
		
			
				|  |  |  |  | 					fix_assignment_prec(prev_prec); | 
		
	
		
			
				|  |  |  |  | 					if (prev_prec < prec | 
		
	
	
		
			
				
					
					|  |  |  | @@ -785,6 +791,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 						break; | 
		
	
		
			
				|  |  |  |  | 					} | 
		
	
		
			
				|  |  |  |  | 				} | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("arith_apply(prev_op:%02x)", prev_op); | 
		
	
		
			
				|  |  |  |  | 				errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr); | 
		
	
		
			
				|  |  |  |  | 				if (errmsg) | 
		
	
		
			
				|  |  |  |  | 					goto err_with_custom_msg; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -794,6 +801,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | 
		
	
		
			
				|  |  |  |  | 		} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		/* Push this operator to the stack and remember it */ | 
		
	
		
			
				|  |  |  |  | //bb_error_msg("push op:%02x", op); | 
		
	
		
			
				|  |  |  |  | 		*stackptr++ = lasttok = op; | 
		
	
		
			
				|  |  |  |  |  next: ; | 
		
	
		
			
				|  |  |  |  | 	} /* while (1) */ | 
		
	
	
		
			
				
					
					|  |  |  |   |