Coding style cleanups.
[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         gint ii;
887
888         /*
889            A          B           A or B
890            ----       ----        ------
891            norm (0)    norm (0)     norm (0)
892            gen (1)     norm (0)     norm (0)
893            norm (0)    gen (1)      norm (0)
894            gen (1)     gen (1)      gen*(1)
895            */
896
897         g_return_val_if_fail (r != NULL, FALSE);
898         g_return_val_if_fail (argc > 0, FALSE);
899
900         r->time_generator = TRUE;
901         for (ii = 0; ii < argc && r->time_generator; ii++) {
902                 r->time_generator = argv[ii]->time_generator;
903         }
904
905         if (r->time_generator) {
906                 r->occuring_start = argv[0]->occuring_start;
907                 r->occuring_end = argv[0]->occuring_end;
908
909                 for (ii = 1; ii < argc; ii++) {
910                         r->occuring_start = MIN (r->occuring_start, argv[ii]->occuring_start);
911                         r->occuring_end = MAX (r->occuring_end, argv[ii]->occuring_end);
912                 }
913         }
914
915         return TRUE;
916 }
917
918 static gboolean
919 and_operator (gint argc, struct _ESExpResult **argv, struct _ESExpResult *r)
920 {
921         gint ii;
922
923         /*
924            A           B          A and B
925            ----        ----       ------- -
926            norm (0)     norm (0)    norm (0)
927            gen (1)      norm (0)    gen (1)
928            norm (0)     gen (1)     gen (1)
929            gen (1)      gen (1)     gen (1)
930            */
931
932         g_return_val_if_fail (r != NULL, FALSE);
933         g_return_val_if_fail (argc > 0, FALSE);
934
935         r->time_generator = FALSE;
936         for (ii = 0; ii < argc && !r->time_generator; ii++) {
937                 r->time_generator = argv[ii]->time_generator;
938         }
939
940         if (r->time_generator) {
941                 r->occuring_start = argv[0]->occuring_start;
942                 r->occuring_end = argv[0]->occuring_end;
943
944                 for (ii = 1; ii < argc; ii++) {
945                         r->occuring_start = MAX (r->occuring_start, argv[ii]->occuring_start);
946                         r->occuring_end = MIN (r->occuring_end, argv[ii]->occuring_end);
947                 }
948         }
949
950         return TRUE;
951 }
952
953 static const struct {
954         const gchar *name;
955         ESOperatorFunc *func;
956 } operators[] = {
957         {"or", or_operator},
958         {"and", and_operator}
959 };
960
961 const gint operators_count = sizeof (operators) / sizeof (operators[0]);
962
963 static ESOperatorFunc*
964 get_operator_function (const gchar *fname)
965 {
966         gint i;
967
968         g_return_val_if_fail (fname != NULL, NULL);
969
970         for (i = 0; i < sizeof (operators) / sizeof (operators[0]); i++)
971                 if (strcmp (operators[i].name, fname) == 0)
972                         return operators[i].func;
973
974         return NULL;
975 }
976
977 static inline gboolean
978 is_time_function (const gchar *fname)
979 {
980         gint i;
981
982         g_return_val_if_fail (fname != NULL, FALSE);
983
984         for (i = 0; i < sizeof (time_functions) / sizeof (time_functions[0]); i++)
985                 if (strcmp (time_functions[i], fname) == 0)
986                         return TRUE;
987
988         return FALSE;
989 }
990
991 static ESGeneratorFunc*
992 get_generator_function (const gchar *fname)
993 {
994         gint i;
995
996         g_return_val_if_fail (fname != NULL, NULL);
997
998         for (i = 0; i < sizeof (generators) / sizeof (generators[0]); i++)
999                 if (strcmp (generators[i].name, fname) == 0)
1000                         return generators[i].func;
1001
1002         return NULL;
1003 }
1004
1005 /* this must only be called from inside term evaluation callbacks! */
1006 static struct _ESExpResult *
1007 e_sexp_term_evaluate_occur_times (struct _ESExp *f, struct _ESExpTerm *t, time_t *start, time_t *end)
1008 {
1009         struct _ESExpResult *r = NULL;
1010         gint i, argc;
1011         struct _ESExpResult **argv;
1012         gboolean ok = TRUE;
1013
1014         g_return_val_if_fail (t != NULL, NULL);
1015         g_return_val_if_fail (start != NULL, NULL);
1016         g_return_val_if_fail (end != NULL, NULL);
1017
1018         /*
1019         printf("eval term :\n");
1020         parse_dump_term (t, 0);
1021         */
1022
1023         switch (t->type) {
1024         case ESEXP_TERM_STRING:
1025                 r(printf(" (string \"%s\")\n", t->value.string));
1026                 r = e_sexp_result_new (f, ESEXP_RES_STRING);
1027                 r->value.string = g_strdup (t->value.string);
1028                 break;
1029         case ESEXP_TERM_IFUNC:
1030         case ESEXP_TERM_FUNC:
1031         {
1032                 ESGeneratorFunc *generator = NULL;
1033                 ESOperatorFunc *operator = NULL;
1034
1035                 r(printf(" (function \"%s\"\n", t->value.func.sym->name));
1036
1037                 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
1038                 argc = t->value.func.termcount;
1039                 argv = alloca (sizeof (argv[0]) * argc);
1040
1041                 for (i=0;i<t->value.func.termcount;i++) {
1042                         argv[i] = e_sexp_term_evaluate_occur_times (f, t->value.func.terms[i],
1043                                                                     start, end);
1044                 }
1045
1046                 if (is_time_function (t->value.func.sym->name)) {
1047                         /* evaluate time */
1048                         if (t->value.func.sym->f.func)
1049                                 r = t->value.func.sym->f.func (f, t->value.func.termcount,
1050                                               argv, t->value.func.sym->data);
1051                 } else if ((generator = get_generator_function (t->value.func.sym->name)) != NULL) {
1052                         /* evaluate generator function */
1053                         r->time_generator = TRUE;
1054                         ok = generator (argc, argv, r);
1055                 } else if ((operator = get_operator_function (t->value.func.sym->name)) != NULL)
1056                         /* evaluate operator function */
1057                         ok = operator (argc, argv, r);
1058                 else {
1059                         /* normal function: we need to scan all objects */
1060                         r->time_generator = FALSE;
1061                 }
1062
1063                 e_sexp_resultv_free (f, t->value.func.termcount, argv);
1064                 break;
1065         }
1066         case ESEXP_TERM_INT:
1067         case ESEXP_TERM_BOOL:
1068         case ESEXP_TERM_TIME:
1069                 break;
1070         default:
1071                 ok = FALSE;
1072                 break;
1073         }
1074
1075         if (!ok)
1076                 e_sexp_fatal_error(f, "Error in parse tree");
1077
1078         if (r==NULL)
1079                 r = e_sexp_result_new (f, ESEXP_RES_UNDEFINED);
1080
1081         return r;
1082 }
1083
1084 /*
1085   PARSER
1086 */
1087
1088 static struct _ESExpTerm *
1089 parse_term_new (struct _ESExp *f, gint type)
1090 {
1091         struct _ESExpTerm *s = e_memchunk_alloc0 (f->term_chunks);
1092         s->type = type;
1093         return s;
1094 }
1095
1096 static void
1097 parse_term_free (struct _ESExp *f, struct _ESExpTerm *t)
1098 {
1099         gint i;
1100
1101         if (t==NULL) {
1102                 return;
1103         }
1104
1105         switch (t->type) {
1106         case ESEXP_TERM_INT:
1107         case ESEXP_TERM_BOOL:
1108         case ESEXP_TERM_TIME:
1109         case ESEXP_TERM_VAR:
1110                 break;
1111
1112         case ESEXP_TERM_STRING:
1113                 g_free (t->value.string);
1114                 break;
1115
1116         case ESEXP_TERM_FUNC:
1117         case ESEXP_TERM_IFUNC:
1118                 for (i=0;i<t->value.func.termcount;i++) {
1119                         parse_term_free (f, t->value.func.terms[i]);
1120                 }
1121                 g_free (t->value.func.terms);
1122                 break;
1123
1124         default:
1125                 printf("parse_term_free: unknown type: %d\n", t->type);
1126         }
1127         e_memchunk_free (f->term_chunks, t);
1128 }
1129
1130 static struct _ESExpTerm **
1131 parse_values (ESExp *f, gint *len)
1132 {
1133         gint token;
1134         struct _ESExpTerm **terms;
1135         gint i, size = 0;
1136         GScanner *gs = f->scanner;
1137         GSList *list = NULL, *l;
1138
1139         p(printf("parsing values\n"));
1140
1141         while ( (token = g_scanner_peek_next_token (gs)) != G_TOKEN_EOF
1142                 && token != ')') {
1143                 list = g_slist_prepend (list, parse_value (f));
1144                 size++;
1145         }
1146
1147         /* go over the list, and put them backwards into the term array */
1148         terms = g_malloc (size * sizeof (*terms));
1149         l = list;
1150         for (i=size-1;i>=0;i--) {
1151                 g_assert (l);
1152                 g_assert (l->data);
1153                 terms[i] = l->data;
1154                 l = g_slist_next (l);
1155         }
1156         g_slist_free (list);
1157
1158         p(printf("found %d subterms\n", size));
1159         *len = size;
1160
1161         p(printf("done parsing values\n"));
1162         return terms;
1163 }
1164
1165 /**
1166  * e_sexp_parse_value:
1167  *
1168  * Since: 2.28
1169  **/
1170 ESExpTerm *
1171 e_sexp_parse_value (ESExp *f)
1172 {
1173         return parse_value (f);
1174 }
1175
1176 static struct _ESExpTerm *
1177 parse_value (ESExp *f)
1178 {
1179         gint token, negative = FALSE;
1180         struct _ESExpTerm *t = NULL;
1181         GScanner *gs = f->scanner;
1182         struct _ESExpSymbol *s;
1183
1184         p(printf("parsing value\n"));
1185
1186         token = g_scanner_get_next_token (gs);
1187         switch (token) {
1188         case G_TOKEN_EOF:
1189                 break;
1190         case G_TOKEN_LEFT_PAREN:
1191                 p(printf("got brace, its a list!\n"));
1192                 return parse_list (f, TRUE);
1193         case G_TOKEN_STRING:
1194                 p(printf("got string '%s'\n", g_scanner_cur_value(gs).v_string));
1195                 t = parse_term_new (f, ESEXP_TERM_STRING);
1196                 t->value.string = g_strdup (g_scanner_cur_value (gs).v_string);
1197                 break;
1198         case '-':
1199                 p(printf ("got negative int?\n"));
1200                 token = g_scanner_get_next_token (gs);
1201                 if (token != G_TOKEN_INT) {
1202                         e_sexp_fatal_error (f, "Invalid format for a integer value");
1203                         return NULL;
1204                 }
1205
1206                 negative = TRUE;
1207                 /* fall through... */
1208         case G_TOKEN_INT:
1209                 t = parse_term_new (f, ESEXP_TERM_INT);
1210                 t->value.number = g_scanner_cur_value (gs).v_int;
1211                 if (negative)
1212                         t->value.number = -t->value.number;
1213                 p(printf("got gint %d\n", t->value.number));
1214                 break;
1215         case '#': {
1216                 gchar *str;
1217
1218                 p(printf("got bool?\n"));
1219                 token = g_scanner_get_next_token (gs);
1220                 if (token != G_TOKEN_IDENTIFIER) {
1221                         e_sexp_fatal_error (f, "Invalid format for a boolean value");
1222                         return NULL;
1223                 }
1224
1225                 str = g_scanner_cur_value (gs).v_identifier;
1226
1227                 g_assert (str != NULL);
1228                 if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
1229                         e_sexp_fatal_error (f, "Invalid format for a boolean value");
1230                         return NULL;
1231                 }
1232
1233                 t = parse_term_new (f, ESEXP_TERM_BOOL);
1234                 t->value.boolean = (str[0] == 't');
1235                 break; }
1236         case G_TOKEN_SYMBOL:
1237                 s = g_scanner_cur_value (gs).v_symbol;
1238                 p(printf("got symbol '%s'\n", s->name));
1239                 switch (s->type) {
1240                 case ESEXP_TERM_FUNC:
1241                 case ESEXP_TERM_IFUNC:
1242                                 /* this is basically invalid, since we can't use function
1243                                    pointers, but let the runtime catch it ... */
1244                         t = parse_term_new (f, s->type);
1245                         t->value.func.sym = s;
1246                         t->value.func.terms = parse_values (f, &t->value.func.termcount);
1247                         break;
1248                 case ESEXP_TERM_VAR:
1249                         t = parse_term_new (f, s->type);
1250                         t->value.var = s;
1251                         break;
1252                 default:
1253                         e_sexp_fatal_error(f, "Invalid symbol type: %s: %d", s->name, s->type);
1254                 }
1255                 break;
1256         case G_TOKEN_IDENTIFIER:
1257                 p(printf("got unknown identifider '%s'\n", g_scanner_cur_value(gs).v_identifier));
1258                 e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1259                 break;
1260         default:
1261                 e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1262         }
1263         p(printf("done parsing value\n"));
1264         return t;
1265 }
1266
1267 /* FIXME: this needs some robustification */
1268 static struct _ESExpTerm *
1269 parse_list (ESExp *f, gint gotbrace)
1270 {
1271         gint token;
1272         struct _ESExpTerm *t = NULL;
1273         GScanner *gs = f->scanner;
1274
1275         p(printf("parsing list\n"));
1276         if (gotbrace)
1277                 token = '(';
1278         else
1279                 token = g_scanner_get_next_token (gs);
1280         if (token =='(') {
1281                 token = g_scanner_get_next_token (gs);
1282                 switch (token) {
1283                 case G_TOKEN_SYMBOL: {
1284                         struct _ESExpSymbol *s;
1285
1286                         s = g_scanner_cur_value (gs).v_symbol;
1287                         p(printf("got funciton: %s\n", s->name));
1288                         t = parse_term_new (f, s->type);
1289                         p(printf("created new list %p\n", t));
1290                         /* if we have a variable, find out its base type */
1291                         while (s->type == ESEXP_TERM_VAR) {
1292                                 s = ((ESExpTerm *)(s->data))->value.var;
1293                         }
1294                         if (s->type == ESEXP_TERM_FUNC
1295                             || s->type == ESEXP_TERM_IFUNC) {
1296                                 t->value.func.sym = s;
1297                                 t->value.func.terms = parse_values (f, &t->value.func.termcount);
1298                         } else {
1299                                 parse_term_free (f, t);
1300                                 e_sexp_fatal_error(f, "Trying to call variable as function: %s", s->name);
1301                         }
1302                         break; }
1303                 case G_TOKEN_IDENTIFIER:
1304                         e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1305                         break;
1306                 case G_TOKEN_LEFT_PAREN:
1307                         return parse_list (f, TRUE);
1308                 default:
1309                         e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1310                 }
1311                 token = g_scanner_get_next_token (gs);
1312                 if (token != ')') {
1313                         e_sexp_fatal_error(f, "Missing ')'");
1314                 }
1315         } else {
1316                 e_sexp_fatal_error(f, "Missing '('");
1317         }
1318
1319         p(printf("returning list %p\n", t));
1320         return t;
1321 }
1322
1323 static void e_sexp_finalise (gpointer);
1324
1325 #ifdef E_SEXP_IS_G_OBJECT
1326 static void
1327 e_sexp_class_init (ESExpClass *klass)
1328 {
1329         GObjectClass *object_class = G_OBJECT_CLASS (klass);
1330
1331         object_class->finalize = e_sexp_finalise;
1332
1333         parent_class = g_type_class_ref (g_object_get_type ());
1334 }
1335 #endif
1336
1337 /* 'builtin' functions */
1338 static const struct {
1339         const gchar *name;
1340         ESExpFunc *func;
1341         gint type;              /* set to 1 if a function can perform shortcut evaluation, or
1342                                    doesn't execute everything, 0 otherwise */
1343 } symbols[] = {
1344         { "and", (ESExpFunc *)term_eval_and, 1 },
1345         { "or", (ESExpFunc *)term_eval_or, 1 },
1346         { "not", (ESExpFunc *)term_eval_not, 0 },
1347         { "<", (ESExpFunc *)term_eval_lt, 1 },
1348         { ">", (ESExpFunc *)term_eval_gt, 1 },
1349         { "=", (ESExpFunc *)term_eval_eq, 1 },
1350         { "+", (ESExpFunc *)term_eval_plus, 0 },
1351         { "-", (ESExpFunc *)term_eval_sub, 0 },
1352         { "cast-int", (ESExpFunc *)term_eval_castint, 0 },
1353         { "cast-string", (ESExpFunc *)term_eval_caststring, 0 },
1354         { "if", (ESExpFunc *)term_eval_if, 1 },
1355         { "begin", (ESExpFunc *)term_eval_begin, 1 },
1356 };
1357
1358 static void
1359 free_symbol (gpointer key, gpointer value, gpointer data)
1360 {
1361         struct _ESExpSymbol *s = value;
1362
1363         g_free (s->name);
1364         g_free (s);
1365 }
1366
1367 static void
1368 e_sexp_finalise (gpointer o)
1369 {
1370         ESExp *s = (ESExp *) o;
1371
1372         if (s->tree) {
1373                 parse_term_free (s, s->tree);
1374                 s->tree = NULL;
1375         }
1376
1377         e_memchunk_destroy (s->term_chunks);
1378         e_memchunk_destroy (s->result_chunks);
1379
1380         g_scanner_scope_foreach_symbol (s->scanner, 0, free_symbol, NULL);
1381         g_scanner_destroy (s->scanner);
1382
1383 #ifdef E_SEXP_IS_G_OBJECT
1384         G_OBJECT_CLASS (parent_class)->finalize (o);
1385 #endif
1386 }
1387
1388 static void
1389 e_sexp_init (ESExp *s)
1390 {
1391         gint i;
1392
1393         s->scanner = g_scanner_new (&scanner_config);
1394         s->term_chunks = e_memchunk_new (16, sizeof (struct _ESExpTerm));
1395         s->result_chunks = e_memchunk_new (16, sizeof (struct _ESExpResult));
1396
1397         /* load in builtin symbols? */
1398         for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
1399                 if (symbols[i].type == 1) {
1400                         e_sexp_add_ifunction (s, 0, symbols[i].name, (ESExpIFunc *) symbols[i].func, (gpointer)&symbols[i]);
1401                 } else {
1402                         e_sexp_add_function (s, 0, symbols[i].name, symbols[i].func, (gpointer)&symbols[i]);
1403                 }
1404         }
1405
1406 #ifndef E_SEXP_IS_G_OBJECT
1407         s->refcount = 1;
1408 #endif
1409 }
1410
1411 ESExp *
1412 e_sexp_new (void)
1413 {
1414 #ifdef E_SEXP_IS_G_OBJECT
1415         ESExp *f = (ESexp *) g_object_new (E_TYPE_SEXP, NULL);
1416 #else
1417         ESExp *f = g_malloc0 (sizeof (ESExp));
1418         e_sexp_init (f);
1419 #endif
1420
1421         return f;
1422 }
1423
1424 #ifndef E_SEXP_IS_G_OBJECT
1425 void
1426 e_sexp_ref (ESExp *f)
1427 {
1428         f->refcount++;
1429 }
1430
1431 void
1432 e_sexp_unref (ESExp *f)
1433 {
1434         f->refcount--;
1435         if (f->refcount == 0) {
1436                 e_sexp_finalise (f);
1437                 g_free (f);
1438         }
1439 }
1440 #endif
1441
1442 void
1443 e_sexp_add_function (ESExp *f, gint scope, const gchar *name, ESExpFunc *func, gpointer data)
1444 {
1445         struct _ESExpSymbol *s;
1446
1447         g_return_if_fail (IS_E_SEXP (f));
1448         g_return_if_fail (name != NULL);
1449
1450         e_sexp_remove_symbol (f, scope, name);
1451
1452         s = g_malloc0 (sizeof (*s));
1453         s->name = g_strdup (name);
1454         s->f.func = func;
1455         s->type = ESEXP_TERM_FUNC;
1456         s->data = data;
1457         g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1458 }
1459
1460 void
1461 e_sexp_add_ifunction (ESExp *f, gint scope, const gchar *name, ESExpIFunc *ifunc, gpointer data)
1462 {
1463         struct _ESExpSymbol *s;
1464
1465         g_return_if_fail (IS_E_SEXP (f));
1466         g_return_if_fail (name != NULL);
1467
1468         e_sexp_remove_symbol (f, scope, name);
1469
1470         s = g_malloc0 (sizeof (*s));
1471         s->name = g_strdup (name);
1472         s->f.ifunc = ifunc;
1473         s->type = ESEXP_TERM_IFUNC;
1474         s->data = data;
1475         g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1476 }
1477
1478 void
1479 e_sexp_add_variable (ESExp *f, gint scope, gchar *name, ESExpTerm *value)
1480 {
1481         struct _ESExpSymbol *s;
1482
1483         g_return_if_fail (IS_E_SEXP (f));
1484         g_return_if_fail (name != NULL);
1485
1486         s = g_malloc0 (sizeof (*s));
1487         s->name = g_strdup (name);
1488         s->type = ESEXP_TERM_VAR;
1489         s->data = value;
1490         g_scanner_scope_add_symbol (f->scanner, scope, s->name, s);
1491 }
1492
1493 void
1494 e_sexp_remove_symbol (ESExp *f, gint scope, const gchar *name)
1495 {
1496         gint oldscope;
1497         struct _ESExpSymbol *s;
1498
1499         g_return_if_fail (IS_E_SEXP (f));
1500         g_return_if_fail (name != NULL);
1501
1502         oldscope = g_scanner_set_scope (f->scanner, scope);
1503         s = g_scanner_lookup_symbol (f->scanner, name);
1504         g_scanner_scope_remove_symbol (f->scanner, scope, name);
1505         g_scanner_set_scope (f->scanner, oldscope);
1506         if (s) {
1507                 g_free (s->name);
1508                 g_free (s);
1509         }
1510 }
1511
1512 gint
1513 e_sexp_set_scope (ESExp *f, gint scope)
1514 {
1515         g_return_val_if_fail (IS_E_SEXP (f), 0);
1516
1517         return g_scanner_set_scope (f->scanner, scope);
1518 }
1519
1520 void
1521 e_sexp_input_text (ESExp *f, const gchar *text, gint len)
1522 {
1523         g_return_if_fail (IS_E_SEXP (f));
1524         g_return_if_fail (text != NULL);
1525
1526         g_scanner_input_text (f->scanner, text, len);
1527 }
1528
1529 void
1530 e_sexp_input_file (ESExp *f, gint fd)
1531 {
1532         g_return_if_fail (IS_E_SEXP (f));
1533
1534         g_scanner_input_file (f->scanner, fd);
1535 }
1536
1537 /* returns -1 on error */
1538 gint
1539 e_sexp_parse (ESExp *f)
1540 {
1541         g_return_val_if_fail (IS_E_SEXP (f), -1);
1542
1543         if (setjmp (f->failenv)) {
1544                 g_warning("Error in parsing: %s", f->error);
1545                 return -1;
1546         }
1547
1548         if (f->tree)
1549                 parse_term_free (f, f->tree);
1550
1551         f->tree = parse_value (f);
1552
1553         return 0;
1554 }
1555
1556 /* returns NULL on error */
1557 struct _ESExpResult *
1558 e_sexp_eval (ESExp *f)
1559 {
1560         g_return_val_if_fail (IS_E_SEXP (f), NULL);
1561         g_return_val_if_fail (f->tree != NULL, NULL);
1562
1563         if (setjmp (f->failenv)) {
1564                 g_warning("Error in execution: %s", f->error);
1565                 return NULL;
1566         }
1567
1568         return e_sexp_term_eval (f, f->tree);
1569 }
1570
1571 /**
1572  * e_cal_backend_sexp_evaluate_occur_times:
1573  * @f: An #ESExp object.
1574  * @start: Start of the time window will be stored here.
1575  * @end: End of the time window will be stored here.
1576  *
1577  * Determines biggest time window given by expressions "occur-in-range" in sexp.
1578  *
1579  * Since: 2.32
1580  */
1581 gboolean
1582 e_sexp_evaluate_occur_times (ESExp *f, time_t *start, time_t *end)
1583 {
1584         struct _ESExpResult *r;
1585         gboolean generator;
1586         g_return_val_if_fail (IS_E_SEXP (f), FALSE);
1587         g_return_val_if_fail (f->tree != NULL, FALSE);
1588         g_return_val_if_fail (start != NULL, FALSE);
1589         g_return_val_if_fail (end != NULL, FALSE);
1590
1591         *start = *end = -1;
1592
1593         if (setjmp (f->failenv)) {
1594                 g_warning("Error in execution: %s", f->error);
1595                 return FALSE;
1596         }
1597
1598         r = e_sexp_term_evaluate_occur_times (f, f->tree, start, end);
1599         generator = r->time_generator;
1600
1601         if (generator) {
1602                 *start = r->occuring_start;
1603                 *end = r->occuring_end;
1604         }
1605
1606         e_sexp_result_free (f, r);
1607
1608         return generator;
1609 }
1610
1611 /**
1612  * e_sexp_encode_bool:
1613  * @s:
1614  * @state:
1615  *
1616  * Encode a bool into an s-expression @s.  Bools are
1617  * encoded using #t #f syntax.
1618  **/
1619 void
1620 e_sexp_encode_bool (GString *s, gboolean state)
1621 {
1622         if (state)
1623                 g_string_append(s, " #t");
1624         else
1625                 g_string_append(s, " #f");
1626 }
1627
1628 /**
1629  * e_sexp_encode_string:
1630  * @s: Destination string.
1631  * @string: String expression.
1632  *
1633  * Add a c string @string to the s-expression stored in
1634  * the gstring @s.  Quotes are added, and special characters
1635  * are escaped appropriately.
1636  **/
1637 void
1638 e_sexp_encode_string (GString *s, const gchar *string)
1639 {
1640         gchar c;
1641         const gchar *p;
1642
1643         if (string == NULL)
1644                 p = "";
1645         else
1646                 p = string;
1647         g_string_append(s, " \"");
1648         while ((c = *p++)) {
1649                 if (c=='\\' || c=='\"' || c=='\'')
1650                         g_string_append_c (s, '\\');
1651                 g_string_append_c (s, c);
1652         }
1653         g_string_append(s, "\"");
1654 }
1655
1656 #ifdef TESTER
1657 gint main (gint argc, gchar **argv)
1658 {
1659         ESExp *f;
1660         gchar *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1661         ESExpResult *r;
1662
1663         g_type_init ();
1664
1665         f = e_sexp_new ();
1666
1667         e_sexp_add_variable(f, 0, "test", NULL);
1668
1669         if (argc < 2 || !argv[1])
1670                 return;
1671
1672         e_sexp_input_text (f, t, t);
1673         e_sexp_parse (f);
1674
1675         if (f->tree) {
1676                 parse_dump_term (f->tree, 0);
1677         }
1678
1679         r = e_sexp_eval (f);
1680         if (r) {
1681                 eval_dump_result (r, 0);
1682         } else {
1683                 printf("no result?|\n");
1684         }
1685
1686         return 0;
1687 }
1688 #endif