3 * Copyright 2012 Samsung Electronics Co., Ltd
5 * Licensed under the Flora License, Version 1.1 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://floralicense.org/license
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an AS IS BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 #include <stdio.h> //snprintf
22 #include <ctype.h> //isdigit
24 #include "calc-main.h"
25 #include "calc-string.h"
26 #include "calc-expression.h"
28 /* special characters */
29 #define PI_S "\xcf\x80"
30 #define DIVIDE "\xc3\xb7"
31 #define MULTIPLY "\xc3\x97"
32 #define SQRT "\xe2\x88\x9a"
33 #define MINUS "\xe2\x88\x92"
34 extern char decimal_ch;
35 extern char separator_ch;
36 extern int scientific_result_len;
37 struct calc_func_t calc_func[] = {
47 {OP_10X, "10^("}, {OP_X2, "^2"}, {OP_XY, "^("}, {OP_ABS, "abs("},
52 * format number with comma
54 static void _calc_expr_format_number(const char *in, char *out)
56 char number[NUMBER_LENGTH] = { 0 };
57 char *dot = strchr(in, decimal_ch);
58 int length = (dot == NULL ? strlen(in) : dot - in);
59 bool negative = (in[0] == '-' ? true : false);
60 length -= (negative ? 1 : 0); /* the number length between '-' and '.' */
61 strncpy(number, negative ? in + 1 : in, length);
62 int comma_count = length / 3; /* the count of comma that will be add */
63 comma_count -= (length % 3 == 0 ? 1 : 0);
64 int p = length - 3; /* insert ',' at number[p] */
70 number[l] = number[l - 1];
73 number[p] = separator_ch;
83 strncpy(s, number, length);
87 strcpy(s + length, dot);
94 * Get the fisrt number's postion in the expression string.
96 * @param expr Expression string
97 * @param begin The index of fisrt digit(maybe '-')
98 * @param end The index of last digit
102 static bool _calc_expr_get_number_position(const char *expr, int *begin,
108 bool negative = false;
109 char *digit = "0123456789";
110 char digit_with_dot[32] = { 0 };
111 snprintf(digit_with_dot, sizeof(digit_with_dot), "%s%c", digit,
113 int b = strcspn(expr, digit);
114 if (b == strlen(expr)) {
117 if (b > 0 && expr[b - 1] == '-')
120 /* if before '-' is ')' or digit, I cosider it as minus. */
121 if (b > 1 && (expr[b - 2] == ')' || isdigit(expr[b - 2])))
131 int length = strspn(expr + b, digit_with_dot);
132 *begin = (negative ? b - 1 : b);
133 *end = b + length - 1;
138 * replace common char with special locally.
140 void calc_expr_replace_with_special_char(char *expr)
143 string_replace(expr, "p", PI_S);
144 string_replace(expr, "x", MULTIPLY);
145 string_replace(expr, "/", DIVIDE);
146 //string_replace(expr,"-",MINUS);
147 string_replace(expr, "sqrt", SQRT);
151 void calc_expr_replace_from_special_char(char *expr)
154 string_replace(expr, PI_S, "p");
155 string_replace(expr, MULTIPLY, "x");
156 string_replace(expr, DIVIDE, "/");
157 string_replace(expr,MINUS,"-");
158 string_replace(expr, SQRT, "sqrt");
163 * convert string for calculate to string for display
165 void calc_expr_format_expression(const char *expr_in, char *expr_out)
168 char number1[NUMBER_LENGTH] = { 0 };
169 char number2[NUMBER_LENGTH] = { 0 };
170 const char *in = expr_in;
171 char *out = expr_out;
173 while (_calc_expr_get_number_position(in, &begin, &end)) {
174 int l = end - begin + 1;
175 strncpy(number1, in + begin, l);
177 _calc_expr_format_number(number1, number2);
178 strncpy(out, in, begin);
180 strcpy(out, number2);
182 out = out + strlen(out);
185 calc_expr_replace_with_special_char(expr_out);
189 int calc_expr_get_operator_num(const char *expr)
194 char *operator = "+-x/^";
199 while (operator[j]) {
200 if (operator[j] == expr[i]) {
211 int calc_expr_get_left_parentheses_num(const char *expr)
218 while (expr[i] != '\0') {
219 if (expr[i] == '(') {
227 void calc_expr_num_remove_end_zero(char *number)
229 int len = strlen(number);
230 if (strchr(number, 'e') != NULL || strchr(number, 'E') != NULL) {
233 if (strchr(number, decimal_ch) != NULL) {
234 while (len > 0 && number[len - 1] == '0') {
235 number[len - 1] = '\0';
238 if (len > 0 && number[len - 1] == decimal_ch) {
239 number[len - 1] = '\0';
247 * Format calculate result to show it suitably in the entry
248 * Mainly, remove end zero, if too long, change it to scientific form
250 * @param[in] result The calculate result
251 * @param[out] text The format string of the result
255 void calc_expr_num_format_result(double result, char *text)
258 char buf[MAX_EXPRESSION_LENGTH] = { 0 };
259 if ((fabs(result) - 0.00001) < 0) {
260 /* Solve the bug of "-0" */
261 if (ceil(fabs(result)) - 0 < 0.000000000001) {
265 snprintf(buf, sizeof(buf), "%.*E", scientific_result_len, result);
267 snprintf(buf, sizeof(buf), "%.*lf", MAX_DECIMAL_NUM, result);
268 calc_expr_num_remove_end_zero(buf);
269 double temp_result = (floor)(fabs(result));
270 char temp_buf[MAX_EXPRESSION_LENGTH] = { 0 };
271 snprintf(temp_buf, sizeof(buf), "%lf",temp_result);
272 calc_expr_num_remove_end_zero(temp_buf);
273 int max_lengh = isdigit(buf[0])? MAX_NUM_LENGTH:(MAX_NUM_LENGTH+1);
274 if (strlen(buf) > max_lengh) {
275 if (strlen(temp_buf) <= max_lengh) {
276 memset(temp_buf, 0, sizeof(temp_buf));
277 snprintf(temp_buf, sizeof(temp_buf), "%s", buf);
278 memset(buf, 0, sizeof(buf));
279 if (isdigit(temp_buf[max_lengh-1])) {
280 snprintf(buf, sizeof(buf), "%.*s",max_lengh,temp_buf);
282 snprintf(buf, sizeof(buf), "%.*s",max_lengh-1,temp_buf);//delete decimal point
285 double revise_result = result;
286 /* 12345678650*100,000 The result should be 1.23456787+E15, not 1.23456786+E15. */
289 sscanf(buf, "%lf", &revise_result);
291 snprintf(buf, sizeof(buf), "%.*E", scientific_result_len, revise_result);
301 * Get fucntion at current cursor position.
302 * If get successfully return the function symbol.
303 * If at the cursor position is not a function, return NULL.
305 char *calc_expr_get_current_func_at_cursor(char *expr, int cursor)
310 int pos = cursor - 1; //previous cursor position
311 int func_num = sizeof(calc_func) / sizeof(calc_func[0]); //the number of fucntions
314 for (i = 0; i < func_num; ++i) {
315 if ((ch = strchr(calc_func[i].symbol, expr[pos])) == NULL){
318 int t = pos - (ch - calc_func[i].symbol);
322 if (!strncmp(calc_func[i].symbol, expr + t, strlen(calc_func[i].symbol))) //equal
324 return calc_func[i].symbol;
332 * Parse the first number and give the number length in the expression.
333 * @param exp the expression string
334 * @param number the first number in the expression
335 * @param length the number's length in the expression string
336 * @return int 0 if parse succefully, else return -1
338 int calc_expr_parse_number(const char *exp, double *number, int *length)
340 const char *ptr = IS_SIGN(exp[0]) ? exp + 1 : exp;
341 char *digit = "0123456789";
342 int t = strspn(ptr, digit);
347 if (ptr[0] == decimal_ch) {
349 t = strspn(ptr, digit);
352 if (IS_SCIENCE_E(ptr[0])) /* science number */ {
354 ptr += IS_SIGN(ptr[0]) ? 1 : 0;
355 t = strspn(ptr, digit);
356 ptr += (t == 0 && IS_SIGN(ptr[-1]) ? -1 : t); /* "1.0E-" are not allowed */
360 char *buf = (char *)malloc(len + 1);
364 strncpy(buf, exp, len);
366 sscanf(buf, "%lf", &num);
368 if (number != NULL) {
371 if (length != NULL) {
374 return 0; /* successfully */
379 * Return the current number position at the cursor in expr
380 * @expr, the expression string
381 * @cursor, the cursor postion
382 * @[out]begin, the current number begin position
383 * @[out]length, the current number's length
384 * @return, return 0 if get succefully, else return -1
386 int calc_expr_get_current_num_at_cursor(char *expr, int cursor, int *begin,
393 if (expr[index] == 'p' || expr[index] == 'e') {
394 if (index > 0 && expr[index - 1] == '-') { //-e OR -p
404 if (expr[index] == 'E' || expr[index] == decimal_ch) {
407 while (calc_expr_parse_number(expr + index, NULL, &_length) ==
409 counter++; /* flag */
410 if (index + _length <= cursor) {
417 if (expr[index] == 'E' || expr[index] == decimal_ch)
423 if (0 != calc_expr_parse_number(expr + index, NULL, NULL)) {
426 calc_expr_parse_number(expr + index, NULL, &_length);
427 if (IS_SIGN(expr[index])) {
429 && (isdigit(expr[index - 1])
430 || expr[index - 1] == ')')) {
440 if (length != NULL) {
443 return 0; /* successfully */
448 * Auto close parentheses at the end of exp.
450 void calc_expr_close_parentheses(char *exp)
452 int cnt_l = 0, cnt_r = 0;
454 for (i = 0; exp[i]; ++i) {
462 int n = cnt_l - cnt_r;
471 * According "[Fraser] UI_Calculator_v0.5_20101125.pdf",
474 * Enter operator at first are allowed.
475 * So it should remove 'x' or '/' at the first position.
477 void calc_expr_remove_first_operator(char *exp)
479 if (exp != NULL && strlen(exp) > 0) {
480 if (exp[0] == 'x' || exp[0] == '/' || exp[0] == '+') {
481 string_remove_at(exp, 0, 1);
489 * According "[Fraser] UI_Calculator_v0.5_20101125.pdf",
490 * 123+= : 123+123=246
492 * 123*= : 123*123=15129
494 * The operator at last are allowed.
495 * The function process these conditions.
501 void calc_expr_process_last_operator(char *exp)
503 int len = strlen(exp);
504 if (len > 1 && IS_OPERATOER(exp[len - 1])) {
507 calc_expr_get_current_num_at_cursor(exp, len - 2, &b, &l)) {
508 strncat(exp, exp + b, l);
516 * Preprocess befeore calculating.
518 void calc_expr_preprocess(char *exp)
520 calc_expr_close_parentheses(exp);
521 calc_expr_remove_first_operator(exp);
522 calc_expr_process_last_operator(exp);
527 * Search the selection string is a legal string
533 bool calc_select_string_search(char *str)
536 calc_expr_replace_from_special_char(str);
537 int length = strlen(str);
539 if (IS_DIGITAL(str[i]) || IS_OPERATOER(str[i])
540 || (str[i] == decimal_ch) || (str[i] == separator_ch)
541 || (str[i] == 'i') || (str[i] == '(') || (str[i] == ')')) {
545 if (str[i+1] == 'i' && str[i+2] == 'n') {
547 } else if (str[i+1] == 'q' && str[i+2] == 'r' && str[i+3] == 't') {
552 } else if (str[i] == 'c') {
553 if (str[i+1] == 'o' && str[i+2] == 's') {
558 } else if (str[i] == 't') {
559 if (str[i+1] == 'a' && str[i+2] == 'n') {
564 } else if (str[i] == 'a') {
565 if (str[i+1] == 'b' && str[i+2] == 's') {
570 } else if (str[i] == 'l') {
571 if (str[i+1] == 'o' && str[i+2] == 'g') {
573 } else if (str[i+1] == 'n') {
579 CALC_INFO_PURPLE("str[i]=%c, i=%d", str[i], i);
588 * process expression input backspace
589 * @[in/out]expr, the expression string
590 * @[in/out]cursor, the cursor postion
591 * When the fuction return, the exp and cursor will be updated.
593 void calc_expr_input_backspace(char *exp, int *cursor)
595 int _cursor = *cursor;
600 if (_cursor > strlen(exp)) {
601 _cursor = strlen(exp);
602 } /* set to the end */
603 char *func = calc_expr_get_current_func_at_cursor(exp, _cursor);
609 while (p >= 0 && (strncmp(func, exp + p, strlen(func)) != 0)) {
612 count = strlen(func);
615 string_remove_at(exp, _cursor, count);
621 * insert str in exp at sursor position
622 * @[in/out]expr, the expression string
623 * @[in/out]cursor, the cursor postion
624 * @[in]str, the string insert into
625 * When the fuction return, the exp and cursor will be updated.
627 void calc_expr_input_insert(char *exp, int *cursor, char *str)
629 int _cursor = *cursor;
633 if (_cursor > strlen(exp)) {
634 _cursor = strlen(exp) + 1;
635 } /* set to the end */
636 string_insert(exp, _cursor, str);
637 *cursor = _cursor + strlen(str);