diff options
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | lib.c | 32 | ||||
-rw-r--r-- | lib.h | 2 | ||||
-rw-r--r-- | match.c | 25 | ||||
-rw-r--r-- | txr.1 | 29 |
5 files changed, 84 insertions, 19 deletions
@@ -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 @@ -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); @@ -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); @@ -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) @@ -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 |