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,366 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2021 Liquidaty and zsv contributors. All rights reserved.
|
|
3
|
+
* This file is part of zsv/lib, distributed under the license defined at
|
|
4
|
+
* https://opensource.org/licenses/MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
#include <assert.h>
|
|
11
|
+
#include <zsv/ext/implementation.h>
|
|
12
|
+
#include <zsv/ext/sheet.h>
|
|
13
|
+
#include <zsv/utils/writer.h>
|
|
14
|
+
#include <zsv/utils/file.h>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* `zsv` can easily be extended by simply creating a shared library
|
|
18
|
+
* that implements the interface specified in zsv/ext/implementation.h
|
|
19
|
+
* for any extension id of up to 8 bytes
|
|
20
|
+
*
|
|
21
|
+
* Once the library file is created, you can run any commands it implements
|
|
22
|
+
* by naming the library file zsvext<id>, placing it in any folder that is
|
|
23
|
+
* in the system lib search path, or in the same folder as zsv, and running:
|
|
24
|
+
* `zsv xx-command`
|
|
25
|
+
*
|
|
26
|
+
* It's as simple as that!
|
|
27
|
+
*
|
|
28
|
+
* In this example, we will implement two simple commands:
|
|
29
|
+
* * `count` will count lines
|
|
30
|
+
* * `echo` will regurgitate its input to stdout
|
|
31
|
+
*
|
|
32
|
+
* We will name our extension "my", so our shared library will be named
|
|
33
|
+
* zsvextmy.so (non-win) or zsvextmy.dll (win). After the shared lib is built,
|
|
34
|
+
* place it anywhere in the PATH or in the same folder as the zsv binary.
|
|
35
|
+
* Our extension commands can then be invoked by running:
|
|
36
|
+
* `zsv my-count`
|
|
37
|
+
* `zsv my-echo`
|
|
38
|
+
*
|
|
39
|
+
* in addition, a description of our extension is available via:
|
|
40
|
+
* `zsv help`
|
|
41
|
+
*
|
|
42
|
+
* and command-specific help displayed via:
|
|
43
|
+
* `zsv help my-<command>`
|
|
44
|
+
*
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* *Required*: define our extension id, of up to 8 bytes in length
|
|
49
|
+
*/
|
|
50
|
+
const char *zsv_ext_id(void) {
|
|
51
|
+
return "my";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* When our library is initialized, zsv will pass it the address of the zsvlib
|
|
56
|
+
* functions we will be using. We can keep track of this any way we want;
|
|
57
|
+
* in this example, we use a global variable to store the function pointers
|
|
58
|
+
*/
|
|
59
|
+
static struct zsv_ext_callbacks zsv_cb;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Each command must be implemented as a function with a signature
|
|
63
|
+
* as defined by `zsv_ext_main`. This is basically the same as a main() function,
|
|
64
|
+
* but with an additional preceding zsv_execution_context parameter.
|
|
65
|
+
* Here, we just declare the functions; we fully define them further below
|
|
66
|
+
*/
|
|
67
|
+
enum zsv_ext_status count_main(zsv_execution_context ctx, int argc, const char *argv[], struct zsv_opts *opts);
|
|
68
|
+
static enum zsv_ext_status echo_main(zsv_execution_context ctx, int argc, const char *argv[], struct zsv_opts *opts);
|
|
69
|
+
|
|
70
|
+
#ifdef ZSVSHEET_BUILD
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Here we define a custom command for the zsv `sheet` feature
|
|
74
|
+
*/
|
|
75
|
+
zsvsheet_status my_test_command_handler(zsvsheet_proc_context_t ctx) {
|
|
76
|
+
char result_buffer[256] = {0};
|
|
77
|
+
int ch = zsv_cb.ext_sheet_keypress(ctx);
|
|
78
|
+
if (ch < 0)
|
|
79
|
+
return zsvsheet_status_error;
|
|
80
|
+
zsv_cb.ext_sheet_prompt(ctx, result_buffer, sizeof(result_buffer), "You pressed %c. Now enter something here",
|
|
81
|
+
(char)ch);
|
|
82
|
+
if (*result_buffer == '\0')
|
|
83
|
+
return zsvsheet_status_ok;
|
|
84
|
+
|
|
85
|
+
char *temp_filename = zsv_get_temp_filename("zsvsheet_extension_example.csv");
|
|
86
|
+
if (!temp_filename) {
|
|
87
|
+
fprintf(stderr, "Out of memory!\n");
|
|
88
|
+
return zsvsheet_status_error;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
FILE *f = fopen(temp_filename, "wb");
|
|
92
|
+
if (!f)
|
|
93
|
+
zsv_cb.ext_sheet_set_status(ctx, "Unable to open for write: %s", temp_filename);
|
|
94
|
+
else {
|
|
95
|
+
fprintf(f, "buffer #,file name\n");
|
|
96
|
+
// get a count of open buffers
|
|
97
|
+
int i = 0;
|
|
98
|
+
for (zsvsheet_buffer_t buff = zsv_cb.ext_sheet_buffer_current(ctx); buff;
|
|
99
|
+
buff = zsv_cb.ext_sheet_buffer_prior(buff), i++)
|
|
100
|
+
;
|
|
101
|
+
|
|
102
|
+
// print a list of open buffers and filenames
|
|
103
|
+
for (zsvsheet_buffer_t buff = zsv_cb.ext_sheet_buffer_current(ctx); buff;
|
|
104
|
+
buff = zsv_cb.ext_sheet_buffer_prior(buff), i--) {
|
|
105
|
+
const char *buff_filename = zsv_cb.ext_sheet_buffer_data_filename(buff);
|
|
106
|
+
if (buff_filename)
|
|
107
|
+
fprintf(f, "%i,%s\n", i, buff_filename); // assumes no need for quoting or escaping buff_filename...
|
|
108
|
+
}
|
|
109
|
+
fclose(f);
|
|
110
|
+
return zsv_cb.ext_sheet_open_file(ctx, temp_filename, NULL);
|
|
111
|
+
}
|
|
112
|
+
free(temp_filename);
|
|
113
|
+
return zsvsheet_status_ok;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
struct transformation_context {
|
|
117
|
+
zsvsheet_proc_context_t proc_ctx;
|
|
118
|
+
size_t col_count;
|
|
119
|
+
size_t row_count;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Similar to a regular ZSV row handler used in ext_parse_all
|
|
123
|
+
void my_transformation_row_handler(zsvsheet_transformation trn) {
|
|
124
|
+
struct transformation_context *priv = zsv_cb.ext_sheet_transformation_user_context(trn);
|
|
125
|
+
zsv_parser parser = zsv_cb.ext_sheet_transformation_parser(trn);
|
|
126
|
+
zsv_csv_writer writer = zsv_cb.ext_sheet_transformation_writer(trn);
|
|
127
|
+
|
|
128
|
+
size_t j = zsv_cb.cell_count(parser);
|
|
129
|
+
for (size_t i = 0; i < j; i++) {
|
|
130
|
+
struct zsv_cell c = zsv_cb.get_cell(parser, i);
|
|
131
|
+
zsv_writer_cell(writer, i == 0, c.str, c.len, c.quoted);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
priv->col_count += j;
|
|
135
|
+
|
|
136
|
+
if (!priv->row_count)
|
|
137
|
+
zsv_writer_cell_s(writer, 0, (const unsigned char *)"Column count", 0);
|
|
138
|
+
else
|
|
139
|
+
zsv_writer_cell_zu(writer, 0, priv->col_count);
|
|
140
|
+
|
|
141
|
+
priv->row_count++;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
zsvsheet_status my_transformation_command_handler(zsvsheet_proc_context_t ctx) {
|
|
145
|
+
struct zsvsheet_buffer_transformation_opts opts = {
|
|
146
|
+
// Gets freed automatically
|
|
147
|
+
.user_context = calloc(1, sizeof(struct transformation_context)),
|
|
148
|
+
.row_handler = my_transformation_row_handler,
|
|
149
|
+
.on_done = NULL,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return zsv_cb.ext_sheet_push_transformation(ctx, opts);
|
|
153
|
+
}
|
|
154
|
+
#endif
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* *Required*. Initialization is called when our extension is loaded. Our
|
|
158
|
+
* initialization routine uses `ext_add_command` to register our commands and
|
|
159
|
+
* `ext_set_help` to set the help text. When we register a command, we provide a
|
|
160
|
+
* callback-- in our cases, those will be `count_main()` and `echo_main()`-- for
|
|
161
|
+
* zsv to invoke when our command is run
|
|
162
|
+
*
|
|
163
|
+
* @param callbacks pointers to zsvlib functions that we must save for later use
|
|
164
|
+
* @param ctx context to be passed whenever we execute a zsvlib function from our init
|
|
165
|
+
* @return status code e.g. zsv_ext_status_ok
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
enum zsv_ext_status zsv_ext_init(struct zsv_ext_callbacks *cb, zsv_execution_context ctx) {
|
|
169
|
+
zsv_cb = *cb;
|
|
170
|
+
zsv_cb.ext_set_help(ctx, "Sample zsv extension");
|
|
171
|
+
zsv_cb.ext_set_license(ctx,
|
|
172
|
+
"Unlicense. See https://github.com/spdx/license-list-data/blob/master/text/Unlicense.txt");
|
|
173
|
+
/**
|
|
174
|
+
* In the common case where your extension uses third-party software, you can add
|
|
175
|
+
* the related licenses and acknowledgements here, which `zsv` will display whenever
|
|
176
|
+
* `zsv thirdparty` is invoked
|
|
177
|
+
*/
|
|
178
|
+
const char *third_party_licenses[] = {"If we used any third-party software, we would list each license here", NULL};
|
|
179
|
+
zsv_cb.ext_set_thirdparty(ctx, third_party_licenses);
|
|
180
|
+
zsv_cb.ext_add_command(ctx, "count", "print the number of rows", count_main);
|
|
181
|
+
zsv_cb.ext_add_command(ctx, "echo", "print the input data back to stdout", echo_main);
|
|
182
|
+
|
|
183
|
+
#ifdef ZSVSHEET_BUILD
|
|
184
|
+
int proc_id = zsv_cb.ext_sheet_register_proc("my-test-command", "my test command", my_test_command_handler);
|
|
185
|
+
if (proc_id < 0)
|
|
186
|
+
return zsv_ext_status_error;
|
|
187
|
+
zsv_cb.ext_sheet_register_proc_key_binding('t', proc_id);
|
|
188
|
+
|
|
189
|
+
proc_id = zsv_cb.ext_sheet_register_proc("my-transformation", "my transformation", my_transformation_command_handler);
|
|
190
|
+
if (proc_id < 0)
|
|
191
|
+
return zsv_ext_status_error;
|
|
192
|
+
zsv_cb.ext_sheet_register_proc_key_binding('T', proc_id);
|
|
193
|
+
#endif
|
|
194
|
+
return zsv_ext_status_ok;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* exit: called once by zsv before the library is unloaded, if `zsv_ext_init()` was
|
|
199
|
+
* previously called
|
|
200
|
+
*/
|
|
201
|
+
enum zsv_ext_status zsv_ext_exit(void) {
|
|
202
|
+
fprintf(stderr, "Exiting extension example!\n");
|
|
203
|
+
return zsv_ext_status_ok;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Now we are getting to the "meat" of our program. Each command will be defined by two
|
|
207
|
+
* functions:
|
|
208
|
+
* - a main routine, which initializes private data, calls the parser, then performs any final
|
|
209
|
+
* steps and/or cleanup
|
|
210
|
+
* - a row handler, which is called by the parser for each parsed row
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* structure that our functions will use to store private state data
|
|
215
|
+
* which our functions can retrieve using the zsvlib callback `ext_get_context()`
|
|
216
|
+
*/
|
|
217
|
+
struct my_data {
|
|
218
|
+
zsv_csv_writer csv_writer;
|
|
219
|
+
size_t rows;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Our row handlers retrieve our state data and update and/or operate on it
|
|
224
|
+
* We can choose, in our main routine, for the ctx pointer it receives to be
|
|
225
|
+
* anything we want, but in most cases there is no reason to set it to anything
|
|
226
|
+
* other than the zsv_execution_context passed to main
|
|
227
|
+
*
|
|
228
|
+
* @param ctx a context pointer of our choice, typically set in the main() function
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
static void count_rowhandler(void *ctx) {
|
|
232
|
+
/* get our private data */
|
|
233
|
+
struct my_data *data = zsv_cb.ext_get_context(ctx);
|
|
234
|
+
|
|
235
|
+
/* increment row counter */
|
|
236
|
+
data->rows++;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
static void echo_rowhandler(void *ctx) {
|
|
240
|
+
/* get our private data */
|
|
241
|
+
struct my_data *data = zsv_cb.ext_get_context(ctx);
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* In most cases, we will want to do something with the row that was just parsed,
|
|
245
|
+
* in which case we can use ext_get_parser(), cell_count() and get_cell()
|
|
246
|
+
* to get a parser handle, the number of cells in our current row, and each
|
|
247
|
+
* cell's length and string (and other info)
|
|
248
|
+
*/
|
|
249
|
+
zsv_parser parser = zsv_cb.ext_get_parser(ctx);
|
|
250
|
+
unsigned j = zsv_cb.cell_count(parser);
|
|
251
|
+
for (unsigned i = 0; i < j; i++) {
|
|
252
|
+
struct zsv_cell c = zsv_cb.get_cell(parser, i);
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* get_cell() returns a zsv_cell structure that holds a pointer to the text,
|
|
256
|
+
* the length (in bytes) of the data,
|
|
257
|
+
* and other parser-generated info (e.g. QUOTED flags)
|
|
258
|
+
*/
|
|
259
|
+
/* write the cell contents to csv output */
|
|
260
|
+
zsv_writer_cell(data->csv_writer, i == 0, c.str, c.len, c.quoted);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Our main routines are similar to normal main() functions, except that the first
|
|
266
|
+
* param is a zsvlib-generated zsv_execution_context pointer for use with other
|
|
267
|
+
* `ext_xxx` functions. All we do here is initialize our data, call the parser, and
|
|
268
|
+
* perform any final steps after all data has been processed
|
|
269
|
+
*/
|
|
270
|
+
static enum zsv_ext_status echo_main(zsv_execution_context ctx, int argc, const char *argv[], struct zsv_opts *optsp) {
|
|
271
|
+
(void)(argc);
|
|
272
|
+
(void)(argv);
|
|
273
|
+
(void)(optsp);
|
|
274
|
+
/* initialize private data */
|
|
275
|
+
struct my_data data;
|
|
276
|
+
memset(&data, 0, sizeof(data));
|
|
277
|
+
|
|
278
|
+
/* initialize a csv writer, which we add to our private data structure */
|
|
279
|
+
unsigned char writer_buff[128];
|
|
280
|
+
/**
|
|
281
|
+
* the the zsv_writer utility has two special optimizations: first, it
|
|
282
|
+
* uses its own buffer to short-circuit costly stdio operations, and second,
|
|
283
|
+
* it accepts a 'quoted' flag that, if zero, tells it to not bother
|
|
284
|
+
* checking for quote requirements and to just output the contents 'raw'
|
|
285
|
+
*/
|
|
286
|
+
if (!(data.csv_writer = zsv_writer_new(NULL)))
|
|
287
|
+
return zsv_ext_status_memory;
|
|
288
|
+
zsv_writer_set_temp_buff(data.csv_writer, writer_buff, sizeof(writer_buff));
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* The following common parser options that are already handled by zsv (so long as we use
|
|
292
|
+
* either of the provided callbacks `ext_parse_all()` or `new_with_context()`), including:
|
|
293
|
+
* ```
|
|
294
|
+
* -B,--buff-size <N>
|
|
295
|
+
* -c,--max-column-count <N>
|
|
296
|
+
* -r,--max-row-size <N>
|
|
297
|
+
* -t,--tab-delim
|
|
298
|
+
* -O,--other-delim <C>
|
|
299
|
+
* -q,--no-quote
|
|
300
|
+
* -R,--skip-head <n>: skip specified number of initial rows
|
|
301
|
+
* -d,--header-row-span <n>: apply header depth (rowspan) of n
|
|
302
|
+
* -S,--keep-blank-headers: disable default behavior of ignoring leading blank rows
|
|
303
|
+
* -v,--verbose: verbose output
|
|
304
|
+
* ```
|
|
305
|
+
*
|
|
306
|
+
* If we wanted our command to support parameters for modifying other
|
|
307
|
+
* `zsv_opts`, we could do so here by processing argc and argv[] and taking
|
|
308
|
+
* the appropriate actions to change our private data and/or modify our opts
|
|
309
|
+
* structure
|
|
310
|
+
*
|
|
311
|
+
* For this example, we will not implement any additional options, so the only
|
|
312
|
+
* `zsv_opts` value we need to update is the row handler
|
|
313
|
+
*/
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* use the `ext_parse_all()` convenience function
|
|
317
|
+
*/
|
|
318
|
+
struct zsv_opts opts = zsv_cb.ext_parser_opts(ctx);
|
|
319
|
+
enum zsv_ext_status stat = zsv_cb.ext_parse_all(ctx, &data, echo_rowhandler, &opts);
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* clean up after we finish parsing
|
|
323
|
+
*/
|
|
324
|
+
zsv_writer_delete(data.csv_writer);
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* the return value of the main function will be passed on as the return value
|
|
328
|
+
* of this process invocation
|
|
329
|
+
*/
|
|
330
|
+
return stat;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Our main routine for counting is just like the one for echo, but even simpler
|
|
335
|
+
* since we need not bother with a csv writer
|
|
336
|
+
*/
|
|
337
|
+
static const char *count_help = "count: print the number of rows in a CSV data file\n"
|
|
338
|
+
"\n"
|
|
339
|
+
"usage: count [-h,--help] [filename]\n";
|
|
340
|
+
|
|
341
|
+
enum zsv_ext_status count_main(zsv_execution_context ctx, int argc, const char *argv[], struct zsv_opts *optsp) {
|
|
342
|
+
(void)(optsp);
|
|
343
|
+
/* help */
|
|
344
|
+
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) {
|
|
345
|
+
printf("%s", count_help);
|
|
346
|
+
return zsv_ext_status_ok;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* initialize private data. see above for details */
|
|
350
|
+
struct my_data data = {0};
|
|
351
|
+
struct zsv_opts opts = zsv_cb.ext_parser_opts(ctx);
|
|
352
|
+
|
|
353
|
+
if (argc > 1 && !(opts.stream = fopen(argv[1], "rb"))) {
|
|
354
|
+
fprintf(stderr, "Unable to open for reading: %s\n", argv[1]);
|
|
355
|
+
return 1;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* parse the input data. see above for details */
|
|
359
|
+
enum zsv_ext_status stat = zsv_cb.ext_parse_all(ctx, &data, count_rowhandler, &opts);
|
|
360
|
+
|
|
361
|
+
/* finish up */
|
|
362
|
+
if (stat == zsv_ext_status_ok)
|
|
363
|
+
printf("Rows: %zu\n", data.rows > 0 ? data.rows - 1 : 0);
|
|
364
|
+
|
|
365
|
+
return stat;
|
|
366
|
+
}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2021 Liquidaty and zsv contributors. All rights reserved.
|
|
3
|
+
* This file is part of zsv/lib, distributed under the license defined at
|
|
4
|
+
* https://opensource.org/licenses/MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#include <stdio.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
#include <errno.h>
|
|
11
|
+
#include <assert.h>
|
|
12
|
+
#include "../external/sqlite3/sqlite3.h"
|
|
13
|
+
#include <zsv/ext/implementation.h>
|
|
14
|
+
#include <zsv/ext/sheet.h>
|
|
15
|
+
#include <zsv/utils/writer.h>
|
|
16
|
+
#include <zsv/utils/file.h>
|
|
17
|
+
#include <zsv/utils/prop.h>
|
|
18
|
+
// #include "../curses.h"
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This is an example to demonstrate various extension capabilities
|
|
22
|
+
* specific to the `sheet` subcommand. For examples of extending the
|
|
23
|
+
* CLI outside of `sheet`, see my_extension.c
|
|
24
|
+
*
|
|
25
|
+
* In this example, we will re-implement the built-in pivot table command
|
|
26
|
+
*
|
|
27
|
+
* We will name our extension "mysheet", so our shared library will be named
|
|
28
|
+
* zsvextmysheet.so (non-win) or zsvextmysheet.dll (win). After the shared lib is
|
|
29
|
+
* built, place it anywhere in the PATH or in the same folder as the zsv binary.
|
|
30
|
+
* Our extension can then be invoked by first running `sheet`, and then pressing
|
|
31
|
+
* 'z'
|
|
32
|
+
*
|
|
33
|
+
* in addition, a description of our extension is displayed in the built-in help
|
|
34
|
+
* command (?)
|
|
35
|
+
*
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* *Required*: define our extension id, of up to 8 bytes in length
|
|
40
|
+
*/
|
|
41
|
+
const char *zsv_ext_id(void) {
|
|
42
|
+
return "mysheet";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* When our library is initialized, zsv will pass it the address of the zsvlib
|
|
47
|
+
* functions we will be using. We can keep track of this any way we want;
|
|
48
|
+
* in this example, we use a global variable to store the function pointers
|
|
49
|
+
*/
|
|
50
|
+
static struct zsv_ext_callbacks zsv_cb;
|
|
51
|
+
|
|
52
|
+
#include "../sql_internal.h"
|
|
53
|
+
|
|
54
|
+
struct pivot_row {
|
|
55
|
+
char *value; // to do: this will be the drill-down criteria
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
struct pivot_data {
|
|
59
|
+
char *value_sql; // the sql expression entered by the user e.g. City
|
|
60
|
+
char *data_filename;
|
|
61
|
+
struct {
|
|
62
|
+
struct pivot_row *data; // for each row, the value of the sql expression e.g. New York
|
|
63
|
+
size_t capacity;
|
|
64
|
+
size_t used;
|
|
65
|
+
} rows;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
static void pivot_data_delete(void *h) {
|
|
69
|
+
struct pivot_data *pd = h;
|
|
70
|
+
if (pd) {
|
|
71
|
+
for (size_t i = 0; i < pd->rows.used; i++)
|
|
72
|
+
free(pd->rows.data[i].value);
|
|
73
|
+
free(pd->rows.data);
|
|
74
|
+
free(pd->value_sql);
|
|
75
|
+
free(pd->data_filename);
|
|
76
|
+
free(pd);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static struct pivot_data *pivot_data_new(const char *data_filename, const char *value_sql) {
|
|
81
|
+
struct pivot_data *pd = calloc(1, sizeof(*pd));
|
|
82
|
+
if (pd && (pd->value_sql = strdup(value_sql)) && (pd->data_filename = strdup(data_filename)))
|
|
83
|
+
return pd;
|
|
84
|
+
pivot_data_delete(pd);
|
|
85
|
+
return NULL;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#define ZSV_MYSHEET_EXTENSION_PIVOT_DATA_ROWS_INITIAL 32
|
|
89
|
+
static int pivot_data_grow(struct pivot_data *pd) {
|
|
90
|
+
if (pd->rows.used == pd->rows.capacity) {
|
|
91
|
+
size_t new_capacity =
|
|
92
|
+
pd->rows.capacity == 0 ? ZSV_MYSHEET_EXTENSION_PIVOT_DATA_ROWS_INITIAL : pd->rows.capacity * 2;
|
|
93
|
+
struct pivot_row *new_data = realloc(pd->rows.data, new_capacity * sizeof(*pd->rows.data));
|
|
94
|
+
if (!new_data)
|
|
95
|
+
return ENOMEM;
|
|
96
|
+
pd->rows.data = new_data;
|
|
97
|
+
pd->rows.capacity = new_capacity;
|
|
98
|
+
}
|
|
99
|
+
return 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static int add_pivot_row(struct pivot_data *pd, const char *value, size_t len) {
|
|
103
|
+
int err = pivot_data_grow(pd);
|
|
104
|
+
char *value_dup = NULL;
|
|
105
|
+
if (!err && value && len) {
|
|
106
|
+
value_dup = malloc(len + 1);
|
|
107
|
+
if (value_dup) {
|
|
108
|
+
memcpy(value_dup, value, len);
|
|
109
|
+
value_dup[len] = '\0';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
pd->rows.data[pd->rows.used++].value = value_dup;
|
|
113
|
+
return err;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static struct pivot_row *get_pivot_row_data(struct pivot_data *pd, size_t row_ix) {
|
|
117
|
+
if (pd && row_ix < pd->rows.used)
|
|
118
|
+
return &pd->rows.data[row_ix];
|
|
119
|
+
return NULL;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// TO DO: return zsvsheet_status
|
|
123
|
+
static enum zsv_ext_status get_cell_attrs(void *pdh, zsvsheet_cell_attr_t *attrs, size_t start_row, size_t row_count,
|
|
124
|
+
size_t cols) {
|
|
125
|
+
struct pivot_data *pd = pdh;
|
|
126
|
+
size_t end_row = start_row + row_count;
|
|
127
|
+
if (end_row > pd->rows.used)
|
|
128
|
+
end_row = pd->rows.used;
|
|
129
|
+
for (size_t i = start_row; i < end_row; i++)
|
|
130
|
+
attrs[i * cols] = zsv_cb.ext_sheet_cell_profile_attrs(zsvsheet_cell_attr_profile_link);
|
|
131
|
+
return zsv_ext_status_ok;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static void pivot_on_header_cell(void *ctx, size_t col_ix, const char *colname) {
|
|
135
|
+
if (col_ix == 0) {
|
|
136
|
+
add_pivot_row(ctx, NULL, 0);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
static void pivot_on_data_cell(void *ctx, size_t col_ix, const char *text, size_t len) {
|
|
141
|
+
if (col_ix == 0)
|
|
142
|
+
add_pivot_row(ctx, text, len);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static zsvsheet_status zsv_sqlite3_to_csv(zsvsheet_proc_context_t pctx, struct zsv_sqlite3_db *zdb, const char *sql,
|
|
146
|
+
void *ctx, void (*on_header_cell)(void *, size_t, const char *),
|
|
147
|
+
void (*on_data_cell)(void *, size_t, const char *, size_t len)) {
|
|
148
|
+
const char *err_msg = NULL;
|
|
149
|
+
zsvsheet_status zst = zsvsheet_status_error;
|
|
150
|
+
sqlite3_stmt *stmt = NULL;
|
|
151
|
+
if ((zdb->rc = sqlite3_prepare_v2(zdb->db, sql, -1, &stmt, NULL)) == SQLITE_OK) {
|
|
152
|
+
char *tmp_fn = zsv_get_temp_filename("zsv_mysheet_ext_XXXXXXXX");
|
|
153
|
+
struct zsv_csv_writer_options writer_opts = zsv_writer_get_default_opts();
|
|
154
|
+
zsv_csv_writer cw = NULL;
|
|
155
|
+
if (!tmp_fn)
|
|
156
|
+
zst = zsvsheet_status_memory;
|
|
157
|
+
else if (!(writer_opts.stream = fopen(tmp_fn, "wb"))) {
|
|
158
|
+
zst = zsvsheet_status_error;
|
|
159
|
+
err_msg = strerror(errno);
|
|
160
|
+
} else if (!(cw = zsv_writer_new(&writer_opts)))
|
|
161
|
+
zst = zsvsheet_status_memory;
|
|
162
|
+
else {
|
|
163
|
+
zst = zsvsheet_status_ok;
|
|
164
|
+
unsigned char cw_buff[1024];
|
|
165
|
+
zsv_writer_set_temp_buff(cw, cw_buff, sizeof(cw_buff));
|
|
166
|
+
|
|
167
|
+
int col_count = sqlite3_column_count(stmt);
|
|
168
|
+
// write header row
|
|
169
|
+
for (int i = 0; i < col_count; i++) {
|
|
170
|
+
const char *colname = sqlite3_column_name(stmt, i);
|
|
171
|
+
zsv_writer_cell(cw, !i, (const unsigned char *)colname, colname ? strlen(colname) : 0, 1);
|
|
172
|
+
if (on_header_cell)
|
|
173
|
+
on_header_cell(ctx, i, colname);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// write sql results
|
|
177
|
+
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
178
|
+
for (int i = 0; i < col_count; i++) {
|
|
179
|
+
const unsigned char *text = sqlite3_column_text(stmt, i);
|
|
180
|
+
int len = text ? sqlite3_column_bytes(stmt, i) : 0;
|
|
181
|
+
zsv_writer_cell(cw, !i, text, len, 1);
|
|
182
|
+
if (on_data_cell)
|
|
183
|
+
on_data_cell(ctx, i, text, len);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (cw)
|
|
188
|
+
zsv_writer_delete(cw);
|
|
189
|
+
if (writer_opts.stream)
|
|
190
|
+
fclose(writer_opts.stream);
|
|
191
|
+
|
|
192
|
+
if (tmp_fn && zsv_file_exists(tmp_fn))
|
|
193
|
+
zst = zsv_cb.ext_sheet_open_file(pctx, tmp_fn, NULL);
|
|
194
|
+
else {
|
|
195
|
+
if (zst == zsvsheet_status_ok) {
|
|
196
|
+
zst = zsvsheet_status_error; // to do: make this more specific
|
|
197
|
+
if (!err_msg && zdb && zdb->rc != SQLITE_OK)
|
|
198
|
+
err_msg = sqlite3_errmsg(zdb->db);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
free(tmp_fn);
|
|
202
|
+
}
|
|
203
|
+
if (stmt)
|
|
204
|
+
sqlite3_finalize(stmt);
|
|
205
|
+
if (err_msg)
|
|
206
|
+
zsv_cb.ext_sheet_set_status(ctx, "Error: %s", err_msg);
|
|
207
|
+
return zst;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
//
|
|
211
|
+
zsvsheet_status pivot_drill_down(zsvsheet_proc_context_t ctx) {
|
|
212
|
+
enum zsvsheet_status zst = zsvsheet_status_ok;
|
|
213
|
+
char result_buffer[256] = {0};
|
|
214
|
+
zsvsheet_buffer_t buff = zsv_cb.ext_sheet_buffer_current(ctx);
|
|
215
|
+
struct pivot_data *pd;
|
|
216
|
+
struct zsvsheet_rowcol rc;
|
|
217
|
+
if (zsv_cb.ext_sheet_buffer_get_ctx(buff, (void **)&pd) != zsv_ext_status_ok ||
|
|
218
|
+
zsv_cb.ext_sheet_buffer_get_selected_cell(buff, &rc) != zsvsheet_status_ok) {
|
|
219
|
+
return zsvsheet_status_error;
|
|
220
|
+
}
|
|
221
|
+
struct pivot_row *pr = get_pivot_row_data(pd, rc.row);
|
|
222
|
+
if (pd && pd->data_filename && pd->value_sql && pr) {
|
|
223
|
+
// zsv_cb.ext_sheet_prompt(ctx, result_buffer, sizeof(result_buffer), "You are in pivot_drill_down! row = %zu, value
|
|
224
|
+
// = %s\n", rc.row, pr->value ? pr->value : "(null)");
|
|
225
|
+
|
|
226
|
+
struct zsv_sqlite3_dbopts dbopts = {0};
|
|
227
|
+
sqlite3_str *sql_str = NULL;
|
|
228
|
+
struct zsv_sqlite3_db *zdb = zsv_cb.ext_sqlite3_db_new(&dbopts);
|
|
229
|
+
if (!zdb || !(sql_str = sqlite3_str_new(zdb->db)))
|
|
230
|
+
zst = zsvsheet_status_memory;
|
|
231
|
+
else if (zdb->rc == SQLITE_OK && zsv_cb.ext_sqlite3_add_csv(zdb, pd->data_filename, NULL, NULL) == SQLITE_OK) {
|
|
232
|
+
if (zsv_cb.ext_sheet_buffer_info(buff).has_row_num)
|
|
233
|
+
sqlite3_str_appendf(sql_str, "select *");
|
|
234
|
+
else
|
|
235
|
+
sqlite3_str_appendf(sql_str, "select rowid as [Row #], *");
|
|
236
|
+
sqlite3_str_appendf(sql_str, " from data where %s = %Q", pd->value_sql, pr->value);
|
|
237
|
+
fprintf(stderr, "SQL: %s\n", sqlite3_str_value(sql_str));
|
|
238
|
+
zst = zsv_sqlite3_to_csv(ctx, zdb, sqlite3_str_value(sql_str), NULL, NULL, NULL);
|
|
239
|
+
}
|
|
240
|
+
if (sql_str)
|
|
241
|
+
sqlite3_free(sqlite3_str_finish(sql_str));
|
|
242
|
+
if (zdb) {
|
|
243
|
+
if (zst != zsvsheet_status_ok) {
|
|
244
|
+
// to do: consolidate this with same code in sql.c
|
|
245
|
+
if (zdb->err_msg)
|
|
246
|
+
fprintf(stderr, "Error: %s\n", zdb->err_msg);
|
|
247
|
+
else if (!zdb->db)
|
|
248
|
+
fprintf(stderr, "Error (unable to open db, code %i): %s\n", zdb->rc, sqlite3_errstr(zdb->rc));
|
|
249
|
+
else if (zdb->rc != SQLITE_OK)
|
|
250
|
+
fprintf(stderr, "Error (code %i): %s\n", zdb->rc, sqlite3_errstr(zdb->rc));
|
|
251
|
+
}
|
|
252
|
+
zsv_cb.ext_sqlite3_db_delete(zdb);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return zst;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Here we define a custom command for the zsv `sheet` feature
|
|
260
|
+
*/
|
|
261
|
+
zsvsheet_status my_pivot_table_command_handler(zsvsheet_proc_context_t ctx) {
|
|
262
|
+
char result_buffer[256] = {0};
|
|
263
|
+
int ch = zsv_cb.ext_sheet_keypress(ctx);
|
|
264
|
+
if (ch < 0)
|
|
265
|
+
return zsvsheet_status_error;
|
|
266
|
+
zsvsheet_buffer_t buff = zsv_cb.ext_sheet_buffer_current(ctx);
|
|
267
|
+
const char *data_filename = NULL;
|
|
268
|
+
if (buff)
|
|
269
|
+
data_filename = zsv_cb.ext_sheet_buffer_data_filename(buff);
|
|
270
|
+
if (!data_filename) { // TO DO: check that the underlying data is a tabular file and we know how to parse
|
|
271
|
+
zsv_cb.ext_sheet_set_status(ctx, "Pivot table only available for tabular data buffers");
|
|
272
|
+
return zsvsheet_status_ok;
|
|
273
|
+
}
|
|
274
|
+
struct zsv_opts opts = zsv_cb.ext_sheet_buffer_get_zsv_opts(buff);
|
|
275
|
+
zsv_cb.ext_sheet_prompt(ctx, result_buffer, sizeof(result_buffer), "Pivot table: Enter group-by SQL expr");
|
|
276
|
+
if (*result_buffer == '\0')
|
|
277
|
+
return zsvsheet_status_ok;
|
|
278
|
+
|
|
279
|
+
enum zsvsheet_status zst = zsvsheet_status_ok;
|
|
280
|
+
struct zsv_sqlite3_dbopts dbopts = {0};
|
|
281
|
+
struct zsv_sqlite3_db *zdb = zsv_cb.ext_sqlite3_db_new(&dbopts);
|
|
282
|
+
sqlite3_str *sql_str = NULL;
|
|
283
|
+
struct pivot_data *pd = NULL;
|
|
284
|
+
if (!zdb || !(sql_str = sqlite3_str_new(zdb->db)))
|
|
285
|
+
zst = zsvsheet_status_memory;
|
|
286
|
+
else if (zdb->rc == SQLITE_OK && zsv_cb.ext_sqlite3_add_csv(zdb, data_filename, NULL, NULL) == SQLITE_OK) {
|
|
287
|
+
sqlite3_str_appendf(sql_str, "select %s as value, count(1) as Count from data group by %s", result_buffer,
|
|
288
|
+
result_buffer);
|
|
289
|
+
if (!(pd = pivot_data_new(data_filename, result_buffer)))
|
|
290
|
+
zst = zsvsheet_status_memory;
|
|
291
|
+
else {
|
|
292
|
+
zst = zsv_sqlite3_to_csv(ctx, zdb, sqlite3_str_value(sql_str), pd, pivot_on_header_cell, pivot_on_data_cell);
|
|
293
|
+
if (zst == zsvsheet_status_ok) {
|
|
294
|
+
zsvsheet_buffer_t buff = zsv_cb.ext_sheet_buffer_current(ctx);
|
|
295
|
+
zsv_cb.ext_sheet_buffer_set_ctx(buff, pd, pivot_data_delete);
|
|
296
|
+
zsv_cb.ext_sheet_buffer_set_cell_attrs(buff, get_cell_attrs);
|
|
297
|
+
zsv_cb.ext_sheet_buffer_on_newline(buff, pivot_drill_down);
|
|
298
|
+
pd = NULL; // so that it isn't cleaned up below
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// TO DO: add param to ext_sheet_open_file to set filename vs data_filename, and set buffer type or proc owner
|
|
302
|
+
// TO DO: add way to attach custom context, and custom context destructor, to the new buffer
|
|
303
|
+
// TO DO: add cell highlighting
|
|
304
|
+
// TO DO: add drill-down
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
out:
|
|
308
|
+
zsv_cb.ext_sqlite3_db_delete(zdb);
|
|
309
|
+
if (sql_str)
|
|
310
|
+
sqlite3_free(sqlite3_str_finish(sql_str));
|
|
311
|
+
pivot_data_delete(pd);
|
|
312
|
+
return zst;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* *Required*. Initialization is called when our extension is loaded
|
|
317
|
+
* See my_extension.c for details
|
|
318
|
+
*/
|
|
319
|
+
|
|
320
|
+
enum zsv_ext_status zsv_ext_init(struct zsv_ext_callbacks *cb, zsv_execution_context ctx) {
|
|
321
|
+
zsv_cb = *cb;
|
|
322
|
+
zsv_cb.ext_set_help(ctx, "Sample zsv sheet extension");
|
|
323
|
+
zsv_cb.ext_set_license(ctx,
|
|
324
|
+
"Unlicense. See https://github.com/spdx/license-list-data/blob/master/text/Unlicense.txt");
|
|
325
|
+
const char *third_party_licenses[] = {"If we used any third-party software, we would list each license here", NULL};
|
|
326
|
+
zsv_cb.ext_set_thirdparty(ctx, third_party_licenses);
|
|
327
|
+
int proc_id = zsv_cb.ext_sheet_register_proc("my-sheet-pivot", "my sheet pivot", my_pivot_table_command_handler);
|
|
328
|
+
if (proc_id < 0)
|
|
329
|
+
return zsv_ext_status_error;
|
|
330
|
+
zsv_cb.ext_sheet_register_proc_key_binding('v', proc_id);
|
|
331
|
+
return zsv_ext_status_ok;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* exit: called once by zsv before the library is unloaded, if `zsv_ext_init()` was
|
|
336
|
+
* previously called
|
|
337
|
+
*/
|
|
338
|
+
enum zsv_ext_status zsv_ext_exit(void) {
|
|
339
|
+
fprintf(stderr, "Exiting mysheet extension example!\n");
|
|
340
|
+
return zsv_ext_status_ok;
|
|
341
|
+
}
|