diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2011-09-25 10:28:41 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2011-09-25 10:28:41 -0700 |
commit | 4ce8dde9cafa8a77a0c623043fded0a751ad4b02 (patch) | |
tree | 2b18b7c7e838da2491327fdd8a9d291f31c2b46c /filter.c | |
parent | 658eb97af000aa0598e3544c2c7ea2cdd60b5b06 (diff) | |
download | txr-4ce8dde9cafa8a77a0c623043fded0a751ad4b02.tar.gz txr-4ce8dde9cafa8a77a0c623043fded0a751ad4b02.tar.bz2 txr-4ce8dde9cafa8a77a0c623043fded0a751ad4b02.zip |
Filtering feature for variable substitution in output.
* filter.c, filter.h: New files.
* Makefile (OBJS): filter.o added.
* gc.c (mark_obj): Mark new alloc field of string objets.
* hash.c (struct hash): New member, userdata.
(hash_mark): Mark new userdata member of hash.
(make_hash): Initialize userdata.
(get_hash_userdata, set_hash_userdata, hashp): New functions.
* hash.h (get_hash_userdata, set_hash_userdata, hashp): New functions
declared.
* lib.c (getplist, string_extend, cobjp): New functions.
(string_own, string, string_utf8): Initialize new alloc field to nil.
(mkstring, mkustring): Initialize new alloc field to actual size.
(length_str): When length is computed and cached, also compute
and cache alloc.
(init): Call filter_init.
* lib.h (string string): New member, alloc.
(num_fast): Macro converted to inline function.
(getplist, string_extend, cobjp): New functions declared.
* match.c (match_line): Follows change of modifier s-exp syntax.
(format_field): New parameter, filter.
New modifier syntax parsed. Filter retrieved, and applied.
(subst_vars): New parameter, filter. Filter is either applied
in this function or passed to format_field, as needed.
(eval_form): Pass nil to new parameter of subst_vars.
(do_output_line): New parameter, filter. Passed down to subst_vars.
(do_output): New parameter, filter. Passed down to do_output_line.
(match_files): Pass nil filter to subst_vars in cat directive.
Output directive refactored to parse keywords, extract the
filter and pass down to do_output.
* parser.y (regex): Generate (sys:regex regex syntax ...)
instead of (regex syntax ...).
(elem, expr): Updated w.r.t. regex syntax change.
(var): Cases '{' IDENT regex '}' and '{' IDENT NUMBER '}'
are removed. new syntax '{' IDENT exprs '}' to handle these
more generally and allow for keywords.
* txr.1: Updated.
Diffstat (limited to 'filter.c')
-rw-r--r-- | filter.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/filter.c b/filter.c new file mode 100644 index 00000000..6b253473 --- /dev/null +++ b/filter.c @@ -0,0 +1,163 @@ +/* Copyright 2011 + * Kaz Kylheku <kkylheku@gmail.com> + * Vancouver, Canada + * All rights reserved. + * + * BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <stddef.h> +#include <setjmp.h> +#include "config.h" +#include "lib.h" +#include "hash.h" +#include "unwind.h" +#include "filter.h" + +static val make_trie(void) +{ + return make_hash(nil, nil); +} + +static val trie_add(val trie, val key, val value) +{ + val node, i, len = length_str(key); + + for (node = trie, i = zero; lt(i, len); i = plus(i, one)) { + val ch = chr_str(key, i); + val newnode_p; + val *loc = gethash_l(node, ch, &newnode_p); + if (newnode_p) + *loc = make_hash(nil, nil); + node = *loc; + } + + set_hash_userdata(node, value); + return node; +} + +val trie_lookup_begin(val trie) +{ + return trie; +} + +val trie_value_at(val node) +{ + return get_hash_userdata(node); +} + +val trie_lookup_feed_char(val node, val ch) +{ + return gethash(node, ch); +} + +val get_filter_trie(val sym) +{ + return gethash(filters, sym); +} + +struct filter_pair { + wchar_t *key, *value; +}; + +static val build_filter(struct filter_pair *pair) +{ + int i; + val trie = make_trie(); + + for (i = 0; pair[i].key; i++) + trie_add(trie, static_str(pair[i].key), static_str(pair[i].value)); + + return trie; +} + +static struct filter_pair to_html_table[] = { + { L"<", L"<" }, + { L">", L">" }, + { L"&", L"&" }, + { L"\"", L""" }, + { 0, 0 } +}; + +static val trie_filter_string(val filter, val str) +{ + val len = length_str(str); + val i; + val out = string(L""); + + for (i = zero; lt(i, len); ) { + val node = trie_lookup_begin(filter); + val match = nil; + val subst; + val j; + + for (j = i; lt(j, len); j = plus(j, one)) { + val ch = chr_str(str, j); + val nnode = trie_lookup_feed_char(node, ch); + val nsubst; + + if (!nnode) + break; + + if ((nsubst = trie_value_at(nnode))) { + match = j; + subst = nsubst; + } + + node = nnode; + } + + if (match) { + string_extend(out, subst); + i = plus(match, one); + } else { + string_extend(out, chr_str(str, i)); + i = plus(i, one); + } + } + + return out; +} + +val filters; +val filter_k, to_html_k; + +val filter_string(val filter, val str) +{ + val type = typeof(filter); + + if (type == null) + return str; + if (type == hash_s) + return trie_filter_string(filter, str); + else if (type == fun_s) + return funcall1(filter, str); + return str; + uw_throwf(error_s, lit("filter_string: invalid filter ~a"), filter, nao); +} + +void filter_init(void) +{ + filters = make_hash(nil, nil); + filter_k = intern(lit("filter"), keyword_package); + to_html_k = intern(lit("to_html"), keyword_package); + sethash(filters, to_html_k, build_filter(to_html_table)); +} |