diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2025-01-21 19:41:00 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2025-01-21 19:41:00 -0800 |
commit | 9ee82d9d744de52916817412318f43f26960d719 (patch) | |
tree | 5dec34c18ec021c580441953a73ac53979cf2a8c | |
parent | 35d1c7f01f6bf2004c048ebecf12132e48454d87 (diff) | |
download | txr-9ee82d9d744de52916817412318f43f26960d719.tar.gz txr-9ee82d9d744de52916817412318f43f26960d719.tar.bz2 txr-9ee82d9d744de52916817412318f43f26960d719.zip |
get-csv: rewrite in C.
* autload.c (csv_set_entries, csv_instantiate): Functions
removed.
(autoload_init): Autoload registration for stdlib/csv
removed.
* stdlib/csv.tl: File removed.
* stream.c (get_csv): New function.
(stream_init): Register get-csv intrinsic.
* stream.h (get_csv): Declared.
-rw-r--r-- | autoload.c | 17 | ||||
-rw-r--r-- | stdlib/csv.tl | 74 | ||||
-rw-r--r-- | stream.c | 78 | ||||
-rw-r--r-- | stream.h | 1 |
4 files changed, 79 insertions, 91 deletions
@@ -1020,22 +1020,6 @@ static val enum_instantiate(void) return nil; } -static val csv_set_entries(val fun) -{ - val name[] = { - lit("get-csv"), - nil - }; - autoload_set(al_fun, name, fun); - return nil; -} - -static val csv_instantiate(void) -{ - load(scat2(stdlib_path, lit("csv"))); - return nil; -} - val autoload_reg(val (*instantiate)(void), val (*set_entries)(val)) { @@ -1108,7 +1092,6 @@ void autoload_init(void) autoload_reg(csort_instantiate, csort_set_entries); autoload_reg(glob_instantiate, glob_set_entries); autoload_reg(enum_instantiate, enum_set_entries); - autoload_reg(csv_instantiate, csv_set_entries); reg_fun(intern(lit("autoload-try-fun"), system_package), func_n1(autoload_try_fun)); } diff --git a/stdlib/csv.tl b/stdlib/csv.tl deleted file mode 100644 index f3b4f190..00000000 --- a/stdlib/csv.tl +++ /dev/null @@ -1,74 +0,0 @@ -;; Copyright 2025 -;; Kaz Kylheku <kaz@kylheku.com> -;; Vancouver, Canada -;; All rights reserved. -;; -;; 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. -;; -;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -;; POSSIBILITY OF SUCH DAMAGE. - -(defun get-csv (: (stream *stdin*)) - (if (stringp stream) - (upd stream make-string-input-stream)) - (let ((record (vec)) - (field (str 0)) - (state :rfield) - (done nil)) - (while (not done) - (let ((ch (get-char stream))) - (when (eq ch #\return) - (let ((ch2 (get-char stream))) - (if (eq ch2 #\newline) - (set ch ch2) - (if ch2 - (unget-char ch2 stream))))) - (caseq state - (:rfield (caseql* ch - (#\newline (vec-push record field) - (set done t)) - (#\, (vec-push record field) - (set field (str 0))) - (#\" (cond - ((empty field) - (set state :qfield)) - (t - (string-extend field ch)))) - (nil (vec-push record field) - (set done t)) - (t (string-extend field ch)))) - (:qfield (caseql* ch - (#\" (set state :quot)) - (nil (vec-push record field) - (set done t)) - (t (string-extend field ch)))) - (:quot (caseql* ch - (#\, (vec-push record field) - (set field (str 0) - state :rfield)) - (#\" (string-extend field ch) - (set state :qfield)) - (#\newline (vec-push record field) - (set done t)) - (nil (vec-push record field) - (set done t)) - (t (string-extend field ch) - (set state :rfield))))))) - record)) @@ -5422,6 +5422,83 @@ val make_byte_input_stream(val obj) } } +val get_csv(val source_opt) +{ + val source = if3(missingp(source_opt), + std_input, + if3(stringp(source_opt), + make_string_input_stream(source_opt), + source_opt)); + val record = vector(zero, nil); + val field = mkstring(zero, chr(' ')); + enum { rfield, qfield, quot } state = rfield; + int done = 0; + + while (!done) { + val ch = get_char(source); + + if (ch == chr('\r')) { + val ch2 = get_char(source); + if (ch2 == chr('\n')) + ch = ch2; + else if (ch2) + unget_char(ch2, source); + } + + switch (state) { + case rfield: + if (ch == chr('\n')) { + vec_push(record, field); + done = 1; + } else if (ch == chr(',')) { + vec_push(record, field); + field = mkstring(zero, chr(' ')); + } else if (ch == chr('"')) { + if (empty(field)) + state = qfield; + else + string_extend(field, ch, nil); + } else if (ch == nil) { + vec_push(record, field); + done = 1; + } else { + string_extend(field, ch, nil); + } + break; + case qfield: + if (ch == chr('"')) { + state = quot; + } else if (ch == nil) { + vec_push(record, field); + done = 1; + } else { + string_extend(field, ch, nil); + } + break; + case quot: + if (ch == chr(',')) { + vec_push(record, field); + field = mkstring(zero, chr(' ')); + state = rfield; + } else if (ch == chr('"')) { + string_extend(field, ch, nil); + state = qfield; + } else if (ch == chr('\n')) { + vec_push(record, field); + done = 1; + } else if (ch == nil) { + vec_push(record, field); + done = 1; + } else { + string_extend(field, ch, nil); + state = rfield; + } + } + } + + return record; +} + val tmpfile_wrap(void) { val self = lit("tmpfile"); @@ -5697,6 +5774,7 @@ void stream_init(void) reg_varl(intern(lit("indent-data"), user_package), num_fast(indent_data)); 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("tmpfile"), user_package), func_n0(tmpfile_wrap)); #if HAVE_MKDTEMP reg_fun(intern(lit("mkdtemp"), user_package), func_n1(mkdtemp_wrap)); @@ -285,6 +285,7 @@ val trim_path_seps(val name); val path_cat(val dir_name, val base_name); val add_suffix(val name, val suffix); val make_byte_input_stream(val obj); +val get_csv(val source_opt); val iobuf_get(void); void iobuf_put(val buf); void iobuf_list_empty(void); |