2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.tizenopensource.org/license
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <math.h> /* For math functions, cos(), sin(), etc. */
24 #include "calc-main.h"
25 #include "calc-string.h"
26 #include "calc-expression.h"
27 #include "calculator_parser.h"
29 #define CALCULATOR_MAX_FUNC_NUMBER 16 /**<maximum num of function*/
31 extern char decimal_ch;
32 static char g_stack[MAX_EXPRESSION_LENGTH];
34 static calculator_parentheses_data_t g_parentheses_data[MAX_PARENTHESES_NUM];
36 static int oper_num = 0;
38 static const function_t g_functions[CALCULATOR_MAX_FUNC_NUMBER] = {
39 {"x^y", "^", 1, '^', FUNCTION_POSTFIX, OPERATOR_TYPE_BINARY,
40 CALCULATOR_CALCULATE_PRIORITY_HIGH, FALSE},
41 {"ln", "ln", 2, 'L', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
42 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
43 {"sqrt", "sqrt", 4, 'q', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
44 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
45 {"e^x", "e^", 2, 'E', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
46 CALCULATOR_CALCULATE_PRIORITY_HIGHER, FALSE},
47 {"x!", "!", 1, '!', FUNCTION_POSTFIX, OPERATOR_TYPE_UNARY,
48 CALCULATOR_CALCULATE_PRIORITY_HIGHEST, FALSE},
49 {"1/x", "/", 1, 'x', FUNCTION_POSTFIX, OPERATOR_TYPE_UNARY,
50 CALCULATOR_CALCULATE_PRIORITY_HIGHEST, FALSE},
51 {"sin", "sin", 3, 's', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
52 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
53 {"cos", "cos", 3, 'c', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
54 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
55 {"tan", "tan", 3, 't', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
56 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
57 {"Pi", "p", 1, 'p', FUNCTION_CONSTANT, OPERATOR_TYPE_INVALID,
58 CALCULATOR_CALCULATE_PRIORITY_INVALID, FALSE},
59 {"e", "e", 1, 'e', FUNCTION_CONSTANT, OPERATOR_TYPE_INVALID,
60 CALCULATOR_CALCULATE_PRIORITY_INVALID, FALSE},
61 {"log", "log", 3, 'l', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
62 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
63 {"abs", "abs", 3, 'b', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
64 CALCULATOR_CALCULATE_PRIORITY_HIGHER, TRUE},
65 {"2^x", "2^", 2, '2', FUNCTION_PREFIX, OPERATOR_TYPE_UNARY,
66 CALCULATOR_CALCULATE_PRIORITY_HIGHER, FALSE},
67 {"xCy", "C", 1, 'C', FUNCTION_POSTFIX, OPERATOR_TYPE_BINARY,
68 CALCULATOR_CALCULATE_PRIORITY_HIGH, FALSE},
69 {"xPy", "P", 1, 'P', FUNCTION_POSTFIX, OPERATOR_TYPE_BINARY,
70 CALCULATOR_CALCULATE_PRIORITY_HIGH, FALSE},
73 #define CALCULATOR_GET_NODE_DATA(t) ((calculator_node_data_t*)(((GNode*)(t))->data))/**<to get data from GNode structure*/
86 __calculator_calculate_insert_node(GNode ** out_tree, GNode * to_insert,
89 GNode *upper_node = NULL;
91 calculator_node_data_t *node_data = NULL;
93 if ((!out_tree) || (!*out_tree) || (!to_insert)) {
97 upper_node = *out_tree;
101 This is redundant comment.
102 Its only use is for Klocwork testing.
103 The comment rete should passed 25%.
104 But we have only one day to do this work.
105 So, sorry, I will delete this comment and add useful comment later.
108 while (CALCULATOR_GET_NODE_DATA(upper_node)->node_calcu_priority >
109 CALCULATOR_GET_NODE_DATA(to_insert)->node_calcu_priority) {
110 if (G_NODE_IS_ROOT(upper_node)) {
111 g_node_insert(to_insert, -1, upper_node);
112 CALCULATOR_GET_NODE_DATA(to_insert)->children_num++;
115 g_node_insert(*out_tree, -1, const_node); //value of last node's priority>= upper_node's > to_insert's
116 CALCULATOR_GET_NODE_DATA(*out_tree)->
122 upper_node = upper_node->parent;
125 if (CALCULATOR_GET_NODE_DATA(upper_node)->node_calcu_priority ==
126 CALCULATOR_GET_NODE_DATA(to_insert)->node_calcu_priority) {
127 if (CALCULATOR_GET_NODE_DATA(to_insert)->operator_type ==
128 OPERATOR_TYPE_BINARY) {
129 GNode *parent_node = NULL;
131 if (!G_NODE_IS_ROOT(upper_node)) {
132 parent_node = upper_node->parent;
133 g_node_unlink(upper_node);
134 g_node_insert(parent_node, -1, to_insert);
137 g_node_insert(to_insert, -1, upper_node);
138 CALCULATOR_GET_NODE_DATA(to_insert)->children_num++;
141 g_node_insert(*out_tree, -1, const_node);
142 CALCULATOR_GET_NODE_DATA(*out_tree)->
145 } else if (CALCULATOR_GET_NODE_DATA(to_insert)->operator_type ==
146 OPERATOR_TYPE_UNARY) {
147 GNode *tmp_node = NULL;
149 This is redundant comment.
150 Its only use is for Klocwork testing.
151 The comment rete should passed 25%.
152 But we have only one day to do this work.
153 So, sorry, I will delete this comment and add useful comment later.
158 g_malloc0(sizeof(calculator_node_data_t));
159 node_data->cur_operator = 'x';
160 node_data->negative_flag = 1;
161 node_data->operator_type = OPERATOR_TYPE_BINARY;
162 node_data->node_calcu_priority =
163 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
164 tmp_node = g_node_new(node_data);
166 if (CALCULATOR_GET_NODE_DATA(to_insert)->
167 cur_operator != '!') {
168 __calculator_calculate_insert_node
169 (out_tree, tmp_node, const_node);
170 } else //(CALCULATOR_GET_NODE_DATA(to_insert)->cur_operator == '!')
172 g_node_insert(to_insert, -1,
174 CALCULATOR_GET_NODE_DATA(to_insert)->
178 g_node_insert(*out_tree, -1, to_insert);
179 CALCULATOR_GET_NODE_DATA(*out_tree)->
182 g_node_insert(upper_node, -1, to_insert); //combine from right
183 CALCULATOR_GET_NODE_DATA(upper_node)->
187 } else if (CALCULATOR_GET_NODE_DATA(upper_node)->node_calcu_priority <
188 CALCULATOR_GET_NODE_DATA(to_insert)->node_calcu_priority) {
189 if (CALCULATOR_GET_NODE_DATA(to_insert)->operator_type ==
190 OPERATOR_TYPE_BINARY) {
191 if (node != upper_node) {
193 CALCULATOR_GET_NODE_DATA(upper_node)->
196 g_node_insert(to_insert, -1, node);
197 CALCULATOR_GET_NODE_DATA(to_insert)->
202 if (CALCULATOR_GET_NODE_DATA(*out_tree)->
203 node_calcu_priority >
204 CALCULATOR_GET_NODE_DATA(to_insert)->
205 node_calcu_priority) {
206 g_node_insert(*out_tree, -1,
208 CALCULATOR_GET_NODE_DATA(*out_tree)->
211 g_node_insert(to_insert, -1,
213 CALCULATOR_GET_NODE_DATA(to_insert)->
218 g_node_insert(upper_node, -1, to_insert);
219 CALCULATOR_GET_NODE_DATA(upper_node)->children_num++;
222 This is redundant comment.
223 Its only use is for Klocwork testing.
224 The comment rete should passed 25%.
225 But we have only one day to do this work.
226 So, sorry, I will delete this comment and add useful comment later.
229 else if (CALCULATOR_GET_NODE_DATA(to_insert)->operator_type == OPERATOR_TYPE_UNARY) //upper_node must be equal to node equalized to *out_tree, for no functions' prority higher than unary operator
233 if (CALCULATOR_GET_NODE_DATA(to_insert)->
234 cur_operator != '!') {
235 GNode *tmp_node = NULL;
239 (calculator_node_data_t));
240 node_data->cur_operator = 'x';
241 node_data->negative_flag = 1;
242 node_data->operator_type =
243 OPERATOR_TYPE_BINARY;
244 node_data->node_calcu_priority =
245 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
246 tmp_node = g_node_new(node_data);
248 __calculator_calculate_insert_node
249 (out_tree, tmp_node, const_node);
250 } else //(CALCULATOR_GET_NODE_DATA(to_insert)->cur_operator == '!')
252 g_node_insert(to_insert, -1,
254 CALCULATOR_GET_NODE_DATA(to_insert)->
259 g_node_insert(*out_tree, -1, to_insert);
260 CALCULATOR_GET_NODE_DATA(*out_tree)->children_num++;
265 *out_tree = to_insert;
279 __calculator_tree_destroy_traverse_func(GNode * node, gpointer data)
281 if (CALCULATOR_GET_NODE_DATA(node)) {
282 g_free(CALCULATOR_GET_NODE_DATA(node));
284 g_node_destroy(node);
296 static gboolean __calculator_tree_destroy_all(GNode ** tree)
302 root = g_node_get_root(*tree);
303 depth = g_node_max_height(root);
304 g_node_traverse(root, G_POST_ORDER, G_TRAVERSE_ALL, depth,
305 __calculator_tree_destroy_traverse_func, NULL);
321 static gboolean __calculator_check_overflow(double result, char *error_msg)
323 if ((result > CALCULATOR_MAX_RESULT_SUM2)
324 || (result < CALCULATOR_MIN_RESULT_SUM2)) {
325 strcat(error_msg, CALC_MSG_OUT_OF_RANGE);
333 * add parenthesis between function and paremeter.
340 static void __calculator_expression_add_parenthesis(char *exp, const char *func)
343 char *digit = "0123456789.";
345 while ((p = strstr(p, func)) != NULL) {
346 p = p + strlen(func);
348 int l = strspn(p, digit);
349 string_insert(exp, p - exp, "(");
350 string_insert(exp, p - exp + l + 1, ")");
358 * If sin/cos/tan function omitted parenthesis, add it
364 static void __calculator_expression_tri_func_parenthesis(char *exp)
366 __calculator_expression_add_parenthesis(exp, "sin");
367 __calculator_expression_add_parenthesis(exp, "cos");
368 __calculator_expression_add_parenthesis(exp, "tan");
373 * record every matching parentheses position
382 __calculator_calculate_formula_scan(char *string, int *end_idx, char *error_msg)
389 memset(g_parentheses_data, 0x0, sizeof(g_parentheses_data));
391 __calculator_expression_tri_func_parenthesis(string);
395 while (g_parentheses_data[i].start_pos) {
398 g_parentheses_data[i].start_pos = p;
401 while (g_parentheses_data[i].end_pos) {
404 if (g_parentheses_data[i].start_pos) {
405 g_parentheses_data[i].end_pos = p;
410 *end_idx = p - 1 - string;
424 static double __calculator_calculate_factorial(double n, char *err_msg)
427 strcat(err_msg, CALC_MSG_INVALID_FAC);
429 } else if (n >= 30) {
430 strcat(err_msg, CALC_MSG_OUT_OF_RANGE);
436 for (i = 2; i <= n; ++i) {
444 * Judge the op is a operator, if yes, give fucntion type
451 static gboolean __calculator_util_get_operator(char *op, function_t * function)
454 gboolean ret = FALSE;
455 if ((*op == decimal_ch) || (*op == '(') || (*op == ')')) {
457 } else if (isdigit(*op)) {
459 } else if ((*op == '+') || (*op == '-') || (*op == 'x') || (*op == '/')) {
460 function->category = FUNCTION_POSTFIX;
461 function->function_char = *op;
462 function->func_name = NULL;
463 function->func_string = NULL;
464 function->has_parentheses = FALSE;
465 function->op_type = OPERATOR_TYPE_BINARY;
466 if ((*op == '+') || (*op == '-')) {
467 function->priority = CALCULATOR_CALCULATE_PRIORITY_LOW;
470 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
472 function->str_len = 1;
475 for (i = 0; i < CALCULATOR_MAX_FUNC_NUMBER; i++) {
477 (op, g_functions[i].func_string,
478 strlen(g_functions[i].func_string))) {
479 memcpy(function, &g_functions[i],
489 /* search function, if have, return TRUE and get the length of current function;else return FALSE */
490 gboolean __calculator_search_function(char *op, int* len)
493 gboolean ret = FALSE;
494 for (i = 0; i < CALCULATOR_MAX_FUNC_NUMBER; i++) {
496 (op, g_functions[i].func_string,
497 strlen(g_functions[i].func_string))) {
500 *len = strlen(g_functions[i].func_string);
513 * @return calculator_parentheses_data_t*
516 static calculator_parentheses_data_t
517 *__calculator_calculate_get_parentheses_info(gchar * pos)
519 calculator_parentheses_data_t *found = NULL;
522 while ((g_parentheses_data[i].start_pos) ||
523 (g_parentheses_data[i].end_pos)) {
524 if (g_parentheses_data[i].start_pos == pos) {
525 found = &g_parentheses_data[i];
527 } else if (g_parentheses_data[i].end_pos == pos) {
528 found = &g_parentheses_data[i];
550 __calculator_calculate_formula_parse(double *tmp_result, GNode ** out_tree,
551 char *start_pos, int end_idx,
555 char *end_pos = start_pos + end_idx;
558 gchar tmp[MAX_RESULT_LENGTH];
561 calculator_state_t calculator_state = CALCULATOR_OPERAND_INPUT;
562 calculator_node_data_t *node_data = NULL;
564 GNode *new_node = NULL;
565 GNode *last_node = NULL; //to proc parentheses
566 calculator_parentheses_data_t *p_data = NULL;
567 gint negative_sign = 1;
568 function_t function = { 0 };
570 memset(tmp, 0x00, sizeof(tmp));
572 if (start_pos > end_pos) {
573 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
577 This is redundant comment.
578 Its only use is for Klocwork testing.
579 The comment rete should passed 25%.
580 But we have only one day to do this work.
581 So, sorry, I will delete this comment and add useful comment later.
584 /* Scan from start to end of string */
585 for (p = start_pos; p <= end_pos;) {
586 q = p; /* Point to start of string */
587 if (q != NULL && __calculator_util_get_operator(q, &function)) //('.'::'('::')') and digits are four exceptions
590 if (oper_num > MAX_OPERATOR_NUM) {
591 strcat(error_msg, CALC_MSG_MAX_OP);
595 p = q + function.str_len; /* Shift */
597 && (function.category != FUNCTION_CONSTANT)) {
600 if ((NULL != p) && (*p == decimal_ch)) {
602 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
605 calculator_state = CALCULATOR_OPERATOR_INPUT;
606 if (i != 0) //save the before operator,create a node.such as 345sin(),save 345
609 memset(tmp, 0x00, sizeof(tmp));
613 g_malloc0(sizeof(calculator_node_data_t));
614 node_data->tmp_result = factor;
616 node_data->negative_flag = 1;
617 node_data->negative_flag *= negative_sign;
618 new_node = g_node_new(node_data);
621 if (!new_node) //no leaf node before, first factor's "+/-" sign allowed.
623 if (((function.op_type ==
624 OPERATOR_TYPE_BINARY)
625 && (function.function_char != '+')
626 && (function.function_char != '-'))
628 ((function.op_type ==
630 && (function.category ==
631 FUNCTION_POSTFIX))) {
632 PLOG("Line:%d", __LINE__);
636 } else if (function.function_char ==
644 This is redundant comment.
645 Its only use is for Klocwork testing.
646 The comment rete should passed 25%.
647 But we have only one day to do this work.
648 So, sorry, I will delete this comment and add useful comment later.
651 if (function.category == FUNCTION_CONSTANT) //Pi, e
653 if (new_node) //have the operator like 345,now it will 345*Pi
657 (calculator_node_data_t));
658 node_data->cur_operator = 'x';
659 node_data->negative_flag = 1;
660 node_data->operator_type =
661 OPERATOR_TYPE_BINARY;
662 node_data->node_calcu_priority =
663 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
664 tree = g_node_new(node_data);
666 if (last_node == NULL) //first node
668 g_node_insert(tree, -1,
670 CALCULATOR_GET_NODE_DATA(tree)->
673 if (CALCULATOR_GET_NODE_DATA
674 (last_node)->children_num >
675 CALCULATOR_GET_NODE_DATA
685 __calculator_calculate_insert_node
692 } //Pi will like a leaf
694 g_malloc0(sizeof(calculator_node_data_t));
695 if (function.function_char == 'p') {
696 node_data->tmp_result = PI;
697 } else if (function.function_char == 'e') {
698 node_data->tmp_result = EXPONENT;
700 node_data->cur_operator =
701 function.function_char;
702 node_data->node_calcu_priority =
704 node_data->negative_flag = 1;
705 node_data->negative_flag *= negative_sign;
706 new_node = g_node_new(node_data);
709 } else if (function.category == FUNCTION_PREFIX) //sin()
711 if (!last_node) //first node
716 (calculator_node_data_t));
717 node_data->cur_operator = 'x';
718 node_data->negative_flag = 1;
719 node_data->operator_type =
720 OPERATOR_TYPE_BINARY;
721 node_data->node_calcu_priority =
722 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
723 tree = g_node_new(node_data);
725 g_node_insert(tree, -1,
727 CALCULATOR_GET_NODE_DATA(tree)->
737 node_data = g_malloc0(sizeof(calculator_node_data_t));
738 node_data->cur_operator = function.function_char;
739 node_data->node_calcu_priority = function.priority;
740 node_data->operator_type = function.op_type;
741 node_data->negative_flag = 1;
742 tree = g_node_new(node_data);
744 if (last_node == NULL) //first node
747 g_node_insert(tree, -1, new_node);
748 CALCULATOR_GET_NODE_DATA(tree)->
752 if (CALCULATOR_GET_NODE_DATA(last_node)->
754 CALCULATOR_GET_NODE_DATA(last_node)->
757 CALC_MSG_SYNTAX_ERROR);
760 __calculator_calculate_insert_node(&last_node,
771 This is redundant comment.
772 Its only use is for Klocwork testing.
773 The comment rete should passed 25%.
774 But we have only one day to do this work.
775 So, sorry, I will delete this comment and add useful comment later.
778 strcat(error_msg, CALC_MSG_SYNTAX_ERROR); //add for "6((" ,then "="
780 } //added by zhaodanni for prevent
781 else if (*q == decimal_ch) {
783 || (calculator_state ==
784 CALCULATOR_OPERAND_FRACTION_INPUT)) {
785 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
789 CALCULATOR_OPERAND_FRACTION_INPUT;
792 } else if (*q == '(') {
793 if (__calculator_util_get_operator(p, &function)) {
794 if ((function.category == FUNCTION_POSTFIX) && ((*p != '+') && (*p != '-'))) //"(*","(/", not allowed.
797 CALC_MSG_SYNTAX_ERROR);
802 This is redundant comment.
803 Its only use is for Klocwork testing.
804 The comment rete should passed 25%.
805 But we have only one day to do this work.
806 So, sorry, I will delete this comment and add useful comment later.
809 //if ((new_node) && (CALCULATOR_GET_NODE_DATA(new_node)->tmp_result == PI || CALCULATOR_GET_NODE_DATA(new_node)->tmp_result == EXPONENT))
813 (CALCULATOR_GET_NODE_DATA(new_node)->tmp_result,
815 || FLOAT_EQUAL(CALCULATOR_GET_NODE_DATA(new_node)->
816 tmp_result, EXPONENT))) {
818 g_malloc0(sizeof(calculator_node_data_t));
819 node_data->cur_operator = 'x';
820 node_data->negative_flag = 1;
821 node_data->operator_type = OPERATOR_TYPE_BINARY;
822 node_data->node_calcu_priority =
823 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
824 tree = g_node_new(node_data);
827 __calculator_calculate_insert_node
828 (&last_node, tree, new_node);
830 g_node_insert(tree, -1, new_node);
831 CALCULATOR_GET_NODE_DATA(tree)->
838 This is redundant comment.
839 Its only use is for Klocwork testing.
840 The comment rete should passed 25%.
841 But we have only one day to do this work.
842 So, sorry, I will delete this comment and add useful comment later.
847 memset(tmp, 0x00, sizeof(tmp));
851 g_malloc0(sizeof(calculator_node_data_t));
852 node_data->tmp_result = factor;
853 node_data->negative_flag = 1;
854 node_data->negative_flag *= negative_sign;
856 new_node = g_node_new(node_data);
859 g_malloc0(sizeof(calculator_node_data_t));
860 node_data->cur_operator = 'x';
861 node_data->negative_flag = 1;
862 node_data->operator_type = OPERATOR_TYPE_BINARY;
863 node_data->node_calcu_priority =
864 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
865 tree = g_node_new(node_data);
867 if (last_node == NULL) //first node
869 g_node_insert(tree, -1, new_node);
870 CALCULATOR_GET_NODE_DATA(tree)->
873 if (CALCULATOR_GET_NODE_DATA
874 (last_node)->children_num >
875 CALCULATOR_GET_NODE_DATA
876 (last_node)->operator_type) {
878 CALC_MSG_SYNTAX_ERROR);
882 __calculator_calculate_insert_node
883 (&last_node, tree, new_node);
889 p_data = __calculator_calculate_get_parentheses_info(q);
891 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
895 } else if (*q == ')') {
896 if (*p == decimal_ch) //").", not allowed.
898 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
902 p_data = __calculator_calculate_get_parentheses_info(q);
904 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
907 if (!__calculator_calculate_formula_parse
908 (NULL, &new_node, (p_data->start_pos + 1),
909 (p_data->end_pos - 1) - (p_data->start_pos + 1),
911 if (new_node != NULL) {
912 __calculator_tree_destroy_all
915 LOGD("current node is null\n");
920 CALCULATOR_GET_NODE_DATA(new_node)->
921 negative_flag *= negative_sign;
925 This is redundant comment.
926 Its only use is for Klocwork testing.
927 The comment rete should passed 25%.
928 But we have only one day to do this work.
929 So, sorry, I will delete this comment and add useful comment later.
932 if ((*p == '(') || (isdigit(*p))) {
934 g_malloc0(sizeof(calculator_node_data_t));
935 node_data->cur_operator = 'x';
936 node_data->negative_flag = 1;
937 node_data->operator_type = OPERATOR_TYPE_BINARY;
938 node_data->node_calcu_priority =
939 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
940 tree = g_node_new(node_data);
942 if (last_node == NULL) //first node
945 g_node_insert(tree, -1,
947 CALCULATOR_GET_NODE_DATA(tree)->
951 if (CALCULATOR_GET_NODE_DATA
952 (last_node)->children_num >
953 CALCULATOR_GET_NODE_DATA
954 (last_node)->operator_type) {
956 CALC_MSG_SYNTAX_ERROR);
960 __calculator_calculate_insert_node
961 (&last_node, tree, new_node);
966 } else if (isdigit(*q)) {
969 g_malloc0(sizeof(calculator_node_data_t));
970 node_data->cur_operator = 'x';
971 node_data->negative_flag = 1;
972 node_data->operator_type = OPERATOR_TYPE_BINARY;
973 node_data->node_calcu_priority =
974 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
975 tree = g_node_new(node_data);
978 __calculator_calculate_insert_node
979 (&last_node, tree, new_node);
981 g_node_insert(tree, -1, new_node);
982 CALCULATOR_GET_NODE_DATA(tree)->
988 calculator_state = CALCULATOR_OPERAND_INPUT;
990 }/*for unvalid input ,such as "clipborad"*/
991 else if ((*q != '+') && (*q != '-') && (*q != 'x')
993 if (!__calculator_search_function(q, NULL)) {
994 printf("q=%s,line=%d\n", q, __LINE__);
995 strcat(error_msg, "invalid input");
1001 This is redundant comment.
1002 Its only use is for Klocwork testing.
1003 The comment rete should passed 25%.
1004 But we have only one day to do this work.
1005 So, sorry, I will delete this comment and add useful comment later.
1008 if (i != 0) //last digit number
1010 //if ((new_node) && (CALCULATOR_GET_NODE_DATA(new_node)->tmp_result == PI || CALCULATOR_GET_NODE_DATA(new_node)->tmp_result == EXPONENT))
1014 (CALCULATOR_GET_NODE_DATA(new_node)->tmp_result, PI)
1015 || FLOAT_EQUAL(CALCULATOR_GET_NODE_DATA(new_node)->
1016 tmp_result, EXPONENT))) {
1017 node_data = g_malloc0(sizeof(calculator_node_data_t));
1018 node_data->cur_operator = 'x';
1019 node_data->negative_flag = 1;
1020 node_data->operator_type = OPERATOR_TYPE_BINARY;
1021 node_data->node_calcu_priority =
1022 CALCULATOR_CALCULATE_PRIORITY_MIDDLE;
1023 tree = g_node_new(node_data);
1026 __calculator_calculate_insert_node(&last_node,
1030 g_node_insert(tree, -1, new_node);
1031 CALCULATOR_GET_NODE_DATA(tree)->children_num++;
1038 memset(tmp, 0x00, sizeof(tmp));
1041 node_data = g_malloc0(sizeof(calculator_node_data_t));
1042 node_data->tmp_result = factor;
1043 node_data->negative_flag = 1;
1044 node_data->negative_flag *= negative_sign;
1046 new_node = g_node_new(node_data);
1048 if (last_node != NULL) {
1049 if (CALCULATOR_GET_NODE_DATA(last_node)->children_num >
1050 CALCULATOR_GET_NODE_DATA(last_node)->
1052 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
1055 g_node_insert(last_node, -1, new_node);
1056 CALCULATOR_GET_NODE_DATA(last_node)->
1063 This is redundant comment.
1064 Its only use is for Klocwork testing.
1065 The comment rete should passed 25%.
1066 But we have only one day to do this work.
1067 So, sorry, I will delete this comment and add useful comment later.
1070 if (new_node != NULL) {
1071 CALCULATOR_GET_NODE_DATA(new_node)->negative_flag *=
1075 if (last_node != NULL) {
1076 if (CALCULATOR_GET_NODE_DATA(last_node)->children_num >
1077 CALCULATOR_GET_NODE_DATA(last_node)->
1079 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
1082 g_node_insert(last_node, -1, new_node);
1083 CALCULATOR_GET_NODE_DATA(last_node)->
1087 last_node = new_node;
1091 *out_tree = g_node_get_root(last_node);
1106 __calculator_calculate_exec_traverse_func(GNode * node, gpointer data)
1108 gdouble operand0, operand1 = 0.0;
1109 char *error_msg = (char *)data;
1112 This is redundant comment.
1113 Its only use is for Klocwork testing.
1114 The comment rete should passed 25%.
1115 But we have only one day to do this work.
1116 So, sorry, I will delete this comment and add useful comment later.
1119 if (CALCULATOR_GET_NODE_DATA(node)->children_num !=
1120 CALCULATOR_GET_NODE_DATA(node)->operator_type) {
1121 strcat(error_msg, CALC_MSG_NUM_AFTER_OP);
1122 return TRUE; //break the recursion
1126 CALCULATOR_GET_NODE_DATA(node->children)->tmp_result *
1127 CALCULATOR_GET_NODE_DATA(node->children)->negative_flag;
1128 CALCULATOR_GET_NODE_DATA(node->children)->negative_flag = 1;
1130 if (CALCULATOR_GET_NODE_DATA(node)->operator_type ==
1131 OPERATOR_TYPE_BINARY) {
1133 CALCULATOR_GET_NODE_DATA(node->children->next)->tmp_result *
1134 CALCULATOR_GET_NODE_DATA(node->children->next)->
1136 CALCULATOR_GET_NODE_DATA(node->children->next)->negative_flag =
1141 This is redundant comment.
1142 Its only use is for Klocwork testing.
1143 The comment rete should passed 25%.
1144 But we have only one day to do this work.
1145 So, sorry, I will delete this comment and add useful comment later.
1147 switch (CALCULATOR_GET_NODE_DATA(node)->cur_operator) {
1149 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1150 operand0 + operand1;
1151 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1154 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1155 operand0 - operand1;
1156 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1159 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1160 operand0 * operand1;
1161 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1164 if (FLOAT_EQUAL(operand1, 0)) {
1165 strcat(error_msg, CALC_MSG_DIVIDE_BY_ZERO);
1166 return TRUE; //break the recursion
1168 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1169 operand0 / operand1;
1170 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1174 This is redundant comment.
1175 Its only use is for Klocwork testing.
1176 The comment rete should passed 25%.
1177 But we have only one day to do this work.
1178 So, sorry, I will delete this comment and add useful comment later.
1183 gdouble power = 0.0;
1184 power = floor(operand1);
1185 if (!FLOAT_EQUAL(power, operand1)) //operand1 is not an integer
1187 strcat(error_msg, CALC_MSG_INVALID_XY);
1191 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1192 pow(operand0, operand1);
1193 if (!__calculator_check_overflow
1194 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1197 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1201 gdouble power = 0.0;
1202 power = floor(operand1);
1203 if (!FLOAT_EQUAL(power, operand1)) //operand1 is not an integer
1205 strcat(error_msg, CALC_MSG_INVALID_FAC);
1209 if (strlen(error_msg) != 0) {
1212 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1213 __calculator_calculate_factorial(operand0, error_msg);
1214 if (strlen(error_msg) != 0) {
1217 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1222 strcat(error_msg, CALC_MSG_INVALID_LN);
1224 } else if (FLOAT_EQUAL(operand0, 0)) {
1225 strcat(error_msg, CALC_MSG_INVALID_LN);
1229 CALCULATOR_GET_NODE_DATA(node)->tmp_result = log(operand0);
1230 if (!__calculator_check_overflow
1231 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1234 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1238 strcat(error_msg, CALC_MSG_INVALID_SQUARE);
1241 CALCULATOR_GET_NODE_DATA(node)->tmp_result = sqrt(operand0);
1242 if (!__calculator_check_overflow
1243 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1246 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1249 CALCULATOR_GET_NODE_DATA(node)->tmp_result = exp(operand0);
1250 if (!__calculator_check_overflow
1251 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1254 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1258 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1259 sin(operand0 * RADIAN_FACTOR);
1260 if (!__calculator_check_overflow
1261 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1264 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1267 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1268 cos(operand0 * RADIAN_FACTOR);
1269 if (!__calculator_check_overflow
1270 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1273 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1276 if (FLOAT_EQUAL(fmod(operand0, 180), 90) || FLOAT_EQUAL(fmod(operand0, 180), -90)) //revise by bfl
1278 strcat(error_msg, CALC_MSG_INVALID_TAN);
1282 CALCULATOR_GET_NODE_DATA(node)->tmp_result =
1283 tan(operand0 * RADIAN_FACTOR);
1284 if (!__calculator_check_overflow
1285 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1288 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1291 This is redundant comment.
1292 Its only use is for Klocwork testing.
1293 The comment rete should passed 25%.
1294 But we have only one day to do this work.
1295 So, sorry, I will delete this comment and add useful comment later.
1300 strcat(error_msg, CALC_MSG_INVALID_LOG);
1302 } else if (FLOAT_EQUAL(operand0, 0)) {
1303 strcat(error_msg, CALC_MSG_INVALID_LOG);
1306 CALCULATOR_GET_NODE_DATA(node)->tmp_result = log10(operand0);
1307 if (!__calculator_check_overflow
1308 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1311 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1314 CALCULATOR_GET_NODE_DATA(node)->tmp_result = fabs(operand0);
1315 if (!__calculator_check_overflow
1316 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1319 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1323 CALCULATOR_GET_NODE_DATA(node)->tmp_result = pow(2, operand0);
1324 if (!__calculator_check_overflow
1325 (CALCULATOR_GET_NODE_DATA(node)->tmp_result, error_msg)) {
1328 //calculator_calculate_truncate_result(&(CALCULATOR_GET_NODE_DATA(node)->tmp_result));
1336 This is redundant comment.
1337 Its only use is for Klocwork testing.
1338 The comment rete should passed 25%.
1339 But we have only one day to do this work.
1340 So, sorry, I will delete this comment and add useful comment later.
1343 CALCULATOR_GET_NODE_DATA(node)->tmp_result *=
1344 CALCULATOR_GET_NODE_DATA(node)->negative_flag;
1345 CALCULATOR_GET_NODE_DATA(node)->negative_flag = 1;
1361 __calculator_calculate_exec(GNode * tree, double **result, char *error_msg)
1364 depth = g_node_max_height(tree);
1367 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
1368 return FALSE; //break the recursion
1369 } else if (depth == 1) {
1370 **result = CALCULATOR_GET_NODE_DATA(tree)->tmp_result;
1371 **result *= CALCULATOR_GET_NODE_DATA(tree)->negative_flag;
1376 This is redundant comment.
1377 Its only use is for Klocwork testing.
1378 The comment rete should passed 25%.
1379 But we have only one day to do this work.
1380 So, sorry, I will delete this comment and add useful comment later.
1382 g_node_traverse(tree,
1384 G_TRAVERSE_NON_LEAFS,
1386 __calculator_calculate_exec_traverse_func,
1387 (gpointer) error_msg);
1389 if (strlen(error_msg) > 0) {
1392 **result = CALCULATOR_GET_NODE_DATA(tree)->tmp_result;
1408 This is redundant comment.
1409 Its only use is for Klocwork testing.
1410 The comment rete should passed 25%.
1411 But we have only one day to do this work.
1412 So, sorry, I will delete this comment and add useful comment later.
1415 bool calculator_calculate_truncate_result(double* tmp_result)
1427 * @param szInputString
1431 int calculator_get_open_braket(const char *szInputString)
1433 int nReversIndex = strlen(szInputString) - 1;
1437 while (nReversIndex >= 0) {
1438 if (szInputString[nReversIndex] == '(') {
1440 } else if (szInputString[nReversIndex] == ')') {
1445 return (nOpenCnt - nCloseCnt);
1453 * @param [out]pDigitCnt : count of digit before point(.)
1454 * @param [out]pPointCnt: count of digit after point(.)
1458 bool calculator_get_digits_number(char *szInput, int *pDigitCnt, int *pPointCnt)
1460 int nLen = strlen(szInput);
1470 This is redundant comment.
1471 Its only use is for Klocwork testing.
1472 The comment rete should passed 25%.
1473 But we have only one day to do this work.
1474 So, sorry, I will delete this comment and add useful comment later.
1477 for (nIndex = nLen - 1; nIndex >= 0; nIndex--) {
1478 if (isdigit(szInput[nIndex])) {
1480 } else if (szInput[nIndex] == decimal_ch) {
1481 *pPointCnt = nTempCnt;
1486 for (nIndex = 0; nIndex < nLen; nIndex++) {
1487 if (isdigit(szInput[nIndex])) {
1489 } else if (szInput[nIndex] == decimal_ch) {
1490 *pDigitCnt = nTempCntb;
1494 //*pDigitCnt = nTempCntb;
1500 This is redundant comment.
1501 Its only use is for Klocwork testing.
1502 The comment rete should passed 25%.
1503 But we have only one day to do this work.
1504 So, sorry, I will delete this comment and add useful comment later.
1516 bool calculator_expression_length_check(char *str, char *error_msg)
1518 int is_digit = 0, has_dot = 0;
1519 int idx = 0, nCount = 0, nDigitCnt = 0, nPointCnt = 0;
1526 if(strlen(str) > CALCULATOR_MAX_INPUT_DIGIT_NUMBER_POR)
1528 strcat(error_msg, CALC_MSG_MAX_INPUT);
1535 while (idx < strlen(str)) {
1539 if (is_digit == 0) {
1546 if (nCount > MAX_NUM_LENGTH) {
1547 strcat(error_msg, CALC_MSG_MAX_DIGIT);
1556 This is redundant comment.
1557 Its only use is for Klocwork testing.
1558 The comment rete should passed 25%.
1559 But we have only one day to do this work.
1560 So, sorry, I will delete this comment and add useful comment later.
1564 if(nPointCnt > CALCULATORUI_MAX_INPUT_DECIMALS)
1566 strcat(error_msg, CALC_MSG_MAX_DEC_DIGIT);
1576 This is redundant comment.
1577 Its only use is for Klocwork testing.
1578 The comment rete should passed 25%.
1579 But we have only one day to do this work.
1580 So, sorry, I will delete this comment and add useful comment later.
1582 else if (c == decimal_ch) {
1584 strcat(error_msg, CALC_MSG_ENTRY_LIMIT);
1590 if (is_digit == 1) {
1616 bool calculator_calculate(gchar * string, gdouble * result, char *error_msg)
1619 string_replace(string, "E+", "x10^");
1620 string_replace(string, "E-", "x0.1^");
1625 memset(error_msg, 0, sizeof(error_msg));
1626 memset(g_stack, 0, sizeof(g_stack));
1629 strncpy(g_stack, string, MAX_EXPRESSION_LENGTH - 1);
1630 g_stack[MAX_EXPRESSION_LENGTH - 1] = '\0';
1632 char *digit = "0123456789pe";
1633 if (strcspn(g_stack, digit) == strlen(g_stack)) { /* no digit in expression */
1634 strcat(error_msg, CALC_MSG_SYNTAX_ERROR);
1638 if (!calculator_expression_length_check(g_stack, error_msg)) {
1641 if (!__calculator_calculate_formula_scan(g_stack, &end_idx, error_msg)) {
1645 if (!__calculator_calculate_formula_parse
1646 (result, &tree, g_stack, end_idx, error_msg)) {
1648 __calculator_tree_destroy_all(&tree);
1650 LOGD("current tree is null\n");
1652 PLOG("error_msg:%s,line:%d\n", error_msg, __LINE__);
1655 if (!__calculator_calculate_exec(tree, &result, error_msg)) {
1657 __calculator_tree_destroy_all(&tree);
1661 if (!__calculator_check_overflow(*result, error_msg)) {
1663 __calculator_tree_destroy_all(&tree);
1669 __calculator_tree_destroy_all(&tree);