1 /*
2 Copyright 2021 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <math_eval.h>
26 #include <compiler.h>
27
28 #define MATH_EVAL_STACK_SIZE 1024
29
30 const char *const math_eval_function_names[] =
31 {
32 "ceil", "floor", "log10", "log2", "log", "sqrt", "sin", "cos", "tan", "asin", "acos", "atan", "abs", "step"
33 };
34
_math_eval_step(double p)35 static double _math_eval_step(double p)
36 {
37 return ((p < 0) ? 0 : 1);
38 }
39
40 typedef double (*MathEvalFunctionType)(double);
41
42 static const MathEvalFunctionType math_eval_functions[] =
43 {
44 ceil, floor, log10, log2, log, sqrt, sin, cos, tan, asin, acos, atan, fabs, _math_eval_step
45 };
46
47
math_eval_push(double n,double * stack,int * stackp)48 double math_eval_push(double n, double *stack, int *stackp)
49 {
50 if (*stackp > MATH_EVAL_STACK_SIZE)
51 {
52 Log(LOG_LEVEL_ERR, "Math evaluation stack size exceeded");
53 return 0;
54 }
55
56 return stack[++(*stackp)]= n;
57 }
58
math_eval_pop(double * stack,int * stackp)59 double math_eval_pop(double *stack, int *stackp)
60 {
61 if (*stackp < 0)
62 {
63 Log(LOG_LEVEL_ERR, "Math evaluation stack could not be popped, internal error!");
64 return 0;
65 }
66
67 return stack[(*stackp)--];
68 }
69
70 #define YYSTYPE double
71 #define YYPARSE yymath_parse
72 #define YYPARSEFROM yymath_parsefrom
73 #define YY_CTX_LOCAL
74 #define YY_PARSE(T) T
75 #define YY_INPUT(ctx, buf, result, max_size) { \
76 result = 0; \
77 if (ctx->input != NULL) \
78 { \
79 /*Log(LOG_LEVEL_ERR, "YYINPUT: %s", ctx->input);*/ \
80 strncpy(buf, ctx->input, max_size); \
81 int n = strlen(ctx->input)+1; \
82 if (n > max_size) n = max_size; \
83 if (n > 0) buf[n - 1]= '\0'; \
84 result = strlen(buf); \
85 ctx->input = NULL; \
86 } \
87 }
88
89 #undef malloc
90 #undef realloc
91 #define malloc xmalloc
92 #define realloc xrealloc
93
94 #define YY_CTX_MEMBERS char *failure; \
95 const char *input; \
96 const char *original_input; \
97 EvalContext *eval_context; \
98 double result; \
99 char fname[50]; \
100 double stack[MATH_EVAL_STACK_SIZE]; \
101 int stackp;
102
103 /* Mark unused functions as such */
104 struct _yycontext;
105 static int yyAccept(struct _yycontext *yy, int tp0) FUNC_UNUSED;
106 static void yyPush(struct _yycontext *yy, char *text, int count) FUNC_UNUSED;
107 static void yyPop(struct _yycontext *yy, char *text, int count) FUNC_UNUSED;
108 static void yySet(struct _yycontext *yy, char *text, int count) FUNC_UNUSED;
109
110 #pragma GCC diagnostic push
111 #pragma GCC diagnostic ignored "-Wunused-parameter"
112
113 #include <math.pc> // Generated from math.peg using 3rdparty/peg-0.1.15
114
115 #pragma GCC diagnostic pop
116
EvaluateMathInfix(EvalContext * ctx,const char * input,char * failure)117 double EvaluateMathInfix(EvalContext *ctx, const char *input, char *failure)
118 {
119 yycontext yyctx;
120 memset(&yyctx, 0, sizeof(yycontext));
121 yyctx.failure = failure;
122 yyctx.original_input = input;
123 yyctx.input = input;
124 yyctx.eval_context = ctx;
125 yyctx.result = 0;
126 yyctx.stackp = -1;
127 yymath_parse(&yyctx);
128 yyrelease(&yyctx);
129 return yyctx.result;
130 }
131
EvaluateMathFunction(const char * f,double p)132 double EvaluateMathFunction(const char *f, double p)
133 {
134 int count = sizeof(math_eval_functions)/sizeof(math_eval_functions[0]);
135
136 for (int i=0; i < count; i++)
137 {
138 if (strcmp(math_eval_function_names[i], f) == 0)
139 {
140 return (*math_eval_functions[i])(p);
141 }
142 }
143
144 return p;
145 }
146