From 6ddb4b8f329b14e6133f29573cfeb88d1ee30846 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Sat, 22 Oct 2011 16:18:11 -0400 Subject: * filter.c (get_filter_trie): Function renamed to get_filter. A filter is not necessarily a trie. (string_filter, compound_filter): New functions. (get_filter): Recognize a compound filters and return a function which implements it. * filter.h (get_filter_trie): Declaration renamed. * match.c (format_field, v_bind, v_output): Follow get_filter_trie rename. Error message text updated. * txr.1: Describe compound filters. --- ChangeLog | 15 +++++++++++++++ filter.c | 23 +++++++++++++++++++++-- filter.h | 2 +- match.c | 12 ++++++------ txr.1 | 28 +++++++++++++++++++++++++--- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 67e0a93a..5ce31148 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2011-10-22 Kaz Kylheku + + * filter.c (get_filter_trie): Function renamed to get_filter. A filter + is not necessarily a trie. + (string_filter, compound_filter): New functions. + (get_filter): Recognize a compound filters and return a function + which implements it. + + * filter.h (get_filter_trie): Declaration renamed. + + * match.c (format_field, v_bind, v_output): Follow get_filter_trie + rename. Error message text updated. + + * txr.1: Describe compound filters. + 2011-10-22 Kaz Kylheku Task #11474 diff --git a/filter.c b/filter.c index d5bdf262..4c787955 100644 --- a/filter.c +++ b/filter.c @@ -122,9 +122,28 @@ val trie_lookup_feed_char(val node, val ch) return nil; } -val get_filter_trie(val sym) +static val string_filter(val str, val filter) { - return gethash(filters, sym); + return filter_string(filter, str); +} + +static val compound_filter(val filter_list, val string) +{ + return reduce_left(func_n2(string_filter), filter_list, string, nil); +} + +val get_filter(val spec) +{ + if (consp(spec)) { + val filter_list = mapcar(curry_12_2(func_n2(gethash), filters), spec); + + if (memqual(nil, filter_list)) + return nil; + + return curry_12_2(func_n2(compound_filter), filter_list); + } + + return gethash(filters, spec); } struct filter_pair { diff --git a/filter.h b/filter.h index 7f37fa7c..d0d7d34b 100644 --- a/filter.h +++ b/filter.h @@ -30,7 +30,7 @@ extern val filter_k, to_html_k, from_html_k; val trie_lookup_begin(val trie); val trie_value_at(val node); val trie_lookup_feed_char(val node, val ch); -val get_filter_trie(val sym); +val get_filter(val sym); val filter_string(val trie, val str); val filter_equal(val filter, val left, val right); val register_filter(val sym, val table); diff --git a/match.c b/match.c index ec153f82..9c8def60 100644 --- a/match.c +++ b/match.c @@ -1002,10 +1002,10 @@ static val format_field(val string_or_list, val modifier, val filter) val filter_sym = getplist(plist, filter_k); if (filter_sym) { - filter = get_filter_trie(filter_sym); + filter = get_filter(filter_sym); if (!filter) { - uw_throwf(query_error_s, lit("format_field: filter ~s not known"), + uw_throwf(query_error_s, lit("format_field: ~s specifies unknown filter"), filter_sym, nao); } } @@ -2144,10 +2144,10 @@ static val v_bind(match_files_ctx c, match_files_ctx *cout) val filter_sym = getplist(keywords, filter_k); if (filter_sym) { - val filter = get_filter_trie(filter_sym); + val filter = get_filter(filter_sym); if (!filter) { - uw_throwf(query_error_s, lit("bind: filter ~s not known"), + uw_throwf(query_error_s, lit("bind: ~s specifies unknown filter"), filter_sym, nao); } @@ -2239,10 +2239,10 @@ static val v_output(match_files_ctx c, match_files_ctx *cout) val filter_sym = cdr(assoc(alist, filter_k)); if (filter_sym) { - filter = get_filter_trie(filter_sym); + filter = get_filter(filter_sym); if (!filter) - sem_error(spec_linenum, lit("unknown filter ~s"), filter_sym, nao); + sem_error(spec_linenum, lit("~s specifies unknown filter"), filter_sym, nao); } } diff --git a/txr.1 b/txr.1 index 2542adcb..dbfffd86 100644 --- a/txr.1 +++ b/txr.1 @@ -2144,6 +2144,8 @@ Bind will see that A and B have bindings already, and so compare their contents. Since the :upcase filter is specified, both their contents will be reduced through it for the purposes of the comparison, rendering them equal. +Of course, compound filters are supported like (:from_html :upcase). + .SS The Set Directive The @(set) directive resembles bind, but is not a pattern match. It overwrites @@ -2750,8 +2752,11 @@ The following value keywords are supported: .IP :filter -The argument is a symbol, which specifies a filter to be applied to the -variable substitutions occuring within the output clause. +The argument can be a symbol, which specifies a filter to be applied to +the variable substitutions occuring within the output clause. +The argument can also be a list of filter symbols, which specifies +that multiple filters are to be applied, in left to right order. + See the later sections Output Filtering below, and The Deffilter Directive. .IP :into @@ -2788,7 +2793,9 @@ that field, if the width is specified as a positive number, and right-adjusted if the width is specified as negative. An output variable may specify a filter which overrides any filter established -for the output clause. The syntax for this is @(NAME :filter }. +for the output clause. The syntax for this is @(NAME :filter }. +The filter specification syntax is the same as in the output clause. +See Output Filtering below. .SS The Repeat Directive @@ -2979,6 +2986,21 @@ To filter an individual variable, add the syntax to the variable spec: @{x :filter :to_html} @(end) +Multiple filters can be applied at the same time. For instance: + + @(output) + @{x :filter (:upcase :to_html)} + @(end) + +This will fold the contents of x to upper case, and then encode any special +characters into HTML. Beware of combinations that do not make sense. +For instance, suppose the original text is HTML, containing codes +like '"'. The compound filter (:upcase :from_html) will not work +because '"' will turn to '"' which no longer be recognized +by the :from_html filter, because the entity names in HTML codes +are case-sensitive. + + .SS The Deffilter Directive The deffilter directive allows a query to define a custom filter, which -- cgit v1.2.3