1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <string.h>
6 #include <ctype.h>
7 #include <limits.h>
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <math.h>
14
15 #include "edje_cc.h"
16 #include <Ecore.h>
17 #include <Ecore_File.h>
18
19 #ifdef _WIN32
20 # define EPP_EXT ".exe"
21 #else
22 # define EPP_EXT
23 #endif
24
25 #define SKIP_NAMESPACE_VALIDATION_SUPPORTED " -DSKIP_NAMESPACE_VALIDATION=1 "
26
27 #define EDJE_1_18_SUPPORTED " -DEFL_VERSION_1_18=1 "
28 #define EDJE_1_19_SUPPORTED " -DEFL_VERSION_1_19=1 "
29 #define EDJE_1_20_SUPPORTED " -DEFL_VERSION_1_20=1 "
30 #define EDJE_1_21_SUPPORTED " -DEFL_VERSION_1_21=1 "
31 #define EDJE_1_22_SUPPORTED " -DEFL_VERSION_1_22=1 "
32 #define EDJE_1_23_SUPPORTED " -DEFL_VERSION_1_23=1 "
33 #define EDJE_1_24_SUPPORTED " -DEFL_VERSION_1_24=1 "
34 #define EDJE_1_25_SUPPORTED " -DEFL_VERSION_1_25=1 "
35
36 #define EDJE_CC_EFL_VERSION_SUPPORTED \
37 EDJE_1_18_SUPPORTED \
38 EDJE_1_19_SUPPORTED \
39 EDJE_1_20_SUPPORTED \
40 EDJE_1_21_SUPPORTED \
41 EDJE_1_22_SUPPORTED \
42 EDJE_1_23_SUPPORTED \
43 EDJE_1_24_SUPPORTED \
44 EDJE_1_25_SUPPORTED
45
46 static void new_object(void);
47 static void new_statement(void);
48 static char *perform_math(char *input);
49 static int isdelim(char c);
50 static char *next_token(char *p, char *end, char **new_p, int *delim);
51 static const char *stack_id(void);
52 static void parse(char *data, off_t size);
53
54 /* simple expression parsing protos */
55 static int my_atoi(const char *s);
56 static char *_alphai(char *s, int *val);
57 static char *_betai(char *s, int *val);
58 static char *_gammai(char *s, int *val);
59 static char *_deltai(char *s, int *val);
60 static char *_get_numi(char *s, int *val);
61 static int _is_numi(char c);
62 static int _is_op1i(char c);
63 static int _is_op2i(char c);
64 static int _calci(char op, int a, int b);
65
66 static double my_atof(const char *s);
67 static char *_alphaf(char *s, double *val);
68 static char *_betaf(char *s, double *val);
69 static char *_gammaf(char *s, double *val);
70 static char *_deltaf(char *s, double *val);
71 static char *_get_numf(char *s, double *val);
72 static int _is_numf(char c);
73 static int _is_op1f(char c);
74 static int _is_op2f(char c);
75 static double _calcf(char op, double a, double b);
76 static int strstrip(const char *in, char *out, size_t size);
77
78 int line = 0;
79 Eina_List *stack = NULL;
80 Eina_Array params;
81 int had_quote = 0;
82 int params_quote = 0;
83
84 static char file_buf[4096];
85 static int did_wildcard = 0;
86 static int verbatim = 0;
87 static int verbatim_line1 = 0;
88 static int verbatim_line2 = 0;
89 static char *verbatim_str = NULL;
90 static Eina_Strbuf *stack_buf = NULL;
91
92 static void
err_show_stack(void)93 err_show_stack(void)
94 {
95 const char *s;
96
97 s = stack_id();
98 if (s)
99 ERR("PARSE STACK:\n%s", s);
100 else
101 ERR("NO PARSE STACK");
102 }
103
104 static void
err_show_params(void)105 err_show_params(void)
106 {
107 Eina_Array_Iterator iterator;
108 unsigned int i;
109 char *p;
110
111 ERR("PARAMS:");
112 EINA_ARRAY_ITER_NEXT(¶ms, i, p, iterator)
113 {
114 ERR(" %s", p);
115 }
116 }
117
118 static void
err_show(void)119 err_show(void)
120 {
121 err_show_stack();
122 err_show_params();
123 }
124
125 static char *
_parse_param_get(int n)126 _parse_param_get(int n)
127 {
128 if (n < (int)eina_array_count(¶ms))
129 return eina_array_data_get(¶ms, n);
130 return NULL;
131 }
132
133 static Eina_Hash *_new_object_hash = NULL;
134 static Eina_Hash *_new_object_short_hash = NULL;
135 static Eina_Hash *_new_statement_hash = NULL;
136 static Eina_Hash *_new_statement_short_hash = NULL;
137 static Eina_Hash *_new_statement_short_single_hash = NULL;
138 static Eina_Hash *_new_nested_hash = NULL;
139 static Eina_Hash *_new_nested_short_hash = NULL;
140 static void
fill_object_statement_hashes(void)141 fill_object_statement_hashes(void)
142 {
143 int i, n;
144
145 if (_new_object_hash) return;
146
147 _new_object_hash = eina_hash_string_superfast_new(NULL);
148 _new_object_short_hash = eina_hash_string_superfast_new(NULL);
149 _new_statement_hash = eina_hash_string_superfast_new(NULL);
150 _new_statement_short_hash = eina_hash_string_superfast_new(NULL);
151 _new_statement_short_single_hash = eina_hash_string_superfast_new(NULL);
152 _new_nested_hash = eina_hash_string_superfast_new(NULL);
153 _new_nested_short_hash = eina_hash_string_superfast_new(NULL);
154
155 n = object_handler_num();
156 for (i = 0; i < n; i++)
157 {
158 eina_hash_direct_add(_new_object_hash, object_handlers[i].type,
159 &(object_handlers[i]));
160 }
161 n = object_handler_short_num();
162 for (i = 0; i < n; i++)
163 {
164 eina_hash_direct_add(_new_object_short_hash, object_handlers_short[i].type,
165 &(object_handlers_short[i]));
166 }
167 n = statement_handler_num();
168 for (i = 0; i < n; i++)
169 {
170 eina_hash_direct_add(_new_statement_hash, statement_handlers[i].type,
171 &(statement_handlers[i]));
172 }
173 n = statement_handler_short_num();
174 for (i = 0; i < n; i++)
175 {
176 eina_hash_direct_add(_new_statement_short_hash, statement_handlers_short[i].type,
177 &(statement_handlers_short[i]));
178 }
179 n = statement_handler_short_single_num();
180 for (i = 0; i < n; i++)
181 {
182 eina_hash_direct_add(_new_statement_short_single_hash, statement_handlers_short_single[i].type,
183 &(statement_handlers_short_single[i]));
184 }
185 n = nested_handler_num();
186 for (i = 0; i < n; i++)
187 {
188 eina_hash_direct_add(_new_nested_hash, nested_handlers[i].type,
189 &(nested_handlers[i]));
190 }
191 n = nested_handler_short_num();
192 for (i = 0; i < n; i++)
193 {
194 eina_hash_direct_add(_new_nested_short_hash, nested_handlers_short[i].type,
195 &(nested_handlers_short[i]));
196 }
197 }
198
199 static char *
stack_dup_wildcard(void)200 stack_dup_wildcard(void)
201 {
202 char buf[PATH_MAX] = { 0, };
203 char *end;
204
205 strncpy(buf, stack_id(), sizeof(buf) - 1);
206
207 end = strrchr(buf, '.');
208 if (end) end++;
209 else end = buf;
210
211 strcpy(end, "*");
212
213 return eina_strdup(buf);
214 }
215
216 static void
new_object(void)217 new_object(void)
218 {
219 const char *id;
220 New_Object_Handler *oh = NULL;
221 New_Statement_Handler *sh;
222
223 fill_object_statement_hashes();
224 id = stack_id();
225 if (!had_quote)
226 {
227 oh = eina_hash_find(_new_object_hash, id);
228 if (!oh)
229 oh = eina_hash_find(_new_object_short_hash, id);
230 }
231 if (oh)
232 {
233 if (oh->func) oh->func();
234 }
235 else
236 {
237 did_wildcard = edje_cc_handlers_wildcard();
238 if (!did_wildcard)
239 {
240 sh = eina_hash_find(_new_statement_hash, id);
241 if (!sh)
242 sh = eina_hash_find(_new_statement_short_hash, id);
243 if (!sh)
244 sh = eina_hash_find(_new_statement_short_single_hash, id);
245 if (!sh)
246 {
247 char *tmp = stack_dup_wildcard();
248 sh = eina_hash_find(_new_statement_hash, tmp);
249 free(tmp);
250 }
251 if ((!sh) && (!did_wildcard) && (!had_quote))
252 {
253 ERR("%s:%i unhandled keyword %s",
254 file_in, line - 1,
255 (char *)eina_list_data_get(eina_list_last(stack)));
256 err_show();
257 exit(-1);
258 }
259 did_wildcard = !sh;
260 }
261 }
262 }
263
264 static void
new_statement(void)265 new_statement(void)
266 {
267 const char *id;
268 New_Statement_Handler *sh = NULL;
269 fill_object_statement_hashes();
270 id = stack_id();
271 sh = eina_hash_find(_new_statement_hash, id);
272 if (!sh)
273 sh = eina_hash_find(_new_statement_short_hash, id);
274 if (sh)
275 {
276 if (sh->func) sh->func();
277 }
278 else
279 {
280 char *tmp = stack_dup_wildcard();
281 sh = eina_hash_find(_new_statement_hash, tmp);
282 free(tmp);
283
284 if (sh)
285 {
286 if (sh->func) sh->func();
287 }
288 else
289 {
290 ERR("%s:%i unhandled keyword %s",
291 file_in, line - 1,
292 (char *)eina_list_data_get(eina_list_last(stack)));
293 err_show();
294 exit(-1);
295 }
296 }
297 }
298
299 static Eina_Bool
new_statement_single(void)300 new_statement_single(void)
301 {
302 const char *id;
303 New_Statement_Handler *sh = NULL;
304 fill_object_statement_hashes();
305 id = stack_id();
306 sh = eina_hash_find(_new_statement_short_single_hash, id);
307 if (sh)
308 {
309 if (sh->func) sh->func();
310 }
311 return !!sh;
312 }
313
314 static char *
perform_math(char * input)315 perform_math(char *input)
316 {
317 char buf[256];
318 double res;
319
320 /* FIXME
321 * Always apply floating-point arithmetic.
322 * Does this cause problems for integer parameters? (yes it will)
323 *
324 * What we should do is, loop over the string and figure out whether
325 * there are floating point operands, too and then switch to
326 * floating point math.
327 */
328 res = my_atof(input);
329 snprintf(buf, sizeof (buf), "%lf", res);
330 return strdup(buf);
331 }
332
333 static int
isdelim(char c)334 isdelim(char c)
335 {
336 const char *delims = "{},;:[]";
337 char *d;
338
339 d = (char *)delims;
340 while (*d)
341 {
342 if (c == *d) return 1;
343 d++;
344 }
345 return 0;
346 }
347
348 static char *
next_token(char * p,char * end,char ** new_p,int * delim)349 next_token(char *p, char *end, char **new_p, int *delim)
350 {
351 char *tok_start = NULL, *tok_end = NULL, *tok = NULL, *sa_start = NULL;
352 int in_tok = 0;
353 int in_quote = 0;
354 int in_parens = 0;
355 int in_comment_ss = 0;
356 int in_comment_cpp = 0;
357 int in_comment_sa = 0;
358 int is_escaped = 0;
359
360 had_quote = 0;
361
362 *delim = 0;
363 if (p >= end) return NULL;
364 while (p < end)
365 {
366 if (*p == '\n')
367 {
368 in_comment_ss = 0;
369 in_comment_cpp = 0;
370 line++;
371 }
372 if ((!in_comment_ss) && (!in_comment_sa))
373 {
374 if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '/'))
375 in_comment_ss = 1;
376 if ((!in_quote) && (*p == '#'))
377 in_comment_cpp = 1;
378 if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '*'))
379 {
380 in_comment_sa = 1;
381 sa_start = p;
382 }
383 }
384 if ((in_comment_cpp) && (*p == '#'))
385 {
386 char *pp, fl[4096];
387 char *tmpstr = NULL;
388 int l, nm;
389
390 /* handle cpp comments */
391 /* their line format is
392 * #line <line no. of next line> <filename from next line on> [??]
393 */
394
395 pp = p;
396 while ((pp < end) && (*pp != '\n'))
397 {
398 pp++;
399 }
400 l = pp - p;
401 tmpstr = alloca(l + 1);
402 memcpy(tmpstr, p, l);
403 tmpstr[l] = 0;
404 if (l >= (int)sizeof(fl))
405 {
406 ERR("Line too long: %i chars: %s", l, tmpstr);
407 err_show();
408 exit(-1);
409 }
410 l = sscanf(tmpstr, "%*s %i \"%[^\"]\"", &nm, fl);
411 if (l == 2)
412 {
413 strcpy(file_buf, fl);
414 line = nm;
415 file_in = file_buf;
416 }
417 }
418 else if ((!in_comment_ss) && (!in_comment_sa) && (!in_comment_cpp))
419 {
420 if (!in_tok)
421 {
422 if (!in_quote)
423 {
424 if (!isspace(*p))
425 {
426 if (*p == '"')
427 {
428 in_quote = 1;
429 had_quote = 1;
430 }
431 else if (*p == '(')
432 in_parens++;
433
434 in_tok = 1;
435 tok_start = p;
436 if (isdelim(*p)) *delim = 1;
437 }
438 }
439 }
440 else
441 {
442 if (in_quote)
443 {
444 if ((*p) == '\\')
445 is_escaped = !is_escaped;
446 else if (((*p) == '"') && (!is_escaped))
447 {
448 in_quote = 0;
449 had_quote = 1;
450 }
451 else if (is_escaped)
452 is_escaped = 0;
453 }
454 else if (in_parens != 0 && (!is_escaped))
455 {
456 if (*p == '(')
457 in_parens++;
458 else if (*p == ')')
459 in_parens--;
460 else if (isdelim(*p))
461 {
462 ERR("check pair of parens %s:%i.", file_in, line - 1);
463 err_show();
464 exit(-1);
465 }
466 }
467 else
468 {
469 if (*p == '"')
470 {
471 in_quote = 1;
472 had_quote = 1;
473 }
474 else if (*p == '(')
475 in_parens++;
476 else if (*p == ')')
477 in_parens--;
478
479 /* check for end-of-token */
480 if (
481 (isspace(*p)) ||
482 ((*delim) && (!isdelim(*p))) ||
483 (isdelim(*p))
484 ) /*the line below this is never used because it skips to
485 * the 'done' label which is after the return call for
486 * in_tok being 0. is this intentional?
487 */
488 {
489 in_tok = 0;
490
491 tok_end = p - 1;
492 if (*p == '\n') line--;
493 goto done;
494 }
495 }
496 }
497 }
498 if (in_comment_sa)
499 {
500 if ((*p == '/') && (*(p - 1) == '*') && ((p - sa_start) > 2))
501 in_comment_sa = 0;
502 }
503 p++;
504 }
505 if (!in_tok) return NULL;
506 tok_end = p - 1;
507
508 done:
509 *new_p = p;
510
511 tok = mem_alloc(tok_end - tok_start + 2);
512 if (!tok) return NULL;
513
514 strncpy(tok, tok_start, tok_end - tok_start + 1);
515 tok[tok_end - tok_start + 1] = 0;
516
517 if (had_quote)
518 {
519 is_escaped = 0;
520 p = tok;
521
522 /* Note: if you change special chars list here make the same changes in
523 * _edje_generate_source_of_style function
524 */
525 while (*p)
526 {
527 if ((*p == '\"') && (!is_escaped))
528 {
529 memmove(p, p + 1, strlen(p));
530 }
531 else if ((*p == '\\') && (*(p + 1) == 'n'))
532 {
533 memmove(p, p + 1, strlen(p));
534 *p = '\n';
535 }
536 else if ((*p == '\\') && (*(p + 1) == 't'))
537 {
538 memmove(p, p + 1, strlen(p));
539 *p = '\t';
540 }
541 else if (*p == '\\')
542 {
543 memmove(p, p + 1, strlen(p));
544 if (*p == '\\') p++;
545 else is_escaped = 1;
546 }
547 else
548 {
549 if (is_escaped) is_escaped = 0;
550 p++;
551 }
552 }
553 }
554 else if (*tok == '(')
555 {
556 char *tmp;
557 tmp = tok;
558 tok = perform_math(tok);
559 free(tmp);
560 }
561
562 return tok;
563 }
564
565 static void
stack_push(char * token)566 stack_push(char *token)
567 {
568 New_Nested_Handler *nested;
569 Eina_Bool do_append = EINA_TRUE;
570
571 if (eina_list_count(stack) > 1)
572 {
573 if (!strcmp(token, eina_list_data_get(eina_list_last(stack))))
574 {
575 char *tmp;
576 int token_length;
577
578 token_length = strlen(token);
579 tmp = alloca(eina_strbuf_length_get(stack_buf));
580 memcpy(tmp,
581 eina_strbuf_string_get(stack_buf),
582 eina_strbuf_length_get(stack_buf) - token_length - 1);
583 tmp[eina_strbuf_length_get(stack_buf) - token_length - 1] = '\0';
584
585 nested = eina_hash_find(_new_nested_hash, tmp);
586 if (!nested)
587 nested = eina_hash_find(_new_nested_short_hash, tmp);
588 if (nested)
589 {
590 if (!strcmp(token, nested->token) &&
591 stack && !strcmp(eina_list_data_get(eina_list_last(stack)), nested->token))
592 {
593 /* Do not append the nested token in buffer */
594 do_append = EINA_FALSE;
595 if (nested->func_push) nested->func_push();
596 }
597 }
598 }
599 }
600 if (do_append)
601 {
602 if (stack) eina_strbuf_append(stack_buf, ".");
603 eina_strbuf_append(stack_buf, token);
604 }
605 stack = eina_list_append(stack, token);
606 }
607
608 static void
stack_pop(void)609 stack_pop(void)
610 {
611 char *tmp;
612 int tmp_length;
613 Eina_Bool do_remove = EINA_TRUE;
614
615 if (!stack)
616 {
617 ERR("parse error %s:%i. } marker without matching { marker",
618 file_in, line - 1);
619 err_show();
620 exit(-1);
621 }
622 tmp = eina_list_data_get(eina_list_last(stack));
623 tmp_length = strlen(tmp);
624
625 stack = eina_list_remove_list(stack, eina_list_last(stack));
626 if (eina_list_count(stack) > 0)
627 {
628 const char *prev;
629 New_Nested_Handler *nested;
630 char *hierarchy;
631 char *lookup;
632
633 hierarchy = alloca(eina_strbuf_length_get(stack_buf) + 1);
634 memcpy(hierarchy,
635 eina_strbuf_string_get(stack_buf),
636 eina_strbuf_length_get(stack_buf) + 1);
637
638 /* This is nasty, but it's the way to get parts.part when they are collapsed together. still not perfect */
639 lookup = strrchr(hierarchy + eina_strbuf_length_get(stack_buf) - tmp_length, '.');
640 while (lookup)
641 {
642 hierarchy[lookup - hierarchy] = '\0';
643 nested = eina_hash_find(_new_nested_hash, hierarchy);
644 if (!nested)
645 nested = eina_hash_find(_new_nested_short_hash, hierarchy);
646 if (nested && nested->func_pop) nested->func_pop();
647 lookup = strrchr(hierarchy + eina_strbuf_length_get(stack_buf) - tmp_length, '.');
648 }
649
650 hierarchy[eina_strbuf_length_get(stack_buf) - 1 - tmp_length] = '\0';
651
652 nested = eina_hash_find(_new_nested_hash, hierarchy);
653 if (!nested)
654 nested = eina_hash_find(_new_nested_short_hash, hierarchy);
655 if (nested)
656 {
657 if (nested->func_pop) nested->func_pop();
658
659 prev = eina_list_data_get(eina_list_last(stack));
660 if (!strcmp(tmp, prev))
661 {
662 if (!strcmp(nested->token, tmp))
663 do_remove = EINA_FALSE;
664 }
665 }
666 else
667 edje_cc_handlers_pop_notify(tmp);
668
669 if (do_remove)
670 eina_strbuf_remove(stack_buf,
671 eina_strbuf_length_get(stack_buf) - tmp_length - 1,
672 eina_strbuf_length_get(stack_buf)); /* remove: '.tmp' */
673 }
674 else
675 {
676 eina_strbuf_remove(stack_buf,
677 eina_strbuf_length_get(stack_buf) - tmp_length,
678 eina_strbuf_length_get(stack_buf)); /* remove: 'tmp' */
679 }
680 free(tmp);
681 }
682
683 void
stack_push_quick(const char * str)684 stack_push_quick(const char *str)
685 {
686 char *s;
687
688 s = mem_strdup(str);
689 stack = eina_list_append(stack, s);
690 eina_strbuf_append_char(stack_buf, '.');
691 eina_strbuf_append(stack_buf, s);
692 }
693
694 char *
stack_pop_quick(Eina_Bool check_last,Eina_Bool do_free)695 stack_pop_quick(Eina_Bool check_last, Eina_Bool do_free)
696 {
697 char *tmp, *str;
698
699 str = tmp = eina_list_last_data_get(stack);
700 if (check_last)
701 {
702 char *end;
703
704 end = strrchr(tmp, '.');
705 if (end)
706 tmp = end + 1;
707 }
708 eina_strbuf_remove(stack_buf,
709 eina_strbuf_length_get(stack_buf) - strlen(tmp) - 1,
710 eina_strbuf_length_get(stack_buf)); /* remove: '.tmp' */
711 stack = eina_list_remove_list(stack, eina_list_last(stack));
712 if (do_free)
713 {
714 free(str);
715 str = NULL;
716 }
717 return str;
718 }
719
720 /* replace the top of stack with given token */
721 void
stack_replace_quick(const char * token)722 stack_replace_quick(const char *token)
723 {
724 char *str;
725
726 str = stack_pop_quick(EINA_FALSE, EINA_FALSE);
727 if ((str) && strchr(str, '.'))
728 {
729 char *end, *tmp = str;
730 Eina_Strbuf *buf;
731
732 end = strchr(tmp, '.');
733 if (end)
734 tmp = end + 1;
735
736 buf = eina_strbuf_new();
737 eina_strbuf_append(buf, str);
738 eina_strbuf_remove(buf,
739 eina_strbuf_length_get(buf) - strlen(tmp),
740 eina_strbuf_length_get(buf));
741 eina_strbuf_append(buf, token);
742
743 stack_push_quick(eina_strbuf_string_get(buf));
744
745 eina_strbuf_free(buf);
746 free(str);
747 }
748 else
749 {
750 stack_push_quick(token);
751 }
752 }
753
754 static const char *
stack_id(void)755 stack_id(void)
756 {
757 return eina_strbuf_string_get(stack_buf);
758 }
759
760 static void
parse(char * data,off_t size)761 parse(char *data, off_t size)
762 {
763 char *p, *end, *token;
764 int delim = 0;
765 int do_params = 0;
766 int do_indexes = 0; // 0: none, 1: ready, 2: done
767
768 DBG("Parsing input file");
769
770 /* Allocate arrays used to impl nested parts */
771 edje_cc_handlers_hierarchy_alloc();
772 p = data;
773 end = data + size;
774 line = 1;
775 while ((token = next_token(p, end, &p, &delim)))
776 {
777 /* if we are in param mode, the only delimiter
778 * we'll accept is the semicolon
779 */
780 if (do_params && delim && *token != ';')
781 {
782 ERR("parse error %s:%i. %c marker before ; marker",
783 file_in, line - 1, *token);
784 err_show();
785 exit(-1);
786 }
787 else if (delim)
788 {
789 if ((do_indexes == 2) && (*token != ']'))
790 {
791 ERR("parse error %s:%i. %c marker before ] marker",
792 file_in, line - 1, *token);
793 err_show();
794 exit(-1);
795 }
796 else if (*token == ',' || *token == ':')
797 do_params = 1;
798 else if (*token == '}')
799 {
800 if (do_params)
801 {
802 ERR("parse error %s:%i. } marker before ; marker",
803 file_in, line - 1);
804 err_show();
805 exit(-1);
806 }
807 else
808 stack_pop();
809 }
810 else if (*token == ';')
811 {
812 if (did_wildcard)
813 {
814 free(token);
815 did_wildcard = 0;
816 continue;
817 }
818 if (do_params)
819 {
820 void *param;
821
822 do_params = 0;
823 new_statement();
824 /* clear out params */
825 while ((param = eina_array_pop(¶ms)))
826 free(param);
827 params_quote = 0;
828 /* remove top from stack */
829 stack_pop();
830 }
831 else
832 {
833 if (new_statement_single())
834 stack_pop();
835 }
836 }
837 else if (*token == '{')
838 {
839 if (do_params)
840 {
841 ERR("parse error %s:%i. { marker before ; marker",
842 file_in, line - 1);
843 err_show();
844 exit(-1);
845 }
846 }
847 else if (*token == '[')
848 {
849 do_indexes = 1;
850 }
851 else if (*token == ']')
852 {
853 if (do_indexes == 2)
854 do_indexes = 0;
855 else
856 {
857 if (do_indexes == 0)
858 ERR("parse error %s:%i. ] marker before [ marker",
859 file_in, line - 1);
860 else
861 ERR("parse error %s:%i. [?] empty bracket",
862 file_in, line - 1);
863
864 err_show();
865 exit(-1);
866 }
867 }
868 free(token);
869 }
870 else
871 {
872 if (do_params)
873 {
874 if (had_quote)
875 params_quote |= (1 << eina_array_count(¶ms));
876 eina_array_push(¶ms, token);
877 }
878 else if (do_indexes)
879 {
880 if (had_quote)
881 params_quote |= (1 << eina_array_count(¶ms));
882 do_indexes++;
883 eina_array_push(¶ms, token);
884 }
885 else
886 {
887 stack_push(token);
888 new_object();
889 if ((verbatim == 1) && (p < (end - 2)))
890 {
891 int escaped = 0;
892 int inquotes = 0;
893 int insquotes = 0;
894 int squigglie = 1;
895 int l1 = 0, l2 = 0;
896 char *verbatim_1;
897 char *verbatim_2;
898
899 l1 = line;
900 while ((p[0] != '{') && (p < end))
901 {
902 if (*p == '\n') line++;
903 p++;
904 }
905 p++;
906 verbatim_1 = p;
907 verbatim_2 = NULL;
908 for (; p < end; p++)
909 {
910 if (*p == '\n') line++;
911 if (escaped) escaped = 0;
912 if (!escaped)
913 {
914 if (p[0] == '\\') escaped = 1;
915 else if (p[0] == '\"')
916 {
917 if (!insquotes)
918 {
919 if (inquotes) inquotes = 0;
920 else inquotes = 1;
921 }
922 }
923 else if (p[0] == '\'')
924 {
925 if (!inquotes)
926 {
927 if (insquotes) insquotes = 0;
928 else insquotes = 1;
929 }
930 }
931 else if ((!inquotes) && (!insquotes))
932 {
933 if (p[0] == '{') squigglie++;
934 else if (p[0] == '}')
935 squigglie--;
936 if (squigglie == 0)
937 {
938 verbatim_2 = p - 1;
939 l2 = line;
940 break;
941 }
942 }
943 }
944 }
945 if (verbatim_2 > verbatim_1)
946 {
947 int l;
948 char *v;
949
950 l = verbatim_2 - verbatim_1 + 1;
951 v = malloc(l + 1);
952 strncpy(v, verbatim_1, l);
953 v[l] = 0;
954 set_verbatim(v, l1, l2);
955 }
956 else
957 {
958 ERR("Parse error %s:%i. { marker does not have matching } marker",
959 file_in, line - 1);
960 err_show();
961 exit(-1);
962 }
963 new_object();
964 verbatim = 0;
965 }
966 }
967 }
968 }
969
970 edje_cc_handlers_hierarchy_free();
971 DBG("Parsing done");
972 }
973
974 static char *clean_file = NULL;
975 static void
clean_tmp_file(void)976 clean_tmp_file(void)
977 {
978 if (clean_file)
979 {
980 unlink(clean_file);
981 free(clean_file);
982 }
983 }
984
985 int
is_verbatim(void)986 is_verbatim(void)
987 {
988 return verbatim;
989 }
990
991 void
track_verbatim(int on)992 track_verbatim(int on)
993 {
994 verbatim = on;
995 }
996
997 void
set_verbatim(char * s,int l1,int l2)998 set_verbatim(char *s, int l1, int l2)
999 {
1000 verbatim_line1 = l1;
1001 verbatim_line2 = l2;
1002 verbatim_str = s;
1003 }
1004
1005 char *
get_verbatim(void)1006 get_verbatim(void)
1007 {
1008 return verbatim_str;
1009 }
1010
1011 int
get_verbatim_line1(void)1012 get_verbatim_line1(void)
1013 {
1014 return verbatim_line1;
1015 }
1016
1017 int
get_verbatim_line2(void)1018 get_verbatim_line2(void)
1019 {
1020 return verbatim_line2;
1021 }
1022
1023 void
compile(void)1024 compile(void)
1025 {
1026 char buf[4096 + 4096 + 4096], buf2[4096];
1027 Eina_Tmpstr *tmpn;
1028 int fd;
1029 off_t size;
1030 char *data;
1031 Eina_List *l;
1032 Edje_Style *stl;
1033
1034 fd = eina_file_mkstemp("edje_cc.edc-tmp-XXXXXX", &tmpn);
1035 if (fd < 0)
1036 {
1037 CRI("Unable to open temp file \"%s\" for pre-processor.", tmpn);
1038 exit(-1);
1039 }
1040
1041 if (fd >= 0)
1042 {
1043 int ret;
1044 char *def;
1045
1046 clean_file = strdup(tmpn);
1047 eina_tmpstr_del(tmpn);
1048 close(fd);
1049 atexit(clean_tmp_file);
1050 if (!defines)
1051 def = mem_strdup("");
1052 else
1053 {
1054 int len;
1055 char *define;
1056
1057 len = 0;
1058 EINA_LIST_FOREACH(defines, l, define)
1059 len += strlen(define) + 1;
1060 def = mem_alloc(len + 1);
1061 def[0] = 0;
1062 EINA_LIST_FOREACH(defines, l, define)
1063 {
1064 strcat(def, define);
1065 strcat(def, " ");
1066 }
1067 }
1068
1069 /*
1070 * Run the input through the C pre-processor.
1071 */
1072
1073 buf2[0] = '\0';
1074 #ifdef NEED_RUN_IN_TREE
1075 if (getenv("EFL_RUN_IN_TREE"))
1076 {
1077 snprintf(buf2, sizeof(buf2),
1078 "%s/src/bin/edje/epp/epp" EPP_EXT,
1079 PACKAGE_BUILD_DIR);
1080 if (!ecore_file_exists(buf2))
1081 buf2[0] = '\0';
1082 }
1083 #endif
1084
1085 if (buf2[0] == '\0')
1086 snprintf(buf2, sizeof(buf2),
1087 "%s/edje/utils/" MODULE_ARCH "/epp" EPP_EXT,
1088 eina_prefix_lib_get(pfx));
1089 if (ecore_file_exists(buf2))
1090 {
1091 char *inc;
1092
1093 inc = ecore_file_dir_get(file_in);
1094 if (depfile)
1095 snprintf(buf, sizeof(buf), "\"%s\" "SKIP_NAMESPACE_VALIDATION_SUPPORTED" -MMD \"%s\" -MT \"%s\" \"%s\""
1096 " -I\"%s\" %s -o \"%s\""
1097 " -DEFL_VERSION_MAJOR=%d -DEFL_VERSION_MINOR=%d"
1098 EDJE_CC_EFL_VERSION_SUPPORTED,
1099 buf2, depfile, file_out, file_in,
1100 inc ? inc : "./", def, clean_file,
1101 EINA_VERSION_MAJOR, EINA_VERSION_MINOR);
1102 else if (annotate)
1103 snprintf(buf, sizeof(buf), "\"%s\" "SKIP_NAMESPACE_VALIDATION_SUPPORTED" -annotate -a \"%s\" \"%s\""
1104 " -I\"%s\" %s -o \"%s\""
1105 " -DEFL_VERSION_MAJOR=%d -DEFL_VERSION_MINOR=%d"
1106 EDJE_CC_EFL_VERSION_SUPPORTED,
1107 buf2, watchfile ? watchfile : "/dev/null", file_in,
1108 inc ? inc : "./", def, clean_file,
1109 EINA_VERSION_MAJOR, EINA_VERSION_MINOR);
1110 else
1111 snprintf(buf, sizeof(buf), "\"%s\" "SKIP_NAMESPACE_VALIDATION_SUPPORTED" -a \"%s\" \"%s\" -I\"%s\" %s"
1112 " -o \"%s\""
1113 " -DEFL_VERSION_MAJOR=%d -DEFL_VERSION_MINOR=%d"
1114 EDJE_CC_EFL_VERSION_SUPPORTED,
1115 buf2, watchfile ? watchfile : "/dev/null", file_in,
1116 inc ? inc : "./", def, clean_file,
1117 EINA_VERSION_MAJOR, EINA_VERSION_MINOR);
1118 #ifdef _WIN32
1119 /* On Windows, if command begins with double quotation marks,
1120 * then the first and the last double quotation marks may be
1121 * either deleted or not. (See "help cmd" on Windows.)
1122 *
1123 * Therefore, to preserve the string between the first and the last
1124 * double quotation marks, "cmd /S /C" and additional outer double
1125 * quotation marks are added.
1126 */
1127 char win_buf[4096];
1128 snprintf(win_buf, sizeof(win_buf), "cmd /S /C \"%s\"", buf);
1129 ret = system(win_buf);
1130 #else
1131 ret = system(buf);
1132 #endif
1133 if (inc)
1134 free(inc);
1135 }
1136 else
1137 {
1138 ERR("Cannot run epp: %s", buf2);
1139 exit(-1);
1140 }
1141 if (ret == EXIT_SUCCESS)
1142 file_in = (char *)clean_file;
1143 else
1144 {
1145 ERR("Exit code of epp not clean: %i", ret);
1146 exit(-1);
1147 }
1148 free(def);
1149 }
1150 fd = open(file_in, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
1151 if (fd < 0)
1152 {
1153 ERR("Cannot open file \"%s\" for input. %s",
1154 file_in, strerror(errno));
1155 exit(-1);
1156 }
1157 DBG("Opening \"%s\" for input", file_in);
1158
1159 /* lseek can return -1 on error. trap that return and exit so that
1160 * we do not pass malloc a -1
1161 *
1162 * NB: Fixes Coverity CID 1040029 */
1163 size = lseek(fd, 0, SEEK_END);
1164 if (size < 0)
1165 {
1166 ERR("Cannot read file \"%s\". %s", file_in, strerror(errno));
1167 exit(-1);
1168 }
1169
1170 lseek(fd, 0, SEEK_SET);
1171 data = malloc(size);
1172 if (data && (read(fd, data, size) == size))
1173 {
1174 stack_buf = eina_strbuf_new();
1175 eina_array_step_set(¶ms, sizeof (Eina_Array), 8);
1176 parse(data, size);
1177 eina_array_flush(¶ms);
1178 eina_strbuf_free(stack_buf);
1179 stack_buf = NULL;
1180 color_tree_root_free();
1181 }
1182 else
1183 {
1184 ERR("Cannot read file \"%s\". %s", file_in, strerror(errno));
1185 exit(-1);
1186 }
1187 free(data);
1188 close(fd);
1189
1190 EINA_LIST_FOREACH(edje_file->styles, l, stl)
1191 {
1192 if (!stl->name)
1193 {
1194 ERR("style must have a name.");
1195 exit(-1);
1196 }
1197 }
1198 }
1199
1200 int
is_param(int n)1201 is_param(int n)
1202 {
1203 char *str;
1204
1205 str = _parse_param_get(n);
1206 if (str) return 1;
1207 return 0;
1208 }
1209
1210 int
is_num(int n)1211 is_num(int n)
1212 {
1213 char *str;
1214 char *end;
1215 long int ret;
1216
1217 str = _parse_param_get(n);
1218 if (!str)
1219 {
1220 ERR("%s:%i no parameter supplied as argument %i",
1221 file_in, line - 1, n + 1);
1222 err_show();
1223 exit(-1);
1224 }
1225 if (str[0] == 0) return 0;
1226 end = str;
1227 ret = strtol(str, &end, 0);
1228 if ((ret == LONG_MIN) || (ret == LONG_MAX))
1229 {
1230 n = 0; // do nothing. shut gcc warnings up
1231 }
1232 if ((end != str) && (end[0] == 0)) return 1;
1233 return 0;
1234 }
1235
1236 char *
parse_str(int n)1237 parse_str(int n)
1238 {
1239 char *str;
1240 char *s;
1241
1242 str = _parse_param_get(n);
1243 if (!str)
1244 {
1245 ERR("%s:%i no parameter supplied as argument %i",
1246 file_in, line - 1, n + 1);
1247 err_show();
1248 exit(-1);
1249 }
1250 s = mem_strdup(str);
1251 return s;
1252 }
1253
1254 static int
_parse_enum(char * str,va_list va)1255 _parse_enum(char *str, va_list va)
1256 {
1257 va_list va2;
1258 va_copy(va2, va); /* iterator for the error message */
1259
1260 for (;; )
1261 {
1262 char *s;
1263 int v;
1264
1265 s = va_arg(va, char *);
1266
1267 /* End of the list, nothing matched. */
1268 if (!s)
1269 {
1270 ERR("%s:%i token %s not one of:", file_in, line - 1, str);
1271 s = va_arg(va2, char *);
1272 while (s)
1273 {
1274 va_arg(va2, int);
1275 fprintf(stderr, " %s", s);
1276 s = va_arg(va2, char *);
1277 if (!s) break;
1278 }
1279 fprintf(stderr, "\n");
1280 va_end(va2);
1281 va_end(va);
1282 err_show();
1283 exit(-1);
1284 }
1285
1286 v = va_arg(va, int);
1287 if (!strcmp(s, str) || !strcmp(s, "*"))
1288 {
1289 va_end(va2);
1290 va_end(va);
1291 return v;
1292 }
1293 }
1294 va_end(va2);
1295 va_end(va);
1296 return 0;
1297 }
1298
1299 int
parse_enum(int n,...)1300 parse_enum(int n, ...)
1301 {
1302 char *str;
1303 int result;
1304 va_list va;
1305
1306 if (n >= 0)
1307 {
1308 str = _parse_param_get(n);
1309 if (!str)
1310 {
1311 ERR("%s:%i no parameter supplied as argument %i",
1312 file_in, line - 1, n + 1);
1313 err_show();
1314 exit(-1);
1315 }
1316 }
1317 else
1318 {
1319 char *end;
1320
1321 str = eina_list_last_data_get(stack);
1322 end = strrchr(str, '.');
1323 if (end)
1324 str = end + 1;
1325 }
1326
1327 va_start(va, n);
1328 result = _parse_enum(str, va);
1329 va_end(va);
1330
1331 return result;
1332 }
1333
1334 int
parse_flags(int n,...)1335 parse_flags(int n, ...)
1336 {
1337 int result = 0;
1338 va_list va;
1339
1340 va_start(va, n);
1341 while (n < (int)eina_array_count(¶ms))
1342 {
1343 result |= _parse_enum(eina_array_data_get(¶ms, n), va);
1344 n++;
1345 }
1346 va_end(va);
1347
1348 return result;
1349 }
1350
1351 int
parse_int(int n)1352 parse_int(int n)
1353 {
1354 char *str;
1355 int i;
1356
1357 str = _parse_param_get(n);
1358 if (!str)
1359 {
1360 ERR("%s:%i no parameter supplied as argument %i",
1361 file_in, line - 1, n + 1);
1362 err_show();
1363 exit(-1);
1364 }
1365 i = my_atoi(str);
1366 return i;
1367 }
1368
1369 int
parse_int_range(int n,int f,int t)1370 parse_int_range(int n, int f, int t)
1371 {
1372 char *str;
1373 int i;
1374
1375 str = _parse_param_get(n);
1376 if (!str)
1377 {
1378 ERR("%s:%i no parameter supplied as argument %i",
1379 file_in, line - 1, n + 1);
1380 err_show();
1381 exit(-1);
1382 }
1383 i = my_atoi(str);
1384 if ((i < f) || (i > t))
1385 {
1386 ERR("%s:%i integer %i out of range of %i to %i inclusive",
1387 file_in, line - 1, i, f, t);
1388 err_show();
1389 exit(-1);
1390 }
1391 return i;
1392 }
1393
1394 int
parse_bool(int n)1395 parse_bool(int n)
1396 {
1397 char *str, buf[4096];
1398 int i;
1399
1400 str = _parse_param_get(n);
1401 if (!str)
1402 {
1403 ERR("%s:%i no parameter supplied as argument %i",
1404 file_in, line - 1, n + 1);
1405 err_show();
1406 exit(-1);
1407 }
1408
1409 if (!strstrip(str, buf, sizeof (buf)))
1410 {
1411 ERR("%s:%i expression is too long",
1412 file_in, line - 1);
1413 return 0;
1414 }
1415
1416 if (!strcasecmp(buf, "false") || !strcasecmp(buf, "off"))
1417 return 0;
1418 if (!strcasecmp(buf, "true") || !strcasecmp(buf, "on"))
1419 return 1;
1420
1421 i = my_atoi(str);
1422 if ((i < 0) || (i > 1))
1423 {
1424 ERR("%s:%i integer %i out of range of 0 to 1 inclusive",
1425 file_in, line - 1, i);
1426 err_show();
1427 exit(-1);
1428 }
1429 return i;
1430 }
1431
1432 double
parse_float(int n)1433 parse_float(int n)
1434 {
1435 char *str;
1436 double i;
1437
1438 str = _parse_param_get(n);
1439 if (!str)
1440 {
1441 ERR("%s:%i no parameter supplied as argument %i",
1442 file_in, line - 1, n + 1);
1443 err_show();
1444 exit(-1);
1445 }
1446 i = my_atof(str);
1447 return i;
1448 }
1449
1450 double
parse_float_range(int n,double f,double t)1451 parse_float_range(int n, double f, double t)
1452 {
1453 char *str;
1454 double i;
1455
1456 str = _parse_param_get(n);
1457 if (!str)
1458 {
1459 ERR("%s:%i no parameter supplied as argument %i",
1460 file_in, line - 1, n + 1);
1461 err_show();
1462 exit(-1);
1463 }
1464 i = my_atof(str);
1465 if ((i < f) || (i > t))
1466 {
1467 ERR("%s:%i float %3.3f out of range of %3.3f to %3.3f inclusive",
1468 file_in, line - 1, i, f, t);
1469 err_show();
1470 exit(-1);
1471 }
1472 return i;
1473 }
1474
1475 int
get_arg_count(void)1476 get_arg_count(void)
1477 {
1478 return eina_array_count(¶ms);
1479 }
1480
1481 void
check_arg_count(int required_args)1482 check_arg_count(int required_args)
1483 {
1484 int num_args = eina_array_count(¶ms);
1485
1486 if (num_args != required_args)
1487 {
1488 ERR("%s:%i got %i arguments, but expected %i",
1489 file_in, line - 1, num_args, required_args);
1490 err_show();
1491 exit(-1);
1492 }
1493 }
1494
1495 void
check_min_arg_count(int min_required_args)1496 check_min_arg_count(int min_required_args)
1497 {
1498 int num_args = eina_array_count(¶ms);
1499
1500 if (num_args < min_required_args)
1501 {
1502 ERR("%s:%i got %i arguments, but expected at least %i",
1503 file_in, line - 1, num_args, min_required_args);
1504 err_show();
1505 exit(-1);
1506 }
1507 }
1508
1509 int
check_range_arg_count(int min_required_args,int max_required_args)1510 check_range_arg_count(int min_required_args, int max_required_args)
1511 {
1512 int num_args = eina_array_count(¶ms);
1513
1514 if (num_args < min_required_args)
1515 {
1516 ERR("%s:%i got %i arguments, but expected at least %i",
1517 file_in, line - 1, num_args, min_required_args);
1518 err_show();
1519 exit(-1);
1520 }
1521 else if (num_args > max_required_args)
1522 {
1523 ERR("%s:%i got %i arguments, but expected at most %i",
1524 file_in, line - 1, num_args, max_required_args);
1525 err_show();
1526 exit(-1);
1527 }
1528
1529 return num_args;
1530 }
1531
1532 /* simple expression parsing stuff */
1533
1534 /*
1535 * alpha ::= beta + beta || beta
1536 * beta ::= gamma + gamma || gamma
1537 * gamma ::= num || delta
1538 * delta ::= '(' alpha ')'
1539 *
1540 */
1541
1542 /* int set of function */
1543
1544 static int
my_atoi(const char * s)1545 my_atoi(const char *s)
1546 {
1547 int res = 0;
1548 char buf[4096];
1549
1550 if (!s) return 0;
1551 if (!strstrip(s, buf, sizeof(buf)))
1552 {
1553 ERR("%s:%i expression is too long",
1554 file_in, line - 1);
1555 return 0;
1556 }
1557 _alphai(buf, &res);
1558 return res;
1559 }
1560
1561 static char *
_deltai(char * s,int * val)1562 _deltai(char *s, int *val)
1563 {
1564 if (!val) return NULL;
1565 if ('(' != s[0])
1566 {
1567 ERR("%s:%i unexpected character at %s",
1568 file_in, line - 1, s);
1569 return s;
1570 }
1571 else
1572 {
1573 s++;
1574 s = _alphai(s, val);
1575 s++;
1576 return s;
1577 }
1578 return s;
1579 }
1580
1581 static char *
_funci(char * s,int * val)1582 _funci(char *s, int *val)
1583 {
1584 if (!strncmp(s, "floor(", 6))
1585 {
1586 s += 5;
1587 s = _deltai(s, val);
1588 }
1589 else if (!strncmp(s, "ceil(", 5))
1590 {
1591 s += 4;
1592 s = _deltai(s, val);
1593 }
1594 else
1595 {
1596 ERR("%s:%i unexpected character at %s",
1597 file_in, line - 1, s);
1598 }
1599 return s;
1600 }
1601
1602 static char *
_gammai(char * s,int * val)1603 _gammai(char *s, int *val)
1604 {
1605 if (!val) return NULL;
1606 if (_is_numi(s[0]))
1607 {
1608 s = _get_numi(s, val);
1609 return s;
1610 }
1611 else if ('(' == s[0])
1612 {
1613 s = _deltai(s, val);
1614 return s;
1615 }
1616 else
1617 {
1618 s = _funci(s, val);
1619 // ERR("%s:%i unexpected character at %s",
1620 // progname, file_in, line - 1, s);
1621 }
1622 return s;
1623 }
1624
1625 static char *
_betai(char * s,int * val)1626 _betai(char *s, int *val)
1627 {
1628 int a1, a2;
1629 char op;
1630
1631 if (!val) return NULL;
1632 s = _gammai(s, &a1);
1633 while (_is_op1i(s[0]))
1634 {
1635 op = s[0];
1636 s++;
1637 s = _gammai(s, &a2);
1638 a1 = _calci(op, a1, a2);
1639 }
1640 (*val) = a1;
1641 return s;
1642 }
1643
1644 static char *
_alphai(char * s,int * val)1645 _alphai(char *s, int *val)
1646 {
1647 int a1 = 0, a2 = 0;
1648 char op;
1649
1650 if (!val) return NULL;
1651 s = _betai(s, &a1);
1652 while (_is_op2i(s[0]))
1653 {
1654 op = s[0];
1655 s++;
1656 s = _betai(s, &a2);
1657 a1 = _calci(op, a1, a2);
1658 }
1659 (*val) = a1;
1660 return s;
1661 }
1662
1663 char *
_get_numi(char * s,int * val)1664 _get_numi(char *s, int *val)
1665 {
1666 char buf[4096];
1667 int pos = 0;
1668
1669 if (!val) return s;
1670 while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
1671 ((0 == pos) && ('-' == s[pos])))
1672 {
1673 buf[pos] = s[pos];
1674 pos++;
1675 }
1676 buf[pos] = '\0';
1677 (*val) = atoi(buf);
1678 return s + pos;
1679 }
1680
1681 int
_is_numi(char c)1682 _is_numi(char c)
1683 {
1684 if (((c >= '0') && (c <= '9')) || ('-' == c) || ('+' == c))
1685 return 1;
1686 else
1687 return 0;
1688 }
1689
1690 int
_is_op1i(char c)1691 _is_op1i(char c)
1692 {
1693 switch (c)
1694 {
1695 case '*':;
1696
1697 case '%':;
1698
1699 case '/': return 1;
1700
1701 default: break;
1702 }
1703 return 0;
1704 }
1705
1706 int
_is_op2i(char c)1707 _is_op2i(char c)
1708 {
1709 switch (c)
1710 {
1711 case '+':;
1712
1713 case '-': return 1;
1714
1715 default: break;
1716 }
1717 return 0;
1718 }
1719
1720 int
_calci(char op,int a,int b)1721 _calci(char op, int a, int b)
1722 {
1723 switch (op)
1724 {
1725 case '+':
1726 a += b;
1727 return a;
1728
1729 case '-':
1730 a -= b;
1731 return a;
1732
1733 case '/':
1734 if (0 != b) a /= b;
1735 else
1736 ERR("%s:%i divide by zero", file_in, line - 1);
1737 return a;
1738
1739 case '*':
1740 a *= b;
1741 return a;
1742
1743 case '%':
1744 if (0 != b) a = a % b;
1745 else
1746 ERR("%s:%i modula by zero", file_in, line - 1);
1747 return a;
1748
1749 default:
1750 ERR("%s:%i unexpected character '%c'", file_in, line - 1, op);
1751 }
1752 return a;
1753 }
1754
1755 /* float set of functoins */
1756
1757 double
my_atof(const char * s)1758 my_atof(const char *s)
1759 {
1760 double res = 0;
1761 char buf[4096];
1762
1763 if (!s) return 0;
1764
1765 if (!strstrip(s, buf, sizeof (buf)))
1766 {
1767 ERR("%s:%i expression is too long", file_in, line - 1);
1768 return 0;
1769 }
1770 _alphaf(buf, &res);
1771 return res;
1772 }
1773
1774 static char *
_deltaf(char * s,double * val)1775 _deltaf(char *s, double *val)
1776 {
1777 if (!val) return NULL;
1778 if ('(' != s[0])
1779 {
1780 ERR("%s:%i unexpected character at %s", file_in, line - 1, s);
1781 return s;
1782 }
1783 else
1784 {
1785 s++;
1786 s = _alphaf(s, val);
1787 s++;
1788 }
1789 return s;
1790 }
1791
1792 static char *
_funcf(char * s,double * val)1793 _funcf(char *s, double *val)
1794 {
1795 if (!strncmp(s, "floor(", 6))
1796 {
1797 s += 5;
1798 s = _deltaf(s, val);
1799 *val = floor(*val);
1800 }
1801 else if (!strncmp(s, "ceil(", 5))
1802 {
1803 s += 4;
1804 s = _deltaf(s, val);
1805 *val = ceil(*val);
1806 }
1807 else
1808 {
1809 ERR("%s:%i unexpected character at %s", file_in, line - 1, s);
1810 }
1811 return s;
1812 }
1813
1814 static char *
_gammaf(char * s,double * val)1815 _gammaf(char *s, double *val)
1816 {
1817 if (!val) return NULL;
1818
1819 if (_is_numf(s[0]))
1820 {
1821 s = _get_numf(s, val);
1822 return s;
1823 }
1824 else if ('(' == s[0])
1825 {
1826 s = _deltaf(s, val);
1827 return s;
1828 }
1829 else
1830 {
1831 s = _funcf(s, val);
1832 // ERR("%s:%i unexpected character at %s",
1833 // progname, file_in, line - 1, s);
1834 }
1835 return s;
1836 }
1837
1838 static char *
_betaf(char * s,double * val)1839 _betaf(char *s, double *val)
1840 {
1841 double a1 = 0, a2 = 0;
1842 char op;
1843
1844 if (!val) return NULL;
1845 s = _gammaf(s, &a1);
1846 while (_is_op1f(s[0]))
1847 {
1848 op = s[0];
1849 s++;
1850 s = _gammaf(s, &a2);
1851 a1 = _calcf(op, a1, a2);
1852 }
1853 (*val) = a1;
1854 return s;
1855 }
1856
1857 static char *
_alphaf(char * s,double * val)1858 _alphaf(char *s, double *val)
1859 {
1860 double a1 = 0, a2 = 0;
1861 char op;
1862
1863 if (!val) return NULL;
1864 s = _betaf(s, &a1);
1865 while (_is_op2f(s[0]))
1866 {
1867 op = s[0];
1868 s++;
1869 s = _betaf(s, &a2);
1870 a1 = _calcf(op, a1, a2);
1871 }
1872 (*val) = a1;
1873 return s;
1874 }
1875
1876 static char *
_get_numf(char * s,double * val)1877 _get_numf(char *s, double *val)
1878 {
1879 char buf[4096];
1880 int pos = 0;
1881
1882 if (!val) return s;
1883
1884 while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
1885 ('.' == s[pos]) ||
1886 ((0 == pos) && ('-' == s[pos])))
1887 {
1888 buf[pos] = s[pos];
1889 pos++;
1890 }
1891 buf[pos] = '\0';
1892 (*val) = atof(buf);
1893 return s + pos;
1894 }
1895
1896 static int
_is_numf(char c)1897 _is_numf(char c)
1898 {
1899 if (((c >= '0') && (c <= '9'))
1900 || ('-' == c)
1901 || ('.' == c)
1902 || ('+' == c))
1903 return 1;
1904 return 0;
1905 }
1906
1907 static int
_is_op1f(char c)1908 _is_op1f(char c)
1909 {
1910 switch (c)
1911 {
1912 case '*':;
1913
1914 case '%':;
1915
1916 case '/': return 1;
1917
1918 default: break;
1919 }
1920 return 0;
1921 }
1922
1923 static int
_is_op2f(char c)1924 _is_op2f(char c)
1925 {
1926 switch (c)
1927 {
1928 case '+':;
1929
1930 case '-': return 1;
1931
1932 default: break;
1933 }
1934 return 0;
1935 }
1936
1937 static double
_calcf(char op,double a,double b)1938 _calcf(char op, double a, double b)
1939 {
1940 switch (op)
1941 {
1942 case '+':
1943 a += b;
1944 return a;
1945
1946 case '-':
1947 a -= b;
1948 return a;
1949
1950 case '/':
1951 if (EINA_DBL_NONZERO(b)) a /= b;
1952 else
1953 ERR("%s:%i divide by zero", file_in, line - 1);
1954 return a;
1955
1956 case '*':
1957 a *= b;
1958 return a;
1959
1960 case '%':
1961 if (EINA_DBL_NONZERO(b)) a = (double)((int)a % (int)b);
1962 else
1963 ERR("%s:%i modula by zero", file_in, line - 1);
1964 return a;
1965
1966 default:
1967 ERR("%s:%i unexpected character '%c'", file_in, line - 1, op);
1968 }
1969 return a;
1970 }
1971
1972 static int
strstrip(const char * in,char * out,size_t size)1973 strstrip(const char *in, char *out, size_t size)
1974 {
1975 if ((size - 1) < strlen(in))
1976 {
1977 ERR("%s:%i expression is too long", file_in, line - 1);
1978 return 0;
1979 }
1980 /* remove spaces and tabs */
1981 while (*in)
1982 {
1983 if ((0x20 != *in) && (0x09 != *in))
1984 {
1985 *out = *in;
1986 out++;
1987 }
1988 in++;
1989 }
1990 *out = '\0';
1991 return 1;
1992 }
1993
1994 int
get_param_index(char * str)1995 get_param_index(char *str)
1996 {
1997 int index;
1998 char *p;
1999
2000 for (index = 0; index < get_arg_count(); index++)
2001 {
2002 p = _parse_param_get(index);
2003 if (!p) continue;
2004
2005 if (!strcmp(str, p))
2006 return index;
2007 }
2008
2009 return -1;
2010 }
2011
2012 int
param_had_quote(int n)2013 param_had_quote(int n)
2014 {
2015 return params_quote & (1 << n);
2016 }
2017
2018