summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2025-01-24 20:49:52 -0800
committerKaz Kylheku <kaz@kylheku.com>2025-01-24 20:49:52 -0800
commit31540ce793f1aa551e1df3054f37fb3221618361 (patch)
treececace480fad4edf6c08e8028bf8043c61103ed9 /stream.c
parentaf458b10e3bc6709e68ef7d0ca1d2aabbeada414 (diff)
downloadtxr-31540ce793f1aa551e1df3054f37fb3221618361.tar.gz
txr-31540ce793f1aa551e1df3054f37fb3221618361.tar.bz2
txr-31540ce793f1aa551e1df3054f37fb3221618361.zip
New functions for producing CSV.
* stream.c (put_csv, tocsv): New functions. (stream_init): put-csv and tocsv intrinsics registered. * stream.h (put_csv, tocsv): Declared. * tests/010/csv.tl (mtest-pcsv): New macro. New test cases. * txr.1: Documented.
Diffstat (limited to 'stream.c')
-rw-r--r--stream.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/stream.c b/stream.c
index 421b70eb..7701ba39 100644
--- a/stream.c
+++ b/stream.c
@@ -5506,6 +5506,46 @@ val get_csv(val source_opt)
return record;
}
+val put_csv(val record, val stream_in)
+{
+ val self = lit("put-csv");
+ val dest = if3(missingp(stream_in), std_output, stream_in);
+ seq_iter_t rec_iter;
+ val field;
+ int comma = 0;
+
+ seq_iter_init(self, &rec_iter, record);
+
+ while (seq_get(&rec_iter, &field)) {
+ val str = tostringp(field);
+ if (comma)
+ put_char(chr(','), dest);
+ comma = 1;
+ if (find(chr('"'), str, nil, nil)) {
+ put_char(chr('"'), dest);
+ put_string(str_esc(lit("\""), chr('"'), str), dest);
+ put_char(chr('"'), dest);
+ } else if (break_str(str, lit(",\n\r"))) {
+ put_char(chr('"'), dest);
+ put_string(str, dest);
+ put_char(chr('"'), dest);
+ } else {
+ put_string(str, dest);
+ }
+ }
+
+ put_char(chr('\n'), dest);
+
+ return nil;
+}
+
+val tocsv(val record)
+{
+ val ss = make_string_output_stream();
+ put_csv(record, ss);
+ return get_string_from_stream(ss);
+}
+
val tmpfile_wrap(void)
{
val self = lit("tmpfile");
@@ -5782,6 +5822,8 @@ void stream_init(void)
reg_varl(intern(lit("indent-code"), user_package), num_fast(indent_code));
reg_varl(intern(lit("indent-foff"), user_package), num_fast(indent_foff));
reg_fun(intern(lit("get-csv"), user_package), func_n1o(get_csv, 0));
+ reg_fun(intern(lit("put-csv"), user_package), func_n2o(put_csv, 1));
+ reg_fun(intern(lit("tocsv"), user_package), func_n1(tocsv));
reg_fun(intern(lit("tmpfile"), user_package), func_n0(tmpfile_wrap));
#if HAVE_MKDTEMP
reg_fun(intern(lit("mkdtemp"), user_package), func_n1(mkdtemp_wrap));