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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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(&regex_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