goa: Add missing linker flag (for real).
[platform/upstream/evolution-data-server.git] / libedataserver / e-sexp.c
1 /*
2  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
3  *
4  * A simple, extensible s-exp evaluation engine.
5  *
6  * Author :
7  *  Michael Zucchi <notzed@ximian.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU Lesser General Public
11  * License as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21  * USA
22  */
23
24 /*
25  *   The following built-in s-exp's are supported:
26  *
27  *   list = (and list*)
28  *      perform an intersection of a number of lists, and return that.
29  *
30  *   bool = (and bool*)
31  *      perform a boolean AND of boolean values.
32  *
33  *   list = (or list*)
34  *      perform a union of a number of lists, returning the new list.
35  *
36  *   bool = (or bool*)
37  *      perform a boolean OR of boolean values.
38  *
39  *   gint = (+ int*)
40  *      Add integers.
41  *
42  *   string = (+ string*)
43  *      Concat strings.
44  *
45  *   time_t = (+ time_t*)
46  *      Add time_t values.
47  *
48  *   gint = (- gint int*)
49  *      Subtract integers from the first.
50  *
51  *   time_t = (- time_t*)
52  *      Subtract time_t values from the first.
53  *
54  *   gint = (cast-int string|int|bool)
55  *         Cast to an integer value.
56  *
57  *   string = (cast-string string|int|bool)
58  *         Cast to an string value.
59  *
60  *   Comparison operators:
61  *
62  *   bool = (< gint gint)
63  *   bool = (> gint gint)
64  *   bool = (= gint gint)
65  *
66  *   bool = (< string string)
67  *   bool = (> string string)
68  *   bool = (= string string)
69  *
70  *   bool = (< time_t time_t)
71  *   bool = (> time_t time_t)
72  *   bool = (= time_t time_t)
73  *      Perform a comparision of 2 integers, 2 string values, or 2 time values.
74  *
75  *   Function flow:
76  *
77  *   type = (if bool function)
78  *   type = (if bool function function)
79  *      Choose a flow path based on a boolean value
80  *
81  *   type = (begin  func func func)
82  *         Execute a sequence.  The last function return is the return type.
83  */
84
85 #ifdef HAVE_CONFIG_H
86 #include <config.h>
87 #endif
88
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <time.h>
92 #include <string.h>
93
94 #include "e-sexp.h"
95 #include "e-memory.h"
96
97 #define p(x)                    /* parse debug */
98 #define r(x)                    /* run debug */
99 #define d(x)                    /* general debug */
100
101 #ifdef E_SEXP_IS_G_OBJECT
102 G_DEFINE_TYPE (ESExp, e_sexp, G_TYPE_OBJECT)
103 #endif
104
105 static struct _ESExpTerm *
106                         parse_list              (ESExp *f,
107                                                  gint gotbrace);
108 static struct _ESExpTerm *
109                         parse_value             (ESExp *f);
110
111 #ifdef TESTER
112 static void             parse_dump_term         (struct _ESExpTerm *t,
113                                                  gint depth);
114 #endif
115
116 typedef gboolean        (ESGeneratorFunc)       (gint argc,
117                                                  struct _ESExpResult **argv,
118                                                  struct _ESExpResult *r);
119 typedef gboolean        (ESOperatorFunc)        (gint argc,
120                                                  struct _ESExpResult **argv,
121                                                  struct _ESExpResult *r);
122
123 /* FIXME: constant _TIME_MAX used in different files, move it somewhere */
124 #define _TIME_MAX       ((time_t) INT_MAX)      /* Max valid time_t     */
125
126 static const GScannerConfig scanner_config =
127 {
128         ( (gchar *) " \t\r\n")          /* cset_skip_characters */,
129         ( (gchar *) G_CSET_a_2_z
130           "_+-<=>?"
131           G_CSET_A_2_Z)                 /* cset_identifier_first */,
132         ( (gchar *) G_CSET_a_2_z
133           "_0123456789-<>?"
134           G_CSET_A_2_Z
135           G_CSET_LATINS
136           G_CSET_LATINC )               /* cset_identifier_nth */,
137         ( (gchar *) ";\n" )             /* cpair_comment_single */,
138
139         FALSE                           /* case_sensitive */,
140
141         TRUE                            /* skip_comment_multi */,
142         TRUE                            /* skip_comment_single */,
143         TRUE                            /* scan_comment_multi */,
144         TRUE                            /* scan_identifier */,
145         TRUE                            /* scan_identifier_1char */,
146         FALSE                           /* scan_identifier_NULL */,
147         TRUE                            /* scan_symbols */,
148         FALSE                           /* scan_binary */,
149         TRUE                            /* scan_octal */,
150         TRUE                            /* scan_float */,
151         TRUE                            /* scan_hex */,
152         FALSE                           /* scan_hex_dollar */,
153         TRUE                            /* scan_string_sq */,
154         TRUE                            /* scan_string_dq */,
155         TRUE                            /* numbers_2_int */,
156         FALSE                           /* int_2_float */,
157         FALSE                           /* identifier_2_string */,
158         TRUE                            /* char_2_token */,
159         FALSE                           /* symbol_2_token */,
160         FALSE                           /* scope_0_fallback */,
161 };
162
163 /* jumps back to the caller of f->failenv, only to be called from inside a callback */
164 void
165 e_sexp_fatal_error (struct _ESExp *f,
166                     const gchar *why,
167                     ...)
168 {
169         va_list args;
170
171         if (f->error)
172                 g_free (f->error);
173
174         va_start (args, why);
175         f->error = g_strdup_vprintf (why, args);
176         va_end (args);
177
178         longjmp (f->failenv, 1);
179 }
180
181 const gchar *
182 e_sexp_error (struct _ESExp *f)
183 {
184         return f->error;
185 }
186
187 struct _ESExpResult *
188 e_sexp_result_new (struct _ESExp *f,
189                    gint type)
190 {
191         struct _ESExpResult *r = e_memchunk_alloc0 (f->result_chunks);
192         r->type = type;
193         r->occuring_start = 0;
194         r->occuring_end = _TIME_MAX;
195         r->time_generator = FALSE;
196         return r;
197 }
198
199 void
200 e_sexp_result_free (struct _ESExp *f,
201                     struct _ESExpResult *t)
202 {
203         if (t == NULL)
204                 return;
205
206         switch (t->type) {
207         case ESEXP_RES_ARRAY_PTR:
208                 g_ptr_array_free (t->value.ptrarray, TRUE);
209                 break;
210         case ESEXP_RES_BOOL:
211         case ESEXP_RES_INT:
212         case ESEXP_RES_TIME:
213                 break;
214         case ESEXP_RES_STRING:
215                 g_free (t->value.string);
216                 break;
217         case ESEXP_RES_UNDEFINED:
218                 break;
219         default:
220                 g_assert_not_reached ();
221         }
222         e_memchunk_free (f->result_chunks, t);
223 }
224
225 /* used in normal functions if they have to abort, and free their arguments */
226 void
227 e_sexp_resultv_free (struct _ESExp *f,
228                      gint argc,
229                      struct _ESExpResult **argv)
230 {
231         gint i;
232
233         for (i = 0; i < argc; i++) {
234                 e_sexp_result_free (f, argv[i]);
235         }
236 }
237
238 /* implementations for the builtin functions */
239
240 /* we can only itereate a hashtable from a called function */
241 struct IterData {
242         gint count;
243         GPtrArray *uids;
244 };
245
246 /* ok, store any values that are in all sets */
247 static void
248 htand (gchar *key,
249        gint value,
250        struct IterData *iter_data)
251 {
252         if (value == iter_data->count) {
253                 g_ptr_array_add (iter_data->uids, key);
254         }
255 }
256
257 /* or, store all unique values */
258 static void
259 htor (gchar *key,
260       gint value,
261       struct IterData *iter_data)
262 {
263         g_ptr_array_add (iter_data->uids, key);
264 }
265
266 static ESExpResult *
267 term_eval_and (struct _ESExp *f,
268                gint argc,
269                struct _ESExpTerm **argv,
270                gpointer data)
271 {
272         struct _ESExpResult *r, *r1;
273         GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
274         struct IterData lambdafoo;
275         gint type=-1;
276         gint bool = TRUE;
277         gint i;
278         const gchar *oper;
279
280         r (printf ("( and\n"));
281
282         r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
283
284         oper = "AND";
285         f->operators = g_slist_prepend (f->operators, (gpointer) oper);
286
287         for (i = 0; bool && i < argc; i++) {
288                 r1 = e_sexp_term_eval (f, argv[i]);
289                 if (type == -1)
290                         type = r1->type;
291                 if (type != r1->type) {
292                         e_sexp_result_free (f, r);
293                         e_sexp_result_free (f, r1);
294                         g_hash_table_destroy (ht);
295                         e_sexp_fatal_error (f, "Invalid types in AND");
296                 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
297                         gchar **a1;
298                         gint l1, j;
299
300                         a1 = (gchar **) r1->value.ptrarray->pdata;
301                         l1 = r1->value.ptrarray->len;
302                         for (j = 0; j < l1; j++) {
303                                 gpointer ptr;
304                                 gint n;
305                                 ptr = g_hash_table_lookup (ht, a1[j]);
306                                 n = GPOINTER_TO_INT (ptr);
307                                 g_hash_table_insert (ht, a1[j], GINT_TO_POINTER (n + 1));
308                         }
309                 } else if (r1->type == ESEXP_RES_BOOL) {
310                         bool = bool && r1->value.boolean;
311                 }
312                 e_sexp_result_free (f, r1);
313         }
314
315         if (type == ESEXP_RES_ARRAY_PTR) {
316                 lambdafoo.count = argc;
317                 lambdafoo.uids = g_ptr_array_new ();
318                 g_hash_table_foreach (ht, (GHFunc) htand, &lambdafoo);
319                 r->type = ESEXP_RES_ARRAY_PTR;
320                 r->value.ptrarray = lambdafoo.uids;
321         } else if (type == ESEXP_RES_BOOL) {
322                 r->type = ESEXP_RES_BOOL;
323                 r->value.boolean = bool;
324         }
325
326         g_hash_table_destroy (ht);
327         f->operators = g_slist_remove (f->operators, oper);
328
329         return r;
330 }
331
332 static ESExpResult *
333 term_eval_or (struct _ESExp *f,
334               gint argc,
335               struct _ESExpTerm **argv,
336               gpointer data)
337 {
338         struct _ESExpResult *r, *r1;
339         GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
340         struct IterData lambdafoo;
341         gint type = -1;
342         gint bool = FALSE;
343         gint i;
344         const gchar *oper;
345
346         r (printf ("(or \n"));
347
348         oper = "OR";
349         f->operators = g_slist_prepend (f->operators, (gpointer) oper);
350
351         r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
352
353         for (i = 0; !bool && i < argc; i++) {
354                 r1 = e_sexp_term_eval (f, argv[i]);
355                 if (type == -1)
356                         type = r1->type;
357                 if (r1->type != type) {
358                         e_sexp_result_free (f, r);
359                         e_sexp_result_free (f, r1);
360                         g_hash_table_destroy (ht);
361                         e_sexp_fatal_error (f, "Invalid types in OR");
362                 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
363                         gchar **a1;
364                         gint l1, j;
365
366                         a1 = (gchar **) r1->value.ptrarray->pdata;
367                         l1 = r1->value.ptrarray->len;
368                         for (j = 0; j < l1; j++) {
369                                 g_hash_table_insert (ht, a1[j], (gpointer) 1);
370                         }
371                 } else if (r1->type == ESEXP_RES_BOOL) {
372                         bool |= r1->value.boolean;
373                 }
374                 e_sexp_result_free (f, r1);
375         }
376
377         if (type == ESEXP_RES_ARRAY_PTR) {
378                 lambdafoo.count = argc;
379                 lambdafoo.uids = g_ptr_array_new ();
380                 g_hash_table_foreach (ht, (GHFunc) htor, &lambdafoo);
381                 r->type = ESEXP_RES_ARRAY_PTR;
382                 r->value.ptrarray = lambdafoo.uids;
383         } else if (type == ESEXP_RES_BOOL) {
384                 r->type = ESEXP_RES_BOOL;
385                 r->value.boolean = bool;
386         }
387         g_hash_table_destroy (ht);
388
389         f->operators = g_slist_remove (f->operators, oper);
390         return r;
391 }
392
393 static ESExpResult *
394 term_eval_not (struct _ESExp *f,
395                gint argc,
396                struct _ESExpResult **argv,
397                gpointer data)
398 {
399         gint res = TRUE;
400         ESExpResult *r;
401
402         if (argc > 0) {
403                 if (argv[0]->type == ESEXP_RES_BOOL
404                     && argv[0]->value.boolean)
405                         res = FALSE;
406         }
407         r = e_sexp_result_new (f, ESEXP_RES_BOOL);
408         r->value.boolean = res;
409         return r;
410 }
411
412 /* this should support all arguments ...? */
413 static ESExpResult *
414 term_eval_lt (struct _ESExp *f,
415               gint argc,
416               struct _ESExpTerm **argv,
417               gpointer data)
418 {
419         struct _ESExpResult *r, *r1, *r2;
420
421         r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
422
423         if (argc == 2) {
424                 r1 = e_sexp_term_eval (f, argv[0]);
425                 r2 = e_sexp_term_eval (f, argv[1]);
426                 if (r1->type != r2->type) {
427                         e_sexp_result_free (f, r1);
428                         e_sexp_result_free (f, r2);
429                         e_sexp_result_free (f, r);
430                         e_sexp_fatal_error (f, "Incompatible types in compare <");
431                 } else if (r1->type == ESEXP_RES_INT) {
432                         r->type = ESEXP_RES_BOOL;
433                         r->value.boolean = r1->value.number < r2->value.number;
434                 } else if (r1->type == ESEXP_RES_TIME) {
435                         r->type = ESEXP_RES_BOOL;
436                         r->value.boolean = r1->value.time < r2->value.time;
437                 } else if (r1->type == ESEXP_RES_STRING) {
438                         r->type = ESEXP_RES_BOOL;
439                         r->value.boolean = strcmp (r1->value.string, r2->value.string) < 0;
440                 }
441                 e_sexp_result_free (f, r1);
442                 e_sexp_result_free (f, r2);
443         }
444         return r;
445 }
446
447 /* this should support all arguments ...? */
448 static ESExpResult *
449 term_eval_gt (struct _ESExp *f,
450               gint argc,
451               struct _ESExpTerm **argv,
452               gpointer data)
453 {
454         struct _ESExpResult *r, *r1, *r2;
455
456         r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
457
458         if (argc == 2) {
459                 r1 = e_sexp_term_eval (f, argv[0]);
460                 r2 = e_sexp_term_eval (f, argv[1]);
461                 if (r1->type != r2->type) {
462                         e_sexp_result_free (f, r1);
463                         e_sexp_result_free (f, r2);
464                         e_sexp_result_free (f, r);
465                         e_sexp_fatal_error (f, "Incompatible types in compare >");
466                 } else if (r1->type == ESEXP_RES_INT) {
467                         r->type = ESEXP_RES_BOOL;
468                         r->value.boolean = r1->value.number > r2->value.number;
469                 } else if (r1->type == ESEXP_RES_TIME) {
470                         r->type = ESEXP_RES_BOOL;
471                         r->value.boolean = r1->value.time > r2->value.time;
472                 } else if (r1->type == ESEXP_RES_STRING) {
473                         r->type = ESEXP_RES_BOOL;
474                         r->value.boolean = strcmp (r1->value.string, r2->value.string) > 0;
475                 }
476                 e_sexp_result_free (f, r1);
477                 e_sexp_result_free (f, r2);
478         }
479         return r;
480 }
481
482 /* this should support all arguments ...? */
483 static ESExpResult *
484 term_eval_eq (struct _ESExp *f,
485               gint argc,
486               struct _ESExpTerm **argv,
487               gpointer data)
488 {
489         struct _ESExpResult *r, *r1, *r2;
490
491         r = e_sexp_result_new (f, ESEXP_RES_BOOL);
492
493         if (argc == 2) {
494                 r1 = e_sexp_term_eval (f, argv[0]);
495                 r2 = e_sexp_term_eval (f, argv[1]);
496                 if (r1->type != r2->type) {
497                         r->value.boolean = FALSE;
498                 } else if (r1->type == ESEXP_RES_INT) {
499                         r->value.boolean = r1->value.number == r2->value.number;
500                 } else if (r1->type == ESEXP_RES_BOOL) {
501                         r->value.boolean = r1->value.boolean == r2->value.boolean;
502                 } else if (r1->type == ESEXP_RES_TIME) {
503                         r->value.boolean = r1->value.time == r2->value.time;
504                 } else if (r1->type == ESEXP_RES_STRING) {
505                         r->value.boolean = strcmp (r1->value.string, r2->value.string) == 0;
506                 }
507                 e_sexp_result_free (f, r1);
508                 e_sexp_result_free (f, r2);
509         }
510         return r;
511 }
512
513 static ESExpResult *
514 term_eval_plus (struct _ESExp *f,
515                 gint argc,
516                 struct _ESExpResult **argv,
517                 gpointer data)
518 {
519         struct _ESExpResult *r = NULL;
520         gint type;
521         gint i;
522
523         if (argc > 0) {
524                 type = argv[0]->type;
525                 switch (type) {
526                 case ESEXP_RES_INT: {
527                         gint total = argv[0]->value.number;
528                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_INT; i++) {
529                                 total += argv[i]->value.number;
530                         }
531                         if (i < argc) {
532                                 e_sexp_resultv_free (f, argc, argv);
533                                 e_sexp_fatal_error (f, "Invalid types in (+ ints)");
534                         }
535                         r = e_sexp_result_new (f, ESEXP_RES_INT);
536                         r->value.number = total;
537                         break; }
538                 case ESEXP_RES_STRING: {
539                         GString *s = g_string_new (argv[0]->value.string);
540                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_STRING; i++) {
541                                 g_string_append (s, argv[i]->value.string);
542                         }
543                         if (i < argc) {
544                                 e_sexp_resultv_free (f, argc, argv);
545                                 e_sexp_fatal_error (f, "Invalid types in (+ strings)");
546                         }
547                         r = e_sexp_result_new (f, ESEXP_RES_STRING);
548                         r->value.string = s->str;
549                         g_string_free (s, FALSE);
550                         break; }
551                 case ESEXP_RES_TIME: {
552                         time_t total;
553
554                         total = argv[0]->value.time;
555
556                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
557                                 total += argv[i]->value.time;
558
559                         if (i < argc) {
560                                 e_sexp_resultv_free (f, argc, argv);
561                                 e_sexp_fatal_error (f, "Invalid types in (+ time_t)");
562                         }
563
564                         r = e_sexp_result_new (f, ESEXP_RES_TIME);
565                         r->value.time = total;
566                         break; }
567                 }
568         }
569
570         if (!r) {
571                 r = e_sexp_result_new (f, ESEXP_RES_INT);
572                 r->value.number = 0;
573         }
574         return r;
575 }
576
577 static ESExpResult *
578 term_eval_sub (struct _ESExp *f,
579                gint argc,
580                struct _ESExpResult **argv,
581                gpointer data)
582 {
583         struct _ESExpResult *r = NULL;
584         gint type;
585         gint i;
586
587         if (argc > 0) {
588                 type = argv[0]->type;
589                 switch (type) {
590                 case ESEXP_RES_INT: {
591                         gint total = argv[0]->value.number;
592                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_INT; i++) {
593                                 total -= argv[i]->value.number;
594                         }
595                         if (i < argc) {
596                                 e_sexp_resultv_free (f, argc, argv);
597                                 e_sexp_fatal_error (f, "Invalid types in -");
598                         }
599                         r = e_sexp_result_new (f, ESEXP_RES_INT);
600                         r->value.number = total;
601                         break; }
602                 case ESEXP_RES_TIME: {
603                         time_t total;
604
605                         total = argv[0]->value.time;
606
607                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
608                                 total -= argv[i]->value.time;
609
610                         if (i < argc) {
611                                 e_sexp_resultv_free (f, argc, argv);
612                                 e_sexp_fatal_error (f, "Invalid types in (- time_t)");
613                         }
614
615                         r = e_sexp_result_new (f, ESEXP_RES_TIME);
616                         r->value.time = total;
617                         break; }
618                 }
619         }
620
621         if (!r) {
622                 r = e_sexp_result_new (f, ESEXP_RES_INT);
623                 r->value.number = 0;
624         }
625         return r;
626 }
627
628 /* cast to gint */
629 static ESExpResult *
630 term_eval_castint (struct _ESExp *f,
631                    gint argc,
632                    struct _ESExpResult **argv,
633                    gpointer data)
634 {
635         struct _ESExpResult *r;
636
637         if (argc != 1)
638                 e_sexp_fatal_error (f, "Incorrect argument count to (gint )");
639
640         r = e_sexp_result_new (f, ESEXP_RES_INT);
641         switch (argv[0]->type) {
642         case ESEXP_RES_INT:
643                 r->value.number = argv[0]->value.number;
644                 break;
645         case ESEXP_RES_BOOL:
646                 r->value.number = argv[0]->value.boolean != 0;
647                 break;
648         case ESEXP_RES_STRING:
649                 r->value.number = strtoul (argv[0]->value.string, NULL, 10);
650                 break;
651         default:
652                 e_sexp_result_free (f, r);
653                 e_sexp_fatal_error (f, "Invalid type in (cast-int )");
654         }
655
656         return r;
657 }
658
659 /* cast to string */
660 static ESExpResult *
661 term_eval_caststring (struct _ESExp *f,
662                       gint argc,
663                       struct _ESExpResult **argv,
664                       gpointer data)
665 {
666         struct _ESExpResult *r;
667
668         if (argc != 1)
669                 e_sexp_fatal_error (f, "Incorrect argument count to (cast-string )");
670
671         r = e_sexp_result_new (f, ESEXP_RES_STRING);
672         switch (argv[0]->type) {
673         case ESEXP_RES_INT:
674                 r->value.string = g_strdup_printf ("%d", argv[0]->value.number);
675                 break;
676         case ESEXP_RES_BOOL:
677                 r->value.string = g_strdup_printf ("%d", argv[0]->value.boolean != 0);
678                 break;
679         case ESEXP_RES_STRING:
680                 r->value.string = g_strdup (argv[0]->value.string);
681                 break;
682         default:
683                 e_sexp_result_free (f, r);
684                 e_sexp_fatal_error (f, "Invalid type in (gint )");
685         }
686
687         return r;
688 }
689
690 /* implements 'if' function */
691 static ESExpResult *
692 term_eval_if (struct _ESExp *f,
693               gint argc,
694               struct _ESExpTerm **argv,
695               gpointer data)
696 {
697         struct _ESExpResult *r;
698         gint doit;
699
700         if (argc >=2 && argc <= 3) {
701                 r = e_sexp_term_eval (f, argv[0]);
702                 doit = (r->type == ESEXP_RES_BOOL && r->value.boolean);
703                 e_sexp_result_free (f, r);
704                 if (doit) {
705                         return e_sexp_term_eval (f, argv[1]);
706                 } else if (argc > 2) {
707                         return e_sexp_term_eval (f, argv[2]);
708                 }
709         }
710         return e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
711 }
712
713 /* implements 'begin' statement */
714 static ESExpResult *
715 term_eval_begin (struct _ESExp *f,
716                  gint argc,
717                  struct _ESExpTerm **argv,
718                  gpointer data)
719 {
720         struct _ESExpResult *r = NULL;
721         gint i;
722
723         for (i = 0; i < argc; i++) {
724                 if (r)
725                         e_sexp_result_free (f, r);
726                 r = e_sexp_term_eval (f, argv[i]);
727         }
728         if (r)
729                 return r;
730         else
731                 return e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
732 }
733
734 /* this must only be called from inside term evaluation callbacks! */
735 struct _ESExpResult *
736 e_sexp_term_eval (struct _ESExp *f,
737                   struct _ESExpTerm *t)
738 {
739         struct _ESExpResult *r = NULL;
740         gint i;
741         struct _ESExpResult **argv;
742
743         g_return_val_if_fail (t != NULL, NULL);
744
745         r (printf ("eval term :\n"));
746         r (parse_dump_term (t, 0));
747
748         switch (t->type) {
749         case ESEXP_TERM_STRING:
750                 r (printf (" (string \"%s\")\n", t->value.string));
751                 r = e_sexp_result_new (f, ESEXP_RES_STRING);
752                 /* erk, this shoul;dn't need to strdup this ... */
753                 r->value.string = g_strdup (t->value.string);
754                 break;
755         case ESEXP_TERM_INT:
756                 r (printf (" (gint %d)\n", t->value.number));
757                 r = e_sexp_result_new (f, ESEXP_RES_INT);
758                 r->value.number = t->value.number;
759                 break;
760         case ESEXP_TERM_BOOL:
761                 r (printf (" (gint %d)\n", t->value.number));
762                 r = e_sexp_result_new (f, ESEXP_RES_BOOL);
763                 r->value.boolean = t->value.boolean;
764                 break;
765         case ESEXP_TERM_TIME:
766                 r (printf (" (time_t %ld)\n", t->value.time));
767                 r = e_sexp_result_new (f, ESEXP_RES_TIME);
768                 r->value.time = t->value.time;
769                 break;
770         case ESEXP_TERM_IFUNC:
771                 if (t->value.func.sym && t->value.func.sym->f.ifunc)
772                         r = t->value.func.sym->f.ifunc (
773                                 f, t->value.func.termcount,
774                                 t->value.func.terms, t->value.func.sym->data);
775                 break;
776         case ESEXP_TERM_FUNC:
777                 /* first evaluate all arguments to result types */
778                 argv = alloca (sizeof (argv[0]) * t->value.func.termcount);
779                 for (i = 0; i < t->value.func.termcount; i++) {
780                         argv[i] = e_sexp_term_eval (f, t->value.func.terms[i]);
781                 }
782                 /* call the function */
783                 if (t->value.func.sym->f.func)
784                         r = t->value.func.sym->f.func (
785                                 f, t->value.func.termcount,
786                                 argv, t->value.func.sym->data);
787
788                 e_sexp_resultv_free (f, t->value.func.termcount, argv);
789                 break;
790         default:
791                 e_sexp_fatal_error (f, "Unknown type in parse tree: %d", t->type);
792         }
793
794         if (r == NULL)
795                 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
796
797         return r;
798 }
799
800 #ifdef TESTER
801 static void
802 eval_dump_result (ESExpResult *r,
803                   gint depth)
804 {
805         gint i;
806
807         if (r == NULL) {
808                 printf ("null result???\n");
809                 return;
810         }
811
812         for (i = 0; i < depth; i++)
813                 printf ("   ");
814
815         switch (r->type) {
816         case ESEXP_RES_ARRAY_PTR:
817                 printf ("array pointers\n");
818                 break;
819         case ESEXP_RES_INT:
820                 printf ("int: %d\n", r->value.number);
821                 break;
822         case ESEXP_RES_STRING:
823                 printf ("string: '%s'\n", r->value.string);
824                 break;
825         case ESEXP_RES_BOOL:
826                 printf ("bool: %c\n", r->value.boolean ? 't':'f');
827                 break;
828         case ESEXP_RES_TIME:
829                 printf ("time_t: %ld\n", (glong) r->value.time);
830                 break;
831         case ESEXP_RES_UNDEFINED:
832                 printf (" <undefined>\n");
833                 break;
834         }
835         printf ("\n");
836 }
837 #endif
838
839 #ifdef TESTER
840 static void
841 parse_dump_term (struct _ESExpTerm *t,
842                  gint depth)
843 {
844         gint i;
845
846         if (t == NULL) {
847                 printf ("null term??\n");
848                 return;
849         }
850
851         for (i = 0; i < depth; i++)
852                 printf ("   ");
853
854         switch (t->type) {
855         case ESEXP_TERM_STRING:
856                 printf (" \"%s\"", t->value.string);
857                 break;
858         case ESEXP_TERM_INT:
859                 printf (" %d", t->value.number);
860                 break;
861         case ESEXP_TERM_BOOL:
862                 printf (" #%c", t->value.boolean ? 't':'f');
863                 break;
864         case ESEXP_TERM_TIME:
865                 printf (" %ld", (glong) t->value.time);
866                 break;
867         case ESEXP_TERM_IFUNC:
868         case ESEXP_TERM_FUNC:
869                 printf (" (function %s\n", t->value.func.sym->name);
870                 /*printf(" [%d] ", t->value.func.termcount);*/
871                 for (i = 0; i < t->value.func.termcount; i++) {
872                         parse_dump_term (t->value.func.terms[i], depth + 1);
873                 }
874                 for (i = 0; i < depth; i++)
875                         printf ("   ");
876                 printf (" )");
877                 break;
878         case ESEXP_TERM_VAR:
879                 printf (" (variable %s )\n", t->value.var->name);
880                 break;
881         default:
882                 printf ("unknown type: %d\n", t->type);
883         }
884
885         printf ("\n");
886 }
887 #endif
888
889 const gchar *time_functions[] = {
890         "time-now",
891         "make-time",
892         "time-add-day",
893         "time-day-begin",
894         "time-day-end"
895 };
896
897 static gboolean
898 occur_in_time_range_generator (gint argc,
899                   struct _ESExpResult **argv,
900                   struct _ESExpResult *r)
901 {
902         g_return_val_if_fail (r != NULL, FALSE);
903         g_return_val_if_fail (argc == 2 || argc == 3, FALSE);
904
905         if ((argv[0]->type != ESEXP_RES_TIME) || (argv[1]->type != ESEXP_RES_TIME))
906                 return FALSE;
907
908         r->occuring_start = argv[0]->value.time;
909         r->occuring_end = argv[1]->value.time;
910
911         return TRUE;
912 }
913
914 static gboolean
915 binary_generator (gint argc,
916                   struct _ESExpResult **argv,
917                   struct _ESExpResult *r)
918 {
919         g_return_val_if_fail (r != NULL, FALSE);
920         g_return_val_if_fail (argc == 2, FALSE);
921
922         if ((argv[0]->type != ESEXP_RES_TIME) || (argv[1]->type != ESEXP_RES_TIME))
923                 return FALSE;
924
925         r->occuring_start = argv[0]->value.time;
926         r->occuring_end = argv[1]->value.time;
927
928         return TRUE;
929 }
930
931 static gboolean
932 unary_generator (gint argc,
933                  struct _ESExpResult **argv,
934                  struct _ESExpResult *r)
935 {
936         /* unary generator with end time */
937         g_return_val_if_fail (r != NULL, FALSE);
938         g_return_val_if_fail (argc == 1, FALSE);
939
940         if (argv[0]->type != ESEXP_RES_TIME)
941                 return FALSE;
942
943         r->occuring_start = 0;
944         r->occuring_end = argv[0]->value.time;
945
946         return TRUE;
947 }
948
949 static const struct {
950         const gchar *name;
951         ESGeneratorFunc *func;
952 } generators[] = {
953         {"occur-in-time-range?", occur_in_time_range_generator},
954         {"due-in-time-range?", binary_generator},
955         {"has-alarms-in-range?", binary_generator},
956         {"completed-before?", unary_generator},
957 };
958
959 const gint generators_count = sizeof (generators) / sizeof (generators[0]);
960
961 static gboolean
962 or_operator (gint argc,
963              struct _ESExpResult **argv,
964              struct _ESExpResult *r)
965 {
966         gint ii;
967
968         /*
969          * A          B           A or B
970          * ----       ----        ------
971          * norm (0)   norm (0)    norm (0)
972          * gen (1)    norm (0)    norm (0)
973          * norm (0)   gen (1)     norm (0)
974          * gen (1)    gen (1)     gen*(1)
975          */
976
977         g_return_val_if_fail (r != NULL, FALSE);
978         g_return_val_if_fail (argc > 0, FALSE);
979
980         r->time_generator = TRUE;
981         for (ii = 0; ii < argc && r->time_generator; ii++) {
982                 r->time_generator = argv[ii]->time_generator;
983         }
984
985         if (r->time_generator) {
986                 r->occuring_start = argv[0]->occuring_start;
987                 r->occuring_end = argv[0]->occuring_end;
988
989                 for (ii = 1; ii < argc; ii++) {
990                         r->occuring_start = MIN (r->occuring_start, argv[ii]->occuring_start);
991                         r->occuring_end = MAX (r->occuring_end, argv[ii]->occuring_end);
992                 }
993         }
994
995         return TRUE;
996 }
997
998 static gboolean
999 and_operator (gint argc,
1000               struct _ESExpResult **argv,
1001               struct _ESExpResult *r)
1002 {
1003         gint ii;
1004
1005         /*
1006          * A           B          A and B
1007          * ----        ----       ------- -
1008          * norm (0)     norm (0)    norm (0)
1009          * gen (1)      norm (0)    gen (1)
1010          * norm (0)     gen (1)     gen (1)
1011          * gen (1)      gen (1)     gen (1)
1012          * */
1013
1014         g_return_val_if_fail (r != NULL, FALSE);
1015         g_return_val_if_fail (argc > 0, FALSE);
1016
1017         r->time_generator = FALSE;
1018         for (ii = 0; ii < argc && !r->time_generator; ii++) {
1019                 r->time_generator = argv[ii]->time_generator;
1020         }
1021
1022         if (r->time_generator) {
1023                 r->occuring_start = argv[0]->occuring_start;
1024                 r->occuring_end = argv[0]->occuring_end;
1025
1026                 for (ii = 1; ii < argc; ii++) {
1027                         r->occuring_start = MAX (r->occuring_start, argv[ii]->occuring_start);
1028                         r->occuring_end = MIN (r->occuring_end, argv[ii]->occuring_end);
1029                 }
1030         }
1031
1032         return TRUE;
1033 }
1034
1035 static const struct {
1036         const gchar *name;
1037         ESOperatorFunc *func;
1038 } operators[] = {
1039         {"or", or_operator},
1040         {"and", and_operator}
1041 };
1042
1043 const gint operators_count = sizeof (operators) / sizeof (operators[0]);
1044
1045 static ESOperatorFunc *
1046 get_operator_function (const gchar *fname)
1047 {
1048         gint i;
1049
1050         g_return_val_if_fail (fname != NULL, NULL);
1051
1052         for (i = 0; i < sizeof (operators) / sizeof (operators[0]); i++)
1053                 if (strcmp (operators[i].name, fname) == 0)
1054                         return operators[i].func;
1055
1056         return NULL;
1057 }
1058
1059 static inline gboolean
1060 is_time_function (const gchar *fname)
1061 {
1062         gint i;
1063
1064         g_return_val_if_fail (fname != NULL, FALSE);
1065
1066         for (i = 0; i < sizeof (time_functions) / sizeof (time_functions[0]); i++)
1067                 if (strcmp (time_functions[i], fname) == 0)
1068                         return TRUE;
1069
1070         return FALSE;
1071 }
1072
1073 static ESGeneratorFunc *
1074 get_generator_function (const gchar *fname)
1075 {
1076         gint i;
1077
1078         g_return_val_if_fail (fname != NULL, NULL);
1079
1080         for (i = 0; i < sizeof (generators) / sizeof (generators[0]); i++)
1081                 if (strcmp (generators[i].name, fname) == 0)
1082                         return generators[i].func;
1083
1084         return NULL;
1085 }
1086
1087 /* this must only be called from inside term evaluation callbacks! */
1088 static struct _ESExpResult *
1089 e_sexp_term_evaluate_occur_times (struct _ESExp *f,
1090                                   struct _ESExpTerm *t,
1091                                   time_t *start,
1092                                   time_t *end)
1093 {
1094         struct _ESExpResult *r = NULL;
1095         gint i, argc;
1096         struct _ESExpResult **argv;
1097         gboolean ok = TRUE;
1098
1099         g_return_val_if_fail (t != NULL, NULL);
1100         g_return_val_if_fail (start != NULL, NULL);
1101         g_return_val_if_fail (end != NULL, NULL);
1102
1103         /*
1104         printf ("eval term :\n");
1105         parse_dump_term (t, 0);
1106         */
1107
1108         switch (t->type) {
1109         case ESEXP_TERM_STRING:
1110                 r (printf (" (string \"%s\")\n", t->value.string));
1111                 r = e_sexp_result_new (f, ESEXP_RES_STRING);
1112                 r->value.string = g_strdup (t->value.string);
1113                 break;
1114         case ESEXP_TERM_IFUNC:
1115         case ESEXP_TERM_FUNC:
1116         {
1117                 ESGeneratorFunc *generator = NULL;
1118                 ESOperatorFunc *operator = NULL;
1119
1120                 r (printf (" (function \"%s\"\n", t->value.func.sym->name));
1121
1122                 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
1123                 argc = t->value.func.termcount;
1124                 argv = alloca (sizeof (argv[0]) * argc);
1125
1126                 for (i = 0; i < t->value.func.termcount; i++) {
1127                         argv[i] = e_sexp_term_evaluate_occur_times (
1128                                 f, t->value.func.terms[i], start, end);
1129                 }
1130
1131                 if (is_time_function (t->value.func.sym->name)) {
1132                         /* evaluate time */
1133                         if (t->value.func.sym->f.func)
1134                                 r = t->value.func.sym->f.func (f, t->value.func.termcount,
1135                                               argv, t->value.func.sym->data);
1136                 } else if ((generator = get_generator_function (t->value.func.sym->name)) != NULL) {
1137                         /* evaluate generator function */
1138                         r->time_generator = TRUE;
1139                         ok = generator (argc, argv, r);
1140                 } else if ((operator = get_operator_function (t->value.func.sym->name)) != NULL)
1141                         /* evaluate operator function */
1142                         ok = operator (argc, argv, r);
1143                 else {
1144                         /* normal function: we need to scan all objects */
1145                         r->time_generator = FALSE;
1146                 }
1147
1148                 e_sexp_resultv_free (f, t->value.func.termcount, argv);
1149                 break;
1150         }
1151         case ESEXP_TERM_INT:
1152         case ESEXP_TERM_BOOL:
1153         case ESEXP_TERM_TIME:
1154                 break;
1155         default:
1156                 ok = FALSE;
1157                 break;
1158         }
1159
1160         if (!ok)
1161                 e_sexp_fatal_error (f, "Error in parse tree");
1162
1163         if (r == NULL)
1164                 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
1165
1166         return r;
1167 }
1168
1169 /*
1170   PARSER
1171 */
1172
1173 static struct _ESExpTerm *
1174 parse_term_new (struct _ESExp *f,
1175                 gint type)
1176 {
1177         struct _ESExpTerm *s = e_memchunk_alloc0 (f->term_chunks);
1178         s->type = type;
1179         return s;
1180 }
1181
1182 static void
1183 parse_term_free (struct _ESExp *f,
1184                  struct _ESExpTerm *t)
1185 {
1186         gint i;
1187
1188         if (t == NULL) {
1189                 return;
1190         }
1191
1192         switch (t->type) {
1193         case ESEXP_TERM_INT:
1194         case ESEXP_TERM_BOOL:
1195         case ESEXP_TERM_TIME:
1196         case ESEXP_TERM_VAR:
1197                 break;
1198
1199         case ESEXP_TERM_STRING:
1200                 g_free (t->value.string);
1201                 break;
1202
1203         case ESEXP_TERM_FUNC:
1204         case ESEXP_TERM_IFUNC:
1205                 for (i = 0; i < t->value.func.termcount; i++) {
1206                         parse_term_free (f, t->value.func.terms[i]);
1207                 }
1208                 g_free (t->value.func.terms);
1209                 break;
1210
1211         default:
1212                 printf ("parse_term_free: unknown type: %d\n", t->type);
1213         }
1214         e_memchunk_free (f->term_chunks, t);
1215 }
1216
1217 static struct _ESExpTerm **
1218 parse_values (ESExp *f,
1219               gint *len)
1220 {
1221         gint token;
1222         struct _ESExpTerm **terms;
1223         gint i, size = 0;
1224         GScanner *gs = f->scanner;
1225         GSList *list = NULL, *l;
1226
1227         p (printf ("parsing values\n"));
1228
1229         while ( (token = g_scanner_peek_next_token (gs)) != G_TOKEN_EOF
1230                 && token != ')') {
1231                 list = g_slist_prepend (list, parse_value (f));
1232                 size++;
1233         }
1234
1235         /* go over the list, and put them backwards into the term array */
1236         terms = g_malloc (size * sizeof (*terms));
1237         l = list;
1238         for (i = size - 1; i >= 0; i--) {
1239                 g_assert (l);
1240                 g_assert (l->data);
1241                 terms[i] = l->data;
1242                 l = g_slist_next (l);
1243         }
1244         g_slist_free (list);
1245
1246         p (printf ("found %d subterms\n", size));
1247         *len = size;
1248
1249         p (printf ("done parsing values\n"));
1250         return terms;
1251 }
1252
1253 /**
1254  * e_sexp_parse_value:
1255  *
1256  * Since: 2.28
1257  **/
1258 ESExpTerm *
1259 e_sexp_parse_value (ESExp *f)
1260 {
1261         return parse_value (f);
1262 }
1263
1264 static struct _ESExpTerm *
1265 parse_value (ESExp *f)
1266 {
1267         gint token, negative = FALSE;
1268         struct _ESExpTerm *t = NULL;
1269         GScanner *gs = f->scanner;
1270         struct _ESExpSymbol *s;
1271
1272         p (printf ("parsing value\n"));
1273
1274         token = g_scanner_get_next_token (gs);
1275         switch (token) {
1276         case G_TOKEN_EOF:
1277                 break;
1278         case G_TOKEN_LEFT_PAREN:
1279                 p (printf ("got brace, its a list!\n"));
1280                 return parse_list (f, TRUE);
1281         case G_TOKEN_STRING:
1282                 p (printf (
1283                         "got string '%s'\n",
1284                         g_scanner_cur_value (gs).v_string));
1285                 t = parse_term_new (f, ESEXP_TERM_STRING);
1286                 t->value.string = g_strdup (g_scanner_cur_value (gs).v_string);
1287                 break;
1288         case '-':
1289                 p (printf ("got negative int?\n"));
1290                 token = g_scanner_get_next_token (gs);
1291                 if (token != G_TOKEN_INT) {
1292                         e_sexp_fatal_error (
1293                                 f, "Invalid format for a integer value");
1294                         return NULL;
1295                 }
1296
1297                 negative = TRUE;
1298                 /* fall through... */
1299         case G_TOKEN_INT:
1300                 t = parse_term_new (f, ESEXP_TERM_INT);
1301                 t->value.number = g_scanner_cur_value (gs).v_int;
1302                 if (negative)
1303                         t->value.number = -t->value.number;
1304                 p (printf ("got gint %d\n", t->value.number));
1305                 break;
1306         case '#': {
1307                 gchar *str;
1308
1309                 p (printf ("got bool?\n"));
1310                 token = g_scanner_get_next_token (gs);
1311                 if (token != G_TOKEN_IDENTIFIER) {
1312                         e_sexp_fatal_error (
1313                                 f, "Invalid format for a boolean value");
1314                         return NULL;
1315                 }
1316
1317                 str = g_scanner_cur_value (gs).v_identifier;
1318
1319                 g_assert (str != NULL);
1320                 if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
1321                         e_sexp_fatal_error (
1322                                 f, "Invalid format for a boolean value");
1323                         return NULL;
1324                 }
1325
1326                 t = parse_term_new (f, ESEXP_TERM_BOOL);
1327                 t->value.boolean = (str[0] == 't');
1328                 break; }
1329         case G_TOKEN_SYMBOL:
1330                 s = g_scanner_cur_value (gs).v_symbol;
1331                 p (printf ("got symbol '%s'\n", s->name));
1332                 switch (s->type) {
1333                 case ESEXP_TERM_FUNC:
1334                 case ESEXP_TERM_IFUNC:
1335                         /* this is basically invalid, since we can't use
1336                          * function pointers, but let the runtime catch it */
1337                         t = parse_term_new (f, s->type);
1338                         t->value.func.sym = s;
1339                         t->value.func.terms = parse_values (
1340                                 f, &t->value.func.termcount);
1341                         break;
1342                 case ESEXP_TERM_VAR:
1343                         t = parse_term_new (f, s->type);
1344                         t->value.var = s;
1345                         break;
1346                 default:
1347                         e_sexp_fatal_error (
1348                                 f, "Invalid symbol type: %s: %d",
1349                                 s->name, s->type);
1350                 }
1351                 break;
1352         case G_TOKEN_IDENTIFIER:
1353                 p (printf (
1354                         "got unknown identifider '%s'\n",
1355                         g_scanner_cur_value (gs).v_identifier));
1356                 e_sexp_fatal_error (
1357                         f, "Unknown identifier: %s",
1358                         g_scanner_cur_value (gs).v_identifier);
1359                 break;
1360         default:
1361                 e_sexp_fatal_error (
1362                         f, "Unexpected token encountered: %d", token);
1363         }
1364         p (printf ("done parsing value\n"));
1365         return t;
1366 }
1367
1368 /* FIXME: this needs some robustification */
1369 static struct _ESExpTerm *
1370 parse_list (ESExp *f,
1371             gint gotbrace)
1372 {
1373         gint token;
1374         struct _ESExpTerm *t = NULL;
1375         GScanner *gs = f->scanner;
1376
1377         p (printf ("parsing list\n"));
1378         if (gotbrace)
1379                 token = '(';
1380         else
1381                 token = g_scanner_get_next_token (gs);
1382         if (token =='(') {
1383                 token = g_scanner_get_next_token (gs);
1384                 switch (token) {
1385                 case G_TOKEN_SYMBOL: {
1386                         struct _ESExpSymbol *s;
1387
1388                         s = g_scanner_cur_value (gs).v_symbol;
1389                         p (printf ("got funciton: %s\n", s->name));
1390                         t = parse_term_new (f, s->type);
1391                         p (printf ("created new list %p\n", t));
1392                         /* if we have a variable, find out its base type */
1393                         while (s->type == ESEXP_TERM_VAR) {
1394                                 s = ((ESExpTerm *)(s->data))->value.var;
1395                         }
1396                         if (s->type == ESEXP_TERM_FUNC
1397                             || s->type == ESEXP_TERM_IFUNC) {
1398                                 t->value.func.sym = s;
1399                                 t->value.func.terms = parse_values (
1400                                         f, &t->value.func.termcount);
1401                         } else {
1402                                 parse_term_free (f, t);
1403                                 e_sexp_fatal_error (
1404                                         f, "Trying to call variable "
1405                                         "as function: %s", s->name);
1406                         }
1407                         break; }
1408                 case G_TOKEN_IDENTIFIER:
1409                         e_sexp_fatal_error (
1410                                 f, "Unknown identifier: %s",
1411                                 g_scanner_cur_value (gs).v_identifier);
1412                         break;
1413                 case G_TOKEN_LEFT_PAREN:
1414                         return parse_list (f, TRUE);
1415                 default:
1416                         e_sexp_fatal_error (f, "Unexpected token encountered: %d", token);
1417                 }
1418                 token = g_scanner_get_next_token (gs);
1419                 if (token != ')') {
1420                         e_sexp_fatal_error (f, "Missing ')'");
1421                 }
1422         } else {
1423                 e_sexp_fatal_error (f, "Missing '('");
1424         }
1425
1426         p (printf ("returning list %p\n", t));
1427         return t;
1428 }
1429
1430 static void e_sexp_finalise (gpointer);
1431
1432 #ifdef E_SEXP_IS_G_OBJECT
1433 static void
1434 e_sexp_class_init (ESExpClass *class)
1435 {
1436         GObjectClass *object_class = G_OBJECT_CLASS (class);
1437
1438         object_class->finalize = e_sexp_finalise;
1439 }
1440 #endif
1441
1442 /* 'builtin' functions */
1443 static const struct {
1444         const gchar *name;
1445         ESExpFunc *func;
1446         gint type;              /* set to 1 if a function can perform shortcut evaluation, or
1447                                    doesn't execute everything, 0 otherwise */
1448 } symbols[] = {
1449         { "and", (ESExpFunc *) term_eval_and, 1 },
1450         { "or", (ESExpFunc *) term_eval_or, 1 },
1451         { "not", (ESExpFunc *) term_eval_not, 0 },
1452         { "<", (ESExpFunc *) term_eval_lt, 1 },
1453         { ">", (ESExpFunc *) term_eval_gt, 1 },
1454         { "=", (ESExpFunc *) term_eval_eq, 1 },
1455         { "+", (ESExpFunc *) term_eval_plus, 0 },
1456         { "-", (ESExpFunc *) term_eval_sub, 0 },
1457         { "cast-int", (ESExpFunc *) term_eval_castint, 0 },
1458         { "cast-string", (ESExpFunc *) term_eval_caststring, 0 },
1459         { "if", (ESExpFunc *) term_eval_if, 1 },
1460         { "begin", (ESExpFunc *) term_eval_begin, 1 },
1461 };
1462
1463 static void
1464 free_symbol (gpointer key,
1465              gpointer value,
1466              gpointer data)
1467 {
1468         struct _ESExpSymbol *s = value;
1469
1470         g_free (s->name);
1471         g_free (s);
1472 }
1473
1474 static void
1475 e_sexp_finalise (gpointer o)
1476 {
1477         ESExp *s = (ESExp *) o;
1478
1479         if (s->tree) {
1480                 parse_term_free (s, s->tree);
1481                 s->tree = NULL;
1482         }
1483
1484         e_memchunk_destroy (s->term_chunks);
1485         e_memchunk_destroy (s->result_chunks);
1486
1487         g_scanner_scope_foreach_symbol (s->scanner, 0, free_symbol, NULL);
1488         g_scanner_destroy (s->scanner);
1489
1490 #ifdef E_SEXP_IS_G_OBJECT
1491         G_OBJECT_CLASS (e_sexp_parent_class)->finalize (o);
1492 #endif
1493 }
1494
1495 static void
1496 e_sexp_init (ESExp *s)
1497 {
1498         gint i;
1499
1500         s->scanner = g_scanner_new (&scanner_config);
1501         s->term_chunks = e_memchunk_new (16, sizeof (struct _ESExpTerm));
1502         s->result_chunks = e_memchunk_new (16, sizeof (struct _ESExpResult));
1503
1504         /* load in builtin symbols? */
1505         for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
1506                 if (symbols[i].type == 1) {
1507                         e_sexp_add_ifunction (
1508                                 s, 0,
1509                                 symbols[i].name,
1510                                 (ESExpIFunc *) symbols[i].func,
1511                                 (gpointer) &symbols[i]);
1512                 } else {
1513                         e_sexp_add_function (
1514                                 s, 0,
1515                                 symbols[i].name,
1516                                 symbols[i].func,
1517                                 (gpointer) &symbols[i]);
1518                 }
1519         }
1520
1521 #ifndef E_SEXP_IS_G_OBJECT
1522         s->refcount = 1;
1523 #endif
1524 }
1525
1526 ESExp *
1527 e_sexp_new (void)
1528 {
1529 #ifdef E_SEXP_IS_G_OBJECT
1530         ESExp *f = (ESexp *) g_object_new (E_TYPE_SEXP, NULL);
1531 #else
1532         ESExp *f = g_malloc0 (sizeof (ESExp));
1533         e_sexp_init (f);
1534 #endif
1535
1536         return f;
1537 }
1538
1539 #ifndef E_SEXP_IS_G_OBJECT
1540 void
1541 e_sexp_ref (ESExp *f)
1542 {
1543         f->refcount++;
1544 }
1545
1546 void
1547 e_sexp_unref (ESExp *f)
1548 {
1549         f->refcount--;
1550         if (f->refcount == 0) {
1551                 e_sexp_finalise (f);
1552                 g_free (f);
1553         }
1554 }
1555 #endif
1556
1557 void
1558 e_sexp_add_function (ESExp *f,
1559                      gint scope,
1560                      const gchar *name,
1561                      ESExpFunc *func,
1562                      gpointer data)
1563 {
1564         struct _ESExpSymbol *s;
1565
1566         g_return_if_fail (IS_E_SEXP (f));
1567         g_return_if_fail (name != NULL);
1568
1569         e_sexp_remove_symbol (f, scope, name);
1570
1571         s = g_malloc0 (sizeof (*s));
1572         s->name = g_strdup (name);
1573         s->f.func = func;
1574         s->type = ESEXP_TERM_FUNC;
1575         s->data = data;
1576         g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1577 }
1578
1579 void
1580 e_sexp_add_ifunction (ESExp *f,
1581                       gint scope,
1582                       const gchar *name,
1583                       ESExpIFunc *ifunc,
1584                       gpointer data)
1585 {
1586         struct _ESExpSymbol *s;
1587
1588         g_return_if_fail (IS_E_SEXP (f));
1589         g_return_if_fail (name != NULL);
1590
1591         e_sexp_remove_symbol (f, scope, name);
1592
1593         s = g_malloc0 (sizeof (*s));
1594         s->name = g_strdup (name);
1595         s->f.ifunc = ifunc;
1596         s->type = ESEXP_TERM_IFUNC;
1597         s->data = data;
1598         g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1599 }
1600
1601 void
1602 e_sexp_add_variable (ESExp *f,
1603                      gint scope,
1604                      gchar *name,
1605                      ESExpTerm *value)
1606 {
1607         struct _ESExpSymbol *s;
1608
1609         g_return_if_fail (IS_E_SEXP (f));
1610         g_return_if_fail (name != NULL);
1611
1612         s = g_malloc0 (sizeof (*s));
1613         s->name = g_strdup (name);
1614         s->type = ESEXP_TERM_VAR;
1615         s->data = value;
1616         g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1617 }
1618
1619 void
1620 e_sexp_remove_symbol (ESExp *f,
1621                       gint scope,
1622                       const gchar *name)
1623 {
1624         gint oldscope;
1625         struct _ESExpSymbol *s;
1626
1627         g_return_if_fail (IS_E_SEXP (f));
1628         g_return_if_fail (name != NULL);
1629
1630         oldscope = g_scanner_set_scope (f->scanner, scope);
1631         s = g_scanner_lookup_symbol (f->scanner, name);
1632         g_scanner_scope_remove_symbol (f->scanner, scope, name);
1633         g_scanner_set_scope (f->scanner, oldscope);
1634         if (s) {
1635                 g_free (s->name);
1636                 g_free (s);
1637         }
1638 }
1639
1640 gint
1641 e_sexp_set_scope (ESExp *f,
1642                   gint scope)
1643 {
1644         g_return_val_if_fail (IS_E_SEXP (f), 0);
1645
1646         return g_scanner_set_scope (f->scanner, scope);
1647 }
1648
1649 void
1650 e_sexp_input_text (ESExp *f,
1651                    const gchar *text,
1652                    gint len)
1653 {
1654         g_return_if_fail (IS_E_SEXP (f));
1655         g_return_if_fail (text != NULL);
1656
1657         g_scanner_input_text (f->scanner, text, len);
1658 }
1659
1660 void
1661 e_sexp_input_file (ESExp *f,
1662                    gint fd)
1663 {
1664         g_return_if_fail (IS_E_SEXP (f));
1665
1666         g_scanner_input_file (f->scanner, fd);
1667 }
1668
1669 /* returns -1 on error */
1670 gint
1671 e_sexp_parse (ESExp *f)
1672 {
1673         g_return_val_if_fail (IS_E_SEXP (f), -1);
1674
1675         if (setjmp (f->failenv))
1676                 return -1;
1677
1678         if (f->tree)
1679                 parse_term_free (f, f->tree);
1680
1681         f->tree = parse_value (f);
1682
1683         return 0;
1684 }
1685
1686 /* returns NULL on error */
1687 struct _ESExpResult *
1688 e_sexp_eval (ESExp *f)
1689 {
1690         g_return_val_if_fail (IS_E_SEXP (f), NULL);
1691         g_return_val_if_fail (f->tree != NULL, NULL);
1692
1693         if (setjmp (f->failenv)) {
1694                 g_warning ("Error in execution: %s", f->error);
1695                 return NULL;
1696         }
1697
1698         return e_sexp_term_eval (f, f->tree);
1699 }
1700
1701 /**
1702  * e_cal_backend_sexp_evaluate_occur_times:
1703  * @f: An #ESExp object.
1704  * @start: Start of the time window will be stored here.
1705  * @end: End of the time window will be stored here.
1706  *
1707  * Determines biggest time window given by expressions "occur-in-range" in sexp.
1708  *
1709  * Since: 2.32
1710  */
1711 gboolean
1712 e_sexp_evaluate_occur_times (ESExp *f,
1713                              time_t *start,
1714                              time_t *end)
1715 {
1716         struct _ESExpResult *r;
1717         gboolean generator;
1718         g_return_val_if_fail (IS_E_SEXP (f), FALSE);
1719         g_return_val_if_fail (f->tree != NULL, FALSE);
1720         g_return_val_if_fail (start != NULL, FALSE);
1721         g_return_val_if_fail (end != NULL, FALSE);
1722
1723         *start = *end = -1;
1724
1725         if (setjmp (f->failenv)) {
1726                 g_warning ("Error in execution: %s", f->error);
1727                 return FALSE;
1728         }
1729
1730         r = e_sexp_term_evaluate_occur_times (f, f->tree, start, end);
1731         generator = r->time_generator;
1732
1733         if (generator) {
1734                 *start = r->occuring_start;
1735                 *end = r->occuring_end;
1736         }
1737
1738         e_sexp_result_free (f, r);
1739
1740         return generator;
1741 }
1742
1743 /**
1744  * e_sexp_encode_bool:
1745  * @s:
1746  * @state:
1747  *
1748  * Encode a bool into an s-expression @s.  Bools are
1749  * encoded using #t #f syntax.
1750  **/
1751 void
1752 e_sexp_encode_bool (GString *s,
1753                     gboolean state)
1754 {
1755         if (state)
1756                 g_string_append (s, " #t");
1757         else
1758                 g_string_append (s, " #f");
1759 }
1760
1761 /**
1762  * e_sexp_encode_string:
1763  * @s: Destination string.
1764  * @string: String expression.
1765  *
1766  * Add a c string @string to the s-expression stored in
1767  * the gstring @s.  Quotes are added, and special characters
1768  * are escaped appropriately.
1769  **/
1770 void
1771 e_sexp_encode_string (GString *s,
1772                       const gchar *string)
1773 {
1774         gchar c;
1775         const gchar *p;
1776
1777         if (string == NULL)
1778                 p = "";
1779         else
1780                 p = string;
1781         g_string_append (s, " \"");
1782         while ((c = *p++)) {
1783                 if (c == '\\' || c == '\"' || c == '\'')
1784                         g_string_append_c (s, '\\');
1785                 g_string_append_c (s, c);
1786         }
1787         g_string_append (s, "\"");
1788 }
1789
1790 #ifdef TESTER
1791 gint main (gint argc, gchar **argv)
1792 {
1793         ESExp *f;
1794         gchar *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1795         ESExpResult *r;
1796
1797         g_type_init ();
1798
1799         f = e_sexp_new ();
1800
1801         e_sexp_add_variable (f, 0, "test", NULL);
1802
1803         if (argc < 2 || !argv[1])
1804                 return;
1805
1806         e_sexp_input_text (f, t, t);
1807         e_sexp_parse (f);
1808
1809         if (f->tree) {
1810                 parse_dump_term (f->tree, 0);
1811         }
1812
1813         r = e_sexp_eval (f);
1814         if (r) {
1815                 eval_dump_result (r, 0);
1816         } else {
1817                 printf ("no result?|\n");
1818         }
1819
1820         return 0;
1821 }
1822 #endif