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,148 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <string.h>
|
|
3
|
+
#include <sqlite3.h>
|
|
4
|
+
#include <jsonwriter.h>
|
|
5
|
+
#include <zsv/utils/string.h>
|
|
6
|
+
|
|
7
|
+
// starts_w_str_underscore(): helper function
|
|
8
|
+
// returns 1 if s starts with prefix (case-insensitive), followed by underscore
|
|
9
|
+
static char starts_w_str_underscore(const unsigned char *s, size_t s_len, const unsigned char *prefix) {
|
|
10
|
+
char result = 0;
|
|
11
|
+
unsigned char *s_lc = zsv_strtolowercase(s, &s_len);
|
|
12
|
+
size_t pfx_len = strlen((const char *)prefix);
|
|
13
|
+
unsigned char *prefix_lc = zsv_strtolowercase(prefix, &pfx_len);
|
|
14
|
+
if (pfx_len + 1 < s_len && !memcmp(s_lc, prefix_lc, pfx_len) && s_lc[pfx_len] == '_')
|
|
15
|
+
result = 1;
|
|
16
|
+
free(s_lc);
|
|
17
|
+
free(prefix_lc);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
int zsv_dbtable2json(sqlite3 *db, const char *tname, jsonwriter_handle jsw, size_t limit) {
|
|
22
|
+
int err = 0;
|
|
23
|
+
const char *index_sql = "select name, sql from sqlite_master where type = 'index' and tbl_name = :tbl_name";
|
|
24
|
+
const char *unique_sql = "select 1 from PRAGMA_index_list(?) where name = ? and [unique] <> 0";
|
|
25
|
+
sqlite3_str *data_sql = sqlite3_str_new(db);
|
|
26
|
+
if (data_sql) {
|
|
27
|
+
sqlite3_str_appendf(data_sql, "select * from \"%w\"", tname);
|
|
28
|
+
sqlite3_stmt *data_stmt = NULL;
|
|
29
|
+
sqlite3_stmt *index_stmt = NULL;
|
|
30
|
+
sqlite3_stmt *unique_stmt = NULL;
|
|
31
|
+
int colcount = 0;
|
|
32
|
+
|
|
33
|
+
err = 1;
|
|
34
|
+
if (sqlite3_prepare_v2(db, sqlite3_str_value(data_sql), -1, &data_stmt, NULL) != SQLITE_OK)
|
|
35
|
+
fprintf(stderr, "Unable to prepare %s: %s\n", sqlite3_str_value(data_sql), sqlite3_errmsg(db));
|
|
36
|
+
else if (!(colcount = sqlite3_column_count(data_stmt)))
|
|
37
|
+
fprintf(stderr, "No columns found in table %s\n", tname);
|
|
38
|
+
else if (sqlite3_prepare_v2(db, index_sql, -1, &index_stmt, NULL) != SQLITE_OK)
|
|
39
|
+
fprintf(stderr, "Unable to prepare %s: %s\n", index_sql, sqlite3_errmsg(db));
|
|
40
|
+
else if (sqlite3_prepare_v2(db, unique_sql, -1, &unique_stmt, NULL) != SQLITE_OK)
|
|
41
|
+
fprintf(stderr, "Unable to prepare %s: %s\n", unique_sql, sqlite3_errmsg(db));
|
|
42
|
+
else {
|
|
43
|
+
err = 0;
|
|
44
|
+
jsonwriter_start_array(jsw); // output is an array with 2 items: meta and data
|
|
45
|
+
|
|
46
|
+
// ----- meta: columns and index info
|
|
47
|
+
jsonwriter_start_object(jsw);
|
|
48
|
+
|
|
49
|
+
jsonwriter_object_cstr(jsw, "name", tname);
|
|
50
|
+
|
|
51
|
+
// indexes
|
|
52
|
+
jsonwriter_object_object(jsw, "indexes"); // indexes
|
|
53
|
+
sqlite3_bind_text(index_stmt, 1, tname, (int)strlen(tname), SQLITE_STATIC);
|
|
54
|
+
while (sqlite3_step(index_stmt) == SQLITE_ROW) {
|
|
55
|
+
const unsigned char *text = sqlite3_column_text(index_stmt, 0);
|
|
56
|
+
const unsigned char *ix_sql = sqlite3_column_text(index_stmt, 1);
|
|
57
|
+
size_t len = text ? sqlite3_column_bytes(index_stmt, 0) : 0;
|
|
58
|
+
size_t ix_sql_len = ix_sql ? sqlite3_column_bytes(index_stmt, 1) : 0;
|
|
59
|
+
|
|
60
|
+
if (text && ix_sql && len && ix_sql_len) {
|
|
61
|
+
// on: for now we just look for the first and last parens
|
|
62
|
+
const unsigned char *first_paren = memchr(ix_sql, '(', ix_sql_len);
|
|
63
|
+
const unsigned char *last_paren = ix_sql + ix_sql_len;
|
|
64
|
+
while (first_paren && last_paren > first_paren + 1 && *last_paren != ')')
|
|
65
|
+
last_paren--;
|
|
66
|
+
if (first_paren && last_paren > first_paren) {
|
|
67
|
+
// name
|
|
68
|
+
|
|
69
|
+
// strip the leading "tablename_" from the index name
|
|
70
|
+
const char *ix_name = (const char *)text;
|
|
71
|
+
size_t ix_name_len = len;
|
|
72
|
+
if (ix_name_len > strlen(tname) + 1 &&
|
|
73
|
+
starts_w_str_underscore((const unsigned char *)ix_name, ix_name_len, (const unsigned char *)tname)) {
|
|
74
|
+
ix_name += strlen(tname) + 1;
|
|
75
|
+
ix_name_len -= strlen(tname) + 1;
|
|
76
|
+
}
|
|
77
|
+
jsonwriter_object_keyn(jsw, (const char *)ix_name, ix_name_len);
|
|
78
|
+
|
|
79
|
+
// ix obj
|
|
80
|
+
jsonwriter_start_object(jsw);
|
|
81
|
+
|
|
82
|
+
// on
|
|
83
|
+
jsonwriter_object_strn(jsw, "on", first_paren + 1, last_paren - first_paren - 1);
|
|
84
|
+
|
|
85
|
+
// unique
|
|
86
|
+
sqlite3_bind_text(unique_stmt, 1, tname, (int)strlen(tname), SQLITE_STATIC);
|
|
87
|
+
sqlite3_bind_text(unique_stmt, 2, (const char *)text, len, SQLITE_STATIC);
|
|
88
|
+
if (sqlite3_step(unique_stmt) == SQLITE_ROW)
|
|
89
|
+
jsonwriter_object_bool(jsw, "unique", 1);
|
|
90
|
+
sqlite3_reset(unique_stmt);
|
|
91
|
+
|
|
92
|
+
// end ix obj
|
|
93
|
+
jsonwriter_end_object(jsw);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
jsonwriter_end_object(jsw); // end indexes
|
|
98
|
+
|
|
99
|
+
// columns
|
|
100
|
+
jsonwriter_object_array(jsw, "columns");
|
|
101
|
+
for (int i = 0; i < colcount; i++) {
|
|
102
|
+
const char *colname = sqlite3_column_name(data_stmt, i);
|
|
103
|
+
jsonwriter_start_object(jsw);
|
|
104
|
+
jsonwriter_object_cstr(jsw, "name", colname);
|
|
105
|
+
const char *dtype = sqlite3_column_decltype(data_stmt, i);
|
|
106
|
+
if (dtype)
|
|
107
|
+
jsonwriter_object_cstr(jsw, "datatype", dtype);
|
|
108
|
+
|
|
109
|
+
// TO DO: collate nocase etc
|
|
110
|
+
jsonwriter_end_object(jsw);
|
|
111
|
+
}
|
|
112
|
+
jsonwriter_end_array(jsw); // end columns
|
|
113
|
+
|
|
114
|
+
jsonwriter_end_object(jsw); // end meta obj
|
|
115
|
+
|
|
116
|
+
// ------ data: array of rows
|
|
117
|
+
jsonwriter_start_array(jsw);
|
|
118
|
+
// for each row
|
|
119
|
+
size_t count = 0;
|
|
120
|
+
while (sqlite3_step(data_stmt) == SQLITE_ROW) {
|
|
121
|
+
jsonwriter_start_array(jsw); // start row
|
|
122
|
+
for (int i = 0; i < colcount; i++) {
|
|
123
|
+
const unsigned char *text = sqlite3_column_text(data_stmt, i);
|
|
124
|
+
if (text) {
|
|
125
|
+
int len = sqlite3_column_bytes(data_stmt, i);
|
|
126
|
+
jsonwriter_strn(jsw, text, len);
|
|
127
|
+
} else
|
|
128
|
+
jsonwriter_null(jsw);
|
|
129
|
+
}
|
|
130
|
+
jsonwriter_end_array(jsw); // end row
|
|
131
|
+
if (limit && ++count >= limit)
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
jsonwriter_end_array(jsw);
|
|
135
|
+
|
|
136
|
+
jsonwriter_end_array(jsw); // end of output
|
|
137
|
+
}
|
|
138
|
+
if (data_stmt)
|
|
139
|
+
sqlite3_finalize(data_stmt);
|
|
140
|
+
if (index_stmt)
|
|
141
|
+
sqlite3_finalize(index_stmt);
|
|
142
|
+
if (unique_stmt)
|
|
143
|
+
sqlite3_finalize(unique_stmt);
|
|
144
|
+
|
|
145
|
+
sqlite3_free(sqlite3_str_finish(data_sql));
|
|
146
|
+
} // if data_sql
|
|
147
|
+
return err;
|
|
148
|
+
}
|
|
@@ -0,0 +1,427 @@
|
|
|
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 <stddef.h>
|
|
10
|
+
#include <stdlib.h>
|
|
11
|
+
#include <stdio.h>
|
|
12
|
+
#include <string.h>
|
|
13
|
+
#include <dirent.h>
|
|
14
|
+
#include <errno.h>
|
|
15
|
+
#include <zsv/utils/os.h>
|
|
16
|
+
#ifndef ZSV_NO_JQ
|
|
17
|
+
#include <zsv/utils/json.h>
|
|
18
|
+
#include <zsv/utils/jq.h>
|
|
19
|
+
#endif
|
|
20
|
+
#include <zsv/utils/dirs.h>
|
|
21
|
+
#include <zsv/utils/string.h>
|
|
22
|
+
#include <unistd.h> // unlink
|
|
23
|
+
#include <sys/stat.h>
|
|
24
|
+
#ifndef ZSV_NO_JQ
|
|
25
|
+
#include <yajl_helper/yajl_helper.h>
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
#if defined(_WIN32)
|
|
29
|
+
#include <windows.h>
|
|
30
|
+
#include "win/io.c"
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Most of these functions require the caller to provide a buffer, in which case
|
|
35
|
+
* the buffer size should be at least FILENAME_MAX
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
static size_t chop_slash(char *buff, size_t len) {
|
|
39
|
+
if (buff[len - 1] == '\\' || buff[len - 1] == '/') {
|
|
40
|
+
buff[len - 1] = '\0';
|
|
41
|
+
len--;
|
|
42
|
+
}
|
|
43
|
+
return (size_t)len;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get os-independent configuration file path
|
|
48
|
+
* prefix should be determined at compile time e.g. /usr/local or ""
|
|
49
|
+
* @return length written to buff, or 0 if failed
|
|
50
|
+
*/
|
|
51
|
+
size_t zsv_get_config_dir(char *buff, size_t buffsize, const char *prefix) {
|
|
52
|
+
#if defined(_WIN32)
|
|
53
|
+
const char *env_val = getenv("ZSV_CONFIG_DIR");
|
|
54
|
+
(void)(prefix);
|
|
55
|
+
// if(!(env_val && *env_val))
|
|
56
|
+
// env_val = getenv(prefix);
|
|
57
|
+
if (!(env_val && *env_val))
|
|
58
|
+
env_val = getenv("LOCALAPPDATA");
|
|
59
|
+
if (!(env_val && *env_val))
|
|
60
|
+
env_val = "C:\\temp";
|
|
61
|
+
int written = snprintf(buff, buffsize, "%s", env_val);
|
|
62
|
+
#elif defined(__EMSCRIPTEN__)
|
|
63
|
+
(void)(prefix);
|
|
64
|
+
int written = snprintf(buff, buffsize, "/tmp");
|
|
65
|
+
#else
|
|
66
|
+
int written;
|
|
67
|
+
const char *env_val = getenv("ZSV_CONFIG_DIR");
|
|
68
|
+
if (env_val && *env_val)
|
|
69
|
+
written = snprintf(buff, buffsize, "%s", env_val);
|
|
70
|
+
else
|
|
71
|
+
written = snprintf(buff, buffsize, "%s/etc", prefix ? prefix : "");
|
|
72
|
+
#endif
|
|
73
|
+
if (written > 0 && ((size_t)written) < buffsize)
|
|
74
|
+
return chop_slash(buff, written);
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if a directory exists
|
|
80
|
+
* return true (non-zero) or false (zero)
|
|
81
|
+
*/
|
|
82
|
+
#ifdef WIN32
|
|
83
|
+
#include "win/dir_exists_longpath.c"
|
|
84
|
+
#endif
|
|
85
|
+
int zsv_dir_exists(const char *path) {
|
|
86
|
+
#ifdef WIN32
|
|
87
|
+
if (strlen(path) >= MAX_PATH)
|
|
88
|
+
return zsv_dir_exists_winlp(path);
|
|
89
|
+
|
|
90
|
+
// TO DO: support win long filepath prefix
|
|
91
|
+
// TO DO: work properly if dir exists but we don't have permission
|
|
92
|
+
wchar_t wpath[MAX_PATH];
|
|
93
|
+
mbstowcs(wpath, path, MAX_PATH);
|
|
94
|
+
|
|
95
|
+
DWORD attrs = GetFileAttributesW(wpath);
|
|
96
|
+
if (attrs == INVALID_FILE_ATTRIBUTES)
|
|
97
|
+
// Could check GetLastError() to see if it's a permission issue vs. not-found
|
|
98
|
+
return 0;
|
|
99
|
+
|
|
100
|
+
// If it has the directory attribute, it's presumably a directory
|
|
101
|
+
return (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
|
102
|
+
|
|
103
|
+
#else
|
|
104
|
+
struct stat path_stat;
|
|
105
|
+
if (!stat(path, &path_stat))
|
|
106
|
+
return S_ISDIR(path_stat.st_mode);
|
|
107
|
+
return 0;
|
|
108
|
+
#endif
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Make a directory, as well as any intermediate dirs
|
|
113
|
+
* return zero on success
|
|
114
|
+
*/
|
|
115
|
+
#ifdef WIN32
|
|
116
|
+
#include "win/mkdir_longpath.c"
|
|
117
|
+
#define zsv_mkdir zsv_mkdir_winlp
|
|
118
|
+
#else
|
|
119
|
+
#define zsv_mkdir mkdir
|
|
120
|
+
#endif
|
|
121
|
+
|
|
122
|
+
int zsv_mkdirs(const char *path, char path_is_filename) {
|
|
123
|
+
// int rc = 0;
|
|
124
|
+
if (!path || !*path)
|
|
125
|
+
return -1;
|
|
126
|
+
size_t len = strlen(path);
|
|
127
|
+
if (len < 1)
|
|
128
|
+
return -1;
|
|
129
|
+
|
|
130
|
+
char *tmp = strdup(path);
|
|
131
|
+
if (!tmp) {
|
|
132
|
+
perror(path);
|
|
133
|
+
return -1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (len && strchr("/\\", tmp[len - 1]))
|
|
137
|
+
tmp[--len] = 0;
|
|
138
|
+
|
|
139
|
+
int offset = 0;
|
|
140
|
+
#ifdef WIN32
|
|
141
|
+
if (len > 1) {
|
|
142
|
+
// starts with two slashes
|
|
143
|
+
if (strchr("/\\", tmp[0]) && strchr("/\\", tmp[1])) {
|
|
144
|
+
offset = 2;
|
|
145
|
+
// find the next slash
|
|
146
|
+
char *path_end = tmp + 3;
|
|
147
|
+
while (*path_end && !strchr("/\\", *path_end))
|
|
148
|
+
path_end++;
|
|
149
|
+
if (*path_end)
|
|
150
|
+
path_end++;
|
|
151
|
+
if (*path_end)
|
|
152
|
+
offset = path_end - tmp;
|
|
153
|
+
else {
|
|
154
|
+
fprintf(stderr, "Invalid path: %s\n", path);
|
|
155
|
+
free(tmp);
|
|
156
|
+
return -1;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// starts with *:
|
|
160
|
+
else if (tmp[1] == ':')
|
|
161
|
+
offset = 2;
|
|
162
|
+
}
|
|
163
|
+
#else
|
|
164
|
+
offset = 1;
|
|
165
|
+
#endif
|
|
166
|
+
|
|
167
|
+
// TO DO: first find the longest subdir that exists, in *reverse* order so as
|
|
168
|
+
// to properly handle case where no access to intermediate dir,
|
|
169
|
+
// and then only start mkdir from there
|
|
170
|
+
int last_dir_exists_rc = 0;
|
|
171
|
+
int last_errno = -1;
|
|
172
|
+
for (char *p = tmp + offset; /* !rc && */ *p; p++) {
|
|
173
|
+
if (strchr("/\\", *p)) {
|
|
174
|
+
char tmp_c = p[1];
|
|
175
|
+
p[0] = FILESLASH;
|
|
176
|
+
p[1] = '\0';
|
|
177
|
+
if (*tmp && !(last_dir_exists_rc = zsv_dir_exists(tmp))) {
|
|
178
|
+
if (zsv_mkdir(tmp
|
|
179
|
+
#ifndef WIN32
|
|
180
|
+
,
|
|
181
|
+
S_IRWXU
|
|
182
|
+
#endif
|
|
183
|
+
)) {
|
|
184
|
+
if (errno == EEXIST)
|
|
185
|
+
last_dir_exists_rc = 1;
|
|
186
|
+
else { // errno could be EEXIST if we have no permissions to an intermediate directory
|
|
187
|
+
last_errno = errno;
|
|
188
|
+
perror(tmp);
|
|
189
|
+
// rc = -1;
|
|
190
|
+
}
|
|
191
|
+
} else
|
|
192
|
+
last_dir_exists_rc = 1;
|
|
193
|
+
}
|
|
194
|
+
p[1] = tmp_c;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (/* !rc && */ path_is_filename == 0 && *tmp && !(last_dir_exists_rc = zsv_dir_exists(tmp))) {
|
|
199
|
+
if (zsv_mkdir(tmp
|
|
200
|
+
#ifndef WIN32
|
|
201
|
+
,
|
|
202
|
+
S_IRWXU
|
|
203
|
+
#endif
|
|
204
|
+
)) {
|
|
205
|
+
if (errno == EEXIST)
|
|
206
|
+
last_dir_exists_rc = 1;
|
|
207
|
+
else {
|
|
208
|
+
last_errno = errno;
|
|
209
|
+
perror(tmp);
|
|
210
|
+
// rc = -1;
|
|
211
|
+
}
|
|
212
|
+
} else
|
|
213
|
+
last_dir_exists_rc = 1;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
free(tmp);
|
|
217
|
+
return last_dir_exists_rc ? 0 : last_errno ? last_errno : -1;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#if defined(_WIN32)
|
|
221
|
+
size_t zsv_get_executable_path(char *buff, size_t buffsize) {
|
|
222
|
+
return GetModuleFileNameA(NULL, buff, (DWORD)buffsize);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#elif defined(__APPLE__)
|
|
226
|
+
#include <mach-o/dyld.h>
|
|
227
|
+
size_t zsv_get_executable_path(char *buff, size_t bufflen) {
|
|
228
|
+
uint32_t pathlen = bufflen;
|
|
229
|
+
if (!_NSGetExecutablePath(buff, &pathlen)) {
|
|
230
|
+
char real[FILENAME_MAX];
|
|
231
|
+
if (realpath(buff, real) != NULL && strlen(real) < bufflen) {
|
|
232
|
+
bufflen = strlen(real);
|
|
233
|
+
memcpy(buff, real, bufflen);
|
|
234
|
+
buff[bufflen] = '\0';
|
|
235
|
+
} else
|
|
236
|
+
bufflen = pathlen;
|
|
237
|
+
return bufflen;
|
|
238
|
+
}
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
#elif defined(__linux__) || defined(__EMSCRIPTEN__)
|
|
242
|
+
#include <unistd.h>
|
|
243
|
+
size_t zsv_get_executable_path(char *buff, size_t buffsize) {
|
|
244
|
+
buffsize = readlink("/proc/self/exe", buff, buffsize - 1);
|
|
245
|
+
buff[buffsize] = '\0';
|
|
246
|
+
return buffsize;
|
|
247
|
+
}
|
|
248
|
+
#elif defined(__FreeBSD__)
|
|
249
|
+
#include <sys/stat.h>
|
|
250
|
+
#include <sys/sysctl.h>
|
|
251
|
+
size_t zsv_get_executable_path(char *buff, size_t buffsize) {
|
|
252
|
+
int mib[4];
|
|
253
|
+
mib[0] = CTL_KERN;
|
|
254
|
+
mib[1] = KERN_PROC;
|
|
255
|
+
mib[2] = KERN_PROC_PATHNAME;
|
|
256
|
+
mib[3] = -1;
|
|
257
|
+
sysctl(mib, 4, buff, &buffsize, NULL, 0);
|
|
258
|
+
buff[buffsize] = '\0';
|
|
259
|
+
return buffsize;
|
|
260
|
+
}
|
|
261
|
+
#else
|
|
262
|
+
// TODO: Add support for this OS!
|
|
263
|
+
#endif /* end of: #if defined(_WIN32) */
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get current user's home dir, without trailing slash
|
|
267
|
+
* On win, any backslashes are replaced with fwd slash
|
|
268
|
+
* ex: zsv_get_home_dir(char[MAX_PATH], MAX_PATH)
|
|
269
|
+
* returns 0 if no home dir could be found
|
|
270
|
+
* returns > 0 and < bufflen on success
|
|
271
|
+
* returns > 0 and >= bufflen if buffer was too small
|
|
272
|
+
*/
|
|
273
|
+
int zsv_get_home_dir(char *buff, size_t bufflen) {
|
|
274
|
+
int written = 0;
|
|
275
|
+
if (getenv("HOME"))
|
|
276
|
+
written = snprintf(buff, bufflen, "%s", getenv("HOME"));
|
|
277
|
+
#if defined(WIN32) || defined(_WIN32)
|
|
278
|
+
if (!written && getenv("HOMEDRIVE") && getenv("HOMEPATH"))
|
|
279
|
+
written = snprintf(buff, bufflen, "%s%s", getenv("HOMEDRIVE"), getenv("HOMEPATH"));
|
|
280
|
+
#endif
|
|
281
|
+
if (written > 0 && ((size_t)written) < bufflen) {
|
|
282
|
+
if (buff[written - 1] == '\\' || buff[written - 1] == '/') {
|
|
283
|
+
buff[written - 1] = '\0';
|
|
284
|
+
written--;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
#if defined(WIN32) || defined(_WIN32)
|
|
288
|
+
for (int i = 0; i < written; i++)
|
|
289
|
+
if (buff[i] == '\\')
|
|
290
|
+
buff[i] = '/';
|
|
291
|
+
#endif
|
|
292
|
+
return written;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
struct dir_path {
|
|
296
|
+
struct dir_path *next;
|
|
297
|
+
char *path;
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* remove an empty directory; on error print msg to stderr
|
|
302
|
+
* return 0 on success
|
|
303
|
+
*/
|
|
304
|
+
static int rmdir_w_msg(const char *path, int *err) {
|
|
305
|
+
#ifdef WIN32
|
|
306
|
+
if (!RemoveDirectoryA(path)) {
|
|
307
|
+
zsv_perror(path);
|
|
308
|
+
// zsv_win_printLastError();
|
|
309
|
+
*err = 1;
|
|
310
|
+
}
|
|
311
|
+
#else
|
|
312
|
+
if (remove(path)) {
|
|
313
|
+
perror(path);
|
|
314
|
+
*err = 1;
|
|
315
|
+
}
|
|
316
|
+
#endif
|
|
317
|
+
return *err;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
static int zsv_foreach_dirent_remove(struct zsv_foreach_dirent_handle *h, size_t depth) {
|
|
321
|
+
(void)(depth);
|
|
322
|
+
if (!h->is_dir) { // file
|
|
323
|
+
if (h->parent_and_entry) {
|
|
324
|
+
if (zsv_remove(h->parent_and_entry)) {
|
|
325
|
+
perror(h->parent_and_entry); // "Unable to remove file");
|
|
326
|
+
return 1;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
} else { // dir
|
|
330
|
+
if (h->parent_and_entry) {
|
|
331
|
+
struct dir_path *dn = calloc(1, sizeof(*dn));
|
|
332
|
+
if (!dn) {
|
|
333
|
+
fprintf(stderr, "Out of memory!\n");
|
|
334
|
+
return 1;
|
|
335
|
+
}
|
|
336
|
+
dn->path = strdup(h->parent_and_entry);
|
|
337
|
+
dn->next = *((struct dir_path **)h->ctx);
|
|
338
|
+
*((struct dir_path **)h->ctx) = dn;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return 0;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
#ifdef _WIN32
|
|
345
|
+
#include "win/foreach_dirent_longpath.c"
|
|
346
|
+
#else
|
|
347
|
+
// return error
|
|
348
|
+
static int zsv_foreach_dirent_aux(const char *dir_path, size_t depth, size_t max_depth,
|
|
349
|
+
zsv_foreach_dirent_handler handler, void *ctx, char verbose) {
|
|
350
|
+
int err = 0;
|
|
351
|
+
if (!dir_path)
|
|
352
|
+
return 1;
|
|
353
|
+
|
|
354
|
+
if (max_depth > 0 && depth >= max_depth)
|
|
355
|
+
return 0;
|
|
356
|
+
|
|
357
|
+
DIR *dr;
|
|
358
|
+
if ((dr = opendir(dir_path))) {
|
|
359
|
+
struct dirent *de;
|
|
360
|
+
while ((de = readdir(dr)) != NULL) {
|
|
361
|
+
if (!*de->d_name || !strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
|
|
362
|
+
continue;
|
|
363
|
+
char *tmp;
|
|
364
|
+
asprintf(&tmp, "%s%c%s", dir_path, FILESLASH, de->d_name);
|
|
365
|
+
if (!tmp)
|
|
366
|
+
fprintf(stderr, "Out of memory!\n"), err = 1;
|
|
367
|
+
else {
|
|
368
|
+
struct zsv_foreach_dirent_handle h = {0};
|
|
369
|
+
h.verbose = verbose;
|
|
370
|
+
stat(tmp, (struct stat *)&h.stat);
|
|
371
|
+
h.parent = dir_path;
|
|
372
|
+
h.entry = de->d_name;
|
|
373
|
+
h.parent_and_entry = tmp;
|
|
374
|
+
h.ctx = ctx;
|
|
375
|
+
char is_dir = h.stat.st_mode & S_IFDIR ? 1 : 0;
|
|
376
|
+
h.is_dir = is_dir;
|
|
377
|
+
if (handler)
|
|
378
|
+
handler(&h, depth + 1);
|
|
379
|
+
|
|
380
|
+
if (is_dir && !h.no_recurse)
|
|
381
|
+
// recurse!
|
|
382
|
+
err = zsv_foreach_dirent_aux(tmp, depth + 1, max_depth, handler, ctx, verbose);
|
|
383
|
+
free(tmp);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
closedir(dr);
|
|
387
|
+
}
|
|
388
|
+
return err;
|
|
389
|
+
}
|
|
390
|
+
#endif
|
|
391
|
+
|
|
392
|
+
int zsv_foreach_dirent(const char *dir_path, size_t max_depth, zsv_foreach_dirent_handler handler, void *ctx,
|
|
393
|
+
char verbose) {
|
|
394
|
+
return zsv_foreach_dirent_aux(dir_path, 0, max_depth, handler, ctx, verbose);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Remove a directory and all of its contents
|
|
399
|
+
*/
|
|
400
|
+
int zsv_remove_dir_recursive(const unsigned char *path) {
|
|
401
|
+
// we will delete all files first, then
|
|
402
|
+
// delete directories in the reverse order we received them
|
|
403
|
+
struct dir_path *reverse_dirs = NULL;
|
|
404
|
+
int err = zsv_foreach_dirent((const char *)path, 0, zsv_foreach_dirent_remove, &reverse_dirs, 0);
|
|
405
|
+
|
|
406
|
+
// unlink each dir
|
|
407
|
+
for (struct dir_path *dn = reverse_dirs; !err && dn; dn = dn->next)
|
|
408
|
+
rmdir_w_msg(dn->path, &err);
|
|
409
|
+
|
|
410
|
+
// free each dir
|
|
411
|
+
for (struct dir_path *next, *dn = reverse_dirs; !err && dn; dn = next) {
|
|
412
|
+
next = dn->next;
|
|
413
|
+
free(dn->path);
|
|
414
|
+
free(dn);
|
|
415
|
+
}
|
|
416
|
+
if (!err)
|
|
417
|
+
rmdir_w_msg((const char *)path, &err);
|
|
418
|
+
|
|
419
|
+
return err;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
#ifndef ZSV_NO_JQ
|
|
423
|
+
#include "dirs_to_json.c"
|
|
424
|
+
|
|
425
|
+
#include "dirs_from_json.c"
|
|
426
|
+
|
|
427
|
+
#endif
|