summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--lib.c32
-rw-r--r--lib.h2
-rw-r--r--match.c25
-rw-r--r--txr.129
5 files changed, 84 insertions, 19 deletions
diff --git a/ChangeLog b/ChangeLog
index af930518..f77390ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2011-10-21 Kaz Kylheku <kaz@kylheku.com>
+
+ * lib.c (proper_plist_to_alist, improper_plist_to_alist): New
+ functions.
+
+ * lib.h (proper_plist_to_alist, improper_plist_to_alist): New
+ functions declared.
+
+ * match.c (append_k): New keyword symbol variable.
+ (complex_open): New append argument.
+ (v_output): Streamlined parsing of keywords.
+ Support :append keyword.
+
+ * txr.1: Output directive's keyword documentation revised.
+
2011-10-20 Kaz Kylheku <kaz@kylheku.com>
Bug #34609
diff --git a/lib.c b/lib.c
index e490228c..91e958b8 100644
--- a/lib.c
+++ b/lib.c
@@ -661,6 +661,38 @@ val getplist(val list, val key)
return nil;
}
+val proper_plist_to_alist(val list)
+{
+ list_collect_decl (out, tail);
+
+ for (; list; list = cdr(cdr(list))) {
+ val ind = first(list);
+ val prop = second(list);
+ list_collect (tail, cons(ind, prop));
+ }
+
+ return out;
+}
+
+val improper_plist_to_alist(val list, val boolean_keys)
+{
+ list_collect_decl (out, tail);
+
+ for (; list; list = cdr(list)) {
+ val ind = first(list);
+
+ if (memqual(ind, boolean_keys)) {
+ list_collect (tail, cons(ind, t));
+ } else {
+ val prop = second(list);
+ list_collect (tail, cons(ind, prop));
+ list = cdr(list);
+ }
+ }
+
+ return out;
+}
+
val num(cnum n)
{
numeric_assert (n >= NUM_MIN && n <= NUM_MAX);
diff --git a/lib.h b/lib.h
index a132296c..dca8220c 100644
--- a/lib.h
+++ b/lib.h
@@ -313,6 +313,8 @@ val listp(val obj);
val proper_listp(val obj);
val length(val list);
val getplist(val list, val key);
+val proper_plist_to_alist(val list);
+val improper_plist_to_alist(val list, val boolean_keys);
val num(cnum val);
cnum c_num(val num);
val nump(val num);
diff --git a/match.c b/match.c
index 8b512f1b..733b99cf 100644
--- a/match.c
+++ b/match.c
@@ -53,6 +53,7 @@ val mingap_k, maxgap_k, gap_k, mintimes_k, maxtimes_k, times_k;
val lines_k, chars_k;
val choose_s, longest_k, shortest_k, greedy_k;
val vars_k;
+val append_k;
static val h_directive_table, v_directive_table;
@@ -1097,10 +1098,9 @@ typedef struct fpip {
enum fpip_close close;
} fpip_t;
-static fpip_t complex_open(val name, val output)
+static fpip_t complex_open(val name, val output, val append)
{
fpip_t ret = { 0, 0 };
-
const wchar_t *namestr = c_str(name);
cnum len = c_num(length_str(name));
@@ -1124,7 +1124,7 @@ static fpip_t complex_open(val name, val output)
free(name);
} else {
ret.close = fpip_fclose;
- ret.f = w_fopen(namestr, output ? L"w" : L"r");
+ ret.f = w_fopen(namestr, output ? append ? L"a" : L"w" : L"r");
}
return ret;
@@ -2090,8 +2090,10 @@ static val v_output(match_files_ctx c, match_files_ctx *cout)
val specs = second(first_spec);
val dest_spec = third(first_spec);
val nothrow = nil;
+ val append = nil;
val dest = lit("-");
val filter = nil;
+ val alist;
fpip_t fp;
if (eq(first(dest_spec), nothrow_k)) {
@@ -2104,13 +2106,13 @@ static val v_output(match_files_ctx c, match_files_ctx *cout)
pop(&dest_spec);
}
- if (eq(first(dest_spec), nothrow_k)) {
- nothrow = t;
- pop(&dest_spec);
- }
+ alist = improper_plist_to_alist(dest_spec, list(nothrow_k, append_k, nao));
+
+ nothrow = cdr(assoc(alist, nothrow_k));
+ append = cdr(assoc(alist, append_k));
- if (keywordp(first(dest_spec))) {
- val filter_sym = getplist(dest_spec, filter_k);
+ {
+ val filter_sym = cdr(assoc(alist, filter_k));
if (filter_sym) {
filter = get_filter_trie(filter_sym);
@@ -2120,7 +2122,7 @@ static val v_output(match_files_ctx c, match_files_ctx *cout)
}
}
- fp = (errno = 0, complex_open(dest, t));
+ fp = (errno = 0, complex_open(dest, t, append));
debugf(lit("opening data sink ~a"), dest, nao);
@@ -2372,7 +2374,7 @@ static val match_files(match_files_ctx c)
} else if (c.files) { /* c.data == t: toplevel call with file list */
val source_spec = first(c.files);
val name = consp(source_spec) ? cdr(source_spec) : source_spec;
- fpip_t fp = (errno = 0, complex_open(name, nil));
+ fpip_t fp = (errno = 0, complex_open(name, nil, nil));
val first_spec_item = second(first(c.spec));
if (consp(first_spec_item) && eq(first(first_spec_item), next_s)) {
@@ -2588,6 +2590,7 @@ static void syms_init(void)
shortest_k = intern(lit("shortest"), keyword_package);
greedy_k = intern(lit("greedy"), keyword_package);
vars_k = intern(lit("vars"), keyword_package);
+ append_k = intern(lit("append"), keyword_package);
}
static void dir_tables_init(void)
diff --git a/txr.1 b/txr.1
index a7577bef..6f8fea85 100644
--- a/txr.1
+++ b/txr.1
@@ -2622,7 +2622,7 @@ usual printing of the variable bindings or the word false.
The syntax of the @(output) directive is:
- @(output [ DESTINATION ] [ :nothrow ] [ { keyword value } * ])
+ @(output [ DESTINATION ] { bool-keyword | keyword value }* )
.
. one or more output directives or lines
.
@@ -2633,21 +2633,34 @@ redirects to standard output, or a shell command preceded by the ! symbol.
In the first form, the destination may be specified as a variable
which holds text, a string literal or a quasiliteral
-The syntax throws an exception if the output destination
+The keyword list consists of a mixture of boolean keywords which
+do not have an argument, or keywords with arguments.
+
+The following boolean keywords are supported:
+
+.IP :nothrow
+
+The output directive throws an exception if the output destination
cannot be opened, unless the :nothrow keyword is present, in which
-case the situation is treated as a match failure. The old syntax throws an
-exception.
+case the situation is treated as a match failure.
Note that since command pipes are processes that report errors
asynchronously, a failing command will not throw an immediate exception that
can be suppressed with :nothrow. This is for synchronous errors, like
trying to open a destination file, but not having permissions, etc.
-The keyword value list is used for passing additional options.
-Currently, the only keyword supported is the :filter keyword.
-This specifies a filter to be applied to the variable substitutions occuring
-within the output clause.
+.IP :append
+
+This keyword is meaningful for files, specifying append mode: the output is to
+be added to the end of the file rather than overwriting the file.
+
+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.
+See the later sections Output Filtering below, and The Deffilter Directive.
.SS Output Text