summaryrefslogtreecommitdiffstats
path: root/filter.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2011-09-25 10:28:41 -0700
committerKaz Kylheku <kaz@kylheku.com>2011-09-25 10:28:41 -0700
commit4ce8dde9cafa8a77a0c623043fded0a751ad4b02 (patch)
tree2b18b7c7e838da2491327fdd8a9d291f31c2b46c /filter.c
parent658eb97af000aa0598e3544c2c7ea2cdd60b5b06 (diff)
downloadtxr-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.c163
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"&lt;" },
+ { L">", L"&gt;" },
+ { L"&", L"&amp;" },
+ { L"\"", L"&quot;" },
+ { 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));
+}