Skip to content
Snippets Groups Projects
ast_expr2.c 95.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 				return result;
    			} else {
    				ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
    				return make_number(0.0);
    			}
    
    		} else if (strcmp(funcname->u.s,"LOG2") == 0) {
    			if (arglist && !arglist->right && arglist->val){
    				to_number(arglist->val);
    				result = make_number(FUNC_LOG2(arglist->val->u.i));
    				return result;
    			} else {
    				ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
    				return make_number(0.0);
    			}
    
    		} else if (strcmp(funcname->u.s,"LOG10") == 0) {
    			if (arglist && !arglist->right && arglist->val){
    				to_number(arglist->val);
    				result = make_number(FUNC_LOG10(arglist->val->u.i));
    				return result;
    			} else {
    				ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
    				return make_number(0.0);
    			}
    
    		} else if (strcmp(funcname->u.s,"REMAINDER") == 0) {
    			if (arglist && arglist->right && !arglist->right->right && arglist->val && arglist->right->val){
    				to_number(arglist->val);
    				to_number(arglist->right->val);
    				result = make_number(FUNC_REMAINDER(arglist->val->u.i, arglist->right->val->u.i));
    				return result;
    			} else {
    				ast_log(LOG_WARNING,"Wrong args to %s() function\n",funcname->u.s);
    				return make_number(0.0);
    			}
    
    		} else if (strcmp(funcname->u.s, "ABS") == 0) {
    			if (arglist && !arglist->right && arglist->val) {
    				to_number(arglist->val);
    				result = make_number(arglist->val->u.i < 0 ? arglist->val->u.i * -1 : arglist->val->u.i);
    				return result;
    			} else {
    				ast_log(LOG_WARNING, "Wrong args to %s() function\n", funcname->u.s);
    				return make_number(0.0);
    			}
    
    		} else {
    			/* is this a custom function we should execute and collect the results of? */
    
    #if !defined(STANDALONE) && !defined(STANDALONE2)
    
    			struct ast_custom_function *f = ast_custom_function_find(funcname->u.s);
    			if (!chan)
    				ast_log(LOG_WARNING,"Hey! chan is NULL.\n");
    			if (!f)
    				ast_log(LOG_WARNING,"Hey! could not find func %s.\n", funcname->u.s);
    			
    			if (f && chan) {
    				if (f->read) {
    					char workspace[512];
    					char *argbuf = compose_func_args(arglist);
    					f->read(chan, funcname->u.s, argbuf, workspace, sizeof(workspace));
    					free(argbuf);
    					if (is_really_num(workspace))
    
    						return make_number(FUNC_STRTOD(workspace,(char **)NULL));
    
    					else
    						return make_str(workspace);
    				} else {
    					ast_log(LOG_ERROR,"Error! Function '%s' cannot be read!\n", funcname->u.s);
    					return (make_number ((FP___TYPE)0.0));
    				}
    				
    			} else {
    
    				ast_log(LOG_ERROR, "Error! '%s' doesn't appear to be an available function!\n", funcname->u.s);
    
    				return (make_number ((FP___TYPE)0.0));
    			}
    #else
    
    			ast_log(LOG_ERROR, "Error! '%s' is not available in the standalone version!\n", funcname->u.s);
    
    		ast_log(LOG_ERROR, "Error! '%s' is not possibly a function name!\n", funcname->u.s);
    
    		return (make_number ((FP___TYPE)0.0));
    	}
    	return (make_number ((FP___TYPE)0.0));
    }
    
    
    
    static struct val *
    op_or (struct val *a, struct val *b)
    {
    	if (is_zero_or_null (a)) {
    		free_value (a);
    		return (b);
    	} else {
    		free_value (b);
    		return (a);
    	}
    }
    		
    static struct val *
    op_and (struct val *a, struct val *b)
    {
    	if (is_zero_or_null (a) || is_zero_or_null (b)) {
    		free_value (a);
    		free_value (b);
    
    		return (make_number ((FP___TYPE)0.0));
    
    	} else {
    		free_value (b);
    		return (a);
    	}
    }
    
    static struct val *
    op_eq (struct val *a, struct val *b)
    {
    	struct val *r; 
    
    	if (isstring (a) || isstring (b)) {
    		to_string (a);
    		to_string (b);	
    
    		r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) == 0));
    
    	} else {
    #ifdef DEBUG_FOR_CONVERSIONS
    		char buffer[2000];
    		sprintf(buffer,"Converting '%s' and '%s' ", a->u.s, b->u.s);
    #endif
    
    		(void)to_number(a);
    		(void)to_number(b);
    
    #ifdef DEBUG_FOR_CONVERSIONS
    		ast_log(LOG_WARNING,"%s to '%lld' and '%lld'\n", buffer, a->u.i, b->u.i);
    #endif
    
    		r = make_number ((FP___TYPE)(a->u.i == b->u.i));
    
    	}
    
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static struct val *
    op_gt (struct val *a, struct val *b)
    {
    	struct val *r;
    
    	if (isstring (a) || isstring (b)) {
    		to_string (a);
    		to_string (b);
    
    		r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) > 0));
    
    		(void)to_number(a);
    		(void)to_number(b);
    		r = make_number ((FP___TYPE)(a->u.i > b->u.i));
    
    	}
    
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static struct val *
    op_lt (struct val *a, struct val *b)
    {
    	struct val *r;
    
    	if (isstring (a) || isstring (b)) {
    		to_string (a);
    		to_string (b);
    
    		r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) < 0));
    
    		(void)to_number(a);
    		(void)to_number(b);
    		r = make_number ((FP___TYPE)(a->u.i < b->u.i));
    
    	}
    
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static struct val *
    op_ge (struct val *a, struct val *b)
    {
    	struct val *r;
    
    	if (isstring (a) || isstring (b)) {
    		to_string (a);
    		to_string (b);
    
    		r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) >= 0));
    
    		(void)to_number(a);
    		(void)to_number(b);
    		r = make_number ((FP___TYPE)(a->u.i >= b->u.i));
    
    	}
    
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static struct val *
    op_le (struct val *a, struct val *b)
    {
    	struct val *r;
    
    	if (isstring (a) || isstring (b)) {
    		to_string (a);
    		to_string (b);
    
    		r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) <= 0));
    
    		(void)to_number(a);
    		(void)to_number(b);
    		r = make_number ((FP___TYPE)(a->u.i <= b->u.i));
    
    	}
    
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static struct val *
    op_cond (struct val *a, struct val *b, struct val *c)
    {
    	struct val *r;
    
    	if( isstring(a) )
    	{
    		if( strlen(a->u.s) && strcmp(a->u.s, "\"\"") != 0 && strcmp(a->u.s,"0") != 0 )
    		{
    			free_value(a);
    			free_value(c);
    			r = b;
    		}
    		else
    		{
    			free_value(a);
    			free_value(b);
    			r = c;
    		}
    	}
    	else
    	{
    
    		(void)to_number(a);
    
    		if( a->u.i )
    		{
    			free_value(a);
    			free_value(c);
    			r = b;
    		}
    		else
    		{
    			free_value(a);
    			free_value(b);
    			r = c;
    		}
    	}
    	return r;
    }
    
    static struct val *
    op_ne (struct val *a, struct val *b)
    {
    	struct val *r;
    
    	if (isstring (a) || isstring (b)) {
    		to_string (a);
    		to_string (b);
    
    		r = make_number ((FP___TYPE)(strcoll (a->u.s, b->u.s) != 0));
    
    		(void)to_number(a);
    		(void)to_number(b);
    		r = make_number ((FP___TYPE)(a->u.i != b->u.i));
    
    chk_plus (FP___TYPE a, FP___TYPE b, FP___TYPE r)
    
    {
    	/* sum of two positive numbers must be positive */
    	if (a > 0 && b > 0 && r <= 0)
    		return 1;
    	/* sum of two negative numbers must be negative */
    	if (a < 0 && b < 0 && r >= 0)
    		return 1;
    	/* all other cases are OK */
    	return 0;
    }
    
    static struct val *
    op_plus (struct val *a, struct val *b)
    {
    	struct val *r;
    
    
    	if (!to_number (a)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING,"non-numeric argument\n");
    
    		if (!to_number (b)) {
    
    			return make_number(0);
    
    	} else if (!to_number(b)) {
    
    	r = make_number (a->u.i + b->u.i);
    
    	if (chk_plus (a->u.i, b->u.i, r->u.i)) {
    		ast_log(LOG_WARNING,"overflow\n");
    	}
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static int
    
    chk_minus (FP___TYPE a, FP___TYPE b, FP___TYPE r)
    
    {
    	/* special case subtraction of QUAD_MIN */
    	if (b == QUAD_MIN) {
    		if (a >= 0)
    			return 1;
    		else
    			return 0;
    	}
    	/* this is allowed for b != QUAD_MIN */
    	return chk_plus (a, -b, r);
    }
    
    static struct val *
    op_minus (struct val *a, struct val *b)
    {
    	struct val *r;
    
    
    	if (!to_number (a)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    		if (!to_number (b)) {
    
    			return make_number(0);
    
    			r = make_number(0 - b->u.i);
    
    	} else if (!to_number(b)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    	r = make_number (a->u.i - b->u.i);
    
    	if (chk_minus (a->u.i, b->u.i, r->u.i)) {
    		ast_log(LOG_WARNING, "overflow\n");
    	}
    	free_value (a);
    	free_value (b);
    	return r;
    }
    
    static struct val *
    op_negate (struct val *a)
    {
    	struct val *r;
    
    
    	if (!to_number (a) ) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    		return make_number(0);
    
    	r = make_number (- a->u.i);
    
    	if (chk_minus (0, a->u.i, r->u.i)) {
    		ast_log(LOG_WARNING, "overflow\n");
    	}
    	free_value (a);
    	return r;
    }
    
    static struct val *
    op_compl (struct val *a)
    {
    	int v1 = 1;
    	struct val *r;
    	
    	if( !a )
    	{
    		v1 = 0;
    	}
    	else
    	{
    		switch( a->type )
    		{
    
    		case AST_EXPR_number:
    
    			if( a->u.i == 0 )
    				v1 = 0;
    			break;
    			
    		case AST_EXPR_string:
    			if( a->u.s == 0 )
    				v1 = 0;
    			else
    			{
    				if( a->u.s[0] == 0 )
    					v1 = 0;
    				else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
    					v1 = 0;
    
    				else
    					v1 = atoi(a->u.s);
    
    			}
    			break;
    			
    		case AST_EXPR_numeric_string:
    			if( a->u.s == 0 )
    				v1 = 0;
    			else
    			{
    				if( a->u.s[0] == 0 )
    					v1 = 0;
    				else if (strlen(a->u.s) == 1 && a->u.s[0] == '0' )
    					v1 = 0;
    
    				else
    					v1 = atoi(a->u.s);
    
    	r = make_number (!v1);
    
    chk_times (FP___TYPE a, FP___TYPE b, FP___TYPE r)
    
    {
    	/* special case: first operand is 0, no overflow possible */
    	if (a == 0)
    		return 0;
    	/* cerify that result of division matches second operand */
    	if (r / a != b)
    		return 1;
    	return 0;
    }
    
    static struct val *
    op_times (struct val *a, struct val *b)
    {
    	struct val *r;
    
    
    	if (!to_number (a) || !to_number (b)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    		return(make_number(0));
    
    	r = make_number (a->u.i * b->u.i);
    
    	if (chk_times (a->u.i, b->u.i, r->u.i)) {
    		ast_log(LOG_WARNING, "overflow\n");
    	}
    	free_value (a);
    	free_value (b);
    	return (r);
    }
    
    static int
    
    chk_div (FP___TYPE a, FP___TYPE b)
    
    {
    	/* div by zero has been taken care of before */
    	/* only QUAD_MIN / -1 causes overflow */
    	if (a == QUAD_MIN && b == -1)
    		return 1;
    	/* everything else is OK */
    	return 0;
    }
    
    static struct val *
    op_div (struct val *a, struct val *b)
    {
    	struct val *r;
    
    
    	if (!to_number (a)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    		return make_number(0);
    	} else if (!to_number (b)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    		return make_number(INT_MAX);
    
    	}
    
    	if (b->u.i == 0) {
    		ast_log(LOG_WARNING, "division by zero\n");		
    		free_value(a);
    		free_value(b);
    
    		return make_number(INT_MAX);
    
    	r = make_number (a->u.i / b->u.i);
    
    	if (chk_div (a->u.i, b->u.i)) {
    		ast_log(LOG_WARNING, "overflow\n");
    	}
    	free_value (a);
    	free_value (b);
    	return r;
    }
    	
    static struct val *
    op_rem (struct val *a, struct val *b)
    {
    	struct val *r;
    
    
    	if (!to_number (a) || !to_number (b)) {
    
    		if( !extra_error_message_supplied )
    			ast_log(LOG_WARNING, "non-numeric argument\n");
    
    		return make_number(0);
    
    	}
    
    	if (b->u.i == 0) {
    		ast_log(LOG_WARNING, "div by zero\n");
    		free_value(a);
    		return(b);
    	}
    
    
    	r = make_number (FUNC_FMOD(a->u.i, b->u.i)); /* either fmod or fmodl if FP___TYPE is available */
    
    	/* chk_rem necessary ??? */
    	free_value (a);
    	free_value (b);
    	return r;
    }
    	
    
    static struct val *
    op_colon (struct val *a, struct val *b)
    {
    	regex_t rp;
    	regmatch_t rm[2];
    	char errbuf[256];
    	int eval;
    	struct val *v;
    
    	/* coerce to both arguments to strings */
    	to_string(a);
    	to_string(b);
    	/* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
    	strip_quotes(a);
    	strip_quotes(b);
    	/* compile regular expression */
    	if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
    		regerror (eval, &rp, errbuf, sizeof(errbuf));
    
    		ast_log(LOG_WARNING, "regcomp() error : %s\n", errbuf);
    
    		free_value(a);
    		free_value(b);
    		return make_str("");		
    	}
    
    	/* compare string against pattern */
    	/* remember that patterns are anchored to the beginning of the line */
    	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
    		if (rm[1].rm_so >= 0) {
    			*(a->u.s + rm[1].rm_eo) = '\0';
    			v = make_str (a->u.s + rm[1].rm_so);
    
    		} else {
    
    			v = make_number ((FP___TYPE)(rm[0].rm_eo - rm[0].rm_so));
    
    			v = make_number ((FP___TYPE)0);
    
    		} else {
    			v = make_str ("");
    		}
    	}
    
    	/* free arguments and pattern buffer */
    	free_value (a);
    	free_value (b);
    	regfree (&rp);
    
    	return v;
    }
    	
    
    static struct val *
    op_eqtilde (struct val *a, struct val *b)
    {
    	regex_t rp;
    	regmatch_t rm[2];
    	char errbuf[256];
    	int eval;
    	struct val *v;
    
    	/* coerce to both arguments to strings */
    	to_string(a);
    	to_string(b);
    	/* strip double quotes from both -- they'll screw up the pattern, and the search string starting at ^ */
    	strip_quotes(a);
    	strip_quotes(b);
    	/* compile regular expression */
    	if ((eval = regcomp (&rp, b->u.s, REG_EXTENDED)) != 0) {
    		regerror (eval, &rp, errbuf, sizeof(errbuf));
    
    		ast_log(LOG_WARNING, "regcomp() error : %s\n", errbuf);
    
    		free_value(a);
    		free_value(b);
    		return make_str("");		
    	}
    
    	/* compare string against pattern */
    	/* remember that patterns are anchored to the beginning of the line */
    	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 ) {
    		if (rm[1].rm_so >= 0) {
    			*(a->u.s + rm[1].rm_eo) = '\0';
    			v = make_str (a->u.s + rm[1].rm_so);
    
    		} else {
    
    			v = make_number ((FP___TYPE)(rm[0].rm_eo - rm[0].rm_so));
    
    			v = make_number ((FP___TYPE)0.0);
    
    		} else {
    			v = make_str ("");
    		}
    	}
    
    	/* free arguments and pattern buffer */
    	free_value (a);
    	free_value (b);
    	regfree (&rp);
    
    	return v;
    }
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    static struct val *  /* this is a string concat operator */
    op_tildetilde (struct val *a, struct val *b)
    {
    	struct val *v;
    	char *vs;
    
    	/* coerce to both arguments to strings */
    	to_string(a);
    	to_string(b);
    	/* strip double quotes from both -- */
    	strip_quotes(a);
    	strip_quotes(b);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	vs = malloc(strlen(a->u.s)+strlen(b->u.s)+1);
    
    	if (vs == NULL) {
    		ast_log(LOG_WARNING, "malloc() failed\n");
    
    		free_value(a);
    		free_value(b);
    
    Steve Murphy's avatar
    Steve Murphy committed
    	strcpy(vs,a->u.s);
    	strcat(vs,b->u.s);
    
    	v = make_str(vs);
    
    
    Steve Murphy's avatar
    Steve Murphy committed
    	/* free arguments */
    	free_value(a);
    	free_value(b);
    
    	return v;
    }