2 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 * A simple, extensible s-exp evaluation engine.
7 * Michael Zucchi <notzed@ximian.com>
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.
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.
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
25 * The following built-in s-exp's are supported:
28 * perform an intersection of a number of lists, and return that.
31 * perform a boolean AND of boolean values.
34 * perform a union of a number of lists, returning the new list.
37 * perform a boolean OR of boolean values.
42 * string = (+ string*)
45 * time_t = (+ time_t*)
48 * gint = (- gint int*)
49 * Subtract integers from the first.
51 * time_t = (- time_t*)
52 * Subtract time_t values from the first.
54 * gint = (cast-int string|int|bool)
55 * Cast to an integer value.
57 * string = (cast-string string|int|bool)
58 * Cast to an string value.
60 * Comparison operators:
62 * bool = (< gint gint)
63 * bool = (> gint gint)
64 * bool = (= gint gint)
66 * bool = (< string string)
67 * bool = (> string string)
68 * bool = (= string string)
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.
77 * type = (if bool function)
78 * type = (if bool function function)
79 * Choose a flow path based on a boolean value
81 * type = (begin func func func)
82 * Execute a sequence. The last function return is the return type.
91 #include "camel-sexp.h"
93 #define p(x) /* parse debug */
94 #define r(x) /* run debug */
95 #define d(x) /* general debug */
97 G_DEFINE_TYPE (CamelSExp, camel_sexp, G_TYPE_OBJECT)
99 static CamelSExpTerm * parse_list (CamelSExp *sexp, gint gotbrace);
100 static CamelSExpTerm * parse_value (CamelSExp *sexp);
103 static void parse_dump_term (CamelSExpTerm *term, gint depth);
106 typedef gboolean (CamelSGeneratorFunc) (gint argc,
107 CamelSExpResult **argv,
108 CamelSExpResult *result);
109 typedef gboolean (CamelSOperatorFunc) (gint argc,
110 CamelSExpResult **argv,
111 CamelSExpResult *result);
113 /* FIXME: constant _TIME_MAX used in different files, move it somewhere */
114 #define _TIME_MAX ((time_t) INT_MAX) /* Max valid time_t */
116 static const GScannerConfig scanner_config =
118 ( (gchar *) " \t\r\n") /* cset_skip_characters */,
119 ( (gchar *) G_CSET_a_2_z
121 G_CSET_A_2_Z) /* cset_identifier_first */,
122 ( (gchar *) G_CSET_a_2_z
126 G_CSET_LATINC ) /* cset_identifier_nth */,
127 ( (gchar *) ";\n" ) /* cpair_comment_single */,
129 FALSE /* case_sensitive */,
131 TRUE /* skip_comment_multi */,
132 TRUE /* skip_comment_single */,
133 TRUE /* scan_comment_multi */,
134 TRUE /* scan_identifier */,
135 TRUE /* scan_identifier_1char */,
136 FALSE /* scan_identifier_NULL */,
137 TRUE /* scan_symbols */,
138 FALSE /* scan_binary */,
139 TRUE /* scan_octal */,
140 TRUE /* scan_float */,
142 FALSE /* scan_hex_dollar */,
143 TRUE /* scan_string_sq */,
144 TRUE /* scan_string_dq */,
145 TRUE /* numbers_2_int */,
146 FALSE /* int_2_float */,
147 FALSE /* identifier_2_string */,
148 TRUE /* char_2_token */,
149 FALSE /* symbol_2_token */,
150 FALSE /* scope_0_fallback */,
154 * camel_sexp_fatal_error:
159 camel_sexp_fatal_error (CamelSExp *sexp,
165 /* jumps back to the caller of sexp->failenv,
166 * only to be called from inside a callback */
169 g_free (sexp->error);
171 va_start (args, why);
172 sexp->error = g_strdup_vprintf (why, args);
175 longjmp (sexp->failenv, 1);
184 camel_sexp_error (CamelSExp *sexp)
190 * camel_sexp_result_new:
195 camel_sexp_result_new (CamelSExp *sexp,
198 CamelSExpResult *result;
200 result = camel_memchunk_alloc0 (sexp->result_chunks);
202 result->occuring_start = 0;
203 result->occuring_end = _TIME_MAX;
204 result->time_generator = FALSE;
210 * camel_sexp_result_free:
215 camel_sexp_result_free (CamelSExp *sexp,
216 CamelSExpResult *term)
221 switch (term->type) {
222 case CAMEL_SEXP_RES_ARRAY_PTR:
223 g_ptr_array_free (term->value.ptrarray, TRUE);
225 case CAMEL_SEXP_RES_BOOL:
226 case CAMEL_SEXP_RES_INT:
227 case CAMEL_SEXP_RES_TIME:
229 case CAMEL_SEXP_RES_STRING:
230 g_free (term->value.string);
232 case CAMEL_SEXP_RES_UNDEFINED:
235 g_assert_not_reached ();
237 camel_memchunk_free (sexp->result_chunks, term);
241 * camel_sexp_resultv_free:
246 camel_sexp_resultv_free (CamelSExp *sexp,
248 CamelSExpResult **argv)
252 /* used in normal functions if they have to abort,
253 * and free their arguments */
255 for (i = 0; i < argc; i++) {
256 camel_sexp_result_free (sexp, argv[i]);
260 /* implementations for the builtin functions */
262 /* we can only itereate a hashtable from a called function */
268 /* ok, store any values that are in all sets */
272 struct IterData *iter_data)
274 if (value == iter_data->count) {
275 g_ptr_array_add (iter_data->uids, key);
279 /* or, store all unique values */
283 struct IterData *iter_data)
285 g_ptr_array_add (iter_data->uids, key);
288 static CamelSExpResult *
289 term_eval_and (CamelSExp *sexp,
291 CamelSExpTerm **argv,
294 CamelSExpResult *result, *r1;
295 GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
296 struct IterData lambdafoo;
302 r (printf ("( and\n"));
304 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
307 sexp->operators = g_slist_prepend (sexp->operators, (gpointer) oper);
309 for (i = 0; bool && i < argc; i++) {
310 r1 = camel_sexp_term_eval (sexp, argv[i]);
313 if (type != r1->type) {
314 camel_sexp_result_free (sexp, result);
315 camel_sexp_result_free (sexp, r1);
316 g_hash_table_destroy (ht);
317 camel_sexp_fatal_error (sexp, "Invalid types in AND");
318 } else if (r1->type == CAMEL_SEXP_RES_ARRAY_PTR) {
322 a1 = (gchar **) r1->value.ptrarray->pdata;
323 l1 = r1->value.ptrarray->len;
324 for (j = 0; j < l1; j++) {
327 ptr = g_hash_table_lookup (ht, a1[j]);
328 n = GPOINTER_TO_INT (ptr);
329 g_hash_table_insert (ht, a1[j], GINT_TO_POINTER (n + 1));
331 } else if (r1->type == CAMEL_SEXP_RES_BOOL) {
332 bool = bool && r1->value.boolean;
334 camel_sexp_result_free (sexp, r1);
337 if (type == CAMEL_SEXP_RES_ARRAY_PTR) {
338 lambdafoo.count = argc;
339 lambdafoo.uids = g_ptr_array_new ();
340 g_hash_table_foreach (ht, (GHFunc) htand, &lambdafoo);
341 result->type = CAMEL_SEXP_RES_ARRAY_PTR;
342 result->value.ptrarray = lambdafoo.uids;
343 } else if (type == CAMEL_SEXP_RES_BOOL) {
344 result->type = CAMEL_SEXP_RES_BOOL;
345 result->value.boolean = bool;
348 g_hash_table_destroy (ht);
349 sexp->operators = g_slist_remove (sexp->operators, oper);
354 static CamelSExpResult *
355 term_eval_or (CamelSExp *sexp,
357 CamelSExpTerm **argv,
360 CamelSExpResult *result, *r1;
361 GHashTable *ht = g_hash_table_new (g_str_hash, g_str_equal);
362 struct IterData lambdafoo;
368 r (printf ("(or \n"));
371 sexp->operators = g_slist_prepend (sexp->operators, (gpointer) oper);
373 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
375 for (i = 0; !bool && i < argc; i++) {
376 r1 = camel_sexp_term_eval (sexp, argv[i]);
379 if (r1->type != type) {
380 camel_sexp_result_free (sexp, result);
381 camel_sexp_result_free (sexp, r1);
382 g_hash_table_destroy (ht);
383 camel_sexp_fatal_error (sexp, "Invalid types in OR");
384 } else if (r1->type == CAMEL_SEXP_RES_ARRAY_PTR) {
388 a1 = (gchar **) r1->value.ptrarray->pdata;
389 l1 = r1->value.ptrarray->len;
390 for (j = 0; j < l1; j++) {
391 g_hash_table_insert (ht, a1[j], (gpointer) 1);
393 } else if (r1->type == CAMEL_SEXP_RES_BOOL) {
394 bool |= r1->value.boolean;
396 camel_sexp_result_free (sexp, r1);
399 if (type == CAMEL_SEXP_RES_ARRAY_PTR) {
400 lambdafoo.count = argc;
401 lambdafoo.uids = g_ptr_array_new ();
402 g_hash_table_foreach (ht, (GHFunc) htor, &lambdafoo);
403 result->type = CAMEL_SEXP_RES_ARRAY_PTR;
404 result->value.ptrarray = lambdafoo.uids;
405 } else if (type == CAMEL_SEXP_RES_BOOL) {
406 result->type = CAMEL_SEXP_RES_BOOL;
407 result->value.boolean = bool;
409 g_hash_table_destroy (ht);
411 sexp->operators = g_slist_remove (sexp->operators, oper);
415 static CamelSExpResult *
416 term_eval_not (CamelSExp *sexp,
418 CamelSExpResult **argv,
422 CamelSExpResult *result;
425 if (argv[0]->type == CAMEL_SEXP_RES_BOOL
426 && argv[0]->value.boolean)
429 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
430 result->value.boolean = res;
435 /* this should support all arguments ...? */
436 static CamelSExpResult *
437 term_eval_lt (CamelSExp *sexp,
439 CamelSExpTerm **argv,
442 CamelSExpResult *result, *r1, *r2;
444 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
447 r1 = camel_sexp_term_eval (sexp, argv[0]);
448 r2 = camel_sexp_term_eval (sexp, argv[1]);
449 if (r1->type != r2->type) {
450 camel_sexp_result_free (sexp, r1);
451 camel_sexp_result_free (sexp, r2);
452 camel_sexp_result_free (sexp, result);
453 camel_sexp_fatal_error (sexp, "Incompatible types in compare <");
454 } else if (r1->type == CAMEL_SEXP_RES_INT) {
455 result->type = CAMEL_SEXP_RES_BOOL;
456 result->value.boolean = r1->value.number < r2->value.number;
457 } else if (r1->type == CAMEL_SEXP_RES_TIME) {
458 result->type = CAMEL_SEXP_RES_BOOL;
459 result->value.boolean = r1->value.time < r2->value.time;
460 } else if (r1->type == CAMEL_SEXP_RES_STRING) {
461 result->type = CAMEL_SEXP_RES_BOOL;
462 result->value.boolean = strcmp (r1->value.string, r2->value.string) < 0;
464 camel_sexp_result_free (sexp, r1);
465 camel_sexp_result_free (sexp, r2);
470 /* this should support all arguments ...? */
471 static CamelSExpResult *
472 term_eval_gt (CamelSExp *sexp,
474 CamelSExpTerm **argv,
477 CamelSExpResult *result, *r1, *r2;
479 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
482 r1 = camel_sexp_term_eval (sexp, argv[0]);
483 r2 = camel_sexp_term_eval (sexp, argv[1]);
484 if (r1->type != r2->type) {
485 camel_sexp_result_free (sexp, r1);
486 camel_sexp_result_free (sexp, r2);
487 camel_sexp_result_free (sexp, result);
488 camel_sexp_fatal_error (sexp, "Incompatible types in compare >");
489 } else if (r1->type == CAMEL_SEXP_RES_INT) {
490 result->type = CAMEL_SEXP_RES_BOOL;
491 result->value.boolean = r1->value.number > r2->value.number;
492 } else if (r1->type == CAMEL_SEXP_RES_TIME) {
493 result->type = CAMEL_SEXP_RES_BOOL;
494 result->value.boolean = r1->value.time > r2->value.time;
495 } else if (r1->type == CAMEL_SEXP_RES_STRING) {
496 result->type = CAMEL_SEXP_RES_BOOL;
497 result->value.boolean = strcmp (r1->value.string, r2->value.string) > 0;
499 camel_sexp_result_free (sexp, r1);
500 camel_sexp_result_free (sexp, r2);
505 /* this should support all arguments ...? */
506 static CamelSExpResult *
507 term_eval_eq (CamelSExp *sexp,
509 CamelSExpTerm **argv,
512 CamelSExpResult *result, *r1, *r2;
514 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
517 r1 = camel_sexp_term_eval (sexp, argv[0]);
518 r2 = camel_sexp_term_eval (sexp, argv[1]);
519 if (r1->type != r2->type) {
520 result->value.boolean = FALSE;
521 } else if (r1->type == CAMEL_SEXP_RES_INT) {
522 result->value.boolean = r1->value.number == r2->value.number;
523 } else if (r1->type == CAMEL_SEXP_RES_BOOL) {
524 result->value.boolean = r1->value.boolean == r2->value.boolean;
525 } else if (r1->type == CAMEL_SEXP_RES_TIME) {
526 result->value.boolean = r1->value.time == r2->value.time;
527 } else if (r1->type == CAMEL_SEXP_RES_STRING) {
528 result->value.boolean = strcmp (r1->value.string, r2->value.string) == 0;
530 camel_sexp_result_free (sexp, r1);
531 camel_sexp_result_free (sexp, r2);
536 static CamelSExpResult *
537 term_eval_plus (CamelSExp *sexp,
539 CamelSExpResult **argv,
542 CamelSExpResult *result = NULL;
547 type = argv[0]->type;
549 case CAMEL_SEXP_RES_INT: {
550 gint total = argv[0]->value.number;
551 for (i = 1; i < argc && argv[i]->type == CAMEL_SEXP_RES_INT; i++) {
552 total += argv[i]->value.number;
555 camel_sexp_resultv_free (sexp, argc, argv);
556 camel_sexp_fatal_error (sexp, "Invalid types in (+ ints)");
558 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
559 result->value.number = total;
561 case CAMEL_SEXP_RES_STRING: {
562 GString *string = g_string_new (argv[0]->value.string);
563 for (i = 1; i < argc && argv[i]->type == CAMEL_SEXP_RES_STRING; i++) {
564 g_string_append (string, argv[i]->value.string);
567 camel_sexp_resultv_free (sexp, argc, argv);
568 camel_sexp_fatal_error (sexp, "Invalid types in (+ strings)");
570 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_STRING);
571 result->value.string = string->str;
572 g_string_free (string, FALSE);
574 case CAMEL_SEXP_RES_TIME: {
577 total = argv[0]->value.time;
579 for (i = 1; i < argc && argv[i]->type == CAMEL_SEXP_RES_TIME; i++)
580 total += argv[i]->value.time;
583 camel_sexp_resultv_free (sexp, argc, argv);
584 camel_sexp_fatal_error (sexp, "Invalid types in (+ time_t)");
587 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_TIME);
588 result->value.time = total;
593 if (result == NULL) {
594 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
595 result->value.number = 0;
601 static CamelSExpResult *
602 term_eval_sub (CamelSExp *sexp,
604 CamelSExpResult **argv,
607 CamelSExpResult *result = NULL;
612 type = argv[0]->type;
614 case CAMEL_SEXP_RES_INT: {
615 gint total = argv[0]->value.number;
616 for (i = 1; i < argc && argv[i]->type == CAMEL_SEXP_RES_INT; i++) {
617 total -= argv[i]->value.number;
620 camel_sexp_resultv_free (sexp, argc, argv);
621 camel_sexp_fatal_error (sexp, "Invalid types in -");
623 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
624 result->value.number = total;
626 case CAMEL_SEXP_RES_TIME: {
629 total = argv[0]->value.time;
631 for (i = 1; i < argc && argv[i]->type == CAMEL_SEXP_RES_TIME; i++)
632 total -= argv[i]->value.time;
635 camel_sexp_resultv_free (sexp, argc, argv);
636 camel_sexp_fatal_error (sexp, "Invalid types in (- time_t)");
639 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_TIME);
640 result->value.time = total;
645 if (result == NULL) {
646 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
647 result->value.number = 0;
653 static CamelSExpResult *
654 term_eval_castint (CamelSExp *sexp,
656 CamelSExpResult **argv,
659 CamelSExpResult *result;
662 camel_sexp_fatal_error (sexp, "Incorrect argument count to (gint )");
664 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
665 switch (argv[0]->type) {
666 case CAMEL_SEXP_RES_INT:
667 result->value.number = argv[0]->value.number;
669 case CAMEL_SEXP_RES_BOOL:
670 result->value.number = argv[0]->value.boolean != 0;
672 case CAMEL_SEXP_RES_STRING:
673 result->value.number = strtoul (argv[0]->value.string, NULL, 10);
676 camel_sexp_result_free (sexp, result);
677 camel_sexp_fatal_error (sexp, "Invalid type in (cast-int )");
684 static CamelSExpResult *
685 term_eval_caststring (CamelSExp *sexp,
687 CamelSExpResult **argv,
690 CamelSExpResult *result;
693 camel_sexp_fatal_error (sexp, "Incorrect argument count to (cast-string )");
695 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_STRING);
696 switch (argv[0]->type) {
697 case CAMEL_SEXP_RES_INT:
698 result->value.string = g_strdup_printf ("%d", argv[0]->value.number);
700 case CAMEL_SEXP_RES_BOOL:
701 result->value.string = g_strdup_printf ("%d", argv[0]->value.boolean != 0);
703 case CAMEL_SEXP_RES_STRING:
704 result->value.string = g_strdup (argv[0]->value.string);
707 camel_sexp_result_free (sexp, result);
708 camel_sexp_fatal_error (sexp, "Invalid type in (gint )");
714 /* implements 'if' function */
715 static CamelSExpResult *
716 term_eval_if (CamelSExp *sexp,
718 CamelSExpTerm **argv,
721 CamelSExpResult *result;
724 if (argc >=2 && argc <= 3) {
725 result = camel_sexp_term_eval (sexp, argv[0]);
726 doit = (result->type == CAMEL_SEXP_RES_BOOL && result->value.boolean);
727 camel_sexp_result_free (sexp, result);
729 return camel_sexp_term_eval (sexp, argv[1]);
730 } else if (argc > 2) {
731 return camel_sexp_term_eval (sexp, argv[2]);
734 return camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
737 /* implements 'begin' statement */
738 static CamelSExpResult *
739 term_eval_begin (CamelSExp *sexp,
741 CamelSExpTerm **argv,
744 CamelSExpResult *result = NULL;
747 for (i = 0; i < argc; i++) {
749 camel_sexp_result_free (sexp, result);
750 result = camel_sexp_term_eval (sexp, argv[i]);
755 return camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
759 * camel_sexp_term_eval:
764 camel_sexp_term_eval (CamelSExp *sexp,
767 CamelSExpResult *result = NULL;
769 CamelSExpResult **argv;
771 /* this must only be called from inside term evaluation callbacks! */
773 g_return_val_if_fail (term != NULL, NULL);
775 r (printf ("eval term :\n"));
776 r (parse_dump_term (term, 0));
778 switch (term->type) {
779 case CAMEL_SEXP_TERM_STRING:
780 r (printf (" (string \"%s\")\n", term->value.string));
781 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_STRING);
782 /* erk, this shoul;dn't need to strdup this ... */
783 result->value.string = g_strdup (term->value.string);
785 case CAMEL_SEXP_TERM_INT:
786 r (printf (" (gint %d)\n", term->value.number));
787 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_INT);
788 result->value.number = term->value.number;
790 case CAMEL_SEXP_TERM_BOOL:
791 r (printf (" (gint %d)\n", term->value.number));
792 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_BOOL);
793 result->value.boolean = term->value.boolean;
795 case CAMEL_SEXP_TERM_TIME:
796 r (printf (" (time_t %ld)\n", term->value.time));
797 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_TIME);
798 result->value.time = term->value.time;
800 case CAMEL_SEXP_TERM_IFUNC:
801 if (term->value.func.sym && term->value.func.sym->f.ifunc)
802 result = term->value.func.sym->f.ifunc (sexp, term->value.func.termcount, term->value.func.terms, term->value.func.sym->data);
804 case CAMEL_SEXP_TERM_FUNC:
805 /* first evaluate all arguments to result types */
806 argv = alloca (sizeof (argv[0]) * term->value.func.termcount);
807 for (i = 0; i < term->value.func.termcount; i++) {
808 argv[i] = camel_sexp_term_eval (sexp, term->value.func.terms[i]);
810 /* call the function */
811 if (term->value.func.sym->f.func)
812 result = term->value.func.sym->f.func (sexp, term->value.func.termcount, argv, term->value.func.sym->data);
814 camel_sexp_resultv_free (sexp, term->value.func.termcount, argv);
817 camel_sexp_fatal_error (sexp, "Unknown type in parse tree: %d", term->type);
821 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
828 eval_dump_result (CamelSExpResult *result,
833 if (result == NULL) {
834 printf ("null result???\n");
838 for (i = 0; i < depth; i++)
841 switch (result->type) {
842 case CAMEL_SEXP_RES_ARRAY_PTR:
843 printf ("array pointers\n");
845 case CAMEL_SEXP_RES_INT:
846 printf ("int: %d\n", result->value.number);
848 case CAMEL_SEXP_RES_STRING:
849 printf ("string: '%s'\n", result->value.string);
851 case CAMEL_SEXP_RES_BOOL:
852 printf ("bool: %c\n", result->value.boolean ? 't':'f');
854 case CAMEL_SEXP_RES_TIME:
855 printf ("time_t: %ld\n", (glong) result->value.time);
857 case CAMEL_SEXP_RES_UNDEFINED:
858 printf (" <undefined>\n");
867 parse_dump_term (CamelSExpTerm *term,
873 printf ("null term??\n");
877 for (i = 0; i < depth; i++)
880 switch (term->type) {
881 case CAMEL_SEXP_TERM_STRING:
882 printf (" \"%s\"", term->value.string);
884 case CAMEL_SEXP_TERM_INT:
885 printf (" %d", term->value.number);
887 case CAMEL_SEXP_TERM_BOOL:
888 printf (" #%c", term->value.boolean ? 't':'f');
890 case CAMEL_SEXP_TERM_TIME:
891 printf (" %ld", (glong) term->value.time);
893 case CAMEL_SEXP_TERM_IFUNC:
894 case CAMEL_SEXP_TERM_FUNC:
895 printf (" (function %s\n", term->value.func.sym->name);
896 /*printf(" [%d] ", term->value.func.termcount);*/
897 for (i = 0; i < term->value.func.termcount; i++) {
898 parse_dump_term (term->value.func.terms[i], depth + 1);
900 for (i = 0; i < depth; i++)
904 case CAMEL_SEXP_TERM_VAR:
905 printf (" (variable %s )\n", term->value.var->name);
908 printf ("unknown type: %d\n", term->type);
915 const gchar *time_functions[] = {
924 occur_in_time_range_generator (gint argc,
925 CamelSExpResult **argv,
926 CamelSExpResult *result)
928 g_return_val_if_fail (result != NULL, FALSE);
929 g_return_val_if_fail (argc == 2 || argc == 3, FALSE);
931 if ((argv[0]->type != CAMEL_SEXP_RES_TIME) || (argv[1]->type != CAMEL_SEXP_RES_TIME))
934 result->occuring_start = argv[0]->value.time;
935 result->occuring_end = argv[1]->value.time;
941 binary_generator (gint argc,
942 CamelSExpResult **argv,
943 CamelSExpResult *result)
945 g_return_val_if_fail (result != NULL, FALSE);
946 g_return_val_if_fail (argc == 2, FALSE);
948 if ((argv[0]->type != CAMEL_SEXP_RES_TIME) || (argv[1]->type != CAMEL_SEXP_RES_TIME))
951 result->occuring_start = argv[0]->value.time;
952 result->occuring_end = argv[1]->value.time;
958 unary_generator (gint argc,
959 CamelSExpResult **argv,
960 CamelSExpResult *result)
962 /* unary generator with end time */
963 g_return_val_if_fail (result != NULL, FALSE);
964 g_return_val_if_fail (argc == 1, FALSE);
966 if (argv[0]->type != CAMEL_SEXP_RES_TIME)
969 result->occuring_start = 0;
970 result->occuring_end = argv[0]->value.time;
975 static const struct {
977 CamelSGeneratorFunc *func;
979 {"occur-in-time-range?", occur_in_time_range_generator},
980 {"due-in-time-range?", binary_generator},
981 {"has-alarms-in-range?", binary_generator},
982 {"completed-before?", unary_generator},
985 const gint generators_count = sizeof (generators) / sizeof (generators[0]);
988 or_operator (gint argc,
989 CamelSExpResult **argv,
990 CamelSExpResult *result)
997 * norm (0) norm (0) norm (0)
998 * gen (1) norm (0) norm (0)
999 * norm (0) gen (1) norm (0)
1000 * gen (1) gen (1) gen*(1)
1003 g_return_val_if_fail (result != NULL, FALSE);
1004 g_return_val_if_fail (argc > 0, FALSE);
1006 result->time_generator = TRUE;
1007 for (ii = 0; ii < argc && result->time_generator; ii++) {
1008 result->time_generator = argv[ii]->time_generator;
1011 if (result->time_generator) {
1012 result->occuring_start = argv[0]->occuring_start;
1013 result->occuring_end = argv[0]->occuring_end;
1015 for (ii = 1; ii < argc; ii++) {
1016 result->occuring_start = MIN (result->occuring_start, argv[ii]->occuring_start);
1017 result->occuring_end = MAX (result->occuring_end, argv[ii]->occuring_end);
1025 and_operator (gint argc,
1026 CamelSExpResult **argv,
1027 CamelSExpResult *result)
1033 * ---- ---- ------- -
1034 * norm (0) norm (0) norm (0)
1035 * gen (1) norm (0) gen (1)
1036 * norm (0) gen (1) gen (1)
1037 * gen (1) gen (1) gen (1)
1040 g_return_val_if_fail (result != NULL, FALSE);
1041 g_return_val_if_fail (argc > 0, FALSE);
1043 result->time_generator = FALSE;
1044 for (ii = 0; ii < argc && !result->time_generator; ii++) {
1045 result->time_generator = argv[ii]->time_generator;
1048 if (result->time_generator) {
1049 result->occuring_start = argv[0]->occuring_start;
1050 result->occuring_end = argv[0]->occuring_end;
1052 for (ii = 1; ii < argc; ii++) {
1053 result->occuring_start = MAX (result->occuring_start, argv[ii]->occuring_start);
1054 result->occuring_end = MIN (result->occuring_end, argv[ii]->occuring_end);
1061 static const struct {
1063 CamelSOperatorFunc *func;
1065 {"or", or_operator},
1066 {"and", and_operator}
1069 const gint operators_count = sizeof (operators) / sizeof (operators[0]);
1071 static CamelSOperatorFunc *
1072 get_operator_function (const gchar *fname)
1076 g_return_val_if_fail (fname != NULL, NULL);
1078 for (i = 0; i < sizeof (operators) / sizeof (operators[0]); i++)
1079 if (strcmp (operators[i].name, fname) == 0)
1080 return operators[i].func;
1085 static inline gboolean
1086 is_time_function (const gchar *fname)
1090 g_return_val_if_fail (fname != NULL, FALSE);
1092 for (i = 0; i < sizeof (time_functions) / sizeof (time_functions[0]); i++)
1093 if (strcmp (time_functions[i], fname) == 0)
1099 static CamelSGeneratorFunc *
1100 get_generator_function (const gchar *fname)
1104 g_return_val_if_fail (fname != NULL, NULL);
1106 for (i = 0; i < sizeof (generators) / sizeof (generators[0]); i++)
1107 if (strcmp (generators[i].name, fname) == 0)
1108 return generators[i].func;
1113 /* this must only be called from inside term evaluation callbacks! */
1114 static CamelSExpResult *
1115 camel_sexp_term_evaluate_occur_times (CamelSExp *sexp,
1116 CamelSExpTerm *term,
1120 CamelSExpResult *result = NULL;
1122 CamelSExpResult **argv;
1125 g_return_val_if_fail (term != NULL, NULL);
1126 g_return_val_if_fail (start != NULL, NULL);
1127 g_return_val_if_fail (end != NULL, NULL);
1130 printf ("eval term :\n");
1131 parse_dump_term (t, 0);
1134 switch (term->type) {
1135 case CAMEL_SEXP_TERM_STRING:
1136 r (printf (" (string \"%s\")\n", term->value.string));
1137 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_STRING);
1138 result->value.string = g_strdup (term->value.string);
1140 case CAMEL_SEXP_TERM_IFUNC:
1141 case CAMEL_SEXP_TERM_FUNC:
1143 CamelSGeneratorFunc *generator = NULL;
1144 CamelSOperatorFunc *operator = NULL;
1146 r (printf (" (function \"%s\"\n", term->value.func.sym->name));
1148 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
1149 argc = term->value.func.termcount;
1150 argv = alloca (sizeof (argv[0]) * argc);
1152 for (i = 0; i < term->value.func.termcount; i++) {
1153 argv[i] = camel_sexp_term_evaluate_occur_times (
1154 sexp, term->value.func.terms[i], start, end);
1157 if (is_time_function (term->value.func.sym->name)) {
1159 if (term->value.func.sym->f.func)
1160 result = term->value.func.sym->f.func (sexp, term->value.func.termcount,
1161 argv, term->value.func.sym->data);
1162 } else if ((generator = get_generator_function (term->value.func.sym->name)) != NULL) {
1163 /* evaluate generator function */
1164 result->time_generator = TRUE;
1165 ok = generator (argc, argv, result);
1166 } else if ((operator = get_operator_function (term->value.func.sym->name)) != NULL)
1167 /* evaluate operator function */
1168 ok = operator (argc, argv, result);
1170 /* normal function: we need to scan all objects */
1171 result->time_generator = FALSE;
1174 camel_sexp_resultv_free (sexp, term->value.func.termcount, argv);
1177 case CAMEL_SEXP_TERM_INT:
1178 case CAMEL_SEXP_TERM_BOOL:
1179 case CAMEL_SEXP_TERM_TIME:
1187 camel_sexp_fatal_error (sexp, "Error in parse tree");
1190 result = camel_sexp_result_new (sexp, CAMEL_SEXP_RES_UNDEFINED);
1199 static CamelSExpTerm *
1200 parse_term_new (CamelSExp *sexp,
1203 CamelSExpTerm *term;
1205 term = camel_memchunk_alloc0 (sexp->term_chunks);
1212 parse_term_free (CamelSExp *sexp,
1213 CamelSExpTerm *term)
1221 switch (term->type) {
1222 case CAMEL_SEXP_TERM_INT:
1223 case CAMEL_SEXP_TERM_BOOL:
1224 case CAMEL_SEXP_TERM_TIME:
1225 case CAMEL_SEXP_TERM_VAR:
1228 case CAMEL_SEXP_TERM_STRING:
1229 g_free (term->value.string);
1232 case CAMEL_SEXP_TERM_FUNC:
1233 case CAMEL_SEXP_TERM_IFUNC:
1234 for (i = 0; i < term->value.func.termcount; i++) {
1235 parse_term_free (sexp, term->value.func.terms[i]);
1237 g_free (term->value.func.terms);
1241 printf ("parse_term_free: unknown type: %d\n", term->type);
1243 camel_memchunk_free (sexp->term_chunks, term);
1246 static CamelSExpTerm **
1247 parse_values (CamelSExp *sexp,
1251 CamelSExpTerm **terms;
1253 GScanner *gs = sexp->scanner;
1254 GSList *list = NULL, *l;
1256 p (printf ("parsing values\n"));
1258 while ( (token = g_scanner_peek_next_token (gs)) != G_TOKEN_EOF
1260 list = g_slist_prepend (list, parse_value (sexp));
1264 /* go over the list, and put them backwards into the term array */
1265 terms = g_malloc (size * sizeof (*terms));
1267 for (i = size - 1; i >= 0; i--) {
1271 l = g_slist_next (l);
1273 g_slist_free (list);
1275 p (printf ("found %d subterms\n", size));
1278 p (printf ("done parsing values\n"));
1283 * camel_sexp_parse_value:
1288 camel_sexp_parse_value (CamelSExp *sexp)
1290 return parse_value (sexp);
1293 static CamelSExpTerm *
1294 parse_value (CamelSExp *sexp)
1296 gint token, negative = FALSE;
1297 CamelSExpTerm *term = NULL;
1298 GScanner *gs = sexp->scanner;
1299 CamelSExpSymbol *sym;
1301 p (printf ("parsing value\n"));
1303 token = g_scanner_get_next_token (gs);
1307 case G_TOKEN_LEFT_PAREN:
1308 p (printf ("got brace, its a list!\n"));
1309 return parse_list (sexp, TRUE);
1310 case G_TOKEN_STRING:
1311 p (printf ("got string '%s'\n", g_scanner_cur_value (gs).v_string));
1312 term = parse_term_new (sexp, CAMEL_SEXP_TERM_STRING);
1313 term->value.string = g_strdup (g_scanner_cur_value (gs).v_string);
1316 p (printf ("got negative int?\n"));
1317 token = g_scanner_get_next_token (gs);
1318 if (token != G_TOKEN_INT) {
1319 camel_sexp_fatal_error (sexp, "Invalid format for a integer value");
1324 /* fall through... */
1326 term = parse_term_new (sexp, CAMEL_SEXP_TERM_INT);
1327 term->value.number = g_scanner_cur_value (gs).v_int;
1329 term->value.number = -term->value.number;
1330 p (printf ("got gint %d\n", term->value.number));
1335 p (printf ("got bool?\n"));
1336 token = g_scanner_get_next_token (gs);
1337 if (token != G_TOKEN_IDENTIFIER) {
1338 camel_sexp_fatal_error (sexp, "Invalid format for a boolean value");
1342 str = g_scanner_cur_value (gs).v_identifier;
1344 g_assert (str != NULL);
1345 if (!(strlen (str) == 1 && (str[0] == 't' || str[0] == 'f'))) {
1346 camel_sexp_fatal_error (sexp, "Invalid format for a boolean value");
1350 term = parse_term_new (sexp, CAMEL_SEXP_TERM_BOOL);
1351 term->value.boolean = (str[0] == 't');
1353 case G_TOKEN_SYMBOL:
1354 sym = g_scanner_cur_value (gs).v_symbol;
1355 p (printf ("got symbol '%s'\n", sym->name));
1356 switch (sym->type) {
1357 case CAMEL_SEXP_TERM_FUNC:
1358 case CAMEL_SEXP_TERM_IFUNC:
1359 /* this is basically invalid, since we can't use function
1360 * pointers, but let the runtime catch it ... */
1361 term = parse_term_new (sexp, sym->type);
1362 term->value.func.sym = sym;
1363 term->value.func.terms = parse_values (sexp, &term->value.func.termcount);
1365 case CAMEL_SEXP_TERM_VAR:
1366 term = parse_term_new (sexp, sym->type);
1367 term->value.var = sym;
1370 camel_sexp_fatal_error (sexp, "Invalid symbol type: %s: %d", sym->name, sym->type);
1373 case G_TOKEN_IDENTIFIER:
1374 p (printf ("got unknown identifider '%s'\n", g_scanner_cur_value (gs).v_identifier));
1375 camel_sexp_fatal_error (sexp, "Unknown identifier: %s", g_scanner_cur_value (gs).v_identifier);
1378 camel_sexp_fatal_error (sexp, "Unexpected token encountered: %d", token);
1380 p (printf ("done parsing value\n"));
1385 /* FIXME: this needs some robustification */
1386 static CamelSExpTerm *
1387 parse_list (CamelSExp *sexp,
1391 CamelSExpTerm *term = NULL;
1392 GScanner *gs = sexp->scanner;
1394 p (printf ("parsing list\n"));
1398 token = g_scanner_get_next_token (gs);
1400 token = g_scanner_get_next_token (gs);
1402 case G_TOKEN_SYMBOL: {
1403 CamelSExpSymbol *sym;
1405 sym = g_scanner_cur_value (gs).v_symbol;
1406 p (printf ("got funciton: %s\n", sym->name));
1407 term = parse_term_new (sexp, sym->type);
1408 p (printf ("created new list %p\n", t));
1409 /* if we have a variable, find out its base type */
1410 while (sym->type == CAMEL_SEXP_TERM_VAR) {
1411 sym = ((CamelSExpTerm *)(sym->data))->value.var;
1413 if (sym->type == CAMEL_SEXP_TERM_FUNC
1414 || sym->type == CAMEL_SEXP_TERM_IFUNC) {
1415 term->value.func.sym = sym;
1416 term->value.func.terms = parse_values (sexp, &term->value.func.termcount);
1418 parse_term_free (sexp, term);
1419 camel_sexp_fatal_error (sexp, "Trying to call variable as function: %s", sym->name);
1422 case G_TOKEN_IDENTIFIER:
1423 camel_sexp_fatal_error (sexp, "Unknown identifier: %s", g_scanner_cur_value (gs).v_identifier);
1425 case G_TOKEN_LEFT_PAREN:
1426 return parse_list (sexp, TRUE);
1428 camel_sexp_fatal_error (sexp, "Unexpected token encountered: %d", token);
1430 token = g_scanner_get_next_token (gs);
1432 camel_sexp_fatal_error (sexp, "Missing ')'");
1435 camel_sexp_fatal_error (sexp, "Missing '('");
1438 p (printf ("returning list %p\n", term));
1444 free_symbol (gpointer key,
1448 CamelSExpSymbol *sym = value;
1455 camel_sexp_finalize (GObject *object)
1457 CamelSExp *sexp = (CamelSExp *) object;
1460 parse_term_free (sexp, sexp->tree);
1464 camel_memchunk_destroy (sexp->term_chunks);
1465 camel_memchunk_destroy (sexp->result_chunks);
1467 g_scanner_scope_foreach_symbol (sexp->scanner, 0, free_symbol, NULL);
1468 g_scanner_destroy (sexp->scanner);
1470 /* Chain up to parent's finalize() method. */
1471 G_OBJECT_CLASS (camel_sexp_parent_class)->finalize (object);
1475 camel_sexp_class_init (CamelSExpClass *class)
1477 GObjectClass *object_class;
1479 object_class = G_OBJECT_CLASS (class);
1480 object_class->finalize = camel_sexp_finalize;
1483 /* 'builtin' functions */
1484 static const struct {
1487 gint type; /* set to 1 if a function can perform shortcut
1488 * evaluation, or doesn't execute everything,
1491 { "and", (CamelSExpFunc) term_eval_and, 1 },
1492 { "or", (CamelSExpFunc) term_eval_or, 1 },
1493 { "not", (CamelSExpFunc) term_eval_not, 0 },
1494 { "<", (CamelSExpFunc) term_eval_lt, 1 },
1495 { ">", (CamelSExpFunc) term_eval_gt, 1 },
1496 { "=", (CamelSExpFunc) term_eval_eq, 1 },
1497 { "+", (CamelSExpFunc) term_eval_plus, 0 },
1498 { "-", (CamelSExpFunc) term_eval_sub, 0 },
1499 { "cast-int", (CamelSExpFunc) term_eval_castint, 0 },
1500 { "cast-string", (CamelSExpFunc) term_eval_caststring, 0 },
1501 { "if", (CamelSExpFunc) term_eval_if, 1 },
1502 { "begin", (CamelSExpFunc) term_eval_begin, 1 },
1506 camel_sexp_init (CamelSExp *sexp)
1510 sexp->scanner = g_scanner_new (&scanner_config);
1511 sexp->term_chunks = camel_memchunk_new (16, sizeof (CamelSExpTerm));
1512 sexp->result_chunks = camel_memchunk_new (16, sizeof (CamelSExpResult));
1514 /* load in builtin symbols? */
1515 for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
1516 if (symbols[i].type == 1) {
1517 camel_sexp_add_ifunction (
1518 sexp, 0, symbols[i].name,
1519 (CamelSExpIFunc) symbols[i].func,
1520 (gpointer) &symbols[i]);
1522 camel_sexp_add_function (
1523 sexp, 0, symbols[i].name,
1525 (gpointer) &symbols[i]);
1536 camel_sexp_new (void)
1538 return g_object_new (CAMEL_TYPE_SEXP, NULL);
1542 * camel_sexp_add_function:
1547 camel_sexp_add_function (CamelSExp *sexp,
1553 CamelSExpSymbol *sym;
1555 g_return_if_fail (CAMEL_IS_SEXP (sexp));
1556 g_return_if_fail (name != NULL);
1558 camel_sexp_remove_symbol (sexp, scope, name);
1560 sym = g_malloc0 (sizeof (*sym));
1561 sym->name = g_strdup (name);
1563 sym->type = CAMEL_SEXP_TERM_FUNC;
1566 g_scanner_scope_add_symbol (sexp->scanner, scope, sym->name, sym);
1570 * camel_sexp_add_ifunction:
1575 camel_sexp_add_ifunction (CamelSExp *sexp,
1578 CamelSExpIFunc ifunc,
1581 CamelSExpSymbol *sym;
1583 g_return_if_fail (CAMEL_IS_SEXP (sexp));
1584 g_return_if_fail (name != NULL);
1586 camel_sexp_remove_symbol (sexp, scope, name);
1588 sym = g_malloc0 (sizeof (*sym));
1589 sym->name = g_strdup (name);
1590 sym->f.ifunc = ifunc;
1591 sym->type = CAMEL_SEXP_TERM_IFUNC;
1594 g_scanner_scope_add_symbol (sexp->scanner, scope, sym->name, sym);
1598 * camel_sexp_add_variable:
1603 camel_sexp_add_variable (CamelSExp *sexp,
1606 CamelSExpTerm *value)
1608 CamelSExpSymbol *sym;
1610 g_return_if_fail (CAMEL_IS_SEXP (sexp));
1611 g_return_if_fail (name != NULL);
1613 sym = g_malloc0 (sizeof (*sym));
1614 sym->name = g_strdup (name);
1615 sym->type = CAMEL_SEXP_TERM_VAR;
1618 g_scanner_scope_add_symbol (sexp->scanner, scope, sym->name, sym);
1622 * camel_sexp_remove_symbol:
1627 camel_sexp_remove_symbol (CamelSExp *sexp,
1632 CamelSExpSymbol *sym;
1634 g_return_if_fail (CAMEL_IS_SEXP (sexp));
1635 g_return_if_fail (name != NULL);
1637 oldscope = g_scanner_set_scope (sexp->scanner, scope);
1638 sym = g_scanner_lookup_symbol (sexp->scanner, name);
1639 g_scanner_scope_remove_symbol (sexp->scanner, scope, name);
1640 g_scanner_set_scope (sexp->scanner, oldscope);
1648 * camel_sexp_set_scope:
1653 camel_sexp_set_scope (CamelSExp *sexp,
1656 g_return_val_if_fail (CAMEL_IS_SEXP (sexp), 0);
1658 return g_scanner_set_scope (sexp->scanner, scope);
1662 * camel_sexp_input_text:
1667 camel_sexp_input_text (CamelSExp *sexp,
1671 g_return_if_fail (CAMEL_IS_SEXP (sexp));
1672 g_return_if_fail (text != NULL);
1674 g_scanner_input_text (sexp->scanner, text, len);
1678 * camel_sexp_input_file:
1683 camel_sexp_input_file (CamelSExp *sexp,
1686 g_return_if_fail (CAMEL_IS_SEXP (sexp));
1688 g_scanner_input_file (sexp->scanner, fd);
1697 camel_sexp_parse (CamelSExp *sexp)
1699 g_return_val_if_fail (CAMEL_IS_SEXP (sexp), -1);
1701 if (setjmp (sexp->failenv)) {
1702 g_warning ("Error in parsing: %s", sexp->error);
1707 parse_term_free (sexp, sexp->tree);
1709 sexp->tree = parse_value (sexp);
1720 camel_sexp_eval (CamelSExp *sexp)
1722 g_return_val_if_fail (CAMEL_IS_SEXP (sexp), NULL);
1723 g_return_val_if_fail (sexp->tree != NULL, NULL);
1725 if (setjmp (sexp->failenv)) {
1726 g_warning ("Error in execution: %s", sexp->error);
1730 return camel_sexp_term_eval (sexp, sexp->tree);
1734 * e_cal_backend_sexp_evaluate_occur_times:
1735 * @f: An #CamelSExp object.
1736 * @start: Start of the time window will be stored here.
1737 * @end: End of the time window will be stored here.
1739 * Determines biggest time window given by expressions "occur-in-range" in sexp.
1744 camel_sexp_evaluate_occur_times (CamelSExp *sexp,
1748 CamelSExpResult *result;
1750 g_return_val_if_fail (CAMEL_IS_SEXP (sexp), FALSE);
1751 g_return_val_if_fail (sexp->tree != NULL, FALSE);
1752 g_return_val_if_fail (start != NULL, FALSE);
1753 g_return_val_if_fail (end != NULL, FALSE);
1757 if (setjmp (sexp->failenv)) {
1758 g_warning ("Error in execution: %s", sexp->error);
1762 result = camel_sexp_term_evaluate_occur_times (
1763 sexp, sexp->tree, start, end);
1764 generator = result->time_generator;
1767 *start = result->occuring_start;
1768 *end = result->occuring_end;
1771 camel_sexp_result_free (sexp, result);
1777 * camel_sexp_encode_bool:
1781 * Encode a bool into an s-expression @string. Bools are
1782 * encoded using #t #f syntax.
1787 camel_sexp_encode_bool (GString *string,
1791 g_string_append (string, " #t");
1793 g_string_append (string, " #f");
1797 * camel_sexp_encode_string:
1798 * @string: Destination string.
1799 * @v_string: String expression.
1801 * Add a c string @v_string to the s-expression stored in
1802 * the gstring @s. Quotes are added, and special characters
1803 * are escaped appropriately.
1808 camel_sexp_encode_string (GString *string,
1809 const gchar *v_string)
1814 if (v_string == NULL)
1818 g_string_append (string, " \"");
1819 while ((c = *p++)) {
1820 if (c == '\\' || c == '\"' || c == '\'')
1821 g_string_append_c (string, '\\');
1822 g_string_append_c (string, c);
1824 g_string_append (string, "\"");
1833 gchar *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")";
1834 CamelSExpResult *result;
1838 sexp = camel_sexp_new ();
1840 camel_sexp_add_variable (sexp, 0, "test", NULL);
1842 if (argc < 2 || !argv[1])
1845 camel_sexp_input_text (sexp, t, t);
1846 camel_sexp_parse (sexp);
1849 parse_dump_term (sexp->tree, 0);
1851 result = camel_sexp_eval (sexp);
1853 eval_dump_result (result, 0);
1855 printf ("no result?|\n");