zsv 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +36 -0
- data/LICENSE +21 -0
- data/README.md +311 -0
- data/ext/zsv/common.h +34 -0
- data/ext/zsv/extconf.rb +137 -0
- data/ext/zsv/options.c +126 -0
- data/ext/zsv/options.h +31 -0
- data/ext/zsv/options_internal.h +8 -0
- data/ext/zsv/parser.c +300 -0
- data/ext/zsv/parser.h +62 -0
- data/ext/zsv/row.c +122 -0
- data/ext/zsv/row.h +39 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/2db.c +756 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/2json.c +381 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/2tsv.c +228 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/help.c +123 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/license.c +39 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/register.c +104 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/thirdparty.c +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/unregister.c +1 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/builtin/version.c +14 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/check/simdutf_wrapper.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/check/utf8.c +116 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/check.c +194 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli.c +796 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_const.h +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_export.h +16 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_ini.c +280 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/cli_internal.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare.c +913 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare.h +23 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_added_column.c +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_internal.h +140 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_sort.c +91 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/compare_unique_colname.c +81 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/count-pull.c +82 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/count.c +404 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/desc.c +569 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/echo.c +365 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/ext_example/my_extension.c +366 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/ext_example/mysheet_extension.c +341 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/ext_template/YOUR_EXTENSION_zsvext.c +263 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/inih/ini.c +298 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/inih/ini.h +157 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/json_numeric.c +177 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/jsonwriter.c +444 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/jsonwriter.h +145 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/json_writer-1.01/utils.c +110 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/memfile-1.0/include/memfile.h +15 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/memfile-1.0/src/memfile.c +64 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sglib/sglib.h +1955 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/simdutf/simdutf.h +6802 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3.c +230517 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3.h +12174 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_and_csv_vtab.c +2 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-mem.c +142 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-mem.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab-zsv.c +485 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3_csv_vtab.c +1015 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/sqlite3ext.h +663 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/sqlite3/vtab_helper.c +85 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_common.h +75 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_gen.h +167 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_parse.h +228 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_tree.h +186 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/build/yajl-2.1.1/include/yajl/yajl_version.h +23 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_common.h +76 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_gen.h +167 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_parse.h +238 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/api/yajl_tree.h +186 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl.c +184 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_alloc.c +52 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_alloc.h +34 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_buf.c +103 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_buf.h +57 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_bytestack.h +69 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_encode.c +220 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_encode.h +34 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_gen.c +362 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_lex.c +764 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_lex.h +117 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_parser.c +508 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_parser.h +78 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_tree.c +505 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl/src/yajl_version.c +7 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper/json_value.h +59 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper/yajl_helper.h +208 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper.c +795 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/external/yajl_helper/yajl_helper_internal.h +28 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/flatten.c +851 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/jq.c +106 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/jq.h +6 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/mv.c +113 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/noop.c +90 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/overwrite.c +295 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/paste.c +175 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/pretty.c +693 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/prop.c +980 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/rm.c +131 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/fixed.c +130 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/internal.h +118 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/parallel.c +45 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/parallel.h +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/processing.c +107 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/rand.c +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/regex.c +61 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/search.c +14 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/selection.c +192 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select/usage.c +72 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select-pull.c +812 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/select.c +753 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/serialize.c +372 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/curses.h +15 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/cursor.c +119 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/errors.c +45 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/file.c +63 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/file.h +12 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/filter.c +166 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/handlers.c +214 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/handlers_internal.h +128 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/help.c +43 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/index.c +81 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/index.h +25 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/key-bindings.c +325 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/key-bindings.h +73 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/lexer.c +203 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/newline_handler.c +7 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/pivot.c +318 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/procedure.c +134 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/procedure.h +119 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/read-data.c +322 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/screen_buffer.c +203 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/screen_buffer.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sheet-sql.c +167 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sheet_internal.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/sqlfilter.c +153 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/terminfo.c +32 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/transformation.c +312 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/transformation.h +29 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/ui_buffer.c +266 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/usage.c +9 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet/utf8-width.c +60 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sheet.c +1007 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sql.c +453 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sql_internal.c +101 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/sql_internal.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/stack.c +393 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/arg.c +322 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/cache.c +228 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/cat.c +91 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/chunk.c +240 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/chunk.h +63 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/clock.c +57 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/db.c +148 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs-no-jq.c +2 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs.c +427 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs_from_json.c +253 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dirs_to_json.c +121 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/dl.c +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/emcc/fs_api.c +159 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/err.c +24 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/file-mem.c +180 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/file.c +256 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/index.c +197 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/index.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/jq.c +400 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/json.c +120 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/mem.c +18 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/memmem.c +132 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/os.c +178 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/overwrite.c +258 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/overwrite_writer.c +246 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8-test.c +123 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8.c +153 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/pcre2-8/pcre2-8.h +54 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/prop.c +267 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/signal.c +53 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/string.c +357 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/dir_exists_longpath.c +83 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/dl.c +33 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/fopen_longpath.c +184 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/foreach_dirent_longpath.c +292 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/io.c +259 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/io.h +13 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/mkdir_longpath.c +255 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/win/remove_longpath.c +96 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/utils/writer.c +361 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/zsv_command.h +40 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/zsv_command_standalone.c +16 -0
- data/ext/zsv/vendor/zsv-1.3.0/app/zsv_main.h +44 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/js/zsv_parser_api_dummy.c +3 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/parse_by_chunk.c +100 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/print_my_column.c +143 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/pull.c +89 -0
- data/ext/zsv/vendor/zsv-1.3.0/examples/lib/simple.c +123 -0
- data/ext/zsv/vendor/zsv-1.3.0/fuzz/fuzz.c +16 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/api.h +336 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/common.h +361 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/implementation.h +62 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/implementation_private.h +113 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext/sheet.h +73 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/ext.h +329 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/arg.h +90 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/cache.h +49 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/clock.h +36 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/compiler.h +58 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/db.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/dirs.h +147 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/dl.h +22 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/emcc/fs_api.h +28 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/err.h +22 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/file-mem.h +17 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/file.h +99 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/jq.h +65 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/json.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/mem.h +19 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/memmem.h +13 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/os.h +54 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/overwrite.h +71 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/overwrite_writer.h +53 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/prop.h +107 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/signal.h +18 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/sql.h +11 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/string.h +148 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/utf8.h +41 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/win/dl.h +25 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/utils/writer.h +101 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv/zsv_export.h +33 -0
- data/ext/zsv/vendor/zsv-1.3.0/include/zsv.h +20 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/vector_delim.c +60 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv.c +484 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_internal.c +731 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_scan_delim.c +285 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_scan_fixed.c +88 -0
- data/ext/zsv/vendor/zsv-1.3.0/src/zsv_strencode.c +51 -0
- data/ext/zsv/zsv_ext.c +343 -0
- data/lib/zsv/version.rb +5 -0
- data/lib/zsv.rb +81 -0
- metadata +340 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
static zsvsheet_status zsv_sqlite3_to_csv(zsvsheet_proc_context_t pctx, struct zsv_sqlite3_db *zdb, const char *sql,
|
|
2
|
+
const char **err_msg, void *ctx,
|
|
3
|
+
void (*on_header_cell)(void *, size_t, const char *),
|
|
4
|
+
void (*on_data_cell)(void *, size_t, const char *, size_t len)) {
|
|
5
|
+
zsvsheet_status zst = zsvsheet_status_error;
|
|
6
|
+
sqlite3_stmt *stmt = NULL;
|
|
7
|
+
char have_data = 0;
|
|
8
|
+
if ((zdb->rc = sqlite3_prepare_v2(zdb->db, sql, -1, &stmt, NULL)) == SQLITE_OK) {
|
|
9
|
+
char *tmp_fn = zsv_get_temp_filename("zsv_mysheet_ext_XXXXXXXX");
|
|
10
|
+
struct zsv_csv_writer_options writer_opts = zsv_writer_get_default_opts();
|
|
11
|
+
zsv_csv_writer cw = NULL;
|
|
12
|
+
if (!tmp_fn)
|
|
13
|
+
zst = zsvsheet_status_memory;
|
|
14
|
+
else if (!(writer_opts.stream = fopen(tmp_fn, "wb"))) {
|
|
15
|
+
zst = zsvsheet_status_error;
|
|
16
|
+
*err_msg = strerror(errno);
|
|
17
|
+
} else if (!(cw = zsv_writer_new(&writer_opts)))
|
|
18
|
+
zst = zsvsheet_status_memory;
|
|
19
|
+
else {
|
|
20
|
+
zst = zsvsheet_status_ok;
|
|
21
|
+
unsigned char cw_buff[1024];
|
|
22
|
+
zsv_writer_set_temp_buff(cw, cw_buff, sizeof(cw_buff));
|
|
23
|
+
|
|
24
|
+
int col_count = sqlite3_column_count(stmt);
|
|
25
|
+
// write header row
|
|
26
|
+
for (int i = 0; i < col_count; i++) {
|
|
27
|
+
const char *colname = sqlite3_column_name(stmt, i);
|
|
28
|
+
zsv_writer_cell(cw, !i, (const unsigned char *)colname, colname ? strlen(colname) : 0, 1);
|
|
29
|
+
if (on_header_cell)
|
|
30
|
+
on_header_cell(ctx, i, colname);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// write sql results
|
|
34
|
+
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
35
|
+
for (int i = 0; i < col_count; i++) {
|
|
36
|
+
const unsigned char *text = sqlite3_column_text(stmt, i);
|
|
37
|
+
int len = text ? sqlite3_column_bytes(stmt, i) : 0;
|
|
38
|
+
zsv_writer_cell(cw, !i, text, len, 1);
|
|
39
|
+
have_data = 1;
|
|
40
|
+
if (on_data_cell)
|
|
41
|
+
on_data_cell(ctx, i, (const char *)text, len);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (cw)
|
|
46
|
+
zsv_writer_delete(cw);
|
|
47
|
+
if (writer_opts.stream)
|
|
48
|
+
fclose(writer_opts.stream);
|
|
49
|
+
|
|
50
|
+
if (tmp_fn && zsv_file_exists(tmp_fn) && have_data) {
|
|
51
|
+
struct zsvsheet_ui_buffer_opts uibopts = {0};
|
|
52
|
+
uibopts.data_filename = tmp_fn;
|
|
53
|
+
zst = zsvsheet_open_file_opts(pctx, &uibopts);
|
|
54
|
+
} else {
|
|
55
|
+
if (zst == zsvsheet_status_ok) {
|
|
56
|
+
if (!have_data)
|
|
57
|
+
zst = zsvsheet_status_no_data;
|
|
58
|
+
if (!*err_msg && zdb && zdb->rc != SQLITE_OK) {
|
|
59
|
+
zst = zsvsheet_status_error; // to do: make this more specific
|
|
60
|
+
*err_msg = sqlite3_errmsg(zdb->db);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (tmp_fn && zsv_file_exists(tmp_fn))
|
|
64
|
+
unlink(tmp_fn);
|
|
65
|
+
}
|
|
66
|
+
free(tmp_fn);
|
|
67
|
+
}
|
|
68
|
+
if (stmt)
|
|
69
|
+
sqlite3_finalize(stmt);
|
|
70
|
+
|
|
71
|
+
return zst;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static int is_constant_expression(sqlite3 *db, const char *expr, int *err) {
|
|
75
|
+
sqlite3_stmt *stmt = NULL;
|
|
76
|
+
// We try to prepare "SELECT [expr]". If this succeeds, the expression
|
|
77
|
+
// does not depend on any columns and is therefore constant.
|
|
78
|
+
char *sql_const_test = sqlite3_mprintf("SELECT %s", expr);
|
|
79
|
+
if (!sql_const_test) {
|
|
80
|
+
*err = errno;
|
|
81
|
+
return 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
int rc = sqlite3_prepare_v2(db, sql_const_test, -1, &stmt, NULL);
|
|
85
|
+
if (stmt) {
|
|
86
|
+
sqlite3_finalize(stmt);
|
|
87
|
+
stmt = NULL;
|
|
88
|
+
}
|
|
89
|
+
sqlite3_free(sql_const_test);
|
|
90
|
+
|
|
91
|
+
int is_constant = (rc == SQLITE_OK);
|
|
92
|
+
return is_constant;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
enum check_select_expression_result {
|
|
96
|
+
zsv_select_sql_expression_valid = 0,
|
|
97
|
+
zsv_select_sql_expression_invalid,
|
|
98
|
+
zsv_select_sql_expression_multiple_statements,
|
|
99
|
+
zsv_select_sql_expression_multiple_expressions,
|
|
100
|
+
zsv_select_sql_expression_other
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const char *check_select_expression_result_str(enum check_select_expression_result rc) {
|
|
104
|
+
switch (rc) {
|
|
105
|
+
case zsv_select_sql_expression_valid:
|
|
106
|
+
return NULL;
|
|
107
|
+
case zsv_select_sql_expression_invalid:
|
|
108
|
+
return "Invalid SQL";
|
|
109
|
+
case zsv_select_sql_expression_multiple_statements:
|
|
110
|
+
return "Please enter only a single expression";
|
|
111
|
+
case zsv_select_sql_expression_multiple_expressions:
|
|
112
|
+
return "Please enter only a single expression";
|
|
113
|
+
case zsv_select_sql_expression_other:
|
|
114
|
+
return "Unknown error";
|
|
115
|
+
}
|
|
116
|
+
return NULL;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static int is_str_empty(const char *s) {
|
|
120
|
+
if (!s)
|
|
121
|
+
return 1;
|
|
122
|
+
while (*s) {
|
|
123
|
+
if (!isspace((unsigned char)*s)) {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
s++;
|
|
127
|
+
}
|
|
128
|
+
return 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
static enum check_select_expression_result check_select_expression(sqlite3 *db, const char *expr, int *err) {
|
|
132
|
+
sqlite3_stmt *stmt = NULL;
|
|
133
|
+
|
|
134
|
+
// Prepare "SELECT [expr] FROM data" to see if it's valid in the
|
|
135
|
+
// context of the 'data' table.
|
|
136
|
+
char *sql_valid_test = sqlite3_mprintf("SELECT %s FROM data LIMIT 0", expr);
|
|
137
|
+
if (!sql_valid_test) {
|
|
138
|
+
*err = errno;
|
|
139
|
+
return zsv_select_sql_expression_other;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const char *pzTail = NULL;
|
|
143
|
+
int rc = sqlite3_prepare_v2(db, sql_valid_test, -1, &stmt, &pzTail);
|
|
144
|
+
sqlite3_free(sql_valid_test); // Free the string immediately
|
|
145
|
+
if (rc != SQLITE_OK) {
|
|
146
|
+
if (stmt)
|
|
147
|
+
sqlite3_finalize(stmt);
|
|
148
|
+
return zsv_select_sql_expression_invalid;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// if we are here, the expression is valid. check it is a single statement
|
|
152
|
+
// pzTail points to the start of the *next* statement. If it's not
|
|
153
|
+
// empty or just whitespace, the user tried to inject a second command.
|
|
154
|
+
if (!is_str_empty(pzTail)) {
|
|
155
|
+
sqlite3_finalize(stmt);
|
|
156
|
+
return zsv_select_sql_expression_multiple_statements;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check that we have a single expression (e.g., not "myvalue, 123")
|
|
160
|
+
int col_count = sqlite3_column_count(stmt);
|
|
161
|
+
|
|
162
|
+
sqlite3_finalize(stmt);
|
|
163
|
+
if (col_count != 1)
|
|
164
|
+
return zsv_select_sql_expression_multiple_expressions;
|
|
165
|
+
|
|
166
|
+
return zsv_select_sql_expression_valid;
|
|
167
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#ifndef ZSVSHEET_INTERNAL_H
|
|
2
|
+
#define ZSVSHEET_INTERNAL_H
|
|
3
|
+
|
|
4
|
+
#define ZSVSHEET_ROWNUM_HEADER "Row #"
|
|
5
|
+
#define ZSVSHEET_ROWNUM_HEADER_LEN strlen(ZSVSHEET_ROWNUM_HEADER)
|
|
6
|
+
|
|
7
|
+
enum zsvsheet_priv_status {
|
|
8
|
+
zsvsheet_priv_status_ok = 0,
|
|
9
|
+
zsvsheet_priv_status_memory,
|
|
10
|
+
zsvsheet_priv_status_error, // generic error
|
|
11
|
+
zsvsheet_priv_status_utf8,
|
|
12
|
+
zsvsheet_priv_status_continue // ignore / continue
|
|
13
|
+
// zsvsheet_priv_status_duplicate
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
struct zsvsheet_input_dimensions {
|
|
17
|
+
size_t col_count;
|
|
18
|
+
size_t row_count;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
struct zsvsheet_display_dimensions {
|
|
22
|
+
size_t rows;
|
|
23
|
+
size_t columns;
|
|
24
|
+
size_t header_span;
|
|
25
|
+
size_t footer_span;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
struct zsvsheet_buffer_info_internal {
|
|
29
|
+
unsigned char index_started : 1;
|
|
30
|
+
unsigned char index_ready : 1;
|
|
31
|
+
unsigned char write_in_progress : 1;
|
|
32
|
+
unsigned char write_done : 1;
|
|
33
|
+
unsigned char _ : 4;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
#endif
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2021 Liquidaty and zsv contributors. All rights
|
|
3
|
+
* reserved. This file is part of zsv/lib, distributed under the
|
|
4
|
+
* license defined at https://opensource.org/licenses/MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#include <assert.h>
|
|
8
|
+
#include <errno.h>
|
|
9
|
+
#include "../external/sqlite3/sqlite3.h"
|
|
10
|
+
#include <zsv/ext/implementation.h>
|
|
11
|
+
#include <zsv/ext/sheet.h>
|
|
12
|
+
#include <zsv/utils/writer.h>
|
|
13
|
+
#include <zsv/utils/file.h>
|
|
14
|
+
#include <zsv/utils/prop.h>
|
|
15
|
+
#include "file.h"
|
|
16
|
+
#include "handlers_internal.h"
|
|
17
|
+
#include "./curses.h"
|
|
18
|
+
#include "../sql_internal.h"
|
|
19
|
+
|
|
20
|
+
struct sqlfilter_data {
|
|
21
|
+
char *value_sql; // the sql expression entered by the user e.g. City
|
|
22
|
+
char *data_filename;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
static void sqlfilter_data_delete(void *h) {
|
|
26
|
+
struct sqlfilter_data *pd = h;
|
|
27
|
+
if (pd) {
|
|
28
|
+
free(pd->value_sql);
|
|
29
|
+
free(pd->data_filename);
|
|
30
|
+
free(pd);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
static struct sqlfilter_data *sqlfilter_data_new(const char *data_filename, const char *value_sql) {
|
|
35
|
+
struct sqlfilter_data *pd = calloc(1, sizeof(*pd));
|
|
36
|
+
if (pd && (pd->value_sql = strdup(value_sql)) && (pd->data_filename = strdup(data_filename)))
|
|
37
|
+
return pd;
|
|
38
|
+
sqlfilter_data_delete(pd);
|
|
39
|
+
return NULL;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static void zsvsheet_check_buffer_worker_updates(struct zsvsheet_ui_buffer *ub,
|
|
43
|
+
struct zsvsheet_display_dimensions *display_dims,
|
|
44
|
+
struct zsvsheet_sheet_context *handler_state);
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Here we define a custom command for the zsv `sheet` feature
|
|
48
|
+
*/
|
|
49
|
+
static zsvsheet_status zsvsheet_sqlfilter_handler(struct zsvsheet_proc_context *ctx) {
|
|
50
|
+
char result_buffer[256] = {0};
|
|
51
|
+
const char *expr;
|
|
52
|
+
zsvsheet_buffer_t buff = zsvsheet_buffer_current(ctx);
|
|
53
|
+
struct zsvsheet_buffer_data bd = zsvsheet_buffer_info(buff);
|
|
54
|
+
const char add_row_num = !bd.has_row_num;
|
|
55
|
+
const char *data_filename = NULL;
|
|
56
|
+
if (buff)
|
|
57
|
+
data_filename = zsvsheet_buffer_data_filename(buff);
|
|
58
|
+
|
|
59
|
+
if (!data_filename) { // TO DO: check that the underlying data is a tabular file and we know how to parse
|
|
60
|
+
zsvsheet_ui_buffer_set_status(buff, "SQL filter only available for tabular data buffers");
|
|
61
|
+
return zsvsheet_status_ok;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
char *selected_cell_str_dup = NULL;
|
|
65
|
+
switch (ctx->proc_id) {
|
|
66
|
+
case zsvsheet_builtin_proc_sqlfilter:
|
|
67
|
+
zsvsheet_ext_prompt(ctx, result_buffer, sizeof(result_buffer), "Enter SQL expr to filter by");
|
|
68
|
+
if (*result_buffer == '\0')
|
|
69
|
+
return zsvsheet_status_ok;
|
|
70
|
+
expr = result_buffer;
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
assert(0);
|
|
74
|
+
return zsvsheet_status_error;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
enum zsvsheet_status zst = zsvsheet_status_ok;
|
|
78
|
+
struct zsv_sqlite3_dbopts dbopts = {0};
|
|
79
|
+
struct zsv_opts zopts = zsvsheet_buffer_get_zsv_opts(buff);
|
|
80
|
+
struct zsv_sqlite3_db *zdb = zsv_sqlite3_db_new(&dbopts);
|
|
81
|
+
sqlite3_str *sql_str = NULL;
|
|
82
|
+
struct sqlfilter_data *sqlfd = NULL;
|
|
83
|
+
if (!zdb || !(sql_str = sqlite3_str_new(zdb->db)))
|
|
84
|
+
zst = zsvsheet_status_memory;
|
|
85
|
+
else if (zdb->rc == SQLITE_OK && zsv_sqlite3_add_csv_no_dq(zdb, data_filename, &zopts, NULL) == SQLITE_OK) {
|
|
86
|
+
int ok = 0;
|
|
87
|
+
const char *err_msg = NULL;
|
|
88
|
+
int err = 0;
|
|
89
|
+
if (is_constant_expression(zdb->db, expr, &err))
|
|
90
|
+
err_msg = "Please enter an expression that is not a constant";
|
|
91
|
+
else {
|
|
92
|
+
enum check_select_expression_result expr_rc = check_select_expression(zdb->db, expr, &err);
|
|
93
|
+
if (expr_rc != zsv_select_sql_expression_valid)
|
|
94
|
+
err_msg = check_select_expression_result_str(expr_rc);
|
|
95
|
+
else if (!err)
|
|
96
|
+
ok = 1;
|
|
97
|
+
}
|
|
98
|
+
if (!ok) {
|
|
99
|
+
if (err)
|
|
100
|
+
zsvsheet_ui_buffer_set_status(buff, strerror(err));
|
|
101
|
+
else if (err_msg)
|
|
102
|
+
zsvsheet_ui_buffer_set_status(buff, err_msg);
|
|
103
|
+
else
|
|
104
|
+
zsvsheet_ui_buffer_set_status(buff, "Unknown error");
|
|
105
|
+
} else {
|
|
106
|
+
if (add_row_num)
|
|
107
|
+
sqlite3_str_appendf(sql_str, "select ROWID as %Q, * from data where %s", ZSVSHEET_ROWNUM_HEADER, expr);
|
|
108
|
+
else
|
|
109
|
+
sqlite3_str_appendf(sql_str, "select * from data where %s", expr);
|
|
110
|
+
|
|
111
|
+
if (!(sqlfd = sqlfilter_data_new(data_filename, expr)))
|
|
112
|
+
zst = zsvsheet_status_memory;
|
|
113
|
+
else {
|
|
114
|
+
zst = zsv_sqlite3_to_csv(ctx, zdb, sqlite3_str_value(sql_str), &err_msg, sqlfd, NULL, NULL);
|
|
115
|
+
if (zst != zsvsheet_status_ok) {
|
|
116
|
+
if (zst == zsvsheet_status_no_data)
|
|
117
|
+
zsvsheet_ui_buffer_set_status(buff, "No results returned");
|
|
118
|
+
else
|
|
119
|
+
zsvsheet_ui_buffer_set_status(buff, err_msg ? err_msg : "Unexpected error preparing SQL");
|
|
120
|
+
} else {
|
|
121
|
+
buff = zsvsheet_buffer_current(ctx);
|
|
122
|
+
zsvsheet_buffer_set_ctx(buff, sqlfd, sqlfilter_data_delete);
|
|
123
|
+
sqlfd = NULL; // so that it isn't cleaned up below
|
|
124
|
+
|
|
125
|
+
while (!zsvsheet_ui_buffer_index_ready(buff, 0))
|
|
126
|
+
napms(200); // sleep for 200ms, then check index again
|
|
127
|
+
// TO DO: fix this if there is no data!
|
|
128
|
+
|
|
129
|
+
if (selected_cell_str_dup) {
|
|
130
|
+
struct zsvsheet_sheet_context *state = (struct zsvsheet_sheet_context *)ctx->subcommand_context;
|
|
131
|
+
struct zsvsheet_display_info *di = &state->display_info;
|
|
132
|
+
zsvsheet_check_buffer_worker_updates(buff, di->dimensions, NULL);
|
|
133
|
+
zsvsheet_handle_find_next(di, buff, selected_cell_str_dup,
|
|
134
|
+
1, // find value in first column
|
|
135
|
+
1, // exact
|
|
136
|
+
1, // header_span
|
|
137
|
+
di->dimensions, &di->update_buffer, NULL);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// TO DO: add param to ext_sheet_open_file to set filename vs data_filename, and set buffer type or proc owner
|
|
143
|
+
// TO DO: add way to attach custom context, and custom context destructor, to the new buffer
|
|
144
|
+
// TO DO: add cell highlighting
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
zsv_sqlite3_db_delete(zdb);
|
|
148
|
+
if (sql_str)
|
|
149
|
+
sqlite3_free(sqlite3_str_finish(sql_str));
|
|
150
|
+
sqlfilter_data_delete(sqlfd);
|
|
151
|
+
free(selected_cell_str_dup);
|
|
152
|
+
return zst;
|
|
153
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
#include <unistd.h>
|
|
5
|
+
|
|
6
|
+
// check_or_set_terminfo: return 1 if ok, 0 if not
|
|
7
|
+
static int terminfo_ok(void) {
|
|
8
|
+
// Check if TERMINFO environment variable is set
|
|
9
|
+
char *terminfo_env = getenv("TERMINFO");
|
|
10
|
+
if (terminfo_env != NULL)
|
|
11
|
+
return 1; // ok
|
|
12
|
+
|
|
13
|
+
// Check some default locations
|
|
14
|
+
const char *default_paths[] = {
|
|
15
|
+
"/usr/share/terminfo", "/lib/terminfo", "/usr/lib/terminfo", "/etc/terminfo", "/usr/local/share/terminfo", NULL};
|
|
16
|
+
|
|
17
|
+
for (int i = 0; default_paths[i] != NULL; i++) {
|
|
18
|
+
if (access(default_paths[i], R_OK) == 0) {
|
|
19
|
+
// Set the TERMINFO environment variable
|
|
20
|
+
if (setenv("TERMINFO", default_paths[i], 1) == 0)
|
|
21
|
+
return 1; // ok
|
|
22
|
+
else {
|
|
23
|
+
perror("Failed to set TERMINFO environment variable");
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
#if defined(WIN32) || defined(_WIN32)
|
|
29
|
+
return 1; // ok
|
|
30
|
+
#endif
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
#include <stdlib.h>
|
|
2
|
+
#include <string.h>
|
|
3
|
+
#include <pthread.h>
|
|
4
|
+
#include <zsv/utils/file.h>
|
|
5
|
+
#include <zsv/utils/prop.h>
|
|
6
|
+
|
|
7
|
+
#include "handlers_internal.h"
|
|
8
|
+
#include "transformation.h"
|
|
9
|
+
#include "../utils/index.h"
|
|
10
|
+
|
|
11
|
+
struct zsvsheet_transformation {
|
|
12
|
+
zsv_parser parser;
|
|
13
|
+
zsv_csv_writer writer;
|
|
14
|
+
char *output_filename;
|
|
15
|
+
FILE *output_stream;
|
|
16
|
+
unsigned char *output_buffer;
|
|
17
|
+
int output_fileno;
|
|
18
|
+
char writer_wrote;
|
|
19
|
+
struct zsvsheet_transformation_opts opts;
|
|
20
|
+
void *user_context;
|
|
21
|
+
|
|
22
|
+
struct zsvsheet_ui_buffer *ui_buffer;
|
|
23
|
+
char *default_status;
|
|
24
|
+
void (*on_done)(zsvsheet_transformation trn);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static size_t transformation_write(const void *restrict ptr, size_t size, size_t nitems, void *restrict stream) {
|
|
28
|
+
struct zsvsheet_transformation *trn = stream;
|
|
29
|
+
|
|
30
|
+
const size_t count = fwrite(ptr, size, nitems, trn->output_stream);
|
|
31
|
+
trn->writer_wrote = count > 0;
|
|
32
|
+
|
|
33
|
+
return count > 0 ? count : 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
struct transformation_writer_index_ctx {
|
|
37
|
+
void *index;
|
|
38
|
+
zsv_csv_writer writer;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
static void transformation_writer_index_on_row(void *p) {
|
|
42
|
+
struct transformation_writer_index_ctx *ctx = p;
|
|
43
|
+
uint64_t written = zsv_writer_cum_bytes_written(ctx->writer);
|
|
44
|
+
zsv_index_add_row(ctx->index, written);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
static void transformation_writer_index_delete(void *p) {
|
|
48
|
+
struct transformation_writer_index_ctx *ctx = p;
|
|
49
|
+
uint64_t written = zsv_writer_cum_bytes_written(ctx->writer);
|
|
50
|
+
if (written)
|
|
51
|
+
zsv_index_add_row(ctx->index, written);
|
|
52
|
+
free(ctx);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
enum zsv_status zsvsheet_transformation_new(struct zsvsheet_transformation_opts opts, zsvsheet_transformation *out) {
|
|
56
|
+
unsigned char *temp_buff = NULL;
|
|
57
|
+
char *temp_filename = NULL;
|
|
58
|
+
FILE *temp_f = NULL;
|
|
59
|
+
zsv_csv_writer temp_file_writer = NULL;
|
|
60
|
+
struct transformation_writer_index_ctx *ctx = NULL;
|
|
61
|
+
enum zsv_status zst = zsv_status_memory;
|
|
62
|
+
|
|
63
|
+
struct zsvsheet_transformation *trn = calloc(1, sizeof(*trn));
|
|
64
|
+
if (trn == NULL)
|
|
65
|
+
return zst;
|
|
66
|
+
|
|
67
|
+
trn->on_done = opts.on_done;
|
|
68
|
+
trn->ui_buffer = opts.ui_buffer;
|
|
69
|
+
zst = zsv_status_error;
|
|
70
|
+
|
|
71
|
+
temp_filename = zsv_get_temp_filename("zsvsheet_filter_XXXXXXXX");
|
|
72
|
+
if (!temp_filename)
|
|
73
|
+
goto free;
|
|
74
|
+
trn->output_filename = temp_filename;
|
|
75
|
+
|
|
76
|
+
if (!(temp_f = fopen(temp_filename, "w+")))
|
|
77
|
+
goto free;
|
|
78
|
+
if (setvbuf(temp_f, NULL, _IONBF, 0))
|
|
79
|
+
goto free;
|
|
80
|
+
trn->output_stream = temp_f;
|
|
81
|
+
|
|
82
|
+
ctx = calloc(1, sizeof(*ctx));
|
|
83
|
+
if (!ctx)
|
|
84
|
+
goto free;
|
|
85
|
+
ctx->index = opts.index;
|
|
86
|
+
|
|
87
|
+
struct zsv_csv_writer_options writer_opts = {
|
|
88
|
+
.with_bom = 0,
|
|
89
|
+
.write = transformation_write,
|
|
90
|
+
.stream = trn,
|
|
91
|
+
.table_init = NULL,
|
|
92
|
+
.table_init_ctx = NULL,
|
|
93
|
+
.on_row = transformation_writer_index_on_row,
|
|
94
|
+
.on_row_ctx = ctx,
|
|
95
|
+
.on_delete = transformation_writer_index_delete,
|
|
96
|
+
.on_delete_ctx = ctx,
|
|
97
|
+
};
|
|
98
|
+
if (!(temp_file_writer = zsv_writer_new(&writer_opts)))
|
|
99
|
+
goto free;
|
|
100
|
+
|
|
101
|
+
ctx->writer = temp_file_writer;
|
|
102
|
+
const size_t temp_buff_size = 2 * 1024 * 1024;
|
|
103
|
+
temp_buff = malloc(temp_buff_size);
|
|
104
|
+
if (!temp_buff)
|
|
105
|
+
goto free;
|
|
106
|
+
trn->output_buffer = temp_buff;
|
|
107
|
+
zsv_writer_set_temp_buff(temp_file_writer, temp_buff, temp_buff_size);
|
|
108
|
+
trn->writer = temp_file_writer;
|
|
109
|
+
|
|
110
|
+
trn->user_context = opts.zsv_opts.ctx;
|
|
111
|
+
opts.zsv_opts.ctx = trn;
|
|
112
|
+
|
|
113
|
+
zst = zsv_new_with_properties(&opts.zsv_opts, opts.custom_prop_handler, opts.input_filename, &trn->parser);
|
|
114
|
+
if (zst != zsv_status_ok)
|
|
115
|
+
goto free;
|
|
116
|
+
|
|
117
|
+
*out = trn;
|
|
118
|
+
return zst;
|
|
119
|
+
|
|
120
|
+
free:
|
|
121
|
+
if (trn)
|
|
122
|
+
free(trn);
|
|
123
|
+
if (temp_filename)
|
|
124
|
+
free(temp_filename);
|
|
125
|
+
if (temp_f)
|
|
126
|
+
fclose(temp_f);
|
|
127
|
+
if (temp_file_writer)
|
|
128
|
+
zsv_writer_delete(temp_file_writer);
|
|
129
|
+
if (temp_buff)
|
|
130
|
+
free(temp_buff);
|
|
131
|
+
if (ctx)
|
|
132
|
+
transformation_writer_index_delete(ctx);
|
|
133
|
+
|
|
134
|
+
return zst;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void zsvsheet_transformation_delete(zsvsheet_transformation trn) {
|
|
138
|
+
zsv_writer_delete(trn->writer);
|
|
139
|
+
zsv_delete(trn->parser);
|
|
140
|
+
free(trn->output_filename);
|
|
141
|
+
fclose(trn->output_stream);
|
|
142
|
+
free(trn->output_buffer);
|
|
143
|
+
free(trn);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
zsv_parser zsvsheet_transformation_parser(zsvsheet_transformation trn) {
|
|
147
|
+
return trn->parser;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
zsv_csv_writer zsvsheet_transformation_writer(zsvsheet_transformation trn) {
|
|
151
|
+
return trn->writer;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const char *zsvsheet_transformation_filename(zsvsheet_transformation trn) {
|
|
155
|
+
return trn->output_filename;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
void *zsvsheet_transformation_user_context(zsvsheet_transformation trn) {
|
|
159
|
+
return trn->user_context;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
static void *zsvsheet_run_buffer_transformation(void *arg) {
|
|
163
|
+
struct zsvsheet_transformation *trn = arg;
|
|
164
|
+
struct zsvsheet_ui_buffer *uib = trn->ui_buffer;
|
|
165
|
+
zsv_parser parser = trn->parser;
|
|
166
|
+
pthread_mutex_t *mutex = &uib->mutex;
|
|
167
|
+
enum zsv_status zst;
|
|
168
|
+
char *default_status = trn->default_status;
|
|
169
|
+
|
|
170
|
+
char cancelled = 0;
|
|
171
|
+
while (!cancelled && (zst = zsv_parse_more(parser)) == zsv_status_ok) {
|
|
172
|
+
pthread_mutex_lock(mutex);
|
|
173
|
+
cancelled = uib->worker_cancelled;
|
|
174
|
+
if (trn->writer_wrote) {
|
|
175
|
+
trn->writer_wrote = 0;
|
|
176
|
+
zsv_index_commit_rows(uib->index);
|
|
177
|
+
uib->index_ready = 1;
|
|
178
|
+
}
|
|
179
|
+
pthread_mutex_unlock(mutex);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (zst == zsv_status_no_more_input || zst == zsv_status_cancelled)
|
|
183
|
+
zsv_finish(parser);
|
|
184
|
+
|
|
185
|
+
if (trn->on_done)
|
|
186
|
+
trn->on_done(trn);
|
|
187
|
+
|
|
188
|
+
if (trn->user_context)
|
|
189
|
+
free(trn->user_context);
|
|
190
|
+
|
|
191
|
+
zsvsheet_transformation_delete(trn);
|
|
192
|
+
|
|
193
|
+
pthread_mutex_lock(mutex);
|
|
194
|
+
char *buff_status_old = uib->status;
|
|
195
|
+
uib->write_done = 1;
|
|
196
|
+
zsv_index_commit_rows(uib->index);
|
|
197
|
+
uib->index_ready = 1;
|
|
198
|
+
if (buff_status_old == default_status)
|
|
199
|
+
uib->status = NULL;
|
|
200
|
+
pthread_mutex_unlock(mutex);
|
|
201
|
+
|
|
202
|
+
if (buff_status_old == default_status)
|
|
203
|
+
free(buff_status_old);
|
|
204
|
+
|
|
205
|
+
return NULL;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
enum zsvsheet_status zsvsheet_push_transformation(zsvsheet_proc_context_t ctx,
|
|
209
|
+
struct zsvsheet_buffer_transformation_opts opts) {
|
|
210
|
+
zsvsheet_buffer_t buff = zsvsheet_buffer_current(ctx);
|
|
211
|
+
const char *filename = zsvsheet_buffer_data_filename(buff);
|
|
212
|
+
enum zsvsheet_status stat = zsvsheet_status_error;
|
|
213
|
+
struct zsvsheet_buffer_info_internal info = zsvsheet_buffer_info_internal(buff);
|
|
214
|
+
struct zsv_index *index = NULL;
|
|
215
|
+
|
|
216
|
+
// TODO: Starting a second transformation before the first ends works, but if the second is faster
|
|
217
|
+
// than the first then it can end prematurely and read a partially written row.
|
|
218
|
+
// We could override the input stream reader to wait for more data when it sees EOF
|
|
219
|
+
if (info.write_in_progress && !info.write_done)
|
|
220
|
+
return zsvsheet_status_busy;
|
|
221
|
+
|
|
222
|
+
if (!(index = zsv_index_new()))
|
|
223
|
+
return zsvsheet_status_memory;
|
|
224
|
+
|
|
225
|
+
// TODO: custom_prop_handler is not passed to extensions?
|
|
226
|
+
struct zsvsheet_transformation_opts trn_opts = {
|
|
227
|
+
.custom_prop_handler = NULL,
|
|
228
|
+
.input_filename = filename,
|
|
229
|
+
.on_done = opts.on_done,
|
|
230
|
+
.ui_buffer = NULL,
|
|
231
|
+
.index = index,
|
|
232
|
+
};
|
|
233
|
+
zsvsheet_transformation trn = NULL;
|
|
234
|
+
struct zsv_opts zopts = zsvsheet_buffer_get_zsv_opts(buff);
|
|
235
|
+
|
|
236
|
+
zopts.ctx = opts.user_context;
|
|
237
|
+
zopts.row_handler = (void (*)(void *))opts.row_handler;
|
|
238
|
+
zopts.stream = fopen(filename, "rb");
|
|
239
|
+
zopts.buffsize = 2 * 1024 * 1024;
|
|
240
|
+
|
|
241
|
+
if (!zopts.stream)
|
|
242
|
+
goto error;
|
|
243
|
+
|
|
244
|
+
trn_opts.zsv_opts = zopts;
|
|
245
|
+
|
|
246
|
+
enum zsv_status zst = zsvsheet_transformation_new(trn_opts, &trn);
|
|
247
|
+
if (zst != zsv_status_ok)
|
|
248
|
+
goto error;
|
|
249
|
+
|
|
250
|
+
// Transform part of the file to initially populate the UI buffer
|
|
251
|
+
// TODO: If the transformation is a reduction that doesn't output for some time this will caus a pause
|
|
252
|
+
zsv_parser parser = zsvsheet_transformation_parser(trn);
|
|
253
|
+
while ((zst = zsv_parse_more(parser)) == zsv_status_ok) {
|
|
254
|
+
if (trn->writer_wrote)
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
trn->writer_wrote = 0;
|
|
258
|
+
|
|
259
|
+
switch (zst) {
|
|
260
|
+
case zsv_status_no_more_input:
|
|
261
|
+
case zsv_status_cancelled:
|
|
262
|
+
if (zsv_finish(parser) != zsv_status_ok)
|
|
263
|
+
goto error;
|
|
264
|
+
zsv_writer_flush(trn->writer);
|
|
265
|
+
break;
|
|
266
|
+
case zsv_status_ok:
|
|
267
|
+
break;
|
|
268
|
+
default:
|
|
269
|
+
goto error;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
struct zsvsheet_ui_buffer_opts uibopts = {0};
|
|
273
|
+
|
|
274
|
+
uibopts.data_filename = zsvsheet_transformation_filename(trn);
|
|
275
|
+
uibopts.write_after_open = 1;
|
|
276
|
+
|
|
277
|
+
stat = zsvsheet_open_file_opts(ctx, &uibopts);
|
|
278
|
+
if (stat != zsvsheet_status_ok)
|
|
279
|
+
goto error;
|
|
280
|
+
|
|
281
|
+
struct zsvsheet_ui_buffer *nbuff = zsvsheet_buffer_current(ctx);
|
|
282
|
+
trn->ui_buffer = nbuff;
|
|
283
|
+
zsv_index_commit_rows(index);
|
|
284
|
+
nbuff->index_started = 1;
|
|
285
|
+
nbuff->index = index;
|
|
286
|
+
|
|
287
|
+
if (zst != zsv_status_ok) {
|
|
288
|
+
nbuff->write_done = 1;
|
|
289
|
+
nbuff->index_ready = 1;
|
|
290
|
+
if (trn->on_done)
|
|
291
|
+
opts.on_done(trn);
|
|
292
|
+
zsvsheet_transformation_delete(trn);
|
|
293
|
+
zsv_index_commit_rows(index);
|
|
294
|
+
return stat;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
asprintf(&trn->default_status, "(working) Press ESC to cancel ");
|
|
298
|
+
nbuff->status = trn->default_status;
|
|
299
|
+
|
|
300
|
+
zsvsheet_ui_buffer_create_worker(nbuff, zsvsheet_run_buffer_transformation, trn);
|
|
301
|
+
return stat;
|
|
302
|
+
|
|
303
|
+
error:
|
|
304
|
+
zsv_index_delete(index);
|
|
305
|
+
|
|
306
|
+
if (trn && trn->on_done)
|
|
307
|
+
opts.on_done(trn);
|
|
308
|
+
if (trn)
|
|
309
|
+
zsvsheet_transformation_delete(trn);
|
|
310
|
+
|
|
311
|
+
return stat;
|
|
312
|
+
}
|