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