Imported Upstream version 1.7.1
[platform/upstream/edje.git] / src / bin / edje_cc_parse.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #ifdef HAVE_ALLOCA_H
6 # include <alloca.h>
7 #elif defined __GNUC__
8 # define alloca __builtin_alloca
9 #elif defined _AIX
10 # define alloca __alloca
11 #elif defined _MSC_VER
12 # include <malloc.h>
13 # define alloca _alloca
14 #else
15 # include <stddef.h>
16 # ifdef  __cplusplus
17 extern "C"
18 # endif
19 void *alloca (size_t);
20 #endif
21
22 #include <string.h>
23 #include <ctype.h>
24 #include <limits.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <math.h>
31
32 #include "edje_cc.h"
33 #include <Ecore.h>
34 #include <Ecore_File.h>
35
36 #ifdef _WIN32
37 # define EPP_EXT ".exe"
38 #else
39 # define EPP_EXT
40 #endif
41
42 static void  new_object(void);
43 static void  new_statement(void);
44 static char *perform_math (char *input);
45 static int   isdelim(char c);
46 static char *next_token(char *p, char *end, char **new_p, int *delim);
47 static char *stack_id(void);
48 static void  stack_chop_top(void);
49 static void  parse(char *data, off_t size);
50
51 /* simple expression parsing protos */
52 static int my_atoi(const char * s);
53 static char * _alphai(char *s, int * val);
54 static char * _betai(char *s, int * val);
55 static char * _gammai(char *s, int * val);
56 static char * _deltai(char *s, int * val);
57 static char * _get_numi(char *s, int * val);
58 static int _is_numi(char c);
59 static int _is_op1i(char c);
60 static int _is_op2i(char c);
61 static int _calci(char op, int a, int b);
62
63 static double my_atof(const char * s);
64 static char * _alphaf(char *s, double * val);
65 static char * _betaf(char *s, double * val);
66 static char * _gammaf(char *s, double * val);
67 static char * _deltaf(char *s, double * val);
68 static char * _get_numf(char *s, double * val);
69 static int _is_numf(char c);
70 static int _is_op1f(char c);
71 static int _is_op2f(char c);
72 static double _calcf(char op, double a, double b);
73 static int strstrip(const char *in, char *out, size_t size);
74
75
76 int        line = 0;
77 Eina_List *stack = NULL;
78 Eina_List *params = NULL;
79
80 static char  file_buf[4096];
81 static int   verbatim = 0;
82 static int   verbatim_line1 = 0;
83 static int   verbatim_line2 = 0;
84 static char *verbatim_str = NULL;
85
86 static void
87 err_show_stack(void)
88 {
89    char *s;
90    
91    s = stack_id();
92    if (s)
93      {
94         ERR("PARSE STACK:\n%s", s);
95         free(s);
96      }
97    else
98       ERR("NO PARSE STACK");
99 }
100
101 static void
102 err_show_params(void)
103 {
104    Eina_List *l;
105    char *p;
106
107    ERR("PARAMS:");
108    EINA_LIST_FOREACH(params, l, p)
109      {
110         ERR("  %s", p);
111      }
112 }
113
114 static void
115 err_show(void)
116 {
117    err_show_stack();
118    err_show_params();
119 }
120
121 static Eina_Hash *_new_object_hash = NULL;
122 static Eina_Hash *_new_statement_hash = NULL;
123 static void
124 fill_object_statement_hashes(void)
125 {
126    int i, n;
127
128    if (_new_object_hash) return;
129    
130    _new_object_hash = eina_hash_string_superfast_new(NULL);
131    _new_statement_hash = eina_hash_string_superfast_new(NULL);
132    
133    n = object_handler_num();
134    for (i = 0; i < n; i++)
135      {
136         eina_hash_add(_new_object_hash, object_handlers[i].type,
137                       &(object_handlers[i]));
138      }
139    n = statement_handler_num();
140    for (i = 0; i < n; i++)
141      {
142         eina_hash_add(_new_statement_hash, statement_handlers[i].type,
143                       &(statement_handlers[i]));
144      }
145 }
146
147 static void
148 new_object(void)
149 {
150    char *id;
151    New_Object_Handler *oh;
152    New_Statement_Handler *sh;
153
154    fill_object_statement_hashes();
155    id = stack_id();
156    oh = eina_hash_find(_new_object_hash, id);
157    if (oh)
158      {
159         if (oh->func) oh->func();
160      }
161    else
162      {
163         sh = eina_hash_find(_new_statement_hash, id);
164         if (!sh)
165           {
166              ERR("%s:%i unhandled keyword %s",
167                  file_in, line - 1,
168                  (char *)eina_list_data_get(eina_list_last(stack)));
169              err_show();
170              exit(-1);
171           }
172      }
173    free(id);
174 }
175
176 static void
177 new_statement(void)
178 {
179    char *id;
180    New_Statement_Handler *sh;
181
182    fill_object_statement_hashes();
183    id = stack_id();
184    sh = eina_hash_find(_new_statement_hash, id);
185    if (sh)
186      {
187         if (sh->func) sh->func();
188      }
189    else
190      {
191         ERR("%s:%i unhandled keyword %s",
192             file_in, line - 1,
193             (char *)eina_list_data_get(eina_list_last(stack)));
194         err_show();
195         exit(-1);
196      }
197    free(id);
198 }
199
200 static char *
201 perform_math (char *input)
202 {
203    char buf[256];
204    double res;
205
206    /* FIXME
207     * Always apply floating-point arithmetic.
208     * Does this cause problems for integer parameters? (yes it will)
209     *
210     * What we should do is, loop over the string and figure out whether
211     * there are floating point operands, too and then switch to
212     * floating point math.
213     */
214    res = my_atof(input);
215    snprintf(buf, sizeof (buf), "%lf", res);
216    return strdup(buf);
217 }
218
219 static int
220 isdelim(char c)
221 {
222    const char *delims = "{},;:";
223    char *d;
224
225    d = (char *)delims;
226    while (*d)
227      {
228         if (c == *d) return 1;
229         d++;
230      }
231    return 0;
232 }
233
234 static char *
235 next_token(char *p, char *end, char **new_p, int *delim)
236 {
237    char *tok_start = NULL, *tok_end = NULL, *tok = NULL, *sa_start = NULL;
238    int in_tok = 0;
239    int in_quote = 0;
240    int in_parens = 0;
241    int in_comment_ss  = 0;
242    int in_comment_cpp = 0;
243    int in_comment_sa  = 0;
244    int had_quote = 0;
245    int is_escaped = 0;
246
247    *delim = 0;
248    if (p >= end) return NULL;
249    while (p < end)
250      {
251         if (*p == '\n')
252           {
253              in_comment_ss = 0;
254              in_comment_cpp = 0;
255              line++;
256           }
257         if ((!in_comment_ss) && (!in_comment_sa))
258           {
259              if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '/'))
260                in_comment_ss = 1;
261              if ((!in_quote) && (*p == '#'))
262                in_comment_cpp = 1;
263              if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '*'))
264                {
265                   in_comment_sa = 1;
266                   sa_start = p;
267                }
268           }
269         if ((in_comment_cpp) && (*p == '#'))
270           {
271              char *pp, fl[4096];
272              char *tmpstr = NULL;
273              int   l, nm;
274
275              /* handle cpp comments */
276              /* their line format is
277               * #line <line no. of next line> <filename from next line on> [??]
278               */
279
280              pp = p;
281              while ((pp < end) && (*pp != '\n'))
282                {
283                   pp++;
284                }
285              l = pp - p;
286              tmpstr = alloca(l + 1);
287              if (!tmpstr)
288                {
289                   ERR("%s:%i malloc %i bytes failed",
290                       file_in, line - 1, l + 1);
291                   exit(-1);
292                }
293              strncpy(tmpstr, p, l);
294              tmpstr[l] = 0;
295              l = sscanf(tmpstr, "%*s %i \"%[^\"]\"", &nm, fl);
296              if (l == 2)
297                {
298                   strcpy(file_buf, fl);
299                   line = nm;
300                   file_in = file_buf;
301                }
302           }
303         else if ((!in_comment_ss) && (!in_comment_sa) && (!in_comment_cpp))
304           {
305              if (!in_tok)
306                {
307                   if (!in_quote)
308                     {
309                        if (!isspace(*p))
310                          {
311                             if (*p == '"')
312                               {
313                                  in_quote = 1;
314                                  had_quote = 1;
315                               }
316                             else if (*p == '(')
317                               in_parens++;
318
319                             in_tok = 1;
320                             tok_start = p;
321                             if (isdelim(*p)) *delim = 1;
322                          }
323                     }
324                }
325              else
326                {
327                   if (in_quote)
328                     {
329                        if ((*p) == '\\')
330                          is_escaped = !is_escaped;
331                        else if (((*p) == '"') && (!is_escaped))
332                          {
333                             in_quote = 0;
334                             had_quote = 1;
335                          }
336                        else if (is_escaped)
337                          is_escaped = 0;
338                     }
339                   else if (in_parens)
340                     {
341                        if (((*p) == ')') && (!is_escaped))
342                          in_parens--;
343                     }
344                   else
345                     {
346                        if (*p == '"')
347                          {
348                             in_quote = 1;
349                             had_quote = 1;
350                          }
351                        else if (*p == '(')
352                          in_parens++;
353
354                        /* check for end-of-token */
355                        if (
356                            (isspace(*p)) ||
357                            ((*delim) && (!isdelim(*p))) ||
358                            (isdelim(*p))
359                            )
360                          {/*the line below this is never  used because it skips to
361                            * the 'done' label which is after the return call for
362                            * in_tok being 0. is this intentional?
363                            */
364                             in_tok = 0;
365
366                             tok_end = p - 1;
367                             if (*p == '\n') line--;
368                             goto done;
369                          }
370                     }
371                }
372           }
373         if (in_comment_sa)
374           {
375              if ((*p == '/') && (*(p - 1) == '*') && ((p - sa_start) > 2))
376                in_comment_sa = 0;
377           }
378         p++;
379      }
380    if (!in_tok) return NULL;
381    tok_end = p - 1;
382
383    done:
384    *new_p = p;
385
386    tok = mem_alloc(tok_end - tok_start + 2);
387    strncpy(tok, tok_start, tok_end - tok_start + 1);
388    tok[tok_end - tok_start + 1] = 0;
389
390    if (had_quote)
391      {
392         is_escaped = 0;
393         p = tok;
394
395         while (*p)
396           {
397              if ((*p == '\"') && (!is_escaped))
398                {
399                   memmove(p, p + 1, strlen(p));
400                }
401              else if ((*p == '\\') && (*(p + 1) == 'n'))
402                {
403                   memmove(p, p + 1, strlen(p));
404                   *p = '\n';
405                }
406              else if ((*p == '\\') && (*(p + 1) == 't'))
407                {
408                   memmove(p, p + 1, strlen(p));
409                   *p = '\t';
410                }
411              else if (*p == '\\')
412                {
413                   memmove(p, p + 1, strlen(p));
414                   if (*p == '\\') p++;
415                   else is_escaped = 1;
416                }
417              else
418                {
419                   if (is_escaped) is_escaped = 0;
420                   p++;
421                }
422           }
423      }
424    else if ((tok) && (*tok == '('))
425      {
426         char *tmp;
427         tmp = tok;
428         tok = perform_math(tok);
429         free(tmp);
430      }
431
432    return tok;
433 }
434
435 static char *
436 stack_id(void)
437 {
438    char *id;
439    int len;
440    Eina_List *l;
441    char *data;
442
443    len = 0;
444    EINA_LIST_FOREACH(stack, l, data)
445      len += strlen(data) + 1;
446    id = mem_alloc(len);
447    id[0] = 0;
448    EINA_LIST_FOREACH(stack, l, data)
449      {
450         strcat(id, data);
451         if (eina_list_next(l)) strcat(id, ".");
452      }
453    return id;
454 }
455
456 static void
457 stack_chop_top(void)
458 {
459    char *top;
460
461    /* remove top from stack */
462    top = eina_list_data_get(eina_list_last(stack));
463    if (top)
464      {
465         free(top);
466         stack = eina_list_remove(stack, top);
467      }
468    else
469      {
470         ERR("parse error %s:%i. } marker without matching { marker",
471             file_in, line - 1);
472         err_show();
473         exit(-1);
474      }
475 }
476
477 static void
478 parse(char *data, off_t size)
479 {
480    char *p, *end, *token;
481    int delim = 0;
482    int do_params = 0;
483
484    DBG("Parsing input file");
485
486    p = data;
487    end = data + size;
488    line = 1;
489    while ((token = next_token(p, end, &p, &delim)))
490      {
491         /* if we are in param mode, the only delimiter
492          * we'll accept is the semicolon
493          */
494         if (do_params && delim && *token != ';')
495           {
496              ERR("parse error %s:%i. %c marker before ; marker",
497                  file_in, line - 1, *token);
498              err_show();
499              exit(-1);
500           }
501         else if (delim)
502           {
503              if (*token == ',' || *token == ':') do_params = 1;
504              else if (*token == '}')
505                {
506                   if (do_params)
507                     {
508                        ERR("Parse error %s:%i. } marker before ; marker",
509                            file_in, line - 1);
510                        err_show();
511                        exit(-1);
512                     }
513                   else
514                     stack_chop_top();
515                }
516              else if (*token == ';')
517                {
518                   if (do_params)
519                     {
520                        do_params = 0;
521                        new_statement();
522                        /* clear out params */
523                        while (params)
524                          {
525                             free(eina_list_data_get(params));
526                             params = eina_list_remove(params, eina_list_data_get(params));
527                          }
528                        /* remove top from stack */
529                        stack_chop_top();
530                     }
531                }
532              else if (*token == '{')
533                {
534                   if (do_params)
535                     {
536                        ERR("parse error %s:%i. { marker before ; marker",
537                            file_in, line - 1);
538                        err_show();
539                        exit(-1);
540                     }
541                }
542              free(token);
543           }
544         else
545           {
546              if (do_params)
547                params = eina_list_append(params, token);
548              else
549                {
550                   stack = eina_list_append(stack, token);
551                   new_object();
552                   if ((verbatim == 1) && (p < (end - 2)))
553                     {
554                        int escaped = 0;
555                        int inquotes = 0;
556                        int insquotes = 0;
557                        int squigglie = 1;
558                        int l1 = 0, l2 = 0;
559                        char *verbatim_1;
560                        char *verbatim_2;
561
562                        l1 = line;
563                        while ((p[0] != '{') && (p < end))
564                          {
565                             if (*p == '\n') line++;
566                             p++;
567                          }
568                        p++;
569                        verbatim_1 = p;
570                        verbatim_2 = NULL;
571                        for (; p < end; p++)
572                          {
573                             if (*p == '\n') line++;
574                             if (escaped) escaped = 0;
575                             if (!escaped)
576                               {
577                                  if (p[0] == '\\') escaped = 1;
578                                  else if (p[0] == '\"')
579                                    {
580                                       if (!insquotes)
581                                         {
582                                            if (inquotes) inquotes = 0;
583                                            else inquotes = 1;
584                                         }
585                                    }
586                                  else if (p[0] == '\'')
587                                    {
588                                       if (!inquotes)
589                                         {
590                                            if (insquotes) insquotes = 0;
591                                            else insquotes = 1;
592                                         }
593                                    }
594                                  else if ((!inquotes) && (!insquotes))
595                                    {
596                                       if      (p[0] == '{') squigglie++;
597                                       else if (p[0] == '}') squigglie--;
598                                       if (squigglie == 0)
599                                         {
600                                            verbatim_2 = p - 1;
601                                            l2 = line;
602                                            break;
603                                         }
604                                    }
605                               }
606                          }
607                        if (verbatim_2 > verbatim_1)
608                          {
609                             int l;
610                             char *v;
611
612                             l = verbatim_2 - verbatim_1 + 1;
613                             v = malloc(l + 1);
614                             strncpy(v, verbatim_1, l);
615                             v[l] = 0;
616                             set_verbatim(v, l1, l2);
617                          }
618                        else
619                          {
620                             ERR("Parse error %s:%i. { marker does not have matching } marker",
621                                 file_in, line - 1);
622                             err_show();
623                             exit(-1);
624                          }
625                        new_object();
626                        verbatim = 0;
627                     }
628                }
629           }
630      }
631
632    DBG("Parsing done");
633 }
634
635 static char *clean_file = NULL;
636 static void
637 clean_tmp_file(void)
638 {
639    if (clean_file) unlink(clean_file);
640 }
641
642 int
643 is_verbatim(void)
644 {
645    return verbatim;
646 }
647
648 void
649 track_verbatim(int on)
650 {
651    verbatim = on;
652 }
653
654 void
655 set_verbatim(char *s, int l1, int l2)
656 {
657    verbatim_line1 = l1;
658    verbatim_line2 = l2;
659    verbatim_str = s;
660 }
661
662 char *
663 get_verbatim(void)
664 {
665    return verbatim_str;
666 }
667
668 int
669 get_verbatim_line1(void)
670 {
671    return verbatim_line1;
672 }
673
674 int
675 get_verbatim_line2(void)
676 {
677    return verbatim_line2;
678 }
679
680 void
681 compile(void)
682 {
683    char buf[4096], buf2[4096];
684    char inc[4096];
685    static char tmpn[4096];
686    int fd;
687    off_t size;
688    char *data, *p;
689    Eina_List *l;
690    Edje_Style *stl;
691
692    if (!tmp_dir)
693 #ifdef HAVE_EVIL
694      tmp_dir = (char *)evil_tmpdir_get();
695 #else
696      tmp_dir = "/tmp";
697 #endif
698
699    strncpy(inc, file_in, 4000);
700    inc[4001] = 0;
701    p = strrchr(inc, '/');
702    if (!p) strcpy(inc, "./");
703    else *p = 0;
704    snprintf(tmpn, PATH_MAX, "%s/edje_cc.edc-tmp-XXXXXX", tmp_dir);
705    fd = mkstemp(tmpn);
706    if (fd >= 0)
707      {
708         int ret;
709         char *def;
710
711         clean_file = tmpn;
712         close(fd);
713         atexit(clean_tmp_file);
714         if (!defines)
715           def = mem_strdup("");
716         else
717           {
718              int len;
719              char *define;
720
721              len = 0;
722              EINA_LIST_FOREACH(defines, l, define)
723                len += strlen(define) + 1;
724              def = mem_alloc(len + 1);
725              def[0] = 0;
726              EINA_LIST_FOREACH(defines, l, define)
727                {
728                   strcat(def, define);
729                   strcat(def, " ");
730                }
731           }
732
733         /*
734          * Run the input through the C pre-processor.
735          */
736         ret = -1;
737         snprintf(buf2, sizeof(buf2), "%s/edje/utils/epp" EPP_EXT, 
738                  eina_prefix_lib_get(pfx));
739         if (ecore_file_exists(buf2))
740           {
741              snprintf(buf, sizeof(buf), "%s -a %s %s -I%s %s -o %s",
742                       buf2, watchfile ? watchfile : "/dev/null", file_in, inc, def, tmpn);
743              ret = system(buf);
744           }
745         else
746           {
747              ERR("Cannot run epp: %s", buf2);
748              exit(-1);
749           }
750         if (ret == EXIT_SUCCESS)
751           file_in = tmpn;
752         else
753           {
754              ERR("Exit code of epp not clean: %i", ret);
755              exit(-1);
756           }
757         free(def);
758      }
759    fd = open(file_in, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
760    if (fd < 0)
761      {
762         ERR("Cannot open file \"%s\" for input. %s",
763             file_in, strerror(errno));
764         exit(-1);
765      }
766    DBG("Opening \"%s\" for input", file_in);
767
768    size = lseek(fd, 0, SEEK_END);
769    lseek(fd, 0, SEEK_SET);
770    data = malloc(size);
771    if (data && (read(fd, data, size) == size))
772       parse(data, size);
773    else
774      {
775         ERR("Cannot read file \"%s\". %s", file_in, strerror(errno));
776         exit(-1);
777      }
778    free(data);
779    close(fd);
780
781    EINA_LIST_FOREACH(edje_file->styles, l, stl)
782      {
783         if (!stl->name)
784           {
785              ERR("style must have a name.");
786              exit(-1);
787           }
788      }
789 }
790
791 int
792 is_param(int n)
793 {
794    char *str;
795
796    str = eina_list_nth(params, n);
797    if (str) return 1;
798    return 0;
799 }
800
801 int
802 is_num(int n)
803 {
804    char *str;
805    char *end;
806    long int ret;
807    
808    str = eina_list_nth(params, n);
809    if (!str)
810      {
811         ERR("%s:%i no parameter supplied as argument %i",
812                 file_in, line - 1, n + 1);
813         err_show();
814         exit(-1);
815      }
816    if (str[0] == 0) return 0;
817    end = str;
818    ret = strtol(str, &end, 0);
819    if ((ret == LONG_MIN) || (ret == LONG_MAX))
820      {
821         n = 0; // do nothing. shut gcc warnings up
822      }
823    if ((end != str) && (end[0] == 0)) return 1;
824    return 0;
825 }
826
827 char *
828 parse_str(int n)
829 {
830    char *str;
831    char *s;
832
833    str = eina_list_nth(params, n);
834    if (!str)
835      {
836         ERR("%s:%i no parameter supplied as argument %i",
837             file_in, line - 1, n + 1);
838         err_show();
839         exit(-1);
840      }
841    s = mem_strdup(str);
842    return s;
843 }
844
845 static int
846 _parse_enum(char *str, va_list va)
847 {
848    va_list va2;
849    va_copy(va2, va); /* iterator for the error message */
850
851    for (;;)
852      {
853         char *s;
854         int   v;
855
856         s = va_arg(va, char *);
857
858         /* End of the list, nothing matched. */
859         if (!s)
860           {
861              ERR("%s:%i token %s not one of:", file_in, line - 1, str);
862              s = va_arg(va2, char *);
863              while (s)
864                {
865                   va_arg(va2, int);
866                   fprintf(stderr, " %s", s);
867                   s = va_arg(va2, char *);
868                   if (!s) break;
869                }
870              fprintf(stderr, "\n");
871              va_end(va2);
872              va_end(va);
873              err_show();
874              exit(-1);
875           }
876
877         v = va_arg(va, int);
878         if (!strcmp(s, str))
879           {
880              va_end(va2);
881              va_end(va);
882              return v;
883           }
884      }
885    va_end(va2);
886    va_end(va);
887    return 0;
888 }
889
890 int
891 parse_enum(int n, ...)
892 {
893    char *str;
894    int result;
895    va_list va;
896
897    str = eina_list_nth(params, n);
898    if (!str)
899      {
900         ERR("%s:%i no parameter supplied as argument %i",
901             file_in, line - 1, n + 1);
902         err_show();
903         exit(-1);
904      }
905
906    va_start(va, n);
907    result = _parse_enum(str, va);
908    va_end(va);
909
910    return result;
911 }
912
913 int
914 parse_flags(int n, ...)
915 {
916    Eina_List *lst;
917    int result = 0;
918    va_list va;
919    char *data;
920
921    va_start(va, n);
922    EINA_LIST_FOREACH(eina_list_nth_list(params, n), lst, data)
923      result |= _parse_enum(data, va);
924    va_end(va);
925
926    return result;
927 }
928
929 int
930 parse_int(int n)
931 {
932    char *str;
933    int i;
934
935    str = eina_list_nth(params, n);
936    if (!str)
937      {
938         ERR("%s:%i no parameter supplied as argument %i",
939             file_in, line - 1, n + 1);
940         err_show();
941         exit(-1);
942      }
943    i = my_atoi(str);
944    return i;
945 }
946
947 int
948 parse_int_range(int n, int f, int t)
949 {
950    char *str;
951    int i;
952
953    str = eina_list_nth(params, n);
954    if (!str)
955      {
956         ERR("%s:%i no parameter supplied as argument %i",
957             file_in, line - 1, n + 1);
958         err_show();
959         exit(-1);
960      }
961    i = my_atoi(str);
962    if ((i < f) || (i > t))
963      {
964         ERR("%s:%i integer %i out of range of %i to %i inclusive",
965             file_in, line - 1, i, f, t);
966         err_show();
967         exit(-1);
968      }
969    return i;
970 }
971
972 int
973 parse_bool(int n)
974 {
975    char *str, buf[4096];
976    int i;
977
978    str = eina_list_nth(params, n);
979    if (!str)
980      {
981         ERR("%s:%i no parameter supplied as argument %i",
982             file_in, line - 1, n + 1);
983         err_show();
984         exit(-1);
985      }
986
987    if (!strstrip(str, buf, sizeof (buf)))
988      {
989         ERR("%s:%i expression is too long",
990             file_in, line - 1);
991         return 0;
992      }
993
994    if (!strcasecmp(buf, "false") || !strcasecmp(buf, "off"))
995       return 0;
996    if (!strcasecmp(buf, "true") || !strcasecmp(buf, "on"))
997       return 1;
998
999    i = my_atoi(str);
1000    if ((i < 0) || (i > 1))
1001      {
1002         ERR("%s:%i integer %i out of range of 0 to 1 inclusive",
1003             file_in, line - 1, i);
1004         err_show();
1005         exit(-1);
1006      }
1007    return i;
1008 }
1009
1010 double
1011 parse_float(int n)
1012 {
1013    char *str;
1014    double i;
1015
1016    str = eina_list_nth(params, n);
1017    if (!str)
1018      {
1019         ERR("%s:%i no parameter supplied as argument %i",
1020             file_in, line - 1, n + 1);
1021         err_show();
1022         exit(-1);
1023      }
1024    i = my_atof(str);
1025    return i;
1026 }
1027
1028 double
1029 parse_float_range(int n, double f, double t)
1030 {
1031    char *str;
1032    double i;
1033
1034    str = eina_list_nth(params, n);
1035    if (!str)
1036      {
1037         ERR("%s:%i no parameter supplied as argument %i",
1038             file_in, line - 1, n + 1);
1039         err_show();
1040         exit(-1);
1041      }
1042    i = my_atof(str);
1043    if ((i < f) || (i > t))
1044      {
1045         ERR("%s:%i float %3.3f out of range of %3.3f to %3.3f inclusive",
1046             file_in, line - 1, i, f, t);
1047         err_show();
1048         exit(-1);
1049      }
1050    return i;
1051 }
1052
1053 int
1054 get_arg_count(void)
1055 {
1056    return eina_list_count (params);
1057 }
1058
1059 void
1060 check_arg_count(int required_args)
1061 {
1062    int num_args = eina_list_count (params);
1063
1064    if (num_args != required_args)
1065      {
1066         ERR("%s:%i got %i arguments, but expected %i",
1067             file_in, line - 1, num_args, required_args);
1068         err_show();
1069         exit(-1);
1070      }
1071 }
1072
1073 void
1074 check_min_arg_count(int min_required_args)
1075 {
1076    int num_args = eina_list_count (params);
1077
1078    if (num_args < min_required_args)
1079      {
1080         ERR("%s:%i got %i arguments, but expected at least %i",
1081             file_in, line - 1, num_args, min_required_args);
1082         err_show();
1083         exit(-1);
1084      }
1085 }
1086
1087 /* simple expression parsing stuff */
1088
1089 /*
1090  * alpha ::= beta + beta || beta
1091  * beta  ::= gamma + gamma || gamma
1092  * gamma ::= num || delta
1093  * delta ::= '(' alpha ')'
1094  *
1095  */
1096
1097 /* int set of function */
1098
1099 static int
1100 my_atoi(const char *s)
1101 {
1102    int res = 0;
1103    char buf[4096];
1104    
1105    if (!s) return 0;
1106    if (!strstrip(s, buf, sizeof(buf)))
1107      {
1108         ERR("%s:%i expression is too long",
1109             file_in, line - 1);
1110         return 0;
1111      }
1112    _alphai(buf, &res);
1113    return res;
1114 }
1115
1116 static char *
1117 _deltai(char *s, int *val)
1118 {
1119    if (!val) return NULL;
1120    if ('(' != s[0])
1121      {
1122         ERR("%s:%i unexpected character at %s",
1123             file_in, line - 1, s);
1124         return s;
1125      }
1126    else
1127      {
1128         s++;
1129         s = _alphai(s, val);
1130         s++;
1131         return s;
1132      }
1133    return s;
1134 }
1135
1136 static char *
1137 _funci(char *s, int *val)
1138 {
1139    if (!strncmp(s, "floor(", 6))
1140      {
1141         s += 5;
1142         s = _deltai(s, val);
1143         *val = *val;
1144      }
1145    else if (!strncmp(s, "ceil(", 5))
1146      {
1147         s += 4;
1148         s = _deltai(s, val);
1149         *val = *val;
1150      }
1151    else
1152      {
1153         ERR("%s:%i unexpected character at %s",
1154             file_in, line - 1, s);
1155      }
1156    return s;
1157 }
1158
1159 static char *
1160 _gammai(char *s, int *val)
1161 {
1162    if (!val) return NULL;
1163    if (_is_numi(s[0]))
1164      {
1165         s = _get_numi(s, val);
1166         return s;
1167      }
1168    else if ('(' == s[0])
1169      {
1170         s = _deltai(s, val);
1171         return s;
1172      }
1173    else
1174      {
1175         s = _funci(s, val);
1176 //        ERR("%s:%i unexpected character at %s",
1177 //                progname, file_in, line - 1, s);
1178      }
1179    return s;
1180 }
1181
1182 static char *
1183 _betai(char *s, int *val)
1184 {
1185    int a1, a2;
1186    char op;
1187
1188    if (!val) return NULL;
1189    s = _gammai(s, &a1);
1190    while (_is_op1i(s[0]))
1191      {
1192         op = s[0];
1193         s++;
1194         s = _gammai(s, &a2);
1195         a1 = _calci(op, a1, a2);
1196      }
1197    (*val) = a1;
1198    return s;
1199 }
1200
1201 static char *
1202 _alphai(char *s, int *val)
1203 {
1204    int a1, a2;
1205    char op;
1206    
1207    if (!val) return NULL;
1208    s = _betai(s, &a1);
1209    while (_is_op2i(s[0]))
1210      {
1211         op = s[0];
1212         s++;
1213         s = _betai(s, &a2);
1214         a1 = _calci(op, a1, a2);
1215      }
1216    (*val) = a1;
1217    return s;
1218 }
1219
1220 char *
1221 _get_numi(char *s, int *val)
1222 {
1223    char buf[4096];
1224    int pos = 0;
1225    
1226    if (!val) return s;
1227    while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
1228           ((0 == pos) && ('-' == s[pos])))
1229      {
1230         buf[pos] = s[pos];
1231         pos++;
1232      }
1233    buf[pos] = '\0';
1234    (*val) = atoi(buf);
1235    return (s + pos);
1236 }
1237
1238 int
1239 _is_numi(char c)
1240 {
1241    if (((c >= '0') && (c <= '9')) || ('-' == c) || ('+' == c))
1242      return 1;
1243    else
1244      return 0;
1245 }
1246
1247 int
1248 _is_op1i(char c)
1249 {
1250    switch (c)
1251      {
1252      case '*':;
1253      case '%':;
1254      case '/': return 1;
1255      default: break;
1256      }
1257    return 0;
1258 }
1259
1260 int
1261 _is_op2i(char c)
1262 {
1263    switch (c)
1264      {
1265      case '+':;
1266      case '-': return 1;
1267      default: break;
1268      }
1269    return 0;
1270 }
1271
1272 int
1273 _calci(char op, int a, int b)
1274 {
1275    switch(op)
1276      {
1277      case '+':
1278         a += b;
1279         return a;
1280      case '-':
1281         a -= b;
1282         return a;
1283      case '/':
1284         if (0 != b) a /= b;
1285         else
1286           ERR("%s:%i divide by zero", file_in, line - 1);
1287         return a;
1288      case '*':
1289         a *= b;
1290         return a;
1291      case '%':
1292         if (0 != b) a = a % b;
1293         else
1294           ERR("%s:%i modula by zero", file_in, line - 1);
1295         return a;
1296      default:
1297         ERR("%s:%i unexpected character '%c'", file_in, line - 1, op);
1298      }
1299    return a;
1300 }
1301
1302 /* float set of functoins */
1303
1304 double
1305 my_atof(const char *s)
1306 {
1307    double res = 0;
1308    char buf[4096];
1309    
1310    if (!s) return 0;
1311
1312    if (!strstrip(s, buf, sizeof (buf)))
1313      {
1314         ERR("%s:%i expression is too long", file_in, line - 1);
1315         return 0;
1316      }
1317    _alphaf(buf, &res);
1318    return res;
1319 }
1320
1321 static char *
1322 _deltaf(char *s, double *val)
1323 {
1324    if (!val) return NULL;
1325    if ('(' != s[0])
1326      {
1327         ERR("%s:%i unexpected character at %s", file_in, line - 1, s);
1328         return s;
1329      }
1330    else
1331      {
1332         s++;
1333         s = _alphaf(s, val);
1334         s++;
1335      }
1336    return s;
1337 }
1338
1339 static char *
1340 _funcf(char *s, double *val)
1341 {
1342    if (!strncmp(s, "floor(", 6))
1343      {
1344         s += 5;
1345         s = _deltaf(s, val);
1346         *val = floor(*val);
1347      }
1348    else if (!strncmp(s, "ceil(", 5))
1349      {
1350         s += 4;
1351         s = _deltaf(s, val);
1352         *val = ceil(*val);
1353      }
1354    else
1355      {
1356         ERR("%s:%i unexpected character at %s", file_in, line - 1, s);
1357      }
1358    return s;
1359 }
1360
1361 static char *
1362 _gammaf(char *s, double *val)
1363 {
1364    if (!val) return NULL;
1365    
1366    if (_is_numf(s[0]))
1367      {
1368         s = _get_numf(s, val);
1369         return s;
1370      }
1371    else if ('(' == s[0])
1372      {
1373         s = _deltaf(s, val);
1374         return s;
1375      }
1376    else
1377      {
1378         s = _funcf(s, val);
1379 //        ERR("%s:%i unexpected character at %s",
1380 //                progname, file_in, line - 1, s);
1381      }
1382    return s;
1383 }
1384
1385 static char *
1386 _betaf(char *s, double *val)
1387 {
1388    double a1=0, a2=0;
1389    char op;
1390    
1391    if (!val) return NULL;
1392    s = _gammaf(s, &a1);
1393    while (_is_op1f(s[0]))
1394      {
1395         op = s[0];
1396         s++;
1397         s = _gammaf(s, &a2);
1398         a1 = _calcf(op, a1, a2);
1399      }
1400    (*val) = a1;
1401    return s;
1402 }
1403
1404 static char *
1405 _alphaf(char *s, double *val)
1406 {
1407    double a1=0, a2=0;
1408    char op;
1409
1410    if (!val) return NULL;
1411    s = _betaf(s, &a1);
1412    while (_is_op2f(s[0]))
1413      {
1414         op = s[0];
1415         s++;
1416         s = _betaf(s, &a2);
1417         a1 = _calcf(op, a1, a2);
1418      }
1419    (*val) = a1;
1420    return s;
1421 }
1422
1423 static char *
1424 _get_numf(char *s, double *val)
1425 {
1426    char buf[4096];
1427    int pos = 0;
1428
1429    if (!val) return s;
1430
1431    while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
1432           ('.' == s[pos]) ||
1433           ((0 == pos) && ('-' == s[pos])))
1434      {
1435         buf[pos] = s[pos];
1436         pos++;
1437      }
1438    buf[pos] = '\0';
1439    (*val) = atof(buf);
1440    return (s+pos);
1441 }
1442
1443 static int
1444 _is_numf(char c)
1445 {
1446    if (((c >= '0') && (c <= '9'))
1447        || ('-' == c)
1448        || ('.' == c)
1449        || ('+' == c))
1450      return 1;
1451    return 0;
1452 }
1453
1454 static int
1455 _is_op1f(char c)
1456 {
1457    switch(c)
1458      {
1459      case '*':;
1460      case '%':;
1461      case '/': return 1;
1462      default: break;
1463      }
1464    return 0;
1465 }
1466
1467 static int
1468 _is_op2f(char c)
1469 {
1470    switch(c)
1471      {
1472      case '+':;
1473      case '-': return 1;
1474      default: break;
1475      }
1476    return 0;
1477 }
1478
1479 static double
1480 _calcf(char op, double a, double b)
1481 {
1482    switch(op)
1483      {
1484      case '+':
1485         a += b;
1486         return a;
1487      case '-':
1488         a -= b;
1489         return a;
1490      case '/':
1491         if (b != 0) a /= b;
1492         else
1493           ERR("%s:%i divide by zero", file_in, line - 1);
1494         return a;
1495      case '*':
1496         a *= b;
1497         return a;
1498      case '%':
1499         if (0 != b) a = (double)((int)a % (int)b);
1500         else
1501           ERR("%s:%i modula by zero", file_in, line - 1);
1502         return a;
1503      default:
1504         ERR("%s:%i unexpected character '%c'", file_in, line - 1, op);
1505      }
1506    return a;
1507 }
1508
1509 static int
1510 strstrip(const char *in, char *out, size_t size)
1511 {
1512    if ((size -1 ) < strlen(in))
1513      {
1514         ERR("%s:%i expression is too long", file_in, line - 1);
1515         return 0;
1516      }
1517    /* remove spaces and tabs */
1518    while (*in)
1519      {
1520         if ((0x20 != *in) && (0x09 != *in))
1521           {
1522              *out = *in;
1523              out++;
1524           }
1525         in++;
1526      }
1527    *out = '\0';
1528    return 1;
1529 }