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,178 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2021 Liquidaty and the zsv/lib contributors
|
|
3
|
+
* All rights reserved
|
|
4
|
+
*
|
|
5
|
+
* This file is part of zsv/lib, distributed under the license defined at
|
|
6
|
+
* https://opensource.org/licenses/MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <unistd.h>
|
|
10
|
+
#include <zsv/utils/os.h>
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
#include <errno.h>
|
|
13
|
+
|
|
14
|
+
#ifdef WIN32
|
|
15
|
+
#include "win/fopen_longpath.c"
|
|
16
|
+
#include "win/remove_longpath.c"
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* zsv_fopen(): same as normal fopen(), except on Win it also works with long filenames
|
|
21
|
+
*/
|
|
22
|
+
#if defined(_WIN32) || defined(WIN32) || defined(WIN)
|
|
23
|
+
FILE *zsv_fopen(const char *fname, const char *mode) {
|
|
24
|
+
if (strlen(fname) >= MAX_PATH)
|
|
25
|
+
return zsv_fopen_longpath(fname, mode);
|
|
26
|
+
return fopen(fname, mode);
|
|
27
|
+
}
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#ifndef _WIN32
|
|
31
|
+
|
|
32
|
+
void zsv_perror(const char *s) {
|
|
33
|
+
perror(s);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
int zsv_replace_file(const char *src, const char *dst) {
|
|
37
|
+
int save_errno = 0;
|
|
38
|
+
|
|
39
|
+
if (rename(src, dst) == 0) {
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (errno != EXDEV) {
|
|
44
|
+
return errno;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Fallback: copy and remove
|
|
48
|
+
FILE *fp_in = zsv_fopen(src, "rb");
|
|
49
|
+
if (!fp_in)
|
|
50
|
+
return errno;
|
|
51
|
+
|
|
52
|
+
FILE *fp_out = zsv_fopen(dst, "wb");
|
|
53
|
+
if (!fp_out) {
|
|
54
|
+
save_errno = errno;
|
|
55
|
+
fclose(fp_in);
|
|
56
|
+
return save_errno;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
char buffer[4096];
|
|
60
|
+
size_t bytes_read;
|
|
61
|
+
while ((bytes_read = fread(buffer, 1, sizeof(buffer), fp_in)) > 0) {
|
|
62
|
+
if (fwrite(buffer, 1, bytes_read, fp_out) != bytes_read) {
|
|
63
|
+
fclose(fp_out);
|
|
64
|
+
fclose(fp_in);
|
|
65
|
+
return EOF;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fclose(fp_out);
|
|
70
|
+
fclose(fp_in);
|
|
71
|
+
|
|
72
|
+
if (remove(src) != 0)
|
|
73
|
+
return errno;
|
|
74
|
+
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
#else
|
|
79
|
+
#include <windows.h>
|
|
80
|
+
#include <strsafe.h>
|
|
81
|
+
|
|
82
|
+
static void strlcpy(register char *dst, register const char *src, size_t n) {
|
|
83
|
+
for (; *src != '\0' && n > 1; n--) {
|
|
84
|
+
*dst++ = *src++;
|
|
85
|
+
}
|
|
86
|
+
*dst = '\0';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static void change_slashes_to_backslashes(char *path) {
|
|
90
|
+
int i;
|
|
91
|
+
for (i = 0; path[i] != '\0'; i++) {
|
|
92
|
+
if (path[i] == '/') {
|
|
93
|
+
path[i] = '\\';
|
|
94
|
+
}
|
|
95
|
+
if ((path[i] == '\\') && (i > 0)) {
|
|
96
|
+
while (path[i + 1] == '\\' || path[i + 1] == '/') {
|
|
97
|
+
(void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void zsv_win_to_unicode(const void *path, wchar_t *wbuf, size_t wbuf_len) {
|
|
104
|
+
char buf[PATH_MAX], buf2[PATH_MAX];
|
|
105
|
+
strlcpy(buf, path, sizeof(buf));
|
|
106
|
+
|
|
107
|
+
change_slashes_to_backslashes(buf);
|
|
108
|
+
|
|
109
|
+
/* Convert to Unicode and back. If doubly-converted string does not
|
|
110
|
+
* match the original, something is fishy, reject. */
|
|
111
|
+
memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
|
|
112
|
+
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
|
|
113
|
+
WideCharToMultiByte(CP_UTF8, 0, wbuf, (int)wbuf_len, buf2, sizeof(buf2), NULL, NULL);
|
|
114
|
+
if (strcmp(buf, buf2) != 0) {
|
|
115
|
+
wbuf[0] = L'\0';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#include <wchar.h>
|
|
120
|
+
|
|
121
|
+
int zsv_replace_file(const char *src, const char *dest) {
|
|
122
|
+
wchar_t wdest[PATH_MAX], wsrc[PATH_MAX];
|
|
123
|
+
|
|
124
|
+
zsv_win_to_unicode(dest, wdest, ARRAY_SIZE(wdest));
|
|
125
|
+
zsv_win_to_unicode(src, wsrc, ARRAY_SIZE(wsrc));
|
|
126
|
+
|
|
127
|
+
if (MoveFileExW(wsrc, wdest, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) // success
|
|
128
|
+
return 0;
|
|
129
|
+
|
|
130
|
+
if (GetLastError() == 2) // file not found, could be target. use simple rename
|
|
131
|
+
return _wrename(wsrc, wdest); // returns 0 on success
|
|
132
|
+
|
|
133
|
+
return 1; // fail
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
static void zsv_win_printLastError(void) {
|
|
137
|
+
DWORD dw = GetLastError();
|
|
138
|
+
LPVOID lpMsgBuf;
|
|
139
|
+
LPVOID lpDisplayBuf;
|
|
140
|
+
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw,
|
|
141
|
+
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
|
|
142
|
+
// Display the error message and exit the process
|
|
143
|
+
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + 40) * sizeof(TCHAR));
|
|
144
|
+
StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s\r\n"), lpMsgBuf);
|
|
145
|
+
fprintf(stderr, "%s\r\n", (LPCTSTR)lpDisplayBuf);
|
|
146
|
+
LocalFree(lpMsgBuf);
|
|
147
|
+
LocalFree(lpDisplayBuf);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
void zsv_perror(const char *s) {
|
|
151
|
+
if (s && *s)
|
|
152
|
+
fwrite(s, 1, strlen(s), stderr);
|
|
153
|
+
zsv_win_printLastError();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
#endif
|
|
157
|
+
|
|
158
|
+
unsigned int zsv_get_number_of_cores() {
|
|
159
|
+
long ncores = 1; // Default to 1 in case of failure
|
|
160
|
+
|
|
161
|
+
#ifdef _WIN32
|
|
162
|
+
// Implementation for Windows (when cross-compiled with mingw64)
|
|
163
|
+
SYSTEM_INFO sysinfo;
|
|
164
|
+
GetSystemInfo(&sysinfo);
|
|
165
|
+
ncores = sysinfo.dwNumberOfProcessors;
|
|
166
|
+
#elif defined(_SC_NPROCESSORS_ONLN)
|
|
167
|
+
// Implementation for Linux and macOS (uses POSIX standard sysconf)
|
|
168
|
+
// _SC_NPROCESSORS_ONLN gets the number of *online* processors.
|
|
169
|
+
ncores = sysconf(_SC_NPROCESSORS_ONLN);
|
|
170
|
+
#else
|
|
171
|
+
// Fallback for other POSIX-like systems that might not define the symbol
|
|
172
|
+
// or for unexpected compilation environments.
|
|
173
|
+
#error Undefined! _SC_NPROCESSORS_ONLN
|
|
174
|
+
xx ncores = 1;
|
|
175
|
+
#endif
|
|
176
|
+
// Ensure we return a positive value
|
|
177
|
+
return (unsigned int)(ncores > 0 ? ncores : 1);
|
|
178
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <string.h>
|
|
4
|
+
#include <inttypes.h>
|
|
5
|
+
|
|
6
|
+
#include <sqlite3.h>
|
|
7
|
+
|
|
8
|
+
#include <zsv.h>
|
|
9
|
+
#include <zsv/utils/overwrite.h>
|
|
10
|
+
#include <zsv/utils/cache.h>
|
|
11
|
+
#include <zsv/utils/file.h>
|
|
12
|
+
#include <zsv/utils/os.h>
|
|
13
|
+
|
|
14
|
+
#define zsv_overwrite_sqlite3_prefix "sqlite3://"
|
|
15
|
+
#define zsv_overwrite_sql_prefix "sql="
|
|
16
|
+
|
|
17
|
+
/* Overwrite structure for CSV or SQLITE3 sources */
|
|
18
|
+
void *zsv_overwrite_context_new(struct zsv_overwrite_opts *opts) {
|
|
19
|
+
struct zsv_overwrite_ctx *ctx = calloc(1, sizeof(*ctx));
|
|
20
|
+
if (ctx && opts->src) {
|
|
21
|
+
if (!(ctx->src = strdup(opts->src)))
|
|
22
|
+
fprintf(stderr, "zsv_overwrite_context_new: out of memory!\n");
|
|
23
|
+
}
|
|
24
|
+
return ctx;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
enum zsv_status zsv_overwrite_context_delete(void *h) {
|
|
28
|
+
struct zsv_overwrite_ctx *ctx = h;
|
|
29
|
+
if (ctx->sqlite3.filename)
|
|
30
|
+
free(ctx->sqlite3.filename);
|
|
31
|
+
if (ctx->sqlite3.stmt)
|
|
32
|
+
sqlite3_finalize(ctx->sqlite3.stmt);
|
|
33
|
+
if (ctx->sqlite3.db)
|
|
34
|
+
sqlite3_close(ctx->sqlite3.db);
|
|
35
|
+
if (ctx->csv.f)
|
|
36
|
+
fclose(ctx->csv.f);
|
|
37
|
+
if (ctx->csv.parser)
|
|
38
|
+
zsv_delete(ctx->csv.parser);
|
|
39
|
+
free(ctx->src);
|
|
40
|
+
free(ctx);
|
|
41
|
+
return zsv_status_ok;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static enum zsv_status zsv_next_overwrite_csv(void *h, struct zsv_overwrite_data *odata) {
|
|
45
|
+
struct zsv_overwrite_ctx *ctx = h;
|
|
46
|
+
if (zsv_next_row(ctx->csv.parser) != zsv_status_row)
|
|
47
|
+
odata->have = 0;
|
|
48
|
+
else {
|
|
49
|
+
// row, column, value
|
|
50
|
+
struct zsv_cell row = zsv_get_cell(ctx->csv.parser, 0);
|
|
51
|
+
struct zsv_cell col = zsv_get_cell(ctx->csv.parser, 1);
|
|
52
|
+
struct zsv_cell val = zsv_get_cell(ctx->csv.parser, 2);
|
|
53
|
+
struct zsv_cell author = {0};
|
|
54
|
+
struct zsv_cell timestamp = {0};
|
|
55
|
+
struct zsv_cell old_value = {0};
|
|
56
|
+
if (ctx->author_ix)
|
|
57
|
+
author = zsv_get_cell(ctx->csv.parser, ctx->author_ix);
|
|
58
|
+
if (ctx->timestamp_ix)
|
|
59
|
+
timestamp = zsv_get_cell(ctx->csv.parser, ctx->timestamp_ix);
|
|
60
|
+
if (ctx->old_value_ix)
|
|
61
|
+
old_value = zsv_get_cell(ctx->csv.parser, ctx->old_value_ix);
|
|
62
|
+
if (row.len && col.len) {
|
|
63
|
+
char *end = (char *)(row.str + row.len);
|
|
64
|
+
char **endp = &end;
|
|
65
|
+
odata->row_ix = strtoumax((char *)row.str, endp, 10);
|
|
66
|
+
end = (char *)(col.str + col.len);
|
|
67
|
+
odata->col_ix = strtoumax((char *)col.str, endp, 10);
|
|
68
|
+
odata->val = val;
|
|
69
|
+
odata->author = author;
|
|
70
|
+
odata->old_value = old_value;
|
|
71
|
+
} else {
|
|
72
|
+
odata->row_ix = 0;
|
|
73
|
+
odata->col_ix = 0;
|
|
74
|
+
odata->val.len = 0;
|
|
75
|
+
odata->old_value.len = 0;
|
|
76
|
+
odata->author.len = 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (timestamp.len) {
|
|
80
|
+
char *end = (char *)(timestamp.str + timestamp.len);
|
|
81
|
+
char **endp = &end;
|
|
82
|
+
odata->timestamp = strtoumax((char *)timestamp.str, endp, 10);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return zsv_status_ok;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static enum zsv_status zsv_next_overwrite_sqlite3(void *h, struct zsv_overwrite_data *odata) {
|
|
89
|
+
struct zsv_overwrite_ctx *ctx = h;
|
|
90
|
+
if (odata->have) {
|
|
91
|
+
sqlite3_stmt *stmt = ctx->sqlite3.stmt;
|
|
92
|
+
if (stmt) {
|
|
93
|
+
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
|
94
|
+
// row, column, value
|
|
95
|
+
odata->row_ix = sqlite3_column_int64(stmt, 0);
|
|
96
|
+
odata->col_ix = sqlite3_column_int64(stmt, 1);
|
|
97
|
+
odata->val.str = (unsigned char *)sqlite3_column_text(stmt, 2);
|
|
98
|
+
odata->val.len = sqlite3_column_bytes(stmt, 2);
|
|
99
|
+
odata->timestamp = sqlite3_column_int64(stmt, 3);
|
|
100
|
+
odata->author.str = (unsigned char *)sqlite3_column_text(stmt, 4);
|
|
101
|
+
odata->author.len = sqlite3_column_bytes(stmt, 4);
|
|
102
|
+
} else {
|
|
103
|
+
odata->row_ix = 0;
|
|
104
|
+
odata->col_ix = 0;
|
|
105
|
+
odata->val.len = 0;
|
|
106
|
+
odata->timestamp = 0;
|
|
107
|
+
odata->author.len = 0;
|
|
108
|
+
odata->have = 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return zsv_status_ok;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
enum zsv_status zsv_overwrite_next(void *h, struct zsv_overwrite_data *odata) {
|
|
116
|
+
struct zsv_overwrite_ctx *ctx = h;
|
|
117
|
+
return ctx->next(ctx, odata);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static enum zsv_status zsv_overwrite_init_sqlite3(struct zsv_overwrite_ctx *ctx, const char *source, size_t len) {
|
|
121
|
+
char ok = 0;
|
|
122
|
+
size_t pfx_len;
|
|
123
|
+
if (len > (pfx_len = strlen(zsv_overwrite_sqlite3_prefix)) &&
|
|
124
|
+
!memcmp(source, zsv_overwrite_sqlite3_prefix, pfx_len)) {
|
|
125
|
+
ctx->sqlite3.filename = malloc(len - pfx_len + 1);
|
|
126
|
+
memcpy(ctx->sqlite3.filename, source + pfx_len, len - pfx_len);
|
|
127
|
+
ctx->sqlite3.filename[len - pfx_len] = '\0';
|
|
128
|
+
char *q = memchr(ctx->sqlite3.filename, '?', len - pfx_len);
|
|
129
|
+
if (q) {
|
|
130
|
+
*q = '\0';
|
|
131
|
+
q++;
|
|
132
|
+
const char *sql = strstr(q, zsv_overwrite_sql_prefix);
|
|
133
|
+
if (sql)
|
|
134
|
+
ctx->sqlite3.sql = sql + strlen(zsv_overwrite_sql_prefix);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!ctx->sqlite3.filename || !*ctx->sqlite3.filename) {
|
|
138
|
+
fprintf(stderr, "Missing sqlite3 file name\n");
|
|
139
|
+
return zsv_status_error;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!ctx->sqlite3.sql || !*ctx->sqlite3.sql) {
|
|
143
|
+
// to do: detect it from the db
|
|
144
|
+
fprintf(stderr, "Missing sql select statement for sqlite3 overwrite data e.g.:\n"
|
|
145
|
+
" select row, column, value from overwrites order by row, column\n");
|
|
146
|
+
return zsv_status_error;
|
|
147
|
+
}
|
|
148
|
+
ok = 1;
|
|
149
|
+
} else if (len > strlen(".sqlite3") && !strcmp(source + len - strlen(".sqlite3"), ".sqlite3")) {
|
|
150
|
+
ctx->sqlite3.filename = strdup(source);
|
|
151
|
+
ctx->sqlite3.sql = "select * from overwrites order by row, column";
|
|
152
|
+
ok = 1;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (ok) {
|
|
156
|
+
int rc = sqlite3_open_v2(ctx->sqlite3.filename, &ctx->sqlite3.db, SQLITE_OPEN_READONLY, NULL);
|
|
157
|
+
if (rc != SQLITE_OK || !ctx->sqlite3.db) {
|
|
158
|
+
fprintf(stderr, "%s: %s\n", sqlite3_errstr(rc), ctx->sqlite3.filename);
|
|
159
|
+
return zsv_status_error;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
rc = sqlite3_prepare_v2(ctx->sqlite3.db, ctx->sqlite3.sql, -1, &ctx->sqlite3.stmt, NULL);
|
|
163
|
+
if (rc != SQLITE_OK || !ctx->sqlite3.stmt) {
|
|
164
|
+
fprintf(stderr, "%s\n", sqlite3_errmsg(ctx->sqlite3.db));
|
|
165
|
+
return zsv_status_error;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// successful sqlite3 connection
|
|
169
|
+
return zsv_status_ok;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
fprintf(stderr, "Invalid overwrite source: %s\n", source);
|
|
173
|
+
return zsv_status_error;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
enum zsv_status zsv_overwrite_open(void *h) {
|
|
177
|
+
struct zsv_overwrite_ctx *ctx = h;
|
|
178
|
+
if (!ctx->src)
|
|
179
|
+
return zsv_status_ok;
|
|
180
|
+
char ok = 0;
|
|
181
|
+
size_t src_len = strlen(ctx->src);
|
|
182
|
+
if ((src_len > strlen(zsv_overwrite_sqlite3_prefix) &&
|
|
183
|
+
!memcmp(zsv_overwrite_sqlite3_prefix, ctx->src, strlen(zsv_overwrite_sqlite3_prefix))) ||
|
|
184
|
+
(src_len > strlen(".sqlite3") && !strcmp(ctx->src + src_len - strlen(".sqlite3"), ".sqlite3"))) {
|
|
185
|
+
if (zsv_overwrite_init_sqlite3(ctx, ctx->src, src_len) == zsv_status_ok) {
|
|
186
|
+
ctx->next = zsv_next_overwrite_sqlite3;
|
|
187
|
+
ok = 1;
|
|
188
|
+
}
|
|
189
|
+
} else { // csv
|
|
190
|
+
struct zsv_opts opts = {0};
|
|
191
|
+
ctx->csv.f = opts.stream = zsv_fopen(ctx->src, "rb");
|
|
192
|
+
if (!ctx->csv.f) {
|
|
193
|
+
perror(ctx->src);
|
|
194
|
+
return zsv_status_error;
|
|
195
|
+
}
|
|
196
|
+
if (!(ctx->csv.parser = zsv_new(&opts)))
|
|
197
|
+
return zsv_status_memory;
|
|
198
|
+
|
|
199
|
+
if (zsv_next_row(ctx->csv.parser) != zsv_status_row) {
|
|
200
|
+
fprintf(stderr, "Unable to fetch any data from overwrite source %s\n", ctx->src);
|
|
201
|
+
} else {
|
|
202
|
+
// row, column, value
|
|
203
|
+
struct zsv_cell row = zsv_get_cell(ctx->csv.parser, 0);
|
|
204
|
+
struct zsv_cell col = zsv_get_cell(ctx->csv.parser, 1);
|
|
205
|
+
struct zsv_cell val = zsv_get_cell(ctx->csv.parser, 2);
|
|
206
|
+
if (row.len < 3 || memcmp(row.str, "row", 3) || col.len < 3 || memcmp(col.str, "col", 3) || val.len < 3 ||
|
|
207
|
+
memcmp(val.str, "val", 3))
|
|
208
|
+
fprintf(stderr, "Warning! overwrite expects 'row,col,value' header, got '%.*s,%.*s,%.*s'\n", (int)row.len,
|
|
209
|
+
row.str, (int)col.len, col.str, (int)val.len, val.str);
|
|
210
|
+
struct zsv_cell next;
|
|
211
|
+
for (size_t i = 3; (next = zsv_get_cell(ctx->csv.parser, i)).len > 0; i++) {
|
|
212
|
+
if (!memcmp(next.str, "timestamp", 9)) {
|
|
213
|
+
ctx->timestamp_ix = i;
|
|
214
|
+
} else if (!memcmp(next.str, "author", 6)) {
|
|
215
|
+
ctx->author_ix = i;
|
|
216
|
+
} else if (!memcmp(next.str, "old value", 9)) {
|
|
217
|
+
ctx->old_value_ix = i;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
ctx->next = zsv_next_overwrite_csv;
|
|
222
|
+
ok = 1;
|
|
223
|
+
}
|
|
224
|
+
return ok ? zsv_status_ok : zsv_status_error;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/*
|
|
228
|
+
* zsv_overwrite_auto() returns:
|
|
229
|
+
* - zsv_status_done if a valid overwrite file was found
|
|
230
|
+
* - zsv_status_no_more_input if no overwrite file was found
|
|
231
|
+
* - a different status code on error
|
|
232
|
+
*/
|
|
233
|
+
enum zsv_status zsv_overwrite_auto(struct zsv_opts *opts, const char *csv_path) {
|
|
234
|
+
enum zsv_status status = zsv_status_error;
|
|
235
|
+
if (opts->overwrite.ctx || opts->overwrite.open || opts->overwrite.next || opts->overwrite.close)
|
|
236
|
+
status = zsv_status_error;
|
|
237
|
+
else {
|
|
238
|
+
unsigned char *overwrite_fn = zsv_cache_filepath((const unsigned char *)csv_path, zsv_cache_type_overwrite, 0, 0);
|
|
239
|
+
if (!overwrite_fn)
|
|
240
|
+
status = zsv_status_memory;
|
|
241
|
+
else if (!zsv_file_exists((char *)overwrite_fn))
|
|
242
|
+
status = zsv_status_no_more_input;
|
|
243
|
+
else {
|
|
244
|
+
struct zsv_overwrite_opts overwrite_opts = {0};
|
|
245
|
+
overwrite_opts.src = (char *)overwrite_fn;
|
|
246
|
+
if (!(opts->overwrite.ctx = zsv_overwrite_context_new(&overwrite_opts)))
|
|
247
|
+
status = zsv_status_memory;
|
|
248
|
+
else {
|
|
249
|
+
opts->overwrite.open = zsv_overwrite_open;
|
|
250
|
+
opts->overwrite.next = zsv_overwrite_next;
|
|
251
|
+
opts->overwrite.close = zsv_overwrite_context_delete;
|
|
252
|
+
status = zsv_status_done;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
free(overwrite_fn);
|
|
256
|
+
}
|
|
257
|
+
return status;
|
|
258
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <sqlite3.h>
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <limits.h>
|
|
6
|
+
|
|
7
|
+
#include <zsv.h>
|
|
8
|
+
#include <zsv/utils/writer.h>
|
|
9
|
+
#include <zsv/utils/dirs.h>
|
|
10
|
+
#include <zsv/utils/file.h>
|
|
11
|
+
#include <zsv/utils/os.h>
|
|
12
|
+
#include <zsv/utils/overwrite.h>
|
|
13
|
+
#include <zsv/utils/overwrite_writer.h>
|
|
14
|
+
|
|
15
|
+
static enum zsv_status zsv_overwrite_writer_init(struct zsv_overwrite *data) {
|
|
16
|
+
enum zsv_status err = zsv_status_ok;
|
|
17
|
+
int tmp_err = 0;
|
|
18
|
+
if (zsv_mkdirs(data->ctx->src, 1) && !zsv_file_readable(data->ctx->src, &tmp_err, NULL)) {
|
|
19
|
+
err = zsv_status_error;
|
|
20
|
+
perror(data->ctx->src);
|
|
21
|
+
return err;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
sqlite3_stmt *query = NULL;
|
|
25
|
+
|
|
26
|
+
if (sqlite3_open_v2(data->ctx->src, &data->ctx->sqlite3.db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK ||
|
|
27
|
+
data->mode == zsvsheet_mode_add || data->mode == zsvsheet_mode_bulk || data->mode == zsvsheet_mode_remove ||
|
|
28
|
+
data->mode == zsvsheet_mode_clear) {
|
|
29
|
+
sqlite3_close(data->ctx->sqlite3.db);
|
|
30
|
+
if (sqlite3_open_v2(data->ctx->src, &data->ctx->sqlite3.db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) !=
|
|
31
|
+
SQLITE_OK) {
|
|
32
|
+
err = zsv_status_error;
|
|
33
|
+
fprintf(stderr, "Failed to open conn: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
34
|
+
return err;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (sqlite3_exec(data->ctx->sqlite3.db, "PRAGMA foreign_keys = on", NULL, NULL, NULL) != SQLITE_OK) {
|
|
38
|
+
err = zsv_status_error;
|
|
39
|
+
fprintf(stderr, "Could not enable foreign keys: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
40
|
+
return err;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (sqlite3_prepare_v2(data->ctx->sqlite3.db,
|
|
44
|
+
"CREATE TABLE IF NOT EXISTS overwrites ( row integer, column integer, value string, "
|
|
45
|
+
"timestamp varchar(25), author varchar(25) );",
|
|
46
|
+
-1, &query, NULL) == SQLITE_OK) {
|
|
47
|
+
if (sqlite3_step(query) != SQLITE_DONE) {
|
|
48
|
+
err = zsv_status_error;
|
|
49
|
+
fprintf(stderr, "Failed to step: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
50
|
+
return err;
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
err = zsv_status_error;
|
|
54
|
+
fprintf(stderr, "Failed to prepare1: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (query)
|
|
58
|
+
sqlite3_finalize(query);
|
|
59
|
+
|
|
60
|
+
if (sqlite3_prepare_v2(data->ctx->sqlite3.db, "CREATE UNIQUE INDEX overwrites_uix ON overwrites (row, column)", -1,
|
|
61
|
+
&query, NULL) == SQLITE_OK) {
|
|
62
|
+
if (sqlite3_step(query) != SQLITE_DONE) {
|
|
63
|
+
err = zsv_status_error;
|
|
64
|
+
fprintf(stderr, "Failed to step: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
65
|
+
return err;
|
|
66
|
+
}
|
|
67
|
+
if (query)
|
|
68
|
+
sqlite3_finalize(query);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!data->ctx->sqlite3.db)
|
|
73
|
+
err = zsv_status_error;
|
|
74
|
+
|
|
75
|
+
return err;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
struct zsv_overwrite *zsv_overwrite_writer_new(struct zsv_overwrite_args *args, struct zsv_overwrite_opts *ctx_opts) {
|
|
79
|
+
struct zsv_overwrite *data = calloc(1, sizeof(*data));
|
|
80
|
+
data->overwrite = calloc(1, sizeof(*data->overwrite));
|
|
81
|
+
data->overwrite->old_value = args->overwrite->old_value;
|
|
82
|
+
data->force = args->force;
|
|
83
|
+
data->all = args->all;
|
|
84
|
+
data->a1 = args->a1;
|
|
85
|
+
data->bulk_file = args->bulk_file;
|
|
86
|
+
data->mode = args->mode;
|
|
87
|
+
data->ctx = zsv_overwrite_context_new(ctx_opts);
|
|
88
|
+
data->overwrite = args->overwrite;
|
|
89
|
+
data->next = args->next;
|
|
90
|
+
struct zsv_csv_writer_options writer_opts = {0};
|
|
91
|
+
data->writer = zsv_writer_new(&writer_opts);
|
|
92
|
+
|
|
93
|
+
enum zsv_status err = zsv_status_ok;
|
|
94
|
+
if (data->mode == zsvsheet_mode_list) {
|
|
95
|
+
if ((err = (zsv_overwrite_open(data->ctx)))) // use open when it's read-only
|
|
96
|
+
fprintf(stderr, "Failed to initalize database\n");
|
|
97
|
+
} else {
|
|
98
|
+
if ((err = zsv_overwrite_writer_init(data))) // use init when writing to db
|
|
99
|
+
fprintf(stderr, "Failed to initalize database\n");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return err == zsv_status_ok ? data : NULL;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
void zsv_overwrite_writer_delete(struct zsv_overwrite *data) {
|
|
106
|
+
if (data->writer)
|
|
107
|
+
zsv_writer_delete(data->writer);
|
|
108
|
+
if (data->ctx)
|
|
109
|
+
zsv_overwrite_context_delete(data->ctx);
|
|
110
|
+
|
|
111
|
+
if (data->overwrite && data->mode != zsvsheet_mode_bulk)
|
|
112
|
+
free(data->overwrite->val.str);
|
|
113
|
+
|
|
114
|
+
if (data->all)
|
|
115
|
+
zsv_remove(data->ctx->src);
|
|
116
|
+
free(data);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
enum zsv_status zsv_overwrite_writer_add(struct zsv_overwrite *data) {
|
|
120
|
+
if (!data->overwrite->val.str)
|
|
121
|
+
return zsv_status_error;
|
|
122
|
+
if (data->force)
|
|
123
|
+
data->ctx->sqlite3.sql =
|
|
124
|
+
"INSERT OR REPLACE INTO overwrites (row, column, value, timestamp, author) VALUES (?, ?, ?, ?, ?)";
|
|
125
|
+
else if (data->overwrite->old_value.len > 0)
|
|
126
|
+
data->ctx->sqlite3.sql = "INSERT OR REPLACE INTO overwrites (row, column, value, timestamp, author) SELECT ?, ?, "
|
|
127
|
+
"?, ?, ? WHERE EXISTS (SELECT 1 FROM overwrites WHERE value = ?)";
|
|
128
|
+
else
|
|
129
|
+
data->ctx->sqlite3.sql = "INSERT INTO overwrites (row, column, value, timestamp, author) VALUES (?, ?, ?, ?, ?)";
|
|
130
|
+
|
|
131
|
+
enum zsv_status err = zsv_status_ok;
|
|
132
|
+
sqlite3_stmt *query = NULL;
|
|
133
|
+
|
|
134
|
+
if (sqlite3_prepare_v2(data->ctx->sqlite3.db, data->ctx->sqlite3.sql, -1, &query, NULL) == SQLITE_OK) {
|
|
135
|
+
sqlite3_bind_int64(query, 1, data->overwrite->row_ix);
|
|
136
|
+
sqlite3_bind_int64(query, 2, data->overwrite->col_ix);
|
|
137
|
+
sqlite3_bind_text(query, 3, (const char *)data->overwrite->val.str, data->overwrite->val.len, SQLITE_STATIC);
|
|
138
|
+
if (data->overwrite->timestamp)
|
|
139
|
+
sqlite3_bind_int64(query, 4, data->overwrite->timestamp);
|
|
140
|
+
else
|
|
141
|
+
sqlite3_bind_null(query, 4);
|
|
142
|
+
if (data->overwrite->author.len > 0)
|
|
143
|
+
sqlite3_bind_text(query, 5, (const char *)data->overwrite->author.str, data->overwrite->author.len,
|
|
144
|
+
SQLITE_STATIC);
|
|
145
|
+
else
|
|
146
|
+
sqlite3_bind_text(query, 5, "", -1, SQLITE_STATIC);
|
|
147
|
+
|
|
148
|
+
if (data->overwrite->old_value.len > 0)
|
|
149
|
+
sqlite3_bind_text(query, 6, (const char *)data->overwrite->old_value.str, data->overwrite->old_value.len,
|
|
150
|
+
SQLITE_STATIC);
|
|
151
|
+
|
|
152
|
+
if (sqlite3_step(query) != SQLITE_DONE) {
|
|
153
|
+
err = zsv_status_error;
|
|
154
|
+
if (data->mode == zsvsheet_mode_bulk)
|
|
155
|
+
sqlite3_exec(data->ctx->sqlite3.db, "ROLLBACK", NULL, NULL, NULL);
|
|
156
|
+
fprintf(stderr, "Value already exists at row %zu and column %zu, use --force to force insert\n",
|
|
157
|
+
data->overwrite->row_ix, data->overwrite->col_ix);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
err = zsv_status_error;
|
|
161
|
+
if (data->mode == zsvsheet_mode_bulk)
|
|
162
|
+
sqlite3_exec(data->ctx->sqlite3.db, "ROLLBACK", NULL, NULL, NULL);
|
|
163
|
+
fprintf(stderr, "Failed to prepare2: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (query)
|
|
167
|
+
sqlite3_finalize(query);
|
|
168
|
+
|
|
169
|
+
return err;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
enum zsv_status zsv_overwrite_writer_remove(struct zsv_overwrite *data) {
|
|
173
|
+
enum zsv_status err = zsv_status_ok;
|
|
174
|
+
if (data->all) {
|
|
175
|
+
err = zsv_overwrite_writer_clear(data);
|
|
176
|
+
return err;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
data->ctx->sqlite3.sql = data->overwrite->old_value.len > 0
|
|
180
|
+
? "DELETE FROM overwrites WHERE row = ? AND column = ? AND value = ?"
|
|
181
|
+
: "DELETE FROM overwrites WHERE row = ? AND column = ?";
|
|
182
|
+
|
|
183
|
+
sqlite3_stmt *query = NULL;
|
|
184
|
+
if (sqlite3_prepare_v2(data->ctx->sqlite3.db, data->ctx->sqlite3.sql, -1, &query, NULL) != SQLITE_OK) {
|
|
185
|
+
err = zsv_status_error;
|
|
186
|
+
if (data->mode == zsvsheet_mode_bulk)
|
|
187
|
+
sqlite3_exec(data->ctx->sqlite3.db, "ROLLBACK", NULL, NULL, NULL);
|
|
188
|
+
fprintf(stderr, "Could not prepare: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
189
|
+
return err;
|
|
190
|
+
}
|
|
191
|
+
sqlite3_bind_int64(query, 1, data->overwrite->row_ix);
|
|
192
|
+
sqlite3_bind_int64(query, 2, data->overwrite->col_ix);
|
|
193
|
+
if (data->overwrite->old_value.len > 0)
|
|
194
|
+
sqlite3_bind_text(query, 3, (const char *)data->overwrite->old_value.str, data->overwrite->old_value.len,
|
|
195
|
+
SQLITE_STATIC);
|
|
196
|
+
|
|
197
|
+
if (sqlite3_step(query) != SQLITE_DONE) {
|
|
198
|
+
err = zsv_status_error;
|
|
199
|
+
if (data->mode == zsvsheet_mode_bulk)
|
|
200
|
+
sqlite3_exec(data->ctx->sqlite3.db, "ROLLBACK", NULL, NULL, NULL);
|
|
201
|
+
fprintf(stderr, "Could not step: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
202
|
+
return err;
|
|
203
|
+
}
|
|
204
|
+
if (query)
|
|
205
|
+
sqlite3_finalize(query);
|
|
206
|
+
return err;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
enum zsv_status zsv_overwrite_writer_bulk(struct zsv_overwrite *data) {
|
|
210
|
+
free(data->ctx->src);
|
|
211
|
+
data->ctx->src = (char *)data->bulk_file;
|
|
212
|
+
if (zsv_overwrite_open(data->ctx) != zsv_status_ok) {
|
|
213
|
+
fprintf(stderr, "Could not open\n");
|
|
214
|
+
return zsv_status_error;
|
|
215
|
+
}
|
|
216
|
+
data->overwrite->have = 1;
|
|
217
|
+
data->ctx->row_ix = 1;
|
|
218
|
+
if (sqlite3_exec(data->ctx->sqlite3.db, "BEGIN TRANSACTION", NULL, NULL, NULL) == SQLITE_OK) {
|
|
219
|
+
while (data->ctx->next(data->ctx, data->overwrite) == zsv_status_ok && data->overwrite->have) {
|
|
220
|
+
data->next(data);
|
|
221
|
+
data->overwrite->timestamp = 0;
|
|
222
|
+
}
|
|
223
|
+
if (sqlite3_exec(data->ctx->sqlite3.db, "COMMIT", NULL, NULL, NULL) != SQLITE_OK)
|
|
224
|
+
fprintf(stderr, "Could not commit changes: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
225
|
+
} else
|
|
226
|
+
fprintf(stderr, "Could not begin transaction: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
227
|
+
return zsv_status_ok;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
enum zsv_status zsv_overwrite_writer_clear(struct zsv_overwrite *data) {
|
|
231
|
+
enum zsv_status err = zsv_status_ok;
|
|
232
|
+
sqlite3_stmt *query = NULL;
|
|
233
|
+
if (sqlite3_prepare_v2(data->ctx->sqlite3.db, "DELETE FROM overwrites", -1, &query, NULL) == SQLITE_OK) {
|
|
234
|
+
if (sqlite3_step(query) != SQLITE_DONE) {
|
|
235
|
+
err = zsv_status_error;
|
|
236
|
+
fprintf(stderr, "Failed to step: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
237
|
+
return err;
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
err = zsv_status_error;
|
|
241
|
+
fprintf(stderr, "Could not prepare: %s\n", sqlite3_errmsg(data->ctx->sqlite3.db));
|
|
242
|
+
}
|
|
243
|
+
if (query)
|
|
244
|
+
sqlite3_finalize(query);
|
|
245
|
+
return err;
|
|
246
|
+
}
|