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(&params, 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(&params))
129      return eina_array_data_get(&params, 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(&params)))
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(&params));
876                   eina_array_push(&params, token);
877                }
878              else if (do_indexes)
879                {
880                   if (had_quote)
881                     params_quote |= (1 << eina_array_count(&params));
882                   do_indexes++;
883                   eina_array_push(&params, 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(&params, sizeof (Eina_Array), 8);
1176         parse(data, size);
1177         eina_array_flush(&params);
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(&params))
1342      {
1343         result |= _parse_enum(eina_array_data_get(&params, 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(&params);
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(&params);
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(&params);
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(&params);
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