1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2021 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/lib/ags_math_util.h>
21
22 #include <stdio.h>
23 #include <string.h>
24
25
26 static GMutex regex_mutex;
27
28 gpointer ags_math_util_copy(gpointer ptr);
29 void ags_math_util_free(gpointer ptr);
30
31 /**
32 * SECTION:ags_math_util
33 * @short_description: math util
34 * @title: AgsMathUtil
35 * @section_id:
36 * @include: ags/lib/ags_math_util.h
37 *
38 * Common math utility functions.
39 */
40
41 GType
ags_math_util_get_type(void)42 ags_math_util_get_type(void)
43 {
44 static volatile gsize g_define_type_id__volatile = 0;
45
46 if(g_once_init_enter (&g_define_type_id__volatile)){
47 GType ags_type_math_util = 0;
48
49 ags_type_math_util =
50 g_boxed_type_register_static("AgsMathUtil",
51 (GBoxedCopyFunc) ags_math_util_copy,
52 (GBoxedFreeFunc) ags_math_util_free);
53
54 g_once_init_leave(&g_define_type_id__volatile, ags_type_math_util);
55 }
56
57 return g_define_type_id__volatile;
58 }
59
60 gpointer
ags_math_util_copy(gpointer ptr)61 ags_math_util_copy(gpointer ptr)
62 {
63 gpointer retval;
64
65 retval = g_memdup(ptr, sizeof(AgsMathUtil));
66
67 return(retval);
68 }
69
70 void
ags_math_util_free(gpointer ptr)71 ags_math_util_free(gpointer ptr)
72 {
73 g_free(ptr);
74 }
75
76 /**
77 * ags_math_util_find_parenthesis_all:
78 * @str: the string
79 * @open_position: (out): open position array return location
80 * @close_position: (out): close position array return location
81 * @open_position_count: (out): open position count return location
82 * @close_position_count: (out): close position count return location
83 *
84 * Find all parenthesis.
85 *
86 * Since: 3.2.0
87 */
88 void
ags_math_util_find_parenthesis_all(gchar * str,gint ** open_position,gint ** close_position,guint * open_position_count,guint * close_position_count)89 ags_math_util_find_parenthesis_all(gchar *str,
90 gint **open_position, gint **close_position,
91 guint *open_position_count, guint *close_position_count)
92 {
93 gint *open_pos, *close_pos;
94
95 gchar *iter;
96
97 guint open_pos_count, close_pos_count;
98
99 if(str == NULL){
100 if(open_position != NULL){
101 open_position[0] = NULL;
102 }
103
104 if(close_position != NULL){
105 close_position[0] = NULL;
106 }
107
108 if(open_position_count != NULL){
109 open_position_count[0] = 0;
110 }
111
112 if(close_position_count != NULL){
113 close_position_count[0] = 0;
114 }
115
116 return;
117 }
118
119 open_pos = NULL;
120 open_pos_count = 0;
121
122 close_pos = NULL;
123 close_pos_count = 0;
124
125 /* get open position */
126 for(iter = str; (iter = strchr(iter, '(')) != NULL; iter++){
127 if(open_pos == NULL){
128 open_pos = g_malloc(sizeof(gint));
129 }else{
130 open_pos = g_realloc(open_pos,
131 (open_pos_count + 1) * sizeof(gint));
132 }
133
134 open_pos[open_pos_count] = iter - str;
135 open_pos_count++;
136 }
137
138 /* get close position */
139 for(iter = str; (iter = strchr(iter, ')')) != NULL; iter++){
140 if(close_pos == NULL){
141 close_pos = g_malloc(sizeof(gint));
142 }else{
143 close_pos = g_realloc(close_pos,
144 (close_pos_count + 1) * sizeof(gint));
145 }
146
147 close_pos[close_pos_count] = iter - str;
148 close_pos_count++;
149 }
150
151 if(open_position != NULL){
152 open_position[0] = open_pos;
153 }
154
155 if(close_position != NULL){
156 close_position[0] = close_pos;
157 }
158
159 if(open_position_count != NULL){
160 open_position_count[0] = open_pos_count;
161 }
162
163 if(close_position_count != NULL){
164 close_position_count[0] = close_pos_count;
165 }
166 }
167
168 /**
169 * ags_math_util_find_exponent_parenthesis:
170 * @str: the string
171 * @exponent_open_position: (out): exponent open position array return location
172 * @exponent_close_position: (out): exponent close position array return location
173 * @exponent_open_position_count: (out): exponent open position count return location
174 * @exponent_close_position_count: (out): exponent close position count return location
175 *
176 * Find exponent parenthesis.
177 *
178 * Since: 3.2.0
179 */
180 void
ags_math_util_find_exponent_parenthesis(gchar * str,gint ** exponent_open_position,gint ** exponent_close_position,guint * exponent_open_position_count,guint * exponent_close_position_count)181 ags_math_util_find_exponent_parenthesis(gchar *str,
182 gint **exponent_open_position, gint **exponent_close_position,
183 guint *exponent_open_position_count, guint *exponent_close_position_count)
184 {
185 gint *exponent_open_pos, *exponent_close_pos;
186
187 gchar *iter;
188
189 guint exponent_open_pos_count, exponent_close_pos_count;
190
191 if(str == NULL){
192 if(exponent_open_position != NULL){
193 exponent_open_position[0] = NULL;
194 }
195
196 if(exponent_close_position != NULL){
197 exponent_close_position[0] = NULL;
198 }
199
200 if(exponent_open_position_count != NULL){
201 exponent_open_position_count[0] = 0;
202 }
203
204 if(exponent_close_position_count != NULL){
205 exponent_close_position_count[0] = 0;
206 }
207
208 return;
209 }
210
211 exponent_open_pos = NULL;
212 exponent_open_pos_count = 0;
213
214 exponent_close_pos = NULL;
215 exponent_close_pos_count = 0;
216
217 /* get exponent open and close position */
218 for(iter = str; (iter = strchr(iter, '(')) != NULL; iter++){
219 gchar *tmp_iter;
220
221 gint current_exponent_open_pos, current_exponent_close_pos;
222 guint nested_parenthesis;
223 gboolean is_exponent;
224
225 current_exponent_open_pos = -1;
226 current_exponent_close_pos = -1;
227
228 is_exponent = FALSE;
229
230 /* scan prev */
231 if(iter > str){
232 for(tmp_iter = iter - 1; tmp_iter[0] == ' ' && tmp_iter > str; tmp_iter--);
233
234 if(tmp_iter[0] == '^'){
235 is_exponent = TRUE;
236
237 current_exponent_open_pos = iter - str;
238 }
239 }
240
241 /* scan next */
242 if(is_exponent){
243 nested_parenthesis = 0;
244
245 for(tmp_iter = iter + 1; tmp_iter[0] != '\0'; tmp_iter++){
246 if(tmp_iter[0] == '('){
247 nested_parenthesis++;
248 }
249
250 if(tmp_iter[0] == ')'){
251 if(nested_parenthesis == 0){
252 current_exponent_close_pos = tmp_iter - str;
253
254 break;
255 }else{
256 nested_parenthesis--;
257 }
258 }
259 }
260 }
261
262 if(is_exponent){
263 /* exponent open position */
264 if(exponent_open_pos == NULL){
265 exponent_open_pos = g_malloc(sizeof(gint));
266 }else{
267 exponent_open_pos = g_realloc(exponent_open_pos,
268 (exponent_open_pos_count + 1) * sizeof(gint));
269 }
270
271 exponent_open_pos[exponent_open_pos_count] = current_exponent_open_pos;
272 exponent_open_pos_count++;
273
274 /* exponent close position */
275 if(exponent_close_pos == NULL){
276 exponent_close_pos = g_malloc(sizeof(gint));
277 }else{
278 exponent_close_pos = g_realloc(exponent_close_pos,
279 (exponent_close_pos_count + 1) * sizeof(gint));
280 }
281
282 exponent_close_pos[exponent_close_pos_count] = current_exponent_close_pos;
283 exponent_close_pos_count++;
284 }
285 }
286
287 if(exponent_open_position != NULL){
288 exponent_open_position[0] = exponent_open_pos;
289 }
290
291 if(exponent_close_position != NULL){
292 exponent_close_position[0] = exponent_close_pos;
293 }
294
295 if(exponent_open_position_count != NULL){
296 exponent_open_position_count[0] = exponent_open_pos_count;
297 }
298
299 if(exponent_close_position_count != NULL){
300 exponent_close_position_count[0] = exponent_close_pos_count;
301 }
302 }
303
304 /**
305 * ags_math_util_find_function_parenthesis:
306 * @str: the string
307 * @function_open_position: (out): function open position array return location
308 * @function_close_position: (out): function close position array return location
309 * @function_open_position_count: (out): function open position count return location
310 * @function_close_position_count: (out): function close position count return location
311 *
312 * Find function parenthesis.
313 *
314 * Since: 3.2.0
315 */
316 void
ags_math_util_find_function_parenthesis(gchar * str,gint ** function_open_position,gint ** function_close_position,guint * function_open_position_count,guint * function_close_position_count)317 ags_math_util_find_function_parenthesis(gchar *str,
318 gint **function_open_position, gint **function_close_position,
319 guint *function_open_position_count, guint *function_close_position_count)
320 {
321 GMatchInfo *function_match_info;
322
323 gint *function_open_pos, *function_close_pos;
324
325 guint function_open_pos_count, function_close_pos_count;
326
327 GError *error;
328
329 static const GRegex *function_regex = NULL;
330
331 static const gchar *function_pattern = "(log|exp|sin|cos|tan|asin|acos|atan|floor|ceil|round)";
332
333 if(str == NULL){
334 if(function_open_position != NULL){
335 function_open_position[0] = NULL;
336 }
337
338 if(function_close_position != NULL){
339 function_close_position[0] = NULL;
340 }
341
342 if(function_open_position_count != NULL){
343 function_open_position_count[0] = 0;
344 }
345
346 if(function_close_position_count != NULL){
347 function_close_position_count[0] = 0;
348 }
349
350 return;
351 }
352
353 function_open_pos = NULL;
354 function_open_pos_count = 0;
355
356 function_close_pos = NULL;
357 function_close_pos_count = 0;
358
359 /* compile regex */
360 g_mutex_lock(®ex_mutex);
361
362 if(function_regex == NULL){
363 error = NULL;
364 function_regex = g_regex_new(function_pattern,
365 (G_REGEX_EXTENDED),
366 0,
367 &error);
368
369 if(error != NULL){
370 g_message("%s", error->message);
371
372 g_error_free(error);
373 }
374 }
375
376 g_mutex_unlock(®ex_mutex);
377
378 /* find parenthesis */
379 g_regex_match(function_regex, str, 0, &function_match_info);
380
381 while(g_match_info_matches(function_match_info)){
382 gchar *tmp_iter;
383
384 gint start_pos, end_pos;
385 gint current_function_open_pos, current_function_close_pos;
386 guint nested_parenthesis;
387
388 current_function_open_pos = -1;
389 current_function_close_pos = -1;
390
391 g_match_info_fetch_pos(function_match_info,
392 0,
393 &start_pos, &end_pos);
394
395 for(tmp_iter = str + end_pos; tmp_iter[0] != '\0' && tmp_iter[0] == ' '; tmp_iter++);
396
397 if(tmp_iter[0] == '('){
398 current_function_open_pos = tmp_iter - str;
399 }else{
400 g_match_info_next(function_match_info,
401 NULL);
402
403 continue;
404 }
405
406 nested_parenthesis = 0;
407
408 for(tmp_iter = str + current_function_open_pos + 1; tmp_iter[0] != '\0'; tmp_iter++){
409 if(tmp_iter[0] == '('){
410 nested_parenthesis++;
411 }
412
413 if(tmp_iter[0] == ')'){
414 if(nested_parenthesis == 0){
415 current_function_close_pos = tmp_iter - str;
416
417 break;
418 }else{
419 nested_parenthesis--;
420 }
421 }
422 }
423
424 if(current_function_open_pos != -1 &&
425 current_function_close_pos != -1){
426 /* function open position */
427 if(function_open_pos == NULL){
428 function_open_pos = g_malloc(sizeof(gint));
429 }else{
430 function_open_pos = g_realloc(function_open_pos,
431 (function_open_pos_count + 1) * sizeof(gint));
432 }
433
434 function_open_pos[function_open_pos_count] = current_function_open_pos;
435 function_open_pos_count++;
436
437 /* function close position */
438 if(function_close_pos == NULL){
439 function_close_pos = g_malloc(sizeof(gint));
440 }else{
441 function_close_pos = g_realloc(function_close_pos,
442 (function_close_pos_count + 1) * sizeof(gint));
443 }
444
445 function_close_pos[function_close_pos_count] = current_function_close_pos;
446 function_close_pos_count++;
447 }
448
449 g_match_info_next(function_match_info,
450 NULL);
451 }
452
453 if(function_open_position != NULL){
454 function_open_position[0] = function_open_pos;
455 }
456
457 if(function_close_position != NULL){
458 function_close_position[0] = function_close_pos;
459 }
460
461 if(function_open_position_count != NULL){
462 function_open_position_count[0] = function_open_pos_count;
463 }
464
465 if(function_close_position_count != NULL){
466 function_close_position_count[0] = function_close_pos_count;
467 }
468 }
469
470 /**
471 * ags_math_util_find_term_parenthesis:
472 * @str: the string
473 * @term_open_position: (out): term open position array return location
474 * @term_close_position: (out): term close position array return location
475 * @term_open_position_count: (out): term open position count return location
476 * @term_close_position_count: (out): term close position count return location
477 *
478 * Find term parenthesis.
479 *
480 * Since: 3.2.0
481 */
482 void
ags_math_util_find_term_parenthesis(gchar * str,gint ** term_open_position,gint ** term_close_position,guint * term_open_position_count,guint * term_close_position_count)483 ags_math_util_find_term_parenthesis(gchar *str,
484 gint **term_open_position, gint **term_close_position,
485 guint *term_open_position_count, guint *term_close_position_count)
486 {
487 gint *open_pos, *close_pos;
488 gint *exponent_open_pos, *exponent_close_pos;
489 gint *function_open_pos, *function_close_pos;
490 gint *term_open_pos, *term_close_pos;
491
492 guint open_pos_count, close_pos_count;
493 guint exponent_open_pos_count, exponent_close_pos_count;
494 guint function_open_pos_count, function_close_pos_count;
495 guint term_open_pos_count, term_close_pos_count;
496 guint i, j, k, l;
497
498 if(str == NULL){
499 if(term_open_position != NULL){
500 term_open_position[0] = NULL;
501 }
502
503 if(term_close_position != NULL){
504 term_close_position[0] = NULL;
505 }
506
507 if(term_open_position_count != NULL){
508 term_open_position_count[0] = 0;
509 }
510
511 if(term_close_position_count != NULL){
512 term_close_position_count[0] = 0;
513 }
514
515 return;
516 }
517
518 open_pos = NULL;
519 close_pos = NULL;
520
521 exponent_open_pos = NULL;
522 exponent_close_pos = NULL;
523
524 function_open_pos = NULL;
525 function_close_pos = NULL;
526
527 term_open_pos = NULL;
528 term_close_pos = NULL;
529
530 ags_math_util_find_parenthesis_all(str,
531 &open_pos, &close_pos,
532 &open_pos_count, &close_pos_count);
533
534 ags_math_util_find_exponent_parenthesis(str,
535 &exponent_open_pos, &exponent_close_pos,
536 &exponent_open_pos_count, &exponent_close_pos_count);
537
538 ags_math_util_find_function_parenthesis(str,
539 &function_open_pos, &function_close_pos,
540 &function_open_pos_count, &function_close_pos_count);
541
542 term_open_pos_count = open_pos_count - exponent_open_pos_count - function_open_pos_count;
543 term_close_pos_count = close_pos_count - exponent_close_pos_count - function_close_pos_count;
544
545 if(term_open_pos_count > 0){
546 term_open_pos = g_malloc(term_open_pos_count * sizeof(gint));
547
548 for(i = 0, j = 0, k = 0, l = 0; i < term_open_pos_count;){
549 for(; j < open_pos_count && k < exponent_close_pos_count && (open_pos[j] == exponent_open_pos[k] || open_pos[j] == function_open_pos[l]); j++){
550 if(open_pos[j] == exponent_open_pos[k]){
551 k++;
552 }
553
554 if(open_pos[j] == function_open_pos[l]){
555 l++;
556 }
557 }
558
559 term_open_pos[i] = open_pos[j];
560 i++;
561 j++;
562 }
563 }
564
565 if(term_close_pos_count > 0){
566 term_close_pos = g_malloc(term_close_pos_count * sizeof(gint));
567
568 for(i = 0, j = 0, k = 0, l = 0; i < term_close_pos_count;){
569 for(; j < close_pos_count && k < exponent_close_pos_count && (close_pos[j] == exponent_close_pos[k] || close_pos[j] == function_close_pos[l]); j++){
570 if(close_pos[j] == exponent_close_pos[k]){
571 k++;
572 }
573
574 if(close_pos[j] == function_close_pos[l]){
575 l++;
576 }
577 }
578
579 term_close_pos[i] = close_pos[j];
580 i++;
581 j++;
582 }
583 }
584
585 g_free(open_pos);
586 g_free(close_pos);
587
588 g_free(exponent_open_pos);
589 g_free(exponent_close_pos);
590
591 g_free(function_open_pos);
592 g_free(function_close_pos);
593
594 if(term_open_position != NULL){
595 term_open_position[0] = term_open_pos;
596 }
597
598 if(term_close_position != NULL){
599 term_close_position[0] = term_close_pos;
600 }
601
602 if(term_open_position_count != NULL){
603 term_open_position_count[0] = term_open_pos_count;
604 }
605
606 if(term_close_position_count != NULL){
607 term_close_position_count[0] = term_close_pos_count;
608 }
609 }
610
611 /**
612 * ags_math_util_match_sign:
613 * @offset: the string pointer
614 * @end_ptr: the end of @offset
615 * @start_offset: (out) (transfer none): points to start offset of matched, otherwise %NULL
616 * @end_offset: (out) (transfer none): points to end offset of matched, otherwise %NULL
617 *
618 * Match sign.
619 *
620 * Returns: %TRUE on success, otherwise %FALSE
621 *
622 * Since: 3.6.0
623 */
624 gboolean
ags_math_util_match_sign(gchar * offset,gchar * end_ptr,gchar ** start_offset,gchar ** end_offset)625 ags_math_util_match_sign(gchar *offset,
626 gchar *end_ptr,
627 gchar **start_offset, gchar **end_offset)
628 {
629 gchar* match[2];
630
631 gboolean success;
632
633 match[0] = NULL;
634 match[1] = NULL;
635
636 success = FALSE;
637
638 if(offset != NULL &&
639 end_ptr != NULL &&
640 offset < end_ptr){
641 if(offset[0] == '-' || offset[0] == '+'){
642 match[0] = offset;
643 match[1] = offset + 1;
644
645 success = TRUE;
646 }
647 }
648
649 if(start_offset != NULL){
650 start_offset[0] = match[0];
651 }
652
653 if(end_offset != NULL){
654 end_offset[0] = match[1];
655 }
656
657 return(success);
658 }
659
660 /**
661 * ags_math_util_match_coefficient:
662 * @offset: the string pointer
663 * @end_ptr: the end of @offset
664 * @start_offset: (out) (transfer none): points to start offset of matched, otherwise %NULL
665 * @end_offset: (out) (transfer none): points to end offset of matched, otherwise %NULL
666 *
667 * Match coefficient including optional sign.
668 *
669 * Returns: %TRUE on success, otherwise %FALSE
670 *
671 * Since: 3.6.0
672 */
673 gboolean
ags_math_util_match_coefficient(gchar * offset,gchar * end_ptr,gchar ** start_offset,gchar ** end_offset)674 ags_math_util_match_coefficient(gchar *offset,
675 gchar *end_ptr,
676 gchar **start_offset, gchar **end_offset)
677 {
678 GMatchInfo *complex_number_match_info;
679
680 gchar* match[2];
681
682 gchar *iter;
683 gchar *look_ahead;
684 gchar *iter_start_offset, *iter_end_offset;
685 gchar *a_start_offset, *a_end_offset;
686 gchar *b_start_offset, *b_end_offset;
687
688 gboolean has_sign;
689 gboolean has_parenthesis;
690 gboolean has_complex_operator;
691 gboolean has_complex_a_sign;
692 gboolean has_complex_a_numeric;
693 gboolean has_complex_a_float;
694 gboolean has_complex_a_exponent;
695 gboolean has_complex_a;
696 gboolean has_complex_b_sign;
697 gboolean has_complex_b_numeric;
698 gboolean has_complex_b_float;
699 gboolean has_complex_b_exponent;
700 gboolean has_complex_b;
701 gboolean has_complex_i0;
702 gboolean has_complex_i1;
703 gboolean has_numeric;
704 gboolean has_float;
705 gboolean success;
706
707 match[0] = NULL;
708 match[1] = NULL;
709
710 a_start_offset = NULL;
711 a_end_offset = NULL;
712
713 b_start_offset = NULL;
714 b_end_offset = NULL;
715
716 has_sign = FALSE;
717 has_parenthesis = FALSE;
718 has_complex_operator = FALSE;
719
720 has_complex_a_sign = FALSE;
721 has_complex_a_numeric = FALSE;
722 has_complex_a_float = FALSE;
723 has_complex_a_exponent = FALSE;
724 has_complex_a = FALSE;
725
726 has_complex_b_sign = FALSE;
727 has_complex_b_numeric = FALSE;
728 has_complex_b_float = FALSE;
729 has_complex_b_exponent = FALSE;
730 has_complex_b = FALSE;
731
732 has_complex_i0 = FALSE;
733 has_complex_i1 = FALSE;
734
735 has_numeric = FALSE;
736 has_float = FALSE;
737
738 success = FALSE;
739
740 if(offset != NULL &&
741 end_ptr != NULL &&
742 offset < end_ptr){
743 iter = offset;
744
745 if(offset[0] == '('){
746 has_parenthesis = TRUE;
747
748 iter++;
749 }
750
751 if(!has_parenthesis){
752 if((offset[0] == '+' ||
753 offset[0] == '-') &&
754 offset[1] == '('){
755 has_sign = TRUE;
756 has_parenthesis = TRUE;
757
758 iter += 2;
759 }
760 }
761
762 for(look_ahead = iter; look_ahead < end_ptr;){
763 /* check sign of a and i */
764 if(!has_complex_a){
765 if(look_ahead[0] == '+' ||
766 look_ahead[0] == '-'){
767 if(!has_complex_a_sign){
768 a_start_offset = iter;
769
770 has_complex_a_sign = TRUE;
771 }else{
772 if(has_complex_a_numeric){
773 a_end_offset = iter;
774
775 has_complex_a = TRUE;
776
777 look_ahead++;
778
779 continue;
780 }else if(has_complex_i0){
781 look_ahead++;
782
783 continue;
784 }else{
785 //failure
786
787 break;
788 }
789 }
790 }
791
792 if(look_ahead[0] >= '0' &&
793 look_ahead[0] <= '9'){
794 has_complex_a_numeric = TRUE;
795
796 look_ahead++;
797
798 continue;
799 }
800
801 if(look_ahead[0] == '.'){
802 if(!has_complex_a_float){
803 has_complex_a_float = TRUE;
804
805 look_ahead++;
806
807 continue;
808 }else{
809 a_start_offset = NULL;
810
811 //failure
812
813 break;
814 }
815 }
816
817 if(look_ahead[0] == 'e' ||
818 look_ahead[0] == 'E'){
819 gchar *exp_look_ahead;
820
821 exp_look_ahead = look_ahead + 1;
822
823 if(exp_look_ahead < end_ptr &&
824 exp_look_ahead[0] == '+' ||
825 exp_look_ahead[0] == '-'){
826 exp_look_ahead++;
827 }
828
829 for(; exp_look_ahead < end_ptr; exp_look_ahead++){
830 if(exp_look_ahead[0] >= '0' &&
831 exp_look_ahead[0] <= '9'){
832 has_complex_a_exponent = TRUE;
833 }else{
834 break;
835 }
836 }
837
838 if(has_complex_a_exponent){
839 look_ahead = exp_look_ahead;
840
841 continue;
842 }else{
843 //failure
844
845 break;
846 }
847 }
848
849 /* default */
850 //completed or failure
851
852 if(has_complex_a_numeric){
853 a_end_offset = iter;
854
855 has_complex_a = TRUE;
856 }
857
858 break;
859 }
860
861 /* check sign of b and i */
862 if(has_complex_operator &&
863 !has_complex_b){
864 if(look_ahead[0] == '+' ||
865 look_ahead[0] == '-'){
866 if(!has_complex_b_sign){
867 b_start_offset = iter;
868
869 has_complex_b_sign = TRUE;
870 }else{
871 if(has_complex_b_numeric){
872 has_complex_b = TRUE;
873
874 look_ahead++;
875
876 continue;
877 }else if(has_complex_i0){
878 look_ahead++;
879
880 continue;
881 }else{
882 //failure
883
884 break;
885 }
886 }
887 }
888
889 if(look_ahead[0] >= '0' &&
890 look_ahead[0] <= '9'){
891 has_complex_b_numeric = TRUE;
892
893 look_ahead++;
894
895 continue;
896 }
897
898 if(look_ahead[0] == '.'){
899 if(!has_complex_b_float){
900 has_complex_b_float = TRUE;
901
902 look_ahead++;
903
904 continue;
905 }else{
906 b_start_offset = NULL;
907 //failure
908
909 break;
910 }
911 }
912
913 if(look_ahead[0] == 'e' ||
914 look_ahead[0] == 'E'){
915 gchar *exp_look_ahead;
916
917 exp_look_ahead = look_ahead + 1;
918
919 if(exp_look_ahead < end_ptr &&
920 exp_look_ahead[0] == '+' ||
921 exp_look_ahead[0] == '-'){
922 exp_look_ahead++;
923 }
924
925 for(; exp_look_ahead < end_ptr; exp_look_ahead++){
926 if(exp_look_ahead[0] >= '0' &&
927 exp_look_ahead[0] <= '9'){
928 has_complex_b_exponent = TRUE;
929 }else{
930 break;
931 }
932 }
933
934 if(has_complex_b_exponent){
935 look_ahead = exp_look_ahead;
936 }else{
937 //failure
938
939 break;
940 }
941 }
942
943 /* default */
944 //completed or failure
945
946 if(has_complex_b_numeric){
947 b_end_offset = iter;
948
949 has_complex_b = TRUE;
950 }
951 }
952
953 if(!has_complex_operator &&
954 !has_complex_i0){
955 if(!g_ascii_strncasecmp(look_ahead,
956 AGS_SYMBOLIC_COMPLEX_UNIT,
957 strlen(AGS_SYMBOLIC_COMPLEX_UNIT))){
958 has_complex_i0 = TRUE;
959
960 look_ahead += strlen(AGS_SYMBOLIC_COMPLEX_UNIT);
961
962 continue;
963 }
964 }
965
966 if(has_complex_operator &&
967 !has_complex_i1){
968 if(!g_ascii_strncasecmp(look_ahead,
969 AGS_SYMBOLIC_COMPLEX_UNIT,
970 strlen(AGS_SYMBOLIC_COMPLEX_UNIT))){
971 has_complex_i1 = TRUE;
972
973 look_ahead += strlen(AGS_SYMBOLIC_COMPLEX_UNIT);
974
975 continue;
976 }
977 }
978
979 if(look_ahead[0] == ')'){
980 if(has_parenthesis){
981 look_ahead++;
982 }
983
984 break;
985 }
986
987 if(!has_complex_operator &&
988 (look_ahead[0] == '+' ||
989 look_ahead[0] == '-')){
990 has_complex_operator = TRUE;
991
992 look_ahead++;
993 }
994
995 break;
996 }
997
998 if((has_complex_i0 || has_complex_i1) &&
999 has_complex_a &&
1000 has_complex_b){
1001 success = TRUE;
1002
1003 match[0] = offset;
1004 //TODO:JK: implement me
1005 // match[1] = ;
1006 }
1007
1008 if(!success){
1009 has_sign = ags_math_util_match_sign(offset,
1010 end_ptr,
1011 &iter_start_offset, &iter_end_offset);
1012
1013 if(has_sign){
1014 iter = iter_end_offset;
1015 }
1016
1017 if(!strncmp(iter,
1018 AGS_SYMBOLIC_EULER,
1019 strlen(AGS_SYMBOLIC_EULER))){
1020 match[0] = offset;
1021 match[1] = iter + strlen(AGS_SYMBOLIC_EULER);
1022
1023 success = TRUE;
1024 }else if(!strncmp(iter,
1025 AGS_SYMBOLIC_PI,
1026 strlen(AGS_SYMBOLIC_PI))){
1027 match[0] = offset;
1028 match[1] = iter + strlen(AGS_SYMBOLIC_PI);
1029
1030 success = TRUE;
1031 }else if(!strncmp(iter,
1032 AGS_SYMBOLIC_PI,
1033 strlen(AGS_SYMBOLIC_PI))){
1034 match[0] = offset;
1035 match[1] = iter + strlen(AGS_SYMBOLIC_PI);
1036
1037 success = TRUE;
1038 }else if(!strncmp(iter,
1039 AGS_SYMBOLIC_INFINIT,
1040 strlen(AGS_SYMBOLIC_INFINIT))){
1041 match[0] = offset;
1042 match[1] = iter + strlen(AGS_SYMBOLIC_INFINIT);
1043
1044 success = TRUE;
1045 }else if(!strncmp(iter,
1046 AGS_SYMBOLIC_COMPLEX_UNIT,
1047 strlen(AGS_SYMBOLIC_COMPLEX_UNIT))){
1048 match[0] = offset;
1049 match[1] = iter + strlen(AGS_SYMBOLIC_COMPLEX_UNIT);
1050
1051 success = TRUE;
1052 }
1053 }
1054 }
1055
1056 if(start_offset != NULL){
1057 start_offset[0] = match[0];
1058 }
1059
1060 if(end_offset != NULL){
1061 end_offset[0] = match[1];
1062 }
1063
1064 return(success);
1065 }
1066
1067 /**
1068 * ags_math_util_match_symbol:
1069 * @offset: the string pointer
1070 * @end_ptr: the end of @offset
1071 * @start_offset: (out) (transfer none): points to start offset of matched, otherwise %NULL
1072 * @end_offset: (out) (transfer none): points to end offset of matched, otherwise %NULL
1073 *
1074 * Match symbol including optional sign.
1075 *
1076 * Returns: %TRUE on success, otherwise %FALSE
1077 *
1078 * Since: 3.6.0
1079 */
1080 gboolean
ags_math_util_match_symbol(gchar * offset,gchar * end_ptr,gchar ** start_offset,gchar ** end_offset)1081 ags_math_util_match_symbol(gchar *offset,
1082 gchar *end_ptr,
1083 gchar **start_offset, gchar **end_offset)
1084 {
1085 gchar* match[2];
1086
1087 gchar *iter;
1088 gchar *iter_start_offset, *iter_end_offset;
1089
1090 gboolean has_sign;
1091 gboolean has_subscript;
1092 gboolean success;
1093
1094 match[0] = NULL;
1095 match[1] = NULL;
1096
1097 has_sign = FALSE;
1098 has_subscript = FALSE;
1099
1100 success = FALSE;
1101
1102 if(offset != NULL &&
1103 end_ptr != NULL &&
1104 offset < end_ptr){
1105 iter = offset;
1106
1107 has_sign = ags_math_util_match_sign(offset,
1108 end_ptr,
1109 &iter_start_offset, &iter_end_offset);
1110
1111 if(has_sign){
1112 iter = iter_end_offset;
1113 }
1114
1115 if(!ags_math_util_match_function(iter,
1116 end_ptr,
1117 NULL, NULL)){
1118 if((iter[0] >= 'a' && iter[0] <= 'z') ||
1119 (iter[0] >= 'A' && iter[0] <= 'Z')){
1120 success = TRUE;
1121
1122 iter++;
1123
1124 /* check subscript */
1125 for(; iter < end_ptr; iter++){
1126 gunichar subscript_x;
1127
1128 static gunichar subscript_0;
1129 static gunichar subscript_9;
1130
1131 static gboolean subscript_set = FALSE;
1132
1133 if(!subscript_set){
1134 subscript_0 = g_utf8_get_char(AGS_SUBSCRIPT_0);
1135 subscript_9 = g_utf8_get_char(AGS_SUBSCRIPT_9);
1136
1137 subscript_set = TRUE;
1138 }
1139
1140 subscript_x = g_utf8_get_char(iter);
1141
1142 if(subscript_x >= subscript_0 && subscript_x <= subscript_9){
1143 has_subscript = TRUE;
1144 }else{
1145 break;
1146 }
1147 }
1148
1149 match[0] = offset;
1150 match[1] = iter;
1151
1152 success = TRUE;
1153 }
1154 }
1155 }
1156
1157 if(start_offset != NULL){
1158 start_offset[0] = match[0];
1159 }
1160
1161 if(end_offset != NULL){
1162 end_offset[0] = match[1];
1163 }
1164
1165 return(success);
1166 }
1167
1168 /**
1169 * ags_math_util_match_exponent:
1170 * @offset: the string pointer
1171 * @end_ptr: the end of @offset
1172 * @start_offset: (out) (transfer none): points to start offset of matched, otherwise %NULL
1173 * @end_offset: (out) (transfer none): points to end offset of matched, otherwise %NULL
1174 *
1175 * Match exponent with or without parenthesis.
1176 *
1177 * Returns: %TRUE on success, otherwise %FALSE
1178 *
1179 * Since: 3.6.0
1180 */
1181 gboolean
ags_math_util_match_exponent(gchar * offset,gchar * end_ptr,gchar ** start_offset,gchar ** end_offset)1182 ags_math_util_match_exponent(gchar *offset,
1183 gchar *end_ptr,
1184 gchar **start_offset, gchar **end_offset)
1185 {
1186 gchar* match[2];
1187
1188 gchar *iter;
1189 gchar *iter_start_offset, *iter_end_offset;
1190
1191 gboolean has_coefficient;
1192 gboolean has_symbol;
1193 gboolean has_function;
1194 gboolean success;
1195
1196 match[0] = NULL;
1197 match[1] = NULL;
1198
1199 has_coefficient = FALSE;
1200 has_symbol = FALSE;
1201 has_function = FALSE;
1202
1203 success = FALSE;
1204
1205 if(offset != NULL &&
1206 end_ptr != NULL &&
1207 offset < end_ptr){
1208 iter = offset;
1209
1210 if(iter[0] == '^'){
1211 iter++;
1212
1213 if(iter[0] == '('){
1214 gint open_parenthesis;
1215
1216 iter++;
1217
1218 open_parenthesis = 1;
1219
1220 while(open_parenthesis > 0){
1221 if(iter[0] == '('){
1222 open_parenthesis++;
1223
1224 iter++;
1225 }else if(iter[0] == ')'){
1226 open_parenthesis--;
1227
1228 iter++;
1229 }else{
1230 gboolean tmp_has_coefficient;
1231 gboolean tmp_has_symbol;
1232 gboolean tmp_has_function;
1233
1234 tmp_has_coefficient = FALSE;
1235 tmp_has_symbol = FALSE;
1236 tmp_has_function = FALSE;
1237
1238 /* check coefficient */
1239 tmp_has_coefficient = ags_math_util_match_coefficient(iter,
1240 end_ptr,
1241 &iter_start_offset, &iter_end_offset);
1242
1243 if(tmp_has_coefficient){
1244 iter = iter_end_offset;
1245
1246 has_coefficient = TRUE;
1247 }
1248
1249 /* check symbol */
1250 if(!tmp_has_coefficient){
1251 tmp_has_symbol = ags_math_util_match_symbol(iter,
1252 end_ptr,
1253 &iter_start_offset, &iter_end_offset);
1254 }
1255
1256 if(tmp_has_symbol){
1257 iter = iter_end_offset;
1258
1259 has_symbol = TRUE;
1260 }
1261
1262 /* check function */
1263 if(!tmp_has_coefficient &&
1264 !tmp_has_symbol){
1265 tmp_has_function = ags_math_util_match_function(iter,
1266 end_ptr,
1267 &iter_start_offset, &iter_end_offset);
1268 }
1269
1270 if(tmp_has_function){
1271 iter = iter_end_offset;
1272
1273 has_function = TRUE;
1274 }
1275
1276 /* skip anything else eg. operators and spaces */
1277 if(!(has_coefficient ||
1278 has_symbol ||
1279 has_function)){
1280 iter++;
1281 }
1282 }
1283 }
1284 }else{
1285 /* check coefficient */
1286 has_coefficient = ags_math_util_match_coefficient(iter,
1287 end_ptr,
1288 &iter_start_offset, &iter_end_offset);
1289
1290 if(has_coefficient){
1291 iter = iter_end_offset;
1292 }
1293
1294 /* check symbol */
1295 if(!has_coefficient){
1296 has_symbol = ags_math_util_match_symbol(iter,
1297 end_ptr,
1298 &iter_start_offset, &iter_end_offset);
1299 }
1300
1301 if(has_symbol){
1302 iter = iter_end_offset;
1303 }
1304
1305 /* check function */
1306 if(!has_coefficient &&
1307 !has_symbol){
1308 has_function = ags_math_util_match_function(iter,
1309 end_ptr,
1310 &iter_start_offset, &iter_end_offset);
1311 }
1312
1313 if(has_function){
1314 iter = iter_end_offset;
1315 }
1316 }
1317
1318 if(has_coefficient ||
1319 has_symbol ||
1320 has_function){
1321 match[0] = offset;
1322 match[1] = iter;
1323 }
1324
1325 success = TRUE;
1326 }
1327 }
1328
1329 if(start_offset != NULL){
1330 start_offset[0] = match[0];
1331 }
1332
1333 if(end_offset != NULL){
1334 end_offset[0] = match[1];
1335 }
1336
1337 return(success);
1338 }
1339
1340 /**
1341 * ags_math_util_match_operator:
1342 * @offset: the string pointer
1343 * @end_ptr: the end of @offset
1344 * @start_offset: (out) (transfer none): points to start offset of matched, otherwise %NULL
1345 * @end_offset: (out) (transfer none): points to end offset of matched, otherwise %NULL
1346 *
1347 * Match operator.
1348 *
1349 * Returns: %TRUE on success, otherwise %FALSE
1350 *
1351 * Since: 3.6.0
1352 */
1353 gboolean
ags_math_util_match_operator(gchar * offset,gchar * end_ptr,gchar ** start_offset,gchar ** end_offset)1354 ags_math_util_match_operator(gchar *offset,
1355 gchar *end_ptr,
1356 gchar **start_offset, gchar **end_offset)
1357 {
1358 gchar* match[2];
1359
1360 gboolean success;
1361
1362 match[0] = NULL;
1363 match[1] = NULL;
1364
1365 success = FALSE;
1366
1367 if(offset != NULL &&
1368 end_ptr != NULL &&
1369 offset < end_ptr){
1370 if(offset[0] == '-' || offset[0] == '+' || offset[0] == '/' || offset[0] == '*'){
1371 match[0] = offset;
1372 match[1] = offset + 1;
1373
1374 success = TRUE;
1375 }
1376 }
1377
1378 if(start_offset != NULL){
1379 start_offset[0] = match[0];
1380 }
1381
1382 if(end_offset != NULL){
1383 end_offset[0] = match[1];
1384 }
1385
1386 return(success);
1387 }
1388
1389 /**
1390 * ags_math_util_match_function:
1391 * @offset: the string pointer
1392 * @end_ptr: the end of @offset
1393 * @start_offset: (out) (transfer none): points to start offset of matched, otherwise %NULL
1394 * @end_offset: (out) (transfer none): points to end offset of matched, otherwise %NULL
1395 *
1396 * Match function.
1397 *
1398 * Returns: %TRUE on success, otherwise %FALSE
1399 *
1400 * Since: 3.6.0
1401 */
1402 gboolean
ags_math_util_match_function(gchar * offset,gchar * end_ptr,gchar ** start_offset,gchar ** end_offset)1403 ags_math_util_match_function(gchar *offset,
1404 gchar *end_ptr,
1405 gchar **start_offset, gchar **end_offset)
1406 {
1407 gchar* match[2];
1408
1409 gchar *iter;
1410 gchar *iter_start_offset, *iter_end_offset;
1411
1412 gboolean is_function;
1413 gboolean has_coefficient;
1414 gboolean has_symbol;
1415 gboolean has_function;
1416 gboolean success;
1417
1418 match[0] = NULL;
1419 match[1] = NULL;
1420
1421 is_function = FALSE;
1422
1423 has_coefficient = FALSE;
1424 has_symbol = FALSE;
1425 has_function = FALSE;
1426
1427 success = FALSE;
1428
1429 if(offset != NULL &&
1430 end_ptr != NULL &&
1431 offset < end_ptr){
1432 iter = offset;
1433
1434 if(!strncmp(iter,
1435 "log",
1436 3)){
1437 iter += 3;
1438
1439 is_function = TRUE;
1440 }else if(!strncmp(iter,
1441 "exp",
1442 3)){
1443 iter += 3;
1444
1445 is_function = TRUE;
1446 }else if(!strncmp(iter,
1447 "sin",
1448 3)){
1449 iter += 3;
1450
1451 is_function = TRUE;
1452 }else if(!strncmp(iter,
1453 "cos",
1454 3)){
1455 iter += 3;
1456
1457 is_function = TRUE;
1458 }else if(!strncmp(iter,
1459 "tan",
1460 3)){
1461 iter += 3;
1462
1463 is_function = TRUE;
1464 }else if(!strncmp(iter,
1465 "asin",
1466 3)){
1467 iter += 3;
1468
1469 is_function = TRUE;
1470 }else if(!strncmp(iter,
1471 "acos",
1472 3)){
1473 iter += 3;
1474
1475 is_function = TRUE;
1476 }else if(!strncmp(iter,
1477 "atan",
1478 3)){
1479 iter += 3;
1480
1481 is_function = TRUE;
1482 }else if(!strncmp(iter,
1483 "floor",
1484 5)){
1485 iter += 5;
1486
1487 is_function = TRUE;
1488 }else if(!strncmp(iter,
1489 "ceil",
1490 4)){
1491 iter += 4;
1492
1493 is_function = TRUE;
1494 }else if(!strncmp(iter,
1495 "round",
1496 5)){
1497 iter += 5;
1498
1499 is_function = TRUE;
1500 }
1501
1502 if(is_function){
1503 if(iter[0] == '('){
1504 gint open_parenthesis;
1505
1506 iter++;
1507
1508 open_parenthesis = 1;
1509
1510 while(open_parenthesis > 0){
1511 if(iter[0] == '('){
1512 open_parenthesis++;
1513
1514 iter++;
1515 }else if(iter[0] == ')'){
1516 open_parenthesis--;
1517
1518 iter++;
1519 }else{
1520 gboolean tmp_has_coefficient;
1521 gboolean tmp_has_symbol;
1522 gboolean tmp_has_function;
1523
1524 tmp_has_coefficient = FALSE;
1525 tmp_has_symbol = FALSE;
1526 tmp_has_function = FALSE;
1527
1528 /* check coefficient */
1529 tmp_has_coefficient = ags_math_util_match_coefficient(iter,
1530 end_ptr,
1531 &iter_start_offset, &iter_end_offset);
1532
1533 if(tmp_has_coefficient){
1534 iter = iter_end_offset;
1535
1536 has_coefficient = TRUE;
1537 }
1538
1539 /* check symbol */
1540 if(!tmp_has_coefficient){
1541 tmp_has_symbol = ags_math_util_match_symbol(iter,
1542 end_ptr,
1543 &iter_start_offset, &iter_end_offset);
1544 }
1545
1546 if(tmp_has_symbol){
1547 iter = iter_end_offset;
1548
1549 has_symbol = TRUE;
1550 }
1551
1552 /* check function */
1553 if(!tmp_has_coefficient &&
1554 !tmp_has_symbol){
1555 tmp_has_function = ags_math_util_match_function(iter,
1556 end_ptr,
1557 &iter_start_offset, &iter_end_offset);
1558 }
1559
1560 if(tmp_has_function){
1561 iter = iter_end_offset;
1562
1563 has_function = TRUE;
1564 }
1565
1566 /* skip anything else eg. operators and spaces */
1567 if(!(has_coefficient ||
1568 has_symbol ||
1569 has_function)){
1570 iter++;
1571 }
1572 }
1573 }
1574 }else{
1575 if(iter[0] == ' '){
1576 iter++;
1577
1578 /* check coefficient */
1579 has_coefficient = ags_math_util_match_coefficient(iter,
1580 end_ptr,
1581 &iter_start_offset, &iter_end_offset);
1582
1583 if(has_coefficient){
1584 iter = iter_end_offset;
1585 }
1586
1587 /* check symbol */
1588 if(!has_coefficient){
1589 has_symbol = ags_math_util_match_symbol(iter,
1590 end_ptr,
1591 &iter_start_offset, &iter_end_offset);
1592 }
1593
1594 if(has_symbol){
1595 iter = iter_end_offset;
1596 }
1597
1598 /* check function */
1599 if(!has_coefficient &&
1600 !has_symbol){
1601 has_function = ags_math_util_match_function(iter,
1602 end_ptr,
1603 &iter_start_offset, &iter_end_offset);
1604 }
1605
1606 if(has_function){
1607 iter = iter_end_offset;
1608 }
1609 }
1610 }
1611 }
1612
1613 if(is_function &&
1614 (has_coefficient ||
1615 has_symbol ||
1616 has_function)){
1617 match[0] = offset;
1618 match[1] = iter;
1619 }
1620 }
1621
1622 if(start_offset != NULL){
1623 start_offset[0] = match[0];
1624 }
1625
1626 if(end_offset != NULL){
1627 end_offset[0] = match[1];
1628 }
1629
1630 return(success);
1631 }
1632
1633 /**
1634 * ags_math_util_coefficient_to_complex:
1635 * @coefficient: the coefficient string
1636 * @value: (out) (transfer none): return location of value
1637 *
1638 * Compute @value from @coefficient.
1639 *
1640 * Returns: %TRUE on success, otherwise %FALSE
1641 *
1642 * Since: 3.6.0
1643 */
1644 gboolean
ags_math_util_coefficient_to_complex(gchar * coefficient,AgsComplex * value)1645 ags_math_util_coefficient_to_complex(gchar *coefficient,
1646 AgsComplex *value)
1647 {
1648 gchar *start_iter, *iter;
1649
1650 AgsComplex this_value;
1651
1652 double _Complex z;
1653 double double_real_val, double_imag_val;
1654 double double_val;
1655 int int_real_val, int_imag_val;
1656 int int_val;
1657
1658 int retval;
1659
1660 gboolean has_sign;
1661 gboolean success;
1662
1663 z = 0.0 + I * 0.0;
1664
1665 ags_complex_set(&this_value,
1666 z);
1667
1668 success = FALSE;
1669
1670 if(coefficient == NULL){
1671 if(value != NULL){
1672 value->real = this_value.real;
1673 value->imag = this_value.imag;
1674 }
1675
1676 return(FALSE);
1677 }
1678
1679 iter =
1680 start_iter = g_strdup(coefficient);
1681
1682 has_sign = FALSE;
1683
1684 /* */
1685 if(!success){
1686 if(!strncmp(iter,
1687 AGS_SYMBOLIC_INFINIT,
1688 strlen(AGS_SYMBOLIC_INFINIT))){
1689 //TODO:JK: implement me
1690 }
1691 }
1692
1693 /* check double _Complex coefficient */
1694 retval = sscanf(iter, "%f+*%f", &double_real_val, &double_imag_val);
1695
1696 if(retval > 0){
1697 z = double_real_val + I * double_imag_val;
1698
1699 success = TRUE;
1700 }
1701
1702 if(!success){
1703 retval = sscanf(iter, "%f-*%f", &double_real_val, &double_imag_val);
1704
1705 if(retval > 0){
1706 z = double_real_val - (I * double_imag_val);
1707
1708 success = TRUE;
1709 }
1710 }
1711
1712 if(!success){
1713 retval = sscanf(iter, "-%f+*%f", &double_real_val, &double_imag_val);
1714
1715 if(retval > 0){
1716 z = (-1.0 * double_real_val) + I * double_imag_val;
1717
1718 success = TRUE;
1719 }
1720 }
1721
1722 if(!success){
1723 retval = sscanf(iter, "-%f-*%f", &double_real_val, &double_imag_val);
1724
1725 if(retval > 0){
1726 z = (-1.0 * double_real_val) - (I * double_imag_val);
1727
1728 success = TRUE;
1729 }
1730 }
1731
1732 /* check int real and double imaginary complex coefficient */
1733 if(!success){
1734 retval = sscanf(iter, "%d+*%f", &int_real_val, &double_imag_val);
1735
1736 if(retval > 0){
1737 z = ((double) int_real_val) + I * double_imag_val;
1738
1739 success = TRUE;
1740 }
1741 }
1742
1743 if(!success){
1744 retval = sscanf(iter, "%d-*%f", &int_real_val, &double_imag_val);
1745
1746 if(retval > 0){
1747 z = ((double) int_real_val) - (I * double_imag_val);
1748
1749 success = TRUE;
1750 }
1751 }
1752
1753 if(!success){
1754 retval = sscanf(iter, "-%d+*%f", &int_real_val, &double_imag_val);
1755
1756 if(retval > 0){
1757 z = (-1.0 * (double) int_real_val) + I * double_imag_val;
1758
1759 success = TRUE;
1760 }
1761 }
1762
1763 if(!success){
1764 retval = sscanf(iter, "-%d-*%f", &int_real_val, &double_imag_val);
1765
1766 if(retval > 0){
1767 z = (-1.0 * (double) int_real_val) - (I * double_imag_val);
1768
1769 success = TRUE;
1770 }
1771 }
1772
1773 /* check double real and int imaginary complex coefficient */
1774 if(!success){
1775 retval = sscanf(iter, "%f+*%d", &double_real_val, &int_imag_val);
1776
1777 if(retval > 0){
1778 z = double_real_val + I * ((double) int_imag_val);
1779
1780 success = TRUE;
1781 }
1782 }
1783
1784 if(!success){
1785 retval = sscanf(iter, "%f-*%d", &double_real_val, &int_imag_val);
1786
1787 if(retval > 0){
1788 z = double_real_val - (I * ((double) int_imag_val));
1789
1790 success = TRUE;
1791 }
1792 }
1793
1794 if(!success){
1795 retval = sscanf(iter, "-%f+*%d", &double_real_val, &int_imag_val);
1796
1797 if(retval > 0){
1798 z = (-1.0 * double_real_val) + I * ((double) int_imag_val);
1799
1800 success = TRUE;
1801 }
1802 }
1803
1804 if(!success){
1805 retval = sscanf(iter, "-%f-*%d", &double_real_val, &int_imag_val);
1806
1807 if(retval > 0){
1808 z = (-1.0 * double_real_val) - (I * ((double) int_imag_val));
1809
1810 success = TRUE;
1811 }
1812 }
1813
1814 if(!success){
1815 if(iter[0] == '+' || iter[0] == '-'){
1816 iter++;
1817
1818 has_sign = TRUE;
1819 }
1820 }
1821
1822 /* check double _Complex coefficient with parenthesis */
1823 if(!success){
1824 retval = sscanf(iter, "(%f+*%f)", &double_real_val, &double_imag_val);
1825
1826 if(retval > 0){
1827 z = double_real_val + I * double_imag_val;
1828
1829 success = TRUE;
1830 }
1831 }
1832
1833 if(!success){
1834 retval = sscanf(iter, "(%f-*%f)", &double_real_val, &double_imag_val);
1835
1836 if(retval > 0){
1837 z = double_real_val - (I * double_imag_val);
1838
1839 success = TRUE;
1840 }
1841 }
1842
1843 if(!success){
1844 retval = sscanf(iter, "(-%f+*%f)", &double_real_val, &double_imag_val);
1845
1846 if(retval > 0){
1847 z = (-1.0 * double_real_val) + I * double_imag_val;
1848
1849 success = TRUE;
1850 }
1851 }
1852
1853 if(!success){
1854 retval = sscanf(iter, "(-%f-*%f)", &double_real_val, &double_imag_val);
1855
1856 if(retval > 0){
1857 z = (-1.0 * double_real_val) - (I * double_imag_val);
1858
1859 success = TRUE;
1860 }
1861 }
1862
1863 /* check int real and double imaginary complex coefficient with parenthesis */
1864 if(!success){
1865 retval = sscanf(iter, "(%d+*%f)", &int_real_val, &double_imag_val);
1866
1867 if(retval > 0){
1868 z = ((double) int_real_val) + I * double_imag_val;
1869
1870 success = TRUE;
1871 }
1872 }
1873
1874 if(!success){
1875 retval = sscanf(iter, "(%d-*%f)", &int_real_val, &double_imag_val);
1876
1877 if(retval > 0){
1878 z = ((double) int_real_val) - (I * double_imag_val);
1879
1880 success = TRUE;
1881 }
1882 }
1883
1884 if(!success){
1885 retval = sscanf(iter, "(-%d+*%f)", &int_real_val, &double_imag_val);
1886
1887 if(retval > 0){
1888 z = (-1.0 * (double) int_real_val) + I * double_imag_val;
1889
1890 success = TRUE;
1891 }
1892 }
1893
1894 if(!success){
1895 retval = sscanf(iter, "(-%d-*%f)", &int_real_val, &double_imag_val);
1896
1897 if(retval > 0){
1898 z = (-1.0 * (double) int_real_val) - (I * double_imag_val);
1899
1900 success = TRUE;
1901 }
1902 }
1903
1904 /* check double real and int imaginary complex coefficient with parenthesis */
1905 if(!success){
1906 retval = sscanf(iter, "(%f+*%d)", &double_real_val, &int_imag_val);
1907
1908 if(retval > 0){
1909 z = double_real_val + I * ((double) int_imag_val);
1910
1911 success = TRUE;
1912 }
1913 }
1914
1915 if(!success){
1916 retval = sscanf(iter, "(%f-*%d)", &double_real_val, &int_imag_val);
1917
1918 if(retval > 0){
1919 z = double_real_val - (I * ((double) int_imag_val));
1920
1921 success = TRUE;
1922 }
1923 }
1924
1925 if(!success){
1926 retval = sscanf(iter, "(-%f+*%d)", &double_real_val, &int_imag_val);
1927
1928 if(retval > 0){
1929 z = (-1.0 * double_real_val) + (I * ((double) int_imag_val));
1930
1931 success = TRUE;
1932 }
1933 }
1934
1935 if(!success){
1936 retval = sscanf(iter, "(-%f-*%d)", &double_real_val, &int_imag_val);
1937
1938 if(retval > 0){
1939 z = (-1.0 * double_real_val) - (I * ((double) int_imag_val));
1940
1941 success = TRUE;
1942 }
1943 }
1944
1945 /* check floating point coefficient */
1946 if(!success){
1947 retval = sscanf(iter, "%f", &double_val);
1948
1949 if(retval > 0){
1950 z = double_val + I * 0.0;
1951
1952 success = TRUE;
1953 }
1954 }
1955
1956 /* check integer coefficient */
1957 if(!success){
1958 retval = sscanf(iter, "%d", &int_val);
1959
1960 if(retval > 0){
1961 z = ((double) int_val) + I * 0.0;
1962
1963 success = TRUE;
1964 }
1965 }
1966
1967 if(success &&
1968 has_sign &&
1969 start_iter[0] == '-'){
1970 z *= -1.0;
1971 }
1972
1973 if(success){
1974 ags_complex_set(&this_value,
1975 z);
1976 }
1977
1978 g_free(start_iter);
1979
1980 if(value != NULL){
1981 value->real = this_value.real;
1982 value->imag = this_value.imag;
1983 }
1984
1985 return(success);
1986 }
1987
1988 /**
1989 * ags_math_util_compute_coefficient_all:
1990 * @coefficient: the coefficients as %NULL termiated string vector
1991 * @value_count: (out) (transfer none): return location of value count
1992 *
1993 * Compute a string vector of coefficients.
1994 *
1995 * Returns: the newly allocated #AgsComplex array of @value_count length, or %NULL
1996 *
1997 * Since: 3.6.0
1998 */
1999 AgsComplex*
ags_math_util_multiply_coefficient_all(gchar ** coefficient,guint * value_count)2000 ags_math_util_multiply_coefficient_all(gchar **coefficient,
2001 guint *value_count)
2002 {
2003 gchar **iter;
2004
2005 guint count;
2006
2007
2008 //TODO:JK: implement me
2009
2010 return(NULL);
2011 }
2012
2013 /**
2014 * ags_math_util_find_function:
2015 * @str: the string
2016 *
2017 * Find next function.
2018 *
2019 * Returns: the string offset matching function, otherwise %NULL
2020 *
2021 * Since: 3.2.0
2022 */
2023 gchar*
ags_math_util_find_function(gchar * str)2024 ags_math_util_find_function(gchar *str)
2025 {
2026 GMatchInfo *function_match_info;
2027
2028 gchar *retval;
2029
2030 GError *error;
2031
2032 static const GRegex *function_regex = NULL;
2033
2034 static const gchar *function_pattern = "(log|exp|sin|cos|tan|asin|acos|atan|floor|ceil|round)";
2035
2036 if(str == NULL){
2037 return(NULL);
2038 }
2039
2040 /* compile regex */
2041 g_mutex_lock(®ex_mutex);
2042
2043 if(function_regex == NULL){
2044 error = NULL;
2045 function_regex = g_regex_new(function_pattern,
2046 (G_REGEX_EXTENDED),
2047 0,
2048 &error);
2049
2050 if(error != NULL){
2051 g_message("%s", error->message);
2052
2053 g_error_free(error);
2054 }
2055 }
2056
2057 g_mutex_unlock(®ex_mutex);
2058
2059 /* find function */
2060 retval = NULL;
2061
2062 g_regex_match(function_regex, str, 0, &function_match_info);
2063
2064 if(g_match_info_matches(function_match_info)){
2065 gint start_pos, end_pos;
2066
2067 g_match_info_fetch_pos(function_match_info,
2068 0,
2069 &start_pos, &end_pos);
2070
2071 retval = str + end_pos;
2072 }
2073
2074 g_match_info_free(function_match_info);
2075
2076 return(retval);
2077 }
2078
2079 /**
2080 * ags_math_util_find_symbol:
2081 * @str: the string
2082 *
2083 * Find next symbol.
2084 *
2085 * Returns: the string offset matching symbol, otherwise %NULL
2086 *
2087 * Since: 3.2.0
2088 */
2089 gchar*
ags_math_util_find_symbol(gchar * str)2090 ags_math_util_find_symbol(gchar *str)
2091 {
2092 GMatchInfo *function_match_info;
2093 GMatchInfo *symbol_match_info;
2094
2095 gchar *retval;
2096 gchar *tmp_str;
2097
2098 gint prev, next;
2099
2100 GError *error;
2101
2102 static const GRegex *function_regex = NULL;
2103 static const GRegex *symbol_regex = NULL;
2104
2105 static const gchar *function_pattern = "(log|exp|sin|cos|tan|asin|acos|atan|floor|ceil|round)";
2106 static const gchar *symbol_pattern = "([a-zA-Z][0-9]*)";
2107
2108 if(str == NULL){
2109 return(NULL);
2110 }
2111
2112 /* compile regex */
2113 g_mutex_lock(®ex_mutex);
2114
2115 if(function_regex == NULL){
2116 error = NULL;
2117 function_regex = g_regex_new(function_pattern,
2118 (G_REGEX_EXTENDED),
2119 0,
2120 &error);
2121
2122 if(error != NULL){
2123 g_message("%s", error->message);
2124
2125 g_error_free(error);
2126 }
2127 }
2128
2129 if(symbol_regex == NULL){
2130 error = NULL;
2131 symbol_regex = g_regex_new(symbol_pattern,
2132 (G_REGEX_EXTENDED),
2133 0,
2134 &error);
2135
2136 if(error != NULL){
2137 g_message("%s", error->message);
2138
2139 g_error_free(error);
2140 }
2141 }
2142
2143 g_mutex_unlock(®ex_mutex);
2144
2145 retval = NULL;
2146
2147 next = -1;
2148 prev = -1;
2149
2150 g_regex_match(function_regex, str, 0, &function_match_info);
2151
2152 while(g_match_info_matches(function_match_info)){
2153 gint function_start_pos, function_end_pos;
2154
2155 tmp_str = NULL;
2156
2157 function_start_pos = -1;
2158 function_end_pos = -1;
2159
2160 g_match_info_fetch_pos(function_match_info,
2161 0,
2162 &function_start_pos, &function_end_pos);
2163
2164 next = function_start_pos;
2165
2166 if(prev == -1){
2167 tmp_str = g_strdup_printf("%*.s",
2168 function_start_pos, str);
2169 }else{
2170 tmp_str = g_strdup_printf("%*.s",
2171 (function_start_pos - prev), str + prev);
2172 }
2173
2174 if(tmp_str != NULL){
2175 g_regex_match(symbol_regex, tmp_str, 0, &symbol_match_info);
2176
2177 if(g_match_info_matches(symbol_match_info)){
2178 gint symbol_start_pos, symbol_end_pos;
2179
2180 g_match_info_fetch_pos(symbol_match_info,
2181 0,
2182 &symbol_start_pos, &symbol_end_pos);
2183
2184 if(prev != -1){
2185 retval = str + prev + symbol_start_pos;
2186 }else{
2187 retval = str + symbol_start_pos;
2188 }
2189 }
2190
2191 g_match_info_free(symbol_match_info);
2192
2193 g_free(tmp_str);
2194 }
2195
2196 if(retval != NULL){
2197 break;
2198 }
2199
2200 prev = next;
2201 next = -1;
2202
2203 g_match_info_next(function_match_info,
2204 NULL);
2205 }
2206
2207 g_match_info_free(function_match_info);
2208
2209 if(retval == NULL){
2210 tmp_str = NULL;
2211
2212 if(prev == -1){
2213 tmp_str = g_strdup(str);
2214 }else{
2215 tmp_str = g_strdup_printf("%*.s",
2216 (strlen(str) - prev), str + prev);
2217 }
2218
2219 if(tmp_str != NULL){
2220 g_regex_match(symbol_regex, tmp_str, 0, &symbol_match_info);
2221
2222 if(g_match_info_matches(symbol_match_info)){
2223 gint symbol_start_pos, symbol_end_pos;
2224
2225 g_match_info_fetch_pos(symbol_match_info,
2226 0,
2227 &symbol_start_pos, &symbol_end_pos);
2228
2229 if(prev != -1){
2230 retval = str + prev + symbol_start_pos;
2231 }else{
2232 retval = str + symbol_start_pos;
2233 }
2234 }
2235
2236 g_match_info_free(symbol_match_info);
2237 }
2238
2239 g_free(tmp_str);
2240 }
2241
2242 return(retval);
2243 }
2244
2245 /**
2246 * ags_math_util_find_symbol_all:
2247 * @str: the string
2248 *
2249 * Find all symbols.
2250 *
2251 * Returns: the string vector containing the symbols
2252 *
2253 * Since: 3.2.0
2254 */
2255 gchar**
ags_math_util_find_symbol_all(gchar * str)2256 ags_math_util_find_symbol_all(gchar *str)
2257 {
2258 GMatchInfo *function_match_info;
2259 GMatchInfo *literal_match_info;
2260
2261 gchar **symbol_arr;
2262
2263 gchar *current_literal;
2264
2265 gint prev, next;
2266 guint n_literals;
2267
2268 GError *error;
2269
2270 static const GRegex *function_regex = NULL;
2271 static const GRegex *literal_regex = NULL;
2272
2273 static const gchar *function_pattern = "(log|exp|sin|cos|tan|asin|acos|atan|floor|ceil|round)|([\\s\\+\\-%\\*\\/\\(\\)\\^\\|\\=])";
2274 static const gchar *literal_pattern = "([a-zA-Z][0-9]*)";
2275
2276 if(str == NULL){
2277 return(NULL);
2278 }
2279
2280 symbol_arr = NULL;
2281
2282 n_literals = 0;
2283
2284 /* compile regex */
2285 g_mutex_lock(®ex_mutex);
2286
2287 if(function_regex == NULL){
2288 error = NULL;
2289 function_regex = g_regex_new(function_pattern,
2290 (G_REGEX_EXTENDED),
2291 0,
2292 &error);
2293
2294 if(error != NULL){
2295 g_message("%s", error->message);
2296
2297 g_error_free(error);
2298 }
2299 }
2300
2301 if(literal_regex == NULL){
2302 error = NULL;
2303 literal_regex = g_regex_new(literal_pattern,
2304 (G_REGEX_EXTENDED),
2305 0,
2306 &error);
2307
2308 if(error != NULL){
2309 g_message("%s", error->message);
2310
2311 g_error_free(error);
2312 }
2313 }
2314
2315 g_mutex_unlock(®ex_mutex);
2316
2317 /* find literals */
2318 g_regex_match(function_regex, str, 0, &function_match_info);
2319
2320 #ifdef AGS_DEBUG
2321 g_message("check %s", str);
2322 #endif
2323
2324 next = -1;
2325 prev = -1;
2326
2327 while(g_match_info_matches(function_match_info)){
2328 gint start_pos, end_pos;
2329
2330 current_literal = NULL;
2331 g_match_info_fetch_pos(function_match_info,
2332 0,
2333 &start_pos, &end_pos);
2334
2335 if(prev == -1){
2336 if(start_pos != 0){
2337 if(next == -1){
2338 current_literal = g_strndup(str,
2339 start_pos);
2340 }else{
2341 if(start_pos - next > 0){
2342 current_literal = g_strndup(str + next,
2343 start_pos - next);
2344 }
2345 }
2346
2347 prev = start_pos;
2348 }
2349
2350 next = end_pos;
2351 }else{
2352 if(start_pos - next > 0){
2353 current_literal = g_strndup(str + next,
2354 start_pos - next);
2355 }
2356
2357 next = end_pos;
2358 prev = start_pos;
2359 }
2360
2361 if(current_literal != NULL){
2362 g_regex_match(literal_regex, current_literal, 0, &literal_match_info);
2363
2364 while(g_match_info_matches(literal_match_info)){
2365 gchar *tmp_literal;
2366
2367 tmp_literal = g_match_info_fetch(literal_match_info,
2368 0);
2369
2370 if(symbol_arr == NULL){
2371 symbol_arr = (gchar **) g_malloc(2 * sizeof(gchar *));
2372
2373 symbol_arr[0] = g_strdup(tmp_literal);
2374 symbol_arr[1] = NULL;
2375
2376 #ifdef AGS_DEBUG
2377 g_message("found %s", symbol_arr[0]);
2378 #endif
2379
2380 n_literals++;
2381 }else{
2382 if(!g_strv_contains(symbol_arr,
2383 tmp_literal)){
2384 symbol_arr = (gchar **) g_realloc(symbol_arr,
2385 (n_literals + 2) * sizeof(gchar *));
2386
2387 symbol_arr[n_literals] = g_strdup(tmp_literal);
2388 symbol_arr[n_literals + 1] = NULL;
2389
2390 #ifdef AGS_DEBUG
2391 g_message("found %s", symbol_arr[n_literals]);
2392 #endif
2393
2394 n_literals++;
2395 }
2396 }
2397
2398 g_match_info_next(literal_match_info,
2399 NULL);
2400 }
2401
2402 g_match_info_free(literal_match_info);
2403
2404 g_free(current_literal);
2405 }
2406
2407 g_match_info_next(function_match_info,
2408 NULL);
2409 }
2410
2411 g_match_info_free(function_match_info);
2412
2413 /* last match */
2414 current_literal = NULL;
2415
2416 if(prev == -1){
2417 if(next == -1){
2418 current_literal = g_strdup(str);
2419 }else{
2420 if(strlen(str) - next > 0){
2421 current_literal = g_strndup(str + next,
2422 strlen(str) - next);
2423 }
2424 }
2425 }else{
2426 if(strlen(str) - next > 0){
2427 current_literal = g_strndup(str + next,
2428 strlen(str) - next);
2429 }
2430 }
2431
2432 if(current_literal != NULL){
2433 g_regex_match(literal_regex, current_literal, 0, &literal_match_info);
2434
2435 while(g_match_info_matches(literal_match_info)){
2436 gchar *tmp_literal;
2437
2438 tmp_literal = g_match_info_fetch(literal_match_info,
2439 0);
2440
2441 if(symbol_arr == NULL){
2442 symbol_arr = (gchar **) g_malloc(2 * sizeof(gchar *));
2443
2444 symbol_arr[0] = g_strdup(tmp_literal);
2445 symbol_arr[1] = NULL;
2446
2447 #ifdef AGS_DEBUG
2448 g_message("found %s", symbol_arr[0]);
2449 #endif
2450
2451 n_literals++;
2452 }else{
2453 if(!g_strv_contains(symbol_arr,
2454 tmp_literal)){
2455 symbol_arr = (gchar **) g_realloc(symbol_arr,
2456 (n_literals + 2) * sizeof(gchar *));
2457
2458 symbol_arr[n_literals] = g_strdup(tmp_literal);
2459 symbol_arr[n_literals + 1] = NULL;
2460
2461 #ifdef AGS_DEBUG
2462 g_message("found %s", symbol_arr[n_literals]);
2463 #endif
2464
2465 n_literals++;
2466 }
2467 }
2468
2469 g_match_info_next(literal_match_info,
2470 NULL);
2471 }
2472
2473 g_match_info_free(literal_match_info);
2474
2475 g_free(current_literal);
2476 }
2477
2478 return(symbol_arr);
2479 }
2480
2481 /**
2482 * ags_math_util_is_term:
2483 * @term: the term
2484 *
2485 * Test if @term is a term.
2486 *
2487 * Returns: %TRUE on success, otherwise %FALSE
2488 *
2489 * Since: 3.2.0
2490 */
2491 gboolean
ags_math_util_is_term(gchar * term)2492 ags_math_util_is_term(gchar *term)
2493 {
2494 //TODO:JK: implement me
2495
2496 return(FALSE);
2497 }
2498
2499 /**
2500 * ags_math_util_rewrite_numeric:
2501 * @numeric_str: the numeric string
2502 *
2503 * Rewrite numeric string.
2504 *
2505 * Returns: the optimized string vector
2506 *
2507 * Since: 3.2.0
2508 */
2509 gchar**
ags_math_util_rewrite_numeric(gchar * numeric_str,gboolean preserve_constants)2510 ags_math_util_rewrite_numeric(gchar *numeric_str,
2511 gboolean preserve_constants)
2512 {
2513 //TODO:JK: implement me
2514
2515 return(NULL);
2516 }
2517
2518 /**
2519 * ags_math_util_split_polynomial:
2520 * @polynomial: the polynomial
2521 * @factor: (out): the return location of factors
2522 * @factor_exponent: (out): the return location of factor exponents
2523 *
2524 * Split @polynomial into coefficient, powers of symbols and summand.
2525 *
2526 * Since: 3.2.0
2527 */
2528 void
ags_math_util_split_polynomial(gchar * polynomial,gchar *** factor,gchar *** factor_exponent)2529 ags_math_util_split_polynomial(gchar *polynomial,
2530 gchar ***factor, gchar ***factor_exponent)
2531 {
2532 GMatchInfo *sign_match_info;
2533 GMatchInfo *multiply_match_info;
2534 GMatchInfo *numeric_match_info;
2535 GMatchInfo *constants_match_info;
2536 GMatchInfo *exponent_match_info;
2537 GMatchInfo *symbol_match_info;
2538
2539 gchar **numeric_factor;
2540 gchar **numeric_factor_exponent;
2541 gchar **symbol_factor;
2542 gchar **symbol_factor_exponent;
2543 gchar *polynomial_sign;
2544
2545 gchar *iter;
2546
2547 guint factor_length;
2548 guint i, j;
2549 gboolean has_function;
2550 gboolean has_symbol;
2551 gboolean success;
2552
2553 GError *error;
2554
2555 static const GRegex *sign_regex = NULL;
2556 static const GRegex *multiply_regex = NULL;
2557 static const GRegex *numeric_regex = NULL;
2558 static const GRegex *constants_regex = NULL;
2559 static const GRegex *exponent_regex = NULL;
2560 static const GRegex *symbol_regex = NULL;
2561
2562 /* groups: #1 sign */
2563 static const gchar *sign_pattern = "^[\\s]*([\\+\\-])";
2564
2565 /* groups: #1 multiply */
2566 static const gchar *multiply_pattern = "^[\\s]*([\\*])";
2567
2568 /* groups: #1-2 numeric base and fraction, */
2569 static const gchar *numeric_pattern = "^[\\s]*([0-9]+(\\.[0-9]+)?)";
2570
2571 /* groups: #1 constants */
2572 static const gchar *constants_pattern = "^[\\s]*([ℯ∞])";
2573
2574 /* groups: #1 exponent operator, #2 exponent */
2575 static const gchar *exponent_pattern = "^[\\s]*(\\^)[\\s]*(\\([^)(]*+(?:(?R)[^)(]*)*+\\))";
2576
2577 /* groups: #1 symbol */
2578 static const gchar *symbol_pattern = "^[\\s]*([a-zA-Z][0-9]*)";
2579
2580 if(polynomial == NULL){
2581 goto ags_math_util_split_polynomial_RETURN_NULL;
2582 }
2583
2584 has_function = (ags_math_util_find_function(polynomial) != NULL) ? TRUE: FALSE;
2585
2586 if(has_function){
2587 g_critical("polynomial contains function, rewrite first");
2588
2589 goto ags_math_util_split_polynomial_RETURN_NULL;
2590 }
2591
2592 numeric_factor = NULL;
2593 numeric_factor_exponent = NULL;
2594
2595 symbol_factor = NULL;
2596 symbol_factor_exponent = NULL;
2597
2598 polynomial_sign = NULL;
2599
2600 iter = NULL;
2601
2602 factor_length = 0;
2603
2604 has_function = FALSE;
2605 has_symbol = FALSE;
2606
2607 /* compile regex */
2608 g_mutex_lock(®ex_mutex);
2609
2610 if(sign_regex == NULL){
2611 error = NULL;
2612 sign_regex = g_regex_new(sign_pattern,
2613 (G_REGEX_EXTENDED),
2614 0,
2615 &error);
2616
2617 if(error != NULL){
2618 g_message("%s", error->message);
2619
2620 g_error_free(error);
2621 }
2622 }
2623
2624 if(multiply_regex == NULL){
2625 error = NULL;
2626 multiply_regex = g_regex_new(multiply_pattern,
2627 (G_REGEX_EXTENDED),
2628 0,
2629 &error);
2630
2631 if(error != NULL){
2632 g_message("%s", error->message);
2633
2634 g_error_free(error);
2635 }
2636 }
2637
2638 if(numeric_regex == NULL){
2639 error = NULL;
2640 numeric_regex = g_regex_new(numeric_pattern,
2641 (G_REGEX_EXTENDED),
2642 0,
2643 &error);
2644
2645 if(error != NULL){
2646 g_message("%s", error->message);
2647
2648 g_error_free(error);
2649 }
2650 }
2651
2652 if(constants_regex == NULL){
2653 error = NULL;
2654 constants_regex = g_regex_new(constants_pattern,
2655 (G_REGEX_EXTENDED),
2656 0,
2657 &error);
2658
2659 if(error != NULL){
2660 g_message("%s", error->message);
2661
2662 g_error_free(error);
2663 }
2664 }
2665
2666 if(exponent_regex == NULL){
2667 error = NULL;
2668 exponent_regex = g_regex_new(exponent_pattern,
2669 (G_REGEX_EXTENDED),
2670 0,
2671 &error);
2672
2673 if(error != NULL){
2674 g_message("%s", error->message);
2675
2676 g_error_free(error);
2677 }
2678 }
2679
2680 if(symbol_regex == NULL){
2681 error = NULL;
2682 symbol_regex = g_regex_new(symbol_pattern,
2683 (G_REGEX_EXTENDED),
2684 0,
2685 &error);
2686
2687 if(error != NULL){
2688 g_message("%s", error->message);
2689
2690 g_error_free(error);
2691 }
2692 }
2693
2694 g_mutex_unlock(®ex_mutex);
2695
2696 has_symbol = (ags_math_util_find_symbol(polynomial) != NULL) ? TRUE: FALSE;
2697
2698 /* match sign */
2699 iter = polynomial;
2700
2701 polynomial_sign = NULL;
2702
2703 g_regex_match(sign_regex, iter, 0, &sign_match_info);
2704
2705 if(g_match_info_matches(sign_match_info)){
2706 gchar *sign_group_0;
2707 gchar *sign_group_1;
2708
2709 sign_group_0 = g_match_info_fetch(sign_match_info,
2710 0);
2711 sign_group_1 = g_match_info_fetch(sign_match_info,
2712 1);
2713
2714 polynomial_sign = sign_group_1;
2715
2716 iter += strlen(sign_group_0);
2717
2718 g_match_info_free(sign_match_info);
2719
2720 g_free(sign_group_0);
2721 }else{
2722 polynomial_sign = g_strdup("+");
2723 }
2724
2725 /* match numeric or constants including exponent */
2726 success = TRUE;
2727
2728 i = 0;
2729
2730 while(success){
2731 gboolean multiply_success, numeric_success, constants_success, exponent_success;
2732
2733 multiply_success = FALSE;
2734 numeric_success = FALSE;
2735 constants_success = FALSE;
2736 exponent_success = FALSE;
2737
2738 /* mulitply */
2739 if(numeric_factor != NULL){
2740 g_regex_match(multiply_regex, iter, 0, &multiply_match_info);
2741
2742 if(g_match_info_matches(multiply_match_info)){
2743 gint start_pos, end_pos;
2744
2745 g_match_info_fetch_pos(multiply_match_info,
2746 0,
2747 &start_pos,
2748 &end_pos);
2749
2750 multiply_success = TRUE;
2751
2752 iter += end_pos;
2753 }
2754
2755 g_match_info_free(multiply_match_info);
2756 }
2757
2758 /* numeric */
2759 g_regex_match(numeric_regex, iter, 0, &numeric_match_info);
2760
2761 if(g_match_info_matches(numeric_match_info)){
2762 gchar *numeric_group_0;
2763 gchar *numeric_group_1;
2764
2765 numeric_group_0 = g_match_info_fetch(numeric_match_info,
2766 0);
2767 numeric_group_1 = g_match_info_fetch(numeric_match_info,
2768 1);
2769
2770 if(numeric_factor == NULL){
2771 numeric_factor = (gchar **) g_malloc(2 * sizeof(gchar *));
2772 numeric_factor_exponent = (gchar **) g_malloc(2 * sizeof(gchar *));
2773 }else{
2774 numeric_factor = (gchar **) g_realloc(numeric_factor,
2775 (i + 2) * sizeof(gchar *));
2776 numeric_factor_exponent = (gchar **) g_realloc(numeric_factor_exponent,
2777 (i + 2) * sizeof(gchar *));
2778 }
2779
2780 numeric_factor[i] = numeric_group_1;
2781 numeric_factor[i + 1] = NULL;
2782
2783 iter += strlen(numeric_group_0);
2784
2785 numeric_success = TRUE;
2786
2787 g_free(numeric_group_0);
2788 }
2789
2790 g_match_info_free(numeric_match_info);
2791
2792 /* constants */
2793 if(!numeric_success){
2794 g_regex_match(constants_regex, iter, 0, &constants_match_info);
2795
2796 if(g_match_info_matches(constants_match_info)){
2797 gchar *constants_group_0;
2798 gchar *constants_group_1;
2799
2800 constants_group_0 = g_match_info_fetch(constants_match_info,
2801 0);
2802 constants_group_1 = g_match_info_fetch(constants_match_info,
2803 1);
2804
2805
2806 if(numeric_factor == NULL){
2807 numeric_factor = (gchar **) g_malloc(2 * sizeof(gchar *));
2808 numeric_factor_exponent = (gchar **) g_malloc(2 * sizeof(gchar *));
2809 }else{
2810 numeric_factor = (gchar **) g_realloc(numeric_factor,
2811 (i + 2) * sizeof(gchar *));
2812 numeric_factor_exponent = (gchar **) g_realloc(numeric_factor_exponent,
2813 (i + 2) * sizeof(gchar *));
2814 }
2815
2816 numeric_factor[i] = constants_group_1;
2817 numeric_factor[i + 1] = NULL;
2818
2819 iter += strlen(constants_group_0);
2820
2821 constants_success = TRUE;
2822
2823 g_free(constants_group_0);
2824 }
2825
2826 g_match_info_free(constants_match_info);
2827 }
2828
2829 /* exponent */
2830 if(numeric_success ||
2831 constants_success){
2832 g_regex_match(exponent_regex, iter, 0, &exponent_match_info);
2833
2834 if(g_match_info_matches(exponent_match_info)){
2835 gchar *exponent_group_0;
2836 gchar *exponent_group_2;
2837
2838 exponent_group_0 = g_match_info_fetch(exponent_match_info,
2839 0);
2840 exponent_group_2 = g_match_info_fetch(exponent_match_info,
2841 2);
2842
2843 numeric_factor_exponent[i] = g_strndup(exponent_group_2 + 1,
2844 strlen(exponent_group_2) - 2);
2845 numeric_factor_exponent[i + 1] = NULL;
2846
2847 iter += strlen(exponent_group_0);
2848
2849 exponent_success = TRUE;
2850
2851 g_free(exponent_group_0);
2852 g_free(exponent_group_2);
2853 }
2854
2855 g_match_info_free(exponent_match_info);
2856 }
2857
2858 if((numeric_success ||
2859 constants_success) &&
2860 !exponent_success){
2861 numeric_factor_exponent[i] = g_strdup("1");
2862 numeric_factor_exponent[i + 1] = NULL;
2863 }
2864
2865 /* check success */
2866 if(!numeric_success &&
2867 !constants_success){
2868 success = FALSE;
2869 }
2870
2871 /* iterate */
2872 i++;
2873 }
2874
2875 /* match numeric or constants including exponent */
2876 if(has_symbol){
2877 success = TRUE;
2878
2879 i = 0;
2880
2881 while(success){
2882 gboolean multiply_success, symbol_success, exponent_success;
2883
2884 multiply_success = FALSE;
2885 symbol_success = FALSE;
2886 exponent_success = FALSE;
2887
2888 /* mulitply */
2889 if(numeric_factor != NULL ||
2890 symbol_factor != NULL){
2891 g_regex_match(multiply_regex, iter, 0, &multiply_match_info);
2892
2893 if(g_match_info_matches(multiply_match_info)){
2894 gint start_pos, end_pos;
2895
2896 g_match_info_fetch_pos(multiply_match_info,
2897 0,
2898 &start_pos,
2899 &end_pos);
2900
2901 multiply_success = TRUE;
2902
2903 iter += end_pos;
2904 }
2905
2906 g_match_info_free(multiply_match_info);
2907 }
2908
2909 /* symbol */
2910 g_regex_match(symbol_regex, iter, 0, &symbol_match_info);
2911
2912 if(g_match_info_matches(symbol_match_info)){
2913 gchar *symbol_group_0;
2914 gchar *symbol_group_1;
2915
2916 symbol_group_0 = g_match_info_fetch(symbol_match_info,
2917 0);
2918 symbol_group_1 = g_match_info_fetch(symbol_match_info,
2919 1);
2920
2921
2922 if(symbol_factor == NULL){
2923 symbol_factor = (gchar **) g_malloc(2 * sizeof(gchar *));
2924 symbol_factor_exponent = (gchar **) g_malloc(2 * sizeof(gchar *));
2925 }else{
2926 symbol_factor = (gchar **) g_realloc(symbol_factor,
2927 (i + 2) * sizeof(gchar *));
2928 symbol_factor_exponent = (gchar **) g_realloc(symbol_factor_exponent,
2929 (i + 2) * sizeof(gchar *));
2930 }
2931
2932 symbol_factor[i] = symbol_group_1;
2933 symbol_factor[i + 1] = NULL;
2934
2935 iter += strlen(symbol_group_0);
2936
2937 symbol_success = TRUE;
2938
2939 g_free(symbol_group_0);
2940 }
2941
2942 g_match_info_free(symbol_match_info);
2943
2944 /* exponent */
2945 if(symbol_success){
2946 g_regex_match(exponent_regex, iter, 0, &exponent_match_info);
2947
2948 if(g_match_info_matches(exponent_match_info)){
2949 gchar *exponent_group_0;
2950 gchar *exponent_group_2;
2951
2952 exponent_group_0 = g_match_info_fetch(exponent_match_info,
2953 0);
2954 exponent_group_2 = g_match_info_fetch(exponent_match_info,
2955 2);
2956
2957 symbol_factor_exponent[i] = g_strndup(exponent_group_2 + 1,
2958 strlen(exponent_group_2) - 2);
2959 symbol_factor_exponent[i + 1] = NULL;
2960
2961 iter += strlen(exponent_group_0);
2962
2963 exponent_success = TRUE;
2964
2965 g_free(exponent_group_0);
2966 g_free(exponent_group_2);
2967 }
2968
2969 g_match_info_free(exponent_match_info);
2970 }
2971
2972 if(symbol_success &&
2973 !exponent_success){
2974 symbol_factor_exponent[i] = g_strdup("1");
2975 symbol_factor_exponent[i + 1] = NULL;
2976 }
2977
2978 /* check success */
2979 if(!symbol_success){
2980 success = FALSE;
2981 }
2982
2983 /* iterate */
2984 i++;
2985 }
2986 }
2987
2988 factor_length = 0;
2989
2990 factor_length += ((numeric_factor != NULL) ? (g_strv_length(numeric_factor)): 0);
2991 factor_length += ((symbol_factor != NULL) ? (g_strv_length(symbol_factor)): 0);
2992
2993 if(factor_length > 0){
2994 gboolean first_success;
2995
2996 first_success = TRUE;
2997
2998 if(!g_ascii_strncasecmp(polynomial_sign, "-", 1)){
2999 first_success = FALSE;
3000 }
3001
3002 if(factor != NULL){
3003 factor[0] = (gchar **) g_malloc((factor_length + 1) * sizeof(gchar *));
3004
3005 i = 0;
3006
3007 if(numeric_factor != NULL){
3008 for(j = 0; numeric_factor[j] != NULL; j++, i++){
3009 if(!first_success){
3010 factor[0][i] = g_strdup_printf("-%s",
3011 numeric_factor[j]);
3012
3013 g_free(numeric_factor[j]);
3014
3015 first_success = TRUE;
3016 }else{
3017 factor[0][i] = numeric_factor[j];
3018 }
3019 }
3020
3021 g_free(numeric_factor);
3022 }
3023
3024 if(symbol_factor != NULL){
3025 for(j = 0; symbol_factor[j] != NULL; j++, i++){
3026 if(!first_success){
3027 factor[0][i] = g_strdup_printf("-%s",
3028 symbol_factor[j]);
3029
3030 g_free(symbol_factor[j]);
3031
3032 first_success = TRUE;
3033 }else{
3034 factor[0][i] = symbol_factor[j];
3035 }
3036 }
3037
3038 g_free(symbol_factor);
3039 }
3040
3041 factor[0][factor_length] = NULL;
3042 }
3043
3044 if(factor_exponent != NULL){
3045 factor_exponent[0] = (gchar **) g_malloc((factor_length + 1) * sizeof(gchar *));
3046
3047 i = 0;
3048
3049 if(numeric_factor_exponent != NULL){
3050 for(j = 0; numeric_factor_exponent[j] != NULL; j++, i++){
3051 factor_exponent[0][i] = numeric_factor_exponent[j];
3052 }
3053
3054 g_free(numeric_factor_exponent);
3055 }
3056
3057 if(symbol_factor_exponent != NULL){
3058 for(j = 0; symbol_factor_exponent[j] != NULL; j++, i++){
3059 factor_exponent[0][i] = symbol_factor_exponent[j];
3060 }
3061
3062 g_free(symbol_factor_exponent);
3063 }
3064
3065 factor_exponent[0][factor_length] = NULL;
3066 }
3067
3068 return;
3069 }
3070
3071 /* return NULL */
3072 ags_math_util_split_polynomial_RETURN_NULL:
3073 if(factor != NULL){
3074 factor[0] = NULL;
3075 }
3076
3077 if(factor_exponent != NULL){
3078 factor_exponent[0] = NULL;
3079 }
3080 }
3081
3082 /**
3083 * ags_math_util_split_sum:
3084 * @sum: the sum
3085 * @summand: (out): the return location of summands
3086 *
3087 * Split @sum into summands.
3088 *
3089 * Since: 3.2.0
3090 */
3091 void
ags_math_util_split_sum(gchar * sum,gchar *** summand)3092 ags_math_util_split_sum(gchar *sum,
3093 gchar ***summand)
3094 {
3095 GMatchInfo *operator_match_info;
3096 GMatchInfo *numeric_match_info;
3097 GMatchInfo *symbol_match_info;
3098 GMatchInfo *exponent_match_info;
3099
3100 gchar **polynomial_summand;
3101
3102 gchar *iter;
3103 gchar *prev;
3104
3105 gint open_parenthesis, close_parenthesis;
3106 gint power;
3107 gint constants;
3108 gint numeric;
3109 gint symbol;
3110 guint i;
3111 gboolean has_function;
3112 gboolean success;
3113
3114 GError *error;
3115
3116 static const GRegex *operator_regex = NULL;
3117 static const GRegex *numeric_regex = NULL;
3118 static const GRegex *symbol_regex = NULL;
3119 static const GRegex *exponent_regex = NULL;
3120
3121 /* groups: #1 operator */
3122 static const gchar *operator_pattern = "^[\\s]*([\\+\\-])";
3123
3124 /* groups: #1-2 numeric base and fraction, */
3125 static const gchar *numeric_pattern = "^([0-9]+(\\.[0-9]+)?)";
3126
3127 /* groups: #1 symbol */
3128 static const gchar *symbol_pattern = "^([a-zA-Z][0-9]*)";
3129
3130 /* groups: #1 exponent operator, #2 exponent */
3131 static const gchar *exponent_pattern = "^(\\^)[\\s]*(\\([^)(]*+(?:(?R)[^)(]*)*+\\))";
3132
3133 if(sum == NULL){
3134 goto ags_math_util_split_sum_RETURN_NULL;
3135 }
3136
3137 has_function = (ags_math_util_find_function(sum) != NULL) ? TRUE: FALSE;
3138
3139 if(has_function){
3140 g_critical("sum contains function, rewrite first");
3141
3142 goto ags_math_util_split_sum_RETURN_NULL;
3143 }
3144
3145 /* compile regex */
3146 g_mutex_lock(®ex_mutex);
3147
3148 if(operator_regex == NULL){
3149 error = NULL;
3150 operator_regex = g_regex_new(operator_pattern,
3151 (G_REGEX_EXTENDED),
3152 0,
3153 &error);
3154
3155 if(error != NULL){
3156 g_message("%s", error->message);
3157
3158 g_error_free(error);
3159 }
3160 }
3161
3162 if(numeric_regex == NULL){
3163 error = NULL;
3164 numeric_regex = g_regex_new(numeric_pattern,
3165 (G_REGEX_EXTENDED),
3166 0,
3167 &error);
3168
3169 if(error != NULL){
3170 g_message("%s", error->message);
3171
3172 g_error_free(error);
3173 }
3174 }
3175
3176 if(symbol_regex == NULL){
3177 error = NULL;
3178 symbol_regex = g_regex_new(symbol_pattern,
3179 (G_REGEX_EXTENDED),
3180 0,
3181 &error);
3182
3183 if(error != NULL){
3184 g_message("%s", error->message);
3185
3186 g_error_free(error);
3187 }
3188 }
3189
3190 if(exponent_regex == NULL){
3191 error = NULL;
3192 exponent_regex = g_regex_new(exponent_pattern,
3193 (G_REGEX_EXTENDED),
3194 0,
3195 &error);
3196
3197 if(error != NULL){
3198 g_message("%s", error->message);
3199
3200 g_error_free(error);
3201 }
3202 }
3203
3204 g_mutex_unlock(®ex_mutex);
3205
3206 polynomial_summand = NULL;
3207
3208 iter =
3209 prev = sum;
3210
3211 open_parenthesis = 0;
3212 close_parenthesis = 0;
3213
3214 power = 0;
3215
3216 numeric = 0;
3217 constants = 0;
3218 symbol = 0;
3219
3220 i = 0;
3221
3222 success = TRUE;
3223
3224 while(success){
3225 gchar *tmp_iter;
3226
3227 gint operator_start_pos, operator_end_pos;
3228
3229 gboolean found_polynomial;
3230 gboolean operator_success;
3231 gboolean polynomial_success;
3232
3233 operator_start_pos = -1;
3234 operator_end_pos = -1;
3235
3236 operator_success = FALSE;
3237 polynomial_success = FALSE;
3238
3239 /* operator */
3240 g_regex_match(operator_regex, iter, 0, &operator_match_info);
3241
3242 if(g_match_info_matches(operator_match_info)){
3243 g_match_info_fetch_pos(operator_match_info,
3244 0,
3245 &operator_start_pos,
3246 &operator_end_pos);
3247
3248 operator_success = TRUE;
3249 }
3250
3251 g_match_info_free(operator_match_info);
3252
3253 /* scan parenthesis */
3254 found_polynomial = FALSE;
3255
3256 for(tmp_iter = iter; tmp_iter < iter + operator_start_pos; tmp_iter++){
3257 if((tmp_iter[0] >= 'a' && tmp_iter[0] <= 'z') ||
3258 (tmp_iter[0] >= 'A' && tmp_iter[0] <= 'Z')){
3259 g_regex_match(symbol_regex, tmp_iter, 0, &symbol_match_info);
3260
3261 if(g_match_info_matches(symbol_match_info)){
3262 gint start_pos, end_pos;
3263
3264 start_pos = -1;
3265 end_pos = -1;
3266
3267 g_match_info_fetch_pos(symbol_match_info,
3268 0,
3269 &start_pos,
3270 &end_pos);
3271
3272 tmp_iter += (end_pos - 1);
3273 }
3274
3275 g_match_info_free(symbol_match_info);
3276
3277 symbol++;
3278
3279 found_polynomial = TRUE;
3280 }else if(tmp_iter[0] >= '0' && tmp_iter[0] <= '9'){
3281 g_regex_match(numeric_regex, tmp_iter, 0, &numeric_match_info);
3282
3283 if(g_match_info_matches(numeric_match_info)){
3284 gint start_pos, end_pos;
3285
3286 g_match_info_fetch_pos(numeric_match_info,
3287 0,
3288 &start_pos,
3289 &end_pos);
3290
3291 tmp_iter += (end_pos - 1);
3292 }
3293
3294 g_match_info_free(numeric_match_info);
3295
3296 numeric++;
3297
3298 found_polynomial = TRUE;
3299 }else if(!g_ascii_strncasecmp(tmp_iter,
3300 AGS_SYMBOLIC_EULER,
3301 strlen(AGS_SYMBOLIC_EULER))){
3302 constants++;
3303
3304 found_polynomial = TRUE;
3305
3306 tmp_iter += (strlen(AGS_SYMBOLIC_EULER) - 1);
3307 }else if(!g_ascii_strncasecmp(tmp_iter,
3308 AGS_SYMBOLIC_PI,
3309 strlen(AGS_SYMBOLIC_PI))){
3310 constants++;
3311
3312 found_polynomial = TRUE;
3313
3314 tmp_iter += (strlen(AGS_SYMBOLIC_PI) - 1);
3315 }else if(!g_ascii_strncasecmp(tmp_iter,
3316 AGS_SYMBOLIC_COMPLEX_UNIT,
3317 strlen(AGS_SYMBOLIC_COMPLEX_UNIT))){
3318 constants++;
3319
3320 found_polynomial = TRUE;
3321
3322 tmp_iter += (strlen(AGS_SYMBOLIC_COMPLEX_UNIT) - 1);
3323 }else if(tmp_iter[0] == '('){
3324 open_parenthesis++;
3325 }else if(tmp_iter[0] == ')'){
3326 close_parenthesis++;
3327 }else if(tmp_iter[0] == '^'){
3328 g_regex_match(exponent_regex, tmp_iter, 0, &exponent_match_info);
3329
3330 if(g_match_info_matches(exponent_match_info)){
3331 gint start_pos, end_pos;
3332
3333 start_pos = -1;
3334 end_pos = -1;
3335
3336 g_match_info_fetch_pos(exponent_match_info,
3337 0,
3338 &start_pos,
3339 &end_pos);
3340
3341 tmp_iter += (end_pos - 1);
3342 }
3343
3344 g_match_info_free(exponent_match_info);
3345
3346 power++;
3347 }
3348
3349 if((symbol > 0 ||
3350 numeric > 0 ||
3351 constants > 0) &&
3352 open_parenthesis == close_parenthesis){
3353 polynomial_success = TRUE;
3354
3355 break;
3356 }
3357 }
3358
3359 if(polynomial_success){
3360 if(prev != sum){
3361 polynomial_summand = (gchar **) g_realloc(polynomial_summand,
3362 (i + 2) * sizeof(gchar *));
3363 }else{
3364 polynomial_summand = (gchar **) g_malloc(2 * sizeof(gchar *));
3365 }
3366
3367 if(operator_success){
3368 polynomial_summand[i] = g_strdup_printf("%*.s",
3369 operator_start_pos, prev);
3370 }else{
3371 polynomial_summand[i] = g_strdup(sum);
3372
3373 success = FALSE;
3374 }
3375
3376 polynomial_summand[i + 1] = NULL;
3377
3378 if(operator_success){
3379 iter += operator_end_pos;
3380 }
3381
3382 prev = iter;
3383
3384 i++;
3385 }else{
3386 iter += operator_end_pos;
3387 }
3388 }
3389
3390 if(summand != NULL){
3391 summand[0] = polynomial_summand;
3392 }
3393
3394 /* return NULL */
3395 ags_math_util_split_sum_RETURN_NULL:
3396
3397 if(summand != NULL){
3398 summand[0] = NULL;
3399 }
3400 }
3401