/* * Copyright 2000 HelixCode (http://www.helixcode.com). * * A simple, extensible s-exp evaluation engine. * * Author : * Michael Zucchi * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ /* The following built-in s-exp's are supported: list = (and list*) perform an intersection of a number of lists, and return that. bool = (and bool*) perform a boolean AND of boolean values. list = (or list*) perform a union of a number of lists, returning the new list. bool = (or bool*) perform a boolean OR of boolean values. int = (+ int*) Add integers. string = (+ string*) Concat strings. int = (- int int*) Subtract integers from the first. Comparison operators: bool = (< int int) bool = (> int int) bool = (= int int) bool = (< string string) bool = (> string string) bool = (= string string) Perform a comparision of 2 integers, or 2 string values. Function flow: type = (if bool function) type = (if bool function function) Choose a flow path based on a boolean value type = (begin func func func) Execute a sequence. The last function return is the return type. */ #include #include #include #include #include #include "e-sexp.h" #define p(x) /* parse debug */ #define r(x) /* run debug */ #define d(x) /* general debug */ static struct _ESExpTerm * parse_list(ESExp *f, int gotbrace); static struct _ESExpTerm * parse_value(ESExp *f); static void parse_dump_term(struct _ESExpTerm *t, int depth); static GtkObjectClass *parent_class; static GScannerConfig scanner_config = { ( " \t\r\n") /* cset_skip_characters */, ( G_CSET_a_2_z "_+-<=>" G_CSET_A_2_Z) /* cset_identifier_first */, ( G_CSET_a_2_z "_0123456789-<>" G_CSET_A_2_Z G_CSET_LATINS G_CSET_LATINC ) /* cset_identifier_nth */, ( ";\n" ) /* cpair_comment_single */, FALSE /* case_sensitive */, TRUE /* skip_comment_multi */, TRUE /* skip_comment_single */, TRUE /* scan_comment_multi */, TRUE /* scan_identifier */, TRUE /* scan_identifier_1char */, FALSE /* scan_identifier_NULL */, TRUE /* scan_symbols */, FALSE /* scan_binary */, TRUE /* scan_octal */, TRUE /* scan_float */, TRUE /* scan_hex */, FALSE /* scan_hex_dollar */, TRUE /* scan_string_sq */, TRUE /* scan_string_dq */, TRUE /* numbers_2_int */, FALSE /* int_2_float */, FALSE /* identifier_2_string */, TRUE /* char_2_token */, FALSE /* symbol_2_token */, FALSE /* scope_0_fallback */, }; struct _ESExpResult * e_sexp_result_new(int type) { struct _ESExpResult *r = g_malloc0(sizeof(*r)); r->type = type; return r; } void e_sexp_result_free(struct _ESExpResult *t) { if (t == NULL) return; switch(t->type) { case ESEXP_RES_ARRAY_PTR: g_ptr_array_free(t->value.ptrarray, TRUE); break; case ESEXP_RES_BOOL: case ESEXP_RES_INT: break; case ESEXP_RES_STRING: g_free(t->value.string); break; case ESEXP_RES_UNDEFINED: break; } g_free(t); } /* implementations for the builtin functions */ /* can you tell, i dont like glib? */ /* we can only itereate a hashtable from a called function */ struct _glib_sux_donkeys { int count; GPtrArray *uids; }; /* ok, store any values that are in all sets */ static void g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup) { if (value == fuckup->count) { g_ptr_array_add(fuckup->uids, key); } } /* or, store all unique values */ static void g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup) { g_ptr_array_add(fuckup->uids, key); } static ESExpResult * term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r, *r1; GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal); struct _glib_sux_donkeys lambdafoo; int type=-1; int bool = TRUE; int i; r(printf("( and\n")); r = e_sexp_result_new(ESEXP_RES_UNDEFINED); for (i=0;bool && itype; if (type != r1->type) { printf("invalid types in and operation, all types must be the same\n"); } else if ( r1->type == ESEXP_RES_ARRAY_PTR ) { char **a1; int l1, j; a1 = (char **)r1->value.ptrarray->pdata; l1 = r1->value.ptrarray->len; for (j=0;jtype == ESEXP_RES_BOOL ) { bool &= r1->value.bool; } e_sexp_result_free(r1); } if (type == ESEXP_RES_ARRAY_PTR) { lambdafoo.count = argc; lambdafoo.uids = g_ptr_array_new(); g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo); r->type = ESEXP_RES_ARRAY_PTR; r->value.ptrarray = lambdafoo.uids; } else if (type == ESEXP_RES_BOOL) { r->type = ESEXP_RES_BOOL; r->value.bool = bool; } g_hash_table_destroy(ht); return r; } static ESExpResult * term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r, *r1; GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal); struct _glib_sux_donkeys lambdafoo; int type = -1; int bool = FALSE; int i; r(printf("(or \n")); r = e_sexp_result_new(ESEXP_RES_UNDEFINED); for (i=0;!bool && itype; if (r1->type != type) { printf("wrong types in or operation\n"); } else if (r1->type == ESEXP_RES_ARRAY_PTR) { char **a1; int l1, j; a1 = (char **)r1->value.ptrarray->pdata; l1 = r1->value.ptrarray->len; for (j=0;jtype == ESEXP_RES_BOOL) { bool |= r1->value.bool; } e_sexp_result_free(r1); } if (type == ESEXP_RES_ARRAY_PTR) { lambdafoo.count = argc; lambdafoo.uids = g_ptr_array_new(); g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo); r->type = ESEXP_RES_ARRAY_PTR; r->value.ptrarray = lambdafoo.uids; } else if (type == ESEXP_RES_BOOL) { r->type = ESEXP_RES_BOOL; r->value.bool = bool; } g_hash_table_destroy(ht); return r; } static ESExpResult * term_eval_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { int res = TRUE; ESExpResult *r; if (argc>0) { if (argv[0]->type == ESEXP_RES_BOOL && argv[0]->value.bool) res = FALSE; } r = e_sexp_result_new(ESEXP_RES_BOOL); r->value.bool = res; return r; } /* this should support all arguments ...? */ static ESExpResult * term_eval_lt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r, *r1, *r2; r = e_sexp_result_new(ESEXP_RES_UNDEFINED); if (argc == 2) { r1 = e_sexp_term_eval(f, argv[0]); r2 = e_sexp_term_eval(f, argv[1]); if (r1->type != r2->type) { printf("error, invalid types in compare\n"); } else if (r1->type == ESEXP_RES_INT) { r->type = ESEXP_RES_BOOL; r->value.bool = r1->value.number < r2->value.number; } else if (r1->type == ESEXP_RES_STRING) { r->type = ESEXP_RES_BOOL; r->value.bool = strcmp(r1->value.string, r2->value.string) < 0; } } return r; } /* this should support all arguments ...? */ static ESExpResult * term_eval_gt(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r, *r1, *r2; r = e_sexp_result_new(ESEXP_RES_UNDEFINED); if (argc == 2) { r1 = e_sexp_term_eval(f, argv[0]); r2 = e_sexp_term_eval(f, argv[1]); if (r1->type != r2->type) { printf("error, invalid types in compare\n"); } else if (r1->type == ESEXP_RES_INT) { r->type = ESEXP_RES_BOOL; r->value.bool = r1->value.number > r2->value.number; } else if (r1->type == ESEXP_RES_STRING) { r->type = ESEXP_RES_BOOL; r->value.bool = strcmp(r1->value.string, r2->value.string) > 0; } } return r; } /* this should support all arguments ...? */ static ESExpResult * term_eval_eq(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r, *r1, *r2; r = e_sexp_result_new(ESEXP_RES_BOOL); if (argc == 2) { r1 = e_sexp_term_eval(f, argv[0]); r2 = e_sexp_term_eval(f, argv[1]); if (r1->type != r2->type) { r->value.bool = FALSE; } else if (r1->type == ESEXP_RES_INT) { r->value.bool = r1->value.number == r2->value.number; } else if (r1->type == ESEXP_RES_BOOL) { r->value.bool = r1->value.bool == r2->value.bool; } else if (r1->type == ESEXP_RES_STRING) { r->value.bool = strcmp(r1->value.string, r2->value.string) == 0; } } return r; } static ESExpResult * term_eval_plus(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { struct _ESExpResult *r=NULL; int type; int i; if (argc>0) { type = argv[0]->type; switch(type) { case ESEXP_RES_INT: { int total = argv[0]->value.number; for (i=1;itype == ESEXP_RES_INT;i++) { total += argv[i]->value.number; } if (ivalue.number = total; break; } case ESEXP_RES_STRING: { GString *s = g_string_new(argv[0]->value.string); for (i=1;itype == ESEXP_RES_STRING;i++) { g_string_append(s, argv[i]->value.string); } if (ivalue.string = s->str; g_string_free(s, FALSE); break; } } } if (!r) { r = e_sexp_result_new(ESEXP_RES_INT); r->value.number = 0; } return r; } static ESExpResult * term_eval_sub(struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { struct _ESExpResult *r=NULL; int type; int i; if (argc>0) { type = argv[0]->type; switch(type) { case ESEXP_RES_INT: { int total = argv[0]->value.number; for (i=1;itype == ESEXP_RES_INT;i++) { total -= argv[i]->value.number; } if (ivalue.number = total; break; } } } if (!r) { r = e_sexp_result_new(ESEXP_RES_INT); r->value.number = 0; } return r; } /* implements 'if' function */ static ESExpResult * term_eval_if(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r; int doit; if (argc >=2 && argc<=3) { r = e_sexp_term_eval(f, argv[0]); doit = (r->type == ESEXP_RES_BOOL && r->value.bool); e_sexp_result_free(r); if (doit) { return e_sexp_term_eval(f, argv[1]); } else if (argc>2) { return e_sexp_term_eval(f, argv[2]); } } return e_sexp_result_new(ESEXP_RES_UNDEFINED); } /* implements 'begin' statement */ static ESExpResult * term_eval_begin(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data) { struct _ESExpResult *r=NULL; int i; for (i=0;itype = ESEXP_RES_UNDEFINED; switch (t->type) { case ESEXP_TERM_STRING: r(printf(" (string \"%s\")\n", t->value.string)); r->type = ESEXP_RES_STRING; /* erk, this shoul;dn't need to strdup this ... */ r->value.string = g_strdup(t->value.string); break; case ESEXP_TERM_INT: r(printf(" (int %d)\n", t->value.number)); r->type = ESEXP_RES_INT; r->value.number = t->value.number; break; case ESEXP_TERM_BOOL: r(printf(" (int %d)\n", t->value.number)); r->type = ESEXP_RES_BOOL; r->value.bool = t->value.bool; break; case ESEXP_TERM_IFUNC: { if (t->value.func.sym->f.ifunc) { r1 = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data); if (r1) { e_sexp_result_free(r); r = r1; } } break; } case ESEXP_TERM_FUNC: { struct _ESExpResult **argv; /* first evaluate all arguments to result types */ argv = alloca(sizeof(argv[0]) * t->value.func.termcount); for (i=0;ivalue.func.termcount;i++) { argv[i] = e_sexp_term_eval(f, t->value.func.terms[i]); } /* call the function */ if (t->value.func.sym->f.func) { r1 = t->value.func.sym->f.func(f, t->value.func.termcount, argv, t->value.func.sym->data); if (r1) { e_sexp_result_free(r); r = r1; } } for (i=0;ivalue.func.termcount;i++) { e_sexp_result_free(argv[i]); } break; } default: printf("Warning: Unknown type encountered in parse tree: %d\n", t->type); r->type = ESEXP_RES_UNDEFINED; } return r; } #if 0 static void eval_dump_result(ESExpResult *r, int depth) { int i; if (r==NULL) { printf("null result???\n"); return; } for (i=0;itype) { case ESEXP_RES_ARRAY_PTR: printf("array pointers\n"); break; case ESEXP_RES_INT: printf("int: %d\n", r->value.number); break; case ESEXP_RES_STRING: printf("string: '%s'\n", r->value.string); break; case ESEXP_RES_BOOL: printf("bool: %c\n", r->value.bool?'t':'f'); break; case ESEXP_RES_UNDEFINED: printf(" \n"); break; } printf("\n"); } #endif static void parse_dump_term(struct _ESExpTerm *t, int depth) { int i; if (t==NULL) { printf("null term??\n"); return; } for (i=0;itype) { case ESEXP_TERM_STRING: printf(" \"%s\"", t->value.string); break; case ESEXP_TERM_INT: printf(" %d", t->value.number); break; case ESEXP_TERM_BOOL: printf(" #%c", t->value.bool?'t':'f'); break; case ESEXP_TERM_IFUNC: case ESEXP_TERM_FUNC: printf(" (function %s\n", t->value.func.sym->name); /*printf(" [%d] ", t->value.func.termcount);*/ for (i=0;ivalue.func.termcount;i++) { parse_dump_term(t->value.func.terms[i], depth+1); } for (i=0;ivalue.var->name); break; default: printf("unknown type: %d\n", t->type); } printf("\n"); } /* PARSER */ static struct _ESExpTerm * parse_new_term(int type) { struct _ESExpTerm *s = g_malloc0(sizeof(*s)); s->type = type; return s; } static void parse_term_free(struct _ESExpTerm *t) { int i; if (t==NULL) { return; } switch (t->type) { case ESEXP_TERM_FUNC: case ESEXP_TERM_IFUNC: for (i=0;ivalue.func.termcount;i++) { parse_term_free(t->value.func.terms[i]); } g_free(t->value.func.terms); break; case ESEXP_TERM_VAR: break; case ESEXP_TERM_STRING: g_free(t->value.string); break; case ESEXP_TERM_INT: break; default: printf("parse_term_free: unknown type: %d\n", t->type); } g_free(t); } static struct _ESExpTerm ** parse_values(ESExp *f, int *len) { int token; struct _ESExpTerm **terms; int i=0; GScanner *gs = f->scanner; p(printf("parsing values\n")); /* FIXME: This hardcoded nonsense!!! :) */ terms = g_malloc0(20*sizeof(*terms)); while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF && token != ')') { terms[i]=parse_value(f); i++; } p(printf("found %d subterms\n", i)); *len = i; p(printf("dont parsing values\n")); return terms; } static struct _ESExpTerm * parse_value(ESExp *f) { int token; struct _ESExpTerm *t = NULL; GScanner *gs = f->scanner; struct _ESExpSymbol *s; p(printf("parsing value\n")); token = g_scanner_get_next_token(gs); switch(token) { case G_TOKEN_LEFT_PAREN: p(printf("got brace, its a list!\n")); return parse_list(f, TRUE); case G_TOKEN_STRING: p(printf("got string\n")); t = parse_new_term(ESEXP_TERM_STRING); t->value.string = g_strdup(g_scanner_cur_value(gs).v_string); break; case G_TOKEN_INT: t = parse_new_term(ESEXP_TERM_INT); t->value.number = g_scanner_cur_value(gs).v_int; p(printf("got int\n")); break; case '#': printf("got bool?\n"); token = g_scanner_get_next_token(gs); t = parse_new_term(ESEXP_TERM_BOOL); t->value.bool = token=='t'; break; case G_TOKEN_SYMBOL: s = g_scanner_cur_value(gs).v_symbol; switch (s->type) { case ESEXP_TERM_FUNC: case ESEXP_TERM_IFUNC: /* this is basically invalid, since we can't use function pointers, but let the runtime catch it ... */ t = parse_new_term(s->type); t->value.func.sym = s; t->value.func.terms = parse_values(f, &t->value.func.termcount); break; case ESEXP_TERM_VAR: t = parse_new_term(s->type); t->value.var = s; break; default: printf("Invalid symbol type: %d\n", s->type); } break; case G_TOKEN_IDENTIFIER: printf("Unknown identifier encountered: %s\n", g_scanner_cur_value(gs).v_identifier); break; default: printf("Innvalid token trying to parse a list of values\n"); } p(printf("done parsing value\n")); return t; } /* FIXME: this needs some robustification */ static struct _ESExpTerm * parse_list(ESExp *f, int gotbrace) { int token; struct _ESExpTerm *t = NULL; GScanner *gs = f->scanner; p(printf("parsing list\n")); if (gotbrace) token = '('; else token = g_scanner_get_next_token(gs); if (token =='(') { token = g_scanner_get_next_token(gs); switch(token) { case G_TOKEN_SYMBOL: { struct _ESExpSymbol *s; s = g_scanner_cur_value(gs).v_symbol; p(printf("got funciton: %s\n", s->name)); t = parse_new_term(s->type); p(printf("created new list %p\n", t)); /* if we have a variable, find out its base type */ while (s->type == ESEXP_TERM_VAR) { s = ((ESExpTerm *)(s->data))->value.var; } if (s->type == ESEXP_TERM_FUNC || s->type == ESEXP_TERM_IFUNC) { t->value.func.sym = s; t->value.func.terms = parse_values(f, &t->value.func.termcount); } else { printf("Error, trying to call variable as function\n"); } break; } case G_TOKEN_IDENTIFIER: printf("Unknown identifier: %s\n", g_scanner_cur_value(gs).v_identifier); break; default: printf("unknown sequence encountered, type = %d\n", token); } token = g_scanner_get_next_token(gs); if (token != ')') { printf("Error, expected ')' not found\n"); } } else { printf("Error, list term without opening (\n"); } p(printf("returning list %p\n", t)); return t; } #if 0 GList * camel_mbox_folder_search_by_expression(CamelFolder *folder, char *expression, CamelException *ex) { GScanner *gs; int i; struct _ESExpTerm *t; struct _searchcontext *ctx; struct _ESExpResult *r; GList *matches = NULL; gs = g_scanner_new(&scanner_config); for(i=0;ifolder = folder; ctx->summary = camel_folder_get_summary(folder, ex); ctx->message_info = camel_folder_summary_get_message_info_list(ctx->summary); #ifdef HAVE_IBEX ctx->index = ibex_open(CAMEL_MBOX_FOLDER(folder)->index_file_path, FALSE); if (!ctx->index) { perror("Cannot open index file, body searches will be ignored\n"); } #endif r = term_eval(ctx, t); /* now create a folder summary to return?? */ if (r && r->type == ESEXP_RES_ARRAY_PTR) { d(printf("got result ...\n")); for (i=0;ivalue.ptrarray->len;i++) { d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i))); matches = g_list_prepend(matches, g_strdup(g_ptr_array_index(r->value.ptrarray, i))); } e_sexp_result_free(r); } if (ctx->index) ibex_close(ctx->index); gtk_object_unref((GtkObject *)ctx->summary); g_free(ctx); parse_term_free(t); } else { printf("Warning, Could not parse expression!\n %s\n", expression); } g_scanner_destroy(gs); return matches; } #endif static void e_sexp_finalise(GtkObject *); static void e_sexp_class_init (ESExpClass *class) { GtkObjectClass *object_class; object_class = (GtkObjectClass *) class; object_class->finalize = e_sexp_finalise; parent_class = gtk_type_class (gtk_object_get_type ()); } /* 'builtin' functions */ static struct { char *name; ESExpFunc *func; int type; /* set to 1 if a function can perform shortcut evaluation, or doesn't execute everything, 0 otherwise */ } symbols[] = { { "and", (ESExpFunc *)term_eval_and, 1 }, { "or", (ESExpFunc *)term_eval_or, 1 }, { "not", (ESExpFunc *)term_eval_not, 0 }, { "<", (ESExpFunc *)term_eval_lt, 1 }, { ">", (ESExpFunc *)term_eval_gt, 1 }, { "=", (ESExpFunc *)term_eval_eq, 1 }, { "+", (ESExpFunc *)term_eval_plus, 0 }, { "-", (ESExpFunc *)term_eval_sub, 0 }, { "if", (ESExpFunc *)term_eval_if, 1 }, { "begin", (ESExpFunc *)term_eval_begin, 1 }, }; static void free_symbol(void *key, void *value, void *data) { struct _ESExpSymbol *s = value; g_free(s->name); g_free(s); } static void e_sexp_finalise(GtkObject *o) { ESExp *s = (ESExp *)o; if (s->tree) { parse_term_free(s->tree); s->tree = NULL; } g_scanner_scope_foreach_symbol(s->scanner, 0, free_symbol, 0); g_scanner_destroy(s->scanner); ((GtkObjectClass *)(parent_class))->finalize((GtkObject *)o); } static void e_sexp_init (ESExp *s) { int i; s->scanner = g_scanner_new(&scanner_config); /* load in builtin symbols? */ for(i=0;iname = g_strdup(name); s->f.func = func; s->type = ESEXP_TERM_FUNC; s->data = data; g_scanner_scope_add_symbol(f->scanner, scope, s->name, s); } void e_sexp_add_ifunction(ESExp *f, int scope, char *name, ESExpIFunc *ifunc, void *data) { struct _ESExpSymbol *s; g_return_if_fail(FILTER_IS_SEXP(f)); g_return_if_fail(name != NULL); s = g_malloc0(sizeof(*s)); s->name = g_strdup(name); s->f.ifunc = ifunc; s->type = ESEXP_TERM_IFUNC; s->data = data; g_scanner_scope_add_symbol(f->scanner, scope, s->name, s); } void e_sexp_add_variable(ESExp *f, int scope, char *name, ESExpTerm *value) { struct _ESExpSymbol *s; g_return_if_fail(FILTER_IS_SEXP(f)); g_return_if_fail(name != NULL); s = g_malloc0(sizeof(*s)); s->name = g_strdup(name); s->type = ESEXP_TERM_VAR; s->data = value; g_scanner_scope_add_symbol(f->scanner, scope, s->name, s); } void e_sexp_remove_symbol(ESExp *f, int scope, char *name) { int oldscope; struct _ESExpSymbol *s; g_return_if_fail(FILTER_IS_SEXP(f)); g_return_if_fail(name != NULL); oldscope = g_scanner_set_scope(f->scanner, scope); s = g_scanner_lookup_symbol(f->scanner, name); g_scanner_scope_remove_symbol(f->scanner, scope, name); g_scanner_set_scope(f->scanner, oldscope); if (s) { g_free(s->name); g_free(s); } } int e_sexp_set_scope(ESExp *f, int scope) { g_return_val_if_fail(FILTER_IS_SEXP(f), 0); return g_scanner_set_scope(f->scanner, scope); } void e_sexp_input_text(ESExp *f, const char *text, int len) { g_return_if_fail(FILTER_IS_SEXP(f)); g_return_if_fail(text != NULL); g_scanner_input_text(f->scanner, text, len); } void e_sexp_input_file (ESExp *f, int fd) { g_return_if_fail(FILTER_IS_SEXP(f)); g_scanner_input_file(f->scanner, fd); } /* needs some error return? */ void e_sexp_parse(ESExp *f) { g_return_if_fail(FILTER_IS_SEXP(f)); if (f->tree) parse_term_free(f->tree); f->tree = parse_list(f, FALSE); } struct _ESExpResult * e_sexp_eval(ESExp *f) { g_return_val_if_fail(FILTER_IS_SEXP(f), NULL); g_return_val_if_fail(f->tree != NULL, NULL); return e_sexp_term_eval(f, f->tree); } /** * e_sexp_encode_bool: * @s: * @state: * * Encode a bool into an s-expression @s. Bools are * encoded using #t #f syntax. **/ void e_sexp_encode_bool(GString *s, gboolean state) { if (state) g_string_append(s, " #t"); else g_string_append(s, " #f"); } /** * e_sexp_encode_string: * @s: Destination string. * @string: String expression. * * Add a c string @string to the s-expression stored in * the gstring @s. Quotes are added, and special characters * are escaped appropriately. **/ void e_sexp_encode_string(GString *s, const char *string) { char c; const char *p; p = string; g_string_append(s, " \""); while ( (c = *p++) ) { if (c=='\\' || c=='\"' || c=='\'') g_string_append_c(s, '\\'); g_string_append_c(s, c); } g_string_append(s, "\""); } #ifdef TESTER int main(int argc, char **argv) { ESExp *f; char *t = "(+ \"foo\" \"\\\"\" \"bar\" \"\\\\ blah \\x \")"; ESExpResult *r; gtk_init(&argc, &argv); f = e_sexp_new(); e_sexp_add_variable(f, 0, "test", NULL); e_sexp_input_text(f, t, strlen(t)); e_sexp_parse(f); if (f->tree) { parse_dump_term(f->tree, 0); } r = e_sexp_eval(f); if (r) { eval_dump_result(r, 0); } else { printf("no result?|\n"); } return 0; } #endif Reset maintainer, email bouncesantoine2014-06-281-1/+1 * - Marked BROKEN, since no public distfilesxride2014-06-261-2/+4 * Remove IS_INTERACTIVE.kuriyama2014-06-241-8/+1 * Deprecate unmaintained interactive ports for removal in 2 monthsmarino2014-06-211-0/+3 * Stagefydaichi2014-06-133-149/+124 * - Stagify.kuriyama2014-06-092-6/+4 * - Update to 1.6.0olivierd2014-06-063-5/+12 * - Convert misc/xosd and dependent ports which need it (deskutils/xneur, polis...amdmi32014-05-271-2/+2 * - Fix build on -currentmiwi2014-05-174-47/+61 * Convert x11-toolkits/unique to "USES=libtool pathfix tar:bzip2".tijl2014-05-131-1/+1 * KDE/FreeBSD team presents KDE SC 4.12.5 and KDE Workspace 4.11.9!makc2014-05-114-8/+8 * - Fix build on i386miwi2014-04-294-48/+26 * The FreeBSD x11@ and graphics team proudly presentszeising2014-04-179-9/+9 * KDE/FreeBSD team presents KDE SC 4.12.4 and KDE Workspace 4.11.8!makc2014-04-038-16/+12 * KDE/FreeBSD team presents KDE SC 4.12.3 and KDE Workspace 4.11.7!makc2014-03-054-8/+8 * - Update MASTER_SITESmiwi2014-02-272-20/+16 * x11-clocks/wmfuzzy: Update at 1 hertz instead of 10 khzmarino2014-02-262-4/+15 * Remove trailing whitespaces from category x11-clocksehaupt2014-02-212-2/+2 * - Bump PORTREVISION after KDE4_PREFIX changemakc2014-02-182-1/+2 * KDE/FreeBSD team presents KDE SC 4.12.2 and KDE Workspace 4.11.6!makc2014-02-1817-61/+128 * According to the Porter's Handbook (5.12.2.3.) default options must be added toehaupt2014-02-102-0/+6 * - Fix make stage [1]novel2014-02-061-1/+2 * - Support STAGEDIRolivierd2014-01-297-12/+15 * - Stagify, convert to OptionsNG, remove check for alpha (unsupported)danfe2014-01-282-34/+14 * Fix properties on pkg-plistbapt2014-01-222-2/+0 * Reduce over inclusion of bsd.port.mkbapt2014-01-171-6/+2 * Support stagedir.vanilla2014-01-1133-117/+124 * - Convert to USES=tkgahr2014-01-102-13/+3 * - Fix build with clangantoine2014-01-091-2/+3 * - Fix pkg-plistjhale2014-01-021-5/+0 * Stage supportantoine2013-12-302-6/+4 * Stage supportantoine2013-12-291-4/+3 * Stage supportantoine2013-12-292-10/+8 * Stage supportantoine2013-12-291-8/+5 * Stage supportantoine2013-12-291-3/+2 * Update to 2.40wxs2013-12-292-3/+3 * Stage supportantoine2013-12-281-3/+1 * Stage supportantoine2013-12-281-6/+2 * - Update to 4.1.4jhale2013-12-202-4/+3 * Switch FreeBSD CURRENT to use the new xorg stack (WITH_NEW_XORG=) [0]zeising2013-12-164-6/+2 * - Fix the usage of 'python' to get rid of the implicit lang/pythonmva2013-12-081-2/+2 * - Return almost all of my ports back to the pool. I have no time to make anyaraujo2013-11-291-1/+1 * - revert r331810dinoex2013-10-291-3/+2 * - use STAGEDIRdinoex2013-10-281-4/+1 * Update to libmpc version 1.0.1 which brings the following fixes:gerald2013-10-263-1/+3 * Support staging.ehaupt2013-10-241-2/+1 * - Remove manual creation and removal of share/applications, as it's now in th...amdmi32013-10-224-4/+0 * - Convert to stagingeadler2013-10-131-8/+6 * fixed build fail on 10-CURRENTdaichi2013-10-051-0/+6 * - Support stagingjhale2013-10-031-2/+1 * - Update to 4.1.3jhale2013-09-293-4/+8 * - fix misplaced NO_STAGE in slaveports and ifdefsdinoex2013-09-211-1/+1 * Add NO_STAGE all over the place in preparation for the staging support (cat: ...bapt2013-09-2157-115/+77 * Remove USE_GCC=any: builds properly with clangbapt2013-09-141-1/+0 * Remove USE_GCC=any, builds properly with clangbapt2013-09-141-1/+0 * - Update to 4.1.2jhale2013-09-123-12/+94 * Add explicit dependency on pkgconf (27 ports)marino2013-09-121-1/+1 * Add an explicit dependency on pkgconfantoine2013-09-101-5/+2 * Update to 1.0.7zeising2013-09-082-3/+3 * Add an explicit dependency on pkgconfbapt2013-09-061-2/+1 * Add an explicit dependency on pkgconfbapt2013-09-032-11/+4 * Add an explicit dependency on pkgconfbapt2013-09-031-2/+1 * Two imake related changes:tijl2013-09-022-8/+26 * - Remove MAKE_JOBS_SAFE variableak2013-08-156-6/+0 * Update to 2.39.wxs2013-08-052-3/+3 * - Convert to new perl frameworkaz2013-08-031-1/+2 * Fix build with clangbapt2013-08-011-6/+3 * Fix build with clangbapt2013-08-011-6/+3 * KDE3 and QT3 expired on 2013-07-01, remove these ports.rene2013-07-275-708/+0 * Remove MAKE_JOBS_SAFE which is now default.ehaupt2013-07-241-1/+0 * Update to 2.38.wxs2013-07-092-3/+3 * Update the KDE Software Compilation to 4.10.5.rakuco2013-07-052-4/+4 * Update to KDE SC 4.10.4, proudly presented by the KDE on FreeBSD team.rakuco2013-07-032-4/+4 * Convert to USES=imakebapt2013-06-298-49/+19 * New USES imake to handle the dependency on imake.bapt2013-06-286-18/+9 * Add explicit dependency on iconv.zeising2013-06-271-0/+2 * Reset maintaner per Bruce Cran's request.zeising2013-06-271-6/+2 * - Do not try to remove dirs. not created by the portmiwi2013-06-011-3/+0 * The FreeBSD x11 team proudly presentszeising2013-05-252-10/+0 * KDE/FreeBSD team presents KDE SC 4.10.3 ports!makc2013-05-192-4/+4 * - Update to 1.5.0olivierd2013-05-123-5/+4 * - Update MASTER_SITESmiwi2013-05-102-9/+5 * - Bump PORTREVISION after update of x11/libxfce4util, and x11-wm/xfce4-panelolivierd2013-05-093-7/+6 * Finish converting x11* from WITHOUT_NLS to PORT_OPTIONS:MNLSbapt2013-05-062-15/+11 * - Trim old-style header.hrs2013-05-033-9/+17 * - Fix build with CLANGsanpei2013-04-291-0/+1 * - Convert USE_ICONV=yes to USES=iconvmva2013-04-281-2/+2 * - Convert USE_GETTEXT to USES (part 3)ak2013-04-253-4/+4 * - Convert USE_GETTEXT to USES (part 1)ak2013-04-242-4/+2 * - Update to 1.0.2olivierd2013-04-243-7/+7 * Finish converting the whole ports tree to USES=pkgconfigbapt2013-04-234-11/+5 * KDE/FreeBSD team presents KDE SC 4.10.1 ports!makc2013-03-274-10/+9 * - convert USE_CMAKE to USESmakc2013-03-232-2/+2 * Mk/bsd.kde4.mk:makc2013-03-222-2/+2 * Return davide's ports to the pool per request.eadler2013-03-101-6/+2 * Remove indefinite article from COMMENTehaupt2013-03-081-6/+2 * Convert USE_BISON to USES= bisonbapt2013-03-081-6/+2 * - Broken Checksum mismatchmiwi2013-02-231-0/+2 * - Update to 0.6.2olivierd2013-02-153-19/+49 * - Fix build with clangmiwi2013-02-101-5/+7 * KDE/FreeBSD team presents KDE SC 4.9.5 ports!makc2013-02-044-12/+5 * - add comment for imake problem with clangdinoex2013-01-261-5/+3 * Remove the created by me and update those header at the same time. I nevermezz2013-01-011-5/+0 * - Deprecate QT3, KDE3 and unmaintained ports depending on them. QT 3.3.8beat2012-12-301-0/+3 * 2012-11-27 devel/p5-SPOPS: Depend on the expired p5-Class-Fieldsbapt2012-11-284-38/+0 * - Update to 2.2.2madpilot2012-11-278-80/+491 * Deprecate a bunch of ports that are either abandonware and/or for which no morebapt2012-10-261-5/+4 * 2012-10-20 x11-themes/metacity-ana-theme: No more public distfilesbapt2012-10-265-54/+0 * Update to 2.37wxs2012-10-172-3/+3 * Force numerous ports that fail to build with clang over to instead alwayslinimon2012-10-101-0/+1 * - Reassign to the heap due to mail bouncestabthorpe2012-09-301-6/+2 * - Update to 1.0.0olivierd2012-09-253-7/+8 * Deprecate a bunch a ports with no more public distfiles (thanks ehaupt's dist...bapt2012-09-211-0/+3 * - Update MAINTAINER to my new FreeBSD.org addressjhale2012-09-132-2/+2 * - reset maintainership per maintainerjgh2012-09-071-4/+6 * Mark ports unsafe per wiki page of broken ports.eadler2012-09-031-0/+2 * - Reassign nork@ ports to the heaptabthorpe2012-08-161-1/+1 * Switch from libglut to freeglut and retire libglut. Libglut hasn't beenkwm2012-08-051-1/+1 * Fix typos in COMMENTcs2012-07-291-1/+1 * new devel/pkgconf added to replace devel/pkg-config. new version of pkg-configbapt2012-07-261-1/+1 * For the ports that are maintained by ports@ that have pkgconfig as theirdougb2012-07-231-1/+1 * - reset MAINTAINERdinoex2012-06-261-1/+1 * KDE/FreeBSD team presents KDE SC 4.8.4, probably the last release in 4.8.x se...makc2012-06-153-5/+4 * Add missing dependseadler2012-06-091-1/+2 * - Convert USE_QT_VER=4 and QT_COMPONETS to USE_QT4miwi2012-06-064-8/+4 * - Update to version 0.4.9.2sylvio2012-06-064-32/+24 * - update png to 1.5.10dinoex2012-06-0120-16/+20 * - Update to 1.0.1miwi2012-05-263-9/+16 * - Bump all XFCE after XFCE importmiwi2012-05-262-1/+2 * KDE/FreeBSD team presents long awaited KDE SC 4.8.3!makc2012-05-257-4/+49 * Update to 2.36wxs2012-04-242-3/+3