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,393 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2021 Liquidaty and zsv contributors. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* This file is part of zsv/lib, distributed under the MIT license as defined at
|
|
5
|
+
* https://opensource.org/licenses/MIT
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <string.h>
|
|
11
|
+
#include <sglib.h>
|
|
12
|
+
|
|
13
|
+
#define ZSV_COMMAND stack
|
|
14
|
+
#include "zsv_command.h"
|
|
15
|
+
|
|
16
|
+
#include <zsv/utils/writer.h>
|
|
17
|
+
#include <zsv/utils/mem.h>
|
|
18
|
+
#include <zsv/utils/string.h>
|
|
19
|
+
|
|
20
|
+
const char *zsv_stack_usage_msg[] = {
|
|
21
|
+
APPNAME ": stack one or more csv files vertically, aligning columns with the same name",
|
|
22
|
+
"",
|
|
23
|
+
"Usage: " APPNAME " [options] filename [filename...]",
|
|
24
|
+
"",
|
|
25
|
+
"Options:",
|
|
26
|
+
" -o <filename> : output file",
|
|
27
|
+
" -b : output with BOM",
|
|
28
|
+
" -q : always add double-quotes",
|
|
29
|
+
// " --prepend-filename : output source filename as the first column of each output row",
|
|
30
|
+
" --unique : only output unique column names;",
|
|
31
|
+
" in case of duplicates, only the last (right-most) column will be kept",
|
|
32
|
+
NULL,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
static int zsv_stack_usage(void) {
|
|
36
|
+
for (size_t i = 0; zsv_stack_usage_msg[i]; i++)
|
|
37
|
+
fprintf(stdout, "%s\n", zsv_stack_usage_msg[i]);
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
typedef struct zsv_stack_colname {
|
|
42
|
+
struct zsv_stack_colname *next;
|
|
43
|
+
char unsigned *orig_name;
|
|
44
|
+
char unsigned *name;
|
|
45
|
+
unsigned occurrence;
|
|
46
|
+
unsigned dupes;
|
|
47
|
+
size_t global_position;
|
|
48
|
+
unsigned char color;
|
|
49
|
+
struct zsv_stack_colname *left;
|
|
50
|
+
struct zsv_stack_colname *right;
|
|
51
|
+
unsigned int raw_col_ix_plus_1;
|
|
52
|
+
} zsv_stack_colname;
|
|
53
|
+
|
|
54
|
+
static struct zsv_stack_colname *zsv_stack_colname_init(struct zsv_stack_colname *e, const unsigned char *name,
|
|
55
|
+
size_t len, unsigned occurrence) {
|
|
56
|
+
memset(e, 0, sizeof(*e));
|
|
57
|
+
if (len)
|
|
58
|
+
e->name = zsv_strtolowercase(name, &len);
|
|
59
|
+
else
|
|
60
|
+
e->name = calloc(1, 2);
|
|
61
|
+
e->occurrence = occurrence;
|
|
62
|
+
return e;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static void zsv_stack_colname_free(struct zsv_stack_colname *e) {
|
|
66
|
+
if (e->name)
|
|
67
|
+
free(e->name);
|
|
68
|
+
if (e->orig_name)
|
|
69
|
+
free(e->orig_name);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static void zsv_stack_colname_delete(struct zsv_stack_colname *e) {
|
|
73
|
+
zsv_stack_colname_free(e);
|
|
74
|
+
free(e);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
static int zsv_stack_colname_cmp(zsv_stack_colname *x, zsv_stack_colname *y) {
|
|
78
|
+
int i = strcmp((const char *)x->name, (const char *)y->name);
|
|
79
|
+
if (i == 0)
|
|
80
|
+
return x->occurrence == y->occurrence ? 0 : x->occurrence > y->occurrence ? 1 : -1;
|
|
81
|
+
return i;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
SGLIB_DEFINE_RBTREE_PROTOTYPES(zsv_stack_colname, left, right, color, zsv_stack_colname_cmp);
|
|
85
|
+
SGLIB_DEFINE_RBTREE_FUNCTIONS(zsv_stack_colname, left, right, color, zsv_stack_colname_cmp);
|
|
86
|
+
|
|
87
|
+
static void zsv_stack_colname_tree_delete(zsv_stack_colname **tree) {
|
|
88
|
+
if (tree && *tree) {
|
|
89
|
+
struct sglib_zsv_stack_colname_iterator it;
|
|
90
|
+
struct zsv_stack_colname *e;
|
|
91
|
+
for (e = sglib_zsv_stack_colname_it_init(&it, *tree); e; e = sglib_zsv_stack_colname_it_next(&it))
|
|
92
|
+
zsv_stack_colname_delete(e);
|
|
93
|
+
*tree = NULL;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
struct zsv_stack_data;
|
|
98
|
+
struct zsv_stack_input_file {
|
|
99
|
+
struct zsv_stack_input_file *next;
|
|
100
|
+
FILE *f;
|
|
101
|
+
const char *fname;
|
|
102
|
+
zsv_parser parser;
|
|
103
|
+
|
|
104
|
+
// output_column_map[x] = n where x = output col ix, n = 0 if no map, else raw_column_ix
|
|
105
|
+
zsv_stack_colname *colnames;
|
|
106
|
+
size_t *output_column_map;
|
|
107
|
+
size_t output_column_map_size;
|
|
108
|
+
size_t header_row_end_offset; // location in buff at which the data row begins
|
|
109
|
+
struct zsv_stack_data *ctx;
|
|
110
|
+
unsigned char headers_done : 1;
|
|
111
|
+
unsigned char _ : 7;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
struct zsv_stack_data {
|
|
115
|
+
struct zsv_stack_input_file *inputs;
|
|
116
|
+
struct zsv_stack_input_file *current_input;
|
|
117
|
+
|
|
118
|
+
unsigned inputs_count;
|
|
119
|
+
unsigned current_input_ix;
|
|
120
|
+
zsv_stack_colname *colnames;
|
|
121
|
+
zsv_stack_colname *first_colname;
|
|
122
|
+
zsv_stack_colname *last_colname;
|
|
123
|
+
unsigned colnames_count;
|
|
124
|
+
int err;
|
|
125
|
+
|
|
126
|
+
zsv_csv_writer csv_writer;
|
|
127
|
+
|
|
128
|
+
unsigned char unique_column_names : 1;
|
|
129
|
+
unsigned char _ : 7;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
static struct zsv_stack_input_file **zsv_stack_input_file_add(const char *filename,
|
|
133
|
+
struct zsv_stack_input_file **target, unsigned *count,
|
|
134
|
+
FILE *f, struct zsv_stack_data *ctx) {
|
|
135
|
+
struct zsv_stack_input_file *e = calloc(1, sizeof(*e));
|
|
136
|
+
if (e) {
|
|
137
|
+
e->f = f;
|
|
138
|
+
e->fname = filename;
|
|
139
|
+
e->ctx = ctx;
|
|
140
|
+
*target = e;
|
|
141
|
+
(*count)++;
|
|
142
|
+
return &e->next;
|
|
143
|
+
}
|
|
144
|
+
return target;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
static void zsv_stack_input_files_delete(struct zsv_stack_input_file *list) {
|
|
148
|
+
for (struct zsv_stack_input_file *next, *e = list; e; e = next) {
|
|
149
|
+
next = e->next;
|
|
150
|
+
if (e->f)
|
|
151
|
+
fclose(e->f);
|
|
152
|
+
if (e->output_column_map)
|
|
153
|
+
free(e->output_column_map);
|
|
154
|
+
zsv_stack_colname_tree_delete(&e->colnames);
|
|
155
|
+
zsv_delete(e->parser);
|
|
156
|
+
free(e);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static void zsv_stack_cleanup(struct zsv_stack_data *data) {
|
|
161
|
+
zsv_stack_input_files_delete(data->inputs);
|
|
162
|
+
zsv_stack_colname_tree_delete(&data->colnames);
|
|
163
|
+
zsv_writer_delete(data->csv_writer);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
static struct zsv_stack_colname *zsv_stack_colname_get_or_add(struct zsv_cell c, unsigned occurrence,
|
|
167
|
+
struct zsv_stack_colname **tree, int *added) {
|
|
168
|
+
const unsigned char *name = c.str;
|
|
169
|
+
size_t name_len = c.len;
|
|
170
|
+
struct zsv_stack_colname e;
|
|
171
|
+
zsv_stack_colname_init(&e, name, name_len, occurrence);
|
|
172
|
+
struct zsv_stack_colname *found = sglib_zsv_stack_colname_find_member(*tree, &e);
|
|
173
|
+
if (found) {
|
|
174
|
+
found->dupes++;
|
|
175
|
+
zsv_stack_colname_free(&e);
|
|
176
|
+
} else {
|
|
177
|
+
found = calloc(1, sizeof(*found));
|
|
178
|
+
if (found) {
|
|
179
|
+
*added = 1;
|
|
180
|
+
*found = e;
|
|
181
|
+
if (name)
|
|
182
|
+
found->orig_name = name ? zsv_memdup(name, name_len) : calloc(1, 2);
|
|
183
|
+
sglib_zsv_stack_colname_add(tree, found);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return found;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// zsv_stack_consolidate_header(): return global position
|
|
190
|
+
static unsigned zsv_stack_consolidate_header(struct zsv_stack_data *d, struct zsv_cell cell, unsigned occurrence) {
|
|
191
|
+
int added = 0;
|
|
192
|
+
zsv_stack_colname *c = zsv_stack_colname_get_or_add(cell, occurrence, &d->colnames, &added);
|
|
193
|
+
if (!c)
|
|
194
|
+
d->err = 1;
|
|
195
|
+
else {
|
|
196
|
+
if (added) {
|
|
197
|
+
c->global_position = ++d->colnames_count;
|
|
198
|
+
if (d->last_colname)
|
|
199
|
+
d->last_colname->next = c;
|
|
200
|
+
else
|
|
201
|
+
d->first_colname = c;
|
|
202
|
+
d->last_colname = c;
|
|
203
|
+
}
|
|
204
|
+
return c->global_position;
|
|
205
|
+
}
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static void zsv_stack_header_row(void *ctx) {
|
|
210
|
+
struct zsv_stack_input_file *input = ctx;
|
|
211
|
+
if (!input->headers_done && !zsv_row_is_blank(input->parser)) { // skip any blank leading rows
|
|
212
|
+
input->headers_done = 1;
|
|
213
|
+
zsv_abort(input->parser);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
static void zsv_stack_data_row(void *ctx) {
|
|
218
|
+
struct zsv_stack_input_file *input = ctx;
|
|
219
|
+
if (!input->headers_done) {
|
|
220
|
+
input->headers_done = 1;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (!zsv_row_is_blank(input->parser)) {
|
|
224
|
+
size_t colnames_count = input->ctx->colnames_count;
|
|
225
|
+
for (unsigned i = 0; i < colnames_count; i++) {
|
|
226
|
+
size_t raw_ix_plus_1;
|
|
227
|
+
if (i < input->output_column_map_size && ((raw_ix_plus_1 = input->output_column_map[i]))) {
|
|
228
|
+
struct zsv_cell cell = zsv_get_cell(input->parser, raw_ix_plus_1 - 1);
|
|
229
|
+
zsv_writer_cell(input->ctx->csv_writer, !i, cell.str, cell.len, cell.quoted);
|
|
230
|
+
} else
|
|
231
|
+
zsv_writer_cell(input->ctx->csv_writer, !i, 0x0, 0, 0);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
int ZSV_MAIN_FUNC(ZSV_COMMAND)(int argc, const char *argv[], struct zsv_opts *opts,
|
|
237
|
+
struct zsv_prop_handler *custom_prop_handler) {
|
|
238
|
+
int err = 0;
|
|
239
|
+
if (argc < 2) {
|
|
240
|
+
zsv_stack_usage();
|
|
241
|
+
return 1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")))
|
|
245
|
+
return zsv_stack_usage();
|
|
246
|
+
|
|
247
|
+
struct zsv_opts saved_opts = *opts;
|
|
248
|
+
struct zsv_stack_data data = {0};
|
|
249
|
+
struct zsv_csv_writer_options writer_opts = zsv_writer_get_default_opts();
|
|
250
|
+
writer_opts.stream = stdout;
|
|
251
|
+
|
|
252
|
+
struct zsv_stack_input_file **next_input = &data.inputs;
|
|
253
|
+
for (int arg_i = 1; !data.err && arg_i < argc; arg_i++) {
|
|
254
|
+
const char *arg = argv[arg_i];
|
|
255
|
+
if (!strcmp(arg, "-b"))
|
|
256
|
+
writer_opts.with_bom = 1;
|
|
257
|
+
// else if (!strcmp(arg, "--prepend-filename")_)
|
|
258
|
+
// data.prepend_filename
|
|
259
|
+
else if (!strcmp(arg, "--unique"))
|
|
260
|
+
data.unique_column_names = 1;
|
|
261
|
+
else if (!strcmp(arg, "-o")) {
|
|
262
|
+
arg_i++;
|
|
263
|
+
if (arg_i >= argc)
|
|
264
|
+
fprintf(stderr, "-o option: no filename specified\n");
|
|
265
|
+
else {
|
|
266
|
+
if (!(writer_opts.stream = fopen(argv[arg_i], "wb"))) {
|
|
267
|
+
data.err = 1;
|
|
268
|
+
fprintf(stderr, "Unable to open file for writing: %s\n", argv[arg_i]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} else if (*arg == '-') {
|
|
272
|
+
fprintf(stderr, "Unrecognized option: %s\n", arg);
|
|
273
|
+
data.err = 1;
|
|
274
|
+
} else {
|
|
275
|
+
FILE *f = fopen(arg, "rb");
|
|
276
|
+
if (!f) {
|
|
277
|
+
fprintf(stderr, "Could not open file for reading: %s\n", arg);
|
|
278
|
+
data.err = 1;
|
|
279
|
+
} else
|
|
280
|
+
next_input = zsv_stack_input_file_add(arg, next_input, &data.inputs_count, f, &data);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!(data.csv_writer = zsv_writer_new(&writer_opts)))
|
|
285
|
+
data.err = 1;
|
|
286
|
+
|
|
287
|
+
// collect all header names so we can line them up
|
|
288
|
+
unsigned i = 0;
|
|
289
|
+
for (struct zsv_stack_input_file *input = data.inputs; !data.err && input; input = input->next, i++) {
|
|
290
|
+
*opts = saved_opts;
|
|
291
|
+
opts->row_handler = zsv_stack_header_row;
|
|
292
|
+
opts->ctx = input;
|
|
293
|
+
|
|
294
|
+
// to do: max_cell_size
|
|
295
|
+
opts->stream = input->f;
|
|
296
|
+
if (zsv_new_with_properties(opts, custom_prop_handler, input->fname, &input->parser) != zsv_status_ok)
|
|
297
|
+
data.err = 1;
|
|
298
|
+
else {
|
|
299
|
+
zsv_handle_ctrl_c_signal();
|
|
300
|
+
enum zsv_status status;
|
|
301
|
+
while (!data.err && !input->headers_done && (status = zsv_parse_more(input->parser)) == zsv_status_ok)
|
|
302
|
+
;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// we have read the header row of each input, so:
|
|
307
|
+
// - consolidate a column header names into a single list
|
|
308
|
+
// - assign output->input column mappings for each input
|
|
309
|
+
|
|
310
|
+
// first, get maximum size of consolidated cols, which is just the sum of the column count
|
|
311
|
+
// of all inputs
|
|
312
|
+
size_t max_columns_count = 0;
|
|
313
|
+
for (struct zsv_stack_input_file *input = data.inputs; !data.err && input; input = input->next)
|
|
314
|
+
max_columns_count += zsv_cell_count(input->parser);
|
|
315
|
+
|
|
316
|
+
// next, for each input, align the input columns with the output columns
|
|
317
|
+
for (struct zsv_stack_input_file *input = data.inputs; input && !data.err; input = input->next) {
|
|
318
|
+
if (max_columns_count) {
|
|
319
|
+
if (!(input->output_column_map = calloc(max_columns_count, sizeof(*input->output_column_map))))
|
|
320
|
+
data.err = 1;
|
|
321
|
+
else {
|
|
322
|
+
input->output_column_map_size = max_columns_count;
|
|
323
|
+
// assign column indexes to global columns
|
|
324
|
+
size_t cols_used = zsv_cell_count(input->parser);
|
|
325
|
+
for (unsigned col_ix = 0; col_ix < cols_used; col_ix++) {
|
|
326
|
+
struct zsv_cell cell = zsv_get_cell(input->parser, col_ix);
|
|
327
|
+
unsigned occurrence = 0;
|
|
328
|
+
if (!data.unique_column_names) {
|
|
329
|
+
int added;
|
|
330
|
+
zsv_stack_colname *c = zsv_stack_colname_get_or_add(cell, 0, &input->colnames, &added);
|
|
331
|
+
if (c)
|
|
332
|
+
occurrence = c->dupes;
|
|
333
|
+
}
|
|
334
|
+
size_t output_ix = zsv_stack_consolidate_header(&data, cell, occurrence);
|
|
335
|
+
if (output_ix)
|
|
336
|
+
input->output_column_map[output_ix - 1] = col_ix + 1;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
zsv_delete(input->parser);
|
|
341
|
+
input->parser = NULL;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// not necessary, but free up unused memory by resizing each input's output_column_map
|
|
345
|
+
for (struct zsv_stack_input_file *input = data.inputs; input && !data.err; input = input->next) {
|
|
346
|
+
if (!data.colnames_count) {
|
|
347
|
+
if (input->output_column_map) {
|
|
348
|
+
free(input->output_column_map);
|
|
349
|
+
input->output_column_map = NULL;
|
|
350
|
+
}
|
|
351
|
+
} else {
|
|
352
|
+
size_t *resized = realloc(input->output_column_map, data.colnames_count * sizeof(*resized));
|
|
353
|
+
if (resized)
|
|
354
|
+
input->output_column_map = resized;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// print headers
|
|
359
|
+
for (struct zsv_stack_colname *e = data.first_colname; !data.err && e; e = e->next) {
|
|
360
|
+
const unsigned char *name = e->orig_name ? e->orig_name : e->name ? e->name : (const unsigned char *)"";
|
|
361
|
+
zsv_writer_cell(data.csv_writer, e == data.first_colname, name, strlen((const char *)name), 1);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// process data
|
|
365
|
+
for (struct zsv_stack_input_file *input = data.inputs; input && !data.err; input = input->next, i++) {
|
|
366
|
+
if (input->headers_done) {
|
|
367
|
+
*opts = saved_opts;
|
|
368
|
+
opts->row_handler = zsv_stack_data_row;
|
|
369
|
+
opts->ctx = input;
|
|
370
|
+
|
|
371
|
+
rewind(input->f);
|
|
372
|
+
input->headers_done = 0;
|
|
373
|
+
opts->stream = input->f;
|
|
374
|
+
if (zsv_new_with_properties(opts, custom_prop_handler, input->fname, &input->parser) != zsv_status_ok)
|
|
375
|
+
data.err = 1;
|
|
376
|
+
else {
|
|
377
|
+
enum zsv_status status = zsv_status_ok;
|
|
378
|
+
while (status == zsv_status_ok && !data.err && (status = zsv_parse_more(input->parser)) == zsv_status_ok)
|
|
379
|
+
;
|
|
380
|
+
zsv_finish(input->parser);
|
|
381
|
+
zsv_delete(input->parser);
|
|
382
|
+
input->parser = NULL;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
err = data.err;
|
|
387
|
+
zsv_stack_cleanup(&data);
|
|
388
|
+
|
|
389
|
+
if (writer_opts.stream && writer_opts.stream != stdout)
|
|
390
|
+
fclose(writer_opts.stream);
|
|
391
|
+
|
|
392
|
+
return err;
|
|
393
|
+
}
|
|
@@ -0,0 +1,322 @@
|
|
|
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 <stdlib.h>
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
#include <zsv.h>
|
|
13
|
+
#include <zsv/utils/string.h>
|
|
14
|
+
#include <zsv/utils/arg.h>
|
|
15
|
+
#include <assert.h>
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
* for now we don't really need thread support because this is only being used
|
|
19
|
+
* by the CLI. However, it's here anyway in case future enhancements or
|
|
20
|
+
* user customizations need multithreading support
|
|
21
|
+
*/
|
|
22
|
+
#ifndef ZSVTLS
|
|
23
|
+
#ifndef NO_THREADING
|
|
24
|
+
#define ZSVTLS _Thread_local
|
|
25
|
+
#else
|
|
26
|
+
#define ZSVTLS
|
|
27
|
+
#endif
|
|
28
|
+
#endif
|
|
29
|
+
/*
|
|
30
|
+
* global zsv_default_opts for convenience funcs zsv_get_default_opts() and zsv_set_default_opts()
|
|
31
|
+
* for the cli to pass global opts to the standalone modules
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* Use a single function for all default-option operations, so as to be able
|
|
36
|
+
* to use thread-local storage with static initializer
|
|
37
|
+
*/
|
|
38
|
+
static struct zsv_opts *zsv_with_default_opts(char mode) {
|
|
39
|
+
ZSVTLS static char zsv_default_opts_initd = 0;
|
|
40
|
+
ZSVTLS static struct zsv_opts zsv_default_opts = {0};
|
|
41
|
+
|
|
42
|
+
switch (mode) {
|
|
43
|
+
case 'c': // clear
|
|
44
|
+
memset(&zsv_default_opts, 0, sizeof(zsv_default_opts));
|
|
45
|
+
zsv_default_opts_initd = 0;
|
|
46
|
+
break;
|
|
47
|
+
case 'g': // get
|
|
48
|
+
if (!zsv_default_opts_initd) {
|
|
49
|
+
zsv_default_opts_initd = 1;
|
|
50
|
+
zsv_default_opts.max_row_size = ZSV_ROW_MAX_SIZE_DEFAULT;
|
|
51
|
+
zsv_default_opts.max_columns = ZSV_MAX_COLS_DEFAULT;
|
|
52
|
+
} else {
|
|
53
|
+
zsv_default_opts.max_row_size =
|
|
54
|
+
zsv_default_opts.max_row_size ? zsv_default_opts.max_row_size : ZSV_ROW_MAX_SIZE_DEFAULT;
|
|
55
|
+
zsv_default_opts.max_columns = zsv_default_opts.max_columns ? zsv_default_opts.max_columns : ZSV_MAX_COLS_DEFAULT;
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
return &zsv_default_opts;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
ZSV_EXPORT
|
|
63
|
+
void zsv_clear_default_opts(void) {
|
|
64
|
+
zsv_with_default_opts('c');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
ZSV_EXPORT
|
|
68
|
+
struct zsv_opts zsv_get_default_opts(void) {
|
|
69
|
+
return *zsv_with_default_opts('g');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
ZSV_EXPORT
|
|
73
|
+
void zsv_set_default_opts(struct zsv_opts opts) {
|
|
74
|
+
*zsv_with_default_opts(0) = opts;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* str_array_index_of: return index in list, or size of list if not found
|
|
79
|
+
*/
|
|
80
|
+
static inline int str_array_index_of(const char *list[], const char *s) {
|
|
81
|
+
int i;
|
|
82
|
+
for (i = 0; list[i] && strcmp(list[i], s); i++)
|
|
83
|
+
;
|
|
84
|
+
return i;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#ifdef ZSV_EXTRAS
|
|
88
|
+
|
|
89
|
+
ZSV_EXPORT
|
|
90
|
+
void zsv_set_default_progress_callback(zsv_progress_callback cb, void *ctx, size_t rows_interval,
|
|
91
|
+
unsigned int seconds_interval) {
|
|
92
|
+
struct zsv_opts opts = zsv_get_default_opts();
|
|
93
|
+
opts.progress.callback = cb;
|
|
94
|
+
opts.progress.ctx = ctx;
|
|
95
|
+
opts.progress.rows_interval = rows_interval;
|
|
96
|
+
opts.progress.seconds_interval = seconds_interval;
|
|
97
|
+
zsv_set_default_opts(opts);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ZSV_EXPORT
|
|
101
|
+
void zsv_set_default_completed_callback(zsv_completed_callback cb, void *ctx) {
|
|
102
|
+
struct zsv_opts opts = zsv_get_default_opts();
|
|
103
|
+
opts.completed.callback = cb;
|
|
104
|
+
opts.completed.ctx = ctx;
|
|
105
|
+
zsv_set_default_opts(opts);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#endif
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Convert common command-line arguments to zsv_opts
|
|
112
|
+
* Return new argc/argv values with processed args stripped out
|
|
113
|
+
* Initializes opts_out with `zsv_get_default_opts()`, then with
|
|
114
|
+
* the below common options if present:
|
|
115
|
+
* -B,--buff-size <N>
|
|
116
|
+
* -c,--max-column-count <N>
|
|
117
|
+
* -r,--max-row-size <N>
|
|
118
|
+
* -t,--tab-delim
|
|
119
|
+
* -O,--other-delim <C>
|
|
120
|
+
* -q,--no-quote
|
|
121
|
+
* -R,--skip-head <n>: skip specified number of initial rows
|
|
122
|
+
* -d,--header-row-span <n> : apply header depth (rowspan) of n
|
|
123
|
+
* -u,--malformed-utf8-replacement <string>: replacement string (can be empty) in case of malformed UTF8
|
|
124
|
+
* input (default for "desc" command is '?') -S,--keep-blank-headers : disable default behavior of ignoring leading
|
|
125
|
+
* blank rows -0,--header-row <header> : insert the provided CSV as the first row (in position 0) e.g. --header-row
|
|
126
|
+
* 'col1,col2,\"my col 3\"'", -v,--verbose
|
|
127
|
+
* -1,--apply-overwrites: automatically apply cached overwrites
|
|
128
|
+
*
|
|
129
|
+
* @param argc count of args to process
|
|
130
|
+
* @param argv args to process
|
|
131
|
+
* @param argc_out count of unprocessed args
|
|
132
|
+
* @param argv_out array of unprocessed arg values. Must be allocated by caller
|
|
133
|
+
* with size of at least argc * sizeof(*argv)
|
|
134
|
+
* @param opts_out options, updated to reflect any processed args
|
|
135
|
+
* @return zero on success, non-zero on error
|
|
136
|
+
*/
|
|
137
|
+
ZSV_EXPORT
|
|
138
|
+
enum zsv_status zsv_args_to_opts(int argc, const char *argv[], int *argc_out, const char **argv_out,
|
|
139
|
+
struct zsv_opts *opts_out) {
|
|
140
|
+
#ifdef ZSV_EXTRAS
|
|
141
|
+
static const char *short_args = "BcrtOqvRdSu01L";
|
|
142
|
+
#else
|
|
143
|
+
static const char *short_args = "BcrtOqvRdSu0";
|
|
144
|
+
#endif
|
|
145
|
+
|
|
146
|
+
static const char *long_args[] = {
|
|
147
|
+
"buff-size",
|
|
148
|
+
"max-column-count",
|
|
149
|
+
"max-row-size",
|
|
150
|
+
"tab-delim",
|
|
151
|
+
"other-delim",
|
|
152
|
+
"no-quote",
|
|
153
|
+
"verbose",
|
|
154
|
+
"skip-head",
|
|
155
|
+
"header-row-span",
|
|
156
|
+
"keep-blank-headers",
|
|
157
|
+
"malformed-utf8-replacement",
|
|
158
|
+
"header-row",
|
|
159
|
+
#ifdef ZSV_EXTRAS
|
|
160
|
+
"apply-overwrites",
|
|
161
|
+
"limit-rows",
|
|
162
|
+
#endif
|
|
163
|
+
NULL,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
*opts_out = zsv_get_default_opts();
|
|
167
|
+
int options_start = 1; // skip this many args before we start looking for options
|
|
168
|
+
int err = 0;
|
|
169
|
+
int new_argc = 0;
|
|
170
|
+
for (; new_argc < options_start && new_argc < argc; new_argc++)
|
|
171
|
+
argv_out[new_argc] = argv[new_argc];
|
|
172
|
+
|
|
173
|
+
for (int i = options_start; !err && i < argc; i++) {
|
|
174
|
+
char arg = 0;
|
|
175
|
+
if (*argv[i] != '-') { /* pass this option through */
|
|
176
|
+
argv_out[new_argc++] = argv[i];
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
unsigned found_ix = 0;
|
|
180
|
+
if (argv[i][1] != '-') {
|
|
181
|
+
char *strchr_result;
|
|
182
|
+
if (!argv[i][2] && (strchr_result = strchr(short_args, argv[i][1]))) {
|
|
183
|
+
arg = argv[i][1];
|
|
184
|
+
found_ix = strchr_result - short_args;
|
|
185
|
+
}
|
|
186
|
+
#ifndef ZSV_NO_ONLY_CRLF
|
|
187
|
+
} else if (!strcmp(argv[i] + 2, "only-crlf")) {
|
|
188
|
+
opts_out->only_crlf_rowend = 1;
|
|
189
|
+
continue;
|
|
190
|
+
#endif
|
|
191
|
+
} else {
|
|
192
|
+
found_ix = str_array_index_of(long_args, argv[i] + 2);
|
|
193
|
+
arg = short_args[found_ix];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
char processed = 1;
|
|
197
|
+
switch (arg) {
|
|
198
|
+
case 't':
|
|
199
|
+
opts_out->delimiter = '\t';
|
|
200
|
+
break;
|
|
201
|
+
case 'S':
|
|
202
|
+
opts_out->keep_empty_header_rows = 1;
|
|
203
|
+
break;
|
|
204
|
+
case 'q':
|
|
205
|
+
opts_out->no_quotes = 1;
|
|
206
|
+
break;
|
|
207
|
+
case 'v':
|
|
208
|
+
opts_out->verbose = 1;
|
|
209
|
+
break;
|
|
210
|
+
#ifdef ZSV_EXTRAS
|
|
211
|
+
case '1':
|
|
212
|
+
opts_out->overwrite_auto = 1;
|
|
213
|
+
break;
|
|
214
|
+
case 'L':
|
|
215
|
+
#endif
|
|
216
|
+
case 'B':
|
|
217
|
+
case 'c':
|
|
218
|
+
case 'r':
|
|
219
|
+
case 'O':
|
|
220
|
+
case 'R':
|
|
221
|
+
case 'd':
|
|
222
|
+
case 'u':
|
|
223
|
+
case '0':
|
|
224
|
+
if (++i >= argc)
|
|
225
|
+
err = fprintf(stderr, "Error: option %s requires a value\n", argv[i - 1]);
|
|
226
|
+
else {
|
|
227
|
+
const char *val = argv[i];
|
|
228
|
+
if (arg == 'O') {
|
|
229
|
+
if (strlen(val) != 1 || *val == 0)
|
|
230
|
+
err = fprintf(stderr, "Error: delimiter '%s' may only be a single ascii character", val);
|
|
231
|
+
else if (strchr("\n\r\"", *val))
|
|
232
|
+
err = fprintf(stderr, "Error: column delimiter may not be '\\n', '\\r' or '\"'\n");
|
|
233
|
+
else
|
|
234
|
+
opts_out->delimiter = *val;
|
|
235
|
+
} else if (arg == 'u') {
|
|
236
|
+
if (!strcmp(val, "none"))
|
|
237
|
+
opts_out->malformed_utf8_replace = ZSV_MALFORMED_UTF8_DO_NOT_REPLACE;
|
|
238
|
+
else if (!*val)
|
|
239
|
+
opts_out->malformed_utf8_replace = ZSV_MALFORMED_UTF8_REMOVE;
|
|
240
|
+
else if (strlen(val) > 2 || *val < 0)
|
|
241
|
+
err =
|
|
242
|
+
fprintf(stderr, "Error: %s value must be a single-byte UTF8 char, empty string or 'none'\n", argv[i - 1]);
|
|
243
|
+
else
|
|
244
|
+
opts_out->malformed_utf8_replace = *val;
|
|
245
|
+
} else if (arg == '0') {
|
|
246
|
+
if (*val == 0)
|
|
247
|
+
err = fprintf(stderr, "Invalid empty Inserted header row\n");
|
|
248
|
+
else
|
|
249
|
+
opts_out->insert_header_row = argv[i];
|
|
250
|
+
} else {
|
|
251
|
+
/* arg = 'B', 'c', 'r', 'R', 'd', or 'L' (ZSV_EXTRAS only) */
|
|
252
|
+
long n = atol(val);
|
|
253
|
+
if (n < 0)
|
|
254
|
+
err = fprintf(stderr, "Error: option %s value may not be less than zero (got %li\n", val, n);
|
|
255
|
+
#ifdef ZSV_EXTRAS
|
|
256
|
+
else if (arg == 'L') {
|
|
257
|
+
if (n < 1)
|
|
258
|
+
err = fprintf(stderr, "Error: max rows may not be less than 1 (got %s)\n", val);
|
|
259
|
+
else
|
|
260
|
+
opts_out->max_rows = n;
|
|
261
|
+
} else
|
|
262
|
+
#endif
|
|
263
|
+
if (arg == 'B') {
|
|
264
|
+
if (n < ZSV_MIN_SCANNER_BUFFSIZE)
|
|
265
|
+
err =
|
|
266
|
+
fprintf(stderr, "Error: buff size may not be less than %u (got %s)\n", ZSV_MIN_SCANNER_BUFFSIZE, val);
|
|
267
|
+
else
|
|
268
|
+
opts_out->buffsize = n;
|
|
269
|
+
} else if (arg == 'c') {
|
|
270
|
+
if (n < 8)
|
|
271
|
+
err = fprintf(stderr, "Error: max column count may not be less than 8 (got %s)\n", val);
|
|
272
|
+
else
|
|
273
|
+
opts_out->max_columns = n;
|
|
274
|
+
} else if (arg == 'r') {
|
|
275
|
+
if (n < ZSV_ROW_MAX_SIZE_MIN)
|
|
276
|
+
err = fprintf(stderr, "Error: max row size size may not be less than %u (got %s)\n", ZSV_ROW_MAX_SIZE_MIN,
|
|
277
|
+
val);
|
|
278
|
+
else
|
|
279
|
+
opts_out->max_row_size = n;
|
|
280
|
+
} else if (arg == 'd') {
|
|
281
|
+
if (n < 8 && n >= 0)
|
|
282
|
+
opts_out->header_span = n;
|
|
283
|
+
else
|
|
284
|
+
err = fprintf(stderr, "Error: header_span must be an integer between 0 and 8\n");
|
|
285
|
+
} else if (arg == 'R') {
|
|
286
|
+
if (n >= 0)
|
|
287
|
+
opts_out->rows_to_ignore = n;
|
|
288
|
+
else
|
|
289
|
+
err = fprintf(stderr, "Error: rows_to_skip must be >= 0\n");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
default: /* pass this option through */
|
|
295
|
+
processed = 0;
|
|
296
|
+
argv_out[new_argc++] = argv[i];
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
if (processed && opts_out) {
|
|
300
|
+
if (arg == 'R')
|
|
301
|
+
opts_out->option_overrides.skip_head = 1;
|
|
302
|
+
else if (arg == 'd')
|
|
303
|
+
opts_out->option_overrides.header_row_span = 1;
|
|
304
|
+
else if (arg == 'c')
|
|
305
|
+
opts_out->option_overrides.max_column_count = 1;
|
|
306
|
+
else if (arg == 'u')
|
|
307
|
+
opts_out->option_overrides.malformed_utf8_replacement = 1;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
*argc_out = new_argc;
|
|
312
|
+
return err ? zsv_status_error : zsv_status_ok;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const char *zsv_next_arg(int arg_i, int argc, const char *argv[], int *err) {
|
|
316
|
+
if (!(arg_i < argc && strlen(argv[arg_i]) > 0)) {
|
|
317
|
+
fprintf(stderr, "%s option value invalid: should be non-empty string\n", argv[arg_i - 1]);
|
|
318
|
+
*err = 1;
|
|
319
|
+
return NULL;
|
|
320
|
+
}
|
|
321
|
+
return argv[arg_i];
|
|
322
|
+
}
|