efl

Форк
0
/
edje_cc_parse.c 
2018 строк · 47.9 Кб
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
#define EDJE_1_26_SUPPORTED " -DEFL_VERSION_1_26=1 "
36

37
#define EDJE_CC_EFL_VERSION_SUPPORTED \
38
  EDJE_1_18_SUPPORTED                 \
39
  EDJE_1_19_SUPPORTED                 \
40
  EDJE_1_20_SUPPORTED                 \
41
  EDJE_1_21_SUPPORTED                 \
42
  EDJE_1_22_SUPPORTED                 \
43
  EDJE_1_23_SUPPORTED                 \
44
  EDJE_1_24_SUPPORTED                 \
45
  EDJE_1_25_SUPPORTED                 \
46
  EDJE_1_26_SUPPORTED
47

48
static void        new_object(void);
49
static void        new_statement(void);
50
static char       *perform_math(char *input);
51
static int         isdelim(char c);
52
static char       *next_token(char *p, char *end, char **new_p, int *delim);
53
static const char *stack_id(void);
54
static void        parse(char *data, off_t size);
55

56
/* simple expression parsing protos */
57
static int         my_atoi(const char *s);
58
static char       *_alphai(char *s, int *val);
59
static char       *_betai(char *s, int *val);
60
static char       *_gammai(char *s, int *val);
61
static char       *_deltai(char *s, int *val);
62
static char       *_get_numi(char *s, int *val);
63
static int         _is_numi(char c);
64
static int         _is_op1i(char c);
65
static int         _is_op2i(char c);
66
static int         _calci(char op, int a, int b);
67

68
static double      my_atof(const char *s);
69
static char       *_alphaf(char *s, double *val);
70
static char       *_betaf(char *s, double *val);
71
static char       *_gammaf(char *s, double *val);
72
static char       *_deltaf(char *s, double *val);
73
static char       *_get_numf(char *s, double *val);
74
static int         _is_numf(char c);
75
static int         _is_op1f(char c);
76
static int         _is_op2f(char c);
77
static double      _calcf(char op, double a, double b);
78
static int         strstrip(const char *in, char *out, size_t size);
79

80
int line = 0;
81
Eina_List *stack = NULL;
82
Eina_Array params;
83
int had_quote = 0;
84
int params_quote = 0;
85

86
static char file_buf[4096];
87
static int did_wildcard = 0;
88
static int verbatim = 0;
89
static int verbatim_line1 = 0;
90
static int verbatim_line2 = 0;
91
static char *verbatim_str = NULL;
92
static Eina_Strbuf *stack_buf = NULL;
93

94
static void
95
err_show_stack(void)
96
{
97
   const char *s;
98

99
   s = stack_id();
100
   if (s)
101
     ERR("PARSE STACK:\n%s", s);
102
   else
103
     ERR("NO PARSE STACK");
104
}
105

106
static void
107
err_show_params(void)
108
{
109
   Eina_Array_Iterator iterator;
110
   unsigned int i;
111
   char *p;
112

113
   ERR("PARAMS:");
114
   EINA_ARRAY_ITER_NEXT(&params, i, p, iterator)
115
   {
116
      ERR("  %s", p);
117
   }
118
}
119

120
static void
121
err_show(void)
122
{
123
   err_show_stack();
124
   err_show_params();
125
}
126

127
static char *
128
_parse_param_get(int n)
129
{
130
   if (n < (int)eina_array_count(&params))
131
     return eina_array_data_get(&params, n);
132
   return NULL;
133
}
134

135
static Eina_Hash *_new_object_hash = NULL;
136
static Eina_Hash *_new_object_short_hash = NULL;
137
static Eina_Hash *_new_statement_hash = NULL;
138
static Eina_Hash *_new_statement_short_hash = NULL;
139
static Eina_Hash *_new_statement_short_single_hash = NULL;
140
static Eina_Hash *_new_nested_hash = NULL;
141
static Eina_Hash *_new_nested_short_hash = NULL;
142
static void
143
fill_object_statement_hashes(void)
144
{
145
   int i, n;
146

147
   if (_new_object_hash) return;
148

149
   _new_object_hash = eina_hash_string_superfast_new(NULL);
150
   _new_object_short_hash = eina_hash_string_superfast_new(NULL);
151
   _new_statement_hash = eina_hash_string_superfast_new(NULL);
152
   _new_statement_short_hash = eina_hash_string_superfast_new(NULL);
153
   _new_statement_short_single_hash = eina_hash_string_superfast_new(NULL);
154
   _new_nested_hash = eina_hash_string_superfast_new(NULL);
155
   _new_nested_short_hash = eina_hash_string_superfast_new(NULL);
156

157
   n = object_handler_num();
158
   for (i = 0; i < n; i++)
159
     {
160
        eina_hash_direct_add(_new_object_hash, object_handlers[i].type,
161
                             &(object_handlers[i]));
162
     }
163
   n = object_handler_short_num();
164
   for (i = 0; i < n; i++)
165
     {
166
        eina_hash_direct_add(_new_object_short_hash, object_handlers_short[i].type,
167
                             &(object_handlers_short[i]));
168
     }
169
   n = statement_handler_num();
170
   for (i = 0; i < n; i++)
171
     {
172
        eina_hash_direct_add(_new_statement_hash, statement_handlers[i].type,
173
                             &(statement_handlers[i]));
174
     }
175
   n = statement_handler_short_num();
176
   for (i = 0; i < n; i++)
177
     {
178
        eina_hash_direct_add(_new_statement_short_hash, statement_handlers_short[i].type,
179
                             &(statement_handlers_short[i]));
180
     }
181
   n = statement_handler_short_single_num();
182
   for (i = 0; i < n; i++)
183
     {
184
        eina_hash_direct_add(_new_statement_short_single_hash, statement_handlers_short_single[i].type,
185
                             &(statement_handlers_short_single[i]));
186
     }
187
   n = nested_handler_num();
188
   for (i = 0; i < n; i++)
189
     {
190
        eina_hash_direct_add(_new_nested_hash, nested_handlers[i].type,
191
                             &(nested_handlers[i]));
192
     }
193
   n = nested_handler_short_num();
194
   for (i = 0; i < n; i++)
195
     {
196
        eina_hash_direct_add(_new_nested_short_hash, nested_handlers_short[i].type,
197
                             &(nested_handlers_short[i]));
198
     }
199
}
200

201
static char *
202
stack_dup_wildcard(void)
203
{
204
   char buf[PATH_MAX] = { 0, };
205
   char *end;
206

207
   strncpy(buf, stack_id(), sizeof(buf) - 1);
208

209
   end = strrchr(buf, '.');
210
   if (end) end++;
211
   else end = buf;
212

213
   strcpy(end, "*");
214

215
   return eina_strdup(buf);
216
}
217

218
static void
219
new_object(void)
220
{
221
   const char *id;
222
   New_Object_Handler *oh = NULL;
223
   New_Statement_Handler *sh;
224

225
   fill_object_statement_hashes();
226
   id = stack_id();
227
   if (!had_quote)
228
     {
229
        oh = eina_hash_find(_new_object_hash, id);
230
        if (!oh)
231
          oh = eina_hash_find(_new_object_short_hash, id);
232
     }
233
   if (oh)
234
     {
235
        if (oh->func) oh->func();
236
     }
237
   else
238
     {
239
        did_wildcard = edje_cc_handlers_wildcard();
240
        if (!did_wildcard)
241
          {
242
             sh = eina_hash_find(_new_statement_hash, id);
243
             if (!sh)
244
               sh = eina_hash_find(_new_statement_short_hash, id);
245
             if (!sh)
246
               sh = eina_hash_find(_new_statement_short_single_hash, id);
247
             if (!sh)
248
               {
249
                  char *tmp = stack_dup_wildcard();
250
                  sh = eina_hash_find(_new_statement_hash, tmp);
251
                  free(tmp);
252
               }
253
             if ((!sh) && (!did_wildcard) && (!had_quote))
254
               {
255
                  ERR("%s:%i unhandled keyword %s",
256
                      file_in, line - 1,
257
                      (char *)eina_list_data_get(eina_list_last(stack)));
258
                  err_show();
259
                  exit(-1);
260
               }
261
             did_wildcard = !sh;
262
          }
263
     }
264
}
265

266
static void
267
new_statement(void)
268
{
269
   const char *id;
270
   New_Statement_Handler *sh = NULL;
271
   fill_object_statement_hashes();
272
   id = stack_id();
273
   sh = eina_hash_find(_new_statement_hash, id);
274
   if (!sh)
275
     sh = eina_hash_find(_new_statement_short_hash, id);
276
   if (sh)
277
     {
278
        if (sh->func) sh->func();
279
     }
280
   else
281
     {
282
        char *tmp = stack_dup_wildcard();
283
        sh = eina_hash_find(_new_statement_hash, tmp);
284
        free(tmp);
285

286
        if (sh)
287
          {
288
             if (sh->func) sh->func();
289
          }
290
        else
291
          {
292
             ERR("%s:%i unhandled keyword %s",
293
                 file_in, line - 1,
294
                 (char *)eina_list_data_get(eina_list_last(stack)));
295
             err_show();
296
             exit(-1);
297
          }
298
     }
299
}
300

301
static Eina_Bool
302
new_statement_single(void)
303
{
304
   const char *id;
305
   New_Statement_Handler *sh = NULL;
306
   fill_object_statement_hashes();
307
   id = stack_id();
308
   sh = eina_hash_find(_new_statement_short_single_hash, id);
309
   if (sh)
310
     {
311
        if (sh->func) sh->func();
312
     }
313
   return !!sh;
314
}
315

316
static char *
317
perform_math(char *input)
318
{
319
   char buf[256];
320
   double res;
321

322
   /* FIXME
323
    * Always apply floating-point arithmetic.
324
    * Does this cause problems for integer parameters? (yes it will)
325
    *
326
    * What we should do is, loop over the string and figure out whether
327
    * there are floating point operands, too and then switch to
328
    * floating point math.
329
    */
330
   res = my_atof(input);
331
   snprintf(buf, sizeof (buf), "%lf", res);
332
   return strdup(buf);
333
}
334

335
static int
336
isdelim(char c)
337
{
338
   const char *delims = "{},;:[]";
339
   char *d;
340

341
   d = (char *)delims;
342
   while (*d)
343
     {
344
        if (c == *d) return 1;
345
        d++;
346
     }
347
   return 0;
348
}
349

350
static char *
351
next_token(char *p, char *end, char **new_p, int *delim)
352
{
353
   char *tok_start = NULL, *tok_end = NULL, *tok = NULL, *sa_start = NULL;
354
   int in_tok = 0;
355
   int in_quote = 0;
356
   int in_parens = 0;
357
   int in_comment_ss = 0;
358
   int in_comment_cpp = 0;
359
   int in_comment_sa = 0;
360
   int is_escaped = 0;
361

362
   had_quote = 0;
363

364
   *delim = 0;
365
   if (p >= end) return NULL;
366
   while (p < end)
367
     {
368
        if (*p == '\n')
369
          {
370
             in_comment_ss = 0;
371
             in_comment_cpp = 0;
372
             line++;
373
          }
374
        if ((!in_comment_ss) && (!in_comment_sa))
375
          {
376
             if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '/'))
377
               in_comment_ss = 1;
378
             if ((!in_quote) && (*p == '#'))
379
               in_comment_cpp = 1;
380
             if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '*'))
381
               {
382
                  in_comment_sa = 1;
383
                  sa_start = p;
384
               }
385
          }
386
        if ((in_comment_cpp) && (*p == '#'))
387
          {
388
             char *pp, fl[4096];
389
             char *tmpstr = NULL;
390
             int l, nm;
391

392
             /* handle cpp comments */
393
             /* their line format is
394
              * #line <line no. of next line> <filename from next line on> [??]
395
              */
396

397
             pp = p;
398
             while ((pp < end) && (*pp != '\n'))
399
               {
400
                  pp++;
401
               }
402
             l = pp - p;
403
             tmpstr = alloca(l + 1);
404
             memcpy(tmpstr, p, l);
405
             tmpstr[l] = 0;
406
             if (l >= (int)sizeof(fl))
407
               {
408
                  ERR("Line too long: %i chars: %s", l, tmpstr);
409
                  err_show();
410
                  exit(-1);
411
               }
412
             l = sscanf(tmpstr, "%*s %i \"%[^\"]\"", &nm, fl);
413
             if (l == 2)
414
               {
415
                  strcpy(file_buf, fl);
416
                  line = nm;
417
                  file_in = file_buf;
418
               }
419
          }
420
        else if ((!in_comment_ss) && (!in_comment_sa) && (!in_comment_cpp))
421
          {
422
             if (!in_tok)
423
               {
424
                  if (!in_quote)
425
                    {
426
                       if (!isspace(*p))
427
                         {
428
                            if (*p == '"')
429
                              {
430
                                 in_quote = 1;
431
                                 had_quote = 1;
432
                              }
433
                            else if (*p == '(')
434
                              in_parens++;
435

436
                            in_tok = 1;
437
                            tok_start = p;
438
                            if (isdelim(*p)) *delim = 1;
439
                         }
440
                    }
441
               }
442
             else
443
               {
444
                  if (in_quote)
445
                    {
446
                       if ((*p) == '\\')
447
                         is_escaped = !is_escaped;
448
                       else if (((*p) == '"') && (!is_escaped))
449
                         {
450
                            in_quote = 0;
451
                            had_quote = 1;
452
                         }
453
                       else if (is_escaped)
454
                         is_escaped = 0;
455
                    }
456
                  else if (in_parens != 0 && (!is_escaped))
457
                    {
458
                       if (*p == '(')
459
                         in_parens++;
460
                       else if (*p == ')')
461
                         in_parens--;
462
                       else if (isdelim(*p))
463
                         {
464
                            ERR("check pair of parens %s:%i.", file_in, line - 1);
465
                            err_show();
466
                            exit(-1);
467
                         }
468
                    }
469
                  else
470
                    {
471
                       if (*p == '"')
472
                         {
473
                            in_quote = 1;
474
                            had_quote = 1;
475
                         }
476
                       else if (*p == '(')
477
                         in_parens++;
478
                       else if (*p == ')')
479
                         in_parens--;
480

481
                       /* check for end-of-token */
482
                       if (
483
                         (isspace(*p)) ||
484
                         ((*delim) && (!isdelim(*p))) ||
485
                         (isdelim(*p))
486
                         ) /*the line below this is never  used because it skips to
487
                            * the 'done' label which is after the return call for
488
                            * in_tok being 0. is this intentional?
489
                            */
490
                         {
491
                            in_tok = 0;
492

493
                            tok_end = p - 1;
494
                            if (*p == '\n') line--;
495
                            goto done;
496
                         }
497
                    }
498
               }
499
          }
500
        if (in_comment_sa)
501
          {
502
             if ((*p == '/') && (*(p - 1) == '*') && ((p - sa_start) > 2))
503
               in_comment_sa = 0;
504
          }
505
        p++;
506
     }
507
   if (!in_tok) return NULL;
508
   tok_end = p - 1;
509

510
done:
511
   *new_p = p;
512

513
   tok = mem_alloc(tok_end - tok_start + 2);
514
   if (!tok) return NULL;
515

516
   strncpy(tok, tok_start, tok_end - tok_start + 1);
517
   tok[tok_end - tok_start + 1] = 0;
518

519
   if (had_quote)
520
     {
521
        is_escaped = 0;
522
        p = tok;
523

524
        /* Note: if you change special chars list here make the same changes in
525
         * _edje_generate_source_of_style function
526
         */
527
        while (*p)
528
          {
529
             if ((*p == '\"') && (!is_escaped))
530
               {
531
                  memmove(p, p + 1, strlen(p));
532
               }
533
             else if ((*p == '\\') && (*(p + 1) == 'n'))
534
               {
535
                  memmove(p, p + 1, strlen(p));
536
                  *p = '\n';
537
               }
538
             else if ((*p == '\\') && (*(p + 1) == 't'))
539
               {
540
                  memmove(p, p + 1, strlen(p));
541
                  *p = '\t';
542
               }
543
             else if (*p == '\\')
544
               {
545
                  memmove(p, p + 1, strlen(p));
546
                  if (*p == '\\') p++;
547
                  else is_escaped = 1;
548
               }
549
             else
550
               {
551
                  if (is_escaped) is_escaped = 0;
552
                  p++;
553
               }
554
          }
555
     }
556
   else if (*tok == '(')
557
     {
558
        char *tmp;
559
        tmp = tok;
560
        tok = perform_math(tok);
561
        free(tmp);
562
     }
563

564
   return tok;
565
}
566

567
static void
568
stack_push(char *token)
569
{
570
   New_Nested_Handler *nested;
571
   Eina_Bool do_append = EINA_TRUE;
572

573
   if (eina_list_count(stack) > 1)
574
     {
575
        if (!strcmp(token, eina_list_data_get(eina_list_last(stack))))
576
          {
577
             char *tmp;
578
             int token_length;
579

580
             token_length = strlen(token);
581
             tmp = alloca(eina_strbuf_length_get(stack_buf));
582
             memcpy(tmp,
583
                    eina_strbuf_string_get(stack_buf),
584
                    eina_strbuf_length_get(stack_buf) - token_length - 1);
585
             tmp[eina_strbuf_length_get(stack_buf) - token_length - 1] = '\0';
586

587
             nested = eina_hash_find(_new_nested_hash, tmp);
588
             if (!nested)
589
               nested = eina_hash_find(_new_nested_short_hash, tmp);
590
             if (nested)
591
               {
592
                  if (!strcmp(token, nested->token) &&
593
                      stack && !strcmp(eina_list_data_get(eina_list_last(stack)), nested->token))
594
                    {
595
                       /* Do not append the nested token in buffer */
596
                       do_append = EINA_FALSE;
597
                       if (nested->func_push) nested->func_push();
598
                    }
599
               }
600
          }
601
     }
602
   if (do_append)
603
     {
604
        if (stack) eina_strbuf_append(stack_buf, ".");
605
        eina_strbuf_append(stack_buf, token);
606
     }
607
   stack = eina_list_append(stack, token);
608
}
609

610
static void
611
stack_pop(void)
612
{
613
   char *tmp;
614
   int tmp_length;
615
   Eina_Bool do_remove = EINA_TRUE;
616

617
   if (!stack)
618
     {
619
        ERR("parse error %s:%i. } marker without matching { marker",
620
            file_in, line - 1);
621
        err_show();
622
        exit(-1);
623
     }
624
   tmp = eina_list_data_get(eina_list_last(stack));
625
   tmp_length = strlen(tmp);
626

627
   stack = eina_list_remove_list(stack, eina_list_last(stack));
628
   if (eina_list_count(stack) > 0)
629
     {
630
        const char *prev;
631
        New_Nested_Handler *nested;
632
        char *hierarchy;
633
        char *lookup;
634

635
        hierarchy = alloca(eina_strbuf_length_get(stack_buf) + 1);
636
        memcpy(hierarchy,
637
               eina_strbuf_string_get(stack_buf),
638
               eina_strbuf_length_get(stack_buf) + 1);
639

640
        /* This is nasty, but it's the way to get parts.part when they are collapsed together. still not perfect */
641
        lookup = strrchr(hierarchy + eina_strbuf_length_get(stack_buf) - tmp_length, '.');
642
        while (lookup)
643
          {
644
             hierarchy[lookup - hierarchy] = '\0';
645
             nested = eina_hash_find(_new_nested_hash, hierarchy);
646
             if (!nested)
647
               nested = eina_hash_find(_new_nested_short_hash, hierarchy);
648
             if (nested && nested->func_pop) nested->func_pop();
649
             lookup = strrchr(hierarchy + eina_strbuf_length_get(stack_buf) - tmp_length, '.');
650
          }
651

652
        hierarchy[eina_strbuf_length_get(stack_buf) - 1 - tmp_length] = '\0';
653

654
        nested = eina_hash_find(_new_nested_hash, hierarchy);
655
        if (!nested)
656
          nested = eina_hash_find(_new_nested_short_hash, hierarchy);
657
        if (nested)
658
          {
659
             if (nested->func_pop) nested->func_pop();
660

661
             prev = eina_list_data_get(eina_list_last(stack));
662
             if (!strcmp(tmp, prev))
663
               {
664
                  if (!strcmp(nested->token, tmp))
665
                    do_remove = EINA_FALSE;
666
               }
667
          }
668
        else
669
          edje_cc_handlers_pop_notify(tmp);
670

671
        if (do_remove)
672
          eina_strbuf_remove(stack_buf,
673
                             eina_strbuf_length_get(stack_buf) - tmp_length - 1,
674
                             eina_strbuf_length_get(stack_buf));  /* remove: '.tmp' */
675
     }
676
   else
677
     {
678
        eina_strbuf_remove(stack_buf,
679
                           eina_strbuf_length_get(stack_buf) - tmp_length,
680
                           eina_strbuf_length_get(stack_buf)); /* remove: 'tmp' */
681
     }
682
   free(tmp);
683
}
684

685
void
686
stack_push_quick(const char *str)
687
{
688
   char *s;
689

690
   s = mem_strdup(str);
691
   stack = eina_list_append(stack, s);
692
   eina_strbuf_append_char(stack_buf, '.');
693
   eina_strbuf_append(stack_buf, s);
694
}
695

696
char *
697
stack_pop_quick(Eina_Bool check_last, Eina_Bool do_free)
698
{
699
   char *tmp, *str;
700

701
   str = tmp = eina_list_last_data_get(stack);
702
   if (check_last)
703
     {
704
        char *end;
705

706
        end = strrchr(tmp, '.');
707
        if (end)
708
          tmp = end + 1;
709
     }
710
   eina_strbuf_remove(stack_buf,
711
                      eina_strbuf_length_get(stack_buf) - strlen(tmp) - 1,
712
                      eina_strbuf_length_get(stack_buf));      /* remove: '.tmp' */
713
   stack = eina_list_remove_list(stack, eina_list_last(stack));
714
   if (do_free)
715
     {
716
        free(str);
717
        str = NULL;
718
     }
719
   return str;
720
}
721

722
/* replace the top of stack with given token */
723
void
724
stack_replace_quick(const char *token)
725
{
726
   char *str;
727

728
   str = stack_pop_quick(EINA_FALSE, EINA_FALSE);
729
   if ((str) && strchr(str, '.'))
730
     {
731
        char *end, *tmp = str;
732
        Eina_Strbuf *buf;
733

734
        end = strchr(tmp, '.');
735
        if (end)
736
          tmp = end + 1;
737

738
        buf = eina_strbuf_new();
739
        eina_strbuf_append(buf, str);
740
        eina_strbuf_remove(buf,
741
                           eina_strbuf_length_get(buf) - strlen(tmp),
742
                           eina_strbuf_length_get(buf));
743
        eina_strbuf_append(buf, token);
744

745
        stack_push_quick(eina_strbuf_string_get(buf));
746

747
        eina_strbuf_free(buf);
748
        free(str);
749
     }
750
   else
751
     {
752
        stack_push_quick(token);
753
     }
754
}
755

756
static const char *
757
stack_id(void)
758
{
759
   return eina_strbuf_string_get(stack_buf);
760
}
761

762
static void
763
parse(char *data, off_t size)
764
{
765
   char *p, *end, *token;
766
   int delim = 0;
767
   int do_params = 0;
768
   int do_indexes = 0;  // 0: none, 1: ready, 2: done
769

770
   DBG("Parsing input file");
771

772
   /* Allocate arrays used to impl nested parts */
773
   edje_cc_handlers_hierarchy_alloc();
774
   p = data;
775
   end = data + size;
776
   line = 1;
777
   while ((token = next_token(p, end, &p, &delim)))
778
     {
779
        /* if we are in param mode, the only delimiter
780
         * we'll accept is the semicolon
781
         */
782
        if (do_params && delim && *token != ';')
783
          {
784
             ERR("parse error %s:%i. %c marker before ; marker",
785
                 file_in, line - 1, *token);
786
             err_show();
787
             exit(-1);
788
          }
789
        else if (delim)
790
          {
791
             if ((do_indexes == 2) && (*token != ']'))
792
               {
793
                  ERR("parse error %s:%i. %c marker before ] marker",
794
                      file_in, line - 1, *token);
795
                  err_show();
796
                  exit(-1);
797
               }
798
             else if (*token == ',' || *token == ':')
799
               do_params = 1;
800
             else if (*token == '}')
801
               {
802
                  if (do_params)
803
                    {
804
                       ERR("parse error %s:%i. } marker before ; marker",
805
                           file_in, line - 1);
806
                       err_show();
807
                       exit(-1);
808
                    }
809
                  else
810
                    stack_pop();
811
               }
812
             else if (*token == ';')
813
               {
814
                  if (did_wildcard)
815
                    {
816
                       free(token);
817
                       did_wildcard = 0;
818
                       continue;
819
                    }
820
                  if (do_params)
821
                    {
822
                       void *param;
823

824
                       do_params = 0;
825
                       new_statement();
826
                       /* clear out params */
827
                       while ((param = eina_array_pop(&params)))
828
                         free(param);
829
                       params_quote = 0;
830
                       /* remove top from stack */
831
                       stack_pop();
832
                    }
833
                  else
834
                    {
835
                       if (new_statement_single())
836
                         stack_pop();
837
                    }
838
               }
839
             else if (*token == '{')
840
               {
841
                  if (do_params)
842
                    {
843
                       ERR("parse error %s:%i. { marker before ; marker",
844
                           file_in, line - 1);
845
                       err_show();
846
                       exit(-1);
847
                    }
848
               }
849
             else if (*token == '[')
850
               {
851
                  do_indexes = 1;
852
               }
853
             else if (*token == ']')
854
               {
855
                  if (do_indexes == 2)
856
                    do_indexes = 0;
857
                  else
858
                    {
859
                       if (do_indexes == 0)
860
                         ERR("parse error %s:%i. ] marker before [ marker",
861
                             file_in, line - 1);
862
                       else
863
                         ERR("parse error %s:%i. [?] empty bracket",
864
                             file_in, line - 1);
865

866
                       err_show();
867
                       exit(-1);
868
                    }
869
               }
870
             free(token);
871
          }
872
        else
873
          {
874
             if (do_params)
875
               {
876
                  if (had_quote)
877
                    params_quote |= (1 << eina_array_count(&params));
878
                  eina_array_push(&params, token);
879
               }
880
             else if (do_indexes)
881
               {
882
                  if (had_quote)
883
                    params_quote |= (1 << eina_array_count(&params));
884
                  do_indexes++;
885
                  eina_array_push(&params, token);
886
               }
887
             else
888
               {
889
                  stack_push(token);
890
                  new_object();
891
                  if ((verbatim == 1) && (p < (end - 2)))
892
                    {
893
                       int escaped = 0;
894
                       int inquotes = 0;
895
                       int insquotes = 0;
896
                       int squigglie = 1;
897
                       int l1 = 0, l2 = 0;
898
                       char *verbatim_1;
899
                       char *verbatim_2;
900

901
                       l1 = line;
902
                       while ((p[0] != '{') && (p < end))
903
                         {
904
                            if (*p == '\n') line++;
905
                            p++;
906
                         }
907
                       p++;
908
                       verbatim_1 = p;
909
                       verbatim_2 = NULL;
910
                       for (; p < end; p++)
911
                         {
912
                            if (*p == '\n') line++;
913
                            if (escaped) escaped = 0;
914
                            if (!escaped)
915
                              {
916
                                 if (p[0] == '\\') escaped = 1;
917
                                 else if (p[0] == '\"')
918
                                   {
919
                                      if (!insquotes)
920
                                        {
921
                                           if (inquotes) inquotes = 0;
922
                                           else inquotes = 1;
923
                                        }
924
                                   }
925
                                 else if (p[0] == '\'')
926
                                   {
927
                                      if (!inquotes)
928
                                        {
929
                                           if (insquotes) insquotes = 0;
930
                                           else insquotes = 1;
931
                                        }
932
                                   }
933
                                 else if ((!inquotes) && (!insquotes))
934
                                   {
935
                                      if (p[0] == '{') squigglie++;
936
                                      else if (p[0] == '}')
937
                                        squigglie--;
938
                                      if (squigglie == 0)
939
                                        {
940
                                           verbatim_2 = p - 1;
941
                                           l2 = line;
942
                                           break;
943
                                        }
944
                                   }
945
                              }
946
                         }
947
                       if (verbatim_2 > verbatim_1)
948
                         {
949
                            int l;
950
                            char *v;
951

952
                            l = verbatim_2 - verbatim_1 + 1;
953
                            v = malloc(l + 1);
954
                            strncpy(v, verbatim_1, l);
955
                            v[l] = 0;
956
                            set_verbatim(v, l1, l2);
957
                         }
958
                       else
959
                         {
960
                            ERR("Parse error %s:%i. { marker does not have matching } marker",
961
                                file_in, line - 1);
962
                            err_show();
963
                            exit(-1);
964
                         }
965
                       new_object();
966
                       verbatim = 0;
967
                    }
968
               }
969
          }
970
     }
971

972
   edje_cc_handlers_hierarchy_free();
973
   DBG("Parsing done");
974
}
975

976
static char *clean_file = NULL;
977
static void
978
clean_tmp_file(void)
979
{
980
   if (clean_file)
981
     {
982
        unlink(clean_file);
983
        free(clean_file);
984
     }
985
}
986

987
int
988
is_verbatim(void)
989
{
990
   return verbatim;
991
}
992

993
void
994
track_verbatim(int on)
995
{
996
   verbatim = on;
997
}
998

999
void
1000
set_verbatim(char *s, int l1, int l2)
1001
{
1002
   verbatim_line1 = l1;
1003
   verbatim_line2 = l2;
1004
   verbatim_str = s;
1005
}
1006

1007
char *
1008
get_verbatim(void)
1009
{
1010
   return verbatim_str;
1011
}
1012

1013
int
1014
get_verbatim_line1(void)
1015
{
1016
   return verbatim_line1;
1017
}
1018

1019
int
1020
get_verbatim_line2(void)
1021
{
1022
   return verbatim_line2;
1023
}
1024

1025
void
1026
compile(void)
1027
{
1028
   char buf[4096 + 4096 + 4096], buf2[4096];
1029
   Eina_Tmpstr *tmpn;
1030
   int fd;
1031
   off_t size;
1032
   char *data;
1033
   Eina_List *l;
1034
   Edje_Style *stl;
1035

1036
   fd = eina_file_mkstemp("edje_cc.edc-tmp-XXXXXX", &tmpn);
1037
   if (fd < 0)
1038
     {
1039
        CRI("Unable to open temp file \"%s\" for pre-processor.", tmpn);
1040
        exit(-1);
1041
     }
1042

1043
   if (fd >= 0)
1044
     {
1045
        int ret;
1046
        char *def;
1047

1048
        clean_file = strdup(tmpn);
1049
        eina_tmpstr_del(tmpn);
1050
        close(fd);
1051
        atexit(clean_tmp_file);
1052
        if (!defines)
1053
          def = mem_strdup("");
1054
        else
1055
          {
1056
             int len;
1057
             char *define;
1058

1059
             len = 0;
1060
             EINA_LIST_FOREACH(defines, l, define)
1061
               len += strlen(define) + 1;
1062
             def = mem_alloc(len + 1);
1063
             def[0] = 0;
1064
             EINA_LIST_FOREACH(defines, l, define)
1065
               {
1066
                  strcat(def, define);
1067
                  strcat(def, " ");
1068
               }
1069
          }
1070

1071
        /*
1072
         * Run the input through the C pre-processor.
1073
         */
1074

1075
        buf2[0] = '\0';
1076
#ifdef NEED_RUN_IN_TREE
1077
        if (getenv("EFL_RUN_IN_TREE"))
1078
          {
1079
             snprintf(buf2, sizeof(buf2),
1080
                      "%s/src/bin/edje/epp/epp" EPP_EXT,
1081
                      PACKAGE_BUILD_DIR);
1082
             if (!ecore_file_exists(buf2))
1083
               buf2[0] = '\0';
1084
          }
1085
#endif
1086

1087
        if (buf2[0] == '\0')
1088
          snprintf(buf2, sizeof(buf2),
1089
                   "%s/edje/utils/" MODULE_ARCH "/epp" EPP_EXT,
1090
                   eina_prefix_lib_get(pfx));
1091
        if (ecore_file_exists(buf2))
1092
          {
1093
             char *inc;
1094

1095
             inc = ecore_file_dir_get(file_in);
1096
             if (depfile)
1097
               snprintf(buf, sizeof(buf), "\"%s\" "SKIP_NAMESPACE_VALIDATION_SUPPORTED" -MMD \"%s\" -MT \"%s\" \"%s\""
1098
                                          " -I\"%s\" %s -o \"%s\""
1099
                                          " -DEFL_VERSION_MAJOR=%d -DEFL_VERSION_MINOR=%d"
1100
                        EDJE_CC_EFL_VERSION_SUPPORTED,
1101
                        buf2, depfile, file_out, file_in,
1102
                        inc ? inc : "./", def, clean_file,
1103
                        EINA_VERSION_MAJOR, EINA_VERSION_MINOR);
1104
             else if (annotate)
1105
               snprintf(buf, sizeof(buf), "\"%s\" "SKIP_NAMESPACE_VALIDATION_SUPPORTED" -annotate -a \"%s\" \"%s\""
1106
                                          " -I\"%s\" %s -o \"%s\""
1107
                                          " -DEFL_VERSION_MAJOR=%d -DEFL_VERSION_MINOR=%d"
1108
                        EDJE_CC_EFL_VERSION_SUPPORTED,
1109
                        buf2, watchfile ? watchfile : "/dev/null", file_in,
1110
                        inc ? inc : "./", def, clean_file,
1111
                        EINA_VERSION_MAJOR, EINA_VERSION_MINOR);
1112
             else
1113
               snprintf(buf, sizeof(buf), "\"%s\" "SKIP_NAMESPACE_VALIDATION_SUPPORTED" -a \"%s\" \"%s\" -I\"%s\" %s"
1114
                                          " -o \"%s\""
1115
                                          " -DEFL_VERSION_MAJOR=%d -DEFL_VERSION_MINOR=%d"
1116
                        EDJE_CC_EFL_VERSION_SUPPORTED,
1117
                        buf2, watchfile ? watchfile : "/dev/null", file_in,
1118
                        inc ? inc : "./", def, clean_file,
1119
                        EINA_VERSION_MAJOR, EINA_VERSION_MINOR);
1120
#ifdef _WIN32
1121
             /* On Windows, if command begins with double quotation marks,
1122
              * then the first and the last double quotation marks may be
1123
              * either deleted or not. (See "help cmd" on Windows.)
1124
              *
1125
              * Therefore, to preserve the string between the first and the last
1126
              * double quotation marks, "cmd /S /C" and additional outer double
1127
              * quotation marks are added.
1128
              */
1129
             char win_buf[4096];
1130
             snprintf(win_buf, sizeof(win_buf), "cmd /S /C \"%s\"", buf);
1131
             ret = system(win_buf);
1132
#else
1133
             ret = system(buf);
1134
#endif
1135
             if (inc)
1136
               free(inc);
1137
          }
1138
        else
1139
          {
1140
             ERR("Cannot run epp: %s", buf2);
1141
             exit(-1);
1142
          }
1143
        if (ret == EXIT_SUCCESS)
1144
          file_in = (char *)clean_file;
1145
        else
1146
          {
1147
             ERR("Exit code of epp not clean: %i", ret);
1148
             exit(-1);
1149
          }
1150
        free(def);
1151
     }
1152
   fd = open(file_in, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
1153
   if (fd < 0)
1154
     {
1155
        ERR("Cannot open file \"%s\" for input. %s",
1156
            file_in, strerror(errno));
1157
        exit(-1);
1158
     }
1159
   DBG("Opening \"%s\" for input", file_in);
1160

1161
   /* lseek can return -1 on error. trap that return and exit so that
1162
    * we do not pass malloc a -1
1163
    *
1164
    * NB: Fixes Coverity CID 1040029 */
1165
   size = lseek(fd, 0, SEEK_END);
1166
   if (size < 0)
1167
     {
1168
        ERR("Cannot read file \"%s\". %s", file_in, strerror(errno));
1169
        exit(-1);
1170
     }
1171

1172
   lseek(fd, 0, SEEK_SET);
1173
   data = malloc(size);
1174
   if (data && (read(fd, data, size) == size))
1175
     {
1176
        stack_buf = eina_strbuf_new();
1177
        eina_array_step_set(&params, sizeof (Eina_Array), 8);
1178
        parse(data, size);
1179
        eina_array_flush(&params);
1180
        eina_strbuf_free(stack_buf);
1181
        stack_buf = NULL;
1182
        color_tree_root_free();
1183
     }
1184
   else
1185
     {
1186
        ERR("Cannot read file \"%s\". %s", file_in, strerror(errno));
1187
        exit(-1);
1188
     }
1189
   free(data);
1190
   close(fd);
1191

1192
   EINA_LIST_FOREACH(edje_file->styles, l, stl)
1193
     {
1194
        if (!stl->name)
1195
          {
1196
             ERR("style must have a name.");
1197
             exit(-1);
1198
          }
1199
     }
1200
}
1201

1202
int
1203
is_param(int n)
1204
{
1205
   char *str;
1206

1207
   str = _parse_param_get(n);
1208
   if (str) return 1;
1209
   return 0;
1210
}
1211

1212
int
1213
is_num(int n)
1214
{
1215
   char *str;
1216
   char *end;
1217
   long int ret;
1218

1219
   str = _parse_param_get(n);
1220
   if (!str)
1221
     {
1222
        ERR("%s:%i no parameter supplied as argument %i",
1223
            file_in, line - 1, n + 1);
1224
        err_show();
1225
        exit(-1);
1226
     }
1227
   if (str[0] == 0) return 0;
1228
   end = str;
1229
   ret = strtol(str, &end, 0);
1230
   if ((ret == LONG_MIN) || (ret == LONG_MAX))
1231
     {
1232
        n = 0; // do nothing. shut gcc warnings up
1233
     }
1234
   if ((end != str) && (end[0] == 0)) return 1;
1235
   return 0;
1236
}
1237

1238
char *
1239
parse_str(int n)
1240
{
1241
   char *str;
1242
   char *s;
1243

1244
   str = _parse_param_get(n);
1245
   if (!str)
1246
     {
1247
        ERR("%s:%i no parameter supplied as argument %i",
1248
            file_in, line - 1, n + 1);
1249
        err_show();
1250
        exit(-1);
1251
     }
1252
   s = mem_strdup(str);
1253
   return s;
1254
}
1255

1256
static int
1257
_parse_enum(char *str, va_list va)
1258
{
1259
   va_list va2;
1260
   va_copy(va2, va); /* iterator for the error message */
1261

1262
   for (;; )
1263
     {
1264
        char *s;
1265
        int v;
1266

1267
        s = va_arg(va, char *);
1268

1269
        /* End of the list, nothing matched. */
1270
        if (!s)
1271
          {
1272
             ERR("%s:%i token %s not one of:", file_in, line - 1, str);
1273
             s = va_arg(va2, char *);
1274
             while (s)
1275
               {
1276
                  va_arg(va2, int);
1277
                  fprintf(stderr, " %s", s);
1278
                  s = va_arg(va2, char *);
1279
                  if (!s) break;
1280
               }
1281
             fprintf(stderr, "\n");
1282
             va_end(va2);
1283
             va_end(va);
1284
             err_show();
1285
             exit(-1);
1286
          }
1287

1288
        v = va_arg(va, int);
1289
        if (!strcmp(s, str) || !strcmp(s, "*"))
1290
          {
1291
             va_end(va2);
1292
             va_end(va);
1293
             return v;
1294
          }
1295
     }
1296
   va_end(va2);
1297
   va_end(va);
1298
   return 0;
1299
}
1300

1301
int
1302
parse_enum(int n, ...)
1303
{
1304
   char *str;
1305
   int result;
1306
   va_list va;
1307

1308
   if (n >= 0)
1309
     {
1310
        str = _parse_param_get(n);
1311
        if (!str)
1312
          {
1313
             ERR("%s:%i no parameter supplied as argument %i",
1314
                 file_in, line - 1, n + 1);
1315
             err_show();
1316
             exit(-1);
1317
          }
1318
     }
1319
   else
1320
     {
1321
        char *end;
1322

1323
        str = eina_list_last_data_get(stack);
1324
        end = strrchr(str, '.');
1325
        if (end)
1326
          str = end + 1;
1327
     }
1328

1329
   va_start(va, n);
1330
   result = _parse_enum(str, va);
1331
   va_end(va);
1332

1333
   return result;
1334
}
1335

1336
int
1337
parse_flags(int n, ...)
1338
{
1339
   int result = 0;
1340
   va_list va;
1341

1342
   va_start(va, n);
1343
   while (n < (int)eina_array_count(&params))
1344
     {
1345
        result |= _parse_enum(eina_array_data_get(&params, n), va);
1346
        n++;
1347
     }
1348
   va_end(va);
1349

1350
   return result;
1351
}
1352

1353
int
1354
parse_int(int n)
1355
{
1356
   char *str;
1357
   int i;
1358

1359
   str = _parse_param_get(n);
1360
   if (!str)
1361
     {
1362
        ERR("%s:%i no parameter supplied as argument %i",
1363
            file_in, line - 1, n + 1);
1364
        err_show();
1365
        exit(-1);
1366
     }
1367
   i = my_atoi(str);
1368
   return i;
1369
}
1370

1371
int
1372
parse_int_range(int n, int f, int t)
1373
{
1374
   char *str;
1375
   int i;
1376

1377
   str = _parse_param_get(n);
1378
   if (!str)
1379
     {
1380
        ERR("%s:%i no parameter supplied as argument %i",
1381
            file_in, line - 1, n + 1);
1382
        err_show();
1383
        exit(-1);
1384
     }
1385
   i = my_atoi(str);
1386
   if ((i < f) || (i > t))
1387
     {
1388
        ERR("%s:%i integer %i out of range of %i to %i inclusive",
1389
            file_in, line - 1, i, f, t);
1390
        err_show();
1391
        exit(-1);
1392
     }
1393
   return i;
1394
}
1395

1396
int
1397
parse_bool(int n)
1398
{
1399
   char *str, buf[4096];
1400
   int i;
1401

1402
   str = _parse_param_get(n);
1403
   if (!str)
1404
     {
1405
        ERR("%s:%i no parameter supplied as argument %i",
1406
            file_in, line - 1, n + 1);
1407
        err_show();
1408
        exit(-1);
1409
     }
1410

1411
   if (!strstrip(str, buf, sizeof (buf)))
1412
     {
1413
        ERR("%s:%i expression is too long",
1414
            file_in, line - 1);
1415
        return 0;
1416
     }
1417

1418
   if (!strcasecmp(buf, "false") || !strcasecmp(buf, "off"))
1419
     return 0;
1420
   if (!strcasecmp(buf, "true") || !strcasecmp(buf, "on"))
1421
     return 1;
1422

1423
   i = my_atoi(str);
1424
   if ((i < 0) || (i > 1))
1425
     {
1426
        ERR("%s:%i integer %i out of range of 0 to 1 inclusive",
1427
            file_in, line - 1, i);
1428
        err_show();
1429
        exit(-1);
1430
     }
1431
   return i;
1432
}
1433

1434
double
1435
parse_float(int n)
1436
{
1437
   char *str;
1438
   double i;
1439

1440
   str = _parse_param_get(n);
1441
   if (!str)
1442
     {
1443
        ERR("%s:%i no parameter supplied as argument %i",
1444
            file_in, line - 1, n + 1);
1445
        err_show();
1446
        exit(-1);
1447
     }
1448
   i = my_atof(str);
1449
   return i;
1450
}
1451

1452
double
1453
parse_float_range(int n, double f, double t)
1454
{
1455
   char *str;
1456
   double i;
1457

1458
   str = _parse_param_get(n);
1459
   if (!str)
1460
     {
1461
        ERR("%s:%i no parameter supplied as argument %i",
1462
            file_in, line - 1, n + 1);
1463
        err_show();
1464
        exit(-1);
1465
     }
1466
   i = my_atof(str);
1467
   if ((i < f) || (i > t))
1468
     {
1469
        ERR("%s:%i float %3.3f out of range of %3.3f to %3.3f inclusive",
1470
            file_in, line - 1, i, f, t);
1471
        err_show();
1472
        exit(-1);
1473
     }
1474
   return i;
1475
}
1476

1477
int
1478
get_arg_count(void)
1479
{
1480
   return eina_array_count(&params);
1481
}
1482

1483
void
1484
check_arg_count(int required_args)
1485
{
1486
   int num_args = eina_array_count(&params);
1487

1488
   if (num_args != required_args)
1489
     {
1490
        ERR("%s:%i got %i arguments, but expected %i",
1491
            file_in, line - 1, num_args, required_args);
1492
        err_show();
1493
        exit(-1);
1494
     }
1495
}
1496

1497
void
1498
check_min_arg_count(int min_required_args)
1499
{
1500
   int num_args = eina_array_count(&params);
1501

1502
   if (num_args < min_required_args)
1503
     {
1504
        ERR("%s:%i got %i arguments, but expected at least %i",
1505
            file_in, line - 1, num_args, min_required_args);
1506
        err_show();
1507
        exit(-1);
1508
     }
1509
}
1510

1511
int
1512
check_range_arg_count(int min_required_args, int max_required_args)
1513
{
1514
   int num_args = eina_array_count(&params);
1515

1516
   if (num_args < min_required_args)
1517
     {
1518
        ERR("%s:%i got %i arguments, but expected at least %i",
1519
            file_in, line - 1, num_args, min_required_args);
1520
        err_show();
1521
        exit(-1);
1522
     }
1523
   else if (num_args > max_required_args)
1524
     {
1525
        ERR("%s:%i got %i arguments, but expected at most %i",
1526
            file_in, line - 1, num_args, max_required_args);
1527
        err_show();
1528
        exit(-1);
1529
     }
1530

1531
   return num_args;
1532
}
1533

1534
/* simple expression parsing stuff */
1535

1536
/*
1537
 * alpha ::= beta + beta || beta
1538
 * beta  ::= gamma + gamma || gamma
1539
 * gamma ::= num || delta
1540
 * delta ::= '(' alpha ')'
1541
 *
1542
 */
1543

1544
/* int set of function */
1545

1546
static int
1547
my_atoi(const char *s)
1548
{
1549
   int res = 0;
1550
   char buf[4096];
1551

1552
   if (!s) return 0;
1553
   if (!strstrip(s, buf, sizeof(buf)))
1554
     {
1555
        ERR("%s:%i expression is too long",
1556
            file_in, line - 1);
1557
        return 0;
1558
     }
1559
   _alphai(buf, &res);
1560
   return res;
1561
}
1562

1563
static char *
1564
_deltai(char *s, int *val)
1565
{
1566
   if (!val) return NULL;
1567
   if ('(' != s[0])
1568
     {
1569
        ERR("%s:%i unexpected character at %s",
1570
            file_in, line - 1, s);
1571
        return s;
1572
     }
1573
   else
1574
     {
1575
        s++;
1576
        s = _alphai(s, val);
1577
        s++;
1578
        return s;
1579
     }
1580
   return s;
1581
}
1582

1583
static char *
1584
_funci(char *s, int *val)
1585
{
1586
   if (!strncmp(s, "floor(", 6))
1587
     {
1588
        s += 5;
1589
        s = _deltai(s, val);
1590
     }
1591
   else if (!strncmp(s, "ceil(", 5))
1592
     {
1593
        s += 4;
1594
        s = _deltai(s, val);
1595
     }
1596
   else
1597
     {
1598
        ERR("%s:%i unexpected character at %s",
1599
            file_in, line - 1, s);
1600
     }
1601
   return s;
1602
}
1603

1604
static char *
1605
_gammai(char *s, int *val)
1606
{
1607
   if (!val) return NULL;
1608
   if (_is_numi(s[0]))
1609
     {
1610
        s = _get_numi(s, val);
1611
        return s;
1612
     }
1613
   else if ('(' == s[0])
1614
     {
1615
        s = _deltai(s, val);
1616
        return s;
1617
     }
1618
   else
1619
     {
1620
        s = _funci(s, val);
1621
        //        ERR("%s:%i unexpected character at %s",
1622
        //                progname, file_in, line - 1, s);
1623
     }
1624
   return s;
1625
}
1626

1627
static char *
1628
_betai(char *s, int *val)
1629
{
1630
   int a1, a2;
1631
   char op;
1632

1633
   if (!val) return NULL;
1634
   s = _gammai(s, &a1);
1635
   while (_is_op1i(s[0]))
1636
     {
1637
        op = s[0];
1638
        s++;
1639
        s = _gammai(s, &a2);
1640
        a1 = _calci(op, a1, a2);
1641
     }
1642
   (*val) = a1;
1643
   return s;
1644
}
1645

1646
static char *
1647
_alphai(char *s, int *val)
1648
{
1649
   int a1 = 0, a2 = 0;
1650
   char op;
1651

1652
   if (!val) return NULL;
1653
   s = _betai(s, &a1);
1654
   while (_is_op2i(s[0]))
1655
     {
1656
        op = s[0];
1657
        s++;
1658
        s = _betai(s, &a2);
1659
        a1 = _calci(op, a1, a2);
1660
     }
1661
   (*val) = a1;
1662
   return s;
1663
}
1664

1665
char *
1666
_get_numi(char *s, int *val)
1667
{
1668
   char buf[4096];
1669
   int pos = 0;
1670

1671
   if (!val) return s;
1672
   while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
1673
          ((0 == pos) && ('-' == s[pos])))
1674
     {
1675
        buf[pos] = s[pos];
1676
        pos++;
1677
     }
1678
   buf[pos] = '\0';
1679
   (*val) = atoi(buf);
1680
   return s + pos;
1681
}
1682

1683
int
1684
_is_numi(char c)
1685
{
1686
   if (((c >= '0') && (c <= '9')) || ('-' == c) || ('+' == c))
1687
     return 1;
1688
   else
1689
     return 0;
1690
}
1691

1692
int
1693
_is_op1i(char c)
1694
{
1695
   switch (c)
1696
     {
1697
      case '*':;
1698

1699
      case '%':;
1700

1701
      case '/': return 1;
1702

1703
      default: break;
1704
     }
1705
   return 0;
1706
}
1707

1708
int
1709
_is_op2i(char c)
1710
{
1711
   switch (c)
1712
     {
1713
      case '+':;
1714

1715
      case '-': return 1;
1716

1717
      default: break;
1718
     }
1719
   return 0;
1720
}
1721

1722
int
1723
_calci(char op, int a, int b)
1724
{
1725
   switch (op)
1726
     {
1727
      case '+':
1728
        a += b;
1729
        return a;
1730

1731
      case '-':
1732
        a -= b;
1733
        return a;
1734

1735
      case '/':
1736
        if (0 != b) a /= b;
1737
        else
1738
          ERR("%s:%i divide by zero", file_in, line - 1);
1739
        return a;
1740

1741
      case '*':
1742
        a *= b;
1743
        return a;
1744

1745
      case '%':
1746
        if (0 != b) a = a % b;
1747
        else
1748
          ERR("%s:%i modula by zero", file_in, line - 1);
1749
        return a;
1750

1751
      default:
1752
        ERR("%s:%i unexpected character '%c'", file_in, line - 1, op);
1753
     }
1754
   return a;
1755
}
1756

1757
/* float set of functoins */
1758

1759
double
1760
my_atof(const char *s)
1761
{
1762
   double res = 0;
1763
   char buf[4096];
1764

1765
   if (!s) return 0;
1766

1767
   if (!strstrip(s, buf, sizeof (buf)))
1768
     {
1769
        ERR("%s:%i expression is too long", file_in, line - 1);
1770
        return 0;
1771
     }
1772
   _alphaf(buf, &res);
1773
   return res;
1774
}
1775

1776
static char *
1777
_deltaf(char *s, double *val)
1778
{
1779
   if (!val) return NULL;
1780
   if ('(' != s[0])
1781
     {
1782
        ERR("%s:%i unexpected character at %s", file_in, line - 1, s);
1783
        return s;
1784
     }
1785
   else
1786
     {
1787
        s++;
1788
        s = _alphaf(s, val);
1789
        s++;
1790
     }
1791
   return s;
1792
}
1793

1794
static char *
1795
_funcf(char *s, double *val)
1796
{
1797
   if (!strncmp(s, "floor(", 6))
1798
     {
1799
        s += 5;
1800
        s = _deltaf(s, val);
1801
        *val = floor(*val);
1802
     }
1803
   else if (!strncmp(s, "ceil(", 5))
1804
     {
1805
        s += 4;
1806
        s = _deltaf(s, val);
1807
        *val = ceil(*val);
1808
     }
1809
   else
1810
     {
1811
        ERR("%s:%i unexpected character at %s", file_in, line - 1, s);
1812
     }
1813
   return s;
1814
}
1815

1816
static char *
1817
_gammaf(char *s, double *val)
1818
{
1819
   if (!val) return NULL;
1820

1821
   if (_is_numf(s[0]))
1822
     {
1823
        s = _get_numf(s, val);
1824
        return s;
1825
     }
1826
   else if ('(' == s[0])
1827
     {
1828
        s = _deltaf(s, val);
1829
        return s;
1830
     }
1831
   else
1832
     {
1833
        s = _funcf(s, val);
1834
        //        ERR("%s:%i unexpected character at %s",
1835
        //                progname, file_in, line - 1, s);
1836
     }
1837
   return s;
1838
}
1839

1840
static char *
1841
_betaf(char *s, double *val)
1842
{
1843
   double a1 = 0, a2 = 0;
1844
   char op;
1845

1846
   if (!val) return NULL;
1847
   s = _gammaf(s, &a1);
1848
   while (_is_op1f(s[0]))
1849
     {
1850
        op = s[0];
1851
        s++;
1852
        s = _gammaf(s, &a2);
1853
        a1 = _calcf(op, a1, a2);
1854
     }
1855
   (*val) = a1;
1856
   return s;
1857
}
1858

1859
static char *
1860
_alphaf(char *s, double *val)
1861
{
1862
   double a1 = 0, a2 = 0;
1863
   char op;
1864

1865
   if (!val) return NULL;
1866
   s = _betaf(s, &a1);
1867
   while (_is_op2f(s[0]))
1868
     {
1869
        op = s[0];
1870
        s++;
1871
        s = _betaf(s, &a2);
1872
        a1 = _calcf(op, a1, a2);
1873
     }
1874
   (*val) = a1;
1875
   return s;
1876
}
1877

1878
static char *
1879
_get_numf(char *s, double *val)
1880
{
1881
   char buf[4096];
1882
   int pos = 0;
1883

1884
   if (!val) return s;
1885

1886
   while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
1887
          ('.' == s[pos]) ||
1888
          ((0 == pos) && ('-' == s[pos])))
1889
     {
1890
        buf[pos] = s[pos];
1891
        pos++;
1892
     }
1893
   buf[pos] = '\0';
1894
   (*val) = atof(buf);
1895
   return s + pos;
1896
}
1897

1898
static int
1899
_is_numf(char c)
1900
{
1901
   if (((c >= '0') && (c <= '9'))
1902
       || ('-' == c)
1903
       || ('.' == c)
1904
       || ('+' == c))
1905
     return 1;
1906
   return 0;
1907
}
1908

1909
static int
1910
_is_op1f(char c)
1911
{
1912
   switch (c)
1913
     {
1914
      case '*':;
1915

1916
      case '%':;
1917

1918
      case '/': return 1;
1919

1920
      default: break;
1921
     }
1922
   return 0;
1923
}
1924

1925
static int
1926
_is_op2f(char c)
1927
{
1928
   switch (c)
1929
     {
1930
      case '+':;
1931

1932
      case '-': return 1;
1933

1934
      default: break;
1935
     }
1936
   return 0;
1937
}
1938

1939
static double
1940
_calcf(char op, double a, double b)
1941
{
1942
   switch (op)
1943
     {
1944
      case '+':
1945
        a += b;
1946
        return a;
1947

1948
      case '-':
1949
        a -= b;
1950
        return a;
1951

1952
      case '/':
1953
        if (EINA_DBL_NONZERO(b)) a /= b;
1954
        else
1955
          ERR("%s:%i divide by zero", file_in, line - 1);
1956
        return a;
1957

1958
      case '*':
1959
        a *= b;
1960
        return a;
1961

1962
      case '%':
1963
        if (EINA_DBL_NONZERO(b)) a = (double)((int)a % (int)b);
1964
        else
1965
          ERR("%s:%i modula by zero", file_in, line - 1);
1966
        return a;
1967

1968
      default:
1969
        ERR("%s:%i unexpected character '%c'", file_in, line - 1, op);
1970
     }
1971
   return a;
1972
}
1973

1974
static int
1975
strstrip(const char *in, char *out, size_t size)
1976
{
1977
   if ((size - 1) < strlen(in))
1978
     {
1979
        ERR("%s:%i expression is too long", file_in, line - 1);
1980
        return 0;
1981
     }
1982
   /* remove spaces and tabs */
1983
   while (*in)
1984
     {
1985
        if ((0x20 != *in) && (0x09 != *in))
1986
          {
1987
             *out = *in;
1988
             out++;
1989
          }
1990
        in++;
1991
     }
1992
   *out = '\0';
1993
   return 1;
1994
}
1995

1996
int
1997
get_param_index(char *str)
1998
{
1999
   int index;
2000
   char *p;
2001

2002
   for (index = 0; index < get_arg_count(); index++)
2003
     {
2004
        p = _parse_param_get(index);
2005
        if (!p) continue;
2006

2007
        if (!strcmp(str, p))
2008
          return index;
2009
     }
2010

2011
   return -1;
2012
}
2013

2014
int
2015
param_had_quote(int n)
2016
{
2017
   return params_quote & (1 << n);
2018
}
2019

2020

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.