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,357 @@
|
|
|
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 <string.h>
|
|
10
|
+
#include <stdint.h>
|
|
11
|
+
#include <ctype.h>
|
|
12
|
+
#include <stdlib.h>
|
|
13
|
+
#include <stdio.h>
|
|
14
|
+
|
|
15
|
+
#include <zsv/utils/compiler.h>
|
|
16
|
+
#include <zsv/utils/utf8.h>
|
|
17
|
+
#include <zsv/utils/string.h>
|
|
18
|
+
|
|
19
|
+
#ifdef ZSV_UTILS_STRING_STANDALONE
|
|
20
|
+
#include "../../src/zsv_strencode.c"
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
#ifndef NO_UTF8PROC
|
|
24
|
+
#include <utf8proc.h>
|
|
25
|
+
|
|
26
|
+
static utf8proc_int32_t utf8proc_tolower1(utf8proc_int32_t codepoint, void *data) {
|
|
27
|
+
(void)data;
|
|
28
|
+
return utf8proc_tolower(codepoint);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static unsigned char *utf8proc_tolower_str(const unsigned char *str, size_t *len) {
|
|
32
|
+
// note: for some unknown reason, this func intermittently can fail on win (compiled w mingw64) when called in a tight
|
|
33
|
+
// loop may be related to realloc()
|
|
34
|
+
utf8proc_uint8_t *output;
|
|
35
|
+
utf8proc_option_t options = {0};
|
|
36
|
+
/* options = UTF8PROC_COMPOSE | UTF8PROC_COMPAT
|
|
37
|
+
| UTF8PROC_CASEFOLD | UTF8PROC_IGNORE | UTF8PROC_STRIPMARK | UTF8PROC_STRIPCC | UTF8PROC_STRIPNA;
|
|
38
|
+
*/
|
|
39
|
+
// utf8proc_map_custom allocates new mem
|
|
40
|
+
options = UTF8PROC_STRIPNA;
|
|
41
|
+
*len = (size_t)utf8proc_map_custom((const utf8proc_uint8_t *)str, (utf8proc_ssize_t)*len, &output, options,
|
|
42
|
+
utf8proc_tolower1, NULL);
|
|
43
|
+
return (unsigned char *)output;
|
|
44
|
+
}
|
|
45
|
+
#endif // ndef NO_UTF8PROC
|
|
46
|
+
|
|
47
|
+
// zsv_strtolowercase(): to do: utf8 support
|
|
48
|
+
unsigned char *zsv_strtolowercase_w_err(const unsigned char *s, size_t *lenp, int *err) {
|
|
49
|
+
*err = 0;
|
|
50
|
+
#ifndef NO_UTF8PROC
|
|
51
|
+
size_t len_orig = *lenp;
|
|
52
|
+
unsigned char *new_s = utf8proc_tolower_str(s, lenp);
|
|
53
|
+
if (!new_s && len_orig) {
|
|
54
|
+
*err = 1;
|
|
55
|
+
unsigned char *tmp_s = malloc(len_orig + 1);
|
|
56
|
+
if (tmp_s) {
|
|
57
|
+
memcpy(tmp_s, s, len_orig);
|
|
58
|
+
tmp_s[len_orig] = '\0';
|
|
59
|
+
*lenp = zsv_strencode(tmp_s, len_orig, '?', NULL, NULL);
|
|
60
|
+
new_s = utf8proc_tolower_str(tmp_s, lenp);
|
|
61
|
+
free(tmp_s);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
#else // ndef NO_UTF8PROC
|
|
65
|
+
unsigned char *new_s = malloc((*lenp + 1) * sizeof(*new_s));
|
|
66
|
+
if (new_s) {
|
|
67
|
+
for (size_t i = 0, j = *lenp; i < j; i++)
|
|
68
|
+
new_s[i] = tolower(s[i]);
|
|
69
|
+
new_s[*lenp] = '\0';
|
|
70
|
+
}
|
|
71
|
+
#endif // ndef NO_UTF8PROC
|
|
72
|
+
return new_s;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
unsigned char *zsv_strtolowercase(const unsigned char *s, size_t *lenp) {
|
|
76
|
+
int err;
|
|
77
|
+
size_t len_orig = *lenp;
|
|
78
|
+
unsigned char *result = zsv_strtolowercase_w_err(s, lenp, &err);
|
|
79
|
+
if (err)
|
|
80
|
+
fprintf(stderr, "Warning: malformed UTF8 '%.*s'\n", (int)len_orig, s);
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// zsv_strstr(): strstr
|
|
85
|
+
const unsigned char *zsv_strstr(const unsigned char *hay, const unsigned char *needle) {
|
|
86
|
+
return (const unsigned char *)strstr((const char *)hay, (const char *)needle);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* zsv_stricmp, zsv_strincmp(): case-insensitive comparison
|
|
91
|
+
*
|
|
92
|
+
* @param s1 string to convert
|
|
93
|
+
* @param len1 length of s1
|
|
94
|
+
* @param s2 string to convert
|
|
95
|
+
* @param len2 length of s2
|
|
96
|
+
*/
|
|
97
|
+
int zsv_stricmp(const unsigned char *s1, const unsigned char *s2) {
|
|
98
|
+
return zsv_strincmp(s1, strlen((const char *)s1), s2, strlen((const char *)s2));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
int zsv_strincmp_ascii(const unsigned char *s1, size_t len1, const unsigned char *s2, size_t len2) {
|
|
102
|
+
while (len1 && len2) {
|
|
103
|
+
if (!*s1)
|
|
104
|
+
return *s2 == 0 ? 0 : -1;
|
|
105
|
+
if (!*s2)
|
|
106
|
+
return 1;
|
|
107
|
+
int c1 = tolower(*s1);
|
|
108
|
+
int c2 = tolower(*s2);
|
|
109
|
+
if (c1 == c2) {
|
|
110
|
+
s1++, s2++, len1--, len2--;
|
|
111
|
+
} else
|
|
112
|
+
return c1 < c2 ? -1 : 1;
|
|
113
|
+
}
|
|
114
|
+
return len1 > len2 ? 1 : len1 < len2 ? -1 : 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
int zsv_strincmp(const unsigned char *s1, size_t len1, const unsigned char *s2, size_t len2) {
|
|
118
|
+
#ifndef NO_UTF8PROC
|
|
119
|
+
unsigned char *lc1 = zsv_strtolowercase(s1, &len1);
|
|
120
|
+
unsigned char *lc2 = zsv_strtolowercase(s2, &len2);
|
|
121
|
+
int result;
|
|
122
|
+
if (VERY_UNLIKELY(!lc1 || !lc2))
|
|
123
|
+
fprintf(stderr, "Out of memory!\n"), result = -2;
|
|
124
|
+
else
|
|
125
|
+
result = strcmp((char *)lc1, (char *)lc2);
|
|
126
|
+
free(lc1);
|
|
127
|
+
free(lc2);
|
|
128
|
+
return result;
|
|
129
|
+
#else
|
|
130
|
+
return zsv_strincmp_ascii(s1, len1, s2, len2);
|
|
131
|
+
#endif
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
__attribute__((always_inline)) static inline const unsigned char *zsv_strtrim_left_inline(
|
|
135
|
+
const char unsigned *restrict s, size_t *lenp) {
|
|
136
|
+
utf8proc_ssize_t bytes_read;
|
|
137
|
+
utf8proc_int32_t codepoint = 0;
|
|
138
|
+
size_t len = *lenp;
|
|
139
|
+
utf8proc_category_t category;
|
|
140
|
+
|
|
141
|
+
// trim front
|
|
142
|
+
while ((bytes_read = zsv_strnext(s, len, &codepoint)) > 0 &&
|
|
143
|
+
((category = utf8proc_category(codepoint)) == UTF8PROC_CATEGORY_ZS || category == UTF8PROC_CATEGORY_ZL ||
|
|
144
|
+
category == UTF8PROC_CATEGORY_ZP)) {
|
|
145
|
+
s += bytes_read;
|
|
146
|
+
len -= bytes_read;
|
|
147
|
+
}
|
|
148
|
+
*lenp = len;
|
|
149
|
+
return s;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
__attribute__((always_inline)) static inline const unsigned char *zsv_strtrim_right_inline(
|
|
153
|
+
const char unsigned *restrict s, size_t *lenp) {
|
|
154
|
+
utf8proc_ssize_t bytes_read;
|
|
155
|
+
utf8proc_int32_t codepoint = 0;
|
|
156
|
+
size_t len = *lenp;
|
|
157
|
+
utf8proc_category_t category;
|
|
158
|
+
|
|
159
|
+
// trim back
|
|
160
|
+
while ((bytes_read = zsv_strlast(s, len, (int32_t *)&codepoint)) > 0 &&
|
|
161
|
+
((category = utf8proc_category(codepoint)) == UTF8PROC_CATEGORY_ZS || category == UTF8PROC_CATEGORY_ZL ||
|
|
162
|
+
category == UTF8PROC_CATEGORY_ZP)) {
|
|
163
|
+
len -= bytes_read;
|
|
164
|
+
}
|
|
165
|
+
*lenp = len;
|
|
166
|
+
return s;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const unsigned char *zsv_strtrim_right(const char unsigned *restrict s, size_t *lenp) {
|
|
170
|
+
return zsv_strtrim_right_inline(s, lenp);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const unsigned char *zsv_strtrim_left(const char unsigned *restrict s, size_t *lenp) {
|
|
174
|
+
return zsv_strtrim_left_inline(s, lenp);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const unsigned char *zsv_strtrim(const char unsigned *restrict s, size_t *lenp) {
|
|
178
|
+
s = zsv_strtrim_left_inline(s, lenp);
|
|
179
|
+
return zsv_strtrim_right_inline(s, lenp);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
size_t zsv_strnext(const unsigned char *s, size_t len, int32_t *codepoint) {
|
|
183
|
+
utf8proc_ssize_t bytes_read = utf8proc_iterate(s, len, (utf8proc_int32_t *)codepoint);
|
|
184
|
+
if (bytes_read < 1)
|
|
185
|
+
return 0;
|
|
186
|
+
return (size_t)bytes_read;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Return the 1-based position of the last byte
|
|
191
|
+
*/
|
|
192
|
+
__attribute__((always_inline)) static inline size_t zsv_strlast_position(const unsigned char *s, size_t len) {
|
|
193
|
+
// from the end, search backwards for the first byte that begins with 0 or 11
|
|
194
|
+
while (len && !(s[len - 1] < 128 || s[len - 1] >= 192))
|
|
195
|
+
len--;
|
|
196
|
+
return len;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
size_t zsv_strlast(const unsigned char *s, size_t len, int32_t *codepoint) {
|
|
200
|
+
size_t position = zsv_strlast_position(s, len);
|
|
201
|
+
if (position) {
|
|
202
|
+
position--;
|
|
203
|
+
return zsv_strnext(s + position, len - position, codepoint);
|
|
204
|
+
}
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Check if the next char is a currency char. If so, return its length, else return 0
|
|
210
|
+
*/
|
|
211
|
+
size_t zsv_strnext_is_currency(const unsigned char *s, size_t len) {
|
|
212
|
+
utf8proc_int32_t codepoint;
|
|
213
|
+
utf8proc_ssize_t bytes_read = utf8proc_iterate(s, len, &codepoint);
|
|
214
|
+
if (VERY_LIKELY(bytes_read > 0)) {
|
|
215
|
+
utf8proc_category_t category = utf8proc_category(codepoint);
|
|
216
|
+
if (category == UTF8PROC_CATEGORY_SC)
|
|
217
|
+
return (size_t)bytes_read;
|
|
218
|
+
}
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Check if the next char is a plus or minus. If so, return its length, else return 0
|
|
224
|
+
*/
|
|
225
|
+
size_t zsv_strnext_is_sign(const unsigned char *s, size_t len) {
|
|
226
|
+
if (len && *s == '+')
|
|
227
|
+
return 1;
|
|
228
|
+
|
|
229
|
+
utf8proc_int32_t codepoint;
|
|
230
|
+
utf8proc_ssize_t bytes_read = utf8proc_iterate(s, len, &codepoint);
|
|
231
|
+
if (VERY_LIKELY(bytes_read > 0)) {
|
|
232
|
+
utf8proc_category_t category = utf8proc_category(codepoint);
|
|
233
|
+
if (category == UTF8PROC_CATEGORY_PD)
|
|
234
|
+
return (size_t)bytes_read;
|
|
235
|
+
}
|
|
236
|
+
return 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* zsv_strwhite(): convert consecutive white to single space
|
|
241
|
+
*
|
|
242
|
+
* @param s string to convert
|
|
243
|
+
* @param len length of input string
|
|
244
|
+
* @param flags bitfield of ZSV_STRWHITE_FLAG_XXX values
|
|
245
|
+
*/
|
|
246
|
+
size_t zsv_strwhite(unsigned char *s, size_t len, unsigned int flags) {
|
|
247
|
+
int this_is_space, last_was_space = 0;
|
|
248
|
+
size_t new_len = 0;
|
|
249
|
+
char replacement = ' ';
|
|
250
|
+
int clen;
|
|
251
|
+
|
|
252
|
+
for (size_t i = 0; i < len; i += clen) {
|
|
253
|
+
#ifndef NO_UTF8PROC
|
|
254
|
+
clen = ZSV_UTF8_CHARLEN(s[i]);
|
|
255
|
+
this_is_space = 0;
|
|
256
|
+
if (UNLIKELY(clen < 1 || i + clen > len)) { // bad UTF8. replace w '?'
|
|
257
|
+
clen = 1;
|
|
258
|
+
s[i] = '?';
|
|
259
|
+
} else if (UNLIKELY(clen > 1)) { // multi-byte UTF8
|
|
260
|
+
utf8proc_int32_t codepoint;
|
|
261
|
+
utf8proc_ssize_t bytes_read = utf8proc_iterate(s + i, clen, &codepoint);
|
|
262
|
+
if (UNLIKELY(bytes_read < 1)) { // error! but this could only happen if ZSV_UTF8_CHARLEN was wrong
|
|
263
|
+
clen = 1;
|
|
264
|
+
s[i] = '?';
|
|
265
|
+
} else {
|
|
266
|
+
utf8proc_category_t category = utf8proc_category(codepoint);
|
|
267
|
+
switch (category) { // Unicode space categories
|
|
268
|
+
case UTF8PROC_CATEGORY_ZL: // line separator
|
|
269
|
+
case UTF8PROC_CATEGORY_ZP: // paragraph separator
|
|
270
|
+
this_is_space = 1;
|
|
271
|
+
s[i] = (flags & ZSV_STRWHITE_FLAG_NO_EMBEDDED_NEWLINE ? ' ' : '\n');
|
|
272
|
+
break;
|
|
273
|
+
case UTF8PROC_CATEGORY_ZS: // regular space
|
|
274
|
+
this_is_space = 1;
|
|
275
|
+
s[i] = ' ';
|
|
276
|
+
break;
|
|
277
|
+
default:
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} else { // regular ascii, clen == 1
|
|
282
|
+
this_is_space = isspace(s[i]);
|
|
283
|
+
}
|
|
284
|
+
#else // no UTF8PROC, assume clen = 1
|
|
285
|
+
{
|
|
286
|
+
clen = 1;
|
|
287
|
+
this_is_space = isspace(s[i]);
|
|
288
|
+
}
|
|
289
|
+
#endif // ndef NO_UTF8PROC
|
|
290
|
+
|
|
291
|
+
if (this_is_space) {
|
|
292
|
+
if (UNLIKELY((s[i] == '\n' || s[i] == '\r')) && !(flags & ZSV_STRWHITE_FLAG_NO_EMBEDDED_NEWLINE))
|
|
293
|
+
replacement = '\n';
|
|
294
|
+
else if (!last_was_space)
|
|
295
|
+
replacement = ' ';
|
|
296
|
+
last_was_space = 1;
|
|
297
|
+
} else {
|
|
298
|
+
// current position is not a space
|
|
299
|
+
if (last_was_space)
|
|
300
|
+
s[new_len++] = replacement;
|
|
301
|
+
for (int j = 0; j < clen; j++)
|
|
302
|
+
s[new_len++] = s[i + j];
|
|
303
|
+
last_was_space = 0;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return new_len;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
size_t zsv_strip_trailing_zeros(const char *s, size_t len) {
|
|
310
|
+
if (len && memchr(s, '.', len)) {
|
|
311
|
+
while (len && s[len - 1] == '0')
|
|
312
|
+
len--;
|
|
313
|
+
if (len && s[len - 1] == '.')
|
|
314
|
+
len--;
|
|
315
|
+
}
|
|
316
|
+
return len;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* zsv_strunescape_backslash(): convert consecutive white to single space
|
|
321
|
+
*
|
|
322
|
+
* @param s string to convert
|
|
323
|
+
* @param len length of input string
|
|
324
|
+
* @param flags bitfield of ZSV_STRWHITE_FLAG_XXX values
|
|
325
|
+
*/
|
|
326
|
+
size_t zsv_strunescape_backslash(unsigned char *s, size_t len) {
|
|
327
|
+
if (len == 0 || !memchr(s, '\\', len - 1))
|
|
328
|
+
return len;
|
|
329
|
+
size_t j = 0;
|
|
330
|
+
for (size_t i = 0; i < len; i++, j++) {
|
|
331
|
+
if (UNLIKELY(s[i] == '\\' && i + 1 < len && memchr("tnr", s[i + 1], 3))) {
|
|
332
|
+
++i;
|
|
333
|
+
s[j] = s[i] == 't' ? '\t' : s[i] == 'n' ? '\n' : '\r';
|
|
334
|
+
} else
|
|
335
|
+
s[j] = s[i];
|
|
336
|
+
}
|
|
337
|
+
return j;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// zsv_strtod_exact(const char *s): return error; if 0, set value of *d
|
|
341
|
+
int zsv_strtod_exact(const char *s, double *d) {
|
|
342
|
+
if (!*s)
|
|
343
|
+
return 1;
|
|
344
|
+
char *end;
|
|
345
|
+
*d = strtod(s, &end);
|
|
346
|
+
if (*end)
|
|
347
|
+
return 1;
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
#ifndef ZSV_STRING_LIB_ONLY
|
|
352
|
+
struct zsv_cell zsv_get_cell_trimmed(zsv_parser parser, size_t ix) {
|
|
353
|
+
struct zsv_cell c = zsv_get_cell(parser, ix);
|
|
354
|
+
c.str = (unsigned char *)zsv_strtrim(c.str, &c.len);
|
|
355
|
+
return c;
|
|
356
|
+
}
|
|
357
|
+
#endif
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
|
2
|
+
#include <windows.h>
|
|
3
|
+
#include <stdlib.h> // For malloc, free
|
|
4
|
+
#include <wchar.h> // Optional, primarily for wcslen if needed
|
|
5
|
+
#include <string.h> // For strncmp, wcslen, wcscpy_s, wcscat_s
|
|
6
|
+
#include <shlwapi.h> // For PathIsRelativeA
|
|
7
|
+
#include <stdio.h> // For printf, fprintf in main
|
|
8
|
+
// Link against -lShlwapi.for PathIsRelativeA
|
|
9
|
+
|
|
10
|
+
#include "io.h"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if a directory exists on Windows, supporting long paths (> MAX_PATH).
|
|
14
|
+
* Handles paths with or without the \\?\ prefix.
|
|
15
|
+
* Works even if directory exists but permissions are limited (as long as attributes can be read).
|
|
16
|
+
*
|
|
17
|
+
* @param path_utf8 The path to check (assumed to be UTF-8 encoded).
|
|
18
|
+
* @return Non-zero (true) if the path exists and is a directory, 0 (false) otherwise.
|
|
19
|
+
*/
|
|
20
|
+
int zsv_dir_exists_winlp(const char *path_utf8) {
|
|
21
|
+
if (path_utf8 == NULL || path_utf8[0] == '\0') {
|
|
22
|
+
return 0; // Invalid or empty path
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
wchar_t *path_to_use;
|
|
26
|
+
DWORD rc = zsv_pathToPrefixedWidePath(path_utf8, &path_to_use);
|
|
27
|
+
if (rc)
|
|
28
|
+
return rc;
|
|
29
|
+
|
|
30
|
+
// --- 3. Call GetFileAttributesW ---
|
|
31
|
+
// fprintf(stderr, "Debug: Calling GetFileAttributesW with: %ls\n", path_to_use); // Debug print wide string
|
|
32
|
+
DWORD dwAttrib = GetFileAttributesW(path_to_use);
|
|
33
|
+
|
|
34
|
+
// --- 4. Check the result ---
|
|
35
|
+
int result;
|
|
36
|
+
if (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
37
|
+
// Path exists and it is a directory.
|
|
38
|
+
result = 1; // True
|
|
39
|
+
} else {
|
|
40
|
+
// Path does not exist, is not a directory, or access denied to get attributes.
|
|
41
|
+
// GetLastError() could distinguish these cases if needed.
|
|
42
|
+
// fprintf(stderr, "Debug: GetFileAttributesW failed or not a directory. Attributes: 0x%lX, LastError: %lu\n",
|
|
43
|
+
// dwAttrib, GetLastError());
|
|
44
|
+
result = 0; // False
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- 5. Cleanup ---
|
|
48
|
+
free(path_to_use);
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
#ifdef ZSV_DIR_EXISTS_WINLP_TEST
|
|
53
|
+
|
|
54
|
+
// --- Main function for testing ---
|
|
55
|
+
int main(int argc, char *argv[]) {
|
|
56
|
+
// Check if a path argument was provided
|
|
57
|
+
if (argc != 2) {
|
|
58
|
+
// Note: argv[0] might not be UTF-8 on Windows console, print generic message
|
|
59
|
+
fprintf(stderr, "Usage: <program_name> <path_to_check>\n");
|
|
60
|
+
fprintf(stderr, "Example: %s C:\\Windows\n", argv[0] ? argv[0] : "checkdir");
|
|
61
|
+
fprintf(stderr, "Example: %s \"\\\\?\\C:\\Very Long Path Directory Name\"\n", argv[0] ? argv[0] : "checkdir");
|
|
62
|
+
fprintf(stderr, "Example: %s non_existent_dir\n", argv[0] ? argv[0] : "checkdir");
|
|
63
|
+
return 1; // Indicate error
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// The path provided by the user
|
|
67
|
+
const char *path_to_check = argv[1];
|
|
68
|
+
|
|
69
|
+
printf("Checking path: '%s'\n", path_to_check);
|
|
70
|
+
|
|
71
|
+
// Call the directory checking function
|
|
72
|
+
int exists = zsv_dir_exists_winlp(path_to_check);
|
|
73
|
+
|
|
74
|
+
// Print the result
|
|
75
|
+
if (exists) {
|
|
76
|
+
printf("Result: Directory exists.\n");
|
|
77
|
+
} else {
|
|
78
|
+
printf("Result: Path does not exist or is not a directory.\n");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return 0; // Indicate success
|
|
82
|
+
}
|
|
83
|
+
#endif // ZSV_DIR_EXISTS_WINLP_TEST
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
#ifdef _WIN32
|
|
10
|
+
#include <windows.h>
|
|
11
|
+
#include <zsv/utils/os.h>
|
|
12
|
+
|
|
13
|
+
#define RTLD_LAZY 0
|
|
14
|
+
void *dlsym(void *handle, const char *symbol) {
|
|
15
|
+
return (void *)GetProcAddress((HINSTANCE)(handle), (symbol));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void *dlopen(const char *dll_name, int flags) {
|
|
19
|
+
(void)flags;
|
|
20
|
+
wchar_t wbuf[PATH_MAX];
|
|
21
|
+
zsv_win_to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
|
|
22
|
+
return LoadLibraryW(wbuf);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
int dlclose(void *handle) {
|
|
26
|
+
int result;
|
|
27
|
+
if (FreeLibrary((HMODULE)handle) != 0)
|
|
28
|
+
result = 0;
|
|
29
|
+
else
|
|
30
|
+
result = -1;
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
#endif
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
#include <windows.h>
|
|
2
|
+
#include <io.h> // For _open_osfhandle, _fdopen
|
|
3
|
+
#include <fcntl.h> // For _O_xxx flags
|
|
4
|
+
#include <stdio.h> // For FILE*, fopen modes, fclose etc.
|
|
5
|
+
#include <wchar.h> // For wchar_t
|
|
6
|
+
#include <stdlib.h> // For malloc, free
|
|
7
|
+
|
|
8
|
+
#include "io.h"
|
|
9
|
+
|
|
10
|
+
FILE *zsv_fopen_longpath(const char *utf8_path, const char *mode) {
|
|
11
|
+
wchar_t *wide_path_prefixed;
|
|
12
|
+
DWORD dwDesiredAccess = 0;
|
|
13
|
+
DWORD dwShareMode = FILE_SHARE_READ; // Example default
|
|
14
|
+
DWORD dwCreationDisposition = 0;
|
|
15
|
+
int c_runtime_flags = 0;
|
|
16
|
+
if (zsv_pathToPrefixedWidePath(utf8_path, &wide_path_prefixed))
|
|
17
|
+
return NULL;
|
|
18
|
+
|
|
19
|
+
// --- 2. Determine CreateFileW params and _open_osfhandle flags from mode string ---
|
|
20
|
+
if (strchr(mode, 'w')) {
|
|
21
|
+
dwDesiredAccess |= GENERIC_WRITE;
|
|
22
|
+
dwCreationDisposition = CREATE_ALWAYS; // Overwrite or create
|
|
23
|
+
c_runtime_flags |= _O_WRONLY;
|
|
24
|
+
} else if (strchr(mode, 'a')) {
|
|
25
|
+
dwDesiredAccess |= GENERIC_WRITE | FILE_APPEND_DATA; // Or just GENERIC_WRITE and seek later
|
|
26
|
+
dwCreationDisposition = OPEN_ALWAYS; // Append or create
|
|
27
|
+
c_runtime_flags |= _O_WRONLY | _O_APPEND;
|
|
28
|
+
} else { // Default to read
|
|
29
|
+
dwDesiredAccess |= GENERIC_READ;
|
|
30
|
+
dwCreationDisposition = OPEN_EXISTING;
|
|
31
|
+
c_runtime_flags |= _O_RDONLY;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (strchr(mode, '+')) { // Read and write modes
|
|
35
|
+
dwDesiredAccess |= GENERIC_READ | GENERIC_WRITE;
|
|
36
|
+
c_runtime_flags &= ~(_O_RDONLY | _O_WRONLY); // Clear read/write only flags
|
|
37
|
+
c_runtime_flags |= _O_RDWR;
|
|
38
|
+
if (!strchr(mode, 'w')) { // If it wasn't 'w+', it implies 'r+' or 'a+'
|
|
39
|
+
dwCreationDisposition = OPEN_ALWAYS; // Make sure it opens if exists
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (strchr(mode, 'b')) {
|
|
44
|
+
c_runtime_flags |= _O_BINARY;
|
|
45
|
+
} else {
|
|
46
|
+
c_runtime_flags |= _O_TEXT;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- 3. Call CreateFileW ---
|
|
50
|
+
HANDLE hFile = CreateFileW(wide_path_prefixed, dwDesiredAccess, dwShareMode,
|
|
51
|
+
NULL, // Default security attributes
|
|
52
|
+
dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
53
|
+
|
|
54
|
+
free(wide_path_prefixed); // Don't need the string anymore
|
|
55
|
+
|
|
56
|
+
if (hFile == INVALID_HANDLE_VALUE) {
|
|
57
|
+
// Handle CreateFileW error (use GetLastError())
|
|
58
|
+
return NULL;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// --- 4. Convert HANDLE to C file descriptor ---
|
|
62
|
+
int fd = _open_osfhandle((intptr_t)hFile, c_runtime_flags);
|
|
63
|
+
if (fd == -1) {
|
|
64
|
+
// Handle _open_osfhandle error
|
|
65
|
+
CloseHandle(hFile); // Crucial: Close handle if fd conversion fails!
|
|
66
|
+
return NULL;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- 5. Convert file descriptor to FILE* stream ---
|
|
70
|
+
FILE *fp = _fdopen(fd, mode);
|
|
71
|
+
if (fp == NULL) {
|
|
72
|
+
// Handle _fdopen error
|
|
73
|
+
// Note: If _fdopen fails, the C runtime might or might not have
|
|
74
|
+
// taken ownership and closed the fd/handle. It's safer to assume
|
|
75
|
+
// it might not have, but closing the original hFile here is risky
|
|
76
|
+
// as _fdopen might have associated it. Usually, _close(fd) is
|
|
77
|
+
// appropriate here IF _fdopen fails, as _close *should* release the handle.
|
|
78
|
+
_close(fd); // Close the C descriptor; this should close the underlying handle.
|
|
79
|
+
return NULL;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --- 6. Success ---
|
|
83
|
+
return fp;
|
|
84
|
+
// Remember: fclose(fp) will clean up fd and hFile later.
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#ifdef ZSV_DIRS_FOPEN_LONGPATH_TEST
|
|
88
|
+
|
|
89
|
+
#include "win/io.c"
|
|
90
|
+
|
|
91
|
+
int main(int argc, char *argv[]) {
|
|
92
|
+
if (argc < 3 || argc > 4) {
|
|
93
|
+
fprintf(stderr, "Usage:\n");
|
|
94
|
+
fprintf(stderr, " For writing: %s w <absolute_filepath> [content_to_write]\n", argv[0]);
|
|
95
|
+
fprintf(stderr, " For reading: %s r <absolute_filepath>\n", argv[0]);
|
|
96
|
+
fprintf(stderr, "\nArguments:\n");
|
|
97
|
+
fprintf(stderr, " mode: 'w' (write - overwrites/creates) or 'r' (read)\n");
|
|
98
|
+
fprintf(stderr, " absolute_filepath: The full, absolute path to the file (can exceed MAX_PATH).\n");
|
|
99
|
+
fprintf(stderr, " Use quotes if the path contains spaces.\n");
|
|
100
|
+
fprintf(stderr, " content_to_write (optional): Text to write to the file if mode is 'w'.\n");
|
|
101
|
+
fprintf(stderr, " If omitted in write mode, default text is written.\n");
|
|
102
|
+
fprintf(stderr, "\nExample (Write):\n");
|
|
103
|
+
fprintf(stderr, " %s w \"C:\\Temp\\Long Path Folder\\very_long_filename_that_works.txt\" \"Hello Long World!\"\n",
|
|
104
|
+
argv[0]);
|
|
105
|
+
fprintf(stderr, "Example (Read):\n");
|
|
106
|
+
fprintf(stderr, " %s r \"\\\\?\\C:\\Temp\\Long Path Folder\\very_long_filename_that_works.txt\"\n", argv[0]);
|
|
107
|
+
return 1;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const char *mode_arg = argv[1];
|
|
111
|
+
const char *filepath_arg = argv[2];
|
|
112
|
+
const char *content_arg = (argc == 4 && strcmp(mode_arg, "w") == 0) ? argv[3] : NULL;
|
|
113
|
+
const char *default_content = "Default content written by fopen_longpath test.\n";
|
|
114
|
+
|
|
115
|
+
char file_mode[4] = ""; // e.g., "rb", "wt", etc. (Max 3 chars + null)
|
|
116
|
+
|
|
117
|
+
if (strcmp(mode_arg, "w") == 0) {
|
|
118
|
+
strcpy(file_mode, "w"); // Use text mode by default for simplicity
|
|
119
|
+
} else if (strcmp(mode_arg, "r") == 0) {
|
|
120
|
+
strcpy(file_mode, "r"); // Use text mode by default
|
|
121
|
+
} else {
|
|
122
|
+
fprintf(stderr, "Error: Invalid mode '%s'. Use 'r' or 'w'.\n", mode_arg);
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
printf("Attempting to open file: %s (Mode: %s)\n", filepath_arg, file_mode);
|
|
127
|
+
|
|
128
|
+
FILE *fp = fopen_longpath(filepath_arg, file_mode);
|
|
129
|
+
|
|
130
|
+
if (fp == NULL) {
|
|
131
|
+
// fopen_longpath should have printed specific errors
|
|
132
|
+
fprintf(stderr, "Main: Failed to open file using fopen_longpath.\n");
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
printf("Main: File opened successfully.\n");
|
|
137
|
+
int operation_status = 0; // 0 for success, non-zero for error
|
|
138
|
+
|
|
139
|
+
// --- Perform Read or Write ---
|
|
140
|
+
if (strcmp(mode_arg, "w") == 0) {
|
|
141
|
+
const char *content_to_write = (content_arg != NULL) ? content_arg : default_content;
|
|
142
|
+
printf("Main: Writing content: \"%s\"\n", content_to_write);
|
|
143
|
+
if (fputs(content_to_write, fp) == EOF) {
|
|
144
|
+
perror("Main: Error writing to file");
|
|
145
|
+
operation_status = 1;
|
|
146
|
+
} else {
|
|
147
|
+
// Add a newline if user content didn't end with one
|
|
148
|
+
if (content_to_write[strlen(content_to_write) - 1] != '\n') {
|
|
149
|
+
if (fputc('\n', fp) == EOF) {
|
|
150
|
+
perror("Main: Error writing newline to file");
|
|
151
|
+
operation_status = 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
printf("Main: Write operation successful.\n");
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
} else { // Mode is 'r'
|
|
158
|
+
printf("Main: Reading file content:\n---\n");
|
|
159
|
+
char buffer[1024];
|
|
160
|
+
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
|
|
161
|
+
printf("%s", buffer); // Print line including its newline
|
|
162
|
+
}
|
|
163
|
+
if (ferror(fp)) {
|
|
164
|
+
perror("Main: Error reading from file");
|
|
165
|
+
operation_status = 1;
|
|
166
|
+
} else {
|
|
167
|
+
printf("\n---\nMain: Read operation finished.\n");
|
|
168
|
+
// Reaching EOF without ferror is success
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// --- Close the file ---
|
|
173
|
+
printf("Main: Closing file.\n");
|
|
174
|
+
if (fclose(fp) != 0) {
|
|
175
|
+
perror("Main: Error closing file");
|
|
176
|
+
// Continue, but report overall failure if write/read also failed
|
|
177
|
+
if (operation_status == 0)
|
|
178
|
+
operation_status = 1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return operation_status; // 0 if all successful, 1 if any error occurred
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#endif // ZSV_DIRS_FOPEN_LONGPATH_TEST
|