Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / libedataserver / e-sexp.c
1 /* 
2  * Copyright 2000 Ximian (www.ximian.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   int = (+ int*)
40         Add integers.
41
42   string = (+ string*)
43         Concat strings.
44
45   time_t = (+ time_t*)
46         Add time_t values.
47
48   int = (- int int*)
49         Subtract integers from the first.
50
51   time_t = (- time_t*)
52         Subtract time_t values from the first.
53
54   int = (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 = (< int int)
63   bool = (> int int)
64   bool = (= int int)
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
86 #ifdef HAVE_CONFIG_H
87 #include <config.h>
88 #endif
89
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <time.h>
93 #include <string.h>
94
95 #include "e-sexp.h"
96 #include "e-memory.h"
97
98 #define p(x)                    /* parse debug */
99 #define r(x)                    /* run debug */
100 #define d(x)                    /* general debug */
101
102
103 static struct _ESExpTerm * parse_list(ESExp *f, int gotbrace);
104 static struct _ESExpTerm * parse_value(ESExp *f);
105
106 static void parse_dump_term(struct _ESExpTerm *t, int depth);
107
108 #ifdef E_SEXP_IS_G_OBJECT
109 static GObjectClass *parent_class;
110 #endif
111
112 static const GScannerConfig scanner_config =
113 {
114         ( " \t\r\n")            /* cset_skip_characters */,
115         ( G_CSET_a_2_z
116           "_+-<=>?"
117           G_CSET_A_2_Z)         /* cset_identifier_first */,
118         ( G_CSET_a_2_z
119           "_0123456789-<>?"
120           G_CSET_A_2_Z
121           G_CSET_LATINS
122           G_CSET_LATINC )       /* cset_identifier_nth */,
123         ( ";\n" )               /* cpair_comment_single */,
124   
125         FALSE                   /* case_sensitive */,
126   
127         TRUE                    /* skip_comment_multi */,
128         TRUE                    /* skip_comment_single */,
129         TRUE                    /* scan_comment_multi */,
130         TRUE                    /* scan_identifier */,
131         TRUE                    /* scan_identifier_1char */,
132         FALSE                   /* scan_identifier_NULL */,
133         TRUE                    /* scan_symbols */,
134         FALSE                   /* scan_binary */,
135         TRUE                    /* scan_octal */,
136         TRUE                    /* scan_float */,
137         TRUE                    /* scan_hex */,
138         FALSE                   /* scan_hex_dollar */,
139         TRUE                    /* scan_string_sq */,
140         TRUE                    /* scan_string_dq */,
141         TRUE                    /* numbers_2_int */,
142         FALSE                   /* int_2_float */,
143         FALSE                   /* identifier_2_string */,
144         TRUE                    /* char_2_token */,
145         FALSE                   /* symbol_2_token */,
146         FALSE                   /* scope_0_fallback */,
147 };
148
149 /* jumps back to the caller of f->failenv, only to be called from inside a callback */
150 void
151 e_sexp_fatal_error(struct _ESExp *f, char *why, ...)
152 {
153         va_list args;
154
155         if (f->error)
156                 g_free(f->error);
157         
158         va_start(args, why);
159         f->error = g_strdup_vprintf(why, args);
160         va_end(args);
161
162         longjmp(f->failenv, 1);
163 }
164
165 const char *
166 e_sexp_error(struct _ESExp *f)
167 {
168         return f->error;
169 }
170
171 struct _ESExpResult *
172 e_sexp_result_new(struct _ESExp *f, int type)
173 {
174         struct _ESExpResult *r = e_memchunk_alloc0(f->result_chunks);
175         r->type = type;
176         return r;
177 }
178
179 void
180 e_sexp_result_free(struct _ESExp *f, struct _ESExpResult *t)
181 {
182         if (t == NULL)
183                 return;
184
185         switch(t->type) {
186         case ESEXP_RES_ARRAY_PTR:
187                 g_ptr_array_free(t->value.ptrarray, TRUE);
188                 break;
189         case ESEXP_RES_BOOL:
190         case ESEXP_RES_INT:
191         case ESEXP_RES_TIME:
192                 break;
193         case ESEXP_RES_STRING:
194                 g_free(t->value.string);
195                 break;
196         case ESEXP_RES_UNDEFINED:
197                 break;
198         default:
199                 g_assert_not_reached();
200         }
201         e_memchunk_free(f->result_chunks, t);
202 }
203
204 /* used in normal functions if they have to abort, and free their arguments */
205 void
206 e_sexp_resultv_free(struct _ESExp *f, int argc, struct _ESExpResult **argv)
207 {
208         int i;
209
210         for (i=0;i<argc;i++) {
211                 e_sexp_result_free(f, argv[i]);
212         }
213 }
214
215 /* implementations for the builtin functions */
216
217 /* can you tell, i dont like glib? */
218 /* we can only itereate a hashtable from a called function */
219 struct _glib_sux_donkeys {
220         int count;
221         GPtrArray *uids;
222 };
223
224 /* ok, store any values that are in all sets */
225 static void
226 g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup)
227 {
228         if (value == fuckup->count) {
229                 g_ptr_array_add(fuckup->uids, key);
230         }
231 }
232
233 /* or, store all unique values */
234 static void
235 g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
236 {
237         g_ptr_array_add(fuckup->uids, key);
238 }
239
240 static ESExpResult *
241 term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
242 {
243         struct _ESExpResult *r, *r1;
244         GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
245         struct _glib_sux_donkeys lambdafoo;
246         int type=-1;
247         int bool = TRUE;
248         int i;
249         
250         r(printf("( and\n"));
251
252         r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
253         
254         for (i=0;bool && i<argc;i++) {
255                 r1 = e_sexp_term_eval(f, argv[i]);
256                 if (type == -1)
257                         type = r1->type;
258                 if (type != r1->type) {
259                         e_sexp_result_free(f, r);
260                         e_sexp_result_free(f, r1);
261                         g_hash_table_destroy(ht);
262                         e_sexp_fatal_error(f, "Invalid types in AND");
263                 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
264                         char **a1;
265                         int l1, j;
266                         
267                         a1 = (char **)r1->value.ptrarray->pdata;
268                         l1 = r1->value.ptrarray->len;
269                         for (j=0;j<l1;j++) {
270                                 gpointer ptr;
271                                 int n;
272                                 ptr = g_hash_table_lookup(ht, a1[j]);
273                                 n = GPOINTER_TO_INT(ptr);
274                                 g_hash_table_insert(ht, a1[j], GINT_TO_POINTER(n+1));
275                         }
276                 } else if (r1->type == ESEXP_RES_BOOL) {
277                         bool = bool && r1->value.bool;
278                 }
279                 e_sexp_result_free(f, r1);
280         }
281         
282         if (type == ESEXP_RES_ARRAY_PTR) {
283                 lambdafoo.count = argc;
284                 lambdafoo.uids = g_ptr_array_new();
285                 g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo);
286                 r->type = ESEXP_RES_ARRAY_PTR;
287                 r->value.ptrarray = lambdafoo.uids;
288         } else if (type == ESEXP_RES_BOOL) {
289                 r->type = ESEXP_RES_BOOL;
290                 r->value.bool = bool;
291         }
292         
293         g_hash_table_destroy(ht);
294         
295         return r;
296 }
297
298 static ESExpResult *
299 term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
300 {
301         struct _ESExpResult *r, *r1;
302         GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
303         struct _glib_sux_donkeys lambdafoo;
304         int type = -1;
305         int bool = FALSE;
306         int i;
307         
308         r(printf("(or \n"));
309
310         r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
311         
312         for (i=0;!bool && i<argc;i++) {
313                 r1 = e_sexp_term_eval(f, argv[i]);
314                 if (type == -1)
315                         type = r1->type;
316                 if (r1->type != type) {
317                         e_sexp_result_free(f, r);
318                         e_sexp_result_free(f, r1);
319                         g_hash_table_destroy(ht);
320                         e_sexp_fatal_error(f, "Invalid types in OR");
321                 } else if (r1->type == ESEXP_RES_ARRAY_PTR) {
322                         char **a1;
323                         int l1, j;
324                         
325                         a1 = (char **)r1->value.ptrarray->pdata;
326                         l1 = r1->value.ptrarray->len;
327                         for (j=0;j<l1;j++) {
328                                 g_hash_table_insert(ht, a1[j], (void *)1);
329                         }
330                 } else if (r1->type == ESEXP_RES_BOOL) {
331                         bool |= r1->value.bool;                         
332                 }
333                 e_sexp_result_free(f, r1);
334         }
335         
336         if (type == ESEXP_RES_ARRAY_PTR) {
337                 lambdafoo.count = argc;
338                 lambdafoo.uids = g_ptr_array_new();
339                 g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
340                 r->type = ESEXP_RES_ARRAY_PTR;
341                 r->value.ptrarray = lambdafoo.uids;
342         } else if (type == ESEXP_RES_BOOL) {
343                 r->type = ESEXP_RES_BOOL;
344                 r->value.bool = bool;
345         }
346         g_hash_table_destroy(ht);
347         
348         return r;
349 }
350
351 static ESExpResult *
352 term_eval_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
353 {
354         int res = TRUE;
355         ESExpResult *r;
356
357         if (argc>0) {
358                 if (argv[0]->type == ESEXP_RES_BOOL
359                     && argv[0]->value.bool)
360                         res = FALSE;
361         }
362         r = e_sexp_result_new(f, ESEXP_RES_BOOL);
363         r->value.bool = res;
364         return r;
365 }
366
367 /* this should support all arguments ...? */
368 static ESExpResult *
369 term_eval_lt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
370 {
371         struct _ESExpResult *r, *r1, *r2;
372
373         r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
374         
375         if (argc == 2) {
376                 r1 = e_sexp_term_eval(f, argv[0]);
377                 r2 = e_sexp_term_eval(f, argv[1]);
378                 if (r1->type != r2->type) {
379                         e_sexp_result_free(f, r1);
380                         e_sexp_result_free(f, r2);
381                         e_sexp_result_free(f, r);
382                         e_sexp_fatal_error(f, "Incompatible types in compare <");
383                 } else if (r1->type == ESEXP_RES_INT) {
384                         r->type = ESEXP_RES_BOOL;
385                         r->value.bool = r1->value.number < r2->value.number;
386                 } else if (r1->type == ESEXP_RES_TIME) {
387                         r->type = ESEXP_RES_BOOL;
388                         r->value.bool = r1->value.time < r2->value.time;
389                 } else if (r1->type == ESEXP_RES_STRING) {
390                         r->type = ESEXP_RES_BOOL;
391                         r->value.bool = strcmp(r1->value.string, r2->value.string) < 0;
392                 }
393                 e_sexp_result_free(f, r1);
394                 e_sexp_result_free(f, r2);
395         }
396         return r;
397 }
398
399 /* this should support all arguments ...? */
400 static ESExpResult *
401 term_eval_gt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
402 {
403         struct _ESExpResult *r, *r1, *r2;
404
405         r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
406         
407         if (argc == 2) {
408                 r1 = e_sexp_term_eval(f, argv[0]);
409                 r2 = e_sexp_term_eval(f, argv[1]);
410                 if (r1->type != r2->type) {
411                         e_sexp_result_free(f, r1);
412                         e_sexp_result_free(f, r2);
413                         e_sexp_result_free(f, r);
414                         e_sexp_fatal_error(f, "Incompatible types in compare >");
415                 } else if (r1->type == ESEXP_RES_INT) {
416                         r->type = ESEXP_RES_BOOL;
417                         r->value.bool = r1->value.number > r2->value.number;
418                 } else if (r1->type == ESEXP_RES_TIME) {
419                         r->type = ESEXP_RES_BOOL;
420                         r->value.bool = r1->value.time > r2->value.time;
421                 } else if (r1->type == ESEXP_RES_STRING) {
422                         r->type = ESEXP_RES_BOOL;
423                         r->value.bool = strcmp(r1->value.string, r2->value.string) > 0;
424                 }
425                 e_sexp_result_free(f, r1);
426                 e_sexp_result_free(f, r2);
427         }
428         return r;
429 }
430
431 /* this should support all arguments ...? */
432 static ESExpResult *
433 term_eval_eq(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
434 {
435         struct _ESExpResult *r, *r1, *r2;
436
437         r = e_sexp_result_new(f, ESEXP_RES_BOOL);
438         
439         if (argc == 2) {
440                 r1 = e_sexp_term_eval(f, argv[0]);
441                 r2 = e_sexp_term_eval(f, argv[1]);
442                 if (r1->type != r2->type) {
443                         r->value.bool = FALSE;
444                 } else if (r1->type == ESEXP_RES_INT) {
445                         r->value.bool = r1->value.number == r2->value.number;
446                 } else if (r1->type == ESEXP_RES_BOOL) {
447                         r->value.bool = r1->value.bool == r2->value.bool;
448                 } else if (r1->type == ESEXP_RES_TIME) {
449                         r->value.bool = r1->value.time == r2->value.time;
450                 } else if (r1->type == ESEXP_RES_STRING) {
451                         r->value.bool = strcmp(r1->value.string, r2->value.string) == 0;
452                 }
453                 e_sexp_result_free(f, r1);
454                 e_sexp_result_free(f, r2);
455         }
456         return r;
457 }
458
459 static ESExpResult *
460 term_eval_plus(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
461 {
462         struct _ESExpResult *r=NULL;
463         int type;
464         int i;
465
466         if (argc>0) {
467                 type = argv[0]->type;
468                 switch(type) {
469                 case ESEXP_RES_INT: {
470                         int total = argv[0]->value.number;
471                         for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
472                                 total += argv[i]->value.number;
473                         }
474                         if (i<argc) {
475                                 e_sexp_resultv_free(f, argc, argv);
476                                 e_sexp_fatal_error(f, "Invalid types in (+ ints)");
477                         }
478                         r = e_sexp_result_new(f, ESEXP_RES_INT);
479                         r->value.number = total;
480                         break; }
481                 case ESEXP_RES_STRING: {
482                         GString *s = g_string_new(argv[0]->value.string);
483                         for (i=1;i<argc && argv[i]->type == ESEXP_RES_STRING;i++) {
484                                 g_string_append(s, argv[i]->value.string);
485                         }
486                         if (i<argc) {
487                                 e_sexp_resultv_free(f, argc, argv);
488                                 e_sexp_fatal_error(f, "Invalid types in (+ strings)");
489                         }
490                         r = e_sexp_result_new(f, ESEXP_RES_STRING);
491                         r->value.string = s->str;
492                         g_string_free(s, FALSE);
493                         break; }
494                 case ESEXP_RES_TIME: {
495                         time_t total;
496
497                         total = argv[0]->value.time;
498
499                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
500                                 total += argv[i]->value.time;
501
502                         if (i < argc) {
503                                 e_sexp_resultv_free (f, argc, argv);
504                                 e_sexp_fatal_error (f, "Invalid types in (+ time_t)");
505                         }
506
507                         r = e_sexp_result_new (f, ESEXP_RES_TIME);
508                         r->value.time = total;
509                         break; }
510                 }
511         }
512
513         if (!r) {
514                 r = e_sexp_result_new(f, ESEXP_RES_INT);
515                 r->value.number = 0;
516         }
517         return r;
518 }
519
520 static ESExpResult *
521 term_eval_sub(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
522 {
523         struct _ESExpResult *r=NULL;
524         int type;
525         int i;
526
527         if (argc>0) {
528                 type = argv[0]->type;
529                 switch(type) {
530                 case ESEXP_RES_INT: {
531                         int total = argv[0]->value.number;
532                         for (i=1;i<argc && argv[i]->type == ESEXP_RES_INT;i++) {
533                                 total -= argv[i]->value.number;
534                         }
535                         if (i<argc) {
536                                 e_sexp_resultv_free(f, argc, argv);
537                                 e_sexp_fatal_error(f, "Invalid types in -");
538                         }
539                         r = e_sexp_result_new(f, ESEXP_RES_INT);
540                         r->value.number = total;
541                         break; }
542                 case ESEXP_RES_TIME: {
543                         time_t total;
544
545                         total = argv[0]->value.time;
546
547                         for (i = 1; i < argc && argv[i]->type == ESEXP_RES_TIME; i++)
548                                 total -= argv[i]->value.time;
549
550                         if (i < argc) {
551                                 e_sexp_resultv_free (f, argc, argv);
552                                 e_sexp_fatal_error (f, "Invalid types in (- time_t)");
553                         }
554
555                         r = e_sexp_result_new (f, ESEXP_RES_TIME);
556                         r->value.time = total;
557                         break; }
558                 }
559         }
560
561         if (!r) {
562                 r = e_sexp_result_new(f, ESEXP_RES_INT);
563                 r->value.number = 0;
564         }
565         return r;
566 }
567
568 /* cast to int */
569 static ESExpResult *
570 term_eval_castint(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
571 {
572         struct _ESExpResult *r;
573
574         if (argc != 1)
575                 e_sexp_fatal_error(f, "Incorrect argument count to (int )");
576
577         r = e_sexp_result_new(f, ESEXP_RES_INT);
578         switch (argv[0]->type) {
579         case ESEXP_RES_INT:
580                 r->value.number = argv[0]->value.number;
581                 break;
582         case ESEXP_RES_BOOL:
583                 r->value.number = argv[0]->value.bool != 0;
584                 break;
585         case ESEXP_RES_STRING:
586                 r->value.number = strtoul(argv[0]->value.string, NULL, 10);
587                 break;
588         default:
589                 e_sexp_result_free(f, r);
590                 e_sexp_fatal_error(f, "Invalid type in (cast-int )");
591         }
592
593         return r;
594 }
595
596 /* cast to string */
597 static ESExpResult *
598 term_eval_caststring(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
599 {
600         struct _ESExpResult *r;
601
602         if (argc != 1)
603                 e_sexp_fatal_error(f, "Incorrect argument count to (cast-string )");
604
605         r = e_sexp_result_new(f, ESEXP_RES_STRING);
606         switch (argv[0]->type) {
607         case ESEXP_RES_INT:
608                 r->value.string = g_strdup_printf("%d", argv[0]->value.number);
609                 break;
610         case ESEXP_RES_BOOL:
611                 r->value.string = g_strdup_printf("%d", argv[0]->value.bool != 0);
612                 break;
613         case ESEXP_RES_STRING:
614                 r->value.string = g_strdup(argv[0]->value.string);
615                 break;
616         default:
617                 e_sexp_result_free(f, r);
618                 e_sexp_fatal_error(f, "Invalid type in (int )");
619         }
620
621         return r;
622 }
623
624 /* implements 'if' function */
625 static ESExpResult *
626 term_eval_if(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
627 {
628         struct _ESExpResult *r;
629         int doit;
630
631         if (argc >=2 && argc<=3) {
632                 r = e_sexp_term_eval(f, argv[0]);
633                 doit = (r->type == ESEXP_RES_BOOL && r->value.bool);
634                 e_sexp_result_free(f, r);
635                 if (doit) {
636                         return e_sexp_term_eval(f, argv[1]);
637                 } else if (argc>2) {
638                         return e_sexp_term_eval(f, argv[2]);
639                 }
640         }
641         return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
642 }
643
644 /* implements 'begin' statement */
645 static ESExpResult *
646 term_eval_begin(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
647 {
648         struct _ESExpResult *r=NULL;
649         int i;
650
651         for (i=0;i<argc;i++) {
652                 if (r)
653                         e_sexp_result_free(f, r);
654                 r = e_sexp_term_eval(f, argv[i]);
655         }
656         if (r)
657                 return r;
658         else
659                 return e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
660 }
661
662
663 /* this must only be called from inside term evaluation callbacks! */
664 struct _ESExpResult *
665 e_sexp_term_eval(struct _ESExp *f, struct _ESExpTerm *t)
666 {
667         struct _ESExpResult *r = NULL;
668         int i;
669         struct _ESExpResult **argv;
670
671         g_return_val_if_fail(t != NULL, NULL);
672
673         r(printf("eval term :\n"));
674         r(parse_dump_term(t, 0));
675
676         switch (t->type) {
677         case ESEXP_TERM_STRING:
678                 r(printf(" (string \"%s\")\n", t->value.string));
679                 r = e_sexp_result_new(f, ESEXP_RES_STRING);
680                 /* erk, this shoul;dn't need to strdup this ... */
681                 r->value.string = g_strdup(t->value.string);
682                 break;
683         case ESEXP_TERM_INT:
684                 r(printf(" (int %d)\n", t->value.number));
685                 r = e_sexp_result_new(f, ESEXP_RES_INT);
686                 r->value.number = t->value.number;
687                 break;
688         case ESEXP_TERM_BOOL:
689                 r(printf(" (int %d)\n", t->value.number));
690                 r = e_sexp_result_new(f, ESEXP_RES_BOOL);
691                 r->value.bool = t->value.bool;
692                 break;
693         case ESEXP_TERM_TIME:
694                 r(printf(" (time_t %d)\n", t->value.time));
695                 r = e_sexp_result_new (f, ESEXP_RES_TIME);
696                 r->value.time = t->value.time;
697                 break;
698         case ESEXP_TERM_IFUNC:
699                 if (t->value.func.sym->f.ifunc)
700                         r = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data);
701                 break;
702         case ESEXP_TERM_FUNC:
703                 /* first evaluate all arguments to result types */
704                 argv = alloca(sizeof(argv[0]) * t->value.func.termcount);
705                 for (i=0;i<t->value.func.termcount;i++) {
706                         argv[i] = e_sexp_term_eval(f, t->value.func.terms[i]);
707                 }
708                 /* call the function */
709                 if (t->value.func.sym->f.func)
710                         r = t->value.func.sym->f.func(f, t->value.func.termcount, argv, t->value.func.sym->data);
711
712                 e_sexp_resultv_free(f, t->value.func.termcount, argv);
713                 break;
714         default:
715                 e_sexp_fatal_error(f, "Unknown type in parse tree: %d", t->type);
716         }
717
718         if (r==NULL)
719                 r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
720
721         return r;
722 }
723
724 #ifdef TESTER
725 static void
726 eval_dump_result(ESExpResult *r, int depth)
727 {
728         int i;
729         
730         if (r==NULL) {
731                 printf("null result???\n");
732                 return;
733         }
734
735         for (i=0;i<depth;i++)
736                 printf("   ");
737
738         switch (r->type) {
739         case ESEXP_RES_ARRAY_PTR:
740                 printf("array pointers\n");
741                 break;
742         case ESEXP_RES_INT:
743                 printf("int: %d\n", r->value.number);
744                 break;
745         case ESEXP_RES_STRING:
746                 printf("string: '%s'\n", r->value.string);
747                 break;
748         case ESEXP_RES_BOOL:
749                 printf("bool: %c\n", r->value.bool?'t':'f');
750                 break;
751         case ESEXP_RES_TIME:
752                 printf("time_t: %ld\n", (long) r->value.time);
753                 break;
754         case ESEXP_RES_UNDEFINED:
755                 printf(" <undefined>\n");
756                 break;
757         }
758         printf("\n");
759 }
760 #endif
761
762 static void
763 parse_dump_term(struct _ESExpTerm *t, int depth)
764 {
765         int i;
766
767         if (t==NULL) {
768                 printf("null term??\n");
769                 return;
770         }
771
772         for (i=0;i<depth;i++)
773                 printf("   ");
774         
775         switch (t->type) {
776         case ESEXP_TERM_STRING:
777                 printf(" \"%s\"", t->value.string);
778                 break;
779         case ESEXP_TERM_INT:
780                 printf(" %d", t->value.number);
781                 break;
782         case ESEXP_TERM_BOOL:
783                 printf(" #%c", t->value.bool?'t':'f');
784                 break;
785         case ESEXP_TERM_TIME:
786                 printf(" %ld", (long) t->value.time);
787                 break;
788         case ESEXP_TERM_IFUNC:
789         case ESEXP_TERM_FUNC:
790                 printf(" (function %s\n", t->value.func.sym->name);
791                 /*printf(" [%d] ", t->value.func.termcount);*/
792                 for (i=0;i<t->value.func.termcount;i++) {
793                         parse_dump_term(t->value.func.terms[i], depth+1);
794                 }
795                 for (i=0;i<depth;i++)
796                         printf("   ");
797                 printf(" )");
798                 break;
799         case ESEXP_TERM_VAR:
800                 printf(" (variable %s )\n", t->value.var->name);
801                 break;
802         default:
803                 printf("unknown type: %d\n", t->type);
804         }
805
806         printf("\n");
807 }
808
809 /*
810   PARSER
811 */
812
813 static struct _ESExpTerm *
814 parse_term_new(struct _ESExp *f, int type)
815 {
816         struct _ESExpTerm *s = e_memchunk_alloc0(f->term_chunks);
817         s->type = type;
818         return s;
819 }
820
821 static void
822 parse_term_free(struct _ESExp *f, struct _ESExpTerm *t)
823 {
824         int i;
825
826         if (t==NULL) {
827                 return;
828         }
829         
830         switch (t->type) {
831         case ESEXP_TERM_INT:
832         case ESEXP_TERM_BOOL:
833         case ESEXP_TERM_TIME:
834         case ESEXP_TERM_VAR:
835                 break;
836
837         case ESEXP_TERM_STRING:
838                 g_free(t->value.string);
839                 break;
840
841         case ESEXP_TERM_FUNC:
842         case ESEXP_TERM_IFUNC:
843                 for (i=0;i<t->value.func.termcount;i++) {
844                         parse_term_free(f, t->value.func.terms[i]);
845                 }
846                 g_free(t->value.func.terms);
847                 break;
848
849         default:
850                 printf("parse_term_free: unknown type: %d\n", t->type);
851         }
852         e_memchunk_free(f->term_chunks, t);
853 }
854
855 static struct _ESExpTerm **
856 parse_values(ESExp *f, int *len)
857 {
858         int token;
859         struct _ESExpTerm **terms;
860         int i, size = 0;
861         GScanner *gs = f->scanner;
862         GSList *list = NULL, *l;
863
864         p(printf("parsing values\n"));
865
866         while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF
867                 && token != ')') {
868                 list = g_slist_prepend(list, parse_value(f));
869                 size++;
870         }
871
872         /* go over the list, and put them backwards into the term array */
873         terms = g_malloc(size * sizeof(*terms));
874         l = list;
875         for (i=size-1;i>=0;i--) {
876                 g_assert(l);
877                 g_assert(l->data);
878                 terms[i] = l->data;
879                 l = g_slist_next(l);
880         }
881         g_slist_free(list);
882
883         p(printf("found %d subterms\n", size));
884         *len = size;
885         
886         p(printf("done parsing values\n"));
887         return terms;
888 }
889
890 static struct _ESExpTerm *
891 parse_value(ESExp *f)
892 {
893         int token, negative = FALSE;
894         struct _ESExpTerm *t = NULL;
895         GScanner *gs = f->scanner;
896         struct _ESExpSymbol *s;
897         
898         p(printf("parsing value\n"));
899         
900         token = g_scanner_get_next_token(gs);
901         switch(token) {
902         case G_TOKEN_EOF:
903                 break;
904         case G_TOKEN_LEFT_PAREN:
905                 p(printf("got brace, its a list!\n"));
906                 return parse_list(f, TRUE);
907         case G_TOKEN_STRING:
908                 p(printf("got string '%s'\n", g_scanner_cur_value(gs).v_string));
909                 t = parse_term_new(f, ESEXP_TERM_STRING);
910                 t->value.string = g_strdup(g_scanner_cur_value(gs).v_string);
911                 break;
912         case '-':
913                 p(printf ("got negative int?\n"));
914                 token = g_scanner_get_next_token (gs);
915                 if (token != G_TOKEN_INT) {
916                         e_sexp_fatal_error (f, "Invalid format for a integer value");
917                         return NULL;
918                 }
919                 
920                 negative = TRUE;
921                 /* fall through... */
922         case G_TOKEN_INT:
923                 t = parse_term_new(f, ESEXP_TERM_INT);
924                 t->value.number = g_scanner_cur_value(gs).v_int;
925                 if (negative)
926                         t->value.number = -t->value.number;
927                 p(printf("got int %d\n", t->value.number));
928                 break;
929         case '#': {
930                 char *str;
931                 
932                 p(printf("got bool?\n"));
933                 token = g_scanner_get_next_token(gs);
934                 if (token != G_TOKEN_IDENTIFIER) {
935                         e_sexp_fatal_error (f, "Invalid format for a boolean value");
936                         return NULL;
937                 }
938                 
939                 str = g_scanner_cur_value (gs).v_identifier;
940                 
941                 g_assert (str != NULL);
942                 if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
943                         e_sexp_fatal_error (f, "Invalid format for a boolean value");
944                         return NULL;
945                 }
946                 
947                 t = parse_term_new(f, ESEXP_TERM_BOOL);
948                 t->value.bool = (str[0] == 't');
949                 break; }
950         case G_TOKEN_SYMBOL:
951                 s = g_scanner_cur_value(gs).v_symbol;
952                 p(printf("got symbol '%s'\n", s->name));
953                 switch (s->type) {
954                 case ESEXP_TERM_FUNC:
955                 case ESEXP_TERM_IFUNC:
956                                 /* this is basically invalid, since we can't use function
957                                    pointers, but let the runtime catch it ... */
958                         t = parse_term_new(f, s->type);
959                         t->value.func.sym = s;
960                         t->value.func.terms = parse_values(f, &t->value.func.termcount);
961                         break;
962                 case ESEXP_TERM_VAR:
963                         t = parse_term_new(f, s->type);
964                         t->value.var = s;
965                         break;
966                 default:
967                         e_sexp_fatal_error(f, "Invalid symbol type: %s: %d", s->name, s->type);
968                 }
969                 break;
970         case G_TOKEN_IDENTIFIER:
971                 p(printf("got unknown identifider '%s'\n", g_scanner_cur_value(gs).v_identifier));
972                 e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
973                 break;
974         default:
975                 e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
976         }
977         p(printf("done parsing value\n"));
978         return t;
979 }
980
981 /* FIXME: this needs some robustification */
982 static struct _ESExpTerm *
983 parse_list(ESExp *f, int gotbrace)
984 {
985         int token;
986         struct _ESExpTerm *t = NULL;
987         GScanner *gs = f->scanner;
988
989         p(printf("parsing list\n"));
990         if (gotbrace)
991                 token = '(';
992         else
993                 token = g_scanner_get_next_token(gs);
994         if (token =='(') {
995                 token = g_scanner_get_next_token(gs);
996                 switch(token) {
997                 case G_TOKEN_SYMBOL: {
998                         struct _ESExpSymbol *s;
999
1000                         s = g_scanner_cur_value(gs).v_symbol;
1001                         p(printf("got funciton: %s\n", s->name));
1002                         t = parse_term_new(f, s->type);
1003                         p(printf("created new list %p\n", t));
1004                         /* if we have a variable, find out its base type */
1005                         while (s->type == ESEXP_TERM_VAR) {
1006                                 s = ((ESExpTerm *)(s->data))->value.var;
1007                         }
1008                         if (s->type == ESEXP_TERM_FUNC
1009                             || s->type == ESEXP_TERM_IFUNC) {
1010                                 t->value.func.sym = s;
1011                                 t->value.func.terms = parse_values(f, &t->value.func.termcount);
1012                         } else {
1013                                 parse_term_free(f, t);
1014                                 e_sexp_fatal_error(f, "Trying to call variable as function: %s", s->name);
1015                         }
1016                         break; }
1017                 case G_TOKEN_IDENTIFIER:
1018                         e_sexp_fatal_error(f, "Unknown identifier: %s", g_scanner_cur_value(gs).v_identifier);
1019                         break;
1020                 default:
1021                         e_sexp_fatal_error(f, "Unexpected token encountered: %d", token);
1022                 }
1023                 token = g_scanner_get_next_token(gs);
1024                 if (token != ')') {
1025                         e_sexp_fatal_error(f, "Missing ')'");
1026                 }
1027         } else {
1028                 e_sexp_fatal_error(f, "Missing '('");
1029         }
1030
1031         p(printf("returning list %p\n", t));
1032         return t;
1033 }
1034
1035 static void e_sexp_finalise(void *);
1036
1037 #ifdef E_SEXP_IS_G_OBJECT
1038 static void
1039 e_sexp_class_init (ESExpClass *klass)
1040 {
1041         GObjectClass *object_class = G_OBJECT_CLASS (klass);
1042
1043         object_class->finalize = e_sexp_finalise;
1044
1045         parent_class = g_type_class_ref (g_object_get_type ());
1046 }
1047 #endif
1048
1049 /* 'builtin' functions */
1050 static const struct {
1051         char *name;
1052         ESExpFunc *func;
1053         int type;               /* set to 1 if a function can perform shortcut evaluation, or
1054                                    doesn't execute everything, 0 otherwise */
1055 } symbols[] = {
1056         { "and", (ESExpFunc *)term_eval_and, 1 },
1057         { "or", (ESExpFunc *)term_eval_or, 1 },
1058         { "not", (ESExpFunc *)term_eval_not, 0 },
1059         { "<", (ESExpFunc *)term_eval_lt, 1 },
1060         { ">", (ESExpFunc *)term_eval_gt, 1 },
1061         { "=", (ESExpFunc *)term_eval_eq, 1 },
1062         { "+", (ESExpFunc *)term_eval_plus, 0 },
1063         { "-", (ESExpFunc *)term_eval_sub, 0 },
1064         { "cast-int", (ESExpFunc *)term_eval_castint, 0 },
1065         { "cast-string", (ESExpFunc *)term_eval_caststring, 0 },
1066         { "if", (ESExpFunc *)term_eval_if, 1 },
1067         { "begin", (ESExpFunc *)term_eval_begin, 1 },
1068 };
1069
1070 static void
1071 free_symbol(void *key, void *value, void *data)
1072 {
1073         struct _ESExpSymbol *s = value;
1074
1075         g_free(s->name);
1076         g_free(s);
1077 }
1078
1079 static void
1080 e_sexp_finalise(void *o)
1081 {
1082         ESExp *s = (ESExp *)o;
1083
1084         if (s->tree) {
1085                 parse_term_free(s, s->tree);
1086                 s->tree = NULL;
1087         }
1088
1089         e_memchunk_destroy(s->term_chunks);
1090         e_memchunk_destroy(s->result_chunks);
1091
1092         g_scanner_scope_foreach_symbol(s->scanner, 0, free_symbol, NULL);
1093         g_scanner_destroy(s->scanner);
1094
1095 #ifdef E_SEXP_IS_G_OBJECT
1096         G_OBJECT_CLASS (parent_class)->finalize (o);
1097 #endif
1098 }
1099
1100 static void
1101 e_sexp_init (ESExp *s)
1102 {
1103         int i;
1104
1105         s->scanner = g_scanner_new(&scanner_config);
1106         s->term_chunks = e_memchunk_new(16, sizeof(struct _ESExpTerm));
1107         s->result_chunks = e_memchunk_new(16, sizeof(struct _ESExpResult));
1108
1109         /* load in builtin symbols? */
1110         for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
1111                 if (symbols[i].type == 1) {
1112                         e_sexp_add_ifunction(s, 0, symbols[i].name, (ESExpIFunc *)symbols[i].func, (void *)&symbols[i]);
1113                 } else {
1114                         e_sexp_add_function(s, 0, symbols[i].name, symbols[i].func, (void *)&symbols[i]);
1115                 }
1116         }
1117
1118 #ifndef E_SEXP_IS_G_OBJECT
1119         s->refcount = 1;
1120 #endif
1121 }
1122
1123 #ifdef E_SEXP_IS_G_OBJECT
1124 GType
1125 e_sexp_get_type (void)
1126 {
1127         static GType type = 0;
1128         
1129         if (!type) {
1130                 static const GTypeInfo info = {
1131                         sizeof (ESExpClass),
1132                         NULL, /* base_class_init */
1133                         NULL, /* base_class_finalize */
1134                         (GClassInitFunc) e_sexp_class_init,
1135                         NULL, /* class_finalize */
1136                         NULL, /* class_data */
1137                         sizeof (ESExp),
1138                         0,    /* n_preallocs */
1139                         (GInstanceInitFunc) e_sexp_init,
1140                 };
1141                 
1142                 type = g_type_register_static (G_TYPE_OBJECT, "ESExp", &info, 0);
1143         }
1144         
1145         return type;
1146 }
1147 #endif
1148
1149 ESExp *
1150 e_sexp_new (void)
1151 {
1152 #ifdef E_SEXP_IS_G_OBJECT
1153         ESExp *f = (ESexp *) g_object_new (E_TYPE_SEXP, NULL);
1154 #else
1155         ESExp *f = g_malloc0 (sizeof (ESExp));
1156         e_sexp_init (f);
1157 #endif
1158         
1159         return f;
1160 }
1161
1162 #ifndef E_SEXP_IS_G_OBJECT
1163 void
1164 e_sexp_ref (ESExp *f)
1165 {
1166         f->refcount++;
1167 }
1168
1169 void
1170 e_sexp_unref (ESExp *f)
1171 {
1172         f->refcount--;
1173         if (f->refcount == 0) {
1174                 e_sexp_finalise(f);
1175                 g_free(f);
1176         }
1177 }
1178 #endif
1179
1180 void
1181 e_sexp_add_function(ESExp *f, int scope, char *name, ESExpFunc *func, void *data)
1182 {
1183         struct _ESExpSymbol *s;
1184
1185         g_return_if_fail (IS_E_SEXP (f));
1186         g_return_if_fail (name != NULL);
1187
1188         e_sexp_remove_symbol (f, scope, name);
1189
1190         s = g_malloc0(sizeof(*s));
1191         s->name = g_strdup(name);
1192         s->f.func = func;
1193         s->type = ESEXP_TERM_FUNC;
1194         s->data = data;
1195         g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1196 }
1197
1198 void
1199 e_sexp_add_ifunction(ESExp *f, int scope, char *name, ESExpIFunc *ifunc, void *data)
1200 {
1201         struct _ESExpSymbol *s;
1202
1203         g_return_if_fail (IS_E_SEXP (f));
1204         g_return_if_fail (name != NULL);
1205
1206         e_sexp_remove_symbol (f, scope, name);
1207
1208         s = g_malloc0(sizeof(*s));
1209         s->name = g_strdup(name);
1210         s->f.ifunc = ifunc;
1211         s->type = ESEXP_TERM_IFUNC;
1212         s->data = data;
1213         g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1214 }
1215
1216 void
1217 e_sexp_add_variable(ESExp *f, int scope, char *name, ESExpTerm *value)
1218 {
1219         struct _ESExpSymbol *s;
1220
1221         g_return_if_fail (IS_E_SEXP (f));
1222         g_return_if_fail (name != NULL);
1223
1224         s = g_malloc0(sizeof(*s));
1225         s->name = g_strdup(name);
1226         s->type = ESEXP_TERM_VAR;
1227         s->data = value;
1228         g_scanner_scope_add_symbol(f->scanner, scope, s->name, s);
1229 }
1230
1231 void
1232 e_sexp_remove_symbol(ESExp *f, int scope, char *name)
1233 {
1234         int oldscope;
1235         struct _ESExpSymbol *s;
1236
1237         g_return_if_fail (IS_E_SEXP (f));
1238         g_return_if_fail (name != NULL);
1239
1240         oldscope = g_scanner_set_scope(f->scanner, scope);
1241         s = g_scanner_lookup_symbol(f->scanner, name);
1242         g_scanner_scope_remove_symbol(f->scanner, scope, name);
1243         g_scanner_set_scope(f->scanner, oldscope);
1244         if (s) {
1245                 g_free(s->name);
1246                 g_free(s);
1247         }
1248 }
1249
1250 int
1251 e_sexp_set_scope(ESExp *f, int scope)
1252 {
1253         g_return_val_if_fail (IS_E_SEXP (f), 0);
1254
1255         return g_scanner_set_scope(f->scanner, scope);
1256 }
1257
1258 void
1259 e_sexp_input_text(ESExp *f, const char *text, int len)
1260 {
1261         g_return_if_fail (IS_E_SEXP (f));
1262         g_return_if_fail (text != NULL);
1263
1264         g_scanner_input_text(f->scanner, text, len);
1265 }
1266
1267 void
1268 e_sexp_input_file (ESExp *f, int fd)
1269 {
1270         g_return_if_fail (IS_E_SEXP (f));
1271
1272         g_scanner_input_file(f->scanner, fd);
1273 }
1274
1275 /* returns -1 on error */
1276 int
1277 e_sexp_parse(ESExp *f)
1278 {
1279         g_return_val_if_fail (IS_E_SEXP (f), -1);
1280
1281         if (setjmp(f->failenv)) {
1282                 g_warning("Error in parsing: %s", f->error);
1283                 return -1;
1284         }
1285
1286         if (f->tree)
1287                 parse_term_free(f, f->tree);
1288
1289         f->tree = parse_value (f);
1290
1291         return 0;
1292 }
1293
1294 /* returns NULL on error */
1295 struct _ESExpResult *
1296 e_sexp_eval(ESExp *f)
1297 {
1298         g_return_val_if_fail (IS_E_SEXP (f), NULL);
1299         g_return_val_if_fail (f->tree != NULL, NULL);
1300
1301         if (setjmp(f->failenv)) {
1302                 g_warning("Error in execution: %s", f->error);
1303                 return NULL;
1304         }
1305
1306         return e_sexp_term_eval(f, f->tree);
1307 }
1308
1309 /**
1310  * e_sexp_encode_bool:
1311  * @s: 
1312  * @state: 
1313  * 
1314  * Encode a bool into an s-expression @s.  Bools are
1315  * encoded using #t #f syntax.
1316  **/
1317 void
1318 e_sexp_encode_bool(GString *s, gboolean state)
1319 {
1320         if (state)
1321                 g_string_append(s, " #t");
1322         else
1323                 g_string_append(s, " #f");
1324 }
1325
1326 /**
1327  * e_sexp_encode_string:
1328  * @s: Destination string.
1329  * @string: String expression.
1330  * 
1331  * Add a c string @string to the s-expression stored in
1332  * the gstring @s.  Quotes are added, and special characters
1333  * are escaped appropriately.
1334  **/
1335 void
1336 e_sexp_encode_string(GString *s, const char *string)
1337 {
1338         char c;
1339         const char *p;
1340
1341         if (string == NULL)
1342                 p = "";
1343         else
1344                 p = string;
1345         g_string_append(s, " \"");
1346         while ( (c = *p++) ) {
1347                 if (c=='\\' || c=='\"' || c=='\'')
1348                         g_string_append_c(s, '\\');
1349                 g_string_append_c(s, c);
1350         }
1351         g_string_append(s, "\"");
1352 }
1353
1354 #ifdef TESTER
1355 int main(int argc, char **argv)
1356 {
1357         ESExp *f;
1358         char *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1359         ESExpResult *r;
1360
1361         g_type_init();
1362
1363         f = e_sexp_new();
1364
1365         e_sexp_add_variable(f, 0, "test", NULL);
1366
1367         e_sexp_input_text(f, t, strlen(t));
1368         e_sexp_parse(f);
1369
1370         if (f->tree) {
1371                 parse_dump_term(f->tree, 0);
1372         }
1373
1374         r = e_sexp_eval(f);
1375         if (r) {
1376                 eval_dump_result(r, 0);
1377         } else {
1378                 printf("no result?|\n");
1379         }
1380
1381         return 0;
1382 }
1383 #endif