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